将数组的元素除以 2 k 次,以使数组的总和最小化

迪帕克·米什拉

我有一个由 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 = 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;
    }

我们如何通过使用最大堆或其他一些数据结构来进一步提高性能?

迪帕克·米什拉

由于假设是 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);
    }

列表类:

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;
    }
}

本文收集自互联网,转载请注明来源。

如有侵权,请联系 [email protected] 删除。

编辑于
0

我来说两句

0 条评论
登录 后参与评论

相关文章