leetcode-java
2016-06-20
今天开始刷LeetCode,先从AC最高的做起来。因为不想放弃java,所以决定用java来完成这些题目。
今晚做了两天题目练练手12
Detail:
第一反应很简单啊,这是我的第一版代码
public class Solution {
public boolean isValidBST(TreeNode root) {
if (root == null) return true;
if (root.left == null && root.right == null) return true;
return validate(root, Integer.MIN_VALUE, Integer.MAX_VALUE);
}
public boolean validate(TreeNode root, int min, int max) {
if (root == null) return true;
if (root.val <= min || root.val >= max) return false;
return validate(root.left, min, root.val) && validate(root.right, root.val, max);
}
}
可是就是跑不通测试,怎么看都不应该错啊。想了好久,又看了网上的讲解。原来不仅要看一个节点跟它的左右子树进行比较,还要看它的儿子和它的父亲之间的关系。
一个很好的方法就是中序遍历,把一棵树按照左根右的方式去排列,然后检查一遍是否合格,不过需要花费额外的空间。
网上看的一个不需要额外空间的优化解法,把代码列上来吧
public class Solution {
// Keep the previous value in inorder traversal.
TreeNode pre = null;
public boolean isValidBST(TreeNode root) {
// Traverse the tree in inorder.
if (root != null) {
// Inorder traversal: left first.
if (!isValidBST(root.left)) return false;
// Compare it with the previous value in inorder traversal.
if (pre != null && root.val <= pre.val) return false;
// Update the previous value.
pre = root;
// Inorder traversal: right last.
return isValidBST(root.right);
}
return true;
}
}
Detail:
Detail:
Detail:
Detail:
运算法则:
1. a ⊕ a = 0
2. a ⊕ 0 = a
3. a ⊕ b = b ⊕ a
4. a ⊕b ⊕ c = a ⊕ (b ⊕ c) = (a ⊕ b) ⊕ c;
5. d = a ⊕ b ⊕ c 可以推出 a = d ⊕ b ⊕ c.
6. a ⊕ b ⊕ a = b.
Detail:
逆波兰表示法(Reverse Polish notation,RPN,或逆波兰记法),是一种是由波兰数学家扬·武卡谢维奇1920年引入的数学表达式方式,在逆波兰记法中,所有操作符置于操作数的后面,因此也被称为后缀表示法。逆波兰记法不需要括号来标识操作符的优先级。
Detail:
Detail:
Detail:
Detail:
Detail:
Detail:
一般人的第一反应就是按照上面的思路呗,可是题目给了要求
Solve it without division and in O(n)
不能用除法之后,只能用乘法操作,那么怎么样利用之前的结果,而不需要每次都做重复的乘法操作呢。
不多说了,直接看代码
for (int i = 1; i < nums.length; i++) {
res[i] = res[i-1] * nums[i-1];
}
第一次遍历,让数组中所有的数res[i] = res[0] res[1] … * res[i-1],等于它左边所有的数的乘积。但是题目的要求是除了自身所有的数,也就是所有左边的和所有右边的都要乘起来。
这时候我们就需要第二次遍历了
for (int i = nums.length - 1; i > 0; i--) {
res[i] = res[i] * res[0];
res[0] = res[0] * nums[i];
}
这里用了一个很巧妙的技巧,就是不断地让第一个数变大,而且是从右往左乘,这样res[i]需要再乘以 res[len-1], res[len-2], …, res[i+1],而res[0]就是在这个循环中不断地从右往左乘。
Detail:
没办法,我只能去看答案,原来真的简单,根本用不到hashmap,因为总共就只有26个英文字符,所以一个26长的数组就能完全覆盖了。
for (char c : s.toCharArray()) {
count[c - 'a']++;
}
for (char c : t.toCharArray()) {
count[c - 'a']--;
if (count[c - 'a'] < 0) return false;
}
两个循环,也是用ascii的值去计算字符在数组中的位置。
第二遍如果发现有小于0的,说明t中肯定有多的字符,那么就不是valid anagram啦。不过当然第一步还是要判断两个字符串的长度是否相同。
Detail:
Detail:
description:
这个题和#136有点相似,但是是有两个数不是为双的。
Detail:
最简单的方法是对数组进行排序,O(NlogN)的时间,然后从后往前遍历,找到最大的一个h。
如果仔细考虑h的特征可以发现,如果数组的长度为n
,那么h大于n肯定不行,因为这将意味着有大于n个数大于等于h,所以对大于n的数可以一视同仁了。这样我们只需要考虑所有小于等于n的数
和一个大于等于n的数
。
代码如下
public class Solution {
public int hIndex(int[] citations) {
if (citations == null || citations.length == 0) {
return 0;
}
int length = citations.length;
int h = 0;
int[] array = new int[length + 1];
// 考虑所有小于等于n的数`和`一个大于等于n的数
for (int i : citations) {
if (i > length) array[length] += 1;
else array[i] += 1;
}
// 从后向前遍历,找到最大的一个符合条件的数
for (int i = length; i >= 0; i--) {
h = h + array[i];
if (h >= i) return i;
}
return 0;
}
}
Detail:
Detail:
Detail:
判断两个单词是否有相同字母,只需要将上面的两个数做与操作,判断是否为0即可,values[i] & values[j]) == 0
。
Detail:
然后hint还提示了可以分组计算,[1, 2], [2, 3], [4, 7], [8, 16],我没想太多,不过应该还是有可以重复利用的部分。
countingBit(n) = countingBit(n + 1) - 1
Detail:
description:
把一个数拆分开,求最大的成绩,用几个简单的例子就可以发现,拆出来的数要么是2,要么是3,所以我的方法还算比较简单,列一下代码,
需要注意的是一个数不能是它自己,如2必须要拆成1*1,所以这里简单注意一下就OK
public class Solution {
public static int integerBreak(int n) {
return integerBreak(n, true);
}
public static int integerBreak(int n, boolean isFirst) {
if (n < 4)
{
if (isFirst)
return n-1 > 0 ? n-1 : 1;
else
return n > 0 ? n : 1;
}
if (n % 3 == 1)
return 4 * integerBreak(n - 4, false);
return 3 * integerBreak(n - 3, false);
}
}
看了下答案,用的dp算法,状态和状态转移方程这里就不一一描述了,但我觉得这样的效率会比较低。
Detail:
Detail:
Detail:
description:
我用的笨方法。
Detail:
Detail:
动态规划
找规律
Let f(k) = count of numbers with unique digits with length equals k.