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;
    }
}
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章