题目一:两数之和 两数之和
标签 数组
、哈希表
题解 1 2 3 4 5 6 7 8 9 10 11 12 class Solution { public int [] twoSum(int [] nums, int target) { int [] res = new int [2 ]; for (int i = 0 ; i < nums.length; i ++) { for (int j = i + 1 ; j < nums.length; j ++) { if (nums[i] + nums[j] == target) return new int []{i, j}; } } return res; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution {public : vector<int > twoSum (vector<int >& nums, int target) { vector<int > arr; for (int i=0 ;i < nums.size () - 1 ; i++){ for (int j = i + 1 ;j< nums.size (); j++){ if (nums[i]+nums[j] == target){ arr.push_back (i); arr.push_back (j); break ; } } } return arr; } };
题目二:两数相加 两数相加
标签 递归
、链表
、数学
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 class Solution { public ListNode addTwoNumbers (ListNode l1, ListNode l2) { ListNode l3 = new ListNode (-1 , null ); ListNode a = l3; ListNode q = l1; ListNode p = l2; int t = 0 ; while (q != null && p != null ) { int x = q.val + p.val + t; t = x / 10 ; a.next = new ListNode (x % 10 , null ); a = a.next; q = q.next; p = p.next; } while (q != null ) { int x = q.val + t; t = x / 10 ; a.next = new ListNode (x % 10 , null ); a = a.next; q = q.next; } while (p != null ) { int x = p.val + t; t = x / 10 ; a.next = new ListNode (x % 10 , null ); a = a.next; p = p.next; } if (t != 0 ) a.next = new ListNode (t, null ); return l3.next; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution {public : ListNode* addTwoNumbers (ListNode* l1, ListNode* l2) { auto dummy = new ListNode (-1 ); auto cur = dummy; int t = 0 ; while (l1 || l2 || t){ if (l1) t += l1 -> val, l1 = l1 -> next; if (l2) t += l2 -> val, l2 = l2 -> next; cur -> next = new ListNode (t % 10 ); cur = cur -> next; t /= 10 ; } return dummy -> next; } };
题目三:无重复字符的最长子串 无重复字符的最长子串
标签 哈希表
、字符串
、滑动窗口
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public int lengthOfLongestSubstring (String s) { if (s.equals("" )) return 0 ; Set<Character> hashSet = new HashSet <>(); int l = 0 , r = 0 ; int ans = 0 ; hashSet.add(s.charAt(0 )); for (int i = 1 ; i < s.length(); i ++) { if (!hashSet.contains(s.charAt(i))) { hashSet.add(s.charAt(i)); r ++; } else { ans = Math.max(ans, hashSet.size()); while (!hashSet.isEmpty() && hashSet.contains(s.charAt(i))) { hashSet.remove(s.charAt(l ++)); } hashSet.add(s.charAt(i)); r ++; } } ans = Math.max(ans, hashSet.size()); return ans; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution {public : int lengthOfLongestSubstring (string s) { unordered_map<char ,int > head; int res = 0 ; for (int i = 0 , j = 0 ; i < s.length (); i ++){ head[s[i]]++; while (head[s[i]] > 1 ) head[s[j++]]--; res = max (res, i - j + 1 ); } return res; } };
题目四:寻找两个正序数组的中位数 寻找两个正序数组的中位数
标签 数组
、二分查找
、分治
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution { public double findMedianSortedArrays (int [] nums1, int [] nums2) { int n = nums1.length; int m = nums2.length; int [] nums = new int [n + m]; System.arraycopy(nums1, 0 , nums, 0 , n); System.arraycopy(nums2, 0 , nums, n, m); Arrays.sort(nums); if ((n + m) % 2 != 0 ) { return nums[(n + m) / 2 ]; } else { return ((double ) nums[(n + m) / 2 ] + (double ) nums[(n + m) / 2 - 1 ]) / 2 ; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution {public : double findMedianSortedArrays (vector<int >& nums1, vector<int >& nums2) { vector<double > arr; int i=0 ,j=0 ; while (i < nums1.size () && j < nums2.size ()){ if (nums1[i] <= nums2[j]) arr.push_back (nums1[i++]); else arr.push_back (nums2[j++]); } while (i < nums1.size ()) arr.push_back (nums1[i++]); while (j < nums2.size ()) arr.push_back (nums2[j++]); int len = arr.size (); for (int k = 0 ; k<arr.size ();k++) cout<<arr[k]<<" " ; if (len % 2 != 0 ){ return arr[len / 2 ]; } else { return (arr[len / 2 ] + arr[len / 2 - 1 ]) / 2 ; } } };
知识点 System.arraycopy(srcArr, srcStartIndex, dstArr, dstStartIndex, length)
函数:
第一个参数:源数组
第二个参数:在源数组中,被复制的数字开始复制的下标
第三个参数:目标数组
第四个参数:在目标数组中,从第几个下标开始放入复制的数据
第五个参数:从源数组中,一共拿几个数值放到目标数组中。
例如:System.arraycopy(nums2, 0, nums, n, m);
是从nums2
数组中的下标为 0 的位置开始复制,复制到nums
数组中从下标为n 开始的位置,复制长度为m
题目五:最长回文串 最长回文串
标签 字符串
、动态规划
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution { public String longestPalindrome (String s) { int x = 0 , y = 0 ; for (int i = 0 ; i < s.length(); i ++) { int l = i - 1 , r = i + 1 ; while (l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r)) { l --; r ++; } if (y - x + 1 < r - l + 1 ) { x = l; y = r; } l = i; r = i + 1 ; while (l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r)) { l --; r ++; } if (y - x + 1 < r - l + 1 ) { x = l; y = r; } } System.out.println(x + " " + y); return s.substring(x + 1 , y); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution {public : string longestPalindrome (string s) { string res; for (int i=0 ;i<s.size ();i++){ int l = i - 1 , r = i + 1 ; while (l >= 0 && r <= s.size () && s[l] == s[r]) l --, r ++; if (res.size () < r - l - 1 ) res = s.substr (l + 1 , r - l - 1 ); l = i, r = i + 1 ; while (l >= 0 && r <= s.size () && s[l] == s[r]) l --, r ++; if (res.size () < r - l -1 ) res = s.substr (l + 1 , r - l -1 ); } return res; } };
题目六:正则表达式匹配❗ 正则表达式匹配
标签 递归
、字符串
、动态规划
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Solution { public boolean isMatch (String s, String p) { int m = s.length(); int n = p.length(); boolean [][] dp = new boolean [m + 1 ][n + 1 ]; dp[0 ][0 ] = true ; for (int i = 0 ; i <= m; i ++) { for (int j = 1 ; j <= n; j ++) { if (p.charAt(j - 1 ) != '*' ) { if (matches(s, p, i, j)) { dp[i][j] = dp[i - 1 ][j - 1 ]; } } else { dp[i][j] = dp[i][j - 2 ]; if (matches(s, p, i, j - 1 )) { dp[i][j] = dp[i - 1 ][j] || dp[i][j]; } } } } return dp[m][n]; } public boolean matches (String s, String p, int i, int j) { if (i == 0 ) return false ; if (p.charAt(j - 1 ) == '.' ) return true ; return s.charAt(i - 1 ) == p.charAt(j - 1 ); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class Solution {public : bool matches (string s, string p, int i, int j) { if (i == 0 ) return false ; if (p[j - 1 ] == '.' ) return true ; return s[i - 1 ] == p[j - 1 ]; } bool isMatch (string s, string p) { int m = s.size (); int n = p.size (); vector<vector<int >> dp (m + 1 , vector <int >(n + 1 )); dp[0 ][0 ] = true ; for (int i = 0 ; i <= m; i ++) { for (int j = 1 ; j <= n; j ++) { if (p[j - 1 ] == '*' ) { dp[i][j] = dp[i][j - 2 ]; if (matches (s, p, i, j - 1 )) { dp[i][j] |= dp[i - 1 ][j]; } } else { if (matches (s, p, i, j)) { dp[i][j] = dp[i - 1 ][j - 1 ]; } } } } return dp[m][n]; } };
思路 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 以一个例子详解动态规划转移方程: S = abbbbc P = ab*d*c 1. 当 i, j 指向的字符均为字母(或 '.' 可以看成一个特殊的字母)时, 只需判断对应位置的字符即可, 若相等,只需判断 i,j 之前的字符串是否匹配即可,转化为子问题 f[i-1][j-1]. 若不等,则当前的 i,j 肯定不能匹配,为 false. f[i-1][j-1] i | | S [a b b b b][c] P [a b * d *][c] | j 2. 如果当前 j 指向的字符为 '*',则不妨把类似 'a*', 'b*' 等的当成整体看待。 看下面的例子 i | S a b [b] b b c P a [b *] d * c | j 注意到当 'b*' 匹配完 'b' 之后,它仍然可以继续发挥作用。 因此可以只把 i 前移一位,而不丢弃 'b*', 转化为子问题 f[i-1][j]: i | <-- S a [b] b b b c P a [b *] d * c | j 另外,也可以选择让 'b*' 不再进行匹配,把 'b*' 丢弃。 转化为子问题 f[i][j-2]: i | S a b [b] b b c P [a] b * d * c | j <-- 3. 冗余的状态转移不会影响答案, 因为当 j 指向 'b*' 中的 'b' 时, 这个状态对于答案是没有用的, 原因参见评论区 稳中求胜 的解释, 当 j 指向 '*' 时, dp[i][j]只与dp[i][j-2]有关, 跳过了 dp[i][j-1].
状态表示 :dp[i][j]
表示字符串s的前i个字符和字符串p的前j个字符是否匹配。其中对应的是字符串s的第i-1 个字符,和字符串p的第j-1 个字符
状态转移 :
如果 p[j - 1] != '*'
:
如果p[j - 1] == '.' || p[j - 1] == s[i - 1]
:则dp[i][j] = dp[i - 1][j - 1]
否则:dp[i][j] = false
如果 p[j - 1] == '*'
:
dp[i][j] = dp[i][j - 2]
,代表 * 不匹配任何字符
如果p[j - 2] == '.' || p[j - 2] == s[i - 1]
:则dp[i][j] = dp[i - 1][j] || dp[i][j - 2]
知识点 C++中定义二维容器vector时指定大小的方法:vector<vector<int>> arr(m, vector<int>(n))
,定义了一个m行n列的容器
题目七:盛最多水的容器⭐ 盛最多水的容器
标签 贪心
、数组
、双指针
题解 1 2 3 4 5 6 7 8 9 10 11 12 class Solution { public int maxArea (int [] height) { int l = 0 , r = height.length - 1 ; int res = 0 ; while (l < r) { res = Math.max(res, Math.min(height[l], height[r]) * (r - l)); if (height[l] < height[r]) l ++; else r --; } return res; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 class Solution {public : int maxArea (vector<int >& height) { int res = 0 ; int len = height.size (); for (int i = 0 , j = len - 1 ; i < j;){ res = max (res, min (height[i], height[j]) * (j - i)); if (height[i] > height[j]) j--; else i++; } return res; } };
题目八:三数之和 三数之和
标签 数组
、双指针
、排序
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 class Solution { public List<List<Integer>> threeSum (int [] nums) { List<List<Integer>> res = new ArrayList <>(); if (nums.length < 3 ) return res; Arrays.sort(nums); for (int i = 0 ; i < nums.length - 2 ; i ++) { if (i == 0 || i != 0 && nums[i] != nums[i - 1 ]){ int l = i + 1 , r = nums.length - 1 ; while (l < r) { if (nums[i] + nums[l] + nums[r] == 0 ) { List<Integer> arr = new ArrayList <>(); arr.add(nums[i]); arr.add(nums[l]); arr.add(nums[r]); res.add(arr); boolean flag = false ; for (int k = l + 1 ; k < r; k ++) { if (nums[k] != nums[l]) { l = k; flag = true ; break ; } } if (!flag) break ; } if (nums[i] + nums[l] + nums[r] > 0 ) r --; else l ++; } } } return res; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 class Solution {public : vector<vector<int >> threeSum (vector<int >& nums) { vector<vector<int >> res; if (nums.size () < 3 ) return res; sort (nums.begin (), nums.end ()); for (int i = 0 ; i < nums.size () - 2 ; i ++){ if (i ==0 || i != 0 && nums[i] != nums[i - 1 ]){ cout << i << endl; int a = 0 - nums[i]; int l = i + 1 , r = nums.size () - 1 ; while (l < r) { if (nums[l] + nums[r] < a){ l ++; } else if (nums[l] + nums[r] > a){ r --; } else { cout << i << endl; vector<int > arr; arr.push_back (nums[i]); arr.push_back (nums[l]); arr.push_back (nums[r]); res.push_back (arr); bool flag = false ; for (int k = l + 1 ; k < r; k++){ if (nums[k] != nums[l]){ l = k; flag = true ; break ; } } if (!flag) break ; } } } } return res; } };
题目九:电话号码的字母组合 电话号码的字母组合
标签 哈希表
、字符串
、回溯
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 class Solution { List<String> res = new LinkedList <>(); String[] strs = new String []{ "" , "abc" , "def" , "ghi" , "jkl" , "mno" , "pqrs" , "tuv" , "wxyz" }; public void dfs (String digits, int len, StringBuilder path) { if (len >= digits.length()) res.add(path.toString()); else { int x = digits.charAt(len) - '0' - 1 ; for (char str : strs[x].toCharArray()) { dfs(digits, len + 1 , path.append(str)); path.deleteCharAt(path.length() - 1 ); } } } public List<String> letterCombinations (String digits) { if ("" .equals(digits)) return res; StringBuilder path = new StringBuilder (); dfs(digits, 0 , path); return res; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution {public : vector<string> ans; string str[10 ] = { "" , "" , "abc" , "def" , "ghi" , "jkl" , "mno" , "pqrs" , "tuv" , "wxyz" , }; vector<string> letterCombinations (string digits) { if (digits.size () == 0 ) return ans; dfs (digits, 0 , "" ); return ans; } void dfs (string& digits, int u, string path) { if (u >= digits.size ()) ans.push_back (path); else { int t = digits[u] - '0' ; for (auto c : str[t]){ dfs (digits, u + 1 , path + c); } } } };
题目十:删除链表的倒数第N个节点 删除链表的倒数第N个节点
标签 链表
、双指针
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class Solution { public ListNode removeNthFromEnd (ListNode head, int n) { int len = 0 ; ListNode p = head; while (p != null ) { p = p.next; len ++; } n = len - n; if (n == 0 ) head = head.next; else { p = head; n --; while (n != 0 ){ p = p.next; n --; } p.next = p.next.next; } return head; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 class Solution {public : ListNode* removeNthFromEnd (ListNode* head, int n) { ListNode *p = head; int num = 0 ; while (p){ num ++; p = p ->next; } int x = num - n; p = head; ListNode *q = head; if (x == 0 ){ head = p ->next; }else { while (x --){ q = p; p = p->next; } q->next = p->next; } return head; } };
题目十一:有效的括号 有效的括号
标签 栈
、字符串
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution { public boolean isValid (String s) { if (s.length() == 1 ) return false ; Stack<Character> stk = new Stack <>(); for (int i = 0 ; i < s.length(); i ++) { char ch = s.charAt(i); if (ch == '(' || ch == '{' || ch == '[' ) stk.push(ch); else if (stk.empty() != true && ch == ')' && stk.peek() == '(' ) stk.pop(); else if (stk.empty() != true && ch == '}' && stk.peek() == '{' ) stk.pop(); else if (stk.empty() != true && ch == ']' && stk.peek() == '[' ) stk.pop(); else { return false ; } } return stk.empty(); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution {public : bool isValid (string s) { stack<char > sta; if (s.size ()==1 ){ return false ; } for (int i=0 ;i<s.size ();i++){ if (s[i] == '(' || s[i] == '[' || s[i] == '{' ){ sta.push (s[i]); }else if (sta.size ()!=0 ){ char c = sta.top (); sta.pop (); if (c == '[' && s[i] == ']' || c == '{' && s[i] == '}' || c == '(' && s[i] == ')' ){ continue ; }else { return false ; } }else if (sta.size ()==0 ){ return false ; } } if (sta.size ()!=0 ){ return false ; } return true ; } };
题目十二:合并两个有序链表 合并两个有序链表
标签 递归
、链表
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution { public ListNode mergeTwoLists (ListNode list1, ListNode list2) { if (list1 == null ) return list2; else if (list2 == null ) return list1; else if (list1.val < list2.val) { list1.next = mergeTwoLists(list1.next, list2); return list1; } else { list2.next = mergeTwoLists(list1, list2.next); return list2; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 class Solution {public : ListNode* mergeTwoLists (ListNode* list1, ListNode* list2) { ListNode *list = new ListNode (-1 ); ListNode *head = list; ListNode *p = list1; ListNode *q = list2; while (p && q){ if (p -> val <= q -> val){ ListNode *x = new ListNode (p->val); head->next = x; head = head->next; p = p->next; } else { ListNode *x = new ListNode (q->val); head->next = x; head = head->next; q = q->next; } } while (p){ ListNode *x = new ListNode (p->val); head->next = x; head = head->next; p = p->next; } while (q){ ListNode *x = new ListNode (q->val); head->next = x; head = head->next; q = q->next; } return list->next; } };
题目十三:括号生成⭐ 括号生成
标签 字符串
、动态规划
、回溯
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { List<String> res = new LinkedList <>(); public void dfs (int n, int l, int r, StringBuilder str) { if (r == n && l == n) { res.add(str.toString()); return ; } if (l < n) { dfs(n, l + 1 , r, str.append("(" )); str.deleteCharAt(str.length() - 1 ); } if (r < n && r < l) { dfs(n, l, r + 1 , str.append(")" )); str.deleteCharAt(str.length() - 1 ); } } public List<String> generateParenthesis (int n) { StringBuilder str = new StringBuilder (); dfs(n, 0 , 0 , str); return res; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 class Solution {public : vector<string> res; void dfs (string str, int lc, int rc, int n) { if (lc == n && rc == n) res.push_back (str); else { if (lc < n) dfs (str + "(" , lc + 1 , rc, n); if (rc < n && lc > rc) dfs (str + ")" , lc, rc + 1 , n); } } vector<string> generateParenthesis (int n) { dfs ("" , 0 , 0 , n); return res; } };
题目十四:合并K个升序链表❗ 合并K个升序链表
标签 链表
、分治
、堆(优先队列)
、归并排序
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 class Solution { public ListNode mergeKLists (ListNode[] lists) { return merge(lists, 0 , lists.length - 1 ); } public ListNode merge (ListNode[] lists, int l, int r) { if (l == r) return lists[l]; else if (l > r) return null ; int mid = (l + r) >> 1 ; return mergeTwoList(merge(lists, l, mid), merge(lists, mid + 1 , r)); } public ListNode mergeTwoList (ListNode l1, ListNode l2) { if (l1 == null ) return l2; else if (l2 == null ) return l1; else if (l1.val < l2.val) { l1.next = mergeTwoList(l1.next, l2); return l1; } else { l2.next = mergeTwoList(l1, l2.next); return l2; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 class Solution {public : ListNode* mergeKLists (vector<ListNode*>& lists) { return merge (lists, 0 , lists.size () - 1 ); } ListNode* merge (vector<ListNode*> &lists, int l, int r) { if (l == r) return lists[l]; else if (l > r) return nullptr ; int mid = (l + r) >> 1 ; return mergeTwoList (merge (lists, l, mid), merge (lists, mid + 1 , r)); } ListNode* mergeTwoList (ListNode* l1, ListNode* l2) { if (l1 == nullptr ) return l2; else if (l2 == nullptr ) return l1; else if (l1->val < l2->val) { l1->next = mergeTwoList (l1->next, l2); return l1; } else { l2->next = mergeTwoList (l1, l2->next); return l2; } } };
题目十五:下一个排列❗ 下一个排列
标签 数组
、双指针
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution { public void nextPermutation (int [] nums) { int l = -1 , r = 0 ; for (int i = nums.length - 2 ; i >= 0 ; i --) { if (nums[i] < nums[i + 1 ]) { l = i; break ; } } if (l != -1 ) { for (int i = nums.length - 1 ; i > l; i --) { if (nums[i] > nums[l]) { r = i; break ; } } int tmp = nums[l]; nums[l] = nums[r]; nums[r] = tmp; } for (int i = l + 1 , j = nums.length - 1 ; i < j; i ++, j --) { int tmp = nums[i]; nums[i] = nums[j]; nums[j] = tmp; } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution {public : void nextPermutation (vector<int >& nums) { int l = -1 , r = 0 ; for (int i = nums.size () - 2 ; i >= 0 ; i --) { if (nums[i] < nums[i + 1 ]) { l = i; break ; } } if (l != -1 ) { for (int i = nums.size () - 1 ; i > l; i --) { if (nums[i] > nums[l]) { r = i; break ; } } int tmp = nums[l]; nums[l] = nums[r]; nums[r] = tmp; } for (int i = l + 1 , j = nums.size () - 1 ; i < j; i ++, j --) { swap (nums[i], nums[j]); } } };
思路 对于长度为n的排列a:
首先从后向前查找第一个顺序对(i, i + 1)
,满足a[i] < a[i + 1]
。这样【较小数】即为a[i]
。此时[i + 1, n)
必然是下降序列。
如果找到了顺序对,那么在区间[i + 1, n)
中从后向前查找第一个元素j满足a[i] < a[j]
。这样【较大数】即为a[j]
。
交换a[i]
与a[j]
,此时可以证明区间[i + 1, n)
必为降序。我们可以直接使用双指针反转区间[i + 1, n)
使其变为升序,而无需对该区间进行排序。
题目十六:最长有效括号❗ 最长有效括号
标签 栈
、字符串
、动态规划
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 class Solution { public int longestValidParentheses (String s) { int len = s.length(); int [] dp = new int [len + 1 ]; dp[0 ] = 0 ; for (int i = 1 ; i < s.length(); i ++) { if (s.charAt(i) == '(' ) dp[i] = 0 ; else { if (s.charAt(i - 1 ) == '(' ) { dp[i] = dp[i - 1 ] + 2 ; if (i - 2 >= 0 ) dp[i] += dp[i - 2 ]; } else { int x = dp[i - 1 ]; if (x == 0 || i - x - 1 < 0 ) dp[i] = 0 ; else if (s.charAt(i - x - 1 ) == '(' ) { dp[i] = dp[i - 1 ] + 2 ; if (i - x - 2 >= 0 ) dp[i] += dp[i - x - 2 ]; } } } } int maxRes = 0 ; for (int i = 0 ; i < s.length(); i ++) { System.out.println(dp[i]); maxRes = Math.max(maxRes, dp[i]); } return maxRes; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 class Solution {public : int longestValidParentheses (string s) { int len = s.size (); int dp[30010 ]{0 }; dp[0 ] = 0 ; for (int i = 1 ; i < s.size (); i ++) { if (s[i] == '(' ) dp[i] = 0 ; else { if (s[i - 1 ] == '(' ) { dp[i] = dp[i - 1 ] + 2 ; if (i - 2 >= 0 ) dp[i] += dp[i - 2 ]; } else { int x = dp[i - 1 ]; if (x == 0 || i - x - 1 < 0 ) dp[i] = 0 ; else if (s[i - x - 1 ] == '(' ){ dp[i] = dp[i - 1 ] + 2 ; if (i - x - 2 >= 0 ) dp[i] += dp[i - x - 2 ]; } } } } int maxRes = 0 ; for (int i = 0 ; i < s.size (); i ++) { maxRes = max (maxRes, dp[i]); } return maxRes; } };
思路 状态表示 :dp[i]
表示以第i个字符结尾的有效括号的长度。
状态转移 :
dp[i] == '('
:则直接让dp[i] = 0
dp[i] == ')'
:
dp[i - 1] == '('
,本身就组成了一个有效括号子串,然后需要判断前面是否存在其他括号子串和其并列,最后的状态方程为:dp[i] = dp[i - 2] + 2
;
dp[i - 1] == ')'
,需要获得以前一个字符结尾的有效括号子串长度x = dp[i - 1]
x == 0 || i - x - 1
,则说明当前右括号为孤立括号 则dp[i] = 0
s[i - x - 1] == '('
,这说明当前右括号有对应的左括号,同时需要判断该左括号前是否有其他有效括号与其并列,则状态方程为 dp[i] = dp[i - 1] + 2 + dp[i - x - 2]
知识点 在LeetCode中,C++定义数组没有初始化,则可能会提交错误。
题目十七:搜索旋转排序数组⭐ 搜索旋转排序数组
标签 数组
、二分查找
题解 1 2 3 4 5 6 7 8 class Solution { public int search (int [] nums, int target) { for (int i = 0 ; i < nums.length; i ++) { if (nums[i] == target) return i; } return -1 ; } }
1 2 3 4 5 6 7 8 9 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 ; } };
题目十八: 在排序数组中查找元素的第一个和最后一个位置 在排序数组中查找元素的第一个和最后一个位置
标签 数组
、二分查找
、二分查找模板题
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 class Solution { public int [] searchRange(int [] nums, int target) { if (nums.length == 0 ) return new int []{-1 , -1 }; int l = 0 , r = nums.length - 1 ; while (l < r) { int mid = (l + r) >> 1 ; if (nums[mid] < target) l = mid + 1 ; else r = mid; } if (nums[l] != target) return new int []{-1 , -1 }; int i = l; l = 0 ; r = nums.length - 1 ; while (l < r) { int mid = (l + r + 1 ) >> 1 ; if (nums[mid] <= target) l = mid; else r = mid - 1 ; } return new int []{i, r}; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 class Solution {public : vector<int > searchRange (vector<int >& nums, int target) { vector<int > res; if (nums.size () == 0 ){ res.push_back (-1 ); res.push_back (-1 ); return res; } int l = 0 , r = nums.size () - 1 ; while (l < r){ int mid = (l + r) >> 1 ; if (nums[mid] >= target) r = mid; else l = mid + 1 ; } if (nums[l] != target){ res.push_back (-1 ); res.push_back (-1 ); }else { res.push_back (l); l = 0 , r = nums.size () - 1 ; while (l < r){ int mid = (l + r + 1 ) >> 1 ; if (nums[mid] <= target) l = mid; else r = mid - 1 ; } res.push_back (r); } return res; } };
题目十九:组合总和 组合总和
标签 数组
、回溯
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution { private List<List<Integer>> res = new ArrayList <List<Integer>>(); private List<Integer> arr = new ArrayList <>(); public void dfs (int target, int sum, int [] candidates, int idx) { if (sum == target) { res.add(new ArrayList <Integer>(arr)); } else if (sum > target) return ; else { for (int i = idx; i < candidates.length; i ++) { sum += candidates[i]; arr.add(candidates[i]); dfs(target, sum, candidates, i); sum -= arr.get(arr.size() - 1 ); arr.remove(arr.size() - 1 ); } } } public List<List<Integer>> combinationSum (int [] candidates, int target) { dfs(target, 0 , candidates, 0 ); return res; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 class Solution {public : vector<vector<int >> res; void dfs (vector<int >& arr, int target, int sum, vector<int >& candidates, int idx) { if (sum == target) res.push_back (arr); else if (sum > target) return ; else { for (int i = idx; i < candidates.size (); i++){ sum += candidates[i]; arr.push_back (candidates[i]); dfs (arr, target, sum, candidates, i); sum -= arr[arr.size () - 1 ]; arr.pop_back (); } } } vector<vector<int >> combinationSum (vector<int >& candidates, int target) { vector<int > arr; dfs (arr, target, 0 , candidates, 0 ); return res; } };
知识点 在Java中将List<>
插入List<List>>
的方法,例如:
1 2 3 4 5 private List<List<Integer>> res = new ArrayList <List<Integer>>();private List<Integer> arr = new ArrayList <>();.... res.add(new ArrayList <Integer>(arr));
ArrayList
删除第i个元素的方法:arr.remove(i)
。获取第i个元素的方法arr.get(i)
题目二十:接雨水❗ 接雨水
标签 栈
、数组
、双指针
、动态规划
、单调栈
题解
题目二十一:全排列 全排列
标签 数组
、回溯
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 class Solution { List<List<Integer>> res = new ArrayList <>(); boolean [] st; void dfs (List<Integer> arr, int [] nums) { if (arr.size() == nums.length) { res.add(new ArrayList <Integer>(arr)); return ; } for (int i = 0 ; i < nums.length; i ++){ if (!st[i]) { arr.add(nums[i]); st[i] = true ; dfs(arr, nums); st[i] = false ; arr.remove(arr.size() - 1 ); } } } public List<List<Integer>> permute (int [] nums) { int n = nums.length; st = new boolean [n]; List<Integer> arr = new ArrayList <>(); dfs(arr, nums); return res; } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 class Solution {public : vector<vector<int >> res; vector<bool > used; void dfs (vector<int >& arr, vector<int >& nums) { if (arr.size () == nums.size ()) res.push_back (arr); else { for (int i = 0 ; i < nums.size (); i++){ if (!used[i]){ arr.push_back (nums[i]); used[i] = true ; dfs (arr, nums); used[i] = false ; arr.pop_back (); } } } } vector<vector<int >> permute (vector<int >& nums) { vector<int > arr; for (int i = 0 ; i < nums.size (); i++){ used.push_back (false ); } dfs (arr, nums); return res; } };
题目二十二:旋转图像 旋转图像
标签 数组
、数学
、矩阵
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 class Solution { public void rotate (int [][] matrix) { int len = matrix.length; for (int i = 0 ; i < len / 2 ; i++){ for (int j = i; j < len - i - 1 ; j++){ int tmp = matrix[i][j]; matrix[i][j] = matrix[len - j - 1 ][i]; matrix[len - j - 1 ][i] = matrix[len - i - 1 ][len - j - 1 ]; matrix[len - i - 1 ][len - j - 1 ] = matrix[j][len - i - 1 ]; matrix[j][len - i - 1 ] = tmp; } } } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 class Solution {public : void rotate (vector<vector<int >>& matrix) { int len = matrix.size (); for (int i = 0 ; i < len / 2 ; i++){ for (int j = i; j < len - i - 1 ; j++){ int tmp = matrix[i][j]; matrix[i][j] = matrix[len - j - 1 ][i]; matrix[len - j - 1 ][i] = matrix[len - i - 1 ][len - j - 1 ]; matrix[len - i - 1 ][len - j - 1 ] = matrix[j][len - i - 1 ]; matrix[j][len - i - 1 ] = tmp; } } } };
题目二十三:字母异位词分组 字母异位词分组
标签 数组
、哈希表
、字符串
、排序
题解 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 class Solution { public List<List<String>> groupAnagrams (String[] strs) { Map<String, List<String>> hsp = new HashMap <>(); for (String str : strs) { char [] arr = str.toCharArray(); Arrays.sort(arr); String key = new String (arr); List<String> list = hsp.getOrDefault(key, new ArrayList <String>()); list.add(str); hsp.put(key, list); } return new ArrayList <List<String>>(hsp.values()); } }
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 class Solution {public : vector<vector<string>> groupAnagrams (vector<string>& strs) { vector<vector<string>> res; unordered_map<string, vector<string>> hashMap; for (int i = 0 ; i < strs.size (); i++){ string str = strs[i]; sort (str.begin (), str.end ()); if (hashMap.empty () || hashMap.find (str) == hashMap.end ()){ vector<string> arr; arr.push_back (strs[i]); hashMap[str] = arr; } else { hashMap[str].push_back (strs[i]); } } for (unordered_map<string, vector<string>>::iterator iter = hashMap.begin (); iter != hashMap.end (); iter++){ res.push_back (iter->second); } return res; } };
知识点
在java中,String类型字符转排序需要先转为char[],然后使用数组排序的方法进行排序,最后再转为String
1 2 3 4 String str = "azxcadfasd" ;char [] arr = str.toCharArray(); Arrays.sort(arr); String key = new String (arr);
HashMap中的getOrDefault(key, default value)
方法是如果存在key,则返回value,否则返回给定的默认值
HashMap中的values()
方法是返回map中所有的value