- 要求数组原地改变,用快慢指针。快指针是当前遍历的位置,慢指针是处理之后数组位置,数组长度有慢指针决定。
推算一遍example,确定逻辑。
26. Remove Duplicates from Sorted Array
Example 1:
Given nums = [1,1,2],
Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.
It doesn't matter what you leave beyond the returned length.
class Solution {
public:
int removeElement(vector<int> nums, int val) {
if (nums.size() == 0) return 0;
int low = 0, fast = 0;
while (fast < nums.size())
{
if (nums[fast] == nums[low]) fast++; //因为给low位置赋值,suoyigen num[low]比较。
else nums[++low] = nums[fast++];
}
return low+1;
}
};
对数组去重最好用新数组索引和旧数组索引。
27. Remove Duplicates from Sorted Array II
重复元素至多出现n次。
Given nums = [1,1,1,2,2,3], n=2
Your function should return length = 5, with the first five elements of nums being 1, 1, 2, 2 and 3 respectively.
It doesn't matter what you leave beyond the returned length.
class Solution {
public:
int removeDuplicates(vector<int>& nums, int bwt ) {
if (nums.size() <= 1) return nums.size();
int pre = bwt;
for (int post = bwt; post < nums.size(); post++)
{
if (nums[post] != nums[pre - bwt]) nums[pre++] = nums[post];
}
return pre;
}
};
变化前后的两数组如果存在变化快和变化慢的指针,那就用两个指针来处理。
56.Merge Intervals在合并区间时,设定[low, high]为合并后的边界。low缓慢变化,high通过判断区间是否相交变化快速,在快变量不变化的时候给新数组添加元素
Example 1:
Input: [[1,3],[2,6],[8,10],[15,18]]
Output: [[1,6],[8,10],[15,18]]
Explanation: Since intervals [1,3] and [2,6] overlaps, merge them into [1,6].
class Solution {
public:
vector<vector<int>> merge(vector<vector<int>> intervals) {
if (intervals.empty()) return {};
vector<vector<int>> res;
sort(intervals.begin(), intervals.end(), cmp);
int low = intervals[0][0], high = intervals[0][1];//记录当前合并后的区间
for (int i = 1; i < intervals.size(); i++)
{//合并后区间和当前区间比较,判断有交集的条件
if (high >= intervals[i][0]) high = max(intervals[i][1], high);
else
{
res.push_back({ low, high });
low = intervals[i][0];
high = intervals[i][1];
}
}
res.push_back({ low, high });
return res;
}
static bool cmp(vector<int> &a, vector<int> &b)
{
return a[0] < b[0];
}
};
27. Remove Element去掉数组中指定元素。
Example 1:
Given nums = [3,2,2,3], val = 3,
Your function should return length = 2, with the first two elements of nums being 2.
It doesn't matter what you leave beyond the returned length.
class Solution {
public:
int removeElement(vector<int>& nums, int val) {
if (nums.size() == 0) return 0;
int low = 0, fast = 0;
while (fast < nums.size())
{
if (nums[fast] == val) fast++;
else nums[low++] = nums[fast++];
}
return low;
}
};
- 二分查找
二分查找失败一定是high = low-1也即arr[high]<tar<arr[low],这时target在数组中的插入位置正好是low。
35. Search Insert Positio查找成功返回位置,失败返回插入位置。
Example 1:
Input: [1,3,5,6], 5
Output: 2
class Solution {
public:
int searchInsert(vector<int>& nums, int target) {
if (nums.empty()) return 0;
int low = 0, high = nums.size() - 1;
while (low <= high)
{
int mid = (low + high) / 2;
if (nums[mid] < target) low = mid + 1;
else if (nums[mid] > target) high = mid - 1;
else return mid;
}
return low;
}
};
- DFS 去重
使用dfs穷举数组所有元素的排列情况,要不能出现重复项,重复来源于:第一中后面的元素去结合前面的元素,如[1,2],排列方式会[1,2], [2,1],这种设置start位置,只结合start及后面的元素;第二种,数组中含有重复项,不同的组合中重复项会造成组合的重复,如[1,1,7]–>[1,7]第一个1, [1,7]第二个1,同一for循环中如果当前元素和上一元素相同就不排列。注意同一递归层的for循环里是创造不同组合的;递归每一层是创造同一 组合的不同元素的。
但是注意任何去重之前先排序。
3.1 在4-sum之后的无限项求和,求出和为target的所有元素组合。
4. Combination Sum II
Example 1:
Input: candidates = [10,1,2,7,6,1,5], target = 8,
A solution set is:
[
[1, 7],
[1, 2, 5],
[2, 6],
[1, 1, 6]
]
class Solution {
public:
vector<vector<int>> combinationSum(vector<int> candidates, int target) {
vector<vector<int>> res;
if (candidates.empty())
return res;
sort(candidates.begin(), candidates.end());
core(res, {}, candidates, 0, target, 0);
return res;
}
void core(vector<vector<int>> &res, vector<int> out, vector<int> candidates, int cur, int target, int start)
{
if (cur == target)
{
res.push_back(out);
return;
}
if (cur > target) return;
for (int i = start; i < candidates.size(); i++)
{
if (i > start && candidates[i] == candidates[i - 1]) continue;
out.push_back(candidates[i]);
core(res, out, candidates, cur + candidates[i], target, i+1);
out.pop_back();
}
}
};
3.2 90. Subsets II求数组的所有子集,去重复项情况同前。
Input: [1,2,2]
Output:
[
[2],
[1],
[1,2,2],
[2,2],
[1,2],
[]
]
class Solution {
public:
public:
vector<vector<int>> subsetsWithDup(vector<int>& nums) {
vector<vector<int>> res = { {} };
if (nums.empty()) return res;
sort(nums.begin(), nums.end());
dfs(res, nums, {}, 0);
return res;
}
void dfs(vector<vector<int>>& res, vector<int>& nums, vector<int> out, int start)
{
if (out.size()) res.push_back(out);
for (int i = start; i < nums.size(); i++)
{
if (i > start && nums[i] == nums[i - 1]) continue;
out.push_back(nums[i]);
dfs(res, nums, out, i + 1);
out.pop_back();
}
}
};
- DFS注意两点:终止条件和约束条件(比如为了去重的约束条件),以及使用for循环还是类似迷宫的单步递归,取决于每次有几种可能性(即递归层数)。
78.Subsets 穷举数列所有子集,包括空集。这里注意终止条件,不能用return否则无法想下递归。
Input: nums = [1,2,3]
Output:
[
[3],
[1],
[2],
[1,2,3],
[1,3],
[2,3],
[1,2],
[]
]
class Solution {
public:
vector<vector<int>> subsets(vector<int>& nums) {
vector<vector<int>> res{ {} };
if (nums.empty())
return res;
dfs(res, nums, {}, 0);
return res;
}
void dfs(vector<vector<int>> &res, vector<int>& nums, vector<int> out, int start)
{
if (out.size())
{
res.push_back(out);
//return;
}
for (int i = start; i < nums.size(); i++)
{
out.push_back(nums[i]);
dfs(res, nums, out, i + 1); //当start>= nums.size()不用额外添加终止判断,不进入for就可以了。
out.pop_back();
}
}
};
3.3 避免string.substr(s,k)时k大于字符串长度,出现重复现象。因为k大于剩余长度和k等于剩余长度结果是一样的。
93. Restore IP Addresses
分割字符串,要求每段字符串符合要求。递归约束条件:
1. 小于等于255,而且不能有前导0.
2. 切出4段字符串后,正好切到结尾。
class Solution {
public:
vector<string> restoreIpAddresses(string s) {
vector<string> res;
core(res, {}, s, 0);
return res;
}
void core(vector<string>& res, vector<string> ip, string s, int cut)
{
if (ip.size()==4 && cut>s.length()-1) {//切出4段字符串后,正好切到结尾。
string addr = ip[0] + "." + ip[1] + "." + ip[2] + "." + ip[3];
res.push_back(addr);
return;
}
if (ip.size() >= 4) return;
for (int i = 1; i <= 3; i++)
{
if (i > s.length() - cut) break;//防止重复出现。
string a = s.substr(cut, i);
if (atoi(a.c_str()) > 255 || (a[0] == '0'&&a.length() > 1)) //约束
continue;
ip.push_back(a);
core(res, ip, s, cut + i);
ip.pop_back();
}
}
};
- 最大和子数组
最大和子数组, 要求子数组连续,求出最大和。用dp来做。