题解 | #和为S的连续正数序列#采用数的分解求解,T(n)理论为O(n/2)
和为S的连续正数序列
http://www.nowcoder.com/practice/c451a3fd84b64cb19485dad758a55ebe
例子
100=2×50(因为两个都是偶数,无法找出=100的序列。如最接近的也是50+51=101.)
100=4×25(因为25为奇数,可以分为(12,13)、(11,14)、(10,15)、(9,16),又因为需要4个25,所以这四个对刚好满足。即[9, 16]成立。)
100=5×20(因为5为奇数,因此可以从20开始,依次往前后加入(5-1)/2个数。即[18, 22]成立。)
规律:
for(i从2到sum/2){
if(sum不能被i整除) continue;
a=n/i;// 即上方的50/25/20等
if(i为奇数)// 对应上方5×20
从a开始,往两边扩(i-1)/2个;
else// i为偶数,对应上方1、 2情况
if(a为偶数) continue;// 对应情况1,不能是两个偶数
else 从a/2和(a/2)+1开始,向两边扩充找i个。对应情况2.
}
} 注意:
- 不能被2整除的特殊情况,即sum=1or2or3,单独考虑。因为如果进入下方的for,因为无法被sum/2以下的值除尽,所以找不到有效情况,但实际上3有成立情况[1,2];
- 往两边扩的时候不能扩到复数,如100不能有从负开始的情况。
代码:
vector<vector<int> > FindContinuousSequence(int sum) {
int s = 0;
vector<int> nums;
vector<vector<int> > v_all_path;
map<int, vector<int> > m_all_path;
if(sum <= 2){
return v_all_path;
}
// 若无法被2整除,则需要加上sum/2及sum/2 + 1
if(sum % 2 == 1){
nums.push_back(sum / 2);
nums.push_back(sum / 2 + 1);
m_all_path[nums[0]] = nums;
nums.clear();
}
for(int i = 2; i <= sum / 2; i++){// 一开始选择sqrt是因为超过了会重复。但对于15来说,÷5=3的情况和÷3=5的情况不同,需要对称考虑所以改为sum/2
if(sum % i){// 无法i整除
continue;
}
int quotient = sum / i;// 商
if(i % 2){// 为奇数
if((quotient - ((i - 1) / 2)) <= 0){// 超过下界0的序列不考虑
continue;
}
nums.push_back(quotient);
for(int j = 1; j <= (i - 1) / 2; j++){
nums.insert(nums.begin(), quotient - j);
nums.push_back(quotient + j);
}
m_all_path[nums[0]] = nums;
nums.clear();
}
else{// 为偶数
if(!(quotient % 2))// 两个都为偶数,无法分割
continue;
int begin = quotient / 2;
int end = quotient / 2 + 1;
if((begin - i + 1) <= 0){// 同上,超过下界0的序列不考虑
continue;
}
for(int j = 0; j < i; j++){// 加i组,每组的和=quotient
nums.insert(nums.begin(), begin - j);
nums.push_back(end + j);
}
m_all_path[nums[0]] = nums;
nums.clear();
}
}
for(map<int, vector<int> >::iterator it = m_all_path.begin();
it != m_all_path.end(); it++){
v_all_path.push_back(it->second);
}
return v_all_path;
} 分析:
T(n)=O(n/2),因为只需要判断sum/2。S(n)=O(1)(存储路径不考虑)。
查看13道真题和解析