很快秋招就來了,今天開始刷劍指,應該不會太慢吧,之前刷了一百道leetcode,按照tag刷的,想着這個月前把劍指刷一遍,第一波,記錄下:
順便附帶亮劍經典語錄 一:
碰到我們獨立團,就是碰到了一羣野狼,在咱們眼裏,任何對手,都是我們嘴裏的一塊肉。
不說雞湯了,上題
1. 二進制中 1 的個數
題目描述
輸入一個整數,輸出該數二進制表示中1的個數。其中負數用補碼錶示。
解題思路:
這道題之前leetcode也有看到,也做過。
第一種可以直接用api Integer.bitCount(n)
public class Solution {
public int NumberOf1(int n) {
return Integer.bitCount(n);
}
}
第二種可以用 & 運算的性質,n & (n - 1) 去除n的二進制最低位。
public class Solution {
public int NumberOf1(int n) {
int count = 0;
while (n != 0) {
n = n & (n - 1);
count++;
}
return count;
}
}
2. 數值的整數次方
題目描述
給定一個double類型的浮點數base和int類型的整數exponent。求base的exponent次方。
解題思路:
自己直接的遍歷循環解法,時間複雜度O(n)
public class Solution {
public double Power(double base, int exponent) {
if (base == 0.0) return 0;
if (exponent == 0) return 1;
double temp = base;
for (int i = 1; i < Math.abs(exponent); i++) {
base *= temp;
}
return exponent > 0 ? base : 1 / base;
}
}
大神的解法思路:
有這樣的規律。。。
當n爲偶數,a^n =(a^n/2)*(a^n/2)
當n爲奇數,a^n = a^[(n-1)/2] * a^[(n-1)/2] * a
因此 (x*x)n/2 可以通過遞歸求解,並且每次遞歸 n 都減小一半,因此整個算法的時間複雜度爲 O(logN)。
public class Solution {
public double Power(double base, int exponent) {
if (base == 0) return 0;
if (exponent == 0) return 1;
if (exponent == 1) return base;
double res = Power(base * base, Math.abs(exponent / 2));
if (exponent % 2 != 0) {
res *= base;
}
return exponent > 0 ? res : 1 / res;
}
}
3.重複的數字
題目描述:
在一個長度爲n的數組裏的所有數字都在0到n-1的範圍內。 數組中某些數字是重複的,但不知道有幾個數字是重複的。也不知道每個數字重複幾次。請找出數組中任意一個重複的數字。 例如,如果輸入長度爲7的數組{2,3,1,0,2,5,3},那麼對應的輸出是第一個重複的數字2。
解題思路:
本題可以用排序,然後判斷即可,不過如果要去時間複雜度O(n),空間複雜度O(n)的話,就不能用排序了,因此注意題目特點,數組元素在 [0, n-1] 範圍內,可以將值爲 i 的元素調整(交換)到第 i 個位置上,然後遍歷的時候判斷對應位置是否已經存在值,進行求解。
public class Solution {
public boolean duplicate(int numbers[],int length,int [] duplication) {
if (length == 0) return false;
for (int i = 0; i < length; i++) {
if (numbers[i] == i) continue;
else{
if (numbers[i] == numbers[numbers[i]] ) {
duplication[0] = numbers[i];
return true;
}
swap(numbers,i,numbers[i]);
}
}
return false;
}
private void swap(int [] arr,int a ,int b){
int temp = arr[a];
arr[a] = arr[b];
arr[b] = temp;
}
}
4.二維數組中的查找
題目描述:
在一個二維數組中(每個一維數組的長度相同),每一行都按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否含有該整數。
解題思路:
這道題剛開始考慮二分查找,結果發現不行,後來看數組的特點,從左到右遞增,從上到下遞減,因此右下角的數字肯定最大,左上角的數字肯定最小,可以考慮從右上角或者左下角判斷與target值 得大小,然後進行移動。
這裏我從右上角開始判斷。
public class Solution {
public boolean Find(int target, int [][] array) {
if (array.length == 0) return false;
int row = array.length;
int column = array[0].length;
int r = 0, c = column - 1;
while (r < row && c >= 0) {
if (target == array[r][c]) return true;
else if (target > array[r][c]) r++;
else c--;
}
return false;
}
}
5.替換空格爲指定字符
題目描述:
請實現一個函數,將一個字符串中的每個空格替換成“%20”。例如,當字符串爲We Are Happy.則經過替換之後的字符串爲We%20Are%20Happy。
解題思路:
-
其實可以使用Java一行代碼即可實現,用replace 方法。。。皮了。
-
也可以用StringBuffer中的append來實現,這樣就需要再創建一個Strinbuffer對象。
-
這裏還是老老實實從後往前遍歷,首先先定義兩個長度,temp1 和 temp2 ,當遍歷到一個空格時,在尾部填充兩個任意字符。
public class Solution {
public String replaceSpace(StringBuffer str) {
int temp1 = str.length() - 1;
for (int i = 0; i <= temp1; i++) {
if (str.charAt(i) == ' '){
str.append(" "); //有多少空格就加多少 " "
}
}
int temp2 = str.length() - 1;
while (temp1 >=0 && temp2 > temp1) {
char c = str.charAt(temp1--);
if (c == ' '){
str.setCharAt(temp2--,'0');
str.setCharAt(temp2--,'2');
str.setCharAt(temp2--,'%');
} else {
str.setCharAt(temp2--,c);
}
}
return str.toString();
}
}
6.從尾到頭打印鏈表
題目描述:
輸入一個鏈表,按鏈表值從尾到頭的順序返回一個ArrayList。
Input : 1 -> 2 -> 3
Output : 3 -> 2 -> 1
解題思路:
題目剛看,感覺就是鏈表反轉,那麼如何進行鏈表反轉呢,其實可以使用 頭插法,這裏 head 就是頭,head不存儲數據,head.next存儲反轉後的鏈表。反轉後再遍歷就是了。
import java.util.ArrayList;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
ListNode head = new ListNode(-1);
while (listNode != null) {
ListNode temp = listNode.next;
listNode.next = head.next;
head.next = listNode;
listNode = temp;
}
ArrayList<Integer> list = new ArrayList();
head = head.next;
while (head != null) {
list.add(head.val);
head = head.next;
}
return list;
}
}
本題也可以說用棧來實現,利用棧的特點,後進先出。
import java.util.*;
public class Solution {
public ArrayList<Integer> printListFromTailToHead(ListNode listNode) {
Stack<Integer> stack = new Stack();
while (listNode != null) {
stack.push(listNode.val);
listNode = listNode.next;
}
ArrayList<Integer> list = new ArrayList();
while (!stack.isEmpty() ) {
list.add(stack.pop());
}
return list;
}
}
7.重建二叉樹
題目描述:
輸入某二叉樹的前序遍歷和中序遍歷的結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不含重複的數字。例如輸入前序遍歷序列{1,2,4,7,3,5,6,8}和中序遍歷序列{4,7,2,1,5,3,8,6},則重建二叉樹並返回。
解題思路:注意二叉樹性質,如果涉及到二叉樹,應當考慮使用遞歸來解決,首先根據前序遍歷第一個值就是根節點,然後根據根結點在中序序列中的位置分割出左右兩個子序列,最後遞歸地對左子樹和右子樹分別遞歸使用同樣的方法繼續分解。
這裏注意Arrays.copyOfRange()的用法,(左閉右開)附上API:
import java.util.Arrays;
public class Solution {
public TreeNode reConstructBinaryTree(int [] pre,int [] in) {
if (pre.length == 0 || in.length == 0) return null;
int value = pre[0];
TreeNode root = new TreeNode(value);
for (int i = 0; i < in.length; i++){
if (in[i] == value) {
root.left = reConstructBinaryTree(Arrays.copyOfRange(pre,1,i+1),Arrays.copyOfRange(in,0,i));
root.right =reConstructBinaryTree(Arrays.copyOfRange(pre,i+1,in.length),Arrays.copyOfRange(in,i+1,in.length));
break;
}
}
return root;
}
}
8.二叉樹的下一個結點
題目描述:
給定一個二叉樹和其中的一個結點,請找出中序遍歷順序的下一個結點並且返回。注意,樹中的結點不僅包含左右子結點,同時包含指向父結點的指針。
解題思路:由於每個節點都有指向父節點的指針,因此先求的根節點,然後再利用根節點和用鏈表存儲中序遍歷的值,然後判斷返回鏈表下一個即可,需注意是否是最後一個。
/*
public class TreeLinkNode {
int val;
TreeLinkNode left = null;
TreeLinkNode right = null;
TreeLinkNode next = null;
TreeLinkNode(int val) {
this.val = val;
}
}
*/
import java.util.*;
public class Solution {
static List<TreeLinkNode> list = new ArrayList();
public TreeLinkNode GetNext(TreeLinkNode pNode){
if (pNode == null) return null;
TreeLinkNode p = pNode;
while (pNode.next != null) {
pNode = pNode.next;
}
getMidTravel(pNode);
for (int i = 0; i < list.size(); i++) {
if (list.get(i) == p) {
return (i == list.size() - 1) ? null : list.get(i+1);
}
}
return null;
}
//中序遍歷
private static void getMidTravel(TreeLinkNode node) {
if (node != null) {
getMidTravel(node.left);
list.add(node);
getMidTravel(node.right);
}
}
}
上述方法時間複雜度O(N),空間複雜度:O(n),下面這種可以做到空間複雜度O(n)
可以把中序下一結點歸爲幾種類型:
-
有右子樹,下一結點是右子樹中的最左結點
-
無右子樹,且結點是該結點父結點的左子樹,則下一結點是該結點的父結點
-
無右子樹,且結點是該結點父結點的右子樹,則我們一直沿着父結點追朔,直到找到某個結點是其父結點的左子樹,如果存在這樣的結點,那麼這個結點的父結點就是我們要找的下一結點。
/*
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 temp = pNode.right;
if (temp.left != null) {
return temp.left;
}
return temp;
}else {
while (pNode.next != null) {
TreeLinkNode temp = pNode.next;
if (temp.left == pNode) return temp;
pNode = pNode.next;
}
}
return null;
}
}
9. 用兩個棧實現隊列
題目描述
用兩個棧來實現一個隊列,完成隊列的Push和Pop操作。 隊列中的元素爲int類型。
解題思路:之前在LeetCode刷過類似題目,當時還寫了一篇文章LeetCode中的棧和隊列的問題,這裏使用兩個棧,利用棧後進先出特點和隊列先進先出特點進行解決即可。需要注意的就是當第二個棧stack2爲空時才往裏面push。
import java.util.Stack;
public class Solution {
Stack<Integer> stack1 = new Stack<Integer>();
Stack<Integer> stack2 = new Stack<Integer>();
public void push(int node) {
stack1.push(node);
}
public int pop() {
//當第二個棧stack2爲空時才往裏面push。
while (stack2.empty()){
while (!stack1.empty()){
stack2.push(stack1.pop());
}
}
return stack2.pop();
}
}