LeetCode刷题笔记(1)——基础题篇

LeetCode刷题笔记(1)——基础题篇

还有不到一年的时间就要找工作了,现在开始刷LeetCode的编程题。
目标:每日1-2题,不仅要Accept,更要学会最优的解法。

针对做题学到的更优解法,记录如下,方便以后复习。
下面开始我的编程之旅喽!

目录

1. Two Sum
7. Reverse Integer
9. Palindrome Number
13. Roman to Integer
14. Longest Common Prefix
15. 3Sum
20. Valid Parentheses
21. Merge Two Sorted Lists
26. Remove Duplicates from Sorted Array
27. Remove Element
28. Implement strStr()
35. Search Insert Position
38. Count and Say
53. Maximum Subarray
58. Length of Last Word
66. Plus One
67. Add Binary
69. Sqrt(x)
70. Climbing Stairs
83. Remove Duplicates from Sorted List
88. Merge Sorted Array
118. Pascal’s Triangle
119. Pascal’s Triangle II
121. Best Time to Buy and Sell Stock
122. Best Time to Buy and Sell Stock II
125. Valid Palindrome
136. Single Number
141. Linked List Cycle
155. Min Stack
167. Two Sum II - Input array is sorted
283. Move Zeroes
561. Array Partition I
709. To Lower Case
717. 1-bit and 2-bit Characters
771. Jewels and Stones
832. Flipping an Image
905. Sort Array By Parity
914. X of a Kind in a Deck of Cards
929. Unique Email Addresses

1. Two Sum

Given an array of integers, return indices of the two numbers such that they add up to a specific target.
You may assume that each input would have exactly one solution, and you may not use the same element twice.

Example:

Given nums = [2, 7, 11, 15], target = 9,

Because nums[0] + nums[1] = 2 + 7 = 9,
return [0, 1].

分析:第一种方法是暴力解(不推荐)。循环遍历每个元素x并找出是否存在另一个元素等于target-x,这样做的时间复杂度是O(n2n^2),空间复杂度是O(1)。
   第二种方法是使用还是哈希表(推荐)。用空间换时间,时间复杂度是O(nn),空间复杂度也是O(n)。此解法的巧妙之处在于以nums[i]为key,以i为value,这方便于后面的的判断和使用。

优化的代码如下:

class Solution {
    public int[] twoSum(int[] nums, int target) {
        HashMap<Integer,Integer> map = new HashMap<>();
        for(int i = 0; i < nums.length; i++){
            int temp = target - nums[i];
            if(map.containsKey(temp)){
                return new int[] {map.get(temp),i};
            }             
            map.put(nums[i],i);
        }
        throw new IllegalArgumentException("No two sum solution");
    }
}

7. Reverse Integer

Given a 32-bit signed integer, reverse digits of an integer.

Example 1:

Input: 123
Output: 321

Example 2:

Input: -123
Output: -321

Example 3:

Input: 120
Output: 21

Note:
Assume we are dealing with an environment which could only store integers within the 32-bit signed integer range: [231-2^{31}, 2312^{31}−1]. For the purpose of this problem, assume that your function returns 0 when the reversed integer overflows.

分析:题目中要求检查溢出,若溢出则返回0。溢出的检查是本题的关键。

检查溢出的方法:如果逆运算的值不等于原来的值,说明求和结果由于溢出发生了改变。

优化的代码如下:

class Solution {
    public int reverse(int x) {
        int result = 0;
        while(x != 0){
            int temp = result * 10 + x % 10;
            if((temp - x % 10)/10 != result){  //逆运算的值不等于原来的值,溢出了
                return 0;
            }
            x = x / 10;
            result = temp;
        }
        return result;
    }
}

9. Palindrome Number

Determine whether an integer is a palindrome. An integer is a palindrome when it reads the same backward as forward.

Example 1:

Input: 121
Output: true

Example 2:

Input: -121
Output: false
Explanation: From left to right, it reads -121. From right to left, it becomes 121-. Therefore it is not a palindrome.

Example 3:

Input: 10
Output: false
Explanation: Reads 01 from right to left. Therefore it is not a palindrome.

Follow up:
Coud you solve it without converting the integer to a string?

分析:首先考虑负数和个位为0的非零数都不是回文数字,返回false,其他的数字进行进一步的判断。通过取余操作将x反转,比较反转后的数字和原数字是否一致即可。

优化的代码如下:

class Solution {
    public boolean isPalindrome(int x) {
        if(x < 0 || (x != 0 && x % 10 == 0)) return false;
        int temp = x;
        int reverse = 0;
        while(temp > 0){
            reverse = reverse * 10 + temp % 10;
            temp /= 10;
        }
        return (reverse == x);
    }
}

13. Roman to Integer

Roman numerals are represented by seven different symbols: I, V, X, L, C, D and M.

在这里插入图片描述
For example, two is written as II in Roman numeral, just two one’s added together. Twelve is written as, XII, which is simply X + II. The number twenty seven is written as XXVII, which is XX + V + II.

Roman numerals are usually written largest to smallest from left to right. However, the numeral for four is not IIII. Instead, the number four is written as IV. Because the one is before the five we subtract it making four. The same principle applies to the number nine, which is written as IX. There are six instances where subtraction is used:

I can be placed before V (5) and X (10) to make 4 and 9.
X can be placed before L (50) and C (100) to make 40 and 90.
C can be placed before D (500) and M (1000) to make 400 and 900.
Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 to 3999.

Example 1:

Input: “III”
Output: 3

Example 2:

Input: “IV”
Output: 4

Example 3:

Input: “IX”
Output: 9

Example 4:

Input: “LVIII”
Output: 58
Explanation: L = 50, V= 5, III = 3.

Example 5:

Input: “MCMXCIV”
Output: 1994
Explanation: M = 1000, CM = 900, XC = 90 and IV = 4.

分析:本题我有两种思路。第一种比较相邻的两个字符,如果前面的比后面的小,则用减法操作前面字符,否则用加法操作。第二种思路是通过枚举的方式将特殊组合(即不是用加法的组合)罗列出来,包括4,9,40,90,400,900。其他的都用加法,这样将特殊组合的差值减掉即可得到正确的结果。

优化的代码如下:
第一种方法:

class Solution {
    public int romanToInt(String s) {
        HashMap<Character,Integer> map = new HashMap<>();
        map.put('I',1);
        map.put('V',5);
        map.put('X',10);
        map.put('L',50);
        map.put('C',100);
        map.put('D',500);
        map.put('M',1000);
        char[] cs = s.toCharArray();
        int result = map.get(cs[cs.length-1]);
        for(int i = cs.length - 2; i >= 0; i--){
            if(map.get(cs[i+1]) <= map.get(cs[i])){
                result += map.get(cs[i]);
            }else{
                result -= map.get(cs[i]);
            }
        }
        return result;
    }
}

第二种方法:

class Solution {
    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();
    
        for(int i = 0;i <= s.length()-1;i++){
            if(c[i]=='M') sum+=1000;
            if(c[i]=='D') sum+=500;
            if(c[i]=='C') sum+=100;
            if(c[i]=='L') sum+=50;
            if(c[i]=='X') sum+=10;
            if(c[i]=='V') sum+=5;
            if(c[i]=='I') sum+=1;       
        }
    	return sum;   
    }
}

14. Longest Common Prefix

Write a function to find the longest common prefix string amongst an array of strings.

If there is no common prefix, return an empty string “”.

Example 1:

Input: [“flower”,“flow”,“flight”]
Output: “fl”

Example 2:

Input: [“dog”,“racecar”,“car”]
Output: “”
Explanation: There is no common prefix among the input strings.

Note:
All given inputs are in lowercase letters a-z.

分析:如果所输入的字符串数组为空,那么返回""。否则假设strs[0]为最长公共前缀prefix,接下来依次判断它是否为strs[1]到strs[strs.length-1]的最长公共前缀。若不是,则去掉末尾字符,直至是最长公共前缀或prefix空为止。最终返回prefix即为最长公共前缀。

优化的代码如下:

class Solution {
    public String longestCommonPrefix(String[] strs) {
        if(strs.length == 0) return "";
        String prefix = strs[0];
        for(int i = 1; i < strs.length; i++){
            if(prefix.equals("")) break;
            while(!strs[i].startsWith(prefix)){
                prefix = prefix.substring(0,prefix.length()-1);
            }                
        }  
        return prefix;
    }
}

15. 3Sum

Given an array nums of n integers, are there elements a, b, c in nums such that a + b + c = 0? Find all unique triplets in the array which gives the sum of zero.

Note:
The solution set must not contain duplicate triplets.

Example:

Given array nums = [-1, 0, 1, 2, -1, -4],
A solution set is:
[
[-1, 0, 1],
[-1, -1, 2]
]

分析:本题的关键在于结果需要去除重复。在解题的过程中,首先将数组中的元素排序,然后依次向后遍历,寻找两个数的与当前元素的和为0,存储结果。注意,这里采用的是遇到与前一个元素相等的元素就跳过,继续向后遍历查找。

优化的代码如下:

class Solution {
    public static List<List<Integer>> threeSum(int[] nums) {
        List<List<Integer>> result = new ArrayList<List<Integer>>();
        Arrays.sort(nums);
        int i = 0;
        while(i < nums.length-2) {
        	while(i > 0 && nums[i] == nums[i-1] && i < nums.length-2) {	//去除重复结果
        		i++;
        	}
            int low = i+1;
            int high = nums.length-1;
            while(low < high){
                if(nums[low]+nums[high]+nums[i] == 0){
                	List<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[low]);
                    list.add(nums[high]);
                    result.add(list);
                    low++;
                    while(nums[low] == nums[low-1] && low < high) {		//去除重复结果
                    	low++;
                	}
                }else if(nums[low]+nums[high]+nums[i] < 0){
                    low++;
                }else{
                    high--;
                }               
            }
            i++;
        }        
        return result;
    }
}

20. Valid Parentheses

Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid.

An input string is valid if:

  Open brackets must be closed by the same type of brackets.
  Open brackets must be closed in the correct order.

Note that an empty string is also considered valid.

Example 1:

Input: “()”
Output: true

Example 2:

Input: “()[]{}”
Output: true

Example 3:

Input: “(]”
Output: false

Example 4:

Input: “([)]”
Output: false

Example 5:

Input: “{[]}”
Output: true

分析:起初,我的想法是用HashMap存储括号对,左括号为key,右括号为value。遍历String中的每个字符,若为左括号就压栈,否则为右括号继续做判断。若栈空时出现右括号,则直接返回false;若栈顶元素在HashMap中所对应的value值正好为当前出现的右括号,则栈顶元素出栈,继续对字符串中下一字符的判断;若栈顶元素在HashMap中所对应的value值不是当前出现的右括号,则返回false。直至最后,字符串中的所有字符都判断完成后,若栈空则返回true。
   上述想法可以做一下简化,可以不使用HashMap。遍历String中的每个字符,若出现左括号,就将对应的右括号压栈,否则为右括号,就栈顶元素出栈,同时判断它是否等于当前出现的右括号。若栈空或栈顶元素不是当前出现的右括号,则返回false。直至最后,字符串中的所有字符都判断完成后,若栈空则返回true。

优化的代码如下:
第一种方法:

class Solution {
    public boolean isValid(String s) {
        HashMap<Character,Character> map = new HashMap<>();
        map.put('(',')');
        map.put('[',']');
        map.put('{','}');
        Stack<Character> stack = new Stack<>();
        for(char c : s.toCharArray()){
            if(map.keySet().contains(c)){
                stack.push(c);
            }else if(stack.empty()){
                return false;
            }else if(map.get(stack.peek()) == c){
                stack.pop();
            }else{
                return false;
            }
        }
        return stack.empty();
    }
}

第二种方法:

class Solution {
    public boolean isValid(String s) {
        Stack<Character> stack = new Stack<>();
        for(char c : s.toCharArray()){
            if(c == '('){
                stack.push(')');
            }else if(c == '['){
                stack.push(']');
            }else if(c == '{'){
                stack.push('}');
            }else if(stack.empty() || stack.pop() != c){
                return false;
            }
        }
        return stack.empty();
    }
}

21. Merge Two Sorted Lists

Merge two sorted linked lists and return it as a new list. The new list should be made by splicing together the nodes of the first two lists.

Example:

Input: 1->2->4, 1->3->4
Output: 1->1->2->3->4->4

分析:本题的解法十分巧妙,应用了递归的思想。比较当前两个链表的第一个元素值val的大小,值val较小的链表next与另一链表递归调用此函数,将结果赋值给值val较小的链表next。返回这个值val较小的链表。相当于每调用一次函数,拼接一个最小值。这种递归的思想十分重要!

优化的代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode mergeTwoLists(ListNode l1, ListNode l2) {
        if(l1 == null) return l2;
        if(l2 == null) return l1;
        if(l1.val < l2.val){
            l1.next = mergeTwoLists(l1.next, l2);
            return l1;
        }else{
            l2.next = mergeTwoLists(l1, l2.next);
            return l2;
        }
    }
}

26. Remove Duplicates from Sorted Array

Given a sorted array nums, remove the duplicates in-place such that each element appear only once and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.

Example 1:

Given nums = [1,1,2],
Your function should return length = 2, with the first two elements of nums being 1 and 2 respectively.
It doesn’t matter what you leave beyond the returned length.

Example 2:

Given nums = [0,0,1,1,1,2,2,3,3,4],
Your function should return length = 5, with the first five elements of nums being modified to 0, 1, 2, 3, and 4 respectively.
It doesn’t matter what values are set beyond the returned length.

分析
题目中的关键信息有:

  • Given a sorted array nums
    输入是一个有序的数组,因此可以按顺序进行遍历比较,输出的结果也是有顺序的。

  • Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
    需要用新的值覆盖掉原数组,而不能创建新的数组。

优化的代码如下:

class Solution {
    public int removeDuplicates(int[] nums) {
        int j = 0;
        for(int i = 1; i < nums.length; i++){
            if(nums[i] != nums[j]){
                nums[++j] = nums[i];
            }
        }
        return j+1;
    }
}

27. Remove Element

Given an array nums and a value val, remove all instances of that value in-place and return the new length.
Do not allocate extra space for another array, you must do this by modifying the input array in-place with O(1) extra memory.
The order of elements can be changed. It doesn’t matter what you leave beyond the new length.

Example 1:

Given nums = [3,2,2,3], val = 3,

Your function should return length = 2, with the first two elements of nums being 2.
It doesn’t matter what you leave beyond the returned length.

Example 2:

Given nums = [0,1,2,2,3,0,4,2], val = 2,

Your function should return length = 5, with the first five elements of nums containing 0, 1, 3, 0, and 4.
Note that the order of those five elements can be arbitrary.
It doesn’t matter what values are set beyond the returned length.

分析:第一种方法是类似于第26题中的方法,设置两个指针,一个用来遍历数组中的元素,另一个用来指向保留的元素。但是当数组中多数元素都不需要移除时,这种方法需要大量的复制操作。为了解决这个问题,有第二种方法。
   第二种方法也是设置两个指针,但不同的是将想要移除的元素与数组最后一个元素互换,这样可以避免大量的复制操作,在数组中只有较少的val元素时优势明显。

优化的代码如下:

第一种方法:

class Solution {
    public int removeElement(int[] nums, int val) {
        int j = 0;
        for(int i = 0; i < nums.length; i++){
            if(nums[i] != val){
                nums[j++] = nums[i];
            }
        }
        return j;
    }
}

第二种方法:

class Solution {
    public int removeElement(int[] nums, int val) {
        int i = 0;
        int n = nums.length;
        while(i < n){
            if(nums[i] == val){
                nums[i] = nums[n-1];
                n--;
            }else{
                i++;
            }
        }
        return n;
    }
}

28. Implement strStr()

Return the index of the first occurrence of needle in haystack, or -1 if needle is not part of haystack.

Example 1:

Input: haystack = “hello”, needle = “ll”
Output: 2

Example 2:

Input: haystack = “aaaaa”, needle = “bba”
Output: -1

Clarification:
What should we return when needle is an empty string? This is a great question to ask during an interview.
For the purpose of this problem, we will return 0 when needle is an empty string. This is consistent to C’s strstr() and Java’s indexOf().

分析:本题我的思路是从haystack中截取长度为needle长度的子字符串,若有与needle相同的子字符串,就返回其下标,否则返回-1。其中,若needle为空,就返回0。

优化的代码如下:

class Solution {
    public int strStr(String haystack, String needle) {
        if(needle.length() == 0) return 0;
        for(int i = 0; i < haystack.length()-needle.length()+1; i++){
            if(haystack.substring(i,i+needle.length()).equals(needle)){
                return i;
            }
        }
        return -1;
    }
}

35. Search Insert Position

Given a sorted array and a target value, return the index if the target is found. If not, return the index where it would be if it were inserted in order.
You may assume no duplicates in the array.

Example 1:

Input: [1,3,5,6], 5
Output: 2

Example 2:

Input: [1,3,5,6], 2
Output: 1

Example 3:

Input: [1,3,5,6], 7
Output: 4

Example 4:

Input: [1,3,5,6], 0
Output: 0

分析:由于数组是有序的,只需要遍历查找第一个大于等于target的元素位置,即为target应当插入的位置。如果所有元素都小于target,则将其插入最后。

优化的代码如下:

class Solution {
    public int searchInsert(int[] nums, int target) {
        for(int i = 0; i < nums.length; i++){
            if(nums[i] >= target){
                return i;
            }
        }
        return nums.length;
    }
}

38. Count and Say

The count-and-say sequence is the sequence of integers with the first five terms as following:
在这里插入图片描述
1 is read off as “one 1” or 11.
11 is read off as “two 1s” or 21.
21 is read off as “one 2, then one 1” or 1211.

Given an integer n where 1 ≤ n ≤ 30, generate the nth term of the count-and-say sequence.

Note: Each term of the sequence of integers will be represented as a string.

Example 1:

Input: 1
Output: “1”

Example 2:

Input: 4
Output: “1211”

分析:第一种方法是按照正常方法计算n次。本题更适合第二种方法,使用递归的思想!当n为1时,返回字符串“1”,否则调用countAndSay(n-1)。针对countAndSay(n-1)返回的字符串结果,依次遍历每个字符,并记录每个字符连续出现的次数count。然后依次存储每个字符出现的次数和此字符,得到的结果即为countAndSay(n)返回的字符串。

优化的代码如下:

第一种方法:

class Solution {
    public String countAndSay(int n) {
        String str = "1";
        char [] cs;
        for(int i = 2; i <= n; i++){
            StringBuilder sb = new StringBuilder();
            cs = str.toCharArray();
            int j = 0;
            while(j < str.length()){
                int count = 1;
                while(j+1 < str.length() && cs[j+1] == cs[j]){
                    count++;
                    j++;
                }
                sb.append(count+""+cs[j]);
                j++;
            }
            str = sb.toString();
        }        
        return str;
    }
}

第二种方法:

class Solution {
    public String countAndSay(int n) {
        if(n == 1) return "1"; 
        
        StringBuilder sb = new StringBuilder();
        String str = countAndSay(n-1);
        
        char[] cs = str.toCharArray();
        int j = 0;
        while(j < str.length()){
            int count = 1;
            while(j+1 < str.length() && cs[j+1] == cs[j]){
                count++;
                j++;
            }
            sb.append(count+""+cs[j]);
            j++;
        }  
        return sb.toString();
    }
}

53. Maximum Subarray

Given an integer array nums, find the contiguous subarray (containing at least one number) which has the largest sum and return its sum.

Example:

Input: [-2,1,-3,4,-1,2,1,-5,4],
Output: 6
Explanation: [4,-1,2,1] has the largest sum = 6.

Follow up:

If you have figured out the O(n) solution, try coding another solution using the divide and conquer approach, which is more subtle.

分析
变量max存储截至当前位置最大的子数组各项和。
关键点是:sum = sum > 0 ? (sum + nums[i]) : nums[i];
即:若前面的几项累加和大于0,就将它们加入到子数组中;若小于0,就从当前项重新记起。

优化的代码如下:

class Solution {
    public int maxSubArray(int[] nums) {
        int sum = nums[0];
        int max = nums[0];
        for(int i = 1; i < nums.length; i++){
            sum = sum > 0 ? (sum + nums[i]) : nums[i];
            max = Math.max(sum,max);
        }
        return max;
    }
}

58. Length of Last Word

Given a string s consists of upper/lower-case alphabets and empty space characters ’ ', return the length of last word in the string.
If the last word does not exist, return 0.

Note: A word is defined as a character sequence consists of non-space characters only.

Example:

Input: “Hello World”
Output: 5

分析:本题的思路是倒序遍历字符串的每一个字符,首先查找第一个非空格的字符,记录下标。然后从此下标处开始,继续倒序遍历,查找第一个空格的字符,记录下标。两个下标的差值即为最后一个单词的长度。

优化的代码如下:

class Solution {
    public int lengthOfLastWord(String s) {
        char [] cs = s.toCharArray();
        int end = s.length()-1;       
        while(end >= 0 && cs[end] == ' '){
            end--;
        }
        int start = end;
        while(start >= 0 && cs[start] != ' '){
            start--;
        }
        return end-start;
    }
}

66. Plus One

Given a non-empty array of digits representing a non-negative integer, plus one to the integer.
The digits are stored such that the most significant digit is at the head of the list, and each element in the array contain a single digit.
You may assume the integer does not contain any leading zero, except the number 0 itself.

Example 1:

Input: [1,2,3]
Output: [1,2,4]
Explanation: The array represents the integer 123.

Example 2:

Input: [4,3,2,1]
Output: [4,3,2,2]
Explanation: The array represents the integer 4321.

分析:如果数组的末尾元素不为9,只需要将该元素加1,所得数组即为所求;如果数组的末尾元素为9,加1后为10,因此此位置为0,其前一位的元素需要加1,过程同上。有一种特殊情况,如999,最终的结果应是1000,需要创建一个长度比原数组大1的新数组。

优化的代码如下:

class Solution {
    public int[] plusOne(int[] digits) {
        int[] extra = new int[digits.length + 1];
        for (int i = digits.length-1; i >= 0; i--) {
            if (digits[i] < 9) {
                digits[i]++;
                return digits;
            } else {
                digits[i] = 0;
            }
            extra[i+1] = digits[i];
        }
        extra[0] = 1;
        return extra;
    }
}

67. Add Binary

Given two binary strings, return their sum (also a binary string).
The input strings are both non-empty and contains only characters 1 or 0.

Example 1:

Input: a = “11”, b = “1”
Output: “100”

Example 2:

Input: a = “1010”, b = “1011”
Output: “10101”

分析:本题是进行二进制的加法运算,注意的是返回值是字符串类型,因此这里选择对字符串进行操作更为方便。首先创建一个StringBuilder对象用于存储最终的结果。设置i和j分别指向字符串a和b的结尾字符,设置进位标志carry。然后,对进位标志carry、i和j进行求和,根据其和设置当前位和进位标志。重复执行上一过程,直至i和j都指向字符串的头位置。最终 将StringBuilder对象翻转即为所求结果。

优化的代码如下:

class Solution {
    public String addBinary(String a, String b) {
        if(a.length() == 0) return b;
        if(b.length() == 0) return a;
        StringBuilder sb = new StringBuilder();
        int i = a.length()-1;
        int j = b.length()-1;
        int carry = 0;
        int sum;
        while(i >= 0 || j >= 0){
            sum = carry;
            if(i >= 0)
                sum += a.charAt(i--) - '0';
            if(j >= 0)
                sum += b.charAt(j--) - '0';
            sb.append(sum % 2);
            carry = sum / 2;
        }
        if(carry == 1)
            sb.append(carry);
        return sb.reverse().toString();
    }
}

69. Sqrt(x)

Implement int sqrt(int x).
Compute and return the square root of x, where x is guaranteed to be a non-negative integer.
Since the return type is an integer, the decimal digits are truncated and only the integer part of the result is returned.

Example 1:

Input: 4
Output: 2

Example 2:

Input: 8
Output: 2
Explanation: The square root of 8 is 2.82842…, and since the decimal part is truncated, 2 is returned.

分析:本题我采用的方法是二分查找,并借助了最大数Integer.MAX_VALUE。本题重点注意:使用mid <= x/mid的形式来表示是正确的,而不能使用mid * mid <= x的形式。因为当mid很大时,mid * mid会比Integer.MAX_VALUE还大而溢出。

优化的代码如下:

class Solution {
    public int mySqrt(int x) {
        if(x == 0) return 0;
        int low = 1;
        int high = Integer.MAX_VALUE;
        int mid;
        while(true){
            mid = (high - low) / 2 + low;
            if(mid <= x/mid && (mid+1) > x/(mid+1))
                return mid;
            if(mid > x/mid)
                high = mid - 1;
            if(mid < x/mid)
                low = mid + 1;
        }
    }
}

70. Climbing Stairs

You are climbing a stair case. It takes n steps to reach to the top.
Each time you can either climb 1 or 2 steps. In how many distinct ways can you climb to the top?
Note: Given n will be a positive integer.

Example 1:

Input: 2
Output: 2
Explanation: There are two ways to climb to the top.
 1 step + 1 step
 2 steps

Example 2:

Input: 3
Output: 3
Explanation: There are three ways to climb to the top.
 1 step + 1 step + 1 step
 1 step + 2 steps
 2 steps + 1 step

分析:通过对问题的分析,不难发现,本题的上楼梯问题的结果实质是一个斐波那契数列:1,2,3,5,8,13……

优化的代码如下:

class Solution {
    public int climbStairs(int n) {
        if(n == 1) return 1;
        if(n == 2) return 2;
        int result = 0;
        int f1 = 1;
        int f2 = 2;
        for(int i = 3; i <= n; i++){
            result = f1 + f2;
            f1 = f2;
            f2 = result;
        }
        return result;
    }
}

83. Remove Duplicates from Sorted List

Given a sorted linked list, delete all duplicates such that each element appear only once.

Example 1:

Input: 1->1->2
Output: 1->2

Example 2:

Input: 1->1->2->3->3
Output: 1->2->3

分析:本题要求去除链表中的重复元素。从表头节点开始一次向后遍历。若当前节点的值与其next节点的值相等,则将其next节点删除;否则继续遍历下一个节点。重复上一过程直至当前节点的next节点空为止。

优化的代码如下:

/**
 * Definition for singly-linked list.
 * public class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) { val = x; }
 * }
 */
class Solution {
    public ListNode deleteDuplicates(ListNode head) {
        ListNode current = head;
        while(current != null && current.next != null){
            if(current.val == current.next.val){
                current.next = current.next.next;
            }else{
                current = current.next;
            }
        }
        return head;
    }
}

88. Merge Sorted Array

Given two sorted integer arrays nums1 and nums2, merge nums2 into nums1 as one sorted array.

Note:

The number of elements initialized in nums1 and nums2 are m and n respectively.
You may assume that nums1 has enough space (size that is greater or equal to m + n) to hold additional elements from nums2.

Example:

Input:
nums1 = [1,2,3,0,0,0], m = 3
nums2 = [2,5,6], n = 3

Output: [1,2,2,3,5,6]

分析:设置两个指针,分别指向两个数组的末尾。比较两个末尾元素的大小,将较大者存入nums1中。若nums1的指针指向了数组第一个元素,将nums2中剩下的元素复制到nums1中的相应位置。

优化的代码如下:

class Solution {
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        int i = m - 1;
        int j = n - 1;
        while(i >= 0 && j >= 0){
            nums1[i+j+1] = nums1[i] >= nums2[j] ? nums1[i--] : nums2[j--];
        }
        if(i < 0){
            while(j >= 0){
                nums1[i+j+1] = nums2[j--];
            }
        }
    }
}

118. Pascal's Triangle

Given a non-negative integer numRows, generate the first numRows of Pascal’s triangle.
在这里插入图片描述
In Pascal’s triangle, each number is the sum of the two numbers directly above it.

Example:

Input: 5
Output:
[
[1],
[1,1],
[1,2,1],
[1,3,3,1],
[1,4,6,4,1]
]

分析:通过这道题,我对List<List< Integer >>的二维集合的使用有了更深一步的理解。

优化的代码如下:

class Solution {
    public List<List<Integer>> generate(int numRows) {
        List<List<Integer>> result = new ArrayList <List<Integer>>();
    	List<Integer> row;
    	List<Integer> temp = null;
        for(int i = 0; i < numRows; i++) {
        	row = new ArrayList<>();
        	for(int j = 0; j <= i; j++) {
        		if(j == 0 || j == i) {
        			row.add(1);
        		}else {
        			row.add(temp.get(j-1)+temp.get(j));
        		}
        	}
        	temp = row;
        	result.add(row);
        }    	   	
    	return result;
    }
}

119. Pascal's Triangle II

Given a non-negative index k where k ≤ 33, return the kth index row of the Pascal’s triangle.
Note that the row index starts from 0.
在这里插入图片描述
In Pascal’s triangle, each number is the sum of the two numbers directly above it.

Example:

Input: 3
Output: [1,3,3,1]

Follow up:

Could you optimize your algorithm to use only O(k) extra space?

分析:此题不同于上一题,不需要保存所有行,直接将list覆盖即可。

优化的代码如下:

class Solution {
    public List<Integer> getRow(int rowIndex) {
        List <Integer> list = new ArrayList<>();
        for(int i = 0; i <= rowIndex; i++) {
            list.add(1);
            for(int j = i-1; j > 0; j--) {
                list.set(j, list.get(j-1) + list.get(j));
            }
        }   
        return list;
    }
}

121. Best Time to Buy and Sell Stock

Say you have an array for which the ith element is the price of a given stock on day i.
If you were only permitted to complete at most one transaction (i.e., buy one and sell one share of the stock), design an algorithm to find the maximum profit.
Note that you cannot sell a stock before you buy one.

Example 1:

Input: [7,1,5,3,6,4]
Output: 5
Explanation: Buy on day 2 (price = 1) and sell on day 5 (price = 6), profit = 6-1 = 5.
Not 7-1 = 6, as selling price needs to be larger than buying price.

Example 2:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

分析:遍历数组,并记录截止目前的最大收益和数组中的最小值。这里,利用For-Each比普通的for循环计算速度更快。

优化的代码如下:

class Solution {
    public int maxProfit(int[] prices) {
        int maxProfit = 0;
        int min = Integer.MAX_VALUE;
        for(int price:prices){
            if(price - min > maxProfit){
                maxProfit = price - min;
            }
            if(price < min){
                min = price;
            }
        }
        return maxProfit;
    }
}

122. Best Time to Buy and Sell Stock II

Say you have an array for which the i th element is the price of a given stock on day i.
Design an algorithm to find the maximum profit. You may complete as many transactions as you like (i.e., buy one and sell one share of the stock multiple times).

Note: You may not engage in multiple transactions at the same time (i.e., you must sell the stock before you buy again).

Example 1:

Input: [7,1,5,3,6,4]
Output: 7
Explanation: Buy on day 2 (price = 1) and sell on day 3 (price = 5), profit = 5-1 = 4.
   Then buy on day 4 (price = 3) and sell on day 5 (price = 6), profit = 6-3 = 3.

Example 2:

Input: [1,2,3,4,5]
Output: 4
Explanation: Buy on day 1 (price = 1) and sell on day 5 (price = 5), profit = 5-1 = 4.
   Note that you cannot buy on day 1, buy on day 2 and sell them later, as you are engaging multiple transactions at the same time. You must sell before buying again.

Example 3:

Input: [7,6,4,3,1]
Output: 0
Explanation: In this case, no transaction is done, i.e. max profit = 0.

分析:此题重要的是对过程的分析,这里学习到一种简单的方法。本题的目标是得到最大的收益值,因此只需要“向山顶攀爬”,即只需要累加各小段的利润,而不必寻找山顶具体的成本值。如下图所示,A+B+C=D,因此只需要计算出三个小段的值进行累加,即求得D,而不必寻找山顶位置的成本。这样,本题所求的最大收益就是各个上升的小段增加的利润之和。 这种解法十分巧妙。
在这里插入图片描述
优化的代码如下:

class Solution {
    public int maxProfit(int[] prices) {
        int maxprofit = 0;
        for (int i = 1; i < prices.length; i++) {
            if (prices[i] > prices[i - 1])
                maxprofit += prices[i] - prices[i - 1];
        }
        return maxprofit;
    }
}

125. Valid Palindrome

Given a string, determine if it is a palindrome, considering only alphanumeric characters and ignoring cases.

Note: For the purpose of this problem, we define empty string as valid palindrome.

Example 1:

Input: “A man, a plan, a canal: Panama”
Output: true

Example 2:

Input: “race a car”
Output: false

分析:此题我的思路是设置两个指针,一头一尾向中间遍历,遇到除字母数字外的字符就移动指针跳过,否则进行判断。注意,对字符是否为数字或字母,这里采用正则表达式进行判断。

优化的代码如下:

class Solution {
    public boolean isPalindrome(String s) {
        char[] sChar = s.toCharArray();
		int start = 0;
		int end = s.length()-1;
		while(start < end) {
            if(!String.valueOf(sChar[end]).matches("[a-zA-Z0-9]")) {
				end--;
			}
            if(!String.valueOf(sChar[start]).matches("[a-zA-Z0-9]")) {
				start++;
			}
			if(String.valueOf(sChar[start]).matches("[a-zA-Z0-9]") && String.valueOf(sChar[end]).matches("[a-zA-Z0-9]")) {
				if(!String.valueOf(sChar[start++]).toLowerCase().equals(String.valueOf(sChar[end--]).toLowerCase())) {
					return false;
				}
			}
		}		
		return true;    
    }
}

136. Single Number

Given a non-empty array of integers, every element appears twice except for one. Find that single one.
Note: Your algorithm should have a linear runtime complexity. Could you implement it without using extra memory?

Example 1:

Input: [2,2,1]
Output: 1

Example 2:

Input: [4,1,2,1,2]
Output: 4

分析:本题利用异或运算来解十分巧妙。异或运算有如下性质:同一个数异或两次等于没有异或:如4 ^ 1 ^ 4 = 1。一个数与0异或的结果为其本身:如4 ^ 0 = 4。因此,可以通过异或运算迅速查找出数组中个数为1的元素。

优化的代码如下:

class Solution {
    public int singleNumber(int[] nums) {
        int res = 0;
        for(int num : nums)
            res ^= num;
        return res;
    }
}

141. Linked List Cycle

Given a linked list, determine if it has a cycle in it.

To represent a cycle in the given linked list, we use an integer pos which represents the position (0-indexed) in the linked list where tail connects to. If pos is -1, then there is no cycle in the linked list.

Example 1:
在这里插入图片描述
Example 2:
在这里插入图片描述
Example 3:
在这里插入图片描述
Follow up:
Can you solve it using O(1) (i.e. constant) memory?

分析:本题主要有两种思路,第一种较为巧妙,推荐使用。
   第一种方法是设置快慢两个指针,慢指针的起始位置为头节点,快指针的起始位置为头节点的后继节点。其中,慢指针每次移动一步,快指针每次移动两步。如果链表有环,那么两个指针终究会相遇;否则,快指针到达链表末尾位置,则说明没有环。
   第二种方法比较直接,即遍历链表中的节点并使用哈希表记录以遍历过的节点,发现重复时,则说明有环。

优化的代码如下:

第一种方法:设置快慢两个指针

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    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;
    }
}

第二种方法:利用哈希表存储遍历过的节点

/**
 * Definition for singly-linked list.
 * class ListNode {
 *     int val;
 *     ListNode next;
 *     ListNode(int x) {
 *         val = x;
 *         next = null;
 *     }
 * }
 */
public class Solution {
    public boolean hasCycle(ListNode head) {
        HashSet<ListNode> set = new HashSet<>();
        while(head != null){
            if(set.contains(head)){
                return true;
            }
            set.add(head);
            head = head.next;
        }
        return false;
    }
}

155. Min Stack

Design a stack that supports push, pop, top, and retrieving the minimum element in constant time.

push(x) – Push element x onto stack.
pop() – Removes the element on top of the stack.
top() – Get the top element.
getMin() – Retrieve the minimum element in the stack.

Example:

MinStack minStack = new MinStack();
minStack.push(-2);
minStack.push(0);
minStack.push(-3);
minStack.getMin(); --> Returns -3.
minStack.pop();
minStack.top(); --> Returns 0.
minStack.getMin(); --> Returns -2.

分析:本题有两种思路,第一种是设置两个栈,第一个栈用于正常的入栈出栈操作,第二个栈用于记录最小值min。其中,在第一个栈进行操作时,判断当前值与min之间的大小,对第二个栈进行操作,最终第二个栈中存放的是一个包含部分元素的有序序列。第二种思路是将最小值也存放在同一个栈中,即在发现新的min时,将当前的min先入栈,再将新的min入栈,同时更新当前min。这样做是为了在当前min出栈后,可以取到它出栈后的新的min。

优化的代码如下:

第一种方法:设置两个stack

class MinStack {

	Stack<Integer> stk1 = new Stack<>();
	Stack<Integer> minStk = new Stack<>();
	
	public void push(int x) {
        stk1.push(x);
        if(minStk.isEmpty() || minStk.peek() >= x) {
        	minStk.push(x);
        }
    }
    
    public void pop() {
        int pop = stk1.pop();
        if(pop == minStk.peek()) {
        	minStk.pop();
        }
    }
    
    public int top() {
        return stk1.peek();
    }
    
    public int getMin() {
        return minStk.peek();
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

第二种方法:只用一个stack,巧妙记录min

class MinStack {

	Stack<Integer> stack = new Stack<>();
	int min = Integer.MAX_VALUE;
	
	public void push(int x) {
		if(x <= min) {
			stack.push(min);
			min = x;
		}
        stack.push(x);
    }
    
    public void pop() {
        if(stack.peek() == min) {
        	stack.pop();
        	min = stack.pop();
        }else {
        	stack.pop();
        }
        
    }
    
    public int top() {
        return stack.peek();
    }
    
    public int getMin() {
        return min;
    }
}

/**
 * Your MinStack object will be instantiated and called as such:
 * MinStack obj = new MinStack();
 * obj.push(x);
 * obj.pop();
 * int param_3 = obj.top();
 * int param_4 = obj.getMin();
 */

167. Two Sum II - Input array is sorted

Given an array of integers that is already sorted in ascending order, find two numbers such that they add up to a specific target number.
The function twoSum should return indices of the two numbers such that they add up to the target, where index1 must be less than index2.

Note:

Your returned answers (both index1 and index2) are not zero-based.
You may assume that each input would have exactly one solution and you may not use the same element twice.

Example:

Input: numbers = [2,7,11,15], target = 9
Output: [1,2]
Explanation: The sum of 2 and 7 is 9. Therefore index1 = 1, index2 = 2.

分析:本题适合使用HashMap,将数组元素的值作为key,元素在数组中的下标作为value。在将数组元素及下标对存储到map的同时,查找map中是否已包含了与之加和为目标值target的元素对,如果已经包含了就返回,否则继续添加。

优化的代码如下:

class Solution {
    public int[] twoSum(int[] numbers,int target){
        HashMap <Integer,Integer> map = new HashMap<>();
        for(int i = 0; i < numbers.length; i++){         
            int temp = target - numbers[i];
            if(map.containsKey(temp)){
                   return new int[] {map.get(temp)+1,i+1};
            }
            map.put(numbers[i],i);
        }
        throw new IllegalArgumentException("No two sum solution");
    }
}

283. Move Zeroes

Given an array nums, write a function to move all 0’s to the end of it while maintaining the relative order of the non-zero elements.

Example:

Input: [0,1,0,3,12]
Output: [1,3,12,0,0]

Note:

You must do this in-place without making a copy of the array.
Minimize the total number of operations.

分析:有两种思路,一种是交换,另一种是末尾填0。

优化的代码如下:

第一种方法:交换

public class Solution {
	public void moveZeroes(int[] nums) {
    	int j = 0;
    	for(int i = 0; i < nums.length; i++) {
        	if(nums[i] != 0) {
            	int temp = nums[j];
            	nums[j] = nums[i];
            	nums[i] = temp;
            	j++;
        	}
    	}
	}
}

第二种方法:末尾填0

class Solution {
    public void moveZeroes(int[] nums) {
        int count = 0;
        for(int i = 0, j = 0; i < nums.length; i++){
            if(nums[i] != 0){
                nums[j++] = nums[i];
            }else{
                count++;
            }
        }
        if(count != 0){
            for(int k = 0; k < count; k++){
                nums[nums.length - 1 - k] = 0;
            }
        }   
    }
}

561. Array Partition I

Given an array of 2n integers, your task is to group these integers into n pairs of integer, say (a1, b1), (a2, b2), …, (an, bn) which makes sum of min(ai, bi) for all i from 1 to n as large as possible.

Example 1:

Input: [1,4,3,2]
Output: 4
Explanation: n is 2, and the maximum sum of pairs is 4 = min(1, 2) + min(3, 4).

Note:

n is a positive integer, which is in the range of [1, 10000].
All the integers in the array will be in the range of [-10000, 10000].

分析:本题理解题意是关键。解法只需要将数组的元素排序,求偶数项的元素之和。

优化的代码如下:

class Solution {
    public int arrayPairSum(int[] nums) {
        int result = 0;
        Arrays.sort(nums);
        for(int i = 0; i < nums.length; i=i+2){
            result += nums[i];
        }    
        return result;
    }
}

709. To Lower Case

Implement function ToLowerCase() that has a string parameter str, and returns the same string in lowercase.

Example 1:

Input: “Hello”
Output: “hello”

Example 2:

Input: “here”
Output: “here”

Example 3:

Input: “LOVELY”
Output: “lovely”

分析:Java语言有toLowerCase()函数可以直接完成大写转为小写的功能。

优化的代码如下:

class Solution {
    public String toLowerCase(String str) {
		return str.toLowerCase();
    }
}

717. 1-bit and 2-bit Characters

We have two special characters. The first character can be represented by one bit 0. The second character can be represented by two bits (10 or 11).
Now given a string represented by several bits. Return whether the last character must be a one-bit character or not. The given string will always end with a zero.

Example 1:

Input: bits = [1, 0, 0]
Output: True
Explanation: The only way to decode it is two-bit character and one-bit character. So the last character is one-bit character.

Example 2:

Input: bits = [1, 1, 1, 0]
Output: False
Explanation: The only way to decode it is two-bit character and two-bit character. So the last character is NOT one-bit character.

Note:

1 <= len(bits) <= 1000.
bits[i] is always 0 or 1.

分析:第一种方法可以通过指针的移动来判断。指针的初始指向数组的第一个元素,若当前元素为1,则指针向后移动2步;否则向后移动1步。最后,若指针停留在数组的最后一个元素,则证明最后一个字符是单字符;否则它是双字符。
   第二种方法可以从右侧执行线性扫描,找到倒数第二个0。直至倒数第二个0,一定是一个字符的结束。只需要记录倒数第二个0和末尾最后一个0之间的1的个数,若是奇数个1,证明最后一个字符是单字符;否则它是双字符。

优化的代码如下:

第一种方法:指针移动

class Solution {
    public boolean isOneBitCharacter(int[] bits) {
        int i = 0;
        while (i < bits.length - 1) {
            i += bits[i] + 1;
        }
        return i == bits.length - 1;
    }
}

第二种方法:找倒数第二个0

class Solution {
    public boolean isOneBitCharacter(int[] bits) {
        int i = bits.length - 2;
        while (i >= 0 && bits[i] > 0) i--;
        return (bits.length - i) % 2 == 0;
    }
}

771. Jewels and Stones

You’re given strings J representing the types of stones that are jewels, and S representing the stones you have. Each character in S is a type of stone you have. You want to know how many of the stones you have are also jewels.
The letters in J are guaranteed distinct, and all characters in J and S are letters. Letters are case sensitive, so “a” is considered a different type of stone from “A”.

Example 1:

Input: J = “aA”, S = “aAAbbbb”
Output: 3

Example 2:

Input: J = “z”, S = “ZZ”
Output: 0

Note:

S and J will consist of letters and have length at most 50.
The characters in J are distinct.

分析:可以将String转成char数组,然后遍历char数组。

优化的代码如下:

class Solution {
    public int numJewelsInStones(String J, String S) {
        int result = 0;
        char [] a = S.toCharArray();
        char [] b = J.toCharArray();
        for(int i = 0; i < b.length; i++){
            for(int j = 0; j < a.length; j++){
                if(a[j] == b[i]){
                    result++;
                }
            }
        }
        
        return result;
    }
}

832. Flipping an Image

Given a binary matrix A, we want to flip the image horizontally, then invert it, and return the resulting image.
To flip an image horizontally means that each row of the image is reversed. For example, flipping [1, 1, 0] horizontally results in [0, 1, 1].
To invert an image means that each 0 is replaced by 1, and each 1 is replaced by 0. For example, inverting [0, 1, 1] results in [1, 0, 0].

Example 1:

Input: [[1,1,0],[1,0,1],[0,0,0]]
Output: [[1,0,0],[0,1,0],[1,1,1]]
Explanation: First reverse each row: [[0,1,1],[1,0,1],[0,0,0]]. Then, invert the image: [[1,0,0],[0,1,0],[1,1,1]]

Example 2:

Input: [[1,1,0,0],[1,0,0,1],[0,1,1,1],[1,0,1,0]]
Output: [[1,1,0,0],[0,1,1,0],[0,0,0,1],[1,0,1,0]]
Explanation: First reverse each row: [[0,0,1,1],[1,0,0,1],[1,1,1,0],[0,1,0,1]]. Then invert the image: [[1,1,0,0],[0,1,1,0],[0,0,0,1],[1,0,1,0]]

Notes:

1 <= A.length = A[0].length <= 20
0 <= A[i][j] <= 1

分析:此题除暴力解法之外,可以稍加优化。通过观察不难发现,在二维数组中的同一行中,第n个元素和倒数第n个元素若为不同,最终相应两个位置的结果不变;第n个元素和倒数第n个元素若为相同,最终相应两个位置的结果改变。注意,若数组A此行元素的个数为奇数,需将中间位置的元素改变。

优化的代码如下:

class Solution {
    public int[][] flipAndInvertImage(int[][] A) {
        int n = A.length;
        for(int i = 0; i < n; i++){
            for(int j = 0; j < n / 2; j++){
                if(A[i][n - 1 - j] == A[i][j]){
                    A[i][j] = 1 - A[i][j];
                    A[i][n - 1 - j] = 1 - A[i][n - 1 - j];
                }
            }
            if(n%2 != 0){
                A[i][n/2] = 1 - A[i][n/2];
            }
        }
        return A;
    }
}

905. Sort Array By Parity

Given an array A of non-negative integers, return an array consisting of all the even elements of A, followed by all the odd elements of A.
You may return any answer array that satisfies this condition.

Example 1:

Input: [3,1,2,4]
Output: [2,4,3,1]
The outputs [4,2,3,1], [2,4,1,3], and [4,2,1,3] would also be accepted.

Note:

1 <= A.length <= 5000
0 <= A[i] <= 5000

分析:此题可以使用两个指针,而不创建新的数组存储最终结果。一个指针用于遍历整改数组,另一个指针用于指向存储偶数元素的位置。从头开始遍历,若为偶数则做交换,使其置于数组的前部分。

优化的代码如下:

class Solution {
    public int[] sortArrayByParity(int[] A) {
        int temp = 0;
        for(int i = 0, j = 0; j < A.length; j++){
            if(A[j] % 2 == 0){
                temp = A[i];
                A[i++] = A[j];
                A[j] = temp;
            }
        }
        return A;
    }
}

929. Unique Email Addresses

Every email consists of a local name and a domain name, separated by the @ sign.
For example, in [email protected], alice is the local name, and leetcode.com is the domain name.
Besides lowercase letters, these emails may contain ‘.‘s or ‘+‘s.
If you add periods (’.’) between some characters in the local name part of an email address, mail sent there will be forwarded to the same address without dots in the local name. For example, "[email protected]" and "[email protected]" forward to the same email address. (Note that this rule does not apply for domain names.)
If you add a plus (’+’) in the local name, everything after the first plus sign will be ignored. This allows certain emails to be filtered, for example [email protected] will be forwarded to [email protected]. (Again, this rule does not apply for domain names.)
It is possible to use both of these rules at the same time.
Given a list of emails, we send one email to each address in the list. How many different addresses actually receive mails?

Example 1:

Input: [“[email protected]”,“[email protected]”,“[email protected]”]
Output: 2
Explanation: "[email protected]" and "[email protected]" actually receive mails

Note:

1 <= emails[i].length <= 100
1 <= emails.length <= 100
Each emails[i] contains exactly one ‘@’ character.

分析:本题的主要目的是熟悉String的相关方法,并灵活的运用。

优化的代码如下:

我的代码:

class Solution {
    public int numUniqueEmails(String[] emails) {
        int result = 0;
        for(int i = 0; i < emails.length; i++){
            String [] s = emails[i].split("@");
            if(s[0].contains(".")){
                s[0] = s[0].replace(".","");
            }
            if(s[0].contains("+")){
                int temp = s[0].indexOf("+");
                s[0] = s[0].substring(0,temp);
            }
            emails[i] = s[0] + "@" + s[1];
        }      
        HashSet set = new HashSet();
        for(int i = 0; i < emails.length; i++){
            set.add(emails[i]);
        }
        result = set.size();
        return result;
    }
}

答案参考的代码:

class Solution {
    public int numUniqueEmails(String[] emails) {
        Set<String> seen = new HashSet();
        for (String email: emails) {
            int i = email.indexOf('@');
            String local = email.substring(0, i);
            String rest = email.substring(i);
            if (local.contains("+")) {
                local = local.substring(0, local.indexOf('+'));
            }
            local = local.replaceAll(".", "");
            seen.add(local + rest);
        }
        return seen.size();
    }
}

914. X of a Kind in a Deck of Cards

In a deck of cards, each card has an integer written on it.
Return true if and only if you can choose X >= 2 such that it is possible to split the entire deck into 1 or more groups of cards,
where:
  Each group has exactly X cards.
  All the cards in each group have the same integer.

Example 1:

Input: [1,2,3,4,4,3,2,1]
Output: true
Explanation: Possible partition [1,1],[2,2],[3,3],[4,4]

Example 2:

Input: [1,1,1,2,2,2,3,3]
Output: false
Explanation: No possible partition.

Example 3:

Input: [1]
Output: false
Explanation: No possible partition.

Example 4:

Input: [1,1]
Output: true
Explanation: Possible partition [1,1]

Example 5:

Input: [1,1,2,2,2,2]
Output: true
Explanation: Possible partition [1,1],[2,2],[2,2]

Note:

1 <= deck.length <= 10000
0 <= deck[i] < 10000

分析:本题的思路是:第一步计算出各个元素出现的次数;第二步求这些次数的最大公约数。如果它们的最大公约数大于1,则返回true,否则返回false。

其中,第二步求最大公约数是此题的亮点,我学会了用递归的思想求取两个数的最大公约数:
   public int gcd(int a, int b) { return b > 0 ? gcd(b, a % b) : a; }

优化的代码如下:

class Solution {
    public boolean hasGroupsSizeX(int[] deck) {
        HashMap<Integer, Integer> count = new HashMap<>();
        int divisor = 0;
        for (int i : deck)
            count.put(i, count.getOrDefault(i, 0) + 1);
        for (int i : count.values())
            divisor = gcd(i, divisor);
        return divisor > 1;
    }
    public int gcd(int a, int b) {
        return b > 0 ? gcd(b, a % b) : a;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章