劍指offer 第十一天

46.撲克牌順子

LL今天心情特別好,由於他去買了一副撲克牌,發現裏面竟然有2個大王,2個小王(一副牌本來是54張^_^)...他隨機從中抽出了5張牌,想測測本身的手氣,看看能不能抽到順子,若是抽到的話,他決定去買體育彩票,嘿嘿!!「紅心A,黑桃3,小王,大王,方片5」,「Oh My God!」不是順子.....LL不高興了,他想了想,決定大\小 王能夠當作任何數字,而且A看做1,J爲11,Q爲12,K爲13。上面的5張牌就能夠變成「1,2,3,4,5」(大小王分別看做2和4),「So Lucky!」。LL決定去買體育彩票啦。 如今,要求你使用這幅牌模擬上面的過程,而後告訴咱們LL的運氣如何。爲了方便起見,你能夠認爲大小王是0。java

import java.util.Arrays;
public class Solution {
    public boolean isContinuous(int [] numbers) {
        if(numbers.length < 5) return false;
        Arrays.sort(numbers);
        int zerosNum = 0;
        int needZeros = 0;
        for(int i = 0 ;i < 5;i++){
            if(numbers[i] == 0){
                zerosNum++;
            }else if(i+1<5){
                //如存在兩數字相同,則必定不是順子
                if(numbers[i+1] == numbers[i]) return false; 
                needZeros += numbers[i+1] - numbers[i] -1;
            }
        }
        //此時大王個數超過四個,不符合題目要求
        if(zerosNum > 4) return false; 
        if(zerosNum >= needZeros) return true;
        else return false;
    }
}

46.孩子們的遊戲

n我的(編號0~(n-1)),從0開始報數,報到(m-1)的退出,剩下的人 繼續從0開始報數。求勝利者的編號。(約瑟夫環問題)
解法一:使用數組模擬環node

public class Solution {
    public int LastRemaining_Solution(int n, int m) {
        if(n<0||m<1) return -1;
        int[] array = new int[n];
        int count=n,step=0,idx=-1;
        while(count>0){
            idx++;
            if(idx == n) idx=0;
            if(array[idx] == -1) continue;//若是是被標記過的則跳過
            step++;
            if(step == m){
                array[idx] = -1;
                count--; 
                step=0;
            } 
        }
        return idx;
    }
}

解法二:使用ArrayList模擬環
正則表達式

import java.util.ArrayList;
public class Solution {
    public int LastRemaining_Solution(int n, int m){
        if(n<0||m<1) return -1;
        ArrayList<Integer> list = new ArrayList<>();
        for(int i = 0;i<n;i++)
            list.add(i);
        int idx = (m-1)%n;
        while(list.size()>1){
            list.remove(idx);
            idx = (idx+m-1)%list.size();
        }
        return list.get(0);
    }
}

47.求1+2+3+...+n

求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。數組

解題思路:(短路求值)app

  1. 需利用邏輯與短路特性實現遞歸終止。
  2. 當n==0時,(n>0)&&((sum+=Sum_Solution(n-1))>0)只執行前面的判斷,爲false,而後直接返回0;
  3. 當n>0時,執行sum+=Sum_Solution(n-1),實現遞歸計算Sum_Solution(n)。
public class Solution {
    public int Sum_Solution(int n) {
        int sum = n;
        boolean isEnd = (sum != 0)&&((sum += Sum_Solution(n-1))>0);
        return sum;
    }
}

48.不用加減乘除作加法

寫一個函數,求兩個整數之和,要求在函數體內不得使用+、-、*、/四則運算符號。函數

解析:按位運算oop

  • step1:按位與是查看兩個數哪些二進制位都爲1,這些都是進位位,結果需左移一位,表示進位後的結果
  • step2:異或是查看兩個數哪些二進制位只有一個爲1,這些是非進位位,能夠直接加、減,結果表示非進位位進行加操做後的結果
  • step3:n1&n2是查看有沒有進位位了,若是有,須要重複step一、step2;若是沒有,保留n一、n2上二進制爲1的部分,用或將之合爲一個數,即爲最後結果
public class Solution {
    public int Add(int num1,int num2) {
        int n1,n2;
        n1 = num1 & num2;
        n1 = n1<<1;
        n2 = num1 ^ num2;
        if((n1 & n2) != 0) return Add(n1,n2);
        return n1 | n2;
    }
}

49.把字符串轉換成整數

將一個字符串轉換成一個整數,要求不能使用字符串轉換整數的庫函數。 數值爲0或者字符串不是一個合法的數值則返回0
this

public class Solution {
    public int StrToInt(String str) {
        if(str.length() < 1) return 0;
        char[] nums = str.toCharArray();
        int result = 0;
        int flag = 1;
        for(int i = 0 ; i<nums.length ; i++){
            if(nums[i]-'0'>9 || nums[i]-'0'<0){
                if( i==0 && (nums[i] == '+' || nums[i] == '-'))
                    flag = nums[i] == '+' ? 1 : -1;
                else
                    return 0;
            }else{
                result*=10;
                result+=(nums[i]-'0');
            }  
        }
        return result*flag;
    }
}

不適用str.toCharArray()方法google

public class Solution {
    public int StrToInt(String str) {
        if(str.length() < 1) return 0;
        int result = 0;
        int flag = 1;
        for(int i = 0 ; i<str.length(); i++){
            if(str.charAt(i)-'0'>9 || str.charAt(i)-'0'<0){
                if( i==0 && (str.charAt(i) == '+' || str.charAt(i) == '-'))
                    flag = str.charAt(i) == '+' ? 1 : -1;
                else
                    return 0;
            }else{
                result*=10;
                result+=(str.charAt(i)-'0');
            }  
        }
        return result*flag;
    }
}

50.數組中重複的數字

在一個長度爲n的數組裏的全部數字都在0到n-1的範圍內。 數組中某些數字是重複的,但不知道有幾個數字是重複的。也不知道每一個數字重複幾回。請找出數組中任意一個重複的數字。 例如,若是輸入長度爲7的數組{2,3,1,0,2,5,3},那麼對應的輸出是第一個重複的數字2。指針

public class Solution {
    // Parameters:
    //    numbers:     an array of integers
    //    length:      the length of array numbers
    //    duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation;
    //                  Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++
    //    這裏要特別注意~返回任意重複的一個,賦值duplication[0]
    // Return value:       true if the input is valid, and there are some duplications in the array number
    //                     otherwise false
    public boolean duplicate(int numbers[],int length,int [] duplication) {
        if(length<0) return false;
        boolean[] result = new boolean[length];
        for(int i = 0;i<length;i++){
            if(numbers[i]>length-1||numbers[i]<0) return false;
            if(result[numbers[i]]){
                duplication[0] = numbers[i];
                return true;
            }
            result[numbers[i]] = true;
        }
        return false;
    }
}

51.構建乘積數組

給定一個數組A[0,1,...,n-1],請構建一個數組B[0,1,...,n-1],其中B中的元素B[i]=A[0]A[1]...A[i-1]A[i+1]...A[n-1]。不能使用除法。

import java.util.ArrayList;
public class Solution {
    public int[] multiply(int[] A) {
        int[] B = new int[A.length];
        if(A.length == 0) return B;
        B[0] = 1;
        for(int i = 1;i<A.length;i++){
            B[i] = B[i-1] * A[i-1];
        }
        int temp = 1;
        for(int i = A.length-1;i>=0;i--){
            B[i] *= temp;
            temp *= A[i];
        }
        return B;
    }
}

==52.正則表達式匹配==

請實現一個函數用來匹配包括'.'和''的正則表達式。模式中的字符'.'表示任意一個字符,而''表示它前面的字符能夠出現任意次(包含0次)。 在本題中,匹配是指字符串的全部字符匹配整個模式。例如,字符串"aaa"與模式"a.a"和"abaca"匹配,可是與"aa.a"和"ab*a"均不匹配

解題思路

1.當patternIndex後一位爲‘’時:
此時若strIndex == str.length時,直接將patternIndex+2,跳過兩個;
若是strIndex!=str.length時,分爲如下三種狀況:
1.strIndex,patternIndex+2;(str != pattern時)
2.strIndex+1,patternIndex+2;(str = pattern 時 或者 此時pattern == ‘.’)
3.strIndex+1,patternIndex;(str == pattern 並且 str+1 也 == pattern)
2.當patternIndex後一位不爲‘

此時若是strIndex = str.length return false;
若是 str = pattern 則 str+1,pattern+1
反之 return false;

public class Solution {
    public boolean match(char[] str, char[] pattern)
    {
        //1.邊緣檢測
        if(str==null||pattern==null) return false;
        int strIndex=0,patternIndex=0;
        return matchCore(str,pattern,strIndex,patternIndex);
    } 
    public boolean matchCore(char[] str,char[] pattern,int strIndex,int patternIndex){
        if(strIndex == str.length && patternIndex == pattern.length) return true;
        if(strIndex != str.length && patternIndex == pattern.length) return false;
        //當模式中第二個字符是‘*’
        if(patternIndex+1 < pattern.length && pattern[patternIndex +1] == '*'){
            //必定注意這裏strIndex有多是str.length 須要把str[strIndex]放在後面,以避免溢出
            if(strIndex != str.length && (pattern[patternIndex] == '.' || str[strIndex] == pattern[patternIndex])){
                return matchCore(str,pattern,strIndex+1,patternIndex) || matchCore(str,pattern,strIndex+1,patternIndex+2) || matchCore(str,pattern,strIndex,patternIndex+2);
            }else{
                return matchCore(str,pattern,strIndex,patternIndex+2);
            }     
        }else{//模式中第二個字符不是’*‘
            if(strIndex != str.length && (str[strIndex] == pattern[patternIndex] || pattern[patternIndex] == '.'))
                return matchCore(str,pattern,strIndex+1,patternIndex+1);
            else
                return false;
        }
    }
}

==53.表示數值的字符串==

請實現一個函數用來判斷字符串是否表示數值(包括整數和小數)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示數值。 可是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

題目分析:數值能夠表示爲"A+'.'+B+'E/e'+C"

  • 其中A爲帶符號整數,能夠爲空
  • B爲不帶符號整數,能夠爲空
  • A和B不能同時爲空
  • C爲帶符號整數,不能爲空
public class Solution {
    //聲明一個全局變量,記錄小數點前是否有數字
    boolean hasInt = false;
    public boolean isNumeric(char[] str) {
        if(str == null || str.length == 0) return false;
        return scanA(str,0);
    }
    //第一部分:爲帶符號整數,後續字符串可包括'./e/E'
    public boolean scanA(char[] str,int index){
        //1.若是有符號則跳過。
        if(str[index] == '-' || str[index] == '+') index++;
        while(index < str.length && str[index]-'0' <= 9 && str[index]-'0' >= 0){
            hasInt = true;
            index++;
        }
        if(index == str.length) return hasInt;
        if(str[index] == '.')
            return scanB(str,index+1);
        else if(str[index] == 'e'||str[index]=='E')
            return scanC(str,index+1);
        else
            return false;
    }
    //第二部分:爲不帶符號整數,後續字符可帶'e/E'
    public boolean scanB(char[] str,int index){
        boolean hasNum = false;
        //用於判斷是不是「12.」這種數字
        if(index == str.length) return hasInt || hasNum;
        while(index < str.length && str[index]-'0' <= 9 && str[index]-'0' >= 0){
            index++;
            hasNum = true;
        }
        if(index == str.length) return hasInt || hasNum;
        if(str[index] == 'e' || str[index] == 'E')
            return (hasInt || hasNum) && scanC(str,index+1);
        else
            return false;
    }
    //第三部分:爲帶符號整數
    public boolean scanC(char[] str,int index){
        //用於判斷是否爲「12e」這樣的數字,這種是不正確的,第三部分不能爲空
        if(index == str.length) return false;
        boolean hasNum = false;
        //若是有符號,則跳過
        if(str[index]=='+'||str[index]=='-') index++;
        while(index < str.length && str[index]-'0' <= 9 && str[index]-'0' >= 0){
            hasNum=true;
            index++;
        }  
        if(index == str.length) return hasNum;
        else return false;
    }
}

54.字符流中第一個不重複的字符

請實現一個函數用來找出字符流中第一個只出現一次的字符。例如,當從字符流中只讀出前兩個字符"go"時,第一個只出現一次的字符是"g"。當從該字符流中讀出前六個字符「google"時,第一個只出現一次的字符是"l"。

輸出描述:

若是當前字符流沒有存在出現一次的字符,返回#字符。

import java.util.ArrayList;
import java.util.HashSet;
public class Solution {
    ArrayList<Character> list = new ArrayList<>();
    HashSet<Character> set = new HashSet<>();
    //Insert one char from stringstream
    public void Insert(char ch)
    {
        if(!set.contains(ch))
            if(list.contains(ch)){
                //注意這裏之因此將char轉換爲Character對象,是由於,若是直接帶入char
                //函數會將char轉變成ASCII碼int值做爲索引,會致使溢出。
                list.remove((Character)ch);
                set.add(ch);
            }else{
                list.add(ch);
            }
    }
  //return the first appearence once char in current stringstream
    public char FirstAppearingOnce()
    {
        if(list.size() > 0)
            return list.get(0);
        else
            return '#';
    }
}

55.鏈表中的入口結點

一個鏈表中包含環,請找出該鏈表的環的入口結點。
方法一:使用輔助Set集合

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
import java.util.HashSet;
public class Solution {

    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        if(pHead == null) return null;
        HashSet<ListNode> set = new HashSet<>();
        while(!set.contains(pHead)){
            if(pHead.next == null) return null;
            set.add(pHead);
            pHead = pHead.next;
        }
        return pHead;
            
    }
}

方法二:單純指針操做

public class Solution {
    public ListNode EntryNodeOfLoop(ListNode pHead)
    {
        if(pHead == null) return null;
        ListNode p1=pHead,p2=pHead.next;
        //第一步:若是有環,則算出環的長度;
        while(p1 != p2 && p2 != null){
            p1 = p1.next;
            p2 = p2.next;
            if(p2 == null) return null;
            p2 = p2.next;
        }
        if(p2 == null) return null;
        int count = 1;
        while(p1.next != p2){
            p1 = p1.next;
            count++;
        }
        //第二步:找到環的入口
        p1 = pHead;
        p2 = pHead;
        while(count-- > 0)
            p2 = p2.next;
        while(p1!=p2){
            p1 = p1.next;
            p2 = p2.next;
        }
        return p1;     
    }
}

56.刪除鏈表中重複的結點這道題糾結了好久!!!很簡單的遞歸就能實現,有點相似於動態規劃

在一個排序的鏈表中,存在重複的結點,請刪除該鏈表中重複的結點,重複的結點不保留,返回鏈表頭指針。 例如,鏈表1->2->3->3->4->4->5 處理後爲 1->2->5

/*
 public class ListNode {
    int val;
    ListNode next = null;

    ListNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public ListNode deleteDuplication(ListNode pHead)
    {
        if(pHead == null || pHead.next == null)
            return pHead;
        if(pHead.val == pHead.next.val){
          while(pHead.next != null && pHead.val == pHead.next.val)
              pHead = pHead.next;
          return deleteDuplication(pHead.next);
        }
        pHead.next = deleteDuplication(pHead.next);
        return pHead;
    }
}

57.二叉樹的下一個結點

給定一個二叉樹和其中的一個結點,請找出中序遍歷順序的下一個結點而且返回。注意,樹中的結點不只包含左右子結點,同時包含指向父結點的指針。

/*
public class TreeLinkNode {
    int val;
    TreeLinkNode left = null;
    TreeLinkNode right = null;
    TreeLinkNode next = null;

    TreeLinkNode(int val) {
        this.val = val;
    }
}
*/
public class Solution {
    public TreeLinkNode GetNext(TreeLinkNode pNode)
    {
        if(pNode == null) return null;
        if(pNode.right != null){
            TreeLinkNode node = pNode.right;
            while(node.left != null)
                node = node.left;
            return node;
        }
        while(pNode.next != null){
            if(pNode.next.right != pNode)
                return pNode.next;
            pNode = pNode.next;
        }
        return null;
    }
}
相關文章
相關標籤/搜索