劍指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();
}
}