11. Container With Most Water【medium】
解题思路:
这道题可以考虑暴力枚举的方式,复杂度应该是O(N^2),嵌套循环即可实现,下面重点讲复杂度只有O(N)的头尾标记法。
考虑到:
容器的容量 = 两端中较矮的板子长度(L) * 两端的距离(d)
在数组两端设置头尾标记,以头尾标记为容器的两端,假设头标记对应的板子长度比较短,那么现在 容器的容量 = 头标记板子 * 头尾标记的距离。那么以头标记为一端的所有容器的容量必然小于当前容器,因为其他以头标记为一端的容器的L一定小于或等于当前容器,而距离d一定小于当前容器。所以这些容器都可以无需遍历,因此让头标记向尾部移动一个单位;假设尾标记对应的板子长度比较短,则以此类推,让尾标记向头部移动一个单位,直至头尾标记相遇则停止寻找。
实现代码:
// 11. Container With Most Waterint maxArea(vector<int>& height) { int res = 0, i = 0, j = height.size() - 1; while (i != j) { res = max(res, (j - i) * min(height[i], height[j])); if (height[i] > height[j]) { j--; } else { i++; } } return res; }
12. Integer To Roman【medium】
解题思路:
这道题没有特别多技巧,直接按照转换规则进行转换即可,对每一位进行遍历,注意考虑4和9的特殊情况即可。
在查看Leetcode讨论区的时候还看到了一种脑洞大开的“全部映射法”,这里贴上来给大家欣赏一下,也开拓了一下思路,这种方法告诉我们在情况不多的时候,可以考虑一下这种思路,代码更为简洁。
实现代码:
// 12. Integer to Romanstring intToRoman(int num) { map<int, char> romanMap; romanMap[1] = 'I'; romanMap[5] = 'V'; romanMap[10] = 'X'; romanMap[50] = 'L'; romanMap[100] = 'C'; romanMap[500] = 'D'; romanMap[1000] = 'M'; string res; for (int i = 3; i >= 0; i--) { int fold = pow(10, i); if (num / fold == 9) { res += romanMap[fold]; res += romanMap[fold * 10]; } else if (num / fold == 4) { res += romanMap[fold]; res += romanMap[fold * 5]; } else if (num / fold > 0) { if (num / fold >= 5) { res += romanMap[fold * 5]; num -= 5 * fold; } for (int i = 0; i < num / fold; i++) { res += romanMap[fold]; } } num %= fold; } return res; }// 脑洞大开的全部映射法string intToRoman(int num) { string M[] = {"", "M", "MM", "MMM"}; string C[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}; string X[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}; string I[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}; return M[num/1000] + C[(num%1000)/100] + X[(num%100)/10] + I[num%10]; }
13. Roman To Integer【easy】
解题思路:
这道题和上一题一样,直接按照转换规则进行转换即可,对每一位进行遍历,注意考虑4和9的特殊情况即可。
实现代码:
// 13. Roman To Integerint romanToInt (string s) { int res = 0; for (int i = 0; i < s.size(); i++) { if (s[i] == 'I') { res += 1; } else if (s[i] == 'V') { res += 5; if (i - 1 >= 0 && s[i - 1] == 'I') { res -= 2; } } else if (s[i] == 'X') { res += 10; if (i - 1 >= 0 && s[i - 1] == 'I') { res -= 2; } } else if (s[i] == 'L') { res += 50; if (i - 1 >= 0 && s[i - 1] == 'X') { res -= 20; } } else if (s[i] == 'C') { res += 100; if (i - 1 >= 0 && s[i - 1] == 'X') { res -= 20; } } else if (s[i] == 'D') { res += 500; if (i - 1 >= 0 && s[i - 1] == 'C') { res -= 200; } } else if (s[i] == 'M') { res += 1000; if (i - 1 >= 0 && s[i - 1] == 'C') { res -= 200; } } } return res; }
14. Longest Common Prefix【easy】
解题思路:
这道题从头到尾每一个字符遍历,如果出现不同或者已经不够长,则把已知的共同前缀返回即可。
考虑边界条件:
当输入字符串数组为空时,返回空字符串""。
实现代码:
// 14. Longest Common Prefixstring longestCommonPrefix(vector<string>& strs) { if (strs.size() == 0) return ""; int length = 0; while (true) { if (strs[0].size() < length + 1) break; for (int i = 0; i < strs.size() - 1; i++) if (strs[i + 1].size() < length + 1 || strs[i][length] != strs[i + 1][length]) return strs[0].substr(0, length); length++; } return strs[0].substr(0, length); }
15. 3Sum【medium】
解题思路:
双指针法枚举,复杂度O(N^2)。
首先,对数组进行排序。然后,从第一个数字 i 开始遍历,每一层遍历中有两个指针 p, q 分别指向该数字后续的数组中的头尾两端,通过判断这三个数组的和与0的关系,移动头尾指针:
如果和大于0,尾指针前移;如果和小于0,头指针后移;如果和等于0,分别移动头尾指针。
这里注意要考虑到数组中处理出现重复数字的情况。
如果 i 与 i - 1重复则直接跳过该项的遍历,如果 p 重复则 p++,如果 q 重复则 q++。
考虑边界条件:
当输入数组长度不足3时,返回空字符串数组。
实现代码:
// 15. 3Sumvector<vector<int> > threeSum(vector<int>& nums) { vector<vector<int> > res; if (nums.size() < 3) return res; sort(nums.begin(), nums.end()); int p, q, sum; for (int i = 0; i < nums.size() - 2; i++) { if (nums[i] > 0) break; else if (i > 0 && nums[i] == nums[i - 1]) continue; p = i + 1; q = nums.size() - 1; while (p < q) { sum = nums[i] + nums[p] + nums[q]; if (sum == 0) { res.push_back({nums[i], nums[p], nums[q]}); while (nums[p] == nums[p + 1] && p < q) p++; p++; while (nums[q] == nums[q - 1] && p < q) q--; q--; } else if (sum > 0) { while (nums[q] == nums[q - 1] && p < q) q--; q--; } else { while (nums[p] == nums[p + 1] && p < q) p++; p++; } } } return res; }
16. 3Sum Closest
解题思路:
与15题如出一辙,采用双指针法枚举,复杂度O(N^2)。
首先,对数组进行排序。然后,从第一个数字 i 开始遍历,每一层遍历中有两个指针 p, q 分别指向该数字后续的数组中的头尾两端,通过判断这三个数组的和与0的关系,移动头尾指针:
如果和大于0,返回target;如果和小于0,头指针后移;如果和等于0,分别移动头尾指针。
这里注意要考虑到数组中处理出现重复数字的情况。
如果 i 与 i - 1重复则直接跳过该项的遍历,如果 p 重复则 p++,如果 q 重复则 q++。
实现代码:
// 16. 3Sum Closestint threeSumClosest(vector<int>& nums, int target) { sort(nums.begin(), nums.end()); int p, q, sum; int gap = INT_MAX; int res; for (int i = 0; i < nums.size() - 2; i++) { if (i > 0 && nums[i] == nums[i - 1]) continue; p = i + 1; q = nums.size() - 1; while (p < q) { sum = nums[i] + nums[p] + nums[q]; if (sum == target) { return target; } else if (sum > target) { if (sum - target < gap) { gap = sum - target; res = sum; } while (nums[q] == nums[q - 1] && p < q) q--; q--; } else { if (target - sum < gap) { gap = target - sum; res = sum; } while (nums[p] == nums[p + 1] && p < q) p++; p++; } } } return res; }
17. Letter Combinations of a Phone Numbe
解题思路:
经典的排列问题,直接用回溯法解决。
下面的解法是使用循环实现非递归的回溯法。linshi作为中间变量,每一个数字按下之后的结果。
实现代码:
// 17. Letter Combinations of a Phone Numbervector<string> letterCombinations(string digits) { if (digits.size() == 0) return {}; map<int, string> digitalMap; digitalMap[2] = "abc"; digitalMap[3] = "def"; digitalMap[4] = "ghi"; digitalMap[5] = "jkl"; digitalMap[6] = "mno"; digitalMap[7] = "pqrs"; digitalMap[8] = "tuv"; digitalMap[9] = "wxyz"; vector<string> linshi; vector<string> res = {""}; for (int i = 0; i < digits.size(); i++) { string tails = digitalMap[digits[i] - 48]; for (int j = 0; j < res.size(); j++) { for (int n = 0; n < tails.size(); n++) { linshi.push_back(res[j] + tails[n]); } } res = linshi; linshi = {}; } return res; }
18. 4Sum
解题思路:
和15题3Sum如出一辙,在3Sum的解法外面再套一层即可。
实现代码:
// 18. 4Sum vector<vector<int>> fourSum(vector<int>& nums, int target) { vector<vector<int> > res; if (nums.size() < 4) return res; sort(nums.begin(), nums.end()); int p, q, sum; for (int j = 0; j < nums.size() - 3; j++) { if (j > 0 && nums[j] == nums[j - 1]) continue; int target3 = target - nums[j]; for (int i = j + 1; i < nums.size() - 2; i++) { if (i > j + 1 && nums[i] == nums[i - 1]) continue; p = i + 1; q = nums.size() - 1; while (p < q) { sum = nums[i] + nums[p] + nums[q]; if (sum == target3) { res.push_back({nums[j], nums[i], nums[p], nums[q]}); while (nums[p] == nums[p + 1] && p < q) p++; p++; while (nums[q] == nums[q - 1] && p < q) q--; q--; } else if (sum > target3) { while (nums[q] == nums[q - 1] && p < q) q--; q--; } else { while (nums[p] == nums[p + 1] && p < q) p++; p++; } } } } return res; }
19. Remove Nth Node From End of List
解题思路:
快慢指针思想,让两个指针 p, q都指向头结点,p 先向后移动 n + 1 步,然后p, q一起向后移动,当 p 到达尾结点时,q指向目标节点的前驱结点,做删除操作,然后按照题目要求返回头结点即可。
实现代码:
// 20. Valid Parenthesesbool isValid(string s) { stack<char> brackets; map<char, char> bracketMap; bracketMap[')'] = '('; bracketMap[']'] = '['; bracketMap['}'] = '{'; for (int i = 0; i < s.size(); i++) { if (s[i] == '(' || s[i] == '[' || s[i] == '{') { brackets.push(s[i]); } else if (s[i] == ')' || s[i] == ']' || s[i] == '}') { if (!brackets.empty() && brackets.top() == bracketMap[s[i]]) { brackets.pop(); } else { return false; } } } if (brackets.empty()) return true; else return false; }
20. Valid Parentheses
解题思路:
栈思想,从左往右遍历,如果是左括号则入栈,右括号则出栈,最后判断栈是否为空,空则为有效括号组,否则无效。
实现代码:
// 20. Valid Parenthesesbool isValid(string s) { stack<char> brackets; map<char, char> bracketMap; bracketMap[')'] = '('; bracketMap[']'] = '['; bracketMap['}'] = '{'; for (int i = 0; i < s.size(); i++) { if (s[i] == '(' || s[i] == '[' || s[i] == '{') { brackets.push(s[i]); } else if (s[i] == ')' || s[i] == ']' || s[i] == '}') { if (!brackets.empty() && brackets.top() == bracketMap[s[i]]) { brackets.pop(); } else { return false; } } } if (brackets.empty()) return true; else return false; }
作者:大雄的学习人生
链接:https://www.jianshu.com/p/4314383492ef
共同学习,写下你的评论
评论加载中...
作者其他优质文章