leetcode 684.354,133,207,121,63,64,jz46,120,357
684 冗余连接
不得不说并查集真的是一种很巧妙的思维了。。。
int[] visit; public int[] findRedundantConnection(int[][] edges) { visit = new int[edges.length+1]; for (int i = 0; i < visit.length; i++) { visit[i] = i; } for (int i = 0; i < edges.length; i++) { if (!connectd(edges[i][0],edges[i][1])){ union(edges[i][0],edges[i][1]); }else { return edges[i]; } } return null; } public void union(int p,int q){ int s = visit[p],t = visit[q]; if (s != t){ for (int i = 0; i < visit.length; i++) { if (visit[i] == s){ visit[i] = t; } } } } public boolean connectd(int p,int q){ return visit[p] == visit[q]; }
然后由于union的复杂度是On,这儿还可以进行优化,quik union。具体的就是相当的亲戚只保留一个根节点 即p = visit[p],其他的都指向自己的父节点即可
public void union(int p,int q){ int proot = find(p); int qroot = find(q); if (proot == qroot){ return; } visit[proot] = qroot; } public int find(int p){ while (p != visit[p]){ p = visit[p]; } return p; } public boolean connectd(int p,int q){ return find(p) == find(q); }
然后这儿如果整个列表都是亲戚,而且顺序极端的情况下会形成一个链表。所以还能继续优化 具体的优化可以查看这边博客 传送门→https://www.cnblogs.com/ggnbnb/p/12586205.html
354 俄罗斯套娃的问题 记住相等是不行的
其实就是个最长递增子序列的问题,这题还有个贪心+二分的解法。。有兴趣的可以去了解下
public int maxEnvelopes(int[][] envelopes) { Arrays.sort(envelopes, new Comparator<int[]>() { @Override public int compare(int[] o1, int[] o2) { return o1[1]-o2[1]; } }); int[] dp = new int[envelopes.length]; dp[0] = 1; int max = 1; for (int i = 1; i < envelopes.length; i++) { dp[i] = 1; int[] cu = envelopes[i]; for (int j = 0; j < i; j++) { if (cu[0]>envelopes[j][0] && cu[1]>envelopes[j][1]){ dp[i] = Math.max(dp[i],dp[j]+1); } } max = Math.max(max,dp[i]); } return max; }
133 克隆图
这题我做的和官解一样。。但不知道为何打败人数很少。。
Map<Integer,Node> nodeMap; public Node cloneGraph(Node node) { if (node == null){ return null; } nodeMap = new HashMap<>(); return dfs(node); } public Node dfs(Node node){ Node cu = new Node(node.val); nodeMap.put(node.val,cu); List<Node> cns = cu.neighbors; List<Node> ns = node.neighbors; for (Node n : ns) { if (nodeMap.containsKey(n.val)){ cns.add(nodeMap.get(n.val)); }else { cns.add(dfs(n)); } } return cu; } static class Node { public int val; public List<Node> neighbors; public Node() { val = 0; neighbors = new ArrayList<Node>(); } public Node(int _val) { val = _val; neighbors = new ArrayList<Node>(); } public Node(int _val, ArrayList<Node> _neighbors) { val = _val; neighbors = _neighbors; } }
207 这是之前做过的一个题,当时用的dfs,现在才知道还可以用拓扑排序
public static boolean canFinish(int numCourses, int[][] prerequisites) { Map<Integer, List<Integer>> map = new HashMap<>(); int[] arr = new int[numCourses]; for (int[] ar : prerequisites) { int x1 =ar[0],x2 = ar[1]; arr[x2]+=1; List<Integer> forws = map.get(x1); if (forws == null){ forws = new ArrayList<>(); map.put(x1,forws); } forws.add(ar[1]); } //计算入度 while (!map.isEmpty()){ int size = map.size(); Set<Integer> set = map.keySet(); Iterator<Integer> iterator = set.iterator(); boolean circle = true; while (iterator.hasNext()){ Integer value = iterator.next(); if (arr[value] == 0){ circle = false; List<Integer> childs = map.get(value); for (Integer child : childs) { if (arr[child]>0){ arr[child]--; } } iterator.remove(); } } if (circle){ return false; } } return true; }
53 最大子序和
public static int maxSubArray(int[] nums) { if (nums.length <1){ return 0; } int pre = nums[0]; int max = pre; for (int i = 1; i < nums.length; i++) { pre = Math.max(nums[i],pre+nums[i]); max = Math.max(pre,max); } return max; }
70 爬楼梯 一次一步 或者两步 N步一共有多少种方法
public static int climbStairs(int n) { if (n <= 3){ return n; } int[] dp = new int[n+1]; dp[1] = 1;dp[2] = 2;dp[3] = 3; for (int i = 4; i <=n ; i++) { dp[i] = dp[i-2]+dp[i-1]; } return dp[n]; }
121 买卖股票的最佳时机
public static int maxProfit(int[] prices) { int k = prices[0]; int max = 0; for (int i = 1; i < prices.length; i++) { int c = prices[i]; if (c > k){ max = Math.max(max, c- k); }else { k = c; } } return max; }
63 不同路径
public static int uniquePathsWithObstacles(int[][] obstacleGrid) { if (obstacleGrid[0][0] == 1){ return 0; } int m = obstacleGrid.length,n = obstacleGrid[0].length; int[][] dp = new int[m][n]; boolean t1 = true,t2 = true; for (int i = 0; i < m; i++) { if (obstacleGrid[i][0] == 1){ t1 = false; } if (t1){ dp[i][0] = 1 ; } if (i == 0){ for (int j = 1; j < n; j++) { if (obstacleGrid[0][j] == 1){ t2 = false; } if (t2){ dp[0][j] = 1; } } } } for (int i = 1; i < m; i++) { for (int j = 1; j < n; j++) { if (obstacleGrid[i][j] != 1){ dp[i][j] = dp[i-1][j]+dp[i][j-1]; } } } return dp[m-1][n-1]; }
64 最小路径和
public static int minPathSum(int[][] grid) { int m = grid.length,n = grid[0].length; int[][] dp = new int[m][n]; boolean t1 = true,t2 = true; dp[0][0] = grid[0][0]; for (int i = 1; i < m; i++) { dp[i][0] = dp[i-1][0]+grid[i][0]; } for (int i = 1; i < n; i++) { dp[0][i] = dp[0][i-1]+grid[0][i]; } for (int i = 1; i < m; i++) { for (int j = 1; j < n; j++) { dp[i][j] = Math.min(dp[i-1][j],dp[i][j-1])+grid[i][j]; } } return dp[m-1][n-1]; }
数字翻译成字符串
思路是如果当前字符和前一个字符可以组成一个有效数字,那么出现的情况就等于前一个加上前前一个字符的情况。否则就等于前一个字符的情况
public static int translateNum(int num) { String value = String.valueOf(num); int[] dp = new int[value.length()]; dp[0] = 1; if (value.length()<=1){ return dp[0]; } int pre = value.charAt(0)-48; dp[1] = pre*10+value.charAt(1)-48 >25?1:2; if (value.length()<=2){ return dp[1]; } pre = dp[1]; for (int i = 2; i < value.length(); i++) { if (pre == 0 || pre*10+value.charAt(i)-48 > 25){ dp[i] = dp[i-1]; }else { dp[i] = dp[i-1]+dp[i-2]; } pre = value.charAt(i)-48; } return dp[value.length()-1]; }
120 三角形的最小路径和
public static int minimumTotal1(List<List<Integer>> triangle) { if (triangle.size() == 1){ return triangle.get(0).get(0); } int[][] dp = new int[triangle.size()][triangle.size()]; dp[0][0] = triangle.get(0).get(0); int min = Integer.MAX_VALUE; for (int i = 1; i < triangle.size(); i++) { List<Integer> integers = triangle.get(i); for (int j = 0; j < integers.size(); j++) { if (j == 0){ dp[i][j] = dp[i-1][j] +integers.get(j); }else if (j == integers.size()-1){ dp[i][j] = dp[i-1][j-1] +integers.get(j); } else { dp[i][j] = Math.min(dp[i-1][j],dp[i-1][j-1])+integers.get(j); } if (i == triangle.size()-1){ min = Math.min(min,dp[i][j]); } } } return min; }
357 计算各个位数不同的数的数字个数
解析直接看如下,摘自题解,就是一个组合的知识吧
public static int countNumbersWithUniqueDigits(int n) { int[] dp = new int[n+1]; dp[0] = 0; if (n == 0 ){ return dp[0]; } dp[1] = 10; if (n == 1){ return dp[1]; } dp[2] = 91; if (n == 2){ return dp[2]; } int s = 81; for (int i = 3; i <= n; i++) { s *= 11-i; dp[i] = dp[i-1]+s; } return dp[n]; }