1. 程式人生 > >劍指Offer 刷題筆記(20/66)——JAVA

劍指Offer 刷題筆記(20/66)——JAVA

文章目錄

11.二進位制中1的個數

題目:輸入一個整數,輸出該數二進位制表示中1的個數。其中負數用補碼錶示。(連結)
解析

按位與運算子“&”是雙目運算子: 其功能是參與運算的兩數各對應的二進位相與。(1&1=1; 1&0=0; 0&0=0)
n&(n-1)作用:將n的二進位制表示中的最低位為1的改為0, 如: n = 10100(二進位制);則(n-1) =10011
n&(n-1) = 10000 可以看到原本最低位為1的那位變為0。

n & (n-1)的其它應用

每次n和n-1按位與,二進位制原本最低位為1的那位變為0。二進位制1的個數減一,最終值為0時,沒有1存在,count值就為1的個數。

public class Solution {
    public int NumberOf1(int n) {
        int count=0;
        while(n!=0){
            n &= (n-1);
            count++;
        }
        return count;
    }
}

12.數值的整數次方

題目:給定一個double型別的浮點數base和int型別的整數exponent。求base的exponent次方。(

連結)
解析:求 baseexponent:指數函式
快速冪:
快速冪的目的就是做到快速求冪,假設我們要求a^b,按照樸素演算法就是把a連乘b次,這樣一來時間複雜度是O(b)也即是O(n)級別,快速冪能做到O(logn),快了好多好多。它的原理如下:
  假設我們要求ab,那麼其實b是可以拆成二進位制的,該二進位制數第i位的權為2(i-1),例如當b==11時,a11 = a^ (2 ^ 0+2^ 1+2^ 3)
  11的二進位制是1011,11 = 2³×1 + 2²×0 + 2¹×1 + 2º×1,因此,我們將a¹¹轉化為算也就是a1 * a2 * a8 。

public class Solution
{ public double Power(double base, int exponent) { if(exponent==0) return 1.0; int e = exponent > 0 ? exponent :-exponent; double res=1; while(e!=0){ if((e & 1) != 0) res *=base; base *= base; e>>=1; } return exponent > 0 ? res : 1/res; } }

13.調整陣列順序使奇數位於偶數前面

題目:輸入一個整數陣列,實現一個函式來調整該陣列中數字的順序,使得所有的奇數位於陣列的前半部分,所有的偶數位於陣列的後半部分,並保證奇數和奇數,偶數和偶數之間的相對位置不變。(連結)
解析類似冒泡演算法,前偶後奇數就交換。

public class Solution {
    public void reOrderArray(int [] array) {
        for(int i=0;i<array.length;i++){
            for(int j=array.length-1;j>i;j--){
                if(array[j]%2==1 && array[j-1]%2 ==0)
                {
                    int x = array[j-1];
                    array[j-1]=array[j];
                    array[j]=x;
                }
            }
        }
    }
}

14.連結串列中倒數第k個節點

題目:輸入一個連結串列,輸出該連結串列中倒數第k個結點。(連結)
解析:前後指標法,讓第一個指標先向前走k-1步,然後第二個指標和第一個指標同時向後走,直到第二個指標後面沒有結點,第二個指標指向的就是第k個結點。
注意:如果連結串列的結點個數少於k,就要返回空指標。

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

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode FindKthToTail(ListNode head,int k) {
        ListNode pre=head,last=head;
        int i=0;
        for(;pre!=null;i++){
            pre=pre.next;
            if(i>=k){
                last=last.next;
            }
        }
        return i<k ? null : last;
    }
}

15.反轉連結串列

題目:輸入一個連結串列,反轉連結串列後,輸出新連結串列的表頭。(連結)
解析:有2種方法:①遞迴②非遞迴。
程式碼是非遞迴方法,利用連結串列的頭插法會得到反序的連結串列這一性質來做。

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

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode ReverseList(ListNode head) {
    	//如果連結串列為空或者連結串列中只有一個元素
        if(head==null||head.next==null) 
            return head;
        ListNode pre=null,next=null;
        while(head!=null){
            next=head.next;
            head.next=pre;
            pre=head;
            head=next;
        }
        return pre;
    }
}

16.合併兩個排序的連結串列

題目:輸入兩個單調遞增的連結串列,輸出兩個連結串列合成後的連結串列,當然我們需要合成後的連結串列滿足單調不減規則。(連結)
解析:有2種法:①遞迴②非遞迴。
程式碼是遞迴方法:兩個連結串列中,哪個頭結點的值小就返回哪個頭結點,然後合併剩下的連結串列,最後令頭結點的值較小的那個頭結點的next指向合併後的剩餘連結串列。

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

    ListNode(int val) {
        this.val = val;
    }
}*/
public class Solution {
    public ListNode Merge(ListNode list1,ListNode list2) {
        if(list1==null)
            return list2;
        if(list2==null)
            return list1;
        if(list1.val<=list2.val){
            list1.next = Merge(list1.next,list2);
            return list1;
        }
        else{
            list2.next = Merge(list1,list2.next);
            return list2;
        }
    }
}

17.樹的子結構

題目:輸入兩棵二叉樹A,B,判斷B是不是A的子結構。(ps:我們約定空樹不是任意一個樹的子結構)(連結)
解析:首先,判斷B是不是A的子結構,然後再判斷B是不是A的左子樹的子結構,B是不是A的右子樹的子結構;
利用好 || 和 && 的短路特性。

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    public boolean HasSubtree(TreeNode root1,TreeNode root2) {
        if(root1==null || root2==null)
            return false;
        //判斷根節點,其左子樹,其右子樹是否為tree2;
        return isSubtree(root1,root2) || HasSubtree(root1.left,root2) ||HasSubtree(root1.right,root2);  
    }
    
    public boolean isSubtree(TreeNode node1,TreeNode node2){
        if(node2 == null)
            return true;
        if(node1 == null)
            return false;
        if(node1.val == node2.val)
            return isSubtree(node1.left,node2.left) && isSubtree(node1.right,node2.right);
        return false;
    }
}

18.二叉樹的映象

題目:操作給定的二叉樹,將其變換為源二叉樹的映象。(連結)
解析:遞迴求解,把根節點的左右子樹都轉化成映象二叉樹,然後再交換左右指標就行了。

/**
public class TreeNode {
    int val = 0;
    TreeNode left = null;
    TreeNode right = null;

    public TreeNode(int val) {
        this.val = val;

    }

}
*/
public class Solution {
    public void Mirror(TreeNode root) {
        if(root == null)
            return;
        TreeNode temp = root.left;
        root.left = root.right;
        root.right = temp;
        Mirror(root.left);
        Mirror(root.right);
    }
}

19.順時針列印矩陣

題目:輸入一個矩陣,按照從外向裡以順時針的順序依次打印出每一個數字,例如,如果輸入如下4 X 4矩陣: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 則依次打印出數字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.(連結)
解析:本來想做個簡潔的,然鵝並沒有做到- -

import java.util.ArrayList;
public class Solution {
     public ArrayList<Integer> printMatrix(int [][] matrix) {
        ArrayList<Integer> res = new ArrayList<Integer>();
        int left=0, right=matrix[0].length-1, top=0, bottom=matrix.length-1;
        while(left<=right && top <=bottom){
            for(int i=left;i<=right;i++)
                res.add(matrix[top][i]);
            for(int i=top+1;i<=bottom;i++)
                res.add(matrix[i][right]);
            if(top!= bottom)
            for(int i=right-1;i>=left;i--)
                res.add(matrix[bottom][i]);
            if(left!=right)
            for(int i=bottom-1;i>top;i--)
                res.add(matrix[i][left]);
            left++;right--;bottom--;top++;
        }
        return res;
    }
}
import java.util.ArrayList;
public class Solution {
    public ArrayList<Integer> printMatrix(int [][] matrix) {
        ArrayList<Integer> res = new ArrayList<Integer>();
        int left=0, right=matrix[0].length-1, top=0, bottom=matrix.length-1;
        int x=0,y=0;
        while(left<=right && top<=bottom){
            for(;y<=right && left<=right && top<=bottom;y++)
                res.add(matrix[x][y]);
            for(top++,y--,x++; x<=bottom && left<=right && top<=bottom;x++)
                res.add(matrix[x][y]);
            for(right--,x--,y--; y>=left && left<=right && top<=bottom;y--)
                res.add(matrix[x][y]);
            for(bottom--,y++,x--; x>=top && left<=right && top<=bottom;x--)
                res.add(matrix[x][y]);
            left++;x++;y++;
        }
        return res;
    }
}

20.包含min函式的棧

題目:定義棧的資料結構,請在該型別中實現一個能夠得到棧中所含最小元素的min函式(時間複雜度應為O(1))。(連結)
解析:題目要求O(1)的時間複雜度內得到最小值。那麼只能空間換時間了;
每次壓棧操作時,如果壓棧元素比當前最小元素更小,就把這個元素壓入最小元素棧,原本的最小元素就成了次小元素。同理,彈棧時,如果彈出的元素和最小元素棧的棧頂元素相等,就把最小元素的棧頂彈出。
如data依次入棧,5, 4, 3,8,10,11,12,1
則min 依次入棧,5, 4, 3,x, x , x , x , 1

import java.util.Stack;

public class Solution {

    Stack<Integer> dataStack = new Stack<Integer>();
    Stack<Integer> minStack = new Stack<Integer>();
    public void push(int node) {
        dataStack.push(node);
        if( minStack.empty() || node <= min())
            minStack.push(node);
    }
    
    public void pop() {
        if(dataStack.peek() == min())
            minStack.pop();
        dataStack.pop();
    }
    
    public int top() {
        return dataStack.peek();
    }
    
    public int min() {
        return minStack.peek();
    }
}