快慢指针
原地修改数组元素
26. 删除有序数组中的重复项 - 力扣(LeetCode)这里我们选择用两种解法,第一种是用map去重,然后将值依次赋给nums;第二种是用快慢指针的思想
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
/*第一种:map*/
map<int,int> m;
int len=nums.size();
for(int i=0;i<len;i++){
m[nums[i]]=1;
}
int cnt=0;
for(auto i:m){
nums[cnt++]=i.first;
}
return cnt;
}
};
class Solution {
public:
int removeDuplicates(vector<int>& nums) {
/*第二种:快慢指针*/
int len=nums.size();
int left=0;
int right=1;
while(right<len){
if(nums[left]==nums[right]){right++;}
else{
left++;
nums[left]=nums[right];
right++;
}
}
return left+1;
}
};
27. 移除元素 - 力扣(LeetCode) 思想与第一题一致,因为限制空间,所以没法用map去重(并且数组无序),请一定要注意双指针思想,因为当数组长度很大时,这个方法就显得尤为重要!
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
int len=nums.size();
int left=0;
int right=0;
while(right<len){
if(nums[right]==val){right++;}
else{
nums[left]=nums[right];
left++;
right++;
}
}
return left;
}
};
283. 移动零 - 力扣(LeetCode)真的不要太简单~,原地修改数组,请用双指针,当这种思想用到了别的题目时,记得会用哦
class Solution {
public:
void moveZeroes(vector<int>& nums) {
/*是不是就是原地修改数组类型,双指针!*/
int len=nums.size();
int left=0;
int right=0;
while(right<len){
if(nums[right]==0){right++;}
else{
nums[left]=nums[right];
left++;
right++;
}
}
for(int i=left;i<len;i++){
nums[i]=0;
}
}
};
滑动窗口(过几日回来补)
明天继续更左右指针~
左右指针
二分(过几日回来补)
两数之和
思路真的很巧妙,左指针指向最左面,右指针指向最右面,两数之和大于关键值,说明右面的数大了;两数之和小于关键值,说明左面的数小了
class Solution {
public:
vector<int> twoSum(vector<int>& numbers, int target) {
vector<int> res;
int left=0;
int len=numbers.size();
int right=len-1;
while(numbers[left]+numbers[right]!=target){
if(numbers[left]+numbers[right]>target){
right--;
}
else{
left++;
}
}
res.push_back(left+1);
res.push_back(right+1);
return res;
}
};
只要数组有序,就应该想到双指针技巧
反转数组(reverse就好)
参考:C++中vector的reverse函数及其用法(详解)_vector reverse-CSDN博客
vector<int> vi ={1,2,3,4,5,6};
reverse(vi.begin(),vi.end()); //vi反转后为6,5,4,3,2,1
回文子串
5. 最长回文子串 - 力扣(LeetCode)第一想法是动态规划,明天用动规做一下(突然想起来是区间dp:AcWing---游戏---区间dp-CSDN博客)
class Solution {
public:
string Palindrome(string s,int i,int j){
int len=s.size();
int l,r;
if(i==j){//以i为中心的奇串
l=i;
r=i;
while(l>=0 && r<len && s[l]==s[r]){
l--;
r++;
}
l++;
r--;
}
else{//以i,i+1为中心的偶串
l=i;
r=i+1;
if(r==len || s[l]!=s[r]){return "";}
while(l>=0 && r<len && s[l]==s[r]){
l--;
r++;
}
l++;
r--;
}
return s.substr(l,r-l+1);
}
string longestPalindrome(string s) {
/*遍历以i为中心*/
string res="";
int len_res=0;
int len=s.size();
for(int i=0;i<len;i++){
string temp1=Palindrome(s,i,i);
int len_temp1=temp1.size();
if(len_temp1>len_res){res=temp1,len_res=len_temp1;}
string temp2=Palindrome(s,i,i+1);
int len_temp2=temp2.size();
if(len_temp2>len_res){res=temp2,len_res=len_temp2;}
}
return res;
}
};
看到回文串:左右指针从中心向两端扩展
动态规划做法:
class Solution {
public:
string longestPalindrome(string s) {
int len=s.size();
vector<vector<int>> g(1010,vector<int>(1010,0));
int l=0;
int len_res=1;
string res;
for(int i=1;i<=len;i++){//字符串的长度
for(int j=0;j+i-1<len;j++){//字符串的起始位置
if(i==1){
g[i][j]=1;
continue;
}
else if(i==2){
if(s[j]==s[j+1]){
g[i][j]=1;
if(len_res<i){
l=j;
len_res=i;
}
}
else{
g[i][j]=0;
}
}
else{
if(g[i-2][j+1]==1 && s[j]==s[j+i-1]){
g[i][j]=1;
if(len_res<i){
l=j;
len_res=i;
}
}
else{
g[i][j]=0;
}
}
}
}
//cout<<l<<endl;
//cout<<len_res<<endl;
res=s.substr(l,len_res);
return res;
}
};
明天将继续更新动态规划解决最长回文子串,以及四道数组双指针问题!
接下来更新4道数组双指针思想题目,找找感觉~
参考: