面试题57 - II. 和为s的连续正数序列
解
方法一:暴力法
注意上界为
⌊
t
a
r
g
e
t
2
⌋
\lfloor \frac{target}{2} \rfloor
⌊2target⌋即可
class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
vector<vector<int>>ret;
vector<int>temp;
int sum = 0, n = (int)(target / 2);
for (int i = 1; i <= n; i++) {
for (int j = i;; j++) {
sum += j;
if (sum > target) {
sum = 0;
break;
} else if (sum == target) {
temp.clear();
for (int k = i; k <= j; k++) {
temp.emplace_back(k);
}
ret.emplace_back(temp);
sum = 0;
break;
}
}
}
return ret;
}
};
方法二:数学法
x到y累加和为
(
x
+
y
)
×
(
y
−
x
+
1
)
2
\frac{(x+y)×(y-x+1)}{2}
2(x+y)×(y−x+1),他要满足
(
x
+
y
)
×
(
y
−
x
+
1
)
2
=
t
a
r
g
e
t
\frac{(x+y)×(y-x+1)}{2}=target
2(x+y)×(y−x+1)=target
化简一下得到
y
2
+
y
−
x
2
+
x
−
2
×
t
a
r
g
e
t
=
0
y^2+y−x^2+x−2×target=0
y2+y−x2+x−2×target=0
这是一个关于y的一元二次方程
它要满足以下两个条件
- Δ \sqrt\Delta Δ为整数
- 根为整数
class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
vector<vector<int>>ret;
vector<int>temp;
int sum = 0, n = (int)(target / 2);
for (int x = 1; x <= n; x++) {
long long delta = 1 - 4 * (-1ll * x * x + x - 2 * target);//防止溢出
if (delta < 0) {
continue;
}
int d_sqrt = (int)sqrt(delta + 0.5);//防止精度损失
if (1ll * d_sqrt * d_sqrt == delta && (d_sqrt - 1) % 2 == 0) {
int y = (-1 + d_sqrt) / 2;
if (x < y) {
temp.clear();
for (int i = x; i <= y; i++) {
temp.emplace_back(i);
}
ret.emplace_back(temp);
}
}
}
return ret;
}
};
方法二改进
我们可以设两数距离
i
=
y
−
x
i=y-x
i=y−x,求和公式化为
(
2
x
+
i
)
×
(
i
+
1
)
2
=
t
a
r
g
e
t
\frac{(2x+i)×(i+1)}{2}=target
2(2x+i)×(i+1)=target
化简得
2
x
i
+
2
x
+
i
2
+
i
=
2
t
2xi+2x+i^2+i=2t
2xi+2x+i2+i=2t
再得
x
=
t
−
i
(
i
+
1
)
2
i
+
1
x=\frac{t-\frac{i(i+1)}{2}}{i+1}
x=i+1t−2i(i+1)
得到两个条件
- t > i ( i + 1 ) 2 t>\frac{i(i+1)}{2} t>2i(i+1)
- x为整数
class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
vector<vector<int>>ret;
vector<int>temp;
for (int i = 1; i * (i + 1) / 2 < target; i++) {
if ((target - i * (i + 1) / 2) % (i + 1) == 0) {
int x = (int)((target - i * (i + 1) / 2) / (i + 1));
int y = x + i;
temp.clear();
for (int k = x; k <= y; k++) {
temp.emplace_back(k);
}
ret.emplace_back(temp);
}
}
reverse(ret.begin(), ret.end());
return ret;
}
};
这个可以达到双百
方法三:双指针
class Solution {
public:
vector<vector<int>> findContinuousSequence(int target) {
vector<vector<int>>ret;
vector<int>temp;
int left = 1, right = 2;
while (left < right) {
int sum = (left + right) * (right - left + 1) / 2;
if (sum == target) {
temp.clear();
for (int i = left; i <= right; i++) {
temp.emplace_back(i);
}
ret.emplace_back(temp);
left++;
} else if (sum < target) {
right++;
} else {
left++;
}
}
return ret;
}
};