461.汉明距离
两个整数之间的汉明距离指的是这两个数字对应二进制位不同的位置的数目。给出两个整数 x 和 y,计算它们之间的汉明距离。
注意:0 ≤ x, y < 231.
示例:输入: x = 1, y = 4 输出: 2
解释:
1 (0 0 0 1)
4 (0 1 0 0)
↑ ↑
上面的箭头指出了对应二进制位不同的位置。
1 class Solution { 2 public int hammingDistance(int x, int y) { 3 int count = 0; 4 int i = x^y; 5 while(i != 0){ 6 if((i & 1) == 1){ 7 count++; 8 } 9 i = i >> 1; 10 } 11 return count; 12 } 13 }
494.目标和
给定一个非负整数数组,a1, a2, ..., an, 和一个目标数S。现在你有两个符号 + 和 -。对于数组中的任意一个整数,你都可以从 + 或 -中选择一个符号添加在前面。返回可以使最终数组和为目标数 S 的所有添加符号的方法数。
示例 1:
输入: nums: [1, 1, 1, 1, 1], S: 3
输出: 5
解释:
-1+1+1+1+1 = 3
+1-1+1+1+1 = 3
+1+1-1+1+1 = 3
+1+1+1-1+1 = 3
+1+1+1+1-1 = 3
一共有5种方法让最终目标和为3。
注意:数组非空,且长度不会超过20。初始的数组的和不会超过1000。保证返回的最终结果能被32位整数存下。
分析:数组中元素非负即正,因此可以分为正负两个子集。
即问题变成找到数组子集和为sum(P)的种数。
1 class Solution { 2 public int findTargetSumWays(int[] nums, int S) { 3 // sum(P) = ( sum + S ) / 2; 4 int sum = 0; 5 for(int num : nums){ 6 sum+=num; 7 } 8 //如果数组总和还小于S或者sum(P)不能为整数 9 if(sum<S||(sum+S)%2==1){ 10 return 0; 11 } 12 int sumP = (sum+S)/2; 13 //创建dp数组,表示组合为i的种类数,dp[i] += dp[i-num]。 14 int[] dp = new int[sumP+1]; 15 dp[0] = 1; 16 for(int num : nums){ 17 for(int i=sumP;i>=num;i--){ 18 dp[i] += dp[i-num];//原来的种类加上和为除去num的种类 19 } 20 } 21 return dp[sumP]; 22 } 23 }
538.把二叉搜索树转换为累加树
给定一个二叉搜索树(Binary Search Tree),把它转换成为累加树(Greater Tree),使得每个节点的值是原来的节点值加上所有大于它的节点值之和。
例如:输入: 二叉搜索树:
5
/ \
2 13
输出: 转换为累加树:
18
/ \
20 13
分析:这玩意要从右下角开始分析,右下角是最大值,定义一个最大值,初始是0,然后按照反前序遍历改变值(右-》中-》左)
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 private int max=0; 12 public TreeNode convertBST(TreeNode root) { 13 int max = 0; 14 helper(root); 15 return root; 16 } 17 public void helper(TreeNode root){ 18 if(root == null) return; 19 helper(root.right); 20 max += root.val; 21 root.val = max; 22 helper(root.left); 23 } 24 }
543.二叉树的直径
给定一棵二叉树,你需要计算它的直径长度。一棵二叉树的直径长度是任意两个结点路径长度中的最大值。这条路径可能穿过根结点。
示例 :给定二叉树
1
/ \
2 3
/ \
4 5
返回 3, 它的长度是路径 [4,2,1,3] 或者 [5,2,1,3]。
注意:两结点之间的路径长度是以它们之间边的数目表示。
分析:递归求每个节点的最长左右两条路径,取最大值并加一(加上当前节点)。
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 int res = 1; 12 public int diameterOfBinaryTree(TreeNode root) { 13 helper(root); 14 return res-1; 15 } 16 public int helper(TreeNode root){ 17 if(root==null) return 0; 18 int L = helper(root.left); 19 int R = helper(root.right); 20 res = Math.max(L+R+1,res); 21 return Math.max(L,R)+1; 22 } 23 }
560.和为K的子数组
给定一个整数数组和一个整数 k,你需要找到该数组中和为 k 的连续的子数组的个数。
示例 1 :输入:nums = [1,1,1], k = 2 输出: 2 , [1,1] 与 [1,1] 为两种不同的情况。
说明 :数组的长度为 [1, 20,000]。数组中元素的范围是 [-1000, 1000] ,且整数 k 的范围是 [-1e7, 1e7]。
分析:连续子数组而且数组元素会有正负值,可以采取这样的思路:
前缀和
P[i] = A[0] + A[1] + … + A[i-1]
P[j] = A[0] + A[1] + … + A[j-1]
那么P[j] – P[i] = A[i] + A[i+1] + … + A[j-1]。即长的减去短的
如果P[j] – P[i] == K的话,那么[i,j]就是符合条件的区间。所以对于每个j,只要计算有多少个i使得P[j] – P[i] == S,那么在遍历数组元素时,就需要一个数据结构来存储每次遍历0~i的数组和,这里可以使用数组或者哈希表,整数K范围[-1e7, 1e7]太大,这里使用哈希表。
1 class Solution { 2 public int subarraySum(int[] nums, int k) { 3 int res = 0, sum = 0; 4 Map<Integer,Integer> map = new HashMap(); 5 map.put(0,1); 6 for(int i=0;i<nums.length;i++){ 7 sum += nums[i]; 8 if(map.containsKey(sum-k)){//如果存在P[j] – P[i] == K 9 res += map.get(sum-k);//之前可能不止一个和为sum-k 10 } 11 map.put(sum, map.getOrDefault(sum,0)+1);//getOrDefault:如果不存在则置为0 12 } 13 return res; 14 } 15 }
581.最短无序连续子数组
给定一个整数数组,你需要寻找一个连续的子数组,如果对这个子数组进行升序排序,那么整个数组都会变为升序排序。你找到的子数组应是最短的,请输出它的长度。
示例 1:
输入: [2, 6, 4, 8, 10, 9, 15] 输出: 5
解释: 你只需要对 [6, 4, 8, 10, 9] 进行升序排序,那么整个表都会变为升序排序。
说明 :输入的数组长度范围在 [1, 10,000]。输入的数组可能包含重复元素 ,所以升序的意思是<=。
例如:1,3,5,4,2
暴力解决:先从左往右遍历找到第一个降序的元素之后的最小值min,例如上例中的2,从右往左找到第一个升序的元素之前的最大值max,例如上例中的5。然后再次从左往右遍历数组,如果出现元素大于min的例如3,则记录最左索引值left。再从右往左遍历,找到小于max的值例如2得索引right,返回right-left+1.
1 class Solution { 2 public int findUnsortedSubarray(int[] nums) { 3 int min=Integer.MAX_VALUE,max=Integer.MIN_VALUE,left=0,right=0; 4 boolean flag = false;//有无乱序 5 for(int i=0;i<nums.length-1;i++){ 6 if(nums[i]>nums[i+1]){ 7 flag = true; 8 } 9 if(flag){ 10 min = Math.min(min,nums[i+1]); 11 } 12 } 13 flag = false; 14 for(int j=nums.length-1;j>=1;j--){ 15 if(nums[j]<nums[j-1]){ 16 flag = true; 17 } 18 if(flag){ 19 max = Math.max(max,nums[j-1]); 20 } 21 } 22 for(int i=0;i<nums.length;i++){ 23 if(nums[i]>min){ 24 left = i; 25 break; 26 } 27 } 28 for(int j=nums.length-1;j>=0;j--){ 29 if(nums[j]<max){ 30 right = j; 31 break; 32 } 33 } 34 if(right == 0 && left ==0) return 0; 35 return right-left+1; 36 } 37 }
617.合并二叉树
给定两个二叉树,想象当你将它们中的一个覆盖到另一个上时,两个二叉树的一些节点便会重叠。你需要将他们合并为一个新的二叉树。合并的规则是如果两个节点重叠,那么将他们的值相加作为节点合并后的新值,否则不为 NULL 的节点将直接作为新二叉树的节点。
示例 1:
输入:
Tree 1 Tree 2
1 2
/ \ / \
3 2 1 3
/ \ \
5 4 7
输出:
合并后的树:
3
/ \
4 5
/ \ \
5 4 7
注意: 合并必须从两个树的根节点开始。
分析:同时遍历递归二叉树
1 /** 2 * Definition for a binary tree node. 3 * public class TreeNode { 4 * int val; 5 * TreeNode left; 6 * TreeNode right; 7 * TreeNode(int x) { val = x; } 8 * } 9 */ 10 class Solution { 11 public TreeNode mergeTrees(TreeNode t1, TreeNode t2) { 12 if(t1!=null || t2!=null){ 13 if(t1==null){ 14 return t2; 15 } 16 if(t2==null){ 17 return t1; 18 } 19 t1.val += t2.val; 20 t1.left = mergeTrees(t1.left,t2.left); 21 t1.right = mergeTrees(t1.right,t2.right); 22 } 23 return t1; 24 } 25 }
621.任务调度器
给定一个用字符数组表示的 CPU 需要执行的任务列表。其中包含使用大写的 A - Z 字母表示的26 种不同种类的任务。任务可以以任意顺序执行,并且每个任务都可以在 1 个单位时间内执行完。CPU 在任何一个单位时间内都可以执行一个任务,或者在待命状态。然而,两个相同种类的任务之间必须有长度为 n 的冷却时间,因此至少有连续 n 个单位时间内 CPU 在执行不同的任务,或者在待命状态。
你需要计算完成所有任务所需要的最短时间。
示例 1:输入: tasks = ["A","A","A","B","B","B"], n = 2 输出: 8
执行顺序: A -> B -> (待命) -> A -> B -> (待命) -> A -> B.
注:任务的总个数为 [1, 10000]。 n 的取值范围为 [0, 100]。
分析:通过分析我们可以得出现次数越多的任务应该越早安排,一轮任务定义为n+1时间,定义一个数组,值是每个任务种类的次数。在每一轮中都选取出现次数最多的任务执行,即数组值减一。
1 class Solution { 2 public int leastInterval(char[] tasks, int n) { 3 int[] times = new int[26]; 4 for(char c : tasks){ 5 times[c-‘A‘]++; 6 } 7 //将数组进行排序,末尾是出现次数最多的种类 8 Arrays.sort(times); 9 //在n+1一轮中选取出现次数最多的n+1任务执行 10 //如果times数组最后一个数组值是0,那么所有任务都执行完了 11 int res = 0; 12 while(times[25]>0){ 13 //将数组末尾n+1个元素值减一,如果已经是0了,那就不用操作,说明剩下的任务种类已经小于n+1 14 int i=0; 15 while(i<=n){ 16 if(times[25]==0) break;////如果末尾为0,即最后一轮没有全部填充,但是任务全部完成了,所以res不用再增加了,直接跳出即可。 17 if(i<26&×[25-i]>0){ 18 times[25-i]--; 19 } 20 res++;//每轮加n+1 21 i++; 22 } 23 //每次减完再重新排序,确保出现次数最多的在后面 24 Arrays.sort(times); 25 } 26 return res; 27 } 28 }
647.回文字串
给定一个字符串,你的任务是计算这个字符串中有多少个回文子串。具有不同开始位置或结束位置的子串,即使是由相同的字符组成,也会被计为是不同的子串。
示例 1:
输入: "abc"
输出: 3
解释: 三个回文子串: "a", "b", "c".
示例 2:
输入: "aaa"
输出: 6
说明: 6个回文子串: "a", "a", "a", "aa", "aa", "aaa".
注意:输入的字符串长度不会超过1000。
暴力解法:遍历数组每个字符,以此字符为中心左右寻找回文子串
1 class Solution { 2 public int countSubstrings(String s) { 3 int res = 0; 4 for(int i=0;i<s.length();i++){ 5 res+=helper(s,i,i); 6 res+=helper(s,i,i+1); 7 } 8 return res; 9 } 10 public int helper(String s, int left, int right){ 11 int count = 0; 12 while(left>=0 && right<s.length() && s.charAt(left)==s.charAt(right)){ 13 left--; 14 right++; 15 count++; 16 } 17 return count; 18 } 19 }
739.每日温度
根据每日 气温 列表,请重新生成一个列表,对应位置的输入是你需要再等待多久温度才会升高超过该日的天数。如果之后都不会升高,请在该位置用 0 来代替。
例如,给定一个列表 temperatures = [73, 74, 75, 71, 69, 72, 76, 73],你的输出应该是 [1, 1, 4, 2, 1, 1, 0, 0]。
提示:气温 列表长度的范围是 [1, 30000]。每个气温的值的均为华氏度,都是在 [30, 100] 范围内的整数。
暴力:遍历数组,然后再次遍历当前元素后面的值
栈:我们只关心当天之后第一个比当天温度高的天数。我们使用栈存储数组索引。使用逆序遍历,遍历到当天时已知后面几天温度。
1 class Solution { 2 public int[] dailyTemperatures(int[] T) { 3 int[] res = new int[T.length]; 4 Stack<Integer> stack = new Stack(); 5 for(int i=T.length-1;i>=0;i--){ 6 //当前元素比栈顶元素大(说明当天温度高,栈里元素即后面几天温度低于当天),那么记录最高值就好 出栈 重新调整栈,直至满足要求. 7 while(!stack.isEmpty()&&T[i]>=T[stack.peek()]){ 8 stack.pop(); 9 } 10 //如果栈为空,说明后面没有比当天温度高的 11 ////如果不为空,说明栈顶元素比当天温度高。那么用温度高的那天索引减去当天的索引 12 res[i] = stack.isEmpty()?0:stack.peek()-i; 13 stack.push(i); 14 } 15 return res; 16 } 17 }
原文:https://www.cnblogs.com/qmillet/p/12179618.html