zoukankan      html  css  js  c++  java
  • leetCode解题报告5道题(九)

    题目一:Combinations

    Given two integers n and k, return all possible combinations of k numbers out of 1 ... n.

    For example,
    If n = 4 and k = 2, a solution is:

    [
      [2,4],
      [3,4],
      [2,3],
      [1,2],
      [1,3],
      [1,4],
    ]

    分析:

    题意给我们一个数字n, 和一个数字k,让我们求出从 1~~n中取出k个数所能得到的组合数

    所以这个题目给我们的第一感觉就是用递归是最方便的了,咱试试递归的方法哈。假设读者对递归方法有疑问,能够看看我之前总结的一个递归算法的集合。

    本文专注于<递归算法和分治思想>

    AC代码:

    public class Solution {
        //终于结果
        private ArrayList<ArrayList<Integer>> arrays = new ArrayList<ArrayList<Integer>>();
        
        public ArrayList<ArrayList<Integer>> combine(int n, int k) {
            //把组合设想成仅仅能升序的话,能做开头的数字仅仅有 1 ~ n-k+1 
            for (int i=1; i<=n-k+1; ++i){
                ArrayList<Integer> list = new ArrayList<Integer>();
                list.add(i);
                cal(list, i+1, n, k-1); //递归
            }
            return arrays;
        }
        public void cal(ArrayList<Integer> list, int start, int end, int k){
            //k==0表示这次list组合满足条件了
            if (k == 0){
                //copy
                ArrayList<Integer> result = new ArrayList<Integer>(list);
                arrays.add(result);
            }
            //循环递归调用
            for (int i=start; i<=end; ++i){
                list.add(i);
                cal(list, i+1, end, k-1);
                list.remove(list.size()-1);
            }
        }
    }

    题目二:Search a 2D Matrix

    Write an efficient algorithm that searches for a value in an m x n matrix. This matrix has the following properties:

    • Integers in each row are sorted from left to right.
    • The first integer of each row is greater than the last integer of the previous row.

    For example,

    Consider the following matrix:

    [
      [1,   3,  5,  7],
      [10, 11, 16, 20],
      [23, 30, 34, 50]
    ]
    

    Given target = 3, return true.

    分析:这道题目是剑指Offer上的老题目咯,可是解题的思路挺巧妙。本来不想把这题写在博文里的,后来想想或许有些同学没看过剑指Offer, 后续由于这题而去看下这本挺不错的书哈,于是把这题写在博文里了。并附上剑指offer的下载地址(http://download.csdn.net/detail/u011133213/7268315),这题便不做具体介绍。


    AC代码:(复杂度O(m+n))

    public class Solution {
        public boolean searchMatrix(int[][] matrix, int target) {
            int m = matrix.length;
            int n = matrix[0].length;
            int row = 0;
            int col = n - 1;
            while (m > row && col >= 0){
                if (target == matrix[row][col]){
                    return true;
                }
                if (target > matrix[row][col]){
                    row++;//往下一行搜索
                }else if (target < matrix[row][col]){
                    col--;//往左一列搜索
                }
            }
            return false;
        }
    }


    题目三:Scramble String

    Given a string s1, we may represent it as a binary tree by partitioning it to two non-empty substrings recursively.

    Below is one possible representation of s1 = "great":

        great
       /    
      gr    eat
     /     /  
    g   r  e   at
               / 
              a   t
    

    To scramble the string, we may choose any non-leaf node and swap its two children.

    For example, if we choose the node "gr" and swap its two children, it produces a scrambled string "rgeat".

        rgeat
       /    
      rg    eat
     /     /  
    r   g  e   at
               / 
              a   t
    

    We say that "rgeat" is a scrambled string of "great".

    Similarly, if we continue to swap the children of nodes "eat" and "at", it produces a scrambled string "rgtae".

        rgtae
       /    
      rg    tae
     /     /  
    r   g  ta  e
           / 
          t   a
    

    We say that "rgtae" is a scrambled string of "great".

    Given two strings s1 and s2 of the same length, determine if s2 is a scrambled string of s1.

    分析:

    这道题目的题意相信大家应该都看得懂,仅仅是做起来的话有些蛋疼.

    我一開始用暴力法TLE,之后用DP才干够的.

    详细看代码:

    暴力法TLE:

    public class Solution {
        public boolean isScramble(String s1, String s2) {
            
            if (s1 == null || s2 == null)
                return false;
            if (s1.equals(s2))
                return true;
            int len1 = s1.length();   
            int len2 = s2.length();
            if (len1 != len2)
                return false;
            int[] hash = new int[26];
            for (int i=0; i<len1; ++i){
                hash[s1.charAt(i) - 'a']++;
            }
            for (int i=0; i<len2; ++i){
                hash[s2.charAt(i) - 'a']--;
            }
            for (int i=0; i<26; ++i){
                if (hash[i] != 0)
                    return false;
            }
            
            for (int i=1; i<len1; ++i){
                boolean flags1 = (isScramble(s1.substring(0,i), s2.substring(0,i)) && isScramble(s1.substring(i,len1), s2.substring(i,len2)));
                boolean flags2 = (isScramble(s1.substring(0,i), s2.substring(len2-i,len2)) && isScramble(s1.substring(i,len1), s2.substring(0,len2-i)));
                if (flags1 && flags2){
                    return true;
                }
            }
            return false;
        }
    }

    DP动态规划:

    设数组flags[len][len][len]来存储每个状态信息.

    如flags[i][j][k] 表示s1字符串的第i个位置開始的k个字符和s2字符串的第j个位置開始的k个字符 是否满足scramble string 

    满足:flags[i][j][k] == true

    不满足: flags[i][j][k] == false

    那么题目所要的终于结果的值事实上就相当于是flags[0][0][len]的值了

    那么状态转移方程是什么呢?

    归纳总结法

    假设k==1:

    flags[i][j][1] 就相当于 s1的第i个位置起,取1个字符。s2的第j个位置起,取1个字符。那假设要使Scramble String成立的话,那么就仅仅能是这两个字符相等了, s1.charAt(i) == s2.charAt(j)

    因此 flags[i][j][1] = s1.charAt(i) == s2.charAt(j);


    假设k==2:

    flags[i][j][2] 就相当于 s1的第i个位置起,取2个字符。s2的第j个位置起,取2个字符。那假设要使Scramble String成立的话,那么情况有下面两种

    一种是flags[i][j][1] && flags[i+1][j+1][1] (就是两个位置的字符都相等 S1="TM" S2="TM")

    一种是flags[i][j+1][1] && flags[i+1][j][1] (两个位置的字符刚好对调位置 S1="TM" S2="MT")


    假设k==n:

    设个变量为x

    flags[i][j][n] =( (flags[i][j][x] && flags[i+x][j+x][k-x])  [第一种情况]

     || (flags[i][j+k-x][x] && flags[i+x][j][k-x]) );  [另外一种情况]


    AC代码:

    public class Solution {
        public boolean isScramble(String s1, String s2) {
            
            if (s1 == null || s2 == null)
                return false;
            if (s1.equals(s2))
                return true;
            int len1 = s1.length();   
            int len2 = s2.length();
            if (len1 != len2)
                return false;
            int len = len1;
            boolean[][][] flags= new boolean[len+1][len+1][len+1];
            for (int t=1; t<=len; ++t){
                for (int i=0; i<=len-t; ++i){
                    for (int j=0; j<=len-t; ++j){
                        if (t == 1){
                            flags[i][j][t] = (s1.charAt(i) == s2.charAt(j));
                        }else{
                            for (int k=1; k<t; ++k){
                                if (flags[i][j][t] == true){
                                    break;
                                }else{
                                    if ((flags[i][j][k] && flags[i+k][j+k][t-k])
                                        || (flags[i][j+t-k][k] && flags[i+k][j][t-k])){
                                        flags[i][j][t] = true;
                                    }
                                }
                            }
                        }
                    }
                }
            }
            return flags[0][0][len];
        }
    }


    题目四:

    Rotate List

     

    Given a list, rotate the list to the right by k places, where k is non-negative.

    For example:
    Given 1->2->3->4->5->NULL and k = 2,
    return 4->5->1->2->3->NULL.

    分析:

    题意要求我们依据所给出的k值,把从最后一个非空结点向前的k个结点移动到链表的开头,又一次组成一个新的链表之后返回。

    这道题目有点像经典的面试题“仅仅遍历一次,怎样找到链表倒数的第K个结点”,採用的是两个指针不一样的起始位置,一个指针从head開始出发,还有一个指针先让它走K步,当第2个指针为Null的时候,则第一个指针所指向的就是倒数第K个的值。

    同理:

    这里我们用两个指针就能够方便地搞定这个题目了,可是须要注意的是,这道题目

    假设K大于了链表长度,比方K=3,Len=2的话,假设K步我们还没走完就碰到了Null结点,那么再从head開始走剩下的。直到K==0;


    AC代码:

    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) {
     *         val = x;
     *         next = null;
     *     }
     * }
     */
    public class Solution {
        public ListNode rotateRight(ListNode head, int n) {
            ListNode firstNode = head;//新链表的第一个结点
            ListNode kstepNode = head;//走了k步的指针
            ListNode preFirstNode = new ListNode(-1);//新链表第一个结点的前一个结点
            ListNode preKstepNode = new ListNode(-1);//k步指针的前一个结点
            
            if (head == null || n == 0){
                return head;
            }
            int k = n;
            
            //先走K步
            while (k != 0){
                //假设走到链表结束了k还不为0,那么再回到head头结点来继续
                if (kstepNode == null){
                    kstepNode = head;
                }
                kstepNode = kstepNode.next;
                k--;
            }
            //假设刚好走到链表结束,那么就不用再处理了,当前的链表就满足题意了
            if (kstepNode == null){
                return firstNode;
            }
            //处理两个结点同一时候走,知道第二个指针走到Null,则第一个指针是倒数第K个结点
            while (kstepNode != null){
                preFirstNode = firstNode;
                firstNode = firstNode.next;
                
                preKstepNode = kstepNode;
                kstepNode = kstepNode.next;
            }
            preKstepNode.next = head;
            preFirstNode.next = null;
            
            return firstNode;
        }
    }


    题目五:Partition List

    Given a linked list and a value x, partition it such that all nodes less than x come before nodes greater than or equal to x.

    You should preserve the original relative order of the nodes in each of the two partitions.

    For example,
    Given 1->4->3->2->5->2 and x = 3,
    return 1->2->2->4->3->5.

    分析:

    妈蛋,英文题目看着就是蛋疼,看了好久才理解它的题意:

    题目要求我们说给出一个X的值,你要把全部的 小于X的值的结点放在全部大于或等于X的值的前面,关键这里X又等于3,跟题目里面给出的链表中当中一个结点的值一样,迷惑了。

    一旦题意明确了,剩下的就好办了,竟然这种话,那我们仅仅须要先找出第一个 “大于或等于X值”的结点,并记录下它的位置。

    然后剩下的仅仅要遍历一次链表,把小于X的插入到它的前面,大于或等于X 不变位置(由于我们这里找到的是第一个“大于或等于X值”的结点)。


    AC代码:

    /**
     * Definition for singly-linked list.
     * public class ListNode {
     *     int val;
     *     ListNode next;
     *     ListNode(int x) {
     *         val = x;
     *         next = null;
     *     }
     * }
     */
    public class Solution {
        public ListNode partition(ListNode head, int x) {
            ListNode firstNode = head;
            ListNode preFirstNode = new ListNode(-1);
            preFirstNode.next = firstNode;
            ListNode tempNode = head;
            ListNode pretempNode = new ListNode(-1);
            pretempNode.next = tempNode;
            ListNode preHead = new ListNode(-1);
            preHead.next = head;
            
            int index = 0;
            //find the first (>= x)'s node
            while (firstNode != null){
                if (firstNode.val >= x){
                    break;
                }else{
                    preFirstNode = firstNode;
                    firstNode = firstNode.next;
                    index++;//记录位置
                }
            }
            //假设第一个满足条件的结点是头结点
            if (firstNode == head){
                preHead = preFirstNode;
            }
            //取得当前下标,假设在第一个满足条件的结点之前则不处理
            int p = 0;
            while (tempNode != null){
                if (tempNode != firstNode){
                    //值小于x,而且在第一个满足条件结点之后。
                    if (tempNode.val < x && p > index){
                        /*做移动*/
                        pretempNode.next = tempNode.next;
                        tempNode.next = preFirstNode.next;
                        preFirstNode.next = tempNode;
                        preFirstNode = tempNode;
                        tempNode = pretempNode.next;
                        index++;
                        p++;
                        continue;
                    }
                }
                pretempNode = tempNode;
                tempNode = tempNode.next;
                p++;
            }
            
            return preHead.next;
            
        }
    }


  • 相关阅读:
    rabbitmq消息路由
    rabbitmq消息消费
    python中的正则匹配
    Spectral Grouping Using Nystrom Method
    基于WKPCA的多路谱聚类算法
    基于加权KPCA的谱聚类算法
    单词拆分
    完全平方数
    零钱兑换
    组合总数
  • 原文地址:https://www.cnblogs.com/lcchuguo/p/3762301.html
Copyright © 2011-2022 走看看