leetcode题解
leetcode
Reverse String
原题目为leetcode 344,难度系数为easy.
将字符串反转
刚开始直接遍历字符串,存到新的字符串开头,提交会超时.String reverse="";
for (int i=0;i
reverse=s.charAt(i)+reverse;
}
将字符串变为数组,只遍历一半,chars[i]与chars[chars.length-i-1]值互换,通过String.valueOf(chars)还原为字符串,提交通过.public String reverseString(String s) {
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length/2; i++) {
char a=chars[chars.length-i-1];
chars[chars.length-i-1]=chars[i];
chars[i]=a;
}
return String.valueOf(chars);
}
discuss里面的一种好办法,二分加递归.public class Solution {
public String reverseString(String s) {
int length = s.length();
if (length <= 1){
return s;
}
String left = s.substring(0, length / 2);
String right = s.substring(length / 2, length);
return reverseString(right) + reverseString(left);
}
}
Nim Game
原题目为leetcode 292,难度系数为easy.
一堆物品,两人各拿1-3个,自己先拿.两人都最理性的,谁先拿完谁赢.输入个数,输出输赢
要发现每输一次,必定会赢三次的规律public class Solution {
public boolean canWinNim(int n) {
return n%4!=0;
}
}
Single Number
原题目为leetcode 136,难度系数为easy.
一个数组的整数,除了一个数外其他的都出现两次.找出这个数.
刚开始的想法是两个循环遍历数组,如果出现重复的将index装到list里面.然后循环开始时进行判断.public int singleNumber(int[] nums) {
ArrayList list=new ArrayList();
int k=0;
for (int i = 0; (i
int n=k;
if (list.contains(i)){
continue;
}
for (int j = i+1; j
if (nums[i]==nums[j]){
list.add(j);
k++;
break;
}
}
if (n==k){
return nums[i];
}
}
return nums[nums.length - 1];
简化后,直接使用一次遍历数组,如果数字出现,加入列表,重复出现,移除.public int singleNumber(int[] nums) {
ArrayList list=new ArrayList();
for (int i = 0; (i
if (list.contains(nums[i])){
list.remove(new Integer(nums[i]));
}
else{
list.add(nums[i]);
}
}
return list.get(0);
}
在discuss里面看到使用异或的办法.任意数与0异或等于本身,与本身异或得0.public int singleNumber(int[] nums) {
int c=0;
for(int i=0;i
{
c=c^nums[i];
}
return c;
}
Two Sum
原题目为leetcode 001,难度系数为easy.
给定一个数组的整数与一个目标数,目标数为数组中两个整数的和,刚好仅有一个解.返回两个整数的下标的数组.
外层循环到倒数第二个数,里层从外层的循环数后一位开始.public int[] twoSum(int[] nums, int target) {
for (int i = 0; i
for (int j = i+1; j
if (nums[i]+nums[j]==target){
return new int[]{i,j};
}
}
}
return new int[]{0,0};
}
Sum of Two Integers
原题目为leetcode 371,难度系数为easy.
不使用加减法得到两个数的和.
使用位运算.public int getSum(int a, int b) {
if (a == 0) return b;
if (b == 0) return a;
while (b != 0) {
int carry = a & b;
a = a ^ b;
b = carry << 1;
}
return a;
}
Maximum Depth of Binary Tree
原题目为leetcode 104,难度系数为easy.
得到二叉树的高度
使用左子树和右子树分别递归.public int maxDepth(TreeNode root) {
return root==null?0:Math.max(maxDepth(root.left),maxDepth(root.right))+1;
}
Find the Difference
原题目为leetcode 389,难度系数为easy.
两个由小写字母组成的字符串s和t.s由随机字母组成,t为s在随机的位置增加一个字母.找出这个字母
使用Single Num里面的思路,将s变换成列表,如果t中的字母在列表中存在,删除。不存在返回该字母。public char findTheDifference(String s, String t) {
ArrayList list = new ArrayList<>();
for (int i = 0; i < s.length(); i++) {
list.add(s.charAt(i));
}
for (int i = 0; i < t.length(); i++) {
if (list.contains(t.charAt(i))){
list.remove(new Character(t.charAt(i)));
}
else {
return t.charAt(i);
}
}
return list.get(0);
}
使用异或来完成比较,重点在于类型转换public char findTheDifference(String s, String t) {
int length = s.length();
char k=0;
for (int i = 0; i < length; i++) {
k ^= s.charAt(i) ^ t.charAt(i);
}
return (char) (k^t.charAt(length));
}
Add Digits
原题目为leetcode 258,难度系数为easy.
给定非负整数num,重复加每位上的数字,直到得到个位数。不使用循环或递归。
使用递归public int addDigits(int num) {
if (num/10==0){
return num;
}
int result=num%10+addDigits(num/10);
return addDigits(result);
}
使用循环,注意到所有位相加等于数的最后一位加上数关于10取余public int addDigits(int num) {
while (num>=10){
int a=num%10;
int b=num/10;
num=a+b;
}
return num;
}
注意到discuss里面最简单的方法,直接将数关于9取余,就能得到结果。9%9=0 1+(9-1)%9=9 0%9=0 1+(0-1)%9=0public int addDigits(int num) {
return 1+(num-1)%9;
}
Invert Binary Tree
原题目为leetcode 226,难度系数为easy.
将二叉树左右镜像反转
使用递归,如果左右子树不同时为空,对节点进行反转。public TreeNode invertTree(TreeNode root) {
if (root==null){
return null;
}
if ((root.left==null)&&(root.right==null)){
return root;
}
TreeNode tmp=root.left;
root.left=root.right;
root.right=tmp;
invertTree(root.left);
invertTree(root.right);
return root;
}
Move Zeroes
原题目为leetcode 283,难度系数为easy.
给定数组nums,写一个函数使数组里所有的0移动到最末端,其它元素相对位置不变
定义变量j=0,遍历数组,对于0元素,让下一个出现的非0元素赋值到其位置。再在数组最后补上0。本质上相当于赋值给一个新的数组,不过是在原数组上操作。public void moveZeroes(int[] nums) {
int j=0;
for (int i = 0; i
if (nums[i]!=0){
nums[j]=nums[i];
j++;
}
}
for (int i = j; i
nums[i]=0;
}
}
Sum of Left Leaves
原题目为leetcode 404,难度系数为easy.
找到给定的二叉树的所有左叶的值之和。
使用递归解决:左叶的特点是没有子节点,并且为父节点的左子节点。如果根节点为空,或者根节点没有子节点,那么左叶的值之和为0;根节点的左节点为左叶,左叶的值之和为它加上以右子节点为根的二叉树的左叶的值之和。以此递归迭代。public int sumOfLeftLeaves(TreeNode root) {
if (root==null){
return 0;
}
if (root.left==null && root.right==null){
return 0;
}
if (root.left!=null && root.left.left==null && root.left.right==null){
return root.left.val+sumOfLeftLeaves(root.right);
}
return sumOfLeftLeaves(root.left)+sumOfLeftLeaves(root.right);
}
discuss里面发现DFS solution Java,使用isLeft这个布尔值判断是否是一个左子节点,递归dfs函数,不断改变sum的值。如果是左子节点并且节点没有子节点,sum+= root.val。这种思路跟我最开始的思路不谋而合,但是当时想到sum变量不好定义,并且关于如何判断节点为左子节点没有思路。public int sum;
public int sumOfLeftLeaves(TreeNode root) {
sum = 0;
dfs(root,false);
return sum;
}
public void dfs(TreeNode root, boolean isLeft){
if(root==null) return;
if(isLeft&&root.left==null&&root.right==null){
sum += root.val;
}
dfs(root.left, true);
dfs(root.right, false);
}
Longest Palindrome
原题目为leetcode 409,难度系数为easy.
给定一个由大小写字母组成的字符串,返回由这些字母能组成的回文的最大长度,区分大小写。
初始思路:
1. 统计出现的字母以及出现的次数
2. 对于奇数个数的字母保留最大的那个奇数
3. 所有的偶数加上最大的奇数public int longestPalindrome(String s) {
int sum=0;
int ji=0;
HashMap map=new HashMap<>();
for (int i = 0; i
char c = s.charAt(i);
if (map.containsKey(c)){
map.put(c,map.get(c)+1);
}else {
map.put(c,1);
}
}
for (Object o : map.entrySet()) {
Map.Entry entry = (Map.Entry) o;
Object val = entry.getValue();
int a=(int)val;
if (a%2==1){
if (a>ji){
sum-=ji;
ji=a;
sum += ji;
}
}else sum+=a;
}
return sum;
}
一直提交出错,发现代码没有错,思路错了。不应该只保留最大的奇数,还需要将小的奇数-1再加进去。或许说是减去奇数的个数再加一(奇数不为0个)。用时33ms。public int longestPalindrome(String s) {
int sum=0;
int ji=0;
HashMap map=new HashMap<>();
for (int i = 0; i
char c = s.charAt(i);
if (map.containsKey(c)){
map.put(c,map.get(c)+1);
}else {
map.put(c,1);
}
}
for (Object o : map.entrySet()) {
Map.Entry entry = (Map.Entry) o;
Object val = entry.getValue();
int a=(int)val;
if (a%2==1){
ji++;
}
sum+=a;
}
return ji==0?sum:sum-ji+1;
}
可以发现最大回文数等于字符串长度减去奇数的字母的个数再加一(存在奇数个数字母)。需要注意list里面只能存Character类型,调用remove方法要注意类型。public int longestPalindrome(String s) {
int sum=0;
ArrayList list = new ArrayList<>();
for (int i = 0; i
char c = s.charAt(i);
if (list.contains(c)){
list.remove((Character)c);
}else {
list.add(c);
}
}
return list.size()==0?s.length():s.length()-list.size()+1;
}
Ransom Note
原题目为leetcode 383,难度系数为easy.
判断ransom note字符串能否由magazine字符串组成。magazine字符串的每个字母只能使用一次
将ransom note字符串转换为列表,遍历magazine字符串的每个字母,如果字母在列表中,删除之。最后判断列表是否为空public boolean canConstruct(String ransomNote, String magazine) {
int length1 = ransomNote.length();
int length2 = magazine.length();
if (length1>length2){
return false;
}
ArrayList list = new ArrayList<>();
for (int i = 0; i
list.add(ransomNote.charAt(i));
}
for (int i = 0; i
if (list.contains(magazine.charAt(i))){
list.remove((Character) magazine.charAt(i));
}
}
return list.size()==0;
}
disscuss里面看到一种利用ASCII码的方法。定义一个数组,26个字母可以分别代表0-25。将magazine字符串的每个字母对应的值遍历自加1,ransom note字符串遍历自减1。如果出现负数,返回false。public boolean canConstruct(String ransomNote, String magazine) {
int[] table=new int[26];
for (int i = 0; i
table[magazine.charAt(i)-'a']++;
}
for (int i = 0; i
if (--table[ransomNote.charAt(i)-'a']<0) return false;
}
return true;
}
发现将字符串转换为数组后foreach循环遍历,速度更快。public boolean canConstruct(String ransomNote, String magazine) {
int[] table=new int[26];
for (char s:magazine.toCharArray()) {
table[s-'a']++;
}
for (char s:ransomNote.toCharArray()) {
if(--table[s-'a']<0) return false;
}
return true;
}
Add Strings
原题目为leetcode 415,难度系数为easy.
两个表示为字符串的非负整数,输出它们的和(字符串)。不能直接将输入转换为integer 。
使用StringBuilder构建字符串,对于短的字符串补零。相加并进位。需要注意将Char转换为int减去'0'就行。注意最高位是不是1。public String addStrings(String num1, String num2) {
int carry=0;
StringBuilder sb1 = new StringBuilder(num1);
StringBuilder sb2 = new StringBuilder(num2);
StringBuilder sb3 = new StringBuilder();
sb1.reverse();
sb2.reverse();
int length=Math.max(sb1.length(),sb2.length());
while (sb1.length()
while (sb2.length()
for (int i = 0; i
int rs=(sb1.charAt(i)-'0')+(sb2.charAt(i)-'0')+carry;
carry=rs/10;
sb3.append(rs % 10);
}
if (carry==1) sb3.append(carry);
sb3.reverse();
return sb3.toString();
}
Delete Node in a Linked List
原题目为leetcode 237,难度系数为easy.
写一个函数删除单链表的给定节点
将要删除的节点变成其指向的节点,即其存储的值改变,指向改变为原先指向的节点所指向的节点。public void deleteNode(ListNode node) {
node.val=node.next.val;
node.next=node.next.next;
}
Intersection of Two Arrays
原题目为leetcode 349,难度系数为easy.
给定两个数组,找出交叉部分。返回的数组的每一个元素都要是唯一的,返回数组不要求排序。
大体思路是先都转换为列表,while循环删除list1的第一个值。如果list1的第一个值在list2中,加入list3。坑在于list3存放的是基本类型,无法直接转换为int数组。public int[] intersection(int[] nums1, int[] nums2) {
ArrayList list1 = new ArrayList();
ArrayList list2 = new ArrayList();
ArrayList list3 = new ArrayList();
for (int i:nums1) list1.add(i);
for (int i:nums2) list2.add(i);
while (list1.size()!=0){
int val=list1.get(0);
list1.remove((Integer) val);
if (list2.contains(val)&&!list3.contains(val)){
list3.add(val);
}
}
return toIntArray(list3);
}
private int[] toIntArray(List list){
int[] ret = new int[list.size()];
for(int i = 0;i < ret.length;i++)
ret[i] = list.get(i);
return ret;
}
Hashset中元素不重复,效率更高。public int[] intersection(int[] nums1, int[] nums2) {
HashSet set = new HashSet();
for (int i:nums1) set.add(i);
ArrayList list3 = new ArrayList();
for (int j:nums2) {
if (set.contains(j)){
set.remove(j);
list3.add(j);
}
}
int[] ret = new int[list3.size()];
for (int i = 0; i
ret[i]=list3.get(i);
}
return ret;
}
Same Tree
原题目为leetcode 100,难度系数为easy.
判断两个二叉树是否一样,即结构和值一样。
如果根节点都为空,一样。如果都不为空,判断节点是否一样。如果节点一样,再判断以左右节点为根节点的二叉树是否一样。public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) return true;
if (p != null && q != null) {
if (!isSameNode(p, q)) return false;
return isSameTree(p.right, q.right) && isSameTree(p.left, q.left);
}
return false;
}
private boolean isSameNode(TreeNode p, TreeNode q) {
if (p == null && q == null) return true;
if (p != null && q != null) {
return p.val == q.val;
}
return false;
}
简版:public boolean isSameTree(TreeNode p, TreeNode q) {
return p == null && q == null || p != null && q != null && isSameNode(p, q) && isSameTree(p.right, q.right) && isSameTree(p.left, q.left);
}
private boolean isSameNode(TreeNode p, TreeNode q) {
return p == null && q == null || p != null && q != null && p.val == q.val;
}
更简版:public boolean isSameTree(TreeNode p, TreeNode q) {
if (p == null && q == null) return true;
if (p != null && q != null) {
return p.val==q.val && isSameTree(p.right, q.right) && isSameTree(p.left, q.left);
}
return false;
}
一行版:public boolean isSameTree(TreeNode p, TreeNode q) {
return p == null && q == null || p != null && q != null && p.val == q.val && isSameTree(p.right, q.right) && isSameTree(p.left, q.left);
}
Excel Sheet Column Number
原题目为leetcode 171,难度系数为easy.
给定excel表的列名称,返回列数。A -> 1
B -> 2
C -> 3
...
Z -> 26
AA -> 27
AB -> 28
相当于每26个数进一位。public int titleToNumber(String s) {
int sum=0;
for (int i = 0; i
int num = s.charAt(i) - 'A' + 1;
sum=sum*26+num;
}
return sum;
}
Excel Sheet Column Title
原题目为leetcode 168,难度系数为easy.
给定excel表的列数,返回列名称
与171刚好相反,注意需要减一。public String convertToTitle(int n) {
StringBuilder sb = new StringBuilder();
while (n>0){
char last = (char) ('A' + (n-1) % 26);
sb.append(last);
n=(n-1)/26;
}
return sb.reverse().toString();
}
discuss里面有迭代的做法,非常nice。public String convertToTitle(int n) {
if (n == 0) {
return "";
}
int div, rem;
div = (n-1)/26;
rem = (n-1)%26;
return convertToTitle(div) + (char)('A'+rem);
}
First Unique Character in a String
原题目为leetcode 387,难度系数为easy.
给定字符串,返回第一个不重复的字母的索引,如果不存在,返回-1。字母都是小写。
使用LinkedHashMap来存储字母及其出现的次数。public int firstUniqChar(String s) {
LinkedHashMap map = new LinkedHashMap<>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (map.containsKey(c)) map.put(c,map.get(c)+1);
else map.put(c,1);
}
for (Map.Entry et:map.entrySet()) {
char key = (char) et.getKey();
int value = (int) et.getValue();
if (value==1){
return s.indexOf(key);
}
}
return -1;
}
看了discuss,又跪了。新建一个int[26]的数组,索引为字母i减去a,用来存储字母第一次出现的位置。public int firstUniqChar(String s) {
int[] ar = new int[26];
int val = s.length() + 1;
for (int i = 0; i < s.length(); i++) {
int c = s.charAt(i) - 'a';
if (ar[c] == 0) ar[c] = i + 1;
else ar[c] = val;
}
for (int i : ar) {
if (i > 0 && i < val) val = i;
}
return val == s.length() + 1 ? -1 : val-1;
}
然后又跪给更简单的使用一个数组的方法。用上一种方法的数组存储字母出现的次数。public int firstUniqChar(String s) {
int[] ar = new int[26];
for (int i = 0; i < s.length(); i++) {
ar[s.charAt(i) - 'a']++;
}
for (int i = 0; i < s.length(); i++) {
if (ar[s.charAt(i) - 'a']==1) return i;
}
return -1;
}
Valid Anagram
原题目为leetcode 242,难度系数为easy.
给定两个字符串s和t,判断t是不是s的回文构词。即s改变字母顺序能否得到t。s = "anagram", t = "nagaram", return true.
s = "rat", t = "car", return false.
由于之前的经验,第一时间想到异或。跪了,思路错掉了。如aa和bb的输入也会返回truepublic boolean isAnagram(String s, String t) {
int sum = 0;
for (Character i : s.toCharArray()) sum ^= (int)i;
for (Character i : t.toCharArray()) sum ^= (int)i;
return sum == 0;
}
返回老路子,s转换为列表,遍历t,如果列表不包含t中字母,返回falsepublic boolean isAnagram(String s, String t) {
if (s.length()!=t.length()) return false;
char[] chars = s.toCharArray();
ArrayList list = new ArrayList<>();
for (Character i:chars) {
list.add(i);
}
for (int j=0;j
char c = t.charAt(j);
if (list.contains(c)) list.remove((Character) c);
else return false;
}
return true;
}
依旧在discuss里面看到了int[26]的办法,简直天才。public boolean isAnagram(String s, String t) {
int[] ab = new int[26];
for (int i = 0; i < s.length(); i++) ab[s.charAt(i)-'a']++;
for (int i = 0; i < t.length(); i++) ab[t.charAt(i)-'a']--;
for (int val:ab) if (val!=0) return false;
return true;
}
思路很简单的将两个数组排序比较public boolean isAnagram(String s, String t) {
if (s.length()!=t.length()) return false;
char[] sc = s.toCharArray();
char[] tc = t.toCharArray();
Arrays.sort(sc);
Arrays.sort(tc);
for (int i = 0; i
if (sc[i]!=tc[i]) return false;
}
return true;
}
Majority Element
原题目为leetcode 169,难度系数为easy.
给定长度为n的数组,找出主元素。主元素是出现了多于n/2次的元素。假设数组非空且主元素一直存在。
利用HashMap数数。思路很直,但是时间开销很大。public int majorityElement(int[] nums) {
HashMap map = new HashMap<>();
for (int item:nums) {
if (map.containsKey(item)){
map.put(item, map.get(item)+1);
}else {
map.put(item, 1);
}
if (map.get(item)>nums.length/2) return item;
}
return 0;
}
由于题目的限定,可以直接排序输出中间的数。public int majorityElement(int[] nums) {
Arrays.sort(nums);
return nums[nums.length/2];
}
另外一种很好的解法。我的理解是将元素看成主元素和非主元素,主元素个数大于n/2public int majorityElement(int[] nums) {
if (nums == null || nums.length == 0) return 0;
int cnt = 0;
int candidate = 0;
for(int i = 0; i < nums.length; i++) {
if (cnt == 0) {
candidate = nums[i];
cnt = 1;
} else if (nums[i] == candidate) {
cnt++;
} else {
cnt--;
}
}
return candidate;
}
Contains Duplicate
原题目为leetcode 217,难度系数为easy.
判断整数数组里面是否有数重复
利用set添加,最后通过长度判断。也可以在添加的过程中判断元素是否存在于set。public boolean containsDuplicate(int[] nums) {
HashSet set = new HashSet<>();
for (int num:nums) {
set.add(num);
}
return nums.length!=set.size();
}
Intersection of Two Arrays II
原题目为leetcode 350,难度系数为easy.
求两个数组的交集。不剔除重复的元素。
利用Arraylist增减元素。public int[] intersect(int[] nums1, int[] nums2) {
ArrayList list1 = new ArrayList<>();
ArrayList list2 = new ArrayList<>();
ArrayList list3 = new ArrayList<>();
for (int i:nums1) {
list1.add(i);
}
for (int i:nums2) {
list2.add(i);
}
System.out.println(list2);
for (int item:list1) {
if (list2.contains(item)){
list2.remove((Integer) item);
list3.add(item);
}
}
int[] ret=new int[list3.size()];
for (int i = 0; i
ret[i]=list3.get(i);
}
return ret;
}
Reverse Linked List
原题目为leetcode 206,难度系数为easy.
将一个单向链表反序。
循环的办法。将前一个节点和下一个节点互换。public ListNode reverseList(ListNode head) {
ListNode cur=head;
ListNode pre=null;
while (cur!=null){
ListNode tmp=cur.next;
cur.next=pre;
pre=cur;
cur=tmp;
}
return pre;
}
迭代的方法。将头节点的下一个节点为头节点的链表反序。头节点的下一个节点的指向改为头节点,头节点的指向改为null。public ListNode reverseList(ListNode head) {
if (head==null||head.next==null) return head;
ListNode p=reverseList(head.next);
head.next.next=head;
head.next=null;
return p;
}
Fizz Buzz
原题目为leetcode 412,难度系数为easy.
if条件判断,思路也很直。public List fizzBuzz(int n) {
ArrayList list=new ArrayList();
for(int i=1;i<=n;i++){
if(i%3==0){
if(i%5==0) list.add("FizzBuzz");
else list.add("Fizz");
}else if(i%5==0) list.add("Buzz");
else list.add(String.valueOf(i));
}
return list;
}
Roman to Integer
原题目为leetcode 412,难度系数为easy.
将罗马数字的输入转换为整数。
最重要的是想办法解决小字母在大字母左边表示减的问题。使用一个变量level表示之前的字母表示的整数,currentl表示当前字母代表的整数。count变量表示字符连续出现的次数。如果level变小,表示之前的字母可以直接加。如果level变大,表示需要减去之前的字母代表的数。public int romanToInt(String s) {
int sum=0;
HashMap map = new HashMap(){
{
put('M',1000);put('D', 500);put('C', 100);put('L', 50);put('X', 10);put('V', 5);put('I', 1);
}
};
int level=1000;
int count=0;
for (int i = 0; i < s.length(); i++) {
char c=s.charAt(i);
int currentl=map.get(c);
if (currentl==level) {
count++;
if (i==s.length()-1) sum+=level*count;
}else if (currentl
sum+=level*count;
count=1;
level=currentl;
if (i==s.length()-1) sum+=level;
}else {
sum+=(currentl-level*count);
count=0;
level=currentl;
}
}
return sum;
}
之后发现大的字母前面最多出现一次小的字母。代码简化。public int romanToInt(String s) {
int sum=0;
HashMap map = new HashMap(){
{
put('M',1000);put('D', 500);put('C', 100);put('L', 50);put('X', 10);put('V', 5);put('I', 1);
}
};
int level=1000;
for (int i = 0; i < s.length(); i++) {
char c=s.charAt(i);
int currentl=map.get(c);
if (currentl>level) sum+=(currentl-level*2);
else sum+=currentl;
level=currentl;
}
return sum;
}
看到非常厉害的方法,直接简单粗暴的检测。public int romanToInt(String s) {
int sum=0;
if(s.indexOf("IV")!=-1){sum-=2;}
if(s.indexOf("IX")!=-1){sum-=2;}
if(s.indexOf("XL")!=-1){sum-=20;}
if(s.indexOf("XC")!=-1){sum-=20;}
if(s.indexOf("CD")!=-1){sum-=200;}
if(s.indexOf("CM")!=-1){sum-=200;}
char c[]=s.toCharArray();
int count=0;
for(;count<=s.length()-1;count++){
if(c[count]=='M') sum+=1000;
if(c[count]=='D') sum+=500;
if(c[count]=='C') sum+=100;
if(c[count]=='L') sum+=50;
if(c[count]=='X') sum+=10;
if(c[count]=='V') sum+=5;
if(c[count]=='I') sum+=1;
}
return sum;
}
Power of Three
原题目为leetcode 326,难度系数为easy.
判断一个整数是否是3的幂次。最好不使用循环或者迭代。
使用迭代的办法:public boolean isPowerOfThree(int n) {
if (n<=0) return false;
if (n==1) return true;
if (n%3!=0) return false;
return isPowerOfThree(n/3);
}
使用循环的办法:public boolean isPowerOfThree(int n) {
while (true) {
if(n<=0) return false;
if (n==1) return true;
if (n%3!=0) return false;
n=n/3;
}
}
discuss里面看到的最聪明的解法。直接关于三的十九次幂取余。因为int类型有长度限制。public boolean isPowerOfThree(int n) {
// 1162261467 is 3^19, 3^20 is bigger than int
return ( n>0 && 1162261467%n==0);
}
使用log函数取对数。判断结果是不是整数。public boolean isPowerOfThree(int n) {
if(n<=0) return false;
double a = Math.log10(n)/Math.log10(3); //log power and base 3
return (a-Math.floor(a))==0; //check after the decimal point.
}
Power of Two
原题目为leetcode 231,难度系数为easy.
看一个整数是不是2的幂次。public boolean isPowerOfTwo(int n) {
if (n==1) return true;
if (n<=0 || n%2!=0) return false;
return isPowerOfTwo(n/2);
}
三种一行的方法://solution 1:
public boolean isPowerOfTwo(int n) {
final double epsilon = 1.e-10;
return (Math.log(n) / Math.log(2) + epsilon) % 1 <= 2 * epsilon;
}
//solution 2:
public boolean isPowerOfTwo(int n) {
return n > 0 && 1073741824 % n == 0;
}
//solution 3:
public boolean isPowerOfTwo(int n) {
return n>0 && Integer.toBinaryString(n).matches("^10*$");
}
Happy Number
原题目为leetcode 202,难度系数为easy.
判断一个整数是否为快乐数。即该数字所有数位(digits)的平方和,得到的新数再次求所有数位的平方和,如此重复进行,最终结果必为1。
难点在于判断不是快乐数,可能会陷入死循环。利用HashSet存放每个判断过的数,如果重复出现,判断false。public boolean isHappy(int n) {
if (n<=0) return false;
HashSet set = new HashSet<>();
while (true){
if (n==1) return true;
if (set.contains(n)) return false;
set.add(n);
int sum=0;
while (n>0){
sum+=(n%10)*(n%10);
n/=10;
}
n=sum;
}
}
Remove Duplicates from Sorted List ##
原题目为leetcode 83,难度系数为easy.
将排好序的单链表的重复元素删除。
Given 1->1->2, return 1->2.
Given 1->1->2->3->3, return 1->2->3.
使用迭代的方法。需要注意传进去的为null需要特殊处理。通过while循环让头元素的指向为与其值不同的下一个元素。public ListNode deleteDuplicates(ListNode head) {
if (head==null||head.next==null) return head;
while (head.next!=null&&head.val==head.next.val){
head.next=head.next.next;
}
head.next=deleteDuplicates(head.next);
return head;
}
Best Time to Buy and Sell Stock
原题目为leetcode 121,难度系数为easy.
数组中每个元素代表当天的股价。只能完成一次交易,即买一次卖一次。必须先买后卖,求最大收益。(可以不做交易)
求出遍历过程中的最小值。每增加一天,新一天股价减去之前最小值成为可能的最大收益。与之前的最大收益比较。public int maxProfit(int[] prices) {
int max=0;
int min=Integer.MAX_VALUE;
for (int price:prices) {
min=Math.min(min,price);
max=Math.max(max,price-min);
}
return max;
}
Climbing Stairs
原题目为leetcode 70,难度系数为easy.
需要爬n个台阶到顶部,每次可以爬一个或者两个台阶。有多少种方法爬楼梯。
感觉上更像一个数学问题。迈最后一步的时候有一个台阶和两个台阶两种情况。可以推出走n个台阶的方法数为走n-1个台阶的方法数加上走n-2个台阶的方法数。使用迭代,遗憾超时。public int climbStairs(int n) {
if (n<=0) return 0;
if (n==1) return 1;
if (n==2) return 2;
return climbStairs(n-1)+climbStairs(n-2);
}
利用数组将每一步计算的结果存下来。public int climbStairs(int n) {
if (n<=0) return 0;
if (n==1) return 1;
if (n==2) return 2;
int[] ints = new int[n];
ints[0]=1;
ints[1]=2;
for (int i = 2; i
ints[i]=ints[i-1]+ints[i-2];
}
return ints[n-1];
}
Ugly Number
原题目为leetcode 263,难度系数为easy.
判断一个数是不是ugly number。ugly number表示质因子只有2, 3, 5的正整数。1也是。
使用迭代的方法public boolean isUgly(int num) {
if (num<=0) return false;
if (num == 1) return true;
if (num % 2 == 0) return isUgly(num / 2);
if (num % 3 == 0) return isUgly(num / 3);
return num % 5 == 0 && isUgly(num / 5);
}
Lowest Common Ancestor of a Binary Search Tree
原题目为leetcode 235,难度系数为easy.
给定二叉查找树,找到其中两个给定节点的最低公共祖先。(节点也是自身的祖先)
利用递归的方法。public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) {
int max=Math.max(p.val,q.val);
int min=Math.min(p.val,q.val);
int rootval=root.val;
if(rootval==min||rootval==max||rootval>min&&rootval
if (rootval
return lowestCommonAncestor(root.left,p,q);
}
Merge Two Sorted Lists
原题目为leetcode 21,难度系数为easy.
合并两个排好序的链表。
如果其中一个为空,返回另一个。比较首个节点的值,小的作为新链表的首节点。新的首节点的指向为原先的去除了首节点的链表和另外的链表的合并。骤然发现自己的答案和discuss里面赞数最多的一字不差,excited!public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
if (l1==null) return l2;
if (l2==null) return l1;
if (l1.val
l1.next=mergeTwoLists(l1.next,l2);
return l1;
}else {
l2.next=mergeTwoLists(l2.next,l1);
return l2;
}
}
Power of Four
原题目为leetcode 342,难度系数为easy.
判断整数是否是4的幂次。public boolean isPowerOfFour(int num) {
if (num==1) return true;
if (num<=0||num%4!=0) return false;
return isPowerOfFour(num/4);
}
Swap Nodes in Pairs
原题目为leetcode 24,难度系数为easy.
交换链表每两个相邻节点的位置。不能改变节点的值。
改变值的办法:public ListNode swapPairs(ListNode head) {
ListNode point=head;
while (point!=null&&point.next!=null){
int tmp=point.val;
point.val=point.next.val;
point.next.val=tmp;
point=point.next.next;
}
return head;
}
改变节点指向:public ListNode swapPairs(ListNode head) {
if (head==null||head.next==null) return head;
ListNode er=head.next;
head.next=swapPairs(er.next);
er.next=head;
return er;
}
Reverse Vowels of a String
原题目为leetcode 345,难度系数为easy.
反转字符串中的元音字母。
利用栈存储字母,ArrayList存储索引。StringBuilder构建字符串。public String reverseVowels(String s) {
Stack sk=new Stack();
ArrayList list = new ArrayList<>();
for (int i=0;i
char c=s.charAt(i);
if (c=='a'||c=='o'||c=='e'||c=='i'||c=='u'||c=='A'||c=='O'||c=='E'||c=='I'||c=='U'){
list.add(i);
sk.push(c);
}
}
StringBuilder sb = new StringBuilder(s);
for (int itm:list) {
sb.replace(itm,itm+1, String.valueOf(sk.pop()));
}
return sb.toString();
}
House Robber
原题目为leetcode 198,难度系数为easy.
考虑最后一家,最后一家有被抢劫和不被抢劫两种情况。如果被抢劫,则倒数第二家肯定没有被抢劫。最大金额为前n-2家被抢的最大金额加最后一家的金额。如果没有被抢劫,最大金额等于前n-1家被抢的最大金额。所以两者取最大值。使用ArrayList存储前x家被抢的最大金额数。public int rob(int[] nums) {
int len=nums.length;
if (len==0) return 0;
if (len==1) return nums[0];
ArrayList list = new ArrayList<>();
list.add(0);
list.add(nums[0]);
for (int i = 2; i <=len; i++) {
list.add(Math.max(list.get(i-2)+nums[i-1],list.get(i-1)));
}
return list.get(len);
}
使用Array存储前x家被抢的最大金额数。public int rob(int[] nums) {
int len=nums.length;
if (len==0) return 0;
if (len==1) return nums[0];
int[] ints = new int[len];
ints[0]=0;
ints[1]=nums[0];
for (int i = 2; i
ints[i]=Math.max(ints[i-2]+nums[i-1],ints[i-1]);
}
return Math.max(ints[len-2]+nums[len-1],ints[len-1]);
}
Binary Tree Level Order Traversal
原题目为leetcode 102,难度系数为easy.
给定二叉树,返回水平顺序遍历的节点的值。For example:
Given binary tree [3,9,20,null,null,15,7],
3
/ \
9 20
/ \
15 7
return its level order traversal as:
[
[3],
[9,20],
[15,7]
]
新建order函数将各个节点的值传入lists中。level表示lists的索引。如果根节点为空,不对lists进行任何操作。如果level不小于lists的长度,增加一个ArrayList元素。将根节点的值传入对应的层级索引的list。public List> levelOrder(TreeNode root) {
List> lists = new ArrayList>();
int level=0;
order(root,lists,level);
return lists;
}
private void order(TreeNode root, List> lists, int level) {
if (root==null) return;
if (level>=lists.size()) lists.add(new ArrayList());
lists.get(level).add(root.val);
order(root.left,lists,level+1);
order(root.right,lists,level+1);
}
使用队列Queue。队列是一种数据结构.它有两个基本操作:在队列尾部加人一个元素,和从队列头部移除一个元素。
offer 添加一个元素并返回true 如果队列已满,则返回false
poll 移除并返问队列头部的元素 如果队列为空,则返回null
peek 返回队列头部的元素 如果队列为空,则返回null
按照水平顺序依次将节点加入队列。public List> levelOrder(TreeNode root) {
List> lists = new ArrayList>();
if (root==null) return lists;
Queue qe=new LinkedList<>();
qe.offer(root);
while (!qe.isEmpty()){
int len=qe.size();
ArrayList integers = new ArrayList<>();
for (int i = 0; i
if (qe.peek().left!=null) qe.offer(qe.peek().left);
if (qe.peek().right!=null) qe.offer(qe.peek().right);
integers.add(qe.poll().val);
}
lists.add(integers);
}
return lists;
}
Symmetric Tree
原题目为leetcode 101,难度系数为easy.
判断二叉树是否是自身的镜像。For example, this binary tree [1,2,2,3,4,4,3] is symmetric:
1
/ \
2 2
/ \ / \
3 4 4 3
But the following [1,2,2,null,3,null,3] is not:
1
/ \
2 2
\ \
3 3
为了使用迭代,考虑构建函数判断两个二叉树是否镜像(感觉这种套路二叉树里面很多)。discuss里面迭代的方法也基本上是这个套路。public boolean isSymmetric(TreeNode root) {
return root == null || cmp(root.left, root.right);
}
public boolean cmp(TreeNode left,TreeNode right){
if (left==null||right==null) return left==null&&right==null;
return left.val==right.val&&cmp(left.left,right.right)&&cmp(left.right,right.left);
}
Plus One
原题目为leetcode 66,难度系数为easy.
一个数组表示非负整数,返回这个整数加一得到的数组。
刚开始想的很直,转换为数,再转换为数组。测试不通过。因为超过了int的范围。强转。使用long也不通过。public int[] plusOne(int[] digits) {
int sum=0;
for (int i:digits) {
sum*=10;
System.out.println(sum);
sum+=i;
}
sum+=1;
int[] rs=new int[String.valueOf(sum).length()];
for (int i = rs.length-1; i >=0; i--) {
rs[i]=(int)sum%10;
sum/=10;
}
return rs;
}
判断数组中是不是每一位都为9,这种情况下需要返回长度加一的数组。否则从末尾遍历,将9置0,非9的那一位加一,直接返回数组。public int[] plusOne(int[] digits) {
for (int i = digits.length-1; i >=0; i--) {
if (digits[i]==9){
digits[i]=0;
}else {
digits[i]+=1;
return digits;
}
}
int[] ints = new int[digits.length + 1];
ints[0]=1;
return ints;
}
Pascal's Triangle
原题目为leetcode 118,难度系数为easy.
帕斯卡三角形For example, given numRows = 5,
Return
[
[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1]
]
套两层循环。public List> generate(int numRows) {
List> rs=new ArrayList<>();
for (int i=1;i<=numRows;i++){
List list=new ArrayList<>();
list.add(1);
if (i>1){
for (int j = 2; j
list.add(rs.get(i-2).get(j-1)+rs.get(i-2).get(j-2));
}
list.add(1);
}
rs.add(list);
}
return rs;
}
discuss里面有一种非常厉害的方法。通过每一次循环在row最前端加一个1,避免了边界的检查。public List> generate(int numRows) {
List> allrows = new ArrayList>();
ArrayList row = new ArrayList();
for(int i=0;i
row.add(0, 1);
for(int j=1;j
row.set(j, row.get(j)+row.get(j+1));
allrows.add(new ArrayList(row));
}
return allrows;
}
Remove Element
原题目为leetcode 27,难度系数为easy.
移除数组中的某个元素,返回新的数组长度Example:
Given input array nums = [3,2,2,3], val = 3
Your function should return length = 2, with the first two elements of nums being 2.
题目的意思是要使得nums数组前length个元素为剔除过val元素后剩下的元素。public int removeElement(int[] nums, int val) {
int index=0;
for (int i = 0; i < nums.length; i++) {
if (nums[i]!=val){
nums[index++]=nums[i];
}
}
return index;
}
Linked List Cycle ##
原题目为leetcode 141,难度系数为easy.
判断链表里面是否存在循环
直接把遍历过的节点存在ArrayList里。几乎超时。public boolean hasCycle(ListNode head) {
ArrayList list = new ArrayList<>();
while (head!=null){
if (list.contains(head)) return true;
list.add(head);
head=head.next;
}
return false;
}
将遍历过的每一个节点的next属性改变为head。一旦再次遍历到已遍历过的任意节点,表示存在循环。public boolean hasCycle(ListNode head) {
while (head!=null){
ListNode tmp=head.next;
if (head.next==head) return true;
head.next=head;
head=tmp;
}
return false;
}
discuss里面的做法。slow挨个遍历,fast隔两个遍历,如果存在循环,它们必然会在某一时刻相等。public boolean hasCycle(ListNode head) {
if (head == null || head.next == null) {
return false;
}
ListNode slow = head;
ListNode fast = head.next;
while (slow != fast) {
if (fast == null || fast.next == null) {
return false;
}
slow = slow.next;
fast = fast.next.next;
}
return true;
}
Balanced Binary Tree
原题目为leetcode 110,难度系数为easy.
判断二叉树是否是高度平衡的,即二叉树每个节点的子树的高度差不超过一。
改造二叉树高度函数。如果高度返回值为-1,说明存在有节点不是高度平衡的。public boolean isBalanced(TreeNode root) {
return depth(root)!=-1;
}
private int depth(TreeNode root) {
if (root==null) return 0;
int left=depth(root.left);
int right=depth(root.right);
if (left==-1||right==-1||Math.abs(left-right)>1) return -1;
return Math.max(left,right)+1;
}
Remove Duplicates from Sorted Array
原题目为leetcode 110,难度系数为easy.
给定排序后的数组,移除重复的元素,即元素只能出现一次。For example,
Given input array nums = [1,1,2],
Your function should return length = 2,
with the first two elements of nums being 1 and 2 respectively.
和之前的套路类似,使用两个变量表示下标。因为排过序了,只要后一项不等于前一项即可。public int removeDuplicates(int[] nums) {
if (nums.length==0) return 0;
int j=1;
for (int i = 1; i
if (nums[i]!=nums[i-1]){
nums[j++]=nums[i];
}
}
return j;
}
Find All Anagrams in a String
原题目为leetcode 438,难度系数为easy.
给一个非空字符串p,找到字符串s中所有p的重组字符串的起始下标。
定义int[26]数组存放字母出现的次数。为了节省时间,每一次循环时,加入新的字符,减去原先的第一个字符。public List findAnagrams(String s, String p) {
ArrayList list = new ArrayList<>();
int lenp=p.length();
int lens=s.length();
if (lenp==0||lens==0||lens
int[] ints = new int[26];
for (char c:p.toCharArray()) {
ints[c-'a']++;
}
for (int i = 0; i < lenp-1; i++) {
ints[s.charAt(i)-'a']--;
}
for (int i = 0; i
ints[s.charAt(i+lenp-1)-'a']--;
if (iszero(ints)) list.add(i);
ints[s.charAt(i)-'a']++;
}
return list;
}
private boolean iszero(int[] ints) {
for (int item:ints) {
if (item!=0) return false;
}
return true;
}
Factorial Trailing Zeroes
原题目为leetcode 172,难度系数为easy.
返回n的阶层末尾的0的个数
计算中碰见5即可在末尾添0。要搞清楚代码的逻辑,第一次n/5得到5的倍数的个数,第二次得到了25的倍数的个数,以此类推。public int trailingZeroes(int n) {
if (n<5) {
return 0;
}
int sum=0;
while (n>=5) {
n/=5;
sum+=n;
}
return sum;
}
Binary Tree Paths
原题目为leetcode 257,难度系数为easy.
给出二叉树所有跟到叶的路径For example, given the following binary tree:
1
/ \
2 3
\
5
All root-to-leaf paths are:
["1->2->5", "1->3"]
考虑迭代方法,注意设置两个边界。public List binaryTreePaths(TreeNode root) {
List result=new ArrayList();
if (root==null) return result;
if (root.left==null&&root.right==null){
result.add(String.valueOf(root.val));
return result;
}
for (String st:binaryTreePaths(root.left)) {
result.add(String.valueOf(root.val)+"->"+st);
}
for (String st:binaryTreePaths(root.right)) {
result.add(String.valueOf(root.val)+"->"+st);
}
return result;
}
Valid Sudoku
原题目为leetcode 36,难度系数为easy.
判断数独是否有效
判断每一行每一列以及块中是否有重复。使用三个数组判断public boolean isValidSudoku(char[][] board) {
int[][] intsi = new int[9][53];
int[][] intsj = new int[9][54];
int[][] intsij = new int[9][55];
for (int i = 0; i <9 ; i++) {
for (int j = 0; j < 9; j++) {
int ct=board[i][j]-'1';
if (board[i][j]!='.') {
if (intsi[i][ct]==1||intsj[j][ct]==1||intsij[(i/3)*3+j/3][ct]==1) return false;
intsi[i][ct]++;
intsj[j][ct]++;
intsij[(i/3)*3+j/3][ct]++;
}
}
}
return true;
}
一种很清晰使用set判断的方法public boolean isValidSudoku(char[][] board) {
Set seen = new HashSet();
for (int i=0; i<9; ++i) {
for (int j=0; j<9; ++j) {
char number = board[i][j];
if (number != '.')
if (!seen.add(number + " in row " + i) ||
!seen.add(number + " in column " + j) ||
!seen.add(number + " in block " + i/3 + "-" + j/3))
return false;
}
}
return true;
}
Guess Number Higher or Lower
原题目为leetcode 374,难度系数为easy.
猜数字。主要点在于使用start+(end-start)/2从而避免overflow的错误。而且需要注意边界。public int guessNumber(int n) {
return gs(1,n);
}
private int gs(int start,int end){
int num=start+(end-start)/2;
int flag=guess(num);
if (flag==0) {
return num;
}
if (flag==-1) {
return gs(start,num);
}
return gs(num+1,end);
}
Bulls and Cows
原题目为leetcode 299,难度系数为easy.
使用arraylist移除
publicStringgetHint(Stringsecret,Stringguess){
ArrayListlist=newArrayList();
for(inti=0;i
list.add(secret.charAt(i));
}
intA=0;
for(inti=0;i
charch=guess.charAt(i);
if(ch==secret.charAt(i)){
A++;
}
if(list.contains(ch)){
list.remove((Character)ch);
}
}
intB=guess.length()-list.size()-A;
StringreString=A+"A"+B+"B";
returnreString;
}
Path Sum
原题目为leetcode 112,难度系数为easy.
判断二叉树根到叶的和中是否存在给定值。
使用迭代的方法。如果是叶子节点,直接判断值是否等于node.val。如果存在子节点,判断子节点中是否存在符合条件的路径。
publicbooleanhasPathSum(TreeNoderoot,intsum){
if(root==null)returnfalse;
if(root.left==null&&root.right==null)returnsum==root.val;
returnhasPathSum(root.left,sum-root.val)||hasPathSum(root.right,sum-root.val);
}
Minimum Depth of Binary Tree
原题目为leetcode 111,难度系数为easy.
找到二叉树跟到叶的最短路径值。
与找最大深度类似,但不同点在于只存在左或者右节点的情况需要单独处理,直接迭代会返回零。
publicintminDepth(TreeNoderoot){
if(root==null)return0;
if(root.left==null&&root.right==null)return1;
if(root.left==null||root.right==null)returnminDepth(root.left)+minDepth(root.right)+1;
returnMath.min(minDepth(root.left),minDepth(root.right))+1;
}
Isomorphic Strings
原题目为leetcode 205,难度系数为easy.
利用hashset和hashmap.注意set.add(tc)返回值表示是否成功添加
publicbooleanisIsomorphic(Strings,Stringt){
if(s.length()!=t.length())returnfalse;
HashMapmap=newHashMap();
HashSetset=newHashSet();
for(inti=0;i
charsc=s.charAt(i);
chartc=t.charAt(i);
if(!map.containsKey(sc)){
if(!set.add(tc)){
returnfalse;
}
map.put(sc,tc);
}else{
if(map.get(sc)!=tc){
returnfalse;
}
}
}
returntrue;
}
Count and Say
原题目为leetcode 38,难度系数为easy.
每一个新的字符都由上一个字符操作得到,使用迭代。
publicStringcountAndSay(intn){
if(n==1)return"1";
StringBuildersb=newStringBuilder();
StringandSay=countAndSay(n-1);
inti=0;
while(i
charc=andSay.charAt(i);
intj=i+1;
while(j
charc2=andSay.charAt(j);
if(c2!=c)break;
j++;
}
sb.append(j-i);
sb.append(c);
i=j;
}
returnsb.toString();
}
Rectangle Area
原题目为leetcode 223,难度系数为easy.
给两个矩形的坐标,求所有覆盖的面积
重点在于找出相交矩形的坐标
publicintcomputeArea(intA,intB,intC,intD,intE,intF,intG,intH){
inttotal=(D-B)*(C-A)+(G-E)*(H-F);
intllx=Math.max(E,A);
intlly=Math.max(F,B);
intrhx=Math.min(C,G);
intrhy=Math.min(D,H);
if(rhx
returntotal-(rhy-lly)*(rhx-llx);
}