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:组合总和