1. 题目来源
前置题:
- xxx
题单:
- 待补充
2. 题目解析
2025年03月27日00:01:32
方法一:贪心模拟
- 依据两数之和的思想,从 i=1 开始填,总共需要填 n 个数。
- 如果当前的 i 不可用,那就一直 i++,找到一个可用的 i
- 如果 k < i 就把 k-i 标记为不可用,因为此时 i 是被选中的数,对应的 k-i 就不可被选。
- 累计答案即可。
这个贪心模拟的思路很不错哈,能够快速解决本题。一开始想的时候想到了二数之和,但没有考虑到这个写法。
方法二:数学解法
显然本题有数学解法,自己在考虑写的时候也是往这边在想,最终并没有推导的很完善吧,在一些边界情况下没有统一处理,还是分情况讨论的。当时的思路是
- 通过双指针找到构成 k 的两个最近的数对,比如 7: {1,6},{2,5},{3,4} 那么就需要找到 {3,4} 这个数对。
- 因为 4 及它后面的所有数 都要进行累加,这个累加的幅度就是 3。此时 4 应该从 7 开始,因为如果从 6 开始是没有意义的,{1,6} 仍然会等于 k。所以需要在最近的这个数对作为分界点,将后续的数字进行累加。就可以了。
这里有一些奇偶性的判断吧,比如
- n = 5, K=6 就可以有 {1,5}, {2,4}, {3, 3}… 那么肯定就是 {1,2,3,6,7}, k//2 = 3
- n=5,K=5 就可以有 {1,4}, {2,3},那么肯定就是 {1,2,5,6,7}, k // 2 = 2
这个分界点的位置就很关键,记为 m
- m = min(k//2, n) k 的下取整。这里可能 k 很大,即便 k 除二后仍旧大于 n,那么 n 就是分界点。
- 那么数组就被分成 1,2,3,…,m、k,k+1,k+2,…,k+n-m-1
- 两段等差数列求和公式即可计算,(首项+尾项)*(项数)/ 2 即可。
- 时间复杂度: O ( 1 ) O(1) O(1)
- 空间复杂度: O ( 1 ) O(1) O(1) 返回值不计算
方法一:贪心模拟
func minimumSum(n int, k int) int {
res := 0
m := map[int]bool{}
i := 1
for n > 0 {
for m[i] {
i ++
}
if k > i {
m[k - i] = true
}
res += i
i ++
n --
}
return res
}
方法二:数学公式
func minimumSum(n int, k int) int {
m := min(k / 2, n)
return (1 + m) * m / 2 + (k + k + n - m - 1) * (n - m) / 2
}