今天中午去剪头发了,这家店不推销卡、不尬聊,全程舒适又愉快,今天顺心的事一件接一件呢~--2021年4月7日
目录
题目描述:
给出一个整数数组,请在数组中找出两个加起来等于目标值的数,
你给出的函数twoSum 需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2.。注意:下标是从1开始的,假设给出的数组中只存在唯一解
例如,给出的数组为 {3, 7, 8, 9, 5, 12, 10},目标值为16,输出 index1=2, index2=4
例(更多博文,欢迎来我的博客学习交流https://blog.csdn.net/have_a_cat)
输入:[3,7,8,9,5,12,10],16
输出:[2,4]
(这是牛客网提供的一道题目,想尝试的码友们,可以通过这个链接挑战https://www.nowcoder.com/practice/20ef0972485e41019e39543e8e895b7f?tpId=188&tqId=38285&rp=1&ru=%2Factivity%2Foj&qru=%2Fta%2Fjob-code-high-week%2Fquestion-ranking&tab=answerKey)
分析
这道题目比较有趣,推出“后指针摇摆法”~(我自己起的名字,请大家将就看下😀)
分为五个步骤:
题目给出数组为numbers,,目标值为target。
numbers=[3,7,8,9,5,12,10]
target=16
步骤一
复制数组numbers到f。(为了接下来做的操作不破坏题目给出的numbers)
f=[3,7,8,9,5,12,10]
步骤二
对f排序(这里使用系统自带的sort函数)
f=[3,5,7,8,9,10,12]
步骤三
在f中找这两个整数(设为f[i]和f[j]),使f[i]+f[j]== target(这里就用到了“后指针摇摆法”)
先来看下这个思想(一时不懂不要紧,随后就来例子演示):
思想:
●初始--i为0,即f[i]为f的第一个数,也是f中最小的数;j为f.size() - 1;,即f[j]为f中的最后一个数,也是f中最大的数;
●i由0依次递增1,即由小到大遍历f中的每一个数;(更多博文,欢迎来我的博客学习交流https://blog.csdn.net/have_a_cat)
●对每一个f[i],
若(f[i]+f[j]) < target,则j++(使f[j]更大一些,使(f[i]+f[j])更靠近target)
若(f[i]+f[j]) > target,则j--(使f[j]更小一些,使(f[i]+f[j])更靠近target)
若(f[i]+f[j]) == target,则进入步骤四
核心代码段:
①int i = 0;
②int j = f.size() - 1;
③while( (2 * f[i]) < (target + 1))
{
④while(((f[i] + f[j]) < target)&&(j < (f.size() - 1)))
{
⑤j++;
}
⑥while(((f[i] + f[j]) > target)&&(j > i))
{/*(更多博文,欢迎来我的博客学习交流https://blog.csdn.net/have_a_cat)*/
⑦j--;
}
⑧if((f[i] + f[j]) == target)
{
⑨break;
}
⑩i++;
}
例子演示:
| numbers | target | 备注 | 执行的代码的序号 |
第1步 | [3,5,7,8,9,10,12] | 16 |
| 初始 |
第2步 | [i->3,5,7,8,9,10,12] | 16 |
| ① |
第3步 | [i->3,5,7,8,9,10, j->12] | 16 |
| ② |
第4步 | [i->3,5,7,8,9,10, j->12] | 16 | (2*3)<(16+1) -->√ | ③ |
第5步 | [i->3,5,7,8,9,10, j->12] | 16 | f[i]+f[j])<target;j已最右 | ④ |
第6步 | [i->3,5,7,8,9,10, j->12] | 16 | f[i]+f[j])!>target | ⑥ |
第7步 | [i->3,5,7,8,9,10, j->12] | 16 | f[i]+f[j])!=target | ⑧ |
第8步 | [3, i->5,7,8,9,10, j->12] | 16 | i++ | ⑩ |
第9步 | [3, i->5,7,8,9,10, j->12] | 16 | (2*5)<(16+1) -->√ | ③ |
第10步 | [3, i->5,7,8,9,10, j->12] | 16 | f[i]+f[j])!<target | ④ |
第11步 | [3, i->5,7,8,9,10, j->12] | 16 | f[i]+f[j])>target | ⑥ |
第12步 | [3, i->5,7,8,9, j->10, 12] | 16 | j-- | ⑦ |
第13步 | [3, i->5,7,8,9, j->10, 12] | 16 | f[i]+f[j])!=target | ⑧ |
第14步 | [3, 5, i->7,8,9, j->10, 12] | 16 | i++ | ⑩ |
第15步 | [3, 5, i->7,8,9, j->10, 12] | 16 | (2*7)<(16+1) -->√ | ③ |
第16步 | [3, 5, i->7,8,9, j->10, 12] | 16 | f[i]+f[j])!<target | ④ |
第17步 | [3, 5, i->7,8,9, j->10, 12] | 16 | f[i]+f[j])>target | ⑥ |
第18步 | [3, 5, i->7,8, j->9, 10, 12] | 16 | j-- | ⑦ |
第19步 | [3, 5, i->7,8, j->9, 10, 12] | 16 | f[i]+f[j])==target | ⑧ |
第20步 | [3, 5, i->7,8, j->9, 10, 12] | 16 | break | ⑨ |
看下j的轨迹,来回小范围摇摆,故我起名 “后指针摇摆法”
步骤四
找到 f[i] 和 f[j]在number中的位置,用num_i记录数字f[i] 在number中的位置;用num_j记录数字f[j] 在number中的位置.
步骤五
把num_i、num_j放入数组result;中。
对result排序(这里使用系统自带的sort函数)【注意!!!题目这里说过:“需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2”】
返回result。(更多博文,欢迎来我的博客学习交流https://blog.csdn.net/have_a_cat)
C++代码
class Solution {
public:
/**
*
* @param numbers int整型vector
* @param target int整型
* @return int整型vector
*/
vector<int> twoSum(vector<int>& numbers, int target) {
// write code here
/*1 复制数组numbers到f*/
vector<int> f(numbers.begin(),numbers.end());
/*2 对f排序(更多博文,欢迎来我的博客学习交流https://blog.csdn.net/have_a_cat)*/
sort(f.begin(), f.end());
/*3 在f中找这两个整数*/
int i = 0;
int j = f.size() - 1;
while( (2 * f[i]) < (target + 1))
{
while(((f[i] + f[j]) < target)&&(j < (f.size() - 1)))
{
j++;
}
while(((f[i] + f[j]) > target)&&(j > i))
{
j--;
}
if((f[i] + f[j]) == target)
{
break;
}
i++;
}
/*4 找到 f[i] 和 f[j]在number中的位置(更多博文,欢迎来我的博客学习交流https://blog.csdn.net/have_a_cat)*/
int num_i = 0;
int num_j = 0;
for(int q = 0; q < numbers.size(); q++)
{
if((f[i] == numbers[q])&&(num_i == 0))
{
num_i = q + 1;
}
else{
if((f[j] == numbers[q])&&(num_j == 0))
{
num_j = q + 1;
}
}
}
/*5 将num_i、num_j放入输出*/
vector<int> result;
result.push_back(num_i);
result.push_back(num_j);
sort(result.begin(),result.end());/*需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2.(更多博文,欢迎来我的博客学习交流https://blog.csdn.net/have_a_cat)*/
return result;
}
};
踩过的坑
踩坑(一)
输入:[0,4,3,0],0
输出:[1,4](更多博文,欢迎来我的博客学习交流https://blog.csdn.net/have_a_cat)
反思:这里结果是0+0==0;所以要注意步骤四中对相同数字的处理。
踩坑(二)
输入:[5,75,25],100
输出:[2,3]
反思:步骤五中要对result排序,因为题目说“需要返回这两个数字的下标(index1,index2),需要满足 index1 小于index2”