www1350 / javaweb

http://www1350.github.io/
31 stars 5 forks source link

菜鸡的leetcode之路 #121

Open www1350 opened 6 years ago

www1350 commented 6 years ago

想刷的清单: 1,2,10,13,15,17,20,23,25,26,28,33,38,43,44,49,50,56,57,67,68,69,71,75,76 78,79,80,85,88,90,91,98,102,117,121,125,127,128,133,139,146,157,158,161 168,173,200,206,208,209,210,211,215,218,221,234,235,236,238,252,253,257 261,265,269,273,274,275,277,278,282,283,285,286,297,301,311,314,325,334 341,377,380,398,404,410,461,477,494,523,525,534,535,543,554

  1. Two Sum

地址:https://leetcode.com/problems/two-sum/description/ 问题: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].

方案: 两遍循环,O(n^2)

   public int[] twoSum(int[] nums, int target) {
        int size = nums.length;
        int[] res = new int[2];
        for(int i=0;i<size-1;i++){
            for(int j=i+1;j<size;j++){
                if(nums[i]+nums[j]==target){
                    res[0]=i;
                    res[1]=j;
                    return res;
                }

            }
        }
        return res;
    }

方案2: 分析,本题重点1.数组可能是乱序的2.不会有相同的值 抓住值都不同,可以反过来想,可以用值做唯一去查找下标 把数组放入hashmap里面,<值,下标>,查找的时候只要循环第一个数,里层因为hashmap的查找效率是O(1),所以这个复杂度就只有O(n)

   public int[] twoSum(int[] nums, int target) {
        int size = nums.length;
        int[] res = new int[2];
        Map<Integer,Integer> map = new HashMap<>();
        for(int i=0;i<size;i++){
            map.put(nums[i],i);
        }
        for(int i=0;i<size-1;i++){
            int find = target - nums[i];
            Integer ind = map.get(find);
            if (ind != null && ind > i){
                res[0]=i;
                res[1]=ind;
                return res;

            }
        }
        return res;
    }
  1. Add Two Numbers

问题:You are given two non-empty linked lists representing two non-negative integers. The digits are stored in reverse order and each of their nodes contain a single digit. Add the two numbers and return it as a linked list. You may assume the two numbers do not contain any leading zero, except the number 0 itself.

Example Input: (2 -> 4 -> 3) + (5 -> 6 -> 4) Output: 7 -> 0 -> 8 Explanation: 342 + 465 = 807.

方案: 这个主要还是考察链表这个数据结构,直接上代码吧。比较简单,时间复杂度O(n),要注意的是最后可能会进位

public ListNode addTwoNumbers(ListNode l1, ListNode l2) {
        int pre = 0;

        ListNode head =  new ListNode(-1);
        ListNode e = head;
        while(l1!=null||l2!=null){
            int v1=0;
            int v2=0;
            v1= l1==null ? 0 : l1.val;
            v2= l2==null ? 0 : l2.val;
            int temp =  v1+v2+pre;
            pre = temp / 10 ;
            e.next = new  ListNode(temp % 10) ;
            e=e.next;
            if(l1!=null)
                l1 = l1.next;
            if(l2!=null)
                l2 = l2.next;
        }
        if( pre > 0 )
            e.next = new  ListNode(1) ;

        return head.next;

    }

  public  class  ListNode {
        int val;
        ListNode next;
        ListNode(int x) { val = x; }
    }
  1. Regular Expression Matching 问题:Implement regular expression matching with support for '.' and '*'.

'.' Matches any single character. '*' Matches zero or more of the preceding element.

The matching should cover the entire input string (not partial).

The function prototype should be: bool isMatch(const char s, const char p)

Some examples: isMatch("aa","a") → false isMatch("aa","aa") → true isMatch("aaa","aa") → false isMatch("aa", "a") → true isMatch("aa", ".") → true isMatch("ab", ".") → true isMatch("aab", "ca*b") → true

题目分析,'.' 可以记成匹配任意字符,'*'则要和他前导的字符一起看,可以匹配0个或者更多前导

方案1: 递归来做,考虑s和p两个数组 1 p长度为0 只有s长度也是0的时候返回true否则是false 2 p长度为1 只有s长度也是1而且p和s一样或者p是'.'的时候 3 p长度大于2
p的第二个字符不是'' 如果s长度是0返回false,如果s第一个字符和p第一个字符相等或者p第一个字符是'.'的时候,递归判断s和p第二个字符后否则false p第二个字符是'' 如果第一个字符相同,递归判断s和p从第二个字符开始

public static boolean isMatch(String s, String p) {
        if ( p.isEmpty() ){
            return s.isEmpty();
        }
        if ( p.length() == 1 ){
            return s.length() == 1 && ( p.charAt(0) == s.charAt(0) || p.charAt(0) == '.' );
        }
        if (p.charAt(1) == '*'){
            while (s.length()>0 && ( p.charAt(0) == s.charAt(0) || p.charAt(0) == '.' )){
                if (isMatch(s,p.substring(2))){
                    return true;
                }
                s = s.substring(1);
            }
            return isMatch(s,p.substring(2));

        }else{
            if (s.isEmpty()) {
                return false;
            }else{
                return ( p.charAt(0) == s.charAt(0) || p.charAt(0) == '.' )
                    && isMatch(s.substring(1),p.substring(1));
            }
        }

    }

可以看出复杂度挺高的

方案2: DP 两个数组s,p分别代表字符串s和p dp[][]二维数组 dp[i][j] 代表s[0-i]和p[0-j]是否匹配最后只要看dp[s.length-1][p.length-1]是不是true就行了

public static boolean isMatch(String s, String p) {
        int m = s.length();
        int n = p.length();
        boolean dp[][] = new boolean[m+1][n+1];
        dp[0][0] = true;
        for (int i = 1; i <= m; i++)
            dp[i][0] = false;
        for (int j = 1; j <= n; j++)
            dp[0][j] = j > 1 && '*' == p.charAt(j-1) && dp[0][j - 2];

        for(int i=1 ; i <= m; i++ ){
            for (int j = 1; j <= n; j++){
                if (p.charAt(j-1) == '*'){
                    dp[i][j] = dp[i][j-2] || (s.charAt(i-1) == p.charAt(j-2) || '.' ==p.charAt(j-2)) && dp[i-1][j];
                }else{
                    dp[i][j] = dp[i-1][j-1] && (s.charAt(i-1) == p.charAt(j-1) || '.' == p.charAt(j-1));
                }
            }
        }

        return dp[m][n];
    }
  1. Roman to Integer

https://leetcode.com/problems/roman-to-integer/description/ 问题:Given a roman numeral, convert it to an integer. Input is guaranteed to be within the range from 1 to 3999.

分析:输入一个罗马数字,输出转化为整数,我们先来学习下罗马数字

基本字符 I V X L C D M
1 5 10 50 100 500 1000
  1. 相同的数字连写、所表示的数等于这些数字相加得到的数、如:Ⅲ=3;
  2. 小的数字在大的数字的右边、所表示的数等于这些数字相加得到的数、 如:Ⅷ=8、Ⅻ=12;
  3. 小的数字(限于 I、X 和 C)在大的数字的左边、所表示的数等于大数减小数得到的数、如:Ⅳ=4、Ⅸ=9;
  4. 正常使用时、连写的数字重复不得超过三次;
  5. 在一个数的上面画一条横线、表示这个数扩大 1000 倍。

有两条须注意掌握:

  1. 基本数字 Ⅰ、X 、C 中的任何一个、自身连用构成数目、或者放在大数的右边连用构成数目、都不能超过三个;放在大数的左边只能用一个;
  2. 不能把基本数字 V 、L 、D 中的任何一个作为小数放在大数的左边采用相减的方法构成数目;放在大数的右边采用相加的方式构成数目、只能使用一个;

·个位数举例 Ⅰ-1、Ⅱ-2、Ⅲ-3、Ⅳ-4、Ⅴ-5、Ⅵ-6、Ⅶ-7、Ⅷ-8、Ⅸ-9 ·十位数举例 Ⅹ-10、Ⅺ-11、Ⅻ-12、XIII-13、XIV-14、XV-15、XVI-16、XVII-17、XVIII-18、XIX-19、XX-20、XXI-21、XXII-22、XXIX-29、XXX-30、XXXIV-34、XXXV-35、XXXIX-39、XL-40、L-50、LI-51、LV-55、LX-60、LXV-65、LXXX-80、XC-90、XCIII-93、XCV-95、XCVIII-98、XCIX-99 ·百位数举例 C-100、CC-200、CCC-300、CD-400、D-500、DC-600、DCC-700、DCCC-800、CM-900、CMXCIX-999 ·千位数举例 M-1000、MC-1100、MCD-1400、MD-1500、MDC-1600、MDCLXVI-1666、MDCCCLXXXVIII-1888、MDCCCXCIX-1899、MCM-1900、MCMLXXVI-1976、MCMLXXXIV-1984、MCMXC-1990、MM-2000、MMMCMXCIX-3999

方案: 其实只是罗马转数字的话很简单,只要当前的比后面的大就用加法,比后面的小用减法

public int romanToInt(String s) {
        int total = 0;
        for(int i=0;i<s.length()-1;i++){
            int now = getNumber(s.charAt(i));
            if (now>=getNumber(s.charAt(i+1))){
                total = total +now;
            }else{
                total = total -now;
            }
        }
        total += getNumber(s.charAt(s.length()-1));
        return total;

    }

    public static int getNumber(char a){
        int number = 0;
        switch (a){
            case 'I':
                return 1;
            case 'V':
                return 5;
            case 'X':
                return 10;
            case 'L':
                return 50;
            case 'C':
                return 100;
            case 'D':
                return 500;
            case 'M':
                return 1000;
            default:
                break;
        }
        return number;
    }
  1. 3Sum https://leetcode.com/problems/3sum/description/ 问题:Given an array S of n integers, are there elements a, b, c in S 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.

For example, given array S = [-1, 0, 1, 2, -1, -4],

A solution set is: [ [-1, 0, 1], [-1, -1, 2] ]

分析: 这题乍看之下好像很简单,循环前两个元素a,b,第三个元素用-(a+b)使用二分查找找出后面是否存在,存在则可以记录下来。然而有个坑,如果出现[0,0,0,0,0,0] 结果应该是[[0,0,0]]但是使用这个算法会出现很多[0,0,0],但是如果算出来后去重,复杂度也非常高。如果数组从小到大排序,相同的都在一起了,现在只要跳过上一次拿过的,比如上次a拿过0就不拿了,b拿过0也不拿了,既然a和b都和上次不同,那么c也会和上次不同。

方案1: 复杂度其实也是蛮高,如果数据全部不相同,高达 O(n^2 x logN)

public List<List<Integer>> threeSum(int[] nums) {
        //a+b=-c
        Arrays.sort(nums);
        //-4,-1,-1,0,1,2
        List allList = new ArrayList();
        int aa = Integer.MAX_VALUE;
        for(int i=0;i<nums.length-1;i++){
            if ( nums[i] ==aa ) continue;
            int bb = Integer.MAX_VALUE;
            int cc = nums.length;
            for (int j=i+1;j<nums.length;j++){
                if ( nums[j] ==bb || cc<=j) continue;
                int c = -(nums[i]+nums[j]);
                int a = Arrays.binarySearch(nums,j+1,cc,c);
                if (a>j) {
                    List e = new ArrayList();
                    e.add(nums[i]);
                    e.add(nums[j]);
                    e.add(c);
                    allList.add(e);
                    cc = a;
                }
                bb = nums[j];
            }
            aa = nums[i];
        }
        return allList;
    }

方案2: O(n^2)

https://discuss.leetcode.com/topic/8125/concise-o-n-2-java-solution/20

  1. Letter Combinations of a Phone Number

https://leetcode.com/problems/letter-combinations-of-a-phone-number/description/ 问题:Given a digit string, return all possible letter combinations that the number could represent.

A mapping of digit to letters (just like on the telephone buttons) is given below. image

Input:Digit string "23" Output: ["ad", "ae", "af", "bd", "be", "bf", "cd", "ce", "cf"]. Note: Although the above answer is in lexicographical order, your answer could be in any order you want.

  1. Valid Parentheses

    https://leetcode.com/problems/valid-parentheses/description/

    问题: Given a string containing just the characters '(', ')', '{', '}', '[' and ']', determine if the input string is valid. The brackets must close in the correct order, "()" and "()[]{}" are all valid but "(]" and "([)]" are not.

方案: 水题,栈解决

public boolean isValid(String s) {
        int size = s.length();
        Stack<Character> stack = new Stack<Character>();
        for(int i=0;i<size;i++){
            if ('(' == s.charAt(i) || '{' == s.charAt(i) ||'[' == s.charAt(i)){
                stack.push(s.charAt(i));
            }else{
                if (stack.isEmpty()) return false;
                char c = stack.pop().charValue();
                switch (s.charAt(i)){
                    case ')':
                        if ('(' != c){
                            return false;
                        }
                        break;
                    case '}':
                        if ('{' != c){
                            return false;
                        }
                        break;
                    case ']':
                        if ('[' != c){
                            return false;
                        }
                        break;
                    default:
                        return  false;
                }
            }
        }
        if (stack.isEmpty()) return true;
        return false;

    }
  1. Merge k Sorted Lists

https://leetcode.com/problems/merge-k-sorted-lists/description/ 问题: Merge k sorted linked lists and return it as one sorted list. Analyze and describe its complexity.

方案1(超时错误-时间复杂度过高): 每个链表取头去比较,拿最小的

public ListNode mergeKLists(ListNode[] lists) {
        ListNode head = new ListNode(-1);
        ListNode ea = head;

        while (true) {
            int idx = -1;
            int tmp = Integer.MAX_VALUE;
            for (int i = 0; i < lists.length; i++) {
                if (lists[i] == null) {
                    continue;
                }
                if (lists[i].val < tmp) {
                    idx = i;
                    tmp = lists[i].val;
                }
            }
            if (idx < 0) break;
            ea.next = lists[idx];
            lists[idx] = lists[idx].next;
            ea = ea.next;
            ea.next = null;
        }
        return head.next;
    }

方案2: 每次取链表的头,被取了就放入下一个。放入大跟堆里面

    public ListNode mergeKLists(ListNode[] lists) {
        ListNode head = new ListNode(-1);
        ListNode eNode = head;
        int size = lists.length;
        Queue<ListNode> queue = new PriorityQueue<ListNode>(new Comparator<ListNode>() {
            @Override
            public int compare(ListNode o1, ListNode o2) {
                return o1.val-o2.val;
            }
        });
        for(int i=0;i<size;i++){
            if (lists[i] != null)
                queue.offer(lists[i]);
        }
        while ( !queue.isEmpty() ){
            eNode.next = queue.poll();
            eNode = eNode.next;
            if (eNode.next != null) {
                queue.offer(eNode.next);
            }
        }

        return head.next;
    }

25. Reverse Nodes in k-Group

https://leetcode.com/problems/reverse-nodes-in-k-group/description/

问题:Given a linked list, reverse the nodes of a linked list k at a time and return its modified list.

k is a positive integer and is less than or equal to the length of the linked list. If the number of nodes is not a multiple of k then left-out nodes in the end should remain as it is.

You may not alter the values in the nodes, only nodes itself may be changed.

Only constant memory is allowed.

For example, Given this linked list: 1->2->3->4->5

For k = 2, you should return: 2->1->4->3->5

For k = 3, you should return: 3->2->1->4->5

方案1: 先得到链表长度,把每k个使用头插法建立新链表,然后把剩余的连接起来

public ListNode reverseKGroup(ListNode head, int k) {

        int length = getLength(head);
        ListNode result = new ListNode(-1);
        ListNode resultTmp = result;
        for(;length>=k;length-=k){
            ListNode pHead = null;
            for(int i=0;i<k;i++){
                ListNode tmp = head;
                head =head.next;
                tmp.next = pHead;
                pHead = tmp;
            }
            resultTmp.next = pHead;
            while (resultTmp.next !=null){ resultTmp = resultTmp.next;}
        }
        resultTmp.next = head;
        return result.next;

    }

       public static int getLength(ListNode head){
        ListNode tmp = head;
        int i=0;
        while (tmp != null) {
            tmp = tmp.next;
            i++;
        }
        return i;
    }

26. Remove Duplicates from Sorted Array

https://leetcode.com/problems/remove-duplicates-from-sorted-array/description/

问题:

Given a sorted array, 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:

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 new length.

水题,不讲

 public int removeDuplicates(int[] nums) {
        int t = 1;

        for(int i=1;i<nums.length;i++){
            if (nums[i] != nums[i-1]) {
                nums[t] = nums[i];
                t++;
            }
        }
        return t;
    }

28. Implement strStr()

https://leetcode.com/problems/implement-strstr/description/

问题: 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

public int strStr(String haystack, String needle) {
        int hySize = haystack.length();
        int ndSize = needle.length();
        if ("".equals(needle)) return 0;
        //abcsdfdwsdwd
        //dwd
        for(int i=0;i<hySize;i++){
            //剩余长度根本不可能匹配,跳出
            if (hySize-i<ndSize) break;
            //包含回溯
            for(int j=0;j<ndSize;j++){
                if (i+j>=hySize) break;
                if (haystack.charAt(i+j)!= needle.charAt(j)) break;
                if (j == ndSize -1) {
                    return i;
                }
            }
        }
        return -1;

    }

33. Search in Rotated Sorted Array

https://leetcode.com/problems/search-in-rotated-sorted-array/description/

问题: Suppose an array sorted in ascending order is rotated at some pivot unknown to you beforehand.

(i.e., 0 1 2 4 5 6 7 might become 4 5 6 7 0 1 2).

You are given a target value to search. If found in the array return its index, otherwise return -1.

You may assume no duplicate exists in the array.

方案1: 遍历,找到直接返回下标,复杂度O(n)

方案2: 改造二分查找,只有中间和目标同时大于或者小于第一个元素,还用二分法,否则就下标挪动一位

public int search(int[] nums, int target) {

        int low = 0;
        int high = nums.length - 1;

        while (low <= high) {
            int mid = (low + high) >>> 1;
            double midVal = (nums[mid] < nums[0]) == (target < nums[0])
                    ? nums[mid]
                    : target < nums[0] ? Double.NEGATIVE_INFINITY : Double.POSITIVE_INFINITY;

            if (midVal < target)
                low = mid + 1;
            else if (midVal > target)
                high = mid - 1;
            else
                return mid; // key found
        }
        if(low>-1) return -1;
        else
        return -(low + 1);  // key not found.

    }

38. Count and Say

https://leetcode.com/problems/count-and-say/description/

The count-and-say sequence is the sequence of integers with the first five terms as following:

  1. 1
  2. 11
  3. 21
  4. 1211
  5. 111221 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, 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"

方案1: 递归,结果居然效率还挺高,不能理解

    public String countAndSay(int n) {

        if (n == 1) return "1";
        String tmp = countAndSay(n-1);
        char[] tt = new char[tmp.length()*2];
        char a = tmp.charAt(0);
        int k=0;
        int t = 1;
        for(int i=1;i<tmp.length();i++){
            if (a != tmp.charAt(i)){
                tt[k++] = (char) (t+'0');
                tt[k++] = a;
                t = 1;
                a = tmp.charAt(i);
            }else{
                t++;
            }
        }
        tt[k++] = (char) (t+'0');
        tt[k++] = a;
        return String.copyValueOf(tt,0,k);

    }