leetcode之双指针类-----OJ 228/15/16/18/26/80/121/75
来源:互联网 发布:歌词改编软件 编辑:程序博客网 时间:2024/06/16 19:08
链表中使用快慢指针的题也都可以算作双指针,本文着重更容易被作为双指针典型考察的典型题;
1、OJ228 summary ranges
给定有序数组找出其中的区间,如给定[0,1,2,4,5,7],结果为:["0->2", "4->5", "7"]
本题看起来是数组类区间相关,但其实是双指针操作能力考察
思路:事实上是3个指针,一个是当前区间头指针st,然后是一个cur和next形成前后双指针,双指针的题一定注意边界处理:
1、next不能越界
2、前后不再自增时,记录st到cur的区间,然后更新st和cur都到next,next再自增
3、前后自增时,cur和next依次前移
4、next过界后,有两种漏加最后一组区间情况:4.1、最后一个区间是单个数,特征为st==cur且next-cur==1;4.2、最后一个区间是一个区间,特征为st!=cur;以上两种情况都要补充区间,这是本题双指针操作重点;
OJ228代码:
class Solution {public: vector<string> summaryRanges(vector<int>& nums) { vector<string> res; if (nums.empty()) { return res; } vector<pair<int, int>> r; int st = 0, cur = 0, next = 1; while (next < nums.size()) { if (nums[next] == nums[cur] + 1) { ++cur; ++next; } else { pair<int, int> p({nums[st], nums[cur]}); r.push_back(p); st = cur = next; ++next; } } if (st != cur) { pair<int, int> p({nums[st], nums[cur]}); r.push_back(p); } if (next == cur + 1 && cur == st) { pair<int, int> p({nums[st], nums[cur]}); r.push_back(p); } for (auto p: r) { if (p.first == p.second) { string str = to_string(p.first); res.push_back(str); } else { string str1 = to_string(p.first), str2 = to_string(p.second), s = str1 + "->" + str2; res.push_back(s); } } return res; }};
2、OJ15 3sum
给定一个数组,找到其中的3个数的组合和为0的全部3数组合;
典型双指针,而且是相遇型双指针,思路是:
1、排序
2、以每个数为基数,然后在它后边的范围内,双指针分别指向首和尾,寻找三数和为0的情况;注意如果基数已经大于0,说明后边的更大,这时要及时停止无谓计算
class Solution {public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> res; if (nums.empty() || nums.size() < 3) { return res; } else if (nums.size() == 3) { if (nums[0] + nums[1] + nums[2] == 0) { vector<int> r; r.push_back(nums[0]); r.push_back(nums[1]); r.push_back(nums[2]); res.push_back(r); return res; } else { return res; } } //用set是为了确保3个数是按题意要求的升序 set<vector<int>> rset; sort(nums.begin(), nums.end()); for (size_t i = 0; i < nums.size() - 2; i++) { int cur = nums[i]; //当前数已经大于0, 都应该break了 if (cur > 0) { break; } //前边已经算过了不要重复计算 if (i > 0 && nums[i] == nums[i - 1]) { continue; } size_t st = i + 1, ed = nums.size() - 1; while (st < ed) { int cursum = nums[st] + nums[ed] + cur; if (cursum == 0) { //找到后记录下来, 然后接着找 vector<int> r; r.push_back(cur); r.push_back(nums[st]); r.push_back(nums[ed]); rset.insert(r); ++st; --ed; } else if (cursum > 0) { //超过target(0)就减减小的 --ed; } else { //小于target(0)就加加大的 ++st; } } } return vector<vector<int>>(rset.begin(), rset.end()); }};
3、OJ16 3sum closet
和3sum几乎一样。
注意最接近target的判断和更新,另外注意如果直接等于target是应该直接返回的,因为这个是最近的
OJ16代码:
class Solution {public: int threeSumClosest(vector<int>& nums, int target) { int res, mindiff = INT_MAX; sort(nums.begin(), nums.end()); for (int i = 0; i < nums.size(); i++) { int cur = nums[i]; if (i > 0 && nums[i] == nums[i - 1]) { continue; } int st = i + 1, ed = nums.size() - 1, curval = INT_MAX; while (st < ed) { //不断更新最接近的sum int sum = cur + nums[st] + nums[ed]; if (abs(sum - target) < mindiff) { mindiff = abs(sum - target); res = sum; } //依然是少进多回, 需要注意当发现等于target时是最近的要直接返回 if (sum > target) { --ed; } else if (sum < target) { ++st; } else { return sum; } } } return res; }};
4、OJ18 4sum
4sum以后统称Ksum,都可以简单的基于3sum的思路去做,只是往往不是最优解法(如4sum宜用二分思路优化),3sum的时间复杂度是O(N^2),基于3sum做法的4sum是O(N^3);
这里先只介绍下基于3sum的4sum可AC方法,道理和3sum一样;
OJ18代码:
class Solution {public: vector<vector<int>> helper (const vector<int> &relate, int target) { vector<vector<int>> res; for (int i = 0; i < relate.size(); i++) { int cur = relate[i]; int st = i + 1, ed = relate.size() - 1; if (i > 0 && relate[i] == relate[i - 1]) { continue; } while (st < ed) { if (relate[st] + relate[ed] + cur == target) { vector<int> s; s.push_back(cur); s.push_back(relate[st]); s.push_back(relate[ed]); res.push_back(s); ++st; --ed; } else if (relate[st] + relate[ed] + cur > target) { --ed; } else { ++st; } } } return res; } vector<vector<int>> fourSum(vector<int>& nums, int target) { set<vector<int>> res; if (nums.empty()) { vector<vector<int>> empty; return empty; } sort(nums.begin(), nums.end()); for (int i = 0; i < nums.size(); i++) { if (i > 0 && nums[i] == nums[i - 1]) { continue; } vector<int> relate; for (int j = i + 1; j < nums.size(); j++) { relate.push_back(nums[j]); } vector<vector<int>> r = helper(relate, target - nums[i]); for (auto v: r) { v.push_back(nums[i]); sort(v.begin(), v.end()); res.insert(v); } } vector<vector<int>> result(res.begin(), res.end()); return result; }};
5、OJ26/80 remove duplicate elements from sorted array I/II
典型双指针运用,原地修改数据
OJ80,允许重复的数据出现2次,外加hashmap记录次数的逻辑
OJ26代码:
class Solution {public: int removeDuplicates(vector<int>& nums) { if (nums.empty()) { return 0; } int res = 1; for (int i = 1, j = 1; i < nums.size(); i++) { if (nums[i] != nums[i - 1]) { ++res; nums[j] = nums[i]; ++j; } } return res; }};
OJ80代码:
class Solution {public: int removeDuplicates(vector<int>& nums) { if (nums.empty()) { return 0; } vector<int>::iterator it = nums.begin(); unordered_map<int, int> hmap; for (int i = 0; i < nums.size(); i++) { if (hmap.find(nums[i]) == hmap.end()) { *it = nums[i]; ++it; hmap[nums[i]] = 1; } else { if (hmap[nums[i]] == 1) { hmap[nums[i]] = 2; *it = nums[i]; ++it; } } } nums.erase(it, nums.end()); return nums.size(); }};
6、OJ121 best time to buy and sell stock
股票买卖题1,典型双指针,一个用于更新最小值,一个用于更新利润值
OJ121代码:
class Solution {public: int maxProfit(vector<int>& prices) { if (prices.empty()) { return 0; } int min = INT_MAX, val = INT_MIN; for (auto i: prices) { min = std::min(i, min); val = std::max(val, i - min); } return val; }};
7、OJ75 sort color
三色排序也叫荷兰国旗,给定数组里边有乱序的最多0、1、2三种元素,需要把0放在左部分,1放在中间部分,2放在右部分;
典型三指针:
1、从头找到第一个不为0的地方st;
2、从尾找到第一个不问2的地方ed;
3、位移指针mid从st开始,如果为1则mid向右顺移,若为0则与st交换元素,且st自增mid也右移,注意如果为2除与ed交换元素ed左移外,mid不能右移,因为可能交换得到的元素是0,需要做下一轮循环中与st交换;
OJ75代码:
class Solution {public: void sortColors(vector<int>& nums) { if (nums.empty()) { return; } //得到从头开始第一个不为0的地方st, 也是mid //得到从尾开始第一个不问2的地方ed int st = 0, mid = 0, ed = nums.size() - 1; while (st < nums.size() && nums[st] == 0) { ++st; } mid = st; while (ed >= 0 && nums[ed] == 2) { --ed; } //保证st <= mid <= ed while (st <= mid && mid <= ed) { if (nums[mid] == 0) { //mid与st交换后, 均自增, 因为如果mid处为2下一次循环就会被处理 int t = nums[st]; nums[st] = nums[mid]; nums[mid] = t; ++st; ++mid; } else if (nums[mid] == 1) { //mid处为1, 正好, 自增mid ++mid; } else { //mid与ed交换后, mid不能自增, 因为mid处可能为0, 还要和st交换 int t = nums[ed]; nums[ed] = nums[mid]; nums[mid] = t; --ed; } } }};
- leetcode之双指针类-----OJ 228/15/16/18/26/80/121/75
- LeetCode之双指针(1)
- LeetCode之双指针(2)
- LeetCode之双指针(3)
- Leetcode双指针16
- LeetCode OJ 之 Copy List with Random Pointer(复制含有随机指针的链表)
- <LeetCode OJ> (1 / 15 / 16 / 18) NSum问题集合
- LeetCode 之双指针 two pointers
- LeetCode OJ 之 Scramble String
- LeetCode OJ 之 Interleaving String
- LeetCode OJ 之 Summary Ranges
- LeetCode OJ 之 Valid Anagram
- LeetCode OJ 系列之228 Summary Ranges --Python
- LeetCode OJ 系列之75 Sort Colors --Python
- 第15周项目3-在OJ上玩指针之指针当形参
- LeetCode oj 167. Two Sum II - Input array is sorted (双指针)
- LeetCode OJ 之 Populating Next Right Pointers in Each Node (为每个结点填充右指针)
- LeetCode OJ 之 Populating Next Right Pointers in Each Node II(为每个结点填充右指针-二)
- 图片风格转换(附TensorFlow代码)
- #leetcode编程日记#583. Delete Operation for Two Strings
- tp3.2.3 命令模式
- hdu5952 Counting Cliques DFS
- 古典问题(兔子生崽)
- leetcode之双指针类-----OJ 228/15/16/18/26/80/121/75
- windows系统单机安装mysql两实例并配置为主从关系
- 【创业日记1】智慧旅游大数据服务平台项目-开始
- 欢迎使用CSDN-markdown编辑器
- 深入理解abstract class和interface
- hadoop之 YARN配置参数剖析—RM与NM相关参数
- CTS 测试细节
- 什么是JavaConfig
- #pragma once 与 #ifndef 解析