中等题:和的逆运算问题(cpp) | 豆包MarsCode AI刷题

33 阅读3分钟

问题描述:n 个整数两两相加可以得到 n(n - 1) / 2 个和。我们的目标是:根据这些和找出原来的 n 个整数。
按非降序排序返回这 n 个数,如果无解,输出 "Impossible"。

问题分析:一开始想的时候在想可不可以通过枚举的方法倒推回我们需要的数字,于是将想法喂给AI,得到思路提示:

    sums.sort()
    result = []

    def find_numbers(sums, result):
        if not sums:
            return result
        
        smallest_sum = sums[0]
        
        # 尝试推导出新的整数
        # 这里需要根据 sums 和 result 的关系进行推导
        # 例如,如果 result 为空,那么 smallest_sum 可能是两个相同整数的和
        # 如果 result 不为空,那么 smallest_sum 可能是 result 中两个整数的和
        
        # 验证推导出的整数是否满足所有 sums
        # 如果满足,继续递归推导
        # 如果不满足,返回 "Impossible"
        
        return "Impossible"
    
    result = find_numbers(sums, result)
    
    if result == "Impossible":
        return "Impossible"
    else:
        return " ".join(map(str, result))

我们从任意的三个数a1,a2,a3展开列举,可以得到

  • sum1=a1+a2
  • sum2=a2+a3
  • sum3=a3+a4

共三种和便可列举出我们需要的数字

数据结构选择

  • vector:用于存储 sums 和推导出的 x 列表。
  • string:用于存储最终的结果。

算法步骤

  1. 枚举所有排列

    • 使用 next_permutation 函数生成 sums 的所有排列。
  2. 推导 x1

    • 根据 sums[0]sums[1] 和 sums[n-1] 推导出 x1
    • 公式:x1 = (sums[0] + sums[1] - sums[n-1]) / 2
  3. 推导其他 xi

    • 利用 x1 和 sums 中的值推导出其他 xi
    • 公式:xi = sums[i] - x1
  4. 验证 xi 和 xj

    • 验证推导出的 xi 和 xj 是否满足所有 sums 条件。
    • 遍历所有 xi 和 xj 的组合,检查它们的和是否等于对应的 sums 值。
  5. 返回结果

    • 如果验证通过,返回排序后的 x 列表。
    • 如果所有排列都不满足,返回 "Impossible"。

上代码!!

#include <bits/stdc++.h>
using namespace std;

string solution(int n, vector<int> sums) {
    // 枚举 sums 的所有排列
    sort(sums.begin(), sums.end());
    do {
        // 利用 sums 前面3个值推导出 x1
        // sums[0] 是 x1 + x2, sums[1] 是 x1 + x3, sums[n-1] 是 x2 + x3
        int x1 = (sums[0] + sums[1] - sums[n-1]) / 2;
  
        // 利用 x1 来推导其他的 xi
        vector<int> x = {x1};
        for (int i = 0; i < n-1; ++i) {
            int xi = sums[i] - x1;
            x.push_back(xi);//在末尾添加xi
        }
        
        // 验证 xi 和 xj 是否满足所有 sums 条件
        int index = 0;
        bool flag = true;
        for (int i = 0; i < n; ++i) {
            for (int j = i+1; j < n; ++j) {
                if (x[i] + x[j] != sums[index]) {
                    flag = false;
                    break;
                }
                index += 1;
            }
            if (!flag) {
                break;
            }
        }
        
        // 如果验证通过,返回结果
        if (flag) {
            sort(x.begin(), x.end());
            string result;
            for (int num : x) {
                result += to_string(num) + " ";
            }
            result.pop_back(); // 去掉最后一个空格
            return result;
        }
    } while (next_permutation(sums.begin(), sums.end()));
    
    // 如果所有排列都不满足,返回 "Impossible"
    return "Impossible";
}

int main() {
    // 测试用例

    return 0;
}

(代码为与marscode A协同完成的)\

详细解析

  • 排列生成:为了满足非降序排列,开始一定要sort一下值。我不知道c++中有没有可以像pythonitertools.permutations函数一样直接生成数的排列的函数,于是问了一下AI,使用next_permutation函数生成了sums的所有排列,next_permutation(BidirIt first,BidirIt last),first和last为迭代的范围,可以生成sums的第一个数到最后一个数这个数列的所有数的组合
  • 推导x1:见代码批注
  • 推导其他xi:利用x1和sums中的值可推导出其他的xi,即将别的和减去这个x1的值得到其他x2,x3...并加入x的栈中
  • 验证xi和xj是否符合sums条件
  • 返回结果result

总结

本质上是一个数学组合问题,如何找出不同排列的