Arrays 使数组对和相等的最小操作数
您将得到一个长度为偶数的整数列表。考虑一个操作,您在NUM中选择任何数字,并用一个值(1,max(NUMS)”更新它。返回所需的操作数,使每个i的nums[i]+nums[n-1-i]等于相同的数。这个问题可以迎刃而解 注意:n是数组的大小,max(nums)是nums中的最大元素 例如:nums=[1,5,4,5,9,3]预期的操作是2 说明:最大nums是9,因此我可以将nums的任何元素更改为[1,9]之间的任何数字,这需要一次操作Arrays 使数组对和相等的最小操作数,arrays,algorithm,Arrays,Algorithm,您将得到一个长度为偶数的整数列表。考虑一个操作,您在NUM中选择任何数字,并用一个值(1,max(NUMS)”更新它。返回所需的操作数,使每个i的nums[i]+nums[n-1-i]等于相同的数。这个问题可以迎刃而解 注意:n是数组的大小,max(nums)是nums中的最大元素 例如:nums=[1,5,4,5,9,3]预期的操作是2 说明:最大nums是9,因此我可以将nums的任何元素更改为[1,9]之间的任何数字,这需要一次操作 在索引0处选择1并将其更改为6 在索引4处选择9并将其
- 在索引0处选择1并将其更改为6
- 在索引4处选择9并将其更改为4
我使用的方法是求和的中值,然后用它来贪婪地求运算的次数。 让我们根据给定的条件求数组的所有和
- 总和可以用nums[i]+nums[n-1-i]计算
- 设i=0,nums[0]+nums[6-1-0]=4
- i=1,nums[1]+nums[6-1-1]=14
- i=2,nums[2]+nums[6-1-2]=9
int operations = 0;
for(int i=0; i<nums.size()/2; i++) {
if(nums[i] + nums[nums.size()-1-i] == mid)
continue;
if(nums[i] + nums[nums.size()-1-i] > mid) {
if(nums[i] + 1 <= mid || 1 + nums[nums.size()-1-i] <= mid) {
operations++;
} else {
operations += 2;
}
} else if (maxnums + nums[nums.size()-1-i] >= mid || nums[i] + maxnums >= mid) {
operations++;
} else {
operations += 2;
}
}
int运算=0;
对于(int i=0;i mid){
如果(nums[i]+1=mid){
操作++;
}否则{
操作+=2;
}
}
本例的总操作数为2,这是正确的
这里的问题是,在某些情况下,选择中值会给出错误的结果。例如,nums=[10,7,2,9,4,1,7,3,10,8]需要5次运算,但如果选择了中位数(16),我的代码会给出6次运算
选择中位数不是最理想的方法吗?有人能提供更好的方法吗?(收到更多信息后更新)
最佳和必须是以下之一:
- 一对的总和->因为你可以保留那对的两个数字
- 一对的最小值+1->因为它是可能的最小和,您只需更改该对的1个数字即可
- 一对的最大值+最大总值->因为它是最大可能的总和,您只需更改该对的1个数字即可
- 获取所有可能的最优和O(N)
- 对于每个可能的和,您可以计算具有该精确和的对的数目,因此不需要任何操作O(N)
- 对于所有其他对,您只需要知道它是否需要1或2次运算才能得到该和。如果一对中的最小值太大而无法达到可能的最小值,或者一对中的最大值太小而无法达到可能的最大值,则为2。许多数据结构可用于此(位、树等)。我只是使用了一个排序列表并应用了二进制搜索(虽然没有经过详尽的测试)O(N日志N)
int[] nums = new int[] {10, 7, 2, 9, 4, 1, 7, 3, 10, 8};
// preprocess pairs: O(N)
int min = 1
, max = nums[0];
List<Integer> minList = new ArrayList<>();
List<Integer> maxList = new ArrayList<>();
Map<Integer, Integer> occ = new HashMap<>();
for (int i=0;i<nums.length/2;i++) {
int curMin = Math.min(nums[i], nums[nums.length-1-i]);
int curMax = Math.max(nums[i], nums[nums.length-1-i]);
min = Math.min(min, curMin);
max = Math.max(max, curMax);
minList.add(curMin);
maxList.add(curMax);
// create all pair sums
int pairSum = nums[i] + nums[nums.length-1-i];
int currentOccurences = occ.getOrDefault(pairSum, 0);
occ.put(pairSum, currentOccurences + 1);
}
// sorting 0(N log N)
Collections.sort(minList);
Collections.sort(maxList);
// border cases
for (int a : minList) {
occ.putIfAbsent(a + max, 0);
}
for (int a : maxList) {
occ.putIfAbsent(a + min, 0);
}
// loop over all condidates O(N log N)
int best = (nums.length-2);
int med = max + min;
for (Map.Entry<Integer, Integer> entry : occ.entrySet()) {
int sum = entry.getKey();
int count = entry.getValue();
int requiredChanges = (nums.length / 2) - count;
if (sum > med) {
// border case where max of pair is too small to be changed to pair of sum
requiredChanges += countSmaller(maxList, sum - max);
} else if (sum < med) {
// border case where having a min of pair is too big to be changed to pair of sum
requiredChanges += countGreater(minList, sum - min);
}
System.out.println(sum + " -> " + requiredChanges);
best = Math.min(best, requiredChanges);
}
System.out.println("Result: " + best);
}
// O(log N)
private static int countGreater(List<Integer> list, int key) {
int low=0, high=list.size();
while(low < high) {
int mid = (low + high) / 2;
if (list.get(mid) <= key) {
low = mid + 1;
} else {
high = mid;
}
}
return list.size() - low;
}
// O(log N)
private static int countSmaller(List<Integer> list, int key) {
int low=0, high=list.size();
while(low < high) {
int mid = (low + high) / 2;
if (list.get(mid) < key) {
low = mid + 1;
} else {
high = mid;
}
}
return low;
}
int[]nums=newint[]{10,7,2,9,4,1,7,3,10,8};
//预处理对:O(N)
int最小值=1
,max=nums[0];
List minList=new ArrayList();
List maxList=new ArrayList();
Map occ=newhashmap();
对于(int i=0;i med){
//边界情况下,对的最大值太小,无法更改为和的对
requiredChanges+=countSmaller(最大值列表,总和-最大值);
}否则如果(总和<平均值){
//边界情况下,对的最小值太大,无法更改为和的对
requiredChanges+=CountMorger(最小列表,总和-最小值);
}
系统输出打印项次(总和+“->”+所需更改);
best=Math.min(最佳,所需更改);
}
System.out.println(“结果:+最佳);
}
//O(对数N)
私有静态整数更大(列表,整数键){
int low=0,high=list.size();
while(低<高){
int mid=(低+高)/2;
如果(list.get(mid)我认为以下方法应该有效:
- 迭代数对
- 对于每一对,计算该对的和,以及仅更改其中一个值即可实现的最小和最大和
- 当开始一个新的“区域”需要较少的更改时,用-1更新字典/地图;当该区域结束时,用+1更新字典/地图
- 迭代该字典中的边界并更新所需的总更改,以找到需要最少更新的总和
Python中的示例代码,将9
作为示例的最佳总和,需要5
更改
从集合导入defaultdict
nums=[10,7,2,9,4,1,7,3,10,8]
m=最大值(nums)
pairs=[(nums[i],nums[-1-i])表示范围内的i(len(nums)//2)]
打印(双)
分数=defaultdict(int)
对于地图中的a、b(已排序,成对):
低=a+1
高=m+b
分数[低]-=1
分数[a+b]-=1
分数[a+b+1]+=1
分数[高+1]+=1
打印(已排序(score.items())
cur=best=len(nums)
num=无
对于排序中的i(分数):
cur+=分数[i]
打印(i,cur)
如果cur<最佳值:
最佳,num=cur,i
打印(最佳,num)
此操作的总复杂度应为O(nlogn),需要O(n)来创建dict