C# 除以一个数组';s元素乘以2乘以k,使数组';s和最小
我有一个由n个整数组成的数组,我需要将它的任意元素除以2(返回结果的上限)k次,这样的总和是最小的。与n相比,k的值可能非常大 我正在使用以下代码:C# 除以一个数组';s元素乘以2乘以k,使数组';s和最小,c#,algorithm,linq,data-structures,C#,Algorithm,Linq,Data Structures,我有一个由n个整数组成的数组,我需要将它的任意元素除以2(返回结果的上限)k次,这样的总和是最小的。与n相比,k的值可能非常大 我正在使用以下代码: private static int GetMaxSum(int[] array, int k) { int n = array.Length; for (int i = 0; i < k; i++) { var indexAtMax = GetMaxI
private static int GetMaxSum(int[] array, int k)
{
int n = array.Length;
for (int i = 0; i < k; i++)
{
var indexAtMax = GetMaxIndex(array);
if (array[indexAtMax] == 1) break;
array[indexAtMax] = array[indexAtMax] / 2 + array[indexAtMax] % 2;
}
return array.Sum();
}
private static int GetMaxIndex(int[] array)
{
int maxIndex = 0;
int max = array[0];
for (int i=1; i<array.Length;i++)
{
if (array[i] > max)
{
max = array[i];
maxIndex = i;
}
}
return maxIndex;
}
私有静态int GetMaxSum(int[]数组,int k)
{
int n=数组长度;
for(int i=0;i
我们如何通过使用max heap或其他数据结构进一步提高性能?除非我误解了您的要求,否则您的解决方案看起来太复杂了(根据评论,显然是错误的) 我现在真的想不透,但全局解决方案不是由最优的中间步骤组成吗?你划分的顺序是不相关的,问题是线性的 如果是这种情况,您只需在每个步骤中评估最佳分割,这并不难做到:
static void Minimize(int[] arr, int k)
{
for (var j = 0; j < k; j++)
{
var maxGainIndex = -1;
var maxGain = int.MinValue;
for (var i = 0; i < arr.Length; i++)
{
var gain = arr[i] - (arr[i]/2 + arr[i] % 2);
if (gain > maxGain)
{
maxGain = gain;
maxGainIndex = i;
}
}
arr[maxGainIndex] -= maxGain;
}
}
可在此处找到基准测试代码:
我提出的算法的性能增益相当惊人(x15),这是意料之中的,因为对于这样一个简单的问题,您的解决方案在初始评估时最多过于复杂。由于假设是k>>n,较简单的算法的阶数为O(kn),这可能会导致太多的迭代。 我写这段代码时考虑了这个问题,以及如何限制排序或计算最小/最大值。我将数组划分为子数组,这样就可以在不考虑操作顺序的情况下对子数组执行操作
private static int GetMinSum(int[] array, int k)
{
int n = array.Length;
var sum = 0;
k = GetOptimizedListAndK(array, n, k, out var lists);
//If more sublists are needed
if (k > 0)
{
var count = lists.CountSum;
var key = lists.Key;
if (key > 0)
{
var poweroftwo = 1 << key;
sum += count * poweroftwo - k * poweroftwo / 2;
var dictionary2 = GetDictionary(array, lists, poweroftwo);
key = dictionary2.Keys.Last();
while (k > 0 && key > 0)
{
var list2 = dictionary2[key];
count = list2.Count;
if (k >= count)
{
list2.ForEach(
index => array[index] = array[index] / 2 + array[index] % 2);
dictionary2.Remove(key);
key = dictionary2.Keys.LastOrDefault();
k -= count;
}
else
{
if (k <= Log2(count))
{
for (int i = 0; i < k; i++)
{
var indexAtMax = GetMaxIndex(list2, array);
array[indexAtMax] = array[indexAtMax] / 2 + array[indexAtMax] % 2;
}
k = 0;
}
if (count - k <= Log2(count))
{
var minIndexes = GetMinIndexes(list2, array, count - k);
foreach (var i in list2)
{
if (!minIndexes.Contains(i))
{
array[i] = array[i] / 2 + array[i] % 2;
}
}
k = 0;
}
if (k > 0)
{
poweroftwo = 1 << key;
sum += list2.Count * poweroftwo - k * poweroftwo / 2;
dictionary2 = GetDictionary(array, list2, poweroftwo);
key = dictionary2.Keys.Last();
}
}
}
}
}
return array.Sum() + sum;
}
private static int GetOptimizedListAndK(int[] array, int n, int k, out Lists lists)
{
lists = null;
Dictionary<int, Lists> dictionary = new Dictionary<int, Lists>();
PopulatePowerBasedDictionary(array, n, dictionary);
var key = dictionary.Keys.Max();
while (key > 0 && k > 0)
{
lists = dictionary[key];
var count = lists.CountSum;
if (k >= count)
{
lists.ForEach(list => list.ForEach(index => array[index] = array[index] / 2 + array[index] % 2));
if (key > 1)
{
if (dictionary.TryGetValue(key - 1, out var lowerlists))
{
lowerlists.AddRange(lists);
lowerlists.CountSum += count;
}
else dictionary.Add((key - 1), lists);
}
dictionary.Remove(key);
key--;
k -= count;
}
else
{
if (k < Log2(count))
{
for (int i = 0; i < k; i++)
{
var indexAtMax = GetMaxIndex(lists, array);
array[indexAtMax] = array[indexAtMax] / 2 + array[indexAtMax] % 2;
}
k = 0;
}
if (count - k < Log2(count))
{
var minIndexes = GetMinIndexes(lists, array, count - k);
foreach (var list in lists)
{
foreach (var i in list)
{
if (!minIndexes.Contains(i))
{
array[i] = array[i] / 2 + array[i] % 2;
}
}
}
k = 0;
}
break;
}
}
return k;
}
private static void PopulatePowerBasedDictionary(int[] array, int n, Dictionary<int, Lists> dictionary)
{
for (int i = 0; i < n; i++)
{
if (array[i] < 2) continue;
var log2 = Log2(array[i]);
if (dictionary.TryGetValue(log2, out var lists))
{
lists[0].Add(i);
lists.CountSum++;
}
else
{
lists = new Lists(1,log2) { new List<int> { i } };
dictionary.Add(log2, lists);
}
}
}
private static int GetMaxIndex(List<int> list, int[] array)
{
var maxIndex = 0;
var max = 0;
foreach (var i in list)
{
if (array[i] > max)
{
maxIndex = i;
max = array[i];
}
}
return maxIndex;
}
private static SortedDictionary<int, List<int>> GetDictionary(int[] array, Lists lists, int poweroftwo)
{
SortedDictionary<int, List<int>> dictionary = new SortedDictionary<int, List<int>>();
foreach (var list in lists)
{
foreach (var i in list)
{
array[i] = array[i] - poweroftwo;
if (array[i] < 2)
{
continue;
}
var log2 = Log2(array[i]);
if (dictionary.TryGetValue(log2, out var list2))
{
list2.Add(i);
}
else
{
list2 = new List<int> { i };
dictionary.Add(log2, list2);
}
}
}
return dictionary;
}
private static SortedDictionary<int, List<int>> GetDictionary(int[] array, List<int> list, int poweroftwo)
{
SortedDictionary<int, List<int>> dictionary = new SortedDictionary<int, List<int>>();
foreach (var i in list)
{
array[i] = array[i] - poweroftwo;
if (array[i] < 2)
{
continue;
}
var log2 = Log2(array[i]);
if (dictionary.TryGetValue(log2, out var list2))
{
list2.Add(i);
}
else
{
list2 = new List<int> { i };
dictionary.Add(log2, list2);
}
}
return dictionary;
}
private static int GetMaxIndex(Lists lists, int[] array)
{
var maxIndex = 0;
var max = 0;
foreach (var list in lists)
{
foreach (var i in list)
{
if (array[i]>max)
{
maxIndex = i;
max = array[i];
}
}
}
return maxIndex;
}
private static HashSet<int> GetMinIndexes(Lists lists, int[] array, int k)
{
var mins = new HashSet<int>();
var minIndex = 0;
var min = int.MaxValue;
for (int j = 0; j < k; j++)
{
foreach (var list in lists)
{
foreach (var i in list)
{
if (array[i] < min && !mins.Contains(i))
{
minIndex = i;
min = array[i];
}
}
}
mins.Add(minIndex);
min = int.MaxValue;
}
return mins;
}
private static HashSet<int> GetMinIndexes(List<int> list, int[] array, int k)
{
var mins = new HashSet<int>();
var minIndex = 0;
var min = int.MaxValue;
for (int j = 0; j < k; j++)
{
foreach (var i in list)
{
if (array[i] < min && !mins.Contains(i))
{
minIndex = i;
min = array[i];
}
}
mins.Add(minIndex);
min = int.MaxValue;
}
return mins;
}
private static int Log2(int n)
{
return BitOperations.Log2((uint)n);
}
私有静态int GetMinSum(int[]数组,int k)
{
int n=数组长度;
var总和=0;
k=GetOptimizedListAndK(数组、n、k、out变量列表);
//如果需要更多的子列表
如果(k>0)
{
var count=lists.CountSum;
var key=lists.key;
如果(键>0)
{
var poweroftwo=1 0&&key>0)
{
var list2=字典2[key];
count=list2.count;
如果(k>=计数)
{
列表2.ForEach(
index=>array[index]=array[index]/2+array[index]%2);
字典2.移除(键);
key=dictionary2.Keys.LastOrDefault();
k-=计数;
}
其他的
{
if(k0)
{
列表=字典[键];
var count=lists.CountSum;
如果(k>=计数)
{
lists.ForEach(list=>list.ForEach(index=>array[index]=array[index]/2+array[index]%2));
如果(键>1)
{
if(dictionary.TryGetValue(键-1,out var lowerlists))
{
lowerlists.AddRange(列表);
lowerlists.CountSum+=计数;
}
添加((键-1),列表);
}
删除(键);
键--;
k-=计数;
}
其他的
{
如果(kmax)
{
maxIndex=i;
max=数组[i];
}
}
返回最大索引;
}
私有静态SortedDictionary GetDictionary(int[]数组,列表,int-poweroftwo)
{
SortedDictionary=新的SortedDictionary();
foreach(列表中的变量列表)
{
foreach(列表中的变量i)
{
数组[i]=数组[i]-幂函数
private static int GetMinSum(int[] array, int k)
{
int n = array.Length;
var sum = 0;
k = GetOptimizedListAndK(array, n, k, out var lists);
//If more sublists are needed
if (k > 0)
{
var count = lists.CountSum;
var key = lists.Key;
if (key > 0)
{
var poweroftwo = 1 << key;
sum += count * poweroftwo - k * poweroftwo / 2;
var dictionary2 = GetDictionary(array, lists, poweroftwo);
key = dictionary2.Keys.Last();
while (k > 0 && key > 0)
{
var list2 = dictionary2[key];
count = list2.Count;
if (k >= count)
{
list2.ForEach(
index => array[index] = array[index] / 2 + array[index] % 2);
dictionary2.Remove(key);
key = dictionary2.Keys.LastOrDefault();
k -= count;
}
else
{
if (k <= Log2(count))
{
for (int i = 0; i < k; i++)
{
var indexAtMax = GetMaxIndex(list2, array);
array[indexAtMax] = array[indexAtMax] / 2 + array[indexAtMax] % 2;
}
k = 0;
}
if (count - k <= Log2(count))
{
var minIndexes = GetMinIndexes(list2, array, count - k);
foreach (var i in list2)
{
if (!minIndexes.Contains(i))
{
array[i] = array[i] / 2 + array[i] % 2;
}
}
k = 0;
}
if (k > 0)
{
poweroftwo = 1 << key;
sum += list2.Count * poweroftwo - k * poweroftwo / 2;
dictionary2 = GetDictionary(array, list2, poweroftwo);
key = dictionary2.Keys.Last();
}
}
}
}
}
return array.Sum() + sum;
}
private static int GetOptimizedListAndK(int[] array, int n, int k, out Lists lists)
{
lists = null;
Dictionary<int, Lists> dictionary = new Dictionary<int, Lists>();
PopulatePowerBasedDictionary(array, n, dictionary);
var key = dictionary.Keys.Max();
while (key > 0 && k > 0)
{
lists = dictionary[key];
var count = lists.CountSum;
if (k >= count)
{
lists.ForEach(list => list.ForEach(index => array[index] = array[index] / 2 + array[index] % 2));
if (key > 1)
{
if (dictionary.TryGetValue(key - 1, out var lowerlists))
{
lowerlists.AddRange(lists);
lowerlists.CountSum += count;
}
else dictionary.Add((key - 1), lists);
}
dictionary.Remove(key);
key--;
k -= count;
}
else
{
if (k < Log2(count))
{
for (int i = 0; i < k; i++)
{
var indexAtMax = GetMaxIndex(lists, array);
array[indexAtMax] = array[indexAtMax] / 2 + array[indexAtMax] % 2;
}
k = 0;
}
if (count - k < Log2(count))
{
var minIndexes = GetMinIndexes(lists, array, count - k);
foreach (var list in lists)
{
foreach (var i in list)
{
if (!minIndexes.Contains(i))
{
array[i] = array[i] / 2 + array[i] % 2;
}
}
}
k = 0;
}
break;
}
}
return k;
}
private static void PopulatePowerBasedDictionary(int[] array, int n, Dictionary<int, Lists> dictionary)
{
for (int i = 0; i < n; i++)
{
if (array[i] < 2) continue;
var log2 = Log2(array[i]);
if (dictionary.TryGetValue(log2, out var lists))
{
lists[0].Add(i);
lists.CountSum++;
}
else
{
lists = new Lists(1,log2) { new List<int> { i } };
dictionary.Add(log2, lists);
}
}
}
private static int GetMaxIndex(List<int> list, int[] array)
{
var maxIndex = 0;
var max = 0;
foreach (var i in list)
{
if (array[i] > max)
{
maxIndex = i;
max = array[i];
}
}
return maxIndex;
}
private static SortedDictionary<int, List<int>> GetDictionary(int[] array, Lists lists, int poweroftwo)
{
SortedDictionary<int, List<int>> dictionary = new SortedDictionary<int, List<int>>();
foreach (var list in lists)
{
foreach (var i in list)
{
array[i] = array[i] - poweroftwo;
if (array[i] < 2)
{
continue;
}
var log2 = Log2(array[i]);
if (dictionary.TryGetValue(log2, out var list2))
{
list2.Add(i);
}
else
{
list2 = new List<int> { i };
dictionary.Add(log2, list2);
}
}
}
return dictionary;
}
private static SortedDictionary<int, List<int>> GetDictionary(int[] array, List<int> list, int poweroftwo)
{
SortedDictionary<int, List<int>> dictionary = new SortedDictionary<int, List<int>>();
foreach (var i in list)
{
array[i] = array[i] - poweroftwo;
if (array[i] < 2)
{
continue;
}
var log2 = Log2(array[i]);
if (dictionary.TryGetValue(log2, out var list2))
{
list2.Add(i);
}
else
{
list2 = new List<int> { i };
dictionary.Add(log2, list2);
}
}
return dictionary;
}
private static int GetMaxIndex(Lists lists, int[] array)
{
var maxIndex = 0;
var max = 0;
foreach (var list in lists)
{
foreach (var i in list)
{
if (array[i]>max)
{
maxIndex = i;
max = array[i];
}
}
}
return maxIndex;
}
private static HashSet<int> GetMinIndexes(Lists lists, int[] array, int k)
{
var mins = new HashSet<int>();
var minIndex = 0;
var min = int.MaxValue;
for (int j = 0; j < k; j++)
{
foreach (var list in lists)
{
foreach (var i in list)
{
if (array[i] < min && !mins.Contains(i))
{
minIndex = i;
min = array[i];
}
}
}
mins.Add(minIndex);
min = int.MaxValue;
}
return mins;
}
private static HashSet<int> GetMinIndexes(List<int> list, int[] array, int k)
{
var mins = new HashSet<int>();
var minIndex = 0;
var min = int.MaxValue;
for (int j = 0; j < k; j++)
{
foreach (var i in list)
{
if (array[i] < min && !mins.Contains(i))
{
minIndex = i;
min = array[i];
}
}
mins.Add(minIndex);
min = int.MaxValue;
}
return mins;
}
private static int Log2(int n)
{
return BitOperations.Log2((uint)n);
}
public class Lists:List<List<int>>
{
public int Key { get; set; }
public int CountSum { get; set; }
public Lists(int countSum, int key):base()
{
CountSum = countSum;
Key = key;
}
}