c++ - 偶数和奇数位置元素之和的最大差值 : How to memoize the brute-force approach?

标签 c++ algorithm dynamic-programming backtracking memoization

我有以下代码来解决一个问题。

问题是: 最大化数组奇数和偶数位置元素之和的绝对差。 为此,您可以删除您想要多少元素。

我是通过使用回溯法通过蛮力完成的。我的逻辑是,对于每个索引,我有 2 个选项: a) 要么删除它(在这种情况下,我把它放在一个集合中) b) 不要删除它(在这种情况下,我从集合中删除索引并回溯)。 我取了两种情况的局部最大值并适本地更新了全局最大值。

void maxAns(vector<int> &arr, int index, set<int> &removed, int &res)
{
    if (index<0)
        return;
    int k=0;
    int s3=0,s4=0;
    for (int i=0;i<arr.size();i++)
    {
        if (i!=index)
        {
            set<int>::iterator it=removed.find(i);
            if (it==removed.end())
            {
                if( k%2==0)
                    s3+=arr[i];
                else
                    s4+=arr[i];
                k++;
            }
        }
        else    //don't delete the element
        {
            if (k%2==0)
                s3+=arr[i];
            else
                s4+=arr[i];
            k++;
        }
    }

    k=0;
    int s1=0, s2=0;
    for (int i=0;i<arr.size();i++)
    {
        if (i!=index)
        {
            set<int>::iterator it=removed.find(i);
            if (it==removed.end())
            {
                if (k%2==0)
                    s1+=arr[i];
                else
                    s2+=arr[i];
                k++;
            }
        }
        else    //delete the element
        {
            //add index into the removed set
            removed.insert(index);
        }
    }

    //delete the index element
    int t1=abs(s1-s2);
    maxAns(arr,index-1,removed,res);

    //don't delete the index element, and then backtrack
    set<int>::iterator itr=removed.find(index);
    removed.erase(itr);

    int t2=abs(s3-s4);
    maxAns(arr,index-1,removed,res);

    //choose the max value
    res=max(res,max(t1,t2));
}

请建议如何内存这个解决方案,因为我认为它效率很低。欢迎分享任何有趣的方法。

最佳答案

提示:分而治之。考虑一个固定长度的列表作为一个更大列表的左侧部分,最大化(或最小化)实际的,而不是绝对差异并且取决于其长度的奇偶校验,将更好地与不依赖于的右侧部分配对其长度的奇偶校验。

[0,3] ++ [0,3]    -> diff -3 -3 = -6
[0,3] ++ [9,13,1] -> diff -3 -3 = -6

我们还可以轻松地为长度为 1 和 2 的列表的 max_actual_diffmin_actual_diff 创建基本情况。请注意,对这些情况的最佳选择可能包括省略一个或多个那几个元素。

JavaScript 代码:

function max_diff(A, el, er, memo){
  if (memo[['mx', el, er]])
    return memo[['mx', el, er]]
  
  if (er == el)
    return memo[['mx', el, er]] = [A[el], 1, 0, 0]

  var best = [A[el], 1, 0, 0]
  
  if (er == el + 1){
    if (A[el] - A[er] > best[2]){
      best[2] = A[el] - A[er]
      best[3] = 2
    }
    if (A[er] > best[0]){
      best[0] = A[er]
      best[1] = 1
    }
    
    return memo[['mx', el, er]] = best
  }
  
  const mid = el + ((er - el) >> 1)

  const left = max_diff(A, el, mid, memo)
  const right_min = min_diff(A, mid + 1, er, memo)
  const right_max = max_diff(A, mid + 1, er, memo)
  
  // Best odd = odd + even
  if (left[0] - right_min[2] > best[0]){
    best[0] = left[0] - right_min[2]
    best[1] = left[1] + right_min[3]
  }
  // Best odd = even + odd
  if (left[2] + right_max[0] > best[0]){
    best[0] = left[2] + right_max[0]
    best[1] = left[3] + right_max[1]
  }
  
  // Best even = odd + odd
  if (left[0] - right_min[0] > best[2]){
    best[2] = left[0] - right_min[0]
    best[3] = left[1] + right_min[1]
  }
  // Best even = even + even
  if (left[2] + right_max[2] > best[2]){
    best[2] = left[2] + right_max[2]
    best[3] = left[3] + right_max[3]
  }
    
  return memo[['mx', el, er]] = best
}

function min_diff(A, el, er, memo){
  if (memo[['mn', el, er]])
    return memo[['mn', el, er]]
  
  if (er == el)
    return memo[['mn', el, er]] = [A[el], 1, 0, 0]

  var best = [A[el], 1, 0, 0]
  
  if (er == el + 1){
    if (A[el] - A[er] < best[2]){
      best[2] = A[el] - A[er]
      best[3] = 2
    }
    if (A[er] < best[0]){
      best[0] = A[er]
      best[1] = 1
    }
    
    return memo[['mn', el, er]] = best
  }
  
  const mid = el + ((er - el) >> 1)

  const left = min_diff(A, el, mid, memo)
  const right_min = min_diff(A, mid + 1, er, memo)
  const right_max = max_diff(A, mid + 1, er, memo)
  
  // Best odd = odd + even
  if (left[0] - right_max[2] < best[0]){
    best[0] = left[0] - right_max[2]
    best[1] = left[1] + right_max[3]
  }
  // Best odd = even + odd
  if (left[2] + right_min[0] < best[0]){
    best[0] = left[2] + right_min[0]
    best[1] = left[3] + right_min[1]
  }
  
  // Best even = odd + odd
  if (left[0] - right_max[0] < best[2]){
    best[2] = left[0] - right_max[0]
    best[3] = left[1] + right_max[1]
  }
  // Best even = even + even
  if (left[2] + right_min[2] < best[2]){
    best[2] = left[2] + right_min[2]
    best[3] = left[3] + right_min[3]
  }
    
  return memo[['mn', el, er]] = best
}


var memo = {}

var A = [1, 2, 3, 4, 5]
console.log(`A: ${ JSON.stringify(A) }`)
console.log(
  JSON.stringify(max_diff(A, 0, A.length-1, memo)) + ' // [odd max, len, even max, len]')
console.log(
  JSON.stringify(min_diff(A, 0, A.length-1, memo)) + ' // [odd min, len, even min, len]')
console.log('\nmemo:\n' + JSON.stringify(memo))

关于c++ - 偶数和奇数位置元素之和的最大差值 : How to memoize the brute-force approach?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/57716907/

相关文章:

寻找趋势 block 的算法

java - 查找直方图中的所有矩形

c++ - 复合文字并通过GCC在C++中通过引用传递?

c++ - C++ 基础知识与 Arduino

c++ - 如何在 Windows 上检测 USB 速度

c++ - QListView 模型用户界面

algorithm - 你将如何着手解决这个问题?

algorithm - 在说谎者-真相出纳员问题中解决说谎者的上限和下限

algorithm - 计算迷宫中唯一路径的数量

algorithm - 如何计算通过网格的路径时的最高分?