LC01:兩數之和
可以采用暴力解法和哈希表
class Solution { public int[] twoSum(int[] nums, int target) { //哈希表法 //建立哈希表 Map<Integer, Integer> hashtable = new HashMap<Integer, Integer>(); for (int i = 0; i < nums.length; ++i) { //如果有target - 自己 的差 if (hashtable.containsKey(target - nums[i])) { //如果找得到另一個加數則返回兩數的下標 return new int[]{hashtable.get(target - nums[i]), i}; } //如果沒找到,就把當前的key-value存入map hashtable.put(nums[i], i); } //無結果返回空數組 return new int[0]; } }
LC02:兩數相加

相當於反過來的加法,采用迭代和遞歸兩種算法
迭代法 class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { int next = 0; int total = 0; ListNode asm = new ListNode(); ListNode cur = asm; while(l1 != null && l2 != null){ total = l1.val + l2.val + next; cur.next = new ListNode(total % 10); next = total / 10; l1 = l1.next; l2 = l2.next; cur = cur.next; } while(l1 != null){ total = l1.val + next; cur.next = new ListNode(total % 10); next = total / 10; l1 = l1.next; cur = cur.next; } while(l2 != null){ total = l2.val + next; cur.next = new ListNode(total % 10); next = total / 10; l2 = l2.next; cur = cur.next; } while(next != 0){ cur.next = new ListNode(next); } return asm.next; } } //遞歸法 class Solution { public ListNode addTwoNumbers(ListNode l1, ListNode l2) { int total = l1.val + l2.val; //表示進位是多少 int next = total / 10; ListNode res = new ListNode(total % 10); if(l1.next != null || l2.next != null || next != 0){ l1 = l1.next != null ? l1.next : new ListNode(0); l2 = l2.next != null ? l2.next : new ListNode(0); l1.val += next; res.next = addTwoNumbers(l1,l2); } return res; } }
LC03:無重復字符的最長子串

采用滑動窗口
class Solution { public int lengthOfLongestSubstring(String s) { //滑動窗口 if(s.length() == 0) return 0; HashMap<Character,Integer> map = new HashMap<Character,Integer>(); int max = 0; int left = 0; for(int i = 0; i < s.length(); i++){ if(map.containsKey(s.charAt(i))){ left = Math.max(left,map.get(s.charAt(i))+1); } map.put(s.charAt(i), i); max = Math.max(max, i - left +1); //max為重復元素下標 - 之前原本擁有的重復元素的下標 +1 //(即兩者之間的距離,即最長子串) } return max; } }
LC04:尋找兩個正序數組的中位數

采用將兩個數組中的所有元素排序的方法
class Solution { public double findMedianSortedArrays(int[] nums1, int[] nums2) { //建立一個新數組存儲兩個里的元素 int[] nums; int m = nums1.length; int n = nums2.length; nums = new int[m + n]; //1.先將兩個數組合並排序 //如果某個數組為空 if (m == 0) { //奇偶數的中位數所在位置不同 if (n % 2 == 0) { return (nums2[n / 2 - 1] + nums2[n / 2]) / 2.0; } else { return nums2[n / 2]; } } if (n == 0) { if (m % 2 == 0) { return (nums1[m / 2 - 1] + nums1[m / 2]) / 2.0; } else { return nums1[m / 2]; } } //兩者都不為空 int count = 0; int i = 0, j = 0; while (count != (m + n)) { //數組一到頂 if (i == m) { while (j != n) { nums[count++] = nums2[j++]; } break; } //數組二到頂 if (j == n) { while (i != m) { nums[count++] = nums1[i++]; } break; } if (nums1[i] < nums2[j]) { nums[count++] = nums1[i++]; } else { nums[count++] = nums2[j++]; } } //2.再計算中位數位置 if (count % 2 == 0) { return (nums[count / 2 - 1] + nums[count / 2]) / 2.0; } else { return nums[count / 2]; } } }
LC05:最長回文子串

暴力法但是會超出時間限制
class Solution { public String longestPalindrome(String s) { int len = s.length(); String ans = ""; int max = 0; for(int i = 0; i < len; i++){ for(int j = i + 1; j <= len; j++){ //s.substring表示截取s的下標第 i 到第 j-1 個字符 String test = s.substring(i,j); if(isPalindrome(test) && test.length() > max){ ans = s.substring(i, j); max = Math.max(ans.length(), max); } } } return ans; } //定義一個函數判斷字符串是否回文 public boolean isPalindrome(String s){ int length = s.length(); //只需檢查一半長度即可 for(int i = 0; i < length/2; i++){ //如果有一個兩邊的對應位置字符不同,則不是回文 if(s.charAt(i) != s.charAt(length-i-1)){ return false; } } return true; } }
LC10: 正則表達式匹配
不會
LC11:盛最多水的容器

雙指針兩頭向中間的解法
class Solution { public int maxArea(int[] height) { //從兩邊向中間求解 //每次只需要移動較短的板 //因為當移動長板時,底會變小,而高會變小或不變,面積一定變小 //但是移動短板就可能會使面積變大 int len = height.length; int i = 0, j = len - 1, res = 0; while(i < j){ res = height[i] < height[j] ? //j - i需要放在height[i++]前面是因為 //如果height[i++]在前面那么i j的值就會先發生改變 Math.max(res, (j - i) * height[i++]): Math.max(res, (j - i) * height[j--]); } return res; } }
LC15:三數之和

排序+雙指針
class Solution { //二維數組List<List<template>> public List<List<Integer>> threeSum(int[] nums) { //先對數組進行排序然后采用雙指針 Arrays.sort(nums); List<List<Integer>> res = new ArrayList<>(); //建立k,為三個數中的最小值 for(int k = 0; k < nums.length - 2; k++){ //如果k大於0那么三個數之和不可能為0 if(nums[k] > 0) break; //如果num[k]和num[k+1]重復,那么跳到下一個值 if(k > 0 && nums[k] == nums[k-1]) continue; //i從k+1開始,j從末尾開始 int i = k + 1, j = nums.length - 1; while(i < j){ int sum = nums[k] + nums[i] + nums[j]; if(sum > 0){ //這么寫容易出錯,不要亂學 while(i < j && nums[j] == nums[--j]); } else if(sum < 0){ while(i < j && nums[i] == nums[++i]); } else{ //sum為0的時候加入這三個數到List里 //自己寫一遍加深印象 //res.add(new ArrayList<Integer>(Arrays.asList(nums[k],nums[i],nums[j]))); res.add(new ArrayList<Integer>(Arrays.asList(nums[k], nums[i], nums[j]))); //i增j減,並跳過所有重復的i, j while(i < j && nums[i] == nums[++i]); while(i < j && nums[j] == nums[--j]); } } } return res; } }
LC17:電話號碼的字母組合
沒看懂
LC19:刪除鏈表的倒數第 N 個結點

雙鏈表法和棧(復雜度較高)
//雙鏈表 class Solution { public ListNode removeNthFromEnd(ListNode head, int n) { //表示per.next = head;而pre為空指針 ListNode pre = new ListNode(0, head); ListNode start = pre, end = pre; //start先往前n個節點 while(n != 0) { start = start.next; n--; } //然后一起往后移動直到start的next指向空 while(start.next != null) { start = start.next; end = end.next; } end.next = end.next.next; return pre.next; //棧 ListNode dummy = new ListNode(0, head); //建立一個棧Deque Deque<ListNode> stack = new LinkedList<ListNode>(); ListNode cur = dummy; //全部入棧 while (cur != null) { stack.push(cur); cur = cur.next; } //出棧n個,棧頂的數就是倒數第 n+1 個 for (int i = 0; i < n; ++i) { stack.pop(); } //stack.peek()指向棧頂元素 ListNode prev = stack.peek(); //棧頂元素的next即為倒數第n項 prev.next = prev.next.next; ListNode ans = dummy.next; return ans; } }

采用棧
class Solution { public boolean isValid(String s) { //如果是奇數則直接false if(s.length() % 2 == 1) return false; //建立哈希表 Map<Character, Character> pairs = new HashMap<Character, Character>() {{ put('(', ')'); put('[', ']'); put('{', '}'); }}; //如果最開始是右括號直接結束 if(pairs.containsValue(s.charAt(0))) return false; //建立棧 Deque<Character> stack = new LinkedList<Character>(); //遍歷 for(Character c : s.toCharArray()){ //如果是左括號則入棧 if(pairs.containsKey(c)) stack.push(c); //如果是右括號且棧頂是其對應的左括號則左括號出棧 else if(pairs.get(stack.peek()) == c) stack.pop(); //否則false else {return false;} } //最后隊列如果不為空,則false return stack.isEmpty(); } }
LC21:合並兩個有序鏈表

遞歸and迭代
class Solution { public ListNode mergeTwoLists(ListNode l1, ListNode l2) { //迭代法 ListNode pre = new ListNode(0); ListNode prev = pre; while(l1 != null && l2!= null){ //Java的鏈表值是val不是value if(l1.val <= l2.val){ //哪個val小指向哪個,且鏈表next prev.next = l1; l1 = l1.next; }else{ prev.next = l2; l2 = l2.next; } //不要記得把prev也next prev = prev.next; } prev.next = l1 ==null? l2 : l1; return pre.next; //遞歸法 if(l1 == null){ return l2; } else if(l2 == null){ return l1; } else if(l1.val <= l2.val){ l1.next = mergeTwoLists(l1.next,l2); return l1; } else{ l2.next = mergeTwoLists(l1,l2.next); return l2; } } }
LC22: 括號生成


這是一個滿二叉樹,要做的是DFS所有節點
class Solution { List<String> res = new ArrayList<>(); public List<String> generateParenthesis(int n) { //如果n < 0則null if (n <= 0) return null; //最開始paths是空的,left,right都賦為0 def("", 0, 0, n); return res; } //遍歷二叉樹的函數 public void def(String paths, int left, int right, int n) { //left或者right的數量不大於n即可 if (left > n || right > left) return; //下面這行錯誤,因為必須現有左括號才有右括號,所有左必先比右達到n // if (right > n || left > right) return; //如果有滿足條件的2n長度的paths則添加進res里 //只有當最后一次迭代才會進這個if if (paths.length() == n * 2) { res.add(paths); return; } //繼續進行,生成一個paths就加一個左或右括號,知道left/right到達max值n def(paths + "(", left + 1, right, n); def(paths + ")", left, right + 1, n); } }
LC23:合並K個升序鏈表

分治成單個鏈表,然后逐一比較每個鏈表的頭結點的val
class Solution { //merge,英文為合並的意思 public ListNode mergeKLists(ListNode[] lists) { return merge(lists, 0, lists.length - 1); } //分治,不斷地尋找ListNodep[]數組里的lists public ListNode merge(ListNode[] lists, int l, int r) { if (l == r) { return lists[l]; } if (l > r) { return null; } int mid = (l + r) >> 1; //直到最終分割成單獨的list,來merge排序 return mergeTwoLists(merge(lists, l, mid), merge(lists, mid + 1, r)); } //合並兩個鏈表的迭代算法 public ListNode mergeTwoLists(ListNode a, ListNode b) { if (a == null || b == null) { return a != null ? a : b; } ListNode head = new ListNode(0); ListNode tail = head, aPtr = a, bPtr = b; while (aPtr != null && bPtr != null) { if (aPtr.val < bPtr.val) { tail.next = aPtr; aPtr = aPtr.next; } else { tail.next = bPtr; bPtr = bPtr.next; } tail = tail.next; } tail.next = aPtr == null ? bPtr : aPtr; return head.next; } }
LC31: 下一個排列

//在盡可能靠右的低位進行交換,需要從后向前查找 //將一個盡可能小的「大數」與前面的「小數」交換。 //比如 123465,下一個排列應該把 5 和 4 交換而不是把 6 和 4 交換 //將「大數」換到前面后,需要將「大數」后面的所有數重置為升序 //升序排列就是最小的排列 //以 123465 為例:首先按照上一步,交換 5 和 4,得到 123564; //然后需要將 5 之后的數重置為升序,得到 123546。 //顯然 123546 比 123564 更小,123546 就是 123465 的下一個排列 class Solution { public void nextPermutation(int[] nums) { int i = nums.length - 2; //按照從后往前,尋找前面比后面大的【小數】(可交換) while (i >= 0 && nums[i] >= nums[i + 1]) { i--; } //如果還沒到數組頭 if (i >= 0) { int j = nums.length - 1; //盡可能往后尋找【大數】與剛剛找到的【小數】交換 while (j >= 0 && nums[i] >= nums[j]) { j--; } //交換大小數 swap(nums, i, j); } //如果沒有找到可以交換的,則重排序整個數組(即升序排列) reverse(nums, i + 1); } public void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } public void reverse(int[] nums, int start) { int left = start, right = nums.length - 1; while (left < right) { swap(nums, left, right); left++; right--; } } } // class Solution { // public void nextPermutation(int[] nums) { // int len = nums.length; // for (int i = len - 1; i > 0; i--) { // //從后往前先找出第一個相鄰的后一個大於前一個情況 // //此時的i-1位置就是需要交換的位置 // if (nums[i] > nums[i - 1]) { // Arrays.sort(nums, i, len); // //對i自己和之后的元素排序,[i,len)從小到大 // for (int j = i; j <len; j++) { // //第一個大於i-1位置的進行交換,那么就是下一個排列 // if (nums[j] > nums[i - 1]) { // int temp = nums[j]; // nums[j] = nums[i - 1]; // nums[i - 1] = temp; // return; // } // } // } // } // Arrays.sort(nums); // //最后3,2,1情況的下一個就是1,2,3要重新排列成最小的 // //這種情況上面的交換執行不了 // return; // } // }
LC32:最長有效括號

//建立一個棧,利用找到一對()就出棧的原則 //利用當前位置減去棧頂位置可得到pop出的括號數 class Solution { public int longestValidParentheses(String s) { //如果為空 if (s == null || s.length() == 0) return 0; //建立一個棧 Deque<Integer> stack = new ArrayDeque<>(); //這一步可以防止當第一個Character是')'的時候發生越界異常 stack.push(-1); //System.out.println(stack); //可以看到stack是[-1] int res = 0; //遍歷棧找尋合適的左右括號 for (int i = 0; i < s.length(); i++) { //如果找到左括號則入棧,為尋找對應右括號做鋪墊 if (s.charAt(i) == '(') stack.push(i); else { //如果是右括號則出棧 stack.pop(); //但是如果棧是空的話還是得(單身的)把右括號放進來 if (stack.isEmpty()) stack.push(i); else { //當前全部人數減去剩余無法配對的人數(單身)即res res = Math.max(res, i - stack.peek()); } } } return res; } }
LC33:搜索旋轉排序數組

//二分查找 class Solution { public int search(int[] nums, int target) { int n = nums.length; if (n == 0) { return -1; } if (n == 1) { return nums[0] == target ? 0 : -1; } int l = 0, r = n - 1; while (l <= r) { int mid = (l + r) / 2; if (nums[mid] == target) { return mid; } if (nums[0] <= nums[mid]) { if (nums[0] <= target && target < nums[mid]) { r = mid - 1; } else { l = mid + 1; } } else { if (nums[mid] < target && target <= nums[n - 1]) { l = mid + 1; } else { r = mid - 1; } } } return -1; } }

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)/2; if(nums[mid] >= target) r = mid; else l = mid + 1; } //查找失敗 if(nums[r] != target) return new int[]{-1,-1}; //記錄左界 int LEFT = r; //二分范圍 l = 0; r = nums.length - 1; //查找元素的結束位置 while(l < r){ //向上取整,防止循環r = l + 1 int mid = (l + r + 1)/2; if(nums[mid] <= target) l = mid; else r = mid - 1; } //記錄右界 int RIGHT = r; return new int[]{LEFT,RIGHT}; } }
LC39:組合總和



class Solution { public List<List<Integer>> combinationSum(int[] candidates, int target) { List<List<Integer>> res = new ArrayList<>(); //為空 if (candidates == null) return res; //path是一個棧,用來存儲從根結點到葉子結點的路徑 Deque<Integer> path = new ArrayDeque<>(); //深搜 dfs(candidates, 0, candidates.length, target, path, res); return res; } void dfs(int[] candidates, int begin, int len, int target, Deque<Integer> path, List<List<Integer>> res) { //符合要求(已剪枝) if (target == 0){ res.add(new ArrayList<>(path)); return; } //從 begin 開始搜索 for (int i = begin; i < len; i++) { //如果減數大於目標值,則差為負數,不符合結果 if (candidates[i]<=target){ //addLast表示向棧尾添加元素,傳值不能為空 path.addLast(candidates[i]); //由於每一個元素可以重復使用,下一輪搜索的起點依然是 i,這里非常容易弄錯 dfs(candidates,i,candidates.length,target - candidates[i],path,res); //每次回溯將最后一次加入的讓 target 等於 0 或者 負數 的元素刪除 path.removeLast(); 遞歸之前 => [2],剩余 = 5 } } } } //可以看到removeLast的作用 // 遞歸之前 => [2, 2],剩余 = 3 // 遞歸之前 => [2, 2, 2],剩余 = 1 // 遞歸之后 => [2, 2] // 遞歸之前 => [2, 2, 3],剩余 = 0 // 遞歸之后 => [2, 2] // 遞歸之后 => [2] // 遞歸之前 => [2, 3],剩余 = 2 // 遞歸之后 => [2] // 遞歸之后 => [] // 遞歸之前 => [3],剩余 = 4 // 遞歸之前 => [3, 3],剩余 = 1 // 遞歸之后 => [3] // 遞歸之后 => [] // 遞歸之前 => [6],剩余 = 1 // 遞歸之后 => [] // 遞歸之前 => [7],剩余 = 0 // 遞歸之后 => [] // 輸出 => [[2, 2, 3], [7]]
LC42:接雨水

/* 一行一行進行求解 * 求第 i 層的水,遍歷每個位置 * 如果當前的高度小於 i,並且兩邊有高度大於等於 i 的 * 說明這個地方一定有水,水就可以加 1 */ //超出時間限制 class Solution { public int trap(int[] height) { int res = 0; int H = getMax(height); //一層一層求解 for(int i = 0; i <= max; i++){ //是否更新temp_sum boolean isStart = false; //一層有的積水初始為0(可理解為低窪塊) int temp_sum = 0; for(int j = 0; j < height.length; j++){ //當temp_sum要開始更新,並且當前高度小於i //設置這個if表示只有當出現低窪(小於i)時,才會在遇到高於i的柱子時加水s if(isStart && height[j] < i){ //之后如果有高於 i 的必定可以加1,所以先改變temp_sum temp_sum++; } //如果兩邊高度大於等於i if(height[j] >= i){ sum = sum + temp_sum; //有水,sum可以加1 temp_sum = 0; //重置temp_sum isStart = true; //重置更新狀態 } } } return sum; } private int getMax(int[] height){ int max = 0; for(int i = 0; i < height.length; i++){ if(height[i] > max) max = height[i]; } return max; } } 棧解法 class Solution { public int trap(int[] walls) { if (walls == null || walls.length <= 2) { return 0; } //單調不增棧,walls元素作為右牆依次入棧 //出現入棧元素(右牆)比棧頂大時,說明在右牆左側形成了低窪處 //低窪處出棧並結算該低窪處能接的雨水 int water = 0; Stack<Integer> stack = new Stack<>(); for (int right=0; right<walls.length; right++) { //棧不為空,且當前元素(右牆)比棧頂(右牆的左側)大:說明形成低窪處了 while (!stack.isEmpty() && walls[right]>walls[stack.peek()]) { //低窪處彈出,嘗試結算此低窪處能積攢的雨水 int bottom = stack.pop(); //看左牆是否存在 //有右牆+有低窪+沒有左牆=白搭 if (stack.isEmpty()) { break; } //左牆位置以及左牆、右牆、低窪處的高度 int left = stack.peek(); int leftHeight = walls[left]; int rightHeight = walls[right]; int bottomHeight = walls[bottom]; // 能積攢的水=(右牆位置-左牆位置-1) * (min(右牆高度, 左牆高度)-低窪處高度) water += (right-left-1) * (Math.min(leftHeight, rightHeight)-bottomHeight); } // 上面的pop循環結束后再push,保證stack是單調不增(保證之后棧頂pop的元素存在) stack.push(right); } return water; } }
LC46:全排列

回溯算法公式
backtrack(路徑, 選擇列表): if 滿足結束條件: result.add(路徑) return for 選擇 in 選擇列表: 做選擇 backtrack(路徑, 選擇列表) 撤銷選擇
代碼:
class Solution { List<List<Integer>> rlc = new ArrayList<>(); //存儲返回結果 List<Integer> rls = new ArrayList<>(3); //存儲當前列表中元素 public List<List<Integer>> permute(int[] nums) { backtacking(nums,0); //返回最終的結果集 return rlc; } void backtacking(int[] nums , int startIndex){ if(rls.size() == nums.length){ //將rls結果集加入進來 rlc.add(new ArrayList<>(rls)); return; } //排列從0開始 for(int i = 0; i < nums.length; i++){ //如果集合中存在相同的元素則不會把nums[i]加入進去 if(rls.contains(nums[i]) == false){ rls.add(nums[i]); backtacking(nums,i + 1); //撤銷處理結點,確保rls.size()-1不會發生數組下標越界的情況 rls.remove(rls.size()-1); } } } }
LC48:旋轉圖像

class Solution { public void rotate(int[][] matrix) { int n = matrix.length; // 水平翻轉 for (int i = 0; i < n / 2; ++i) { for (int j = 0; j < n; ++j) { int temp = matrix[i][j]; matrix[i][j] = matrix[n - i - 1][j]; matrix[n - i - 1][j] = temp; } } // 主對角線翻轉 for (int i = 0; i < n; ++i) { for (int j = 0; j < i; ++j) { int temp = matrix[i][j]; matrix[i][j] = matrix[j][i]; matrix[j][i] = temp; } } } }
LC49:字母異位詞分組


class Solution { public List<List<String>> groupAnagrams(String[] strs) { Map<String, ArrayList<String>> map = new HashMap<>(); for (int i = 0; i < strs.length ; i++) { //toCharArray將字符轉換為字符數組 char[] chars = strs[i].toCharArray(); //這里將char都變成了有序的,如“aet” Arrays.sort(chars); //String.valueOf(char[] data):將char數組data轉換成字符串 //通過有序的字母尋找 String key = String.valueOf(chars); if (!map.containsKey(key)) { //沒有key則加一個 map.put(key, new ArrayList<>()); } //根據對應key放入string map.get(key).add(strs[i]); } return new ArrayList<>(map.values()); } }
LC53:最大子序和

動態規划
class Solution { public int maxSubArray(int[] nums) { int pre = 0, maxAns = nums[0]; for (int x : nums) { pre = Math.max(pre + x, x); maxAns = Math.max(maxAns, pre); } return maxAns; } }
LC55: 跳躍游戲

貪心算法
class Solution { public boolean canJump(int[] nums) { //如果某一個作為起跳點的格子可以跳躍的距離是 3,那么表示后面 3 個格子都可以作為起跳點 //可以對每一個能作為起跳點的格子都嘗試跳一次,把能跳到最遠的距離不斷更新 //如果可以一直跳到最后,就成功了 int n = nums.length; int k = 0; if(nums.length == 1) return true; else if(nums[0] == 0) return false; for (int i = 0; i < n; i++) { //當前的距離比最遠能跳到的距離大則無法成功 if (i > k) return false; k = Math.max(k, i + nums[i]); } return true; } }
LC56:合並區間

import java.util.Arrays; public class LC_56 { public int[][] merge(int[][] intervals) { //先按照區間起始位置排序 //假設傳來兩個值,v1 與 v2,那么他們的先后順序以 v1[0] 比 v2[0] 的結果為准,即:若 v1[0] < v2[0] 則 v1 < v2,若 = 則 =,若 > 則 > //即按照vn[0]升序排列 Arrays.sort(intervals, (v1, v2) -> v1[0] - v2[0]); int[][] res = new int[intervals.length][2]; int idx = -1; //遍歷區間 for (int[] interval: intervals) { //如果結果數組是空的,或者當前區間的起始位置 > 結果數組中最后區間的終止位置, //則不合並,直接將當前區間加入結果數組。 if (idx == -1 || interval[0] > res[idx][1]) { res[++idx] = interval; } else { //反之將當前區間合並至結果數組的最后區間 res[idx][1] = Math.max(res[idx][1], interval[1]); } } //Arrays的copyOf()方法傳回的數組是新的數組對象,改變傳回數組中的元素值,不會影響原來的數組 //copyOf()的第二個自變量指定要建立的新數組長度,如果新數組的長度超過原數組的長度,則保留數組默認值 //如: //int[] arr1 = {1, 2, 3, 4, 5}; //int[] arr2 = Arrays.copyOf(arr1, 10); //輸出arr2為: //1 2 3 4 5 0 0 0 0 0 return Arrays.copyOf(res, idx + 1); } public static void main(String[] args) { int[][] intervals = new int[][] {{1,3},{2,6},{8,10},{15,18}}; LC_56 lc = new LC_56(); //首先:定義一個date數組for循環這個數組 for (int[] data : lc.merge(intervals)) //直接用Arrays.toString(date)方法 System.out.println(Arrays.toString(data)); } }
LC62:不同路徑

public class LC_62 { public int uniquePaths(int m, int n) { //dp為到達該點的最多路徑數 int[][] dp = new int[m][n]; //最左邊一行和最上面一行的dp只能是1,因為只可能從上面或者左邊來 for (int i = 0; i < n; i++) dp[0][i] = 1; for (int i = 0; i < m; i++) dp[i][0] = 1; for (int i = 1; i < m; i++) { for (int j = 1; j < n; j++) { dp[i][j] = dp[i - 1][j] + dp[i][j - 1]; } } return dp[m - 1][n - 1]; } public static void main(String[] args) { LC_62 lc = new LC_62(); int m = 3, n = 7; System.out.print(lc.uniquePaths(m, n)); } }
更一下基礎知識:
哈希表:
哈希表里的Key不允許存放基本數據類型(char,boolean,byte,short,int,long,float,double)
HashSet只有Key,HashMap里存在Key --> Value的映射關系。
HashSet<String> set = new HashSet<>(); HashMap<Integer,String> map = new HashMap<>();
哈希表不管數據量多大,增刪改查時間復雜度都是O(1)。
當哈希表里存放入基礎數據類型時,內部按值傳遞,占用空間大小與數據本身有關;
當不是基礎類型時,內部按引用傳遞,內存占用是地址大小。
有序表:
Set、Map同理


有序表不管數據量多大,增刪改查時間復雜度都是O(logN)。
當有序表里存放入基礎數據類型時,內部按值傳遞,占用空間大小與數據本身有關;
當不是基礎類型時,必須提供比較器,內部按引用傳遞,內存占用是地址大小。

二叉樹的先、中、后序遍歷來由:(遞歸實現)

分別是由遞歸序每個數第一(第一次來到)、第二(遍歷完左樹)、第三次(遍歷完右樹)出現為統計打印的結果。


遍歷的非遞歸:
前序遍歷


后序遍歷:


中序遍歷:


特別的:寬度優先遍歷
先左再右
求得寬度
示例:
LC39:組合總和