一刷leetcode——未分类
1、Two Sum
题意:给定一个数组和一个目标值,输出数组中值之和等于目标值的两个元素的索引值
解法一:暴力(也是自己的解法),两重循环暴搜
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { vector<int> ans; for (int i = 0; i < nums.size(); i++) { for (int j = i+1; j < nums.size(); j++) { if (nums[i]+nums[j] == target) { ans.push_back(i); ans.push_back(j); } } } return ans; } };
解法二:哈希表(最优解),建立key为数值、value为索引值的哈希表,一重循环遍历每一个值nums[i],若能找到target-nums[i]的索引,则输出两索引值(target-nums[i]的索引值更小,因为他是先入map的);否则将nums[i]与i加入map。
class Solution { public: vector<int> twoSum(vector<int>& nums, int target) { // hash[i]表示nums中数值为i的下标 unordered_map<int, int> hash; vector<int> result; // 一边循环每个数,一边加入hash表。 for (int i = 0; i < nums.size(); i++) { if (hash.find(target - nums[i]) != hash.end()) { // target - nums[i]的下标更小,放在前面 result.push_back(hash[target - nums[i]]); result.push_back(i); return result; } hash[nums[i]] = i; } // 无解的情况 result.push_back(-1); result.push_back(-1); return result; } };
167、Two Sum II - Input array is sorted
题意:给定一个升序数组和一个目标值,输出数组中值之和等于目标值的两个元素的索引值(以1起)
我的思路:最简单的可以用第一题的代码复制过来也可以过;考虑到数组为升序,可以将小于target/2的元素直接入哈希表,从不小于target/2的值找起
我的代码:
class Solution { public: vector<int> twoSum(vector<int>& numbers, int target) { unordered_map<int, int> hash; vector<int> result; int j = lower_bound(numbers.begin(), numbers.end(), target/2)-numbers.begin(); for (int i = 0; i < j; i++) hash[numbers[i]] = i; for (int i = j; i < numbers.size(); i++) { if (hash.find(target - numbers[i]) != hash.end()) { result.push_back(hash[target - numbers[i]]+1); result.push_back(i+1); return result; } hash[numbers[i]] = i; } return result; } };
查题解:双指针问题,首尾两指针,和小于target时左指针右移,大于时右指针左移,等于输出。
我的代码:
class Solution { public: vector<int> twoSum(vector<int>& numbers, int target) { vector<int> result; int left = 0, right = numbers.end()-numbers.begin()-1; while (left<=right) { if (numbers[left]+numbers[right] < target) left++; else if (numbers[left]+numbers[right] > target) right--; else { result.push_back(left+1); result.push_back(right+1); break; } } return result; } };
2、Add Two Numbers
题意:链表形式模拟高精度加法,表头为低位
解法:模拟,注意进位细节
我的代码:
* struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { ListNode* ans = l1; int jinwei = 0; while (1) { int tmp = l1->val + l2->val + jinwei; l1->val = tmp % 10; jinwei = tmp / 10; if ((l1->next == NULL) ||(l2->next == NULL)) { break; } l1 = l1->next; l2 = l2->next; } while (l1->next != NULL) { int tmp = l1->next->val + jinwei; l1->next->val = tmp % 10; jinwei = tmp /10; l1 = l1->next; } while (l2->next != NULL) { l1->next = l2->next; int tmp = l2->next->val + jinwei; l1->next->val = tmp % 10; jinwei = tmp / 10; l1 = l1->next; l2 = l2->next; } if (jinwei != 0) { ListNode* tmp = new ListNode(0); tmp->val = jinwei; l1->next = tmp; } return ans; } };
九章最优解:(虽然思路一样,但是写法被秒杀。。好在我的更快一些)
class Solution { public: ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { // 题意可以认为是实现高精度加法 ListNode *head = new ListNode(0); ListNode *ptr = head; int carry = 0; while (true) { if (l1 != NULL) { carry += l1->val; l1 = l1->next; } if (l2 != NULL) { carry += l2->val; l2 = l2->next; } ptr->val = carry % 10; carry /= 10; // 当两个表非空或者仍有进位时需要继续运算,否则退出循环 if (l1 != NULL || l2 != NULL || carry != 0) { ptr = (ptr->next = new ListNode(0)); } else break; } return head; } };
3、Longest Substring Without Repeating Characters
题意:找出最长的无重复字符的子串的长度
我的思路:暴搜,另开一标志数组做哈希
我的代码:
class Solution { public: int lengthOfLongestSubstring(string s) { int ans = 0; bool ch[256]; for (int i = 0; i < s.size(); i++) { int j = 0, cnt = 0; memset(ch, 0, sizeof(ch)); while ( i+j < s.size() ) { if (!ch[s[i+j]]) { ch[s[i+j]] = true; cnt++; j++; continue; } break; } if (cnt > ans) ans = cnt; } return ans; } };
九章最优解:开一数组记录字符上次出现的位置,当重复出现时,将结果串开头更新为上次的位置,并更新最大长度
代码:
class Solution { public: int lengthOfLongestSubstring(string s) { // 题意为求不包含重复字符的最长子串 // left用以记录合法的最远左边界位置,last记录字符上一次出现的位置 int ans = 0, left = 0, len = s.length(); int last[255]; memset(last, -1, sizeof last); for (int i = 0; i < len; i++) { // 上次出现位置在当前记录边界之后,即该子串中出现了重复字符,需调整left使得子串合法 if (last[s[i]] >= left) left = last[s[i]] + 1; last[s[i]] = i; ans = max(ans, i - left + 1); } return ans; } };
4. Median of Two Sorted Arrays
题意:寻找两个有序数组的中位数
我的思路:寻找第k大的数,http://blog.csdn.net/yutianzuijin/article/details/11499917/
我的代码:
class Solution { public: double findknum (vector<int>& a, int m, vector<int>& b, int n, int k) { if (m > n) return findknum(b, n, a, m, k); if (m == 0) return b[k-1]; if (k == 1) return min(a[0], b[0]); int ka = min(k/2, m), kb = k-ka; vector<int> tmp; if (a[ka-1] == b[kb-1]) return a[ka-1]; else if (a[ka-1] < b[kb-1]) { tmp.assign(a.begin()+ka, a.end()); return findknum(tmp, m-ka, b, n, k-ka); } else { tmp.assign(b.begin()+kb, b.end()); return findknum(a, m, tmp, n-kb, k-kb); } } double findMedianSortedArrays(vector<int>& nums1, vector<int>& nums2) { int m = nums1.size(), n = nums2.size(); if ((m+n)%2) return findknum(nums1, m, nums2, n, (m+n)/2+1); else return (findknum(nums1, m, nums2, n, (m+n)/2)+findknum(nums1, m, nums2, n, (m+n)/2+1))/2; } };
6、ZigZag Conversion
题意:将一字符串竖着写成n行的之字形,再按行读出
我的思路:模拟,找到规律即可,按行号i=0~numRows-1循环,每个循环每次前进两步,第一步step=2*numRows-2-2*i,第二步step = 2*numRows-2-step。
我的代码:
class Solution { public: string convert(string s, int numRows) { if (numRows == 1) return s; string ans; ans.push_back(s[0]); for (int i = 0; i < numRows; i++) { int loc = i, step = 2*i; while (loc < s.size()) { if (step) ans.push_back(s[loc]); step = 2*numRows-2-step; loc += step; } } return ans; } };
九章最优解代码:(Java写,思路一致,但我感觉我的简洁一些~)
public class Solution { public String convert(String s, int nRows) { int length = s.length(); if (length <= nRows || nRows == 1) return s; char[] chars = new char[length]; int step = 2 * (nRows - 1); int count = 0; for (int i = 0; i < nRows; i++){ int interval = step - 2 * i; for (int j = i; j < length; j += step){ chars[count] = s.charAt(j); count++; if (interval < step && interval > 0 && j + interval < length && count < length){ chars[count] = s.charAt(j + interval); count++; } } } return new String(chars); } }
7、Reverse Integer
题意:将一个整数高低位倒置成为一个新数输出,正负号不变
我的思路:对x模10可得到其低位blabla~注意倒置后可能超int,此时输出0。
我的代码:
class Solution { public: int reverse(int x) { int flag = 0, ans; long long tmp = 0; if (x < 0) { flag = 1; x = -x; } while (x > 0) { tmp = tmp*10+x%10; x /= 10; } if (flag) tmp = -tmp; ans = (int)tmp; if (ans == tmp) return ans; return 0; } };
九章最优解:(将下个循环的ans/10看是否等于上个循环的ans判断有没有超int,没我的快~)
class Solution { public: int reverse(int x) { int rst = 0; while(x != 0){ int next_rst = rst * 10 + x % 10; x = x / 10; if(next_rst/10 != rst) return 0; rst = next_rst; } return rst; } };
8、String to Integer (atoi)
题意:将字符串转为整数输出
我的思路:没什么思维上的难度,测试数据有些变态,前边可能有多余的空格,大于int正数上限时输出上限值,小于负数下限时输出下限值,个人认为题目价值不大。
我的代码:
class Solution { public: int myAtoi(string str) { int i = 0, flag = 0; long long ans=0; while(str[i] == ' ') i++; if (str[i] == '-' || str[i] == '+') { if (str[i] == '-') flag = 1; i++; if(str[i] < '0' || str[i] > '9') return 0; } for (; i < str.length(); i++) { if (str[i]-'0' > 9 || str[i]-'0' < -9) break; ans = ans*10+str[i]-'0'; if (ans > 2147483648) break; } if (flag == 0) { if (ans > 2147483647) ans = 2147483647; } if (flag) { if (ans > 2147483648) ans = 2147483648; } if (flag) return -ans; return (int)ans; } };
9、Palindrome Number
题意:判回文数,不允许额外空间(即不允许先转为字符串再判)
我的思路:负数直接输出false,正数低位变高位,看最后数字是否等于原数
我的代码:
class Solution { public: bool isPalindrome(int x) { if (x < 0) return 0; int ans = 0, xx=x; while (x > 0) { ans = ans*10+x%10; x /= 10; } return (ans == xx); } };
11、Container With Most Water
题意:已知若干挡板高度,求两块挡板间的最大容积(两块挡板间没有其他挡板,所以简单一些)
我的思路:首尾两指针,若左边的挡板高度小,左指针右移(因为肯定比右指针左移要大,水位由较低挡板高度决定),反之右指针左移,更新最大容积
我的代码:
class Solution { public: int maxArea(vector<int>& height) { int l = 0, r = height.size()-1; int ans = (r-l)*min(height[l], height[r]); while (r > l) { if (height[l] < height[r]) { ans = max(ans, (r-l-1)*min(height[++l], height[r])); } else { ans = max(ans, (r-l-1)*min(height[l], height[--r])); } } return ans; } };
九章最优解:一样
九章代码:
class Solution { public: int maxArea(vector<int> &height) { int max = 0, area; int start = 0, end = height.size() - 1; while (start < end) { if (height[start] > height[end]) { area = height[end] * (end - start); end --; } else { area = height[start] * (end - start); start ++; } if (area > max) { max = area; } } return max; } };
12、Integer to Roman
题意:整数转罗马数字
我的思路:打表
我的代码:
class Solution { public: string intToRoman(int num) { char *C[4][10] = {{"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}, {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}, {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}, {"", "M", "MM", "MMM"}}; string s; s.append(C[3][num/1000]); s.append(C[2][num/100%10]); s.append(C[1][num/10%10]); s.append(C[0][num%10]); return s; } };
九章最优解:打表方式不同
九章代码:
class Solution { public: /* 题意:将数字转换成罗马数字 对照转换表模拟即可 */ string intToRoman(int num) { int Num[] = {1000, 900, 500, 400, 100, 90, 50, 40, 10, 9, 5, 4, 1}; string Roman[] = {"M", "CM", "D", "CD", "C", "XC", "L", "XL", "X", "IX", "V", "IV", "I"}; string ans = ""; int i = 0, times; while (num) { times = num / Num[i]; num %= Num[i]; while (times--) ans += Roman[i]; i++; } return ans; } };
13、Roman to Integer
题意:将罗马数字转为整数输出
思路:左小右大,右减左;左大右小,左加右
我的代码:
class Solution { public: int romanToInt(string s) { unordered_map<char, int> mapp; mapp['M'] = 1000; mapp['D'] = 500; mapp['C'] = 100; mapp['L'] = 50; mapp['X'] = 10; mapp['V'] = 5; mapp['I'] = 1; int ans = 0, i; for (i = 0; i < s.length()-1; i++) { if (mapp[s[i]] >= mapp[s[i+1]]) ans += mapp[s[i]]; else ans -= mapp[s[i]]; } ans += mapp[s[i]]; return ans; } };
九章最优解:
class Solution { public: /* 题意: 将罗马数字转换成int 按照转换表模拟即可 */ int romanToInt(string s) { map<char, int> num; num['I'] = 1; num['V'] = 5; num['X'] = 10; num['L'] = 50; num['C'] = 100; num['D'] = 500; num['M'] = 1000; int ans = num[s[s.length() - 1]]; for (int i = s.length() - 2; i >= 0; i--) { if (num[s[i]] < num[s[i + 1]]) ans -= num[s[i]]; else ans += num[s[i]]; } return ans; } };
14、Longest Common Prefix
题意:求若干字符串的最长公共前缀
我的思路:暴力判断,注意空串特判
我的代码:
class Solution { public: string longestCommonPrefix(vector<string>& strs) { string ans; if (strs.size() == 0) return ans; int i = 0, length = strs.size(); while (i < strs[0].size()) { int j=1; while (j<length && strs[j][i] == strs[0][i]) j++; if (j == length) ans.push_back(strs[0][i++]); else break; } return ans; } };
九章最优解:
class Solution { public: /** * @param strs: A list of strings * @return: The longest common prefix */ string longestCommonPrefix(vector<string> &strs) { if (strs.size() == 0) { return ""; } string prefix = ""; for (int i = 0; i < strs[0].length(); i++) { for (int j = 1; j < strs.size(); j++) { if (strs[j][i] != strs[0][i]) { return prefix; } } prefix += strs[0][i]; } return prefix; } };
15. 3Sum
题意:找出数组中和为0的所有三个数字的组合,不可重复
我的思路:先排序,从头遍历作第一个元素,在其后边的区间取后两个元素,初始状态为区间的首尾,根据和的情况确定左端右移还是右端左移,注意在第一个元素遍历过程中和取后两个元素过程中把相同的元素跳过去。
我的代码:
class Solution { public: vector<vector<int>> threeSum(vector<int>& nums) { vector<vector<int>> ans; if (nums.size() < 3) return ans; sort (nums.begin(), nums.end()); for (int i = 0; i < nums.size()-2; i++) { if (i > 0 && nums[i] == nums[i-1]) continue; int l = i+1, r = nums.size()-1; while (l < r) { if (nums[i]+nums[l]+nums[r] == 0) { vector<int> tmp; tmp.push_back(nums[i]); tmp.push_back(nums[l]); tmp.push_back(nums[r]); ans.push_back(tmp); while (l < r && nums[l] == nums[l+1]) ++l; while (l < r && nums[r] == nums[r-1]) --r; } if (nums[i]+nums[l]+nums[r] > 0) --r; else ++l; } } return ans; } };
九章最优解:思路一样
九章代码:
class Solution { public: /** * @param numbers : Give an array numbers of n integer * @return : Find all unique triplets in the array which gives the sum of zero. */ vector<vector<int> > threeSum(vector<int> &nums) { vector<vector<int> > result; sort(nums.begin(), nums.end()); for (int i = 0; i < nums.size(); i++) { if (i > 0 && nums[i] == nums[i - 1]) { continue; } // two sum; int start = i + 1, end = nums.size() - 1; int target = -nums[i]; while (start < end) { if (start > i + 1 && nums[start - 1] == nums[start]) { start++; continue; } if (nums[start] + nums[end] < target) { start++; } else if (nums[start] + nums[end] > target) { end--; } else { vector<int> triple; triple.push_back(nums[i]); triple.push_back(nums[start]); triple.push_back(nums[end]); result.push_back(triple); start++; } } } return result; } };
16. 3Sum Closest
题意:从数组中找出三个数之和与target最近,输出这个值
我的思路:先对数组排序,之后遍历作第一个数,后两个从第一个数之后的区间找,取区间首尾l,r分别为另两个数,根据距离更新,若三数之和大于target,r左移,泛指l右移
我的代码:
class Solution { public: int threeSumClosest(vector<int>& nums, int target) { int ans = nums[0]+nums[1]+nums[2]-target; sort(nums.begin(), nums.end()); for (int i = 0; i < nums.size()-2; i++) { int l = i+1, r = nums.size()-1; while (l < r) { int tmp = nums[i]+nums[l]+nums[r]-target; if (fabs(tmp) < fabs(ans)) ans = tmp; if (tmp > 0) --r; else ++l; } } return ans+target; } };
九章最优解:思路一样
九章代码:
class Solution { public: /** * @param numbers: Give an array numbers of n integer * @param target: An integer * @return: return the sum of the three integers, the sum closest target. */ int threeSumClosest(vector<int> nums, int target) { sort(nums.begin(), nums.end()); int result = nums[0] + nums[1] + nums[2]; for (int i = 0; i < nums.size(); i++) { int start = i + 1, end = nums.size() - 1; while (start < end) { if (abs(result - target) > abs(nums[i] + nums[start] + nums[end] - target)) { result = nums[i] + nums[start] + nums[end]; } if (nums[i] + nums[start] + nums[end] < target) { start++; } else { end--; } } } return result; } };
17、Letter Combinations of a Phone Number
题意:输出拼音九键数字串对应的所有字符组合
我的思路:先建立数字与字符的map,再dfs,递归时间爆炸......
我的代码:
class Solution { public: vector<string> ans; map<int, string> mapp; void dfs(int i, int k, string tmp, string digits) { if (i == k) { ans.push_back(tmp); return; } for (int j = 0; j < mapp[digits[i]-'0'].size(); j++) { tmp += mapp[digits[i]-'0'][j]; dfs(i+1, k, tmp, digits); tmp = tmp.substr(0, tmp.length()-1); } } vector<string> letterCombinations(string digits) { if (digits.size() == 0) return ans; mapp[1]="1"; mapp[2]="abc"; mapp[3]="def"; mapp[4]="ghi"; mapp[5]="jkl"; mapp[6]="mno"; mapp[7]="pqrs"; mapp[8]="tuv"; mapp[9]="wxyz"; mapp[0]=" "; dfs(0, digits.size(), "", digits); return ans; } };
九章最优解:思路 一样,但是写法碾压。。
九章代码:
class Solution { public: const vector<string> keyboard { " ", "", "abc", "def", // '0','1','2',... "ghi", "jkl", "mno", "pqrs", "tuv", "wxyz" }; vector<string> letterCombinations (const string &digits) { if (digits == "") return {}; vector<string> result; dfs(digits, 0, "", result); return result; } void dfs(const string &digits, size_t cur, string path, vector<string> &result) { if (cur == digits.size()) { result.push_back(path); return; } for (auto c : keyboard[digits[cur] - '0']) { dfs(digits, cur + 1, path + c, result); } } };
18. 4Sum
题意:找出数组中所有和为target的四个数
我的思路:3sum外再加一循环
我的代码:
class Solution { public: vector<vector<int>> fourSum(vector<int>& nums, int target) { vector<vector<int>> ans; if (nums.size() < 4) return ans; sort (nums.begin(), nums.end()); for (int i = 0; i < nums.size()-3; i++) { if (i > 0 && nums[i] == nums[i-1]) continue; for (int j = i+1; j < nums.size()-2; j++) { if (j > i+1 && nums[j] == nums[j-1]) continue; int l = j+1, r = nums.size()-1; while (l < r) { if (nums[i]+nums[j]+nums[l]+nums[r] == target) { vector<int> tmp; tmp.push_back(nums[i]); tmp.push_back(nums[j]); tmp.push_back(nums[l]); tmp.push_back(nums[r]); ans.push_back(tmp); while (l < r && nums[l] == nums[l+1]) ++l; while (l < r && nums[r] == nums[r-1]) --r; } if (nums[i]+nums[j]+nums[l]+nums[r] > target) --r; else ++l; } } } return ans; } };
22、Generate Parentheses
题意:给定小括号对数n,输出合法的扩号序列
我的思路:递归,左括号数不到n时可以加左括号,右括号数小于左括号时可以加右括号,参照上题
我的代码:
class Solution { public: void dfs(int n, int m1, int m2, string tmp, vector<string> &ans) { if (m1 == n && m2 == n) ans.push_back(tmp); if (m1 < n) dfs(n, m1+1, m2, tmp+'(', ans); if (m2 < m1) dfs(n, m1, m2+1, tmp+')', ans); } vector<string> generateParenthesis(int n) { vector<string> ans; dfs(n, 1, 0, "(", ans); return ans; } };
九章最优解:思路一样,个人感觉我写的漂亮些~
九章代码:
class Solution { public: /** * @param n n pairs * @return All combinations of well-formed parentheses */ vector<string> generateParenthesis(int n) { // Write your code here vector<string> res; string s; helper(s,res,0,0,n); return res; } void helper(string s,vector<string> &res,int l,int r,int n){ if(r==n){ res.push_back(s); } else if(l==n){ s+=')'; helper(s,res,l,r+1,n); } else{ if(l>r) helper(s+')',res,l,r+1,n); helper(s+'(',res,l+1,r,n); } } };
19、Remove Nth Node From End of List
题意:删除链表的倒数第n个节点
问的思路:两个指针,第一个先走n步,之后两个指针一起后移,第一个到链表结尾时第二个的next正好是要去掉的那个节点,特别地,当去掉的是最后一个节点时,要用需要返回的ans指针直接指过去,因为第一个指针到结尾时第二个指针还没动
我的代码:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* removeNthFromEnd(ListNode* head, int n) { if (head == NULL) return head; ListNode* headn = head, * ans = head; if (head->next == NULL) return ans = NULL; while (head->next) { head = head->next; if (n <= 0) headn = headn->next; n--; } if (n > 0) ans = headn->next; else headn->next = headn->next->next; return ans; } };
九章最优解:使用两个指针扫描,当第一个指针扫描到第N个结点后,第二个指针从表头与第一个指针同时向后移动,当第一个指针指向空节点时,另一个指针就指向倒数第n个结点了。思路本质一致。
九章代码:(这才是我自己理想的写法,被指针搞凌乱了没写好。。)
class Solution { public: /* 题意:删除链表中倒数第n个结点,尽量只扫描一遍。 使用两个指针扫描,当第一个指针扫描到第N个结点后, 第二个指针从表头与第一个指针同时向后移动, 当第一个指针指向空节点时,另一个指针就指向倒数第n个结点了 */ ListNode* removeNthFromEnd(ListNode* head, int n) { ListNode *res = new ListNode(0); res->next = head; ListNode *tmp = res; for (int i = 0; i < n; i++) { head = head->next; } while (head != NULL) { head = head->next; tmp = tmp->next; } tmp->next = tmp->next->next; return res->next; } };
20、Valid Parentheses
题意:判断括号对序列是否合法
我的思路:栈
我的代码:
class Solution { public: bool isValid(string s) { stack<char> judge; for (int i = 0; i < s.size(); i++) { if (s[i] == '(' || s[i] == '[' || s[i] == '{') { judge.push(s[i]); } else { if (judge.empty()) return false; char c = judge.top(); judge.pop(); if (s[i]-c > 2 || s[i]-c < 1) return false; } } if (judge.empty()) return true; else return false; } };
九章思路:一致
九章代码:
class Solution { public: /* 题意:输入一个只包含括号的字符串,判断括号是否匹配 模拟堆栈,读到左括号压栈,读到右括号判断栈顶括号是否匹配 */ bool isValidParentheses((string s) { int len = s.length(); vector<char> stack; for (int i = 0; i < len; i++) { // 左括号压栈 if (s[i] == '(' || s[i] == '[' || s[i] == '{') stack.push_back(s[i]); else { // 右括号出栈 if (stack.empty()) return false; char top = stack[stack.size() - 1]; if (s[i] == ')' && top != '(') return false; if (s[i] == ']' && top != '[') return false; if (s[i] == '}' && top != '{') return false; stack.pop_back(); } } // 栈中无多余左括号 if (stack.size() > 0) return false; return true; } };
21、 Merge Two Sorted Lists
题意:将两个有序链表合并成一个
我的思路:哪个小串哪个
我的代码:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { ListNode *res = new ListNode(0); ListNode *ans = res; while (l1 && l2) { if (l1->val <= l2->val) { res->next = l1; l1 = l1->next; res = res->next; } else { res->next = l2; l2 = l2->next; res = res->next; } } if (l1) res->next = l1; else res->next = l2; return ans->next; } };
九章最优解:思路代码都一样。。
23. Merge k Sorted Lists
题意:合并k个有序链表
我的思路:常规题。。
我的代码:
class Solution { public: ListNode* mergeKLists(vector<ListNode*>& lists) { ListNode* ans = new ListNode(0); ListNode* tmp = ans; int k, minn; while (1) { k = -1; minn = 0x7fffffff; for (int i = 0; i < lists.size(); i++) { if (lists[i] == NULL) continue; if (lists[i]->val < minn) { minn = lists[i]->val; k = i; } } if (k == -1) break; tmp->next = lists[k]; lists[k] = lists[k]->next; tmp = tmp->next; } return ans->next; } };
solution解法:时间爆出屎,类似归并排序
class Solution { public: ListNode* mergeKLists(vector<ListNode*>& lists) { if (!lists.size()) { return NULL; } return mergeKlistsHelper(lists, 0, lists.size() - 1); } ListNode* mergeKlistsHelper(vector<ListNode*>& lists, int begin, int end) { int mid = (begin + end) / 2; ListNode *l1, *l2; if(begin >= end) { return lists[begin]; } l1 = mergeKlistsHelper(lists, begin, mid); l2 = mergeKlistsHelper(lists, mid + 1, end); return mergeTwoLists(l1, l2); } ListNode* mergeTwoLists(ListNode* l1, ListNode* l2) { if (l1 == NULL) { return l2; } if (l2 == NULL) { return l1; } ListNode dummy(INT_MIN); ListNode *head = &dummy; while (l1 && l2) { if (l1->val < l2->val) { head->next = l1; l1 = l1->next; } else { head->next = l2; l2 = l2->next; } head = head->next; } head->next = l1 ? l1 : l2; return dummy.next; } };
24、 Swap Nodes in Pairs
题意:交换链表相邻节点
我的思路:不被指针整晕就可以。。注意奇数个节点的情况
我的代码:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* swapPairs(ListNode* head) { if (head == NULL || head->next == NULL) return head; ListNode* ans = new ListNode(0); ListNode* tmp = ans; while (head && head->next) { tmp->next = head->next; tmp = head; head = head->next; tmp->next = head->next; head->next = tmp; head = head->next->next; } return ans->next; } };
九章最优解:思路一致,代码很像但是比我的长哈哈
class Solution { public: /** * @param head a ListNode * @return a ListNode */ ListNode* swapPairs(ListNode* head) { // Write your code here if(head==NULL || head->next==NULL) return head; ListNode *helper=new ListNode(0); ListNode *ret=head; ListNode *cur=helper; while(ret && ret->next) { ListNode *next=ret->next->next; cur->next=ret->next; cur=cur->next; cur->next=ret; cur=cur->next; cur->next=NULL; ret=next; } if(ret) cur->next=ret; return helper->next; } };
25. Reverse Nodes in k-Group
题意:将链表以k为一组翻转
我的思路:指针数组
我的代码:
class Solution { public: ListNode* reverseKGroup(ListNode* head, int k) { if (head == NULL || head->next == NULL) return head; ListNode* ans = new ListNode(0); ListNode* l = ans; vector<ListNode*> tmp(k); while (head) { int i; for (i = 0; i < k; i++) { tmp[i] = head; if (head == NULL) break; head = head->next; } if (i < k) { l->next = tmp[0]; break; } l->next = tmp[i-1]; tmp[0]->next = tmp[i-1]->next; l = tmp[0]; for (int j = k-1; j > 0; j--) tmp[j]->next = tmp[j-1]; } return ans->next; } };
solution解法:
class Solution { public: ListNode* reverseKGroup(ListNode* head, int k) { ListNode* node = head; int cnt = 0; for (; node && cnt < k - 1; cnt++) node = node->next; if (!node) return head; else node->next = reverseKGroup(node->next, k); ListNode dummy(-1); ListNode* root = &dummy; root->next = head; for (int i = 1; i < k; i++) { ListNode* cur = head->next; head->next = cur->next; cur->next = root->next; root->next = cur; } return dummy.next; }
26、Remove Duplicates from Sorted Array
题意:删除有序数组中重复的元素,将所有不同元素排在数组前边,后边不管
我的思路:两个相邻指针往后扫,元素不相等时入数组,相等时扫过
我的代码(写的相当满意~):
class Solution { public: int removeDuplicates(vector<int>& nums) { int i = 0, ans = 0; while (i < nums.size()) { while (i+1 < nums.size() && nums[i] == nums[i+1]) i++; nums[ans++] = nums[i++]; } return ans; } };
九章最优解:从第二个元素起往后扫,遇到不一样的元素加入数组,更简单一些。。
九章代码:
class Solution { public: /** * @param A: a list of integers * @return : return an integer */ int removeDuplicates(vector<int> &nums) { if (nums.size() == 0) { return 0; } int len = 0; for (int i = 1; i < nums.size(); i++) { if (nums[len] != nums[i]) { nums[++len] = nums[i]; } } return len + 1; } };
27、Remove Element
题意:删除数组中给定元素,水题
我的代码:
class Solution { public: int removeElement(vector<int>& nums, int val) { int ans = 0; for (int i = 0; i < nums.size(); i++) { if (nums[i] != val) nums[ans++] = nums[i]; } return ans; } };
九章最优解:一样
class Solution { public: /** *@param A: A list of integers *@param elem: An integer *@return: The new length after remove */ int removeElement(vector<int> &A, int elem) { // write your code here int start = 0; int n = A.size(); for(int i = 0; i < n; i++) if (elem != A[i]) { A[start++] = A[i]; } return start; } };
28、Implement strStr()
题意:给定两个字符串,返回后一个字符串存在于前一个字符串中的索引值,不存在返回-1
我的思路:暴搜,当大串后边长度不足小串长度时即可停止。这里发现string.size()的返回值是unsigned int!
我的代码:
class Solution { public: int strStr(string haystack, string needle) { if (needle.size() == 0) return 0; int i = 0, j; while (i < (int)(haystack.size()-needle.size()+1)) { j = 0; while (j < needle.size() && haystack[i+j] == needle[j]) j++; if (j == needle.size()) return i; i++; } return -1; } };
九章最优解:思路一样
九章代码:
class Solution { public: int strStr(string haystack, string needle) { int i, j, lenh = haystack.length(), lenn = needle.length(); if (lenn == 0) return 0; for (i = 0; i <= lenh - lenn; i++) { for (j = 0; j < lenn; j++) if (haystack[i + j] != needle[j]) break; // 匹配成功 if (j == lenn) return i; } return -1; } };
29. Divide Two Integers
题意:不用乘除做除法
我的思路:将商表示成2进制的形式,将可以用左移代替乘2
我的代码:
class Solution { public: int divide(int dividend, int divisor) { if (divisor == 0 || dividend == 0x80000000 && divisor == -1) return 0x7fffffff; if (divisor == 1) return dividend; int flag = (dividend^divisor)>>31 ? -1 : 1; long long a = abs((long long)dividend), b = abs((long long)divisor); int ans = 0; while (b <= a) { int tmp = 0; while ((b<<tmp) <= a) tmp++; ans += 1<<(tmp-1); a -= b<<(tmp-1); } return ans*flag; } };
30. Substring with Concatenation of All Words
题意:给一个长串s和很多长度相同的短串,找出s中的索引,从它开始出现所有短串各一次且中间没别的字符
我的思路:简单hash
class Solution { public: vector<int> findSubstring(string s, vector<string>& words) { map <string, int> hash; vector<int> ans; int n = words.size(), m = words[0].size(); for (int i = 0; i < n; i++) { if (hash.find(words[i]) != hash.end()) hash[words[i]]++; else hash[words[i]] = 1; } for (int i = 0; i <= (int)s.size()-n*m; i++) { map <string, int> chash = hash; for (int j = 0; j < n; j++) { string ss; for (int k = 0; k < m; k++) ss += s[i+j*m+k]; if (chash.find(ss) == chash.end()) break; else { chash[ss]--; if (chash[ss] < 1) chash.erase(ss); } } if (chash.size() == 0) ans.push_back(i); } return ans; } };
disscuss有O(n)解法
31、 Next Permutation
题意:输出给定数组的下一个排列
我的思路:我知道这么一个函数。。
我的代码:
class Solution { public: void nextPermutation(vector<int>& nums) { next_permutation(nums.begin(), nums.end()); } };
九章最优解:(1)从右往左找到第一个破坏升序(非严格)的元素num1,下标为i;(2)从右往左找到第一个大于num1的元素num2,交换num1和num2;(3)从i+1到最右端逆置。
九章代码:
#include <vector> using namespace std; class Solution { public: /** * @param nums: An array of integers * @return: An array of integers that's next permuation */ vector<int> nextPermutation(vector<int> &nums) { int i = nums.size() - 2; while (i >= 0 && nums[i] >= nums[i + 1]) { i--; } if (i < 0) { reverse(nums.begin(), nums.end() - 1); } else { int j = i + 2; while (j < nums.size() && nums[j] > nums[i]) { j++; } j--; nums[i] ^= nums[j]; nums[j] ^= nums[i]; nums[i] ^= nums[j]; reverse(nums.begin() + i + 1, nums.end() - 1); } return nums; } private: void reverse(vector<int>::iterator i1, vector<int>::iterator i2) { while (i1 < i2) { *i1 ^= *i2; *i2 ^= *i1; *i1 ^= *i2; i1++; i2--; } } };
278、First Bad Version
题意:一组产品从某个之后全是坏的,找第一个坏的
我的思路:二分
我的代码:
// Forward declaration of isBadVersion API. bool isBadVersion(int version); class Solution { public: int firstBadVersion(int n) { int l = 1, r = n; while (l < r) { int mid = (int)(((long long)l+r)/2); if (isBadVersion(mid)) { r = mid; } else { l = mid+1; } } return r; } };
九章最优解:思路一样
九章代码:
bool isBadVersion(int version); class Solution { public: /** * @param n: An integers. * @return: An integer which is the first bad version. */ int findFirstBadVersion(int n) { int start = 1, end = n; while (start + 1 < end) { int mid = start + (end - start) / 2; if (isBadVersion(mid)) { end = mid; } else { start = mid; } } if (isBadVersion(start)) { return start; } return end; } };
33. Search in Rotated Sorted Array
题意:在折过的有序数组中查找特定值,返回下标
我的思路:渣渣暴力
我的代码:
class Solution { public: int search(vector<int>& nums, int target) { for (int i = 0; i < nums.size(); i++) if (nums[i] == target) return i; return -1; } };
九章最优解:二分,根据一个区间的首尾项即可判断其中间有无折断,没有折断时普通二分查找,有折断时mid前后两端区间分别进行一次相同的递归
九章代码:
class Solution { public: int find(vector<int>& nums, int l, int r, int target) { if (l > r) return -1; int indx = -1; if (nums[l] <= nums[r]) { int left = l, right = r; while (left+1 < right) { int mid = (left+right)/2; if (nums[mid] > target) { right = mid; } else { left = mid; } } if (nums[left] == target) indx = left; if (nums[right] == target) indx = right; } else { int mid = (l+r)/2; if (nums[mid] == target) return mid; indx = find(nums, l, mid-1, target); indx = indx == -1 ? find(nums, mid+1, r, target) : indx; } return indx; } int search(vector<int>& nums, int target) { return find(nums, 0, nums.size()-1, target); } };
34、 Search for a Range
题意:在给定有序数组中查找给定target值的左右边界,没有此值时返回(-1,-1)
我的思路1:分别二分查找左右边界,此题严重显示了二分不熟练
我的代码1:
class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { int l = 0, r = nums.size() - 1; vector<int> ans; while (l+1 < r) { int mid = (l + r) / 2; if (nums[mid] >= target) { r = mid; } else { l = mid; } } if (nums[l] == target) { ans.push_back(l); } else if (nums[r] == target) { ans.push_back(r); } else { ans.push_back(-1); ans.push_back(-1); return ans; } l = 0, r = nums.size() - 1; while (l+1 < r) { int mid = (l + r) / 2; if (nums[mid] > target) { r = mid; } else { l = mid; } } if (nums[r] == target) { ans.push_back(r); } else if (nums[l] == target) { ans.push_back(l); } return ans; } };
九章最优解:用find函数查找左边界,再倒暴搜右边界
九章代码:
class Solution { /** *@param A : an integer sorted array *@param target : an integer to be inserted *return : a list of length 2, [index1, index2] */ public: vector<int> searchRange(vector<int> &A, int target) { // write your code here vector<int> result; vector<int>::iterator p; int l,r ; p = find( A.begin( ), A.end( ), target ); if (p != A.end()) l = p - A.begin(); else l = -1; r = -1; int len = A.size(); for (int i = len-1; i>=0; --i) if (A[i]==target) { r = i; break; } result.push_back(l); result.push_back(r); return result; } };
我的思路2:突然想起了lower_bound函数(返回不小于目标值的第一个索引)和upper_bound函数(返回大于目标值的第一个索引)
我的代码2:
class Solution { public: vector<int> searchRange(vector<int>& nums, int target) { vector<int> ans; int l = lower_bound(nums.begin(), nums.end(), target) - nums.begin(); if (l == nums.size() || nums[l] != target) { ans.push_back(-1); ans.push_back(-1); return ans; } else { ans.push_back(l); int r = upper_bound(nums.begin(), nums.end(), target) - nums.begin(); ans.push_back(r-1); } return ans; } };
35. Search Insert Position
题意:查找给定值在有序数组中的位置,没有此元素时返回要插入的位置
我的思路:二分
我的代码:
class Solution { public: int searchInsert(vector<int>& nums, int target) { int l = 0, r = nums.size() - 1; while (l + 1 < r) { int mid = (l + r) / 2; if (nums[mid] > target) { r = mid; } else { l = mid; } } if (nums[l] >= target) { return l; } else if (nums[r] >= target) { return r; } else { return r + 1; } } };
九章最优解:思路一样
九章代码:
public: int searchInsert(vector<int> &A, int target) { // find first position >= target if (A.size() == 0) { return 0; } int start = 0, end = A.size() - 1; while (start + 1 < end) { int mid = (end - start) / 2 + start; if (A[mid] >= target) { end = mid; } else { start = mid; } } if (A[start] >= target) { return start; } if (A[end] >= target) { return end; } return A.size(); } };
36. Valid Sudoku
题意:判二维数组是否合法,合法标准:同一行、同一列、同一九宫格数字1-9不能重复
我的思路:判行判列判方块
我的代码:
class Solution { private: const int dir[9][2] = {{-1, -1}, {-1, 0}, {-1, 1}, {0, -1}, {0, 0}, {0, 1}, {1, -1}, {1, 0}, {1, 1}}; bool is(vector<vector<char>>& board, int x, int y) { bool flag[10]; memset(flag, 0, sizeof(flag)); for (int i = 0; i < 9; i++) { int xx = x + dir[i][0], yy = y + dir[i][1]; if (board[xx][yy] >= '0' && board[xx][yy] <= '9') { if (flag[board[xx][yy]-'0']) return true; flag[board[xx][yy]-'0'] = true; } } return false; } public: bool isValidSudoku(vector<vector<char>>& board) { bool flag[10]; for (int i = 0; i < board.size(); i++) { memset(flag, 0, sizeof(flag)); for (int j = 0; j < board[0].size(); j++) { if (board[i][j] >= '0' && board[i][j] <= '9') { if (flag[board[i][j]-'0']) return false; flag[board[i][j]-'0'] = true; } } } for (int i = 0; i < board[0].size(); i++) { memset(flag, 0, sizeof(flag)); for (int j = 0; j < board.size(); j++) { if (board[j][i] >= '0' && board[j][i] <= '9') { if (flag[board[j][i]-'0']) return false; flag[board[j][i]-'0'] = true; } } } for (int i = 1; i < board.size() - 1; i += 3) { for (int j = 1; j < board[0].size() - 1; j += 3) { if (is(board, i, j)) return false; } } return true; } };
九章最优解:思路一样,主要才知道棋盘是固定的9*9。。。
九章代码:
class Solution { public: bool isValidSudoku(const vector<vector<char>>& board) { bool used[9]; for (int i = 0; i < 9; ++i) { fill(used, used + 9, false); for (int j = 0; j < 9; ++j) // 检查行 if (!check(board[i][j], used)) return false; fill(used, used + 9, false); for (int j = 0; j < 9; ++j) // 检查列 if (!check(board[j][i], used)) return false; } for (int r = 0; r < 3; ++r) // 检查9 个子格子 for (int c = 0; c < 3; ++c) { fill(used, used + 9, false); for (int i = r * 3; i < r * 3 + 3; ++i) for (int j = c * 3; j < c * 3 + 3; ++j) if (!check(board[i][j], used)) return false; } return true; } bool check(char ch, bool used[9]) { if (ch == '.') return true; if (used[ch - '1']) return false; return used[ch - '1'] = true; } };
37. Sudoku Solver
题意:填数独
我的思路:每个空位放1-9,判是否合法
我的代码:
class Solution { public: bool isValid(vector<vector<char>>& board, int i, int j) { for(int k=0;k<9;k++) if(k!=j && board[i][k]==board[i][j]) return false; for(int k=0;k<9;k++) if(k!=i && board[k][j]==board[i][j]) return false; for(int row = i/3*3; row<i/3*3+3; row++) for(int col=j/3*3; col<j/3*3+3; col++) if((row!=i || col!=j) && board[row][col]==board[i][j]) return false; return true; } bool dfs(vector<vector<char>>& board, int x, int y) { if (x > 8) return 1; if (y > 8) return dfs(board, x+1, 0); if (board[x][y] == '.') { for (int i = 1; i < 10; i++) { board[x][y] = i+'0'; if (isValid(board, x, y) && dfs(board, x, y+1)) return 1; board[x][y] = '.'; } } else return dfs(board, x, y+1); return 0; } void solveSudoku(vector<vector<char>>& board) { if (board.size() == 0 || board.size()!= 9 || board[0].size() != 9) return; dfs(board, 0, 0); } };
38. Count and Say
题意:下一个串是前一个串的描述,如1, 11, 21, 1211, 111221, ...,写出第n个串
我的思路:模拟
我的代码:
class Solution { public: string countAndSay(int n) { if (n == 1) return "1"; if (n == 2) return "11"; string ans, tmp; ans.append("11"); while (n > 2) { tmp.clear(); int cnt = 1; for (int i = 1; i < ans.size(); i++) { if (ans[i] == ans[i-1]) { cnt++; } else { tmp.push_back('0' + cnt); tmp.push_back(ans[i-1]); cnt = 1; } } tmp.push_back('0' + cnt); tmp.push_back(ans[ans.size() - 1]); ans = tmp; n--; } return ans; } };
九章最优解:思路都一样,直接上代码吧
class Solution { public: string int_to_string(int j) { stringstream in; in << j; string temp; in >> temp; return temp; } string genate(string s) { string now; int j = 0; for(int i = 0; i < s.size(); i += j) { for(j = 0; j + i < s.size(); j++) { if(s[i] != s[i+j]) { break; } } now = now + int_to_string(j) + s[i]; } return now; } string countAndSay(int n) { string s("1"); while(--n) { s = genate(s); } return s; } };
39. Combination Sum
题意:从集合(元素不重复)中找出所有和为target的数字组合,每个数字都可以重复多次,但是输出组合不能重复
我的思路:dfs,每次递归维护插入值的索引,从此值开始往后找即可避免重复集合
我的代码:
class Solution { private: void dfs(vector<int>& candidates, vector<vector<int>>& ans, vector<int> tmp, int sum, int target, int j) { if (sum == target) { ans.push_back(tmp); return; } else if (sum > target) { return; } else { for (int i = j; i < candidates.size(); i++) { if (i > j) tmp.pop_back(); tmp.push_back(candidates[i]); dfs(candidates, ans, tmp, sum+candidates[i], target, i); } } } public: vector<vector<int>> combinationSum(vector<int>& candidates, int target) { vector<vector<int>> ans; vector<int> tmp; dfs(candidates, ans, tmp, 0, target, 0); return ans; } };
九章最优解:思路一致,个人认为排序是多余的
九章代码:
class Solution { private: const int index_count; vector<vector<int> > results; public: Solution() : index_count(10000) {}; void backtrace(int target, int sum, vector<int> &candidates, int index[], int n) { if (sum > target) { return; } if (sum == target) { vector<int> result; for (int i = 1; i <= n; ++i) { result.push_back(candidates[index[i]]); } results.push_back(result); return; } for (int i = index[n]; i < candidates.size(); ++i) { index[n+1] = i; backtrace(target, sum+candidates[i], candidates, index, n+1); } } /** * @param candidates: A list of integers * @param target:An integer * @return: A list of lists of integers */ vector<vector<int> > combinationSum(vector<int> &candidates, int target) { // write your code here sort(candidates.begin(), candidates.end()); int m = 0, n = candidates.size(); for (int i = 1; i < n; ++i) if (candidates[i] != candidates[m]) candidates[++m] = candidates[i]; candidates.resize(m + 1); int *index = new int[index_count]; memset(index, 0, sizeof(int)*index_count); results.clear(); backtrace(target, 0, candidates, index, 0); delete[] index; return results; } };
40. Combination Sum II
题意: 从集合(元素有重复)中找出所有和为target的数字组合,每个数字都可以重复多次(最多出现原给的次数),但是输出组合不能重复
我的思路:相比于上一道题,只需要在dfs之后加一句跳过所有相同元素即可
我的代码:
class Solution { private: void dfs(vector<int>& candidates, vector<vector<int>>& ans, vector<int> tmp, int sum, int target, int j) { if (sum == target) { ans.push_back(tmp); return; } else { for (int i = j; i < candidates.size(); i++) { if (i > j) tmp.pop_back(); tmp.push_back(candidates[i]); if (sum + candidates[i] <= target)dfs(candidates, ans, tmp, sum + candidates[i], target, i+1); while (candidates[i + 1] == candidates[i]) i++; } } } public: vector<vector<int>> combinationSum2(vector<int>& candidates, int target) { vector<vector<int>> ans; vector<int> tmp; sort(candidates.begin(), candidates.end()); dfs(candidates, ans, tmp, 0, target, 0); return ans; } };
九章最优解:一句注释没有没太明白啥思路。。
九章代码:
class Solution { public: /** * @param num: Given the candidate numbers * @param target: Given the target number * @return: All the combinations that sum to target */ vector<vector<int> > combinationSum2(vector<int> &num, int target) { // write your code here sort(num.begin(), num.end()); vector<int> stack, rec; int sum=0, cur=0; vector<vector<int> > ans; while (cur<num.size() && num[cur]+sum<=target) { stack.push_back(num[cur]); rec.push_back(cur); sum+=num[cur++]; } if (sum==target) ans.push_back(stack); while (rec.size()!=0) { cur=rec.back(); int x=num[cur]; sum-=x; stack.pop_back(); rec.pop_back(); for (++cur; cur<num.size(); ++cur) if (num[cur]!=x || sum+num[cur]>target) break; if (cur<num.size() && num[cur]!=x) while (cur<num.size() && num[cur]+sum<=target) { stack.push_back(num[cur]); rec.push_back(cur); sum+=num[cur++]; } if (sum==target) ans.push_back(stack); } return ans; } };
41. First Missing Positive
题意:找出无序数组中缺失的第一个正数
我的思路:将每个正数放到他的值减1的位置,再扫一轮
我的代码:
class Solution { public: int firstMissingPositive(vector<int>& nums) { for (int i = 0; i < nums.size(); i++) { if (nums[i] > 0 && nums[i] <= nums.size() && nums[i] != i+1 && nums[i] != nums[nums[i]-1]) { int tmp = nums[nums[i]-1]; nums[nums[i]-1] = nums[i]; nums[i--] = tmp; } } for (int i = 0; i < nums.size(); i++) if (nums[i] != i+1) return i+1; return nums.size()+1; } };
42. Trapping Rain Water
题意:给定一个数组,每个数表示一个宽度为1的柱形,输出最毒存多少水
我的思路:先从左至右扫一遍,保存lmax[i]表示i位置i左边(不包括i处)的最高值,再从右到左扫一遍rmax保存右边最高值;最后遍历整个数组,若min(lmax[i], rmax[height.size()-1-i]) > height[i],结果加上他们的差值
我的代码:
class Solution { public: int trap(vector<int>& height) { if (height.size() == 0) return 0; vector<int> lmax, rmax; int ans = 0; lmax.push_back(0); for (int i = 1; i < height.size(); i++) { if (lmax[lmax.size()-1] > height[i-1]) { lmax.push_back(lmax[lmax.size()-1]); } else { lmax.push_back(height[i-1]); } } rmax.push_back(0); for (int i = height.size()-2; i >= 0; i--) { if (height[i+1] < rmax[rmax.size()-1]) { rmax.push_back(rmax[rmax.size()-1]); } else { rmax.push_back(height[i+1]); } } for (int i = 1; i < height.size()-1; i++) { int bian = min(lmax[i], rmax[height.size()-1-i]); if (height[i] < bian) ans += bian-height[i]; } return ans; } };
九章最优解:先遍历一遍找到塔顶,然后分别从两边开始,往塔顶所在位置遍历,水位只会增高不会减小,且一直和最近遇到的最大高度持平,这样知道了实时水位,就可以边遍历边计算面积。
九章代码:
class Solution { public: int trap(vector<int>& heights) { int maxHeight = 0, maxIndex; for (int i = 0; i < heights.size(); i++) { if (heights[i] > maxHeight) { maxHeight = heights[i]; maxIndex = i; } } int sum = 0; maxHeight = 0; for (int i = 0; i < maxIndex; i++) { if (maxHeight > heights[i]) { sum += maxHeight - heights[i]; } maxHeight = max(maxHeight, heights[i]); } maxHeight = 0; for (int i = heights.size() - 1; i > maxIndex; i--) { if (maxHeight > heights[i]) { sum += maxHeight - heights[i]; } maxHeight = max(maxHeight, heights[i]); } return sum; } };
43. Multiply Strings
题意:大数乘法
思路:模拟手算,push_back()插入的是大索引值
我的代码:
class Solution { private: void reverse(string &s) { int l = s.size(); for (int i = 0; i < l/2; i++) { s[i] ^= s[l-1-i]; s[l-1-i] ^= s[i]; s[i] ^= s[l-1-i]; } } public: string multiply(string num1, string num2) { if ((num1.size() == 1) && (num1[0] == '0') || (num2.size() == 1) && (num2[0] == '0')) return "0"; string ans; int w; reverse(num1); reverse(num2); for (int i = 0; i < num2.size(); i++) { w = 0; for (int j = 0; j < num1.size(); j++) { int k = (num2[i] - '0') * (num1[j] - '0') + w; if (ans.size() > i + j) { w = (ans[i+j] - '0' + k) / 10; ans[i+j] = (ans[i+j] - '0' + k) % 10 + '0'; } else { ans.push_back(k % 10 + '0'); w = k / 10; } } if (w) ans.push_back(w + '0'); } reverse(ans); return ans; } };
46. Permutations
题意:输出给定数组的所有排列
我的思路:next_permutation
我的代码:
class Solution { public: vector<vector<int>> permute(vector<int>& nums) { int n = 1; for (int i = nums.size(); i > 0; i--) n *= i; n--; vector<vector<int>> ans; ans.push_back(nums); while (n--) { next_permutation(nums.begin(), nums.end()); ans.push_back(nums); } return ans; } };
九章最优解:
// version 2: Recursion class Solution { public: /** * @param nums: A list of integers. * @return: A list of permutations. */ vector<vector<int> > permute(vector<int> nums) { vector<vector<int> > res; int n = nums.size(); if (n == 0) { res.push_back(vector<int>()); return res; } helper(res, nums, n - 1); return res; } void helper(vector<vector<int> > &res, vector<int> nums, int n){ if(n == 0){ res.push_back(nums); } for(int i = 0 ; i <= n; i++){ swap(nums[i], nums[n]); helper(res, nums, n - 1); swap(nums[i], nums[n]); } } }; // version 1: Non-Recursion class Solution { public: /** * @param nums: A list of integers. * @return: A list of permutations. */ vector<vector<int> > permute(vector<int> nums) { vector<vector<int> > permutations; if (nums.size() == 0) { permutations.push_back(vector<int>()); return permutations; } int n = nums.size(); vector<int> stack; bool inStack[n]; for (int i = 0; i < n; i++) { inStack[i] = false; } stack.push_back(-1); while (stack.size() != 0) { // pop the last int last = stack[stack.size() - 1]; stack.pop_back(); if (last != -1) { inStack[last] = false; } // increase the last, find the next bigger & avaiable number int next = -1; for (int i = last + 1; i < n; i++) { if (inStack[i] == false) { next = i; break; } } if (next == -1) { continue; } // generate the next permutation stack.push_back(next); inStack[next] = true; for (int i = 0; i < n; i++) { if (!inStack[i]) { stack.push_back(i); inStack[i] = true; } } // generate real permutation from index vector<int> permutation; for (int i = 0; i < n; i++) { permutation.push_back(nums[stack[i]]); } permutations.push_back(permutation); } return permutations; } };
47. Permutations II
题意:在有重复元素的情况下写出所有排列
我的思路:next_permutation函数可以去除重复元素带来的排列重复问题
我的代码:
class Solution { public: vector<vector<int>> permuteUnique(vector<int>& nums) { vector<int> prime(nums); vector<vector<int>> ans; while (1) { ans.push_back(nums); next_permutation(nums.begin(), nums.end()); if (nums == prime) break; } return ans; } };
九章最优解:
class Solution { /** * @param nums: A list of integers. * @return: A list of unique permutations. */ public List<List<Integer>> permuteUnique(int[] nums) { ArrayList<List<Integer>> results = new ArrayList<List<Integer>>(); if (nums == null) { return results; } if(nums.length == 0) { results.add(new ArrayList<Integer>()); return results; } Arrays.sort(nums); ArrayList<Integer> list = new ArrayList<Integer>(); int[] visited = new int[nums.length]; for ( int i = 0; i < visited.length; i++){ visited[i] = 0; } helper(results, list, visited, nums); return results; } public void helper(ArrayList<List<Integer>> results, ArrayList<Integer> list, int[] visited, int[] nums) { if(list.size() == nums.length) { results.add(new ArrayList<Integer>(list)); return; } for(int i = 0; i < nums.length; i++) { if ( visited[i] == 1 || ( i != 0 && nums[i] == nums[i - 1] && visited[i-1] == 0)){ continue; } /* 上面的判断主要是为了去除重复元素影响。 比如,给出一个排好序的数组,[1,2,2],那么第一个2和第二2如果在结果中互换位置, 我们也认为是同一种方案,所以我们强制要求相同的数字,原来排在前面的,在结果 当中也应该排在前面,这样就保证了唯一性。所以当前面的2还没有使用的时候,就 不应该让后面的2使用。 */ visited[i] = 1; list.add(nums[i]); helper(results, list, visited, nums); list.remove(list.size() - 1); visited[i] = 0; } } }
48. Rotate Image
题意:将矩阵顺时针旋转90度
我的思路:易知顺时针旋转90度就是第一行变最后一列、第二行变倒数第二列......也可以这样实现,先把行以中心线为轴交换,再做转置
我的代码:
class Solution { public: void rotate(vector<vector<int>>& matrix) { for (int i = 0; i < matrix.size()/2; i++) { vector<int> tmp = matrix[i]; matrix[i] = matrix[matrix.size()-1-i]; matrix[matrix.size()-1-i] = tmp; } for (int i = 0; i < matrix.size(); i++) { for (int j = 0; j < i; j++) { int tmp = matrix[i][j]; matrix[i][j] = matrix[j][i]; matrix[j][i] = tmp; } } } };
九章最优解:没注释看起来是真tm难受啊
九章代码:
class Solution { public: /** * @param matrix: A list of lists of integers * @return: Void */ void rotate(vector<vector<int> > &matrix, size_t topleft, size_t bottomright) { for (size_t i = 0; i < bottomright - topleft; ++i) { int tmp = matrix[topleft][topleft + i]; matrix[topleft][topleft + i] = matrix[bottomright - i][topleft]; matrix[bottomright - i][topleft] = matrix[bottomright][bottomright - i]; matrix[bottomright][bottomright - i] = matrix[topleft + i][bottomright]; matrix[topleft + i][bottomright] = tmp; } } void rotate(vector<vector<int> > &matrix) { // write your code here if (matrix.size() <= 0) return ; size_t topleft = 0, bottomright = matrix.size() - 1; while (topleft < bottomright) { rotate(matrix, topleft, bottomright); ++topleft; --bottomright; } } };
242. Valid Anagram
题意:判断t串是否能由s串改变字母顺序得到
我的思路:大水题,看他俩26个字母数是否分别一致即可
我的代码:
class Solution { public: bool isAnagram(string s, string t) { vector<int> num1(26,0), num2(26,0); for (int i = 0; i < s.size(); i++) num1[s[i]-'a']++; for (int i = 0; i < t.size(); i++) num2[t[i]-'a']++; for (int i = 0; i < 26; i++) if (num1[i] != num2[i]) return 0; return 1; } };
九章没有
49. Group Anagrams
题意:给定若干字符串,将相同字符组成的串归为一类输出一个vector<vector<string>> ans。
我的思路:遍历每个字符串,对其最小字典序哈希,记录在ans中的下标,归类push_back
我的代码:
class Solution { public: vector<vector<string>> groupAnagrams(vector<string>& strs) { vector<vector<string>> ans; vector<string> kk; int k = 0, n = strs.size(); unordered_map<string, int> hash; for (int i = 0; i < n; i++) { string tmp = strs[i]; sort(tmp.begin(), tmp.end()); if (hash.find(tmp) != hash.end()) { ans[hash[tmp]].push_back(strs[i]); } else { hash[tmp] = k; ans.push_back(kk); ans[k++].push_back(strs[i]); } } return ans; } };
没有九章最优解
50. Pow(x, n)
题意:计算一个小数的n次方,n可以为负数
我的思路:快速幂
我的代码:
class Solution { public: double myPow(double x, int n) { double ans = 1.0; long long nn = n; bool flag = 0; if (nn < 0) { flag = 1; nn = -nn; } while (nn > 0) { if (nn & 1) ans *= x; x = x * x; nn >>= 1; } if (flag) return 1/ans; return ans; } };
九章最优解:也是通过二分来加速,区别在于他用递归来实现
九章代码:
class Solution { public: /** * @param x the base number * @param n the power number * @return the result */ public: double myPow(double x, int n) { if (n < 0) return 1.0 / power(x, -n); else return power(x, n); } private: double power(double x, int n) { if (n == 0) return 1; double v = power(x, n / 2); if (n % 2 == 0) return v * v; else return v * v * x; } };
51. N-Queens
题意:输出n*n的棋盘上n皇后的所有方法,规则:皇后不能在同一行、列、对角线
我的思路:开三个标志数组分别标记某列、对角线(两个)有无皇后,进行深搜
我的代码:
1 class Solution { 2 private: 3 void dfs(vector<vector<string>> &ans, vector<string> tmp, bool *flag, bool *diag, bool *vice_diag, int i, int n) { 4 if (i == n) { 5 ans.push_back(tmp); 6 return; 7 } 8 for (int j = 0; j < n; j++) { 9 if (!flag[j] && !vice_diag[i+j] && !diag[i-j+n-1]) { 10 flag[j] = vice_diag[i+j] = diag[i-j+n-1] = true; 11 string tmpstr; 12 for (int k = 0; k < n; k++) { 13 if (k == j) { 14 tmpstr.push_back('Q'); 15 } else { 16 tmpstr.push_back('.'); 17 } 18 } 19 tmp.push_back(tmpstr); 20 dfs(ans, tmp, flag, diag, vice_diag, i+1, n); 21 tmp.erase(tmp.end()-1); 22 flag[j] = vice_diag[i+j] = diag[i-j+n-1] = 0; 23 } 24 } 25 } 26 27 public: 28 vector<vector<string>> solveNQueens(int n) { 29 vector<vector<string>> ans; 30 vector<string> tmp; 31 bool *flag = new bool[n]; 32 bool *diag = new bool[2*n-1]; 33 bool *vice_diag = new bool[2*n-1]; 34 memset(flag, 0, sizeof(flag)); 35 memset(diag, 0, sizeof(diag)); 36 memset(vice_diag, 0, sizeof(vice_diag)); 37 dfs(ans, tmp, flag, diag, vice_diag, 0, n); 38 return ans; 39 } 40 };
九章最优解:开一个记录列的数组col,col[i]的值意思是第i行的col[i]列是皇后,深搜判断是否与前面的皇后冲突即可,最后由col生成棋盘
class Solution { public: vector<vector<string> > solveNQueens(int n) { // write your code here vector<vector<string> > result; if( n <= 0 ) { return result; } vector<int> cols; search(n, cols, result); return result; } void search(int n, vector<int> &cols, vector<vector<string> > &result) { if(cols.size() == n) { result.push_back(drawResult(cols, n)); return; } for(int col = 0; col < n; col++) { if(!isValid(cols, col)) { continue; } cols.push_back(col); search(n, cols, result); cols.pop_back(); } } bool isValid(vector<int> &cols, int col) { int row = cols.size(); for(int i = 0; i < row; ++i) { if(cols[i] == col) { return false; } if(i - cols[i] == row - col) { return false; } if(i + cols[i] == row + col) { return false; } } return true; } vector<string> drawResult(vector<int> &cols, int n) { vector<string> result; for(int i = 0; i < cols.size(); ++i) { string temp(n, '.'); temp[cols[i]] = 'Q'; result.push_back(temp); } return result; } };
52. N-Queens II
题意:输出n*n的棋盘上n皇后的所有方法数目
我的思路:dfs,参见51题九章解,稍作改动即可
我的代码:
class Solution { public: bool isValid(int k, vector<int> &cols) { int j = cols.size(); for (int i = 0; i < j; i++) { if (cols[i] == k || cols[i]+i == j+k || cols[i]-i == k-j) return 0; } return 1; } void dfs(int n, vector<int> &cols, int &ans) { if (cols.size() == n) { ans++; return; } for (int i = 0; i < n; i++) { if (isValid(i, cols)) { cols.push_back(i); dfs(n, cols, ans); cols.pop_back(); } } } int totalNQueens(int n) { int ans = 0; vector<int> cols; dfs(n, cols, ans); return ans; } };
九章最优解:一致
class Solution { public: int sum; bool canPut(int row, int col, vector<int> &cols) { for (int i = 0; i < row; i++) { if (cols[i] - i == col - row) { return false; } if (cols[i] + i == col + row) { return false; } if (cols[i] == col) { return false; } } return true; } void dfs(int n, int k, vector<int> &cols) { if (k == n) { sum++; return; } for (int i = 0; i < n; i++) { if (!canPut(k, i, cols)) { continue; } cols[k] = i; dfs(n, k + 1, cols); } } int totalNQueens(int n) { vector<int> cols(n); sum = 0; dfs(n, 0, cols); return sum; } };
53. Maximum Subarray
题意:求最大子段和
我的思路:基础dp
我的代码:
class Solution { public: int maxSubArray(vector<int>& nums) { int ans = nums[0], sum = nums[0]; for (int i = 1; i < nums.size(); i++) { sum = sum > 0 ? sum + nums[i] : nums[i]; if (sum > ans) ans = sum; } return ans; } };
九章最优解:感觉并不好
class Solution { public: /** * @param nums: A list of integers * @return: A integer indicate the sum of max subarray */ int maxSubArray(vector<int> nums) { int sum = 0, minSum = 0, maxSum = INT_MIN; for (int i = 0; i < nums.size(); i++) { sum += nums[i]; maxSum = max(maxSum, sum - minSum); minSum = min(minSum, sum); } return maxSum; } };
54. Spiral Matrix
题意:将矩阵顺时针螺旋输出
我的思路:由外向里,给定左上角的位置,一次输出一个方框
我的代码:
class Solution { private: void out(int i, vector<vector<int>>& matrix, vector<int>& ans) { for (int j = i; j < matrix[i].size()-i; j++) ans.push_back(matrix[i][j]); for (int j = i+1; j < matrix.size()-i-1; j++) ans.push_back(matrix[j][matrix[i].size()-1-i]); for (int j = matrix[i].size()-1-i; matrix.size()-1-i != i && j >= i; j--) ans.push_back(matrix[matrix.size()-1-i][j]); for (int j = matrix.size()-i-2; matrix[i].size()-1-i != i && j >= i+1; j--) ans.push_back(matrix[j][i]); } public: vector<int> spiralOrder(vector<vector<int>>& matrix) { vector<int> ans; if (matrix.size() == 0) return ans; for (int i = 0; i <= (min(matrix.size(), matrix[0].size())-1)/2; i++) out(i, matrix, ans); return ans; } };
九章最优解:从matrix[0][0]开始,按右边、下边、左边、上边的优先级dfs,用一标志数组记录下已经入栈的元素不再查找
九章代码:
class Solution { public: /** * @param matrix a matrix of m x n elements * @return an integer array */ vector<int> spiralOrder(vector<vector<int>>& matrix) { // Write your code here step[0][0] = 0; step[0][1] = 1; step[1][0] = 1; step[1][1] = 0; step[2][0] = 0; step[2][1] = -1; step[3][0] = -1; step[3][1] = 0; ret.clear(); memset(canUse, true, sizeof(canUse)); dfs(matrix, 0, 0, -1); return ret; } private: int step[4][2]; vector<int> ret; bool canUse[100][100]; public: void dfs(vector<vector<int> > &matrix, int direct, int x, int y) { for(int i = 0; i < 4; i++) { int j = (direct + i) % 4; int tx = x + step[j][0]; int ty = y + step[j][1]; if (0 <= tx && tx < matrix.size() && 0 <= ty && ty < matrix[0].size() && canUse[tx][ty]) { canUse[tx][ty] = false; ret.push_back(matrix[tx][ty]); dfs(matrix, j, tx, ty); } } } };
59. Spiral Matrix II
题意:输出一个n维矩阵,从左上角起螺旋1~n2
我的思路:顺承上一题,先开一个n维数组,放数
我的代码:
class Solution { private: int cnt; void out(int i, int n, vector<vector<int>>& ans) { for (int j = i; j < n-i; j++) ans[i][j] = cnt++; for (int j = i+1; j < n-i-1; j++) ans[j][n-1-i] = cnt++; for (int j = n-1-i; n-1-i != i && j >= i; j--) ans[n-1-i][j] = cnt++; for (int j = n-i-2; n-1-i != i && j >= i+1; j--) ans[j][i] = cnt++; } public: vector<vector<int>> generateMatrix(int n) { vector<vector<int>> ans(n); for (int i = 0; i < n; i++) ans[i].resize(n); cnt = 1; for (int i = 0; i <= (n-1)/2; i++) out(i, n, ans); return ans; } };
九章最优解:dfs,类似54题
九章代码:
class Solution { public: /** * @param n an integer * @return a square matrix */ vector<vector<int>> generateMatrix(int n) { // Write your code here step[0][0] = 0; step[0][1] = 1; step[1][0] = 1; step[1][1] = 0; step[2][0] = 0; step[2][1] = -1; step[3][0] = -1; step[3][1] = 0; vector<vector<int> > ret(n, vector<int>(n)); memset(canUse, true, sizeof(canUse)); dfs(1, ret, 0, 0, -1); return ret; } private: int step[4][2]; bool canUse[100][100]; public: void dfs(int dep, vector<vector<int> > &matrix, int direct, int x, int y) { for(int i = 0; i < 4; i++) { int j = (direct + i) % 4; int tx = x + step[j][0]; int ty = y + step[j][1]; if (0 <= tx && tx < matrix.size() && 0 <= ty && ty < matrix[0].size() && canUse[tx][ty]) { canUse[tx][ty] = false; matrix[tx][ty] = dep; dfs(dep + 1, matrix, j, tx, ty); } } } };
55. Jump Game
题意:给定一个数组,每个数表示该位置可以往后走的距离,判断能否走到最后一个位置
我的思路:维护一个可以到达的最大位置,从头扫到尾更新、判断
我的代码:
class Solution { public: bool canJump(vector<int>& nums) { int maxn = 0; for (int i = 0; i < nums.size(); i++) { if (maxn >= nums.size()-1) return 1; if (i > maxn) return 0; maxn = max(maxn, i+nums[i]); } return 1; } };
九章最优解:思路一样,代码上我多了一条剪枝
九章代码:
class Solution { public: bool canJump(vector<int> A) { int tmpMax = 0; int n = A.size(); for (int i = 0; i < n; i++) { if (i > tmpMax) return false; if (tmpMax < i + A[i]) tmpMax = i + A[i]; } return true; } };
45. Jump Game II
题意:条件与55题一样,求到达最后一个位置的最小步数
我的思路:开一个数组step[i]记录到达位置i的最小步数
我的代码:
class Solution { public: int jump(vector<int>& nums) { if (nums.size() == 1) return 0; int n = nums.size(); int *step = (int *)malloc(n*sizeof(int)); for (int i = 0; i < n; i++) step[i] = 0; for (int i = 0; i < n; i++) { if (i+nums[i] >= n-1) return step[i]+1; for (int j = nums[i]; j > 0; j--) { if (step[i+j] == 0) step[i+j] = step[i]+1; } } return 0; } };
九章最优解:二指针问题,最大覆盖区间。从左往右扫描,维护一个每走一步的最大覆盖区间,每扫过一个元素,就重新计算覆盖区间的边界。比如,开始时区间[start, end], 遍历A数组的过程中,不断计算A[i]+i最大值(即从i坐标开始最大的覆盖坐标),并设置这个最大覆盖坐标为新的end边界。而新的start边界则为原end+1。不断循环,直到end> n。
九章代码:
class Solution { public: int jump(vector<int> A) { // Start typing your C/C++ solution below // DO NOT write int main() function int n = A.size(); int minstep = 0; int ldist = 0; int hdist = 0; if (n == 1) return 0; while(ldist <= hdist) { ++minstep; int lasthdist = hdist; for(int i = ldist; i <= lasthdist; ++i) { int possibledist = i + A[i]; if (possibledist >= n-1) return minstep; if (possibledist > hdist) { hdist = possibledist; } } ldist = lasthdist + 1; } return 0; } };
56. Merge Intervals
题意:容器中给出若干区间的首尾,将能合并的合并后输出
我的思路:将区间起始按从小到大排序,之后遍历所有区间,l为最小的起始,r为最大的结束,直到某个区间的起始大于之前最大的结束,则把当时的l和r组成一个区间加入结果中。此题要学会sort的比较函数的写法,写在类内时前边要加static变成静态函数,否则必须写在类外。
我的代码:
/** * Definition for an interval. * struct Interval { * int start; * int end; * Interval() : start(0), end(0) {} * Interval(int s, int e) : start(s), end(e) {} * }; */ class Solution { public: static bool cmp(const Interval& a, const Interval& b) { if (a.start == b.start) return a.end<b.end; return a.start<b.start; } vector<Interval> merge(vector<Interval>& intervals) { vector<Interval> ans; sort(intervals.begin(), intervals.end(), cmp); for (int i = 0; i < intervals.size(); i++) { int l = intervals[i].start, r = intervals[i].end; while (i+1 < intervals.size() && intervals[i+1].start <= r) { r = max(r, intervals[i+1].end); i++; } Interval tmp(l, r); ans.push_back(tmp); } return ans; } };
九章最优解:思路一样,写法有些区别
九章代码:
/** * Definition of Interval: * classs Interval { * int start, end; * Interval(int start, int end) { * this->start = start; * this->end = end; * } */ class Solution { public: /** * @param intervals: Sorted interval list. * @return: A new interval list. */ static bool comp(const Interval& a, const Interval& b){ return a.start < b.start; } vector<Interval> merge(vector<Interval> &intervals) { // write your code here vector<Interval> result; if(intervals.empty()){ return result; } sort(intervals.begin(), intervals.end(), comp); result.push_back(intervals[0]); for(int i = 1; i < intervals.size(); i++){ if(intervals[i].start <= result.back().end){ Interval temp(result.back().start, max(result.back().end, intervals[i].end)); result.pop_back(); result.push_back(temp); } else{ result.push_back(intervals[i]); } } return result; } };
57. Insert Interval
题意:在若干区间(起始增序)中插入一个区间,该合并合并
我的思路:在上题代码中加一句把待加入区间插入区间容器中
我的代码:
/** * Definition for an interval. * struct Interval { * int start; * int end; * Interval() : start(0), end(0) {} * Interval(int s, int e) : start(s), end(e) {} * }; */ class Solution { public: static bool cmp(const Interval& a, const Interval& b) { if (a.start == b.start) return a.end < b.end; return a.start < b.start; } vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) { vector<Interval> ans; intervals.push_back(newInterval); sort(intervals.begin(), intervals.end(), cmp); for (int i = 0; i < intervals.size(); i++) { int l = intervals[i].start, r = intervals[i].end; while (i+1 < intervals.size() && intervals[i+1].start <= r) { r = max(r, intervals[i+1].end); i++; } Interval tmp(l, r); ans.push_back(tmp); } return ans; } };
九章最优解:先把前后都搞定,这时能够确定待插区间的位置,更新区间首尾后插入
九章代码:
/** * 本代码由九章算法编辑提供。版权所有,转发请注明出处。 * - 九章算法致力于帮助更多中国人找到好的工作,教师团队均来自硅谷和国内的一线大公司在职工程师。 * - 现有的面试培训课程包括:九章算法班,系统设计班,算法强化班,Java入门与基础算法班,Android 项目实战班,Big Data 项目实战班, * - 更多详情请见官方网站:http://www.jiuzhang.com/?source=code */ /** * Definition for an interval. * struct Interval { * int start; * int end; * Interval() : start(0), end(0) {} * Interval(int s, int e) : start(s), end(e) {} * }; */ class Solution { public: vector<Interval> insert(vector<Interval>& intervals, Interval newInterval) { vector<Interval> ans; if(intervals.size() == 0) { ans.push_back(newInterval); return ans; } int ins_pos = 0; for (Interval now : intervals) { if(now.end < newInterval.start) { ins_pos++; ans.push_back(now); } else if(newInterval.end < now.start) { ans.push_back(now); } else { newInterval.start = min(newInterval.start, now.start); newInterval.end = max(newInterval.end, now.end); } } ans.insert(ans.begin() + ins_pos, newInterval); return ans; } };
58. Length of Last Word
题意:输出最后一个单词的长度
我的思路:水题,倒查
我的代码:
class Solution { public: int lengthOfLastWord(string s) { int i = s.size()-1, j; while (i >= 0 && s[i] == ' ') i--; for (j = i; j >= 0; j--) { if (s[j] == ' ') break; } return i-j; } };
60. Permutation Sequence
题意:输出长度为n的第k个排列
我的思路:康托展开,介绍见链接http://blog.csdn.net/modiziri/article/details/22389303?utm_source=tuicool&utm_medium=referral
我的代码:
class Solution { public: string getPermutation(int n, int k) { string ans; vector<int> tmp; for (int i = 1; i <= n; i++) tmp.push_back(i); k--; for (int cyc_num = n-1; cyc_num > 0; cyc_num--) { int jiecheng = 1; for (int i = 1; i <= cyc_num; i++) jiecheng *= i; int kk = k / jiecheng; ans.push_back('0'+tmp[kk]); tmp.erase(tmp.begin()+kk); k = k % jiecheng; } ans.push_back('0'+tmp[0]); return ans; } };
九章最优解:思路一样,写法不同
九章代码:
class Solution { public: string getPermutation(int n, int k) { string s(n, '0'); string result; for (int i = 0; i < n; ++i) s[i] += i + 1; return kth_permutation(s, k); } private: int factorial(int n) { int result = 1; for (int i = 1; i <= n; ++i) result *= i; return result; } // seq 已排好序,是第一个排列 template<typename Sequence> Sequence kth_permutation(const Sequence &seq, int k) { const int n = seq.size(); Sequence S(seq); Sequence result; int base = factorial(n - 1); --k; // 康托编码从0 开始 for (int i = n - 1; i > 0; k %= base, base /= i, --i) { auto a = next(S.begin(), k / base); result.push_back(*a); S.erase(a); } result.push_back(S[0]); // 最后一个 return result; } };
189. Rotate Array
题意:将数组右数k个移到前边
我的思路:先将前边n-k个加到后边,在将前边的删除
我的代码:
class Solution { public: void rotate(vector<int>& nums, int k) { int n = nums.size(); k %= n; for (int i = 0; i < n-k; i++) nums.push_back(nums[i]); if (k < n) nums.erase(nums.begin(), nums.begin()+n-k); } };
九章最优解:lintcode上给的是string,可以直接用取子串函数substr
class Solution { public: /** * @param str: a string * @param offset: an integer * @return: nothing */ void rotateString(string &str,int offset){ //wirte your code here if (str.size() == 0) return; offset = offset % str.size(); str = str.substr(str.size() - offset, offset) + str.substr(0, str.size() - offset); } };
网上一种解法:前半部分反转,后半部分反转,再整体反转。
class Solution { public: void rotate(int nums[], int n, int k) { k %= n; reverse(nums, nums+(n-k)); reverse(nums+(n-k), nums+n); reverse(nums, nums+n); } };
61. Rotate List
题意:给定一个链表,将右数k个移到前边
我的思路:将链表尾连到首,在将右数第k个节点作链表首即可
我的代码:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* rotateRight(ListNode* head, int k) { if (head == NULL) return NULL; ListNode* tmp = head; int n = 1; while (tmp->next) { tmp = tmp->next; n++; } tmp->next = head; tmp = head; k %= n; for (int i = 0; i < n-k-1; i++) tmp = tmp->next; head = tmp->next; tmp->next = NULL; return head; } };
九章最优解:思路一样
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: /** * @param head: the list * @param k: rotate to the right k places * @return: the list after rotation */ ListNode *rotateRight(ListNode *head, int k) { if (head == NULL) { return head; } int len = 0; for (ListNode *node = head; node != NULL; node = node->next) { len++; } k = k % len; if (k == 0) { return head; } ListNode *fast = head; for (int i = 0; i < k; i++) { fast = fast->next; } ListNode *slow = head; while (fast->next != NULL) { slow = slow->next; fast = fast->next; } fast->next = head; head = slow->next; slow->next = NULL; return head; } };
62. Unique Paths
题意:给定m*n个格子,求从左上角格子到右下角格子有几种走法
我的思路:组合问题,C(m-1, m+n-2)
我的代码:
class Solution { private: int C(int m, int n) { m = min(m, n-m); long long a1 = 1, a2 = 1; for (int i = 1; i <= m; i++) { a1 *= i; a2 *= n-m+i; } return (int)(a2/a1); } public: int uniquePaths(int m, int n) { return C(m-1, m+n-2); } };
九章最优解:利用公式C(m,n)=C(m-1,n-1)+C(m-1,n)递推
九章代码:
class Solution { public: /** * @param n, m: positive integer (1 <= n ,m <= 100) * @return an integer */ int uniquePaths(int m, int n) { // wirte your code here vector<vector<int> > f(m, vector<int>(n)); for(int i = 0; i < n; i++) f[0][i] = 1; for(int i = 0; i < m; i++) f[i][0] = 1; for(int i = 1; i < m; i++) for(int j = 1; j < n; j++) f[i][j] = f[i-1][j] + f[i][j-1]; return f[m-1][n-1]; } };
63. Unique Paths II
题意:基本要求62题,另外给定的m*n矩阵1表示不可走,求最后的走法数
我的思路:用组合数的递推解法,当[x,y]处值为1不可达时,f[x-1][x+y-2]值置为0即可,注意边缘附初始值时当出现一个1时,他右边全部或者下边全部就全是0了
我的代码:
class Solution { public: int uniquePathsWithObstacles(vector<vector<int>>& obstacleGrid) { int m = obstacleGrid.size(), n = obstacleGrid[0].size(); vector<vector<int>> f(m, vector<int>(n)); int flag = 1; for (int i = 0; i < n; i++) { if (obstacleGrid[0][i]) flag = 0; f[0][i] = flag; } flag = 1; for (int i = 0; i < m; i++) { if (obstacleGrid[i][0]) flag = 0; f[i][0] = flag; } for (int i = 1; i < m; i++) for (int j = 1; j < n; j++) f[i][j] = obstacleGrid[i][j] == 1 ? 0 : f[i-1][j] + f[i][j-1]; return f[m-1][n-1]; } };
九章最优解:思路一致
九章代码:
class Solution { public: /** * @param obstacleGrid: A list of lists of integers * @return: An integer */ int uniquePathsWithObstacles(vector<vector<int> > &obstacleGrid) { // write your code here int m = obstacleGrid.size(); if(m<=0){ return 0; } int n = obstacleGrid[0].size(); if(n<=0){ return 0; } if(obstacleGrid[0][0]==1){ return 0; } int map[101][101]; map[0][0]=1; for(int i=1;i<m;i++){ if(obstacleGrid[i][0]==1) map[i][0]=0; else map[i][0]=map[i-1][0]; } for(int i=1;i<n;i++){ if(obstacleGrid[0][i]==1) map[0][i]=0; else map[0][i]=map[0][i-1]; } for(int i=1;i<m;i++) for(int j=1;j<n;j++){ if(obstacleGrid[i][j]==1){ map[i][j]=0; } else map[i][j]=map[i-1][j]+map[i][j-1]; } return map[m-1][n-1]; } };
64. Minimum Path Sum
题意:给定m*n矩阵,求从左上角走到右下角的最小路径和(只能往下或者往右走)
我的思路:参照62、63题,因为(m,n)处只能由上方或者左边过来,所以到达(m,n)处的最小路径和就是grid[m][n]+min(grid[m-1][n],grid[m][n-1])
我的代码:
class Solution { public: int minPathSum(vector<vector<int>>& grid) { int m = grid.size(), n = grid[0].size(); for (int i = 1; i < m; i++) grid[i][0] += grid[i-1][0]; for (int i = 1; i < n; i++) grid[0][i] += grid[0][i-1]; for (int i = 1; i < m; i++) for (int j = 1; j < n; j++) grid[i][j] += min(grid[i-1][j], grid[i][j-1]); return grid[m-1][n-1]; } };
九章最优解:思路一样
九章代码:数组f其实感觉多余
class Solution { public: /** * @param grid: a list of lists of integers. * @return: An integer, minimizes the sum of all numbers along its path */ int minPathSum(vector<vector<int> > &grid) { // write your code here int f[1000][1000]; if (grid.size() == 0 || grid[0].size() == 0) return 0; f[0][0] = grid[0][0]; for(int i = 1; i < grid.size(); i++) f[i][0] = f[i-1][0] + grid[i][0]; for(int i = 1; i < grid[0].size(); i++) f[0][i] = f[0][i-1] + grid[0][i]; for(int i = 1; i < grid.size(); i++) for(int j = 1; j < grid[0].size(); j++) f[i][j] = min(f[i-1][j], f[i][j-1]) + grid[i][j]; return f[grid.size()-1][grid[0].size()-1]; } };
65. Valid Number
垃圾题
class Solution { public: bool isNumber(string s) { int flage = 0, flagdot = 0, flagnum = 0; int n = s.size()-1, m = 0; while (s[n] == ' ') n--; while (s[m] == ' ') m++; if (n < m) return 0; if (m == n) return s[m] >= '0' && s[m] <= '9'; for (int i = m; i <=n ; i++) { if (s[i] >= '0' && s[i] <= '9' || i == m && s[i] == '-' || i == m && s[i] == '+') { if (s[i] >= '0' && s[i] <= '9') flagnum = 1; continue; } else if (i > m && s[i] == 'e' && flage == 0 && i < n && flagnum) { if (i+1 < n && s[i+1] == '+' || i+1 < n && s[i+1] == '-') i++; if (i+1 <= n && s[i+1] == '.') return 0; flage = 1; } else if (s[i] == '.' && flagdot == 0 && flage == 0) { if (i+1 <= n && s[i+1] == 'e' && flagnum == 0) return 0; flagdot = 1; } else return 0; } return flagnum; } };
66. Plus One
题意:一个数组组成一个非负数,低位大下标,将这个数加一
我的思路:水题,处理进位就行
我的代码:
class Solution { public: vector<int> plusOne(vector<int>& digits) { int cnt = 1; for (int i = digits.size()-1; i >= 0; i--) { digits[i] += cnt; cnt = digits[i]/10; digits[i] %= 10; if (!cnt) break; } if (cnt) digits.insert(digits.begin(), cnt); return digits; } };
九章最优解:一样的思路
class Solution { public: vector<int> plusOne(vector<int> &digits) { add(digits, 1); return digits; } private: // 0 <= digit <= 9 void add(vector<int> &digits, int digit) { int c = digit; // carry, 进位 for (auto it = digits.rbegin(); it != digits.rend(); ++it) { *it += c; c = *it / 10; *it %= 10; } if (c > 0) digits.insert(digits.begin(), 1); } };
67. Add Binary
题意:实现两个字符串表示的二进制加法
我的思路:按位走,相加是异或,进位是jin = a[i]&b[i] | b[i]&jin | a[i]&jin,竟然是画卡诺图得出来的。。第一次感觉数电没白学
我的代码:
class Solution { private: void reverse(string &ans){ int l = ans.size(); for (int i = 0; i < l/2; i++) { ans[i] ^= ans[l-1-i]; ans[l-1-i] ^= ans[i]; ans[i] ^= ans[l-1-i]; } } public: string addBinary(string a, string b) { char jin = 0; string ans; int l = max(a.size(), b.size()); reverse(a); reverse(b); for (int i = 0; i < l; i++) { char tmp = jin, A = 0, B = 0; if (i < a.size()) tmp ^= a[i]-'0', A = a[i]-'0'; if (i < b.size()) tmp ^= b[i]-'0', B = b[i]-'0'; jin = A&B | B&jin | A&jin; ans.push_back(tmp+'0'); } if (jin) ans.push_back(jin+'0'); reverse(ans); return ans; } };
九章最优解:加法用的是(a[i]+b[i]+jinwei)%2,进位用的是(a[i]+b[i]+jinwei)/2,对string的操作明显比我强很多,看看代码
public class Solution { public String addBinary(String a, String b) { if(a.length() < b.length()){ String tmp = a; a = b; b = tmp; } int pa = a.length()-1; int pb = b.length()-1; int carries = 0; String rst = ""; while(pb >= 0){ int sum = (int)(a.charAt(pa) - '0') + (int)(b.charAt(pb) - '0') + carries; rst = String.valueOf(sum % 2) + rst; carries = sum / 2; pa --; pb --; } while(pa >= 0){ int sum = (int)(a.charAt(pa) - '0') + carries; rst = String.valueOf(sum % 2) + rst; carries = sum / 2; pa --; } if (carries == 1) rst = "1" + rst; return rst; } }
68. Text Justification
学不到什么东西。。
class Solution { public: vector<string> fullJustify(vector<string>& words, int maxWidth) { vector<string> ans; int i = 0, n = (int)words.size(); if (n == 0) return ans; while (i < n) { int sum = 0, j = i; string tmp; while (sum-1 <= maxWidth && j < n) { sum += words[j].size()+1; j++; } if (sum-1 > maxWidth) { j--; sum--; sum -= words[j].size()+1; int kong = maxWidth-sum; for (int k = i; k < j-1; k++) { words[k] += ' '; if (j-i-1 > 0) { for (int hehe = 0; hehe < kong/(j-i-1); hehe++) words[k] += ' '; } if (j-i-1 > 0 && k-i < kong%(j-i-1)) words[k] += ' '; } if (j-i == 1) { for (int hehe = 0; hehe < kong; hehe++) words[i] += ' '; } for (int k = i; k < j; k++) tmp += words[k]; ans.push_back(tmp); } else { for (int k = i; k < j; k++) { tmp += words[k]; if (k < j-1) tmp += ' '; } int gg = maxWidth-sum+1; while (gg--) tmp += ' '; ans.push_back(tmp); } i = j; } return ans; } };
69. Sqrt(x)
题意:输出正数x的平方根
我的思路:sqrt明明就可以非要用二分。。
我的代码:sqrt
class Solution { public: int mySqrt(int x) { return (int)sqrt(double(x)); } };
二分:
class Solution { public: int mySqrt(int x) { long long l = 0, r = x/2+1; while (l+1 < r) { long long mid = (l+r)/2; if (mid*mid > x) { r = mid; } else { l = mid; } } if (r*r <= x) return r; return l; } };
九章最优解:
class Solution { public: /** * @param x: An integer * @return: The sqrt of x */ int sqrt(int x) { // write your code here long left = 0; if (x == 1) return 1; long right = x; long mid = left + (right-left)/2; while (left+1 < right) { if (x > mid*mid) { left = mid; } else if (x < mid*mid) { right = mid; } else { return mid; } mid = left + (right-left)/2; } return left; } };
70. Climbing Stairs
题意:爬楼梯,每次可以爬一个或者两个阶梯,求到n阶有多少种方法
我的思路:斐波那契
我的代码:
class Solution { public: int climbStairs(int n) { if (n <= 2) return n; int ans = 2, tmp = 1; while (n > 2) { ans += tmp; tmp = ans-tmp; n--; } return ans; } };
九章最优解:
class Solution { public: int climbStairs(int n) { // write your code here if(n <= 2) return n; int* step = new int[n]; step[0] = 1; step[1] = 2; for(int i = 2; i < n; i++) { step[i] = step[i-1] + step[i-2]; } return step[n-1]; } };
71. Simplify Path
题意:将文件路径化简
我的思路:思路很简单,判断而已,就是代码写的太tm丑了,satck和queue都不好写用vector啊笨蛋!!
class Solution { public: string simplifyPath(string path) { stack<string> que, que2; string ans, tmp; path += '/'; for (int i = 0; i < path.size(); i++) { if (path[i] == '/') { if (!tmp.empty()) { if (tmp == ".") { } else if (tmp == "..") { if (!que.empty()) que.pop(); } else { que.push(tmp); } tmp = ""; } } else { tmp += path[i]; } } while (!que.empty()) { que2.push(que.top()); que.pop(); } while (!que2.empty()) { ans += '/' + que2.top(); que2.pop(); } if (ans.empty()) ans += '/'; return ans; } };
九章最优解:
class Solution { public: string simplifyPath(string const& path) { vector<string> dirs; // 当做栈 for (auto i = path.begin(); i != path.end();) { ++i; auto j = find(i, path.end(), '/'); auto dir = string(i, j); if (!dir.empty() && dir != ".") {// 当有连续 '///'时,dir 为空 if (dir == "..") { if (!dirs.empty()) dirs.pop_back(); } else dirs.push_back(dir); } i = j; } stringstream out; if (dirs.empty()) { out << "/"; } else { for (auto dir : dirs) out << '/' << dir; } return out.str(); } };
72. Edit Distance
题意:求经过插入、删除或者替换操作将串1变成串2的最小步数
我的思路:经典dp,dp[i][j]记录1串的前i个(最后一个下标是i-1)变成2串的前j个需要的步数,显然初始化dp[0][i]和dp[i][0]都是i,因为若1串是空串,只需一直添加,若2串是空串,只需一直删除。之后分为两种情况,若word1[i-1]==word2[j-1],dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]),dp[i-1][j]+1表示删除,可以这样理解,把word1前i个变成word2前j个等于前i-1个变成word2前j个再删除word1的第i个元素,同理,dp[i][j-1]表示添加,dp[i-1][j-1]表示不需替换;若word1[i-1]!=word2[j-1],dp[i][j] = min(dp[i-1][j]+1, dp[i][j-1]+1, dp[i-1][j-1]+1),分别表示删除、添加和替换。
我的代码:
class Solution { public: int minDistance(string word1, string word2) { int m = word1.size(), n = word2.size(); int **dp = new int *[m+1]; for (int i = 0; i <= m; i++) dp[i] = new int[n+1]; for (int i = 0; i <= m; i++) dp[i][0] = i; for (int i = 0; i <= n; i++) dp[0][i] = i; for (int i = 1; i <= m; i++) { for (int j = 1; j <= n; j++) { int tmp = min(dp[i-1][j]+1, dp[i][j-1]+1); if (word1[i-1] == word2[j-1]) dp[i][j] = min(tmp, dp[i-1][j-1]); if (word1[i-1] != word2[j-1]) dp[i][j] = min(tmp, dp[i-1][j-1]+1); } } return dp[m][n]; } };
九章最优解:一样的思路,记一下二维vector的开法vector<vector<int> > f(row, vector<int>(col));
class Solution { public: /** * @param word1 & word2: Two string. * @return: The minimum number of steps. */ int minDistance(string word1, string word2) { // write your code here int row = word1.length() + 1; int col = word2.length() + 1; vector<vector<int> > f(row, vector<int>(col)); for (int i = 0; i < row; i++) f[i][0] = i; for (int i = 0; i < col; i++) f[0][i] = i; for (int i = 1; i < row; i++) for (int j = 1; j < col; j++){ if (word1[i-1] == word2[j-1]) f[i][j] = f[i-1][j-1]; else f[i][j] = f[i-1][j-1] + 1; f[i][j] = min(f[i][j], min(f[i-1][j]+1, f[i][j-1]+1)); } return f[row-1][col-1]; } };
73. Set Matrix Zeroes
题意:将矩阵中0元素所在的行和列都置0
我的思路:将有0的行和列标记,最后统一置0
我的代码:
class Solution { public: void setZeroes(vector<vector<int>>& matrix) { int m = matrix.size(), n = matrix[0].size(); bool *raw = new bool[m]; bool *col = new bool[n]; for (int i = 0; i < m; i++) raw[i] = 0; for (int i = 0; i < n; i++) col[i] = 0; for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) if (matrix[i][j] == 0) raw[i] = col[j] = 1; for (int i = 0; i < m; i++) { if (raw[i]) { for (int j = 0; j < n; j++) matrix[i][j] = 0; } } for (int i = 0; i < n; i++) { if (col[i]) { for (int j = 0; j < m; j++) matrix[j][i] = 0; } } } };
九章最优解:把每行和每列的第一个元素作为标记元素,记录此行或列是否置0
九章代码:
class Solution { public: void setZeroes(vector<vector<int> > &matrix) { // write your code here if (matrix.size()==0) return ; int m = matrix.size(), n = matrix[0].size(); bool row0 = false, col0 = false; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { if ((i == 0 || j == 0) && matrix[i][j] == 0) { row0 |= i == 0; col0 |= j == 0; } else { matrix[i][0] = matrix[i][j] == 0 ? 0 : matrix[i][0]; matrix[0][j] = matrix[i][j] == 0 ? 0 : matrix[0][j]; } } } for (int i = 1; i < m; i++) { for (int j = 1; j < n; j++) { matrix[i][j] = matrix[i][0] == 0 || matrix[0][j] == 0 ? 0 : matrix[i][j]; } } for (int i = 0; i < m && col0; i++) { matrix[i][0] = 0; } for (int j = 0; j < n && row0; j++) { matrix[0][j] = 0; } } };
74. Search a 2D Matrix
题意:在有序矩阵(每行由小到大,每列由小到大)中查找目标值
我的思路:先根据行首尾元素看有没有可能在这行,再二分查找行内元素
我的代码:
class Solution { public: bool searchMatrix(vector<vector<int>>& matrix, int target) { int m = matrix.size(); if (m == 0) return 0; int n = matrix[0].size(); if (n == 0) return 0; for (int i = 0; i < m; i++) { if (matrix[i][n-1] < target) continue; if (matrix[i][0] > target) break; int l = 0, r = n-1; while (l+1 < r) { int mid = (l+r)/2; if (matrix[i][mid] < target) { l = mid; } else { r = mid; } } if (matrix[i][l] == target || matrix[i][r] == target) return 1; } return 0; } };
九章最优解:没有
我的思路:二分水题
我的代码:
class Solution { public: bool searchMatrix(vector<vector<int>>& matrix, int target) { if (matrix.size() == 0) return false; int m = matrix.size(), n = matrix[0].size(); if (n == 0) return false; int l = 0, r = m*n-1; while (l+1 < r) { int mid = (l+r)/2; if (matrix[mid/n][mid%n] > target) { r = mid; } else { l = mid; } } if (matrix[l/n][l%n] == target || matrix[r/n][r%n] == target) return true; return false; } };
九章最优解:基本一样
240. Search a 2D Matrix II
题意:在有序矩阵中(每行由小到大,上一行最后一个比下一行第一个小)查找目标值
75. Sort Colors
题意:数组中0,1,2代表三种颜色,将相同颜色按0,1,2的顺序排在一起
我的思路:统计一下每种颜色多少个,再统一写
我的代码:
class Solution { public: void sortColors(vector<int>& nums) { int cnt[3] = {0}, n = nums.size(); for (int i = 0; i < n; i++) cnt[nums[i]]++; int k = 0; for (int i = 0; i < 3; i++) for (int j = 0; j < cnt[i]; j++) nums[k++] = i; } };
九章最优解:三个指针,中间一个从前往后扫,遇0往前换,遇2往后换,遇1跳过,知道与后边指针相遇即排完
九章代码:
class Solution{ public: /** * @param nums: A list of integer which is 0, 1 or 2 * @return: nothing */ void sortColors(vector<int> &nums) { int left = 0, right = nums.size() - 1; int middle = 0; // should be <= not < while (middle <= right) { if (nums[middle] == 0) { swap(nums[middle], nums[left]); left++; middle++; } else if (nums[middle] == 1) { middle++; } else { swap(nums[middle], nums[right]); right--; } } } };
76. Minimum Window Substring
题意:找出s串的最短连续子串包含t串中的所有字符
我的思路:hash记录t串中个字符个数,首尾两指针i、j,往后扫j的位置,即包含了t串中所有字符,在把i往后缩,j-i小的话更新结果
我的代码:
class Solution { public: string minWindow(string s, string t) { int m = s.size(), n = t.size(), i = 0, j = 0, l = 0, r = 0x7fffffff; vector<int> map(128, -m); for (int i = 0; i < n; i++) { if (map[t[i]] == -m) map[t[i]] = 1; else map[t[i]]++; } while (i < m) { while (j < m && n > 0) { if (map[s[j]] > -m) { if (map[s[j]] > 0) n--; map[s[j]]--; } j++; } if (n == 0) { while (map[s[i]] < 0) map[s[i++]]++; if (j-i < r-l) l = i, r = j; } map[s[i++]]++; n++; } return r >= 0x7fffffff ? "" : s.substr(l, r-l); } };
77. Combinations
题意:输出1-n的所有个数为k的组合,不重复
我的思路:dfs水题
我的代码:
class Solution { public: void dfs(int n, int k, vector<vector<int>>& ans, vector<int> tmp, int j) { if (tmp.size() == k) { ans.push_back(tmp); return; } for (int i = j; i <= n; i++) { tmp.push_back(i); dfs(n, k, ans, tmp, i+1); tmp.pop_back(); } } vector<vector<int>> combine(int n, int k) { vector<vector<int>> ans; vector<int> tmp; dfs(n, k, ans, tmp, 1); return ans; } };
九章最优解:差不多,他用循环代替了dfs
九章代码:
class Solution { public: /** * @param n: Given the range of numbers * @param k: Given the numbers of combinations * @return: All the combinations of k numbers out of 1..n */ vector<vector<int> > combine(int n, int k) { // write your code here vector<vector<int> > ans;vector<int> stack; for (int i=1; i<=k; ++i) stack.push_back(i); ans.push_back(stack); while (1){ while (stack.size()>0 && stack.back()==n+stack.size()-k) stack.pop_back(); if (stack.size()==0) break; ++stack[stack.size()-1]; while (stack.size()<k) stack.push_back(stack[stack.size()-1]+1); ans.push_back(stack); } return ans; } };
79. Word Search
题意:从二维字符数组中找词,起点任意,词的下一个字符只能与上一个相邻(上下左右)
我的思路:dfs1A
我的代码:
class Solution { public: const int dir[4][2] = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; bool dfs(int i, int j, int m, int n, vector<vector<char>>& board, string word, int k, vector<vector<bool>>& flag) { if (k == word.size()) return 1; for (int r = 0; r < 4; r++) { int x = i+dir[r][0], y = j+dir[r][1]; if (x >=0 && x < m && y >= 0 && y < n && flag[x][y] == 0 && board[x][y] == word[k]) { flag[x][y] = 1; if (dfs(x, y, m, n, board, word, k+1, flag)) return 1; flag[x][y] = 0; } } return 0; } bool exist(vector<vector<char>>& board, string word) { int m = board.size(), n = board[0].size(); vector<vector<bool>> flag(m, vector<bool>(n)); for (int i = 0; i < m; i++) for (int j = 0; j < n; j++) if (board[i][j] == word[0]) { flag[i][j] = 1; if (dfs(i, j, m, n, board, word, 1, flag)) return 1; flag[i][j] = 0; } return 0; } };
九章最优解:思路一样,写法稍有区别
九章代码:
class Solution { public: /** * @param board: A list of lists of character * @param word: A string * @return: A boolean */ bool exist(vector<vector<char> > &board, string word) { // write your code here vector<vector<bool> > mask(board.size(), vector<bool>(board[0].size(), true)); if (board.size() < 1) return false; for (int i = 0; i <board.size(); ++i) { for (int j = 0; j < board[0].size(); ++j) { if (board[i][j] == word[0] && search(board, word, mask, 0, i, j)) { return true; } } } return false; } bool search(vector<vector<char> > &board, string &word, vector<vector<bool> > &mask, int idx, int x, int y) { if (word[idx] == board[x][y]) { ++idx; if (idx == word.length()){ return true; } } else { return false; } mask[x][y] = false; bool flag1, flag2, flag3, flag4; flag1 = flag2 = flag3 = flag4 = false; if (y + 1 < board[0].size() && mask[x][y+1] && board[x][y+1] == word[idx]) { if (search(board, word, mask, idx, x, y + 1)) return true; } if (x + 1 < board.size() && mask[x+1][y] && board[x+1][y] == word[idx]) { if (search(board, word, mask, idx, x + 1, y)) return true; } if (x - 1 >= 0 && mask[x-1][y] && board[x-1][y] == word[idx]) { if (search(board, word, mask, idx, x - 1, y)) return true; } if (y - 1 >= 0 && mask[x][y-1] && board[x][y-1] == word[idx]) { if (search(board, word, mask, idx, x, y - 1)) return true; } mask[x][y] = true; return false; } };
80. Remove Duplicates from Sorted Array II
题意:从有序数组中删除重复元素,允许最多有两个一样的,并返回操作后的数组长度
我的思路:大水题,标记下是否出现多于两次即可
我的代码:
class Solution { public: int removeDuplicates(vector<int>& nums) { int n = nums.size(), i = 0, j = 1; if (n <= 2) return n; bool flag = 0; while (j < n) { if (nums[j] == nums[i] && flag) { j++; } else if (nums[j] == nums[i] && !flag) { nums[++i] = nums[j++]; flag = 1; } else { nums[++i] = nums[j++]; flag = 0; } } return ++i; } };
九章最优解:思路差不多
class Solution { public: /** * @param A: a list of integers * @return : return an integer */ int removeDuplicates(vector<int> &nums) { // write your code here vector <int> B; if(nums.size() == 0) return 0; int before = nums[0] - 1; int countb = 0; for(int i = 0; i < nums.size(); i++) { if(before != nums[i]) { B.push_back(nums[i]); countb = 1; before = nums[i]; } else if(countb < 2 ) { B.push_back(nums[i]); countb++ ; before = nums[i]; } } int len = 0; for(int i = 0; i < B.size(); i++) nums[len++] = B[i]; return len; } };
81. Search in Rotated Sorted Array II
题意:在旋转后的有序数组里查找特定值
我的思路:从头往后找
我的代码:
class Solution { public: bool search(vector<int>& nums, int target) { for (int i = 0; i < nums.size(); i++) if (nums[i] == target) return 1; return 0; } };
九章最优解:思路感觉一样但是不知道为什么他多好多并不能减少时间复杂度的代码
class Solution { /** * param A : an integer ratated sorted array and duplicates are allowed * param target : an integer to be search * return : a boolean */ public: bool search(vector<int> &A, int target) { // write your code here int ans = -1; int len = A.size(); int cnt = 0; for ( int i = 0; i < len; ++i) { if (A[i] == target) { ans = i; } if (i != 0) if (A[i] < A[i-1]) cnt ++; } if (cnt > 1) ans = -ans; return (ans>=0); } };
83. Remove Duplicates from Sorted List
题意:删除链表中的重复元素
我的思路:链表大水题
我的代码:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* deleteDuplicates(ListNode* head) { if (head == NULL) return NULL; ListNode* ans = head; while (head->next) { if (head->next->val == head->val) { head->next = head->next->next; } else { head = head->next; } } return ans; } };
九章最优解:基本一致
82. Remove Duplicates from Sorted List II
题意:删除链表中的重复元素,连带它自己
我的思路:设一个标志记录此元素是否重复,其余就是链表操作了
我的代码:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* deleteDuplicates(ListNode* head) { if (head == NULL) return NULL; ListNode* ans = new ListNode(0); ListNode* tmp = ans; tmp->next = head; bool flag = 0; while (head->next != NULL) { if (head->next->val == tmp->next->val) { flag = 1; } if (head->next->val != tmp->next->val && flag) { tmp->next = head->next; flag = 0; } if (head->next->val != tmp->next->val && !flag) { tmp->next->next = head->next; tmp = tmp->next; } head = head->next; } if (flag) tmp->next = head->next; if (!flag) tmp->next->next = head->next; return ans->next; } };
九章最优解:有重复元素时记录这个值,把相应节点全跳过去;程序用了指针的指针,很漂亮
九章代码:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode *deleteDuplicates(ListNode *head) { ListNode *root = NULL; ListNode **ppNext = &root; while(head) { if(head->next == NULL || head->next->val != head->val) { *ppNext = head; ppNext = &(head->next); head = head->next; } else { int val = head->val; do { head = head->next; } while(head != NULL && head->val == val); } } *ppNext = NULL; return root; } };
84. Largest Rectangle in Histogram
题意:求柱状图中最大矩形
我的思路: 栈,http://blog.csdn.net/yutianzuijin/article/details/52072427
我的代码:
class Solution { public: int largestRectangleArea(vector<int>& heights) { heights.push_back(-1); int i = 0, n = heights.size(), ans = 0; stack<int> loc; while (i < n) { if (loc.empty() || heights[loc.top()] <= heights[i]) { loc.push(i++); } else { int tmp = loc.top(); loc.pop(); int l = loc.empty() ? 0 : loc.top()+1; ans = max(ans, heights[tmp]*(i-l)); } } return ans; } };
86. Partition List
题意:将链表中小于某值的节点置于新链表前端,其他按原顺序放在新链表后边
我的思路:遍历一次,将小于该值的节点形成左链表,大于等于的形成右链表,最后右连在左链表后边即可,操作不出错即大水题
我的代码:
/** * Definition for singly-linked list. * struct ListNode { * int val; * ListNode *next; * ListNode(int x) : val(x), next(NULL) {} * }; */ class Solution { public: ListNode* partition(ListNode* head, int x) { ListNode* tmp1 = new ListNode(0), *tmp2 = new ListNode(0); ListNode* ans = tmp1, *tmp = tmp2; while (head) { if (head->val < x) { tmp1->next = head; tmp1 = tmp1->next; } else { tmp2->next = head; tmp2 = tmp2->next; } head = head->next; } tmp2->next = NULL; tmp1->next = tmp->next; return ans->next; } };
九章最优解:基本都一样
/** * Definition of ListNode * class ListNode { * public: * int val; * ListNode *next; * ListNode(int val) { * this->val = val; * this->next = NULL; * } * } */ class Solution { public: /** * @param head: The first node of linked list. * @param x: an integer * @return: a ListNode */ ListNode *partition(ListNode *head, int x) { ListNode *leftDummy = new ListNode(0); ListNode *rightDummy = new ListNode(0); ListNode *leftTail = leftDummy; ListNode *rightTail = rightDummy; while (head != NULL) { if (head->val < x) { leftTail->next = head; leftTail = head; } else { rightTail->next = head; rightTail = head; } head = head->next; } leftTail->next = rightDummy->next; rightTail->next = NULL; return leftDummy->next; } };
88. Merge Sorted Array
题意:将有序数组2并到有序数组1中,1只看前m个,1的长度不小于m+n
我的思路:两个数组各一个指针,比较大小,插入,注意细节就水题
我的代码:
class Solution { public: void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) { int i, j; for (i = 0, j = 0; i < m && j < n; i++) { if (nums1[i] >= nums2[j]) { nums1.insert(nums1.begin()+i, nums2[j]); nums1.pop_back(); j++; m++; } } while (j < n) nums1[i++] = nums2[j++]; } };
九章最优解:倒着放,两个数从后往前两个指针谁大放谁
九章代码:
class Solution { public: void merge(vector<int>& nums1, int m, vector<int>& nums2, int n) { int pos = m + n - 1 , i = m - 1 , j = n - 1; while (i >= 0 && j >= 0) nums1[pos--] = nums1[i] > nums2[j] ? nums1[i--] : nums2[j--]; while (j >= 0) nums1[pos--] = nums2[j--]; } };
89. Gray Code
题意:给定n,生成n bit的格雷码序列
我的思路:二进制转格雷码规则:从右起每一位与其左边一位异或得的值为该位置格雷码的值
我的代码:
class Solution { public: vector<int> grayCode(int n) { vector<int> ans; for (int i = 0; i < pow(2, n); i++) ans.push_back(i^(i>>1)); return ans; } };
九章最优解:思路一样
class Solution { public: /** * @param n a number * @return Gray code */ vector<int> grayCode(int n) { // Write your code here vector<int> result; const size_t size = 1 << n; // 2^n result.reserve(size); for (size_t i = 0; i < size; ++i) result.push_back(binary_to_gray(i)); return result; } private: static unsigned int binary_to_gray(unsigned int n) { return n ^ (n >> 1); } };
90. Subsets II
题意:输出给定序列的所有子集
我的思路:回溯所有集合情况,用set判是否重复,注意预处理将原序列排序以防止重复
我的代码:
class Solution { public: void dfs(int num, vector<int>& nums, vector<vector<int>>& ans, vector<int> tmp, set<vector<int>>& s, bool *flag) { if (num == nums.size()) return; for (int i = num; i < nums.size(); i++) { if (!flag[i]) { tmp.push_back(nums[i]); flag[i] = 1; if (s.find(tmp) == s.end()) { s.insert(tmp); ans.push_back(tmp); dfs(i+1, nums, ans, tmp, s, flag); } tmp.pop_back(); flag[i] = 0; } } } vector<vector<int>> subsetsWithDup(vector<int>& nums) { vector<vector<int>> ans; vector<int> tmp; bool *flag = new bool[nums.size()]; for (int i = 0; i < nums.size(); i++) flag[i] = 0; sort(nums.begin(), nums.end()); set<vector<int>> s; ans.push_back(tmp); dfs(0, nums, ans, tmp, s, flag); return ans; } };
九章最优解:也是dfs,但是他只记录dfs深度,分别dfs加/不加入此元素时的集合来求结果
九章代码:
class Solution { public: vector<vector<int> > result; bool equls( vector<int> a, vector<int> b){ if (a.size() != b.size()) return false; int cnt = a.size(); for (int i = 0; i < cnt;++i) if (a[i]!=b[i]) return false; return true; } void dfs(vector<int> tmp, int x , vector<int> nums) { if (x == nums.size()) { int cnt = result.size(); for ( int i = 0; i < cnt ; ++i) if ( equls(result[i], tmp) ) return ; result.push_back(tmp); return ; } dfs(tmp, x + 1, nums); tmp.push_back(nums[x]); dfs(tmp, x + 1, nums); } vector<vector<int> > subsetsWithDup(vector<int> &nums){ sort(nums.begin(), nums.end()); vector<int> tmp; dfs(tmp, 0 , nums) ; // write your code here return result; } };
78. Subsets
题意:上题的简化版,输出一个全异序列的所有子集
我的思路:dfs水题
我的代码:
class Solution { public: void dfs(int num, vector<int>& nums, vector<vector<int>>& ans, vector<int> tmp) { for (int i = num; i < nums.size(); i++) { tmp.push_back(nums[i]); ans.push_back(tmp); dfs(i+1, nums, ans, tmp); tmp.pop_back(); } } vector<vector<int>> subsets(vector<int>& nums) { vector<vector<int>> ans; vector<int> tmp; ans.push_back(tmp); dfs(0, nums, ans, tmp); return ans; } };
九章最优解:基本一样
class Solution { private: void helper(vector<vector<int> > &results, vector<int> &subset, vector<int> &nums, int start) { results.push_back(subset); for (int i = start; i < nums.size(); i++) { subset.push_back(nums[i]); helper(results, subset, nums, i + 1); subset.pop_back(); } } public: vector<vector<int> > subsets(vector<int> &nums) { vector<vector<int> > results; vector<int> subset; helper(results, subset, nums, 0); return results; } };
93. Restore IP Addresses
题意:给定以串数字,中间加点输出有效的ip地址
我的思路:dfs,没什么难度
我的代码:
class Solution { public: vector<string> ans; void dfs(string s, string tmp, int l) { if (l > 1) tmp += '.'; if (l == 4 && s.size() > 0 && s.size() < 4 && stoi(s) < 256) { if (s.size() > 1 && s[0] == '0') return; tmp += s; ans.push_back(tmp); } else if (l < 4) { int k = min((int)s.size(), 3); for (int i = 1; i <= k; i++) { if (i > 1 && s[0] == '0') continue; if (i < 3 || stoi(s.substr(0, i)) < 256) { dfs(s.substr(i, s.size()-i), tmp+s.substr(0, i), l+1); } } } } vector<string> restoreIpAddresses(string s) { string tmp; dfs(s, tmp, 1); return ans; } };
100. Same Tree
题意:判断两二叉树是否一样
我的思路:dfs判断此节点、左节点、右节点是否都一样
我的代码:
/** * Definition for a binary tree node. * struct TreeNode { * int val; * TreeNode *left; * TreeNode *right; * TreeNode(int x) : val(x), left(NULL), right(NULL) {} * }; */ class Solution { public: bool same(TreeNode* p, TreeNode* q) { if (p == NULL && q == NULL) return 1; if ((p != NULL && q != NULL && p->val == q->val)) { if ((p->left == NULL && q->left != NULL) || (p->left != NULL && q->left == NULL) ||(p->right == NULL && q->right != NULL) ||(p->right != NULL && q->right == NULL)) return 0; if (p->left == NULL && q->left == NULL && p->right == NULL && q->right == NULL) return 1; if (same(p->left, q->left) && same(p->right, q->right)) return 1; } return 0; } bool isSameTree(TreeNode* p, TreeNode* q) { if (same(p, q)) return 1; return 0; } };
九章最优解:没有

浙公网安备 33010602011771号