Problem2:實現Singleton模式
題目描述:設計一個類,我們只能生成該類的一個實例
1 package Problem2; 2 3 public class SingletonClass { 4 5 /* 6 * 題目描述:設計一個類,我們只能生成該類的一個實例 7 */ 8 //volatile:防止指令重排序 9 private static volatile SingletonClass instance; 10 11 private SingletonClass() { 12 } 13 14 public static SingletonClass getInstace() { 15 if (instance == null) { 16 synchronized (SingletonClass.class) { 17 if (instance == null) { 18 instance = new SingletonClass(); 19 } 20 } 21 } 22 23 return instance; 24 25 } 26 27 }
Problem3:二維數組中的查找
題目描述:在一個二維數組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下的順序排序。 完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否包含該整數;
1 package Problem3; 2 3 public class Find { 4 5 /* 6 * 題目描述:二維數組中的查找 7 * 在一個二維數組中,每一行都按照從左到右遞增的順序排序,每一列都按照從上到下的順序排序。 8 * 完成一個函數,輸入這樣的一個二維數組和一個整數,判斷數組中是否包含該整數 9 * 10 */ 11 public static boolean find(int arr[][],int keyNumber){ 12 //從二維數組的右上角開始選取與keyNumber比較的整數 13 //column的變化:arr[0].length-1-->0; 14 //row的變化:0-->arr.length; 15 int column=arr[0].length-1; 16 int row=0; 17 while(column>=0&&row<arr.length){ 18 if(arr[row][column]==keyNumber){ 19 return true; 20 } 21 else if(arr[row][column]>keyNumber){ 22 column--; 23 } 24 else { 25 row++; 26 } 27 } 28 return false; 29 30 } 31 //測試find函數 32 public static void main(String[] args) { 33 /* 34 * 1 2 8 9 35 * 2 4 9 12 36 * 4 7 10 13 37 * 6 8 11 15 38 */ 39 int array[][]=new int[4][4]; 40 array[0][0]=1; 41 array[0][1]=2; 42 array[0][2]=8; 43 array[0][3]=9; 44 array[1][0]=2; 45 array[1][1]=4; 46 array[1][2]=9; 47 array[1][3]=12; 48 array[2][0]=4; 49 array[2][1]=7; 50 array[2][2]=10; 51 array[2][3]=13; 52 array[3][0]=6; 53 array[3][1]=8; 54 array[3][2]=11; 55 array[3][3]=15; 56 System.out.println(find(array, 7)); 57 System.out.println(find(array, 5)); 58 } 59 60 }
同理,比較關鍵字也可以從二維數組的左下角開始選擇,則column和row的增減方式調換一下,但是不能選擇左上角和右下角的元素作為與查找元素比較的關鍵字,因為無論比較結果怎樣,都無法進一步縮小查找的范圍。
Problem4:替換空格
題目描述:請實現一個函數,將字符串的每個空格替換為"%20"。例如輸入"We are happy",則輸出"We%20are%20happy."。
1 package Problem4; 2 3 public class ReplaceBank { 4 5 /* 6 * 題目描述: 請實現一個函數,將字符串的每個空格替換為"%20"。 7 * 例如輸入"We are happy",則輸出"We%20are%20happy."。 8 */ 9 /** 10 * @param args 11 */ 12 13 public String replace(String input) { 14 StringBuilder builder = new StringBuilder(); 15 if (input == null || input.length() == 0) { 16 return null; 17 } 18 for (int i = 0; i < input.length(); i++) { 19 if (input.charAt(i) == ' ') { 20 builder.append("%"); 21 builder.append("2"); 22 builder.append("0"); 23 } else { 24 builder.append(input.charAt(i)); 25 } 26 } 27 return builder.toString(); 28 } 29 30 // 測試用例 31 public static void main(String[] args) { 32 ReplaceBank test = new ReplaceBank(); 33 // 輸入的字符串包含空格:最后面,最前面,中間,連續空格 34 String str1 = "We are happy."; 35 String str2 = " Wearehappy."; 36 String str3 = "Wearehappy. "; 37 String str4 = "We are happy ."; 38 //輸入的字符串沒有空格 39 String str5="Wearehappy."; 40 //特殊輸入測試:字符串只有連續空格、只有一個空格、字符串是一個null指針、字符串是一個空字符串; 41 String str6=" "; 42 String str7=" "; 43 String str8=null; 44 String str9=""; 45 System.out.println(test.replace(str1)); 46 System.out.println(test.replace(str2)); 47 System.out.println(test.replace(str3)); 48 System.out.println(test.replace(str4)); 49 System.out.println(test.replace(str5)); 50 System.out.println(test.replace(str6)); 51 System.out.println(test.replace(str7)); 52 System.out.println(test.replace(str8)); 53 System.out.println(test.replace(str9)); 54 } 55 56 }
Problem5:從尾到頭打印鏈表
題目描述:輸入一個鏈表的頭結點,從尾到頭反過來打印出每個結點的值.
1 package Problem5; 2 3 import java.util.Stack; 4 5 //首先定義鏈表結構 6 class LinkNode{ 7 LinkNode next; 8 int node_value; 9 } 10 11 public class PrintListReverse { 12 public void reverse(LinkNode headNode){ 13 //用棧的思想來實現鏈表的倒序輸出 14 Stack<LinkNode> stack=new Stack<LinkNode>(); 15 while(headNode!=null){ 16 stack.push(headNode); 17 headNode=headNode.next; 18 } 19 while(!stack.isEmpty()){ 20 System.out.print(stack.pop().node_value+" "); 21 } 22 System.out.println(); 23 } 24 25 /** 26 * @param args 27 */ 28 public static void main(String[] args) { 29 //輸入的鏈表有多個結點 30 PrintListReverse plr=new PrintListReverse(); 31 LinkNode node1=new LinkNode(); 32 LinkNode node2=new LinkNode(); 33 LinkNode node3=new LinkNode(); 34 node1.node_value=1; 35 node2.node_value=2; 36 node3.node_value=3; 37 node1.next=node2; 38 node2.next=node3; 39 plr.reverse(node1); 40 } 41 42 }
Problem5:重建二叉樹
題目描述:輸入某二叉樹的前序遍歷和中序遍歷結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中都不包含重復的數字。例如輸入前序遍歷序列:{1,2,4,7,3,5,6,8}和中序遍歷{4,7,2,1,5,3,8,6},則重建出圖中所示二叉樹並且輸出它的頭結點。
重建的二叉樹:
1 package Problem6; 2 3 /* 重建二叉樹 4 * 問題描述:輸入某二叉樹的前序遍歷和中序遍歷結果,請重建出該二叉樹。假設輸入的前序遍歷和中序遍歷的結果中 5 * 都不包含重復的數字。例如輸入前序遍歷序列:{1,2,4,7,3,5,6,8}和中序遍歷{4,7,2,1,5,3,8,6}, 6 * 則重建出圖中所示二叉樹並且輸出它的頭結點。 7 */ 8 //定義二叉樹節點 9 class BinaryTreeNode { 10 public int value; 11 public BinaryTreeNode leftNode; 12 public BinaryTreeNode rightNode; 13 14 // 無參構造函數 15 public BinaryTreeNode() { 16 17 } 18 19 // 有參構造函數 20 public BinaryTreeNode(int value) { 21 this.value = value; 22 this.leftNode = null; 23 this.rightNode = null; 24 } 25 } 26 27 public class ConstructBinaryTree { 28 29 public static BinaryTreeNode construct(int preOrder[], int inOrder[], 30 int length) throws Exception { 31 if (preOrder == null || inOrder == null || length < 0) { 32 return null; 33 } 34 return constructCore(preOrder, 0, preOrder.length - 1, inOrder, 0, 35 inOrder.length - 1); 36 } 37 38 public static BinaryTreeNode constructCore(int preOrder[], 39 int startPreIndex, int endPreIndex, int inOrder[], 40 int startInIndex, int endInIndex) throws InvalidPutException { 41 // 頭結點的值 42 int rootValue = preOrder[startInIndex]; 43 44 // 構建一個只有一個根節點的二叉樹 45 BinaryTreeNode root = new BinaryTreeNode(rootValue); 46 // 只有一個元素的情況下: 47 if (startPreIndex == endPreIndex) { 48 if (startInIndex == endInIndex 49 && preOrder[startInIndex] == inOrder[endInIndex]) { 50 System.out.println("只有一個元素"); 51 return root; 52 } else { 53 throw new InvalidPutException(); 54 } 55 56 } 57 // 最重要的一步:在中序遍歷中找到根結點的索引 58 int rootInIndex = startInIndex; 59 while (rootInIndex <= endInIndex && inOrder[rootInIndex] != rootValue) { 60 rootInIndex++; 61 } 62 if (rootInIndex == endInIndex && inOrder[rootInIndex] != rootInIndex) { 63 throw new InvalidPutException(); 64 } 65 // 根節點的左子樹的長度 66 int leftLength = rootInIndex - startInIndex; 67 // 根節點的左子樹的最右端的索引值 68 int leftPreEndIndex = startPreIndex + leftLength; 69 // 構建左子樹 70 if (leftLength > 0) { 71 root.leftNode = constructCore(preOrder, startPreIndex + 1, 72 leftPreEndIndex, inOrder, startInIndex, rootInIndex - 1); 73 } 74 // 說明根節點存在右子樹 75 if (leftLength < endPreIndex - startPreIndex) { 76 root.rightNode = constructCore(preOrder, leftPreEndIndex + 1, 77 endPreIndex, inOrder, rootInIndex + 1, endInIndex); 78 } 79 return root; 80 } 81 82 // 按照前序遍歷打印二叉樹的節點 83 public static void printPreBinaryTree(BinaryTreeNode root) { 84 if (root == null) { 85 return; 86 } else { 87 System.out.println(root.value + " "); 88 } 89 if (root.leftNode != null) { 90 printPreBinaryTree(root.leftNode); 91 } 92 if (root.rightNode != null) { 93 printPreBinaryTree(root.rightNode); 94 } 95 } 96 97 public static class InvalidPutException extends Exception { 98 99 private static final long serialVersionUID = 1L; 100 } 101 102 /** 103 * @param args 104 * @throws Exception 105 */ 106 public static void main(String[] args) throws Exception { 107 int preOrder[] = { 1, 2, 4, 7, 3, 5, 6, 8 }; 108 int inOrder[] = { 4, 7, 2, 1, 5, 3, 8, 6 }; 109 ConstructBinaryTree test = new ConstructBinaryTree(); 110 printPreBinaryTree(test.construct(preOrder, inOrder, preOrder.length)); 111 } 112 113 }
Problem7:用兩個棧實現隊列
題目描述:用兩個棧實現一個隊列。隊列的聲明如下,請實現它的兩個函數appendTail和deleteHead,分別完成在隊列尾部插入結點和在隊列頭部刪除結點的功能
1 package Problem7; 2 3 import java.util.Stack; 4 5 public class ConStructQueue { 6 /* 7 * 問題描述:用兩個棧實現一個隊列。隊列的聲明如下,請實現它的兩個函數appendTail和deleteHead, 8 * 分別完成在隊列尾部插入結點和在隊列頭部刪除結點的功能 9 */ 10 11 /** 12 * @param args 13 */ 14 Stack<String> stack1 = new Stack<String>(); 15 Stack<String> stack2 = new Stack<String>(); 16 17 // 實現appendTail函數 18 public void appendTail(String s) { 19 stack1.push(s); 20 } 21 22 // 實現deleteHead函數 23 public String deleteHead() throws Exception { 24 if (stack2.isEmpty()) { 25 while (!stack1.isEmpty()) { 26 stack2.push(stack1.pop()); 27 } 28 } 29 if (stack2.isEmpty()) { 30 throw new Exception("隊列為空,不能進行刪除操作"); 31 } 32 return stack2.pop(); 33 } 34 35 public static void main(String[] args) throws Exception { 36 ConStructQueue test = new ConStructQueue(); 37 // 向空的隊列中添加元素、刪除元素 38 test.appendTail("1"); 39 System.out.println(test.deleteHead()); 40 // 向非空的隊列添加刪除元素 41 test.appendTail("2"); 42 test.appendTail("3"); 43 System.out.println(test.deleteHead()); 44 45 } 46 47 }
Problem8:旋轉數組的最小數字
題目描述:把一個數組最開始的若干個元素搬到數組的末尾,我們稱之為數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如數組{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉,該數組的最小值為1;
1 package Problem8; 2 3 public class MinInReversingList { 4 /* 5 * 題目描述:把一個數組最開始的若干個元素搬到數組的末尾,我們稱之為數組的旋轉。 6 * 輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。例如數組{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉,該數組的最小值為1; 7 */ 8 9 /** 10 * @param args 11 * @throws Exception 12 */ 13 public static int minElement(int array[]) throws Exception { 14 // 條件判斷 15 if (array == null || array.length <= 0) { 16 throw new Exception("Invalid parameters"); 17 } 18 int left = 0; 19 int right = array.length - 1; 20 int mid = left; 21 while (array[left] >= array[right]) { 22 // 跳出循環的條件 23 if (right - left == 1) { 24 mid = right; 25 break; 26 } 27 mid = (left + right) / 2; 28 if (array[left] == array[mid] && array[mid] == array[right]) { 29 return minFromSortSearch(array); 30 // 算法的核心思想 31 } else { 32 if (array[mid] >= array[left]) { 33 left = mid; 34 } 35 if (array[mid] <= array[right]) { 36 right = mid; 37 } 38 } 39 } 40 return array[right]; 41 } 42 43 public static int minFromSortSearch(int[] array) { 44 int minEle = array[0]; 45 for (int i = 1; i < array.length; i++) { 46 if (array[i] < minEle) { 47 minEle = array[i]; 48 } 49 } 50 return minEle; 51 } 52 53 // 測試 54 public static void main(String[] args) throws Exception { 55 // 功能測試:輸入的數組是升序排序數組的一個旋轉,數組中有重復數字或者沒有重復數字 56 int array1[] = { 3, 4, 5, 1, 2 }; 57 System.out.println(minElement(array1)); 58 int array2[] = { 3, 4, 5, 3, 3 }; 59 System.out.println(minElement(array2)); 60 // 邊界測試:輸入的數組是一個升序排序數組、只包含一個數字的數組 61 int array3[] = { 3 }; 62 System.out.println(minElement(array3)); 63 // 特殊輸入測試:輸入null指針 64 int array4[] = null; 65 System.out.println(minElement(array4)); 66 } 67 68 }
Problem9:斐波那契數列
題目描述:寫一個函數,輸入n,求斐波那契數列的第n項,斐波那契數列的定義如下: n=0,f(n)=0 ;n=1,f(n)=1 n>1;f(n)=f(n-1)+f(n-2).
1 package Problem9; 2 3 public class Fibonacci { 4 /* 5 * 題目描述: 寫一個函數,輸入n,求斐波那契數列的第n項,斐波那契數列的定義如下: n=0,f(n)=0 n=1,f(n)=1 6 * n>1;f(n)=f(n-1)+f(n-2) 7 */ 8 9 /** 10 * @param args 11 */ 12 // 解法1:用遞歸解決,但是存在很嚴重的效率問題,做了很多次的重復計算 13 public static int Fib1(int n) { 14 if (n == 0) { 15 return 0; 16 } else if (n == 1) { 17 return 1; 18 } else { 19 return Fib1(n - 1) + Fib1(n - 2); 20 } 21 22 } 23 24 // 解法2:時間復雜度為O(n),從下向上計算,保存已經計算過的數值,避免重復計算 25 public static long Fib2(int n) { 26 long FibOne = 0; 27 long FibTwo = 1; 28 long FibN = 0; 29 int result[] = { 1, 2 }; 30 if (n < 2) { 31 return result[n]; 32 } else { 33 for (int i = 2; i <= n; i++) { 34 FibN = FibTwo + FibOne; 35 FibOne = FibTwo; 36 FibTwo = FibN; 37 } 38 } 39 return FibN; 40 } 41 42 public static void main(String[] args) { 43 // 用解法1求序列的第100項,直接不動了 44 // System.out.println(Fib1(100)); 45 System.out.println(Fib2(100)); 46 } 47 }
相關題目:一只青蛙一次可以跳上一級台階,也可以跳上2級。求該青蛙跳上一個n級台階共有多少種跳法;
Problem10:二進制中1的個數
問題描述: 請實現一個函數,輸入一個整數,輸出該數二進制表示中1的個數。例如把9表示成二進制是1001,有2位是1 因此如果輸入9,該函數輸出2;
1 package Problem10; 2 3 public class NumberOf1 { 4 /* 5 * 問題描述: 請實現一個函數,輸入一個整數,輸出該數二進制表示中1的個數。例如把9表示成二進制是1001,有2位是1 因此如果輸入9,該函數輸出2 6 */ 7 8 /** 9 * @param args 10 */ 11 // 可能引起死循環的解法1 12 public static int numberof1_1(int n) { 13 int count = 0; 14 while (n != 0) { 15 if ((n & 1) != 0) { 16 count++; 17 } 18 n = n >> 1; 19 } 20 return count; 21 } 22 23 // 常規解法2 24 public static int numberof1_2(int n) { 25 int count = 0; 26 int flag = 1; 27 while (flag != 0) { 28 if ((n & flag) != 0) { 29 count++; 30 } 31 flag = flag << 1; 32 } 33 return count; 34 } 35 36 // 解法3:把一個吧整數減去1,再和原整數做位與運算,會把該整數最右邊一個1變成0 37 // 一個整數的二進制表示中有多少個1,就可以進行多少次這樣的操作 38 public static int numberof1_3(int n) { 39 int count = 0; 40 while (n != 0) { 41 count++; 42 n = n & (n - 1); 43 } 44 return count; 45 } 46 47 public static void main(String[] args) { 48 NumberOf1 test = new NumberOf1(); 49 // 測試一下解法1 50 System.out.println("解法1:" + test.numberof1_1(9)); 51 // 測試一下解法2 52 System.out.println("解法2:" + test.numberof1_2(100254)); 53 // 測試一下解法3:正數(邊界值)、負數、0 54 System.out.println("解法3:" + test.numberof1_3(0x7FFFFFFF)); 55 System.out.println("解法3:" + test.numberof1_3(1)); 56 System.out.println("解法3:" + test.numberof1_3(0x80000000)); 57 System.out.println("解法3:" + test.numberof1_3(0xFFFFFFFF)); 58 System.out.println("解法3:" + test.numberof1_3(0)); 59 } 60 61 }
Problem11:數值的整數次方
問題描述:實現函數double power(double base,int exponent),求base的exponent次方。不能使用庫函數,同時不需要考慮大數問題。
1 package Problem11; 2 3 public class Power { 4 /* 5 * 問題描述: 實現函數double power(double base,int exponent),求base的exponent 6 * 次方。不能使用庫函數,同時不需要考慮大數問題。 7 */ 8 9 /** 10 * @param args 11 */ 12 public double power(double base, int exponet) throws Exception { 13 double result = 0.0; 14 if (equals(base, 0) && (exponet < 0)) { 15 throw new Exception("0的負數次冪無意義"); 16 } 17 if (exponet == 0) { 18 return 1.0; 19 } 20 if (exponet < 0) { 21 result = powerWithUnsignedExponent(base, -exponet); 22 } else { 23 result = powerWithUnsignedExponent(base, exponet); 24 } 25 return result; 26 } 27 28 private double powerWithUnsignedExponent(double base, int exponet) { 29 double result = 1.0; 30 for (int i = 1; i <= exponet; i++) { 31 result = result * base; 32 } 33 return result; 34 } 35 36 // 由於計算機中表示小數都有誤差,不能用等號判斷兩個小數是否相等。如果兩個小數的差的絕對值很小 37 // 我們就可以認為它們是相等的 38 private boolean equals(double number1, int number2) { 39 if ((number1 - number2 > -0.00000001) 40 && (number1 - number2) < 0.00000001) { 41 return true; 42 } 43 return false; 44 } 45 46 // 寫測試:把底數和指數分別設置成正數、負數、0; 47 public static void main(String[] args) throws Exception { 48 Power test = new Power(); 49 System.out.println(test.power(2, 3)); 50 System.out.println(test.power(2, 0)); 51 System.out.println(test.power(2, -2)); 52 System.out.println(test.power(0, 3)); 53 System.out.println(test.power(0, 0)); 54 System.out.println(test.power(0, -2)); 55 56 } 57 58 }
Problem13:O(1)時間刪除鏈表結點
問題描述:給定單向鏈表的頭指針和一個結點指針,定義一個函數在O(1)時間刪除該結點。
1 package Problem13; 2 3 /* 4 * 問題描述:給定單向鏈表的頭指針和一個結點指針,定義一個函數在O(1)時間刪除該結點。 5 * 6 */ 7 //定義結點的結構 8 class ListNode { 9 ListNode nextNode; 10 int nodeValue; 11 } 12 13 public class DeleteNode { 14 public static void deleteNode(ListNode head, ListNode deListNode) { 15 // 空鏈表 16 if (head == null || deListNode == null) { 17 return; 18 } 19 // 要刪除的鏈表中只有一個結點 20 if (head == deListNode) { 21 head = null; 22 } else { 23 // 要刪除的結點不在鏈表的中間,不在尾部 24 if (deListNode.nextNode != null) { 25 deListNode.nodeValue = deListNode.nextNode.nodeValue; 26 deListNode.nextNode = deListNode.nextNode.nextNode; 27 } else { 28 ListNode pointNode = head; 29 while (pointNode.nextNode != deListNode) { 30 pointNode = pointNode.nextNode; 31 } 32 pointNode.nextNode = null; 33 } 34 } 35 } 36 37 /** 38 * @param args 39 */ 40 // 測試代碼 41 public static void main(String[] args) { 42 DeleteNode test = new DeleteNode(); 43 ListNode firListNode = new ListNode(); 44 ListNode secListNode = new ListNode(); 45 ListNode thiListNode = new ListNode(); 46 firListNode.nextNode = secListNode; 47 secListNode.nextNode = thiListNode; 48 firListNode.nodeValue = 1; 49 secListNode.nodeValue = 2; 50 thiListNode.nodeValue = 3; 51 test.deleteNode(firListNode, thiListNode); 52 System.out.println(firListNode.nextNode.nodeValue); 53 } 54 55 }
Problem14:調整數組順序使奇數位與偶數的后面
問題描述:輸入一個整數數組,實現一個函數來調整該數組中數字的順序,使得所有奇數位與數組的前半部分,所有偶數位與數組的后半部分;
1 package Problem14; 2 3 /* 4 * 問題描述: 5 * 輸入一個整數數組,實現一個函數來調整該數組中數字的順序,使得所有奇數位與數組的前半部分,所有偶數位與數組的 6 * 后半部分 7 */ 8 public class ReorderOddEven { 9 public static void reOrder(int array[]) { 10 int firstIndex = 0; 11 int lastIndex = array.length - 1; 12 if (array == null || (0 == array.length)) { 13 return; 14 } 15 while (firstIndex < lastIndex) { 16 while ((firstIndex < lastIndex) && !(isEven(array[firstIndex]))) { 17 firstIndex++; 18 } 19 while ((firstIndex < lastIndex) && isEven(array[lastIndex])) { 20 lastIndex--; 21 } 22 if (firstIndex < lastIndex) { 23 int temp = array[firstIndex]; 24 array[firstIndex] = array[lastIndex]; 25 array[lastIndex] = temp; 26 } 27 } 28 } 29 30 // 進行解耦操作:odd(奇數)、even(偶數) 31 private static boolean isEven(int n) { 32 33 return (n & 1) == 0; 34 } 35 36 public static void printArr(int array[]) { 37 for (int i = 0; i < array.length; i++) { 38 System.out.print(array[i] + ""); 39 } 40 } 41 42 /** 43 * @param args 44 * @throws Exception 45 */ 46 public static void main(String[] args) { 47 ReorderOddEven test = new ReorderOddEven(); 48 // 功能測試 49 // 奇偶交替出現 50 int array1[] = { 1, 2, 3, 4, 5, 6 }; 51 test.reOrder(array1); 52 printArr(array1); 53 System.out.println("------1------"); 54 // 所有偶數都位於奇數的前面 55 int array2[] = { 8, 2, 4, 5, 3, 6 }; 56 test.reOrder(array2); 57 printArr(array2); 58 System.out.println("------2------"); 59 // 所有奇數都位於偶數的前面 60 int array3[] = { 5, 3, 1, 7, 2, 4, 6, 8 }; 61 test.reOrder(array3); 62 printArr(array3); 63 System.out.println("------3------"); 64 // 輸入的數組只有一個元素 65 int array4[] = { 2 }; 66 test.reOrder(array4); 67 printArr(array4); 68 System.out.println("------4------"); 69 // 特殊輸入測試:輸入null指針 70 int array5[] = null; 71 test.reOrder(array5); 72 printArr(array5); 73 System.out.println("------5------"); 74 75 } 76 77 }
對應OJ在線編程題目:
題目描述
1 public class Solution { 2 public void reOrderArray(int [] array) { 3 for(int i=0;i<array.length-1;i++) 4 { 5 for(int j=0;j<array.length-1;j++) 6 { 7 if(array[j]%2==0&&array[j+1]%2==1) 8 { 9 int t=array[j]; 10 array[j]=array[j+1]; 11 array[j+1]=t; 12 } 13 } 14 } 15 16 } 17 }
解法二:時間復雜度O(n),空間復雜度O(n)
1 public class Solution { 2 public void reOrderArray(int [] array) { 3 4 reOrderCore(array,array.length); 5 } 6 private void reOrderCore(int array[],int len){ 7 8 if(array==null||array.length==0){ 9 return; 10 } 11 12 //用空間換時間 13 int newArray[]=new int[len]; 14 int index=0; 15 for(int i=0;i<len;i++){ 16 if((array[i]&1)==1){ 17 newArray[index++]=array[i]; 18 } 19 } 20 for(int i=0;i<len;i++){ 21 if((array[i]&1)==0){ 22 newArray[index++]=array[i]; 23 } 24 } 25 for(int i=0;i<len;i++){ 26 array[i]=newArray[i]; 27 } 28 } 29 }
Problem15:鏈表中倒數第K個結點
問題描述:輸入一個鏈表,輸出該鏈表中倒數第K個結點。為了符合大多數人的習慣,從1開始計數,即鏈表的尾結點是倒數第一個結點。例如一個鏈表有6個結點,從頭結點開始它們的值依次是1、2、3、4、5、6.這個鏈表的倒數第三個結點是值為4的結點。
1 package Problem15; 2 3 /* 4 * 問題描述: 5 * 輸入一個鏈表,輸出該鏈表中倒數第K個結點。為了符合大多數人的習慣,從1開始計數,即鏈表的 6 * 尾結點是倒數第一個結點。例如一個鏈表有6個結點,從頭結點開始它們的值依次是1、2、3、4、5、6. 7 * 這個鏈表的倒數第三個結點是值為4的結點。 8 */ 9 10 //定義鏈表的結點結構 11 class ListNode { 12 ListNode next; 13 int data; 14 15 public ListNode(int data) { 16 this.data = data; 17 } 18 } 19 20 public class FindKthFromTail { 21 22 /* 23 * 需要考慮三種情況: 1.鏈表為空; 2.鏈表的長度不足k; 3.k=0; 24 */ 25 26 public static int find(ListNode head, int k) { 27 if (head == null || (0 == k)) { 28 return 0; 29 } 30 ListNode first = head; 31 ListNode second = null; 32 // 第一個指針先走k-1 33 for (int i = 1; i < k; i++) { 34 if (first.next != null) { 35 first = first.next; 36 } else { 37 return 0; 38 } 39 } 40 second = head; 41 while (first.next != null) { 42 first = first.next; 43 second = second.next; 44 } 45 return second.data; 46 } 47 48 /** 49 * @param args 50 */ 51 // 進行測試 52 public static void main(String[] args) { 53 FindKthFromTail test = new FindKthFromTail(); 54 // 功能測試:第K個結點位與鏈表的中間、頭部、尾部 55 ListNode node1 = new ListNode(1); 56 ListNode node2 = new ListNode(2); 57 ListNode node3 = new ListNode(3); 58 ListNode node4 = new ListNode(4); 59 node1.next = node2; 60 node2.next = node3; 61 node3.next = node4; 62 node4.next = null; 63 System.out.println(test.find(node1, 3)); 64 System.out.println(test.find(node1, 1)); 65 System.out.println(test.find(node1, 4)); 66 // 特殊輸入測試:k=0 67 System.out.println(test.find(node1, 0)); 68 // k>4 69 System.out.println(test.find(node1, 5)); 70 // 鏈表為空 71 node1 = null; 72 System.out.println(test.find(node1, 3)); 73 } 74 75 }
Problem16:反轉鏈表
問題描述:定義一個函數,輸入一個鏈表的頭結點,反轉該鏈表並輸出反轉后鏈表的頭結點。
解法一:非遞歸實現
1 package Problem16; 2 3 /* 4 * 問題描述: 5 * 定義一個函數,輸入一個鏈表的頭結點,反轉該鏈表並輸出反轉后鏈表的頭結點。 6 */ 7 //定義鏈表的結點結構 8 class ListNode { 9 ListNode next; 10 int data; 11 12 public ListNode(int data) { 13 this.data = data; 14 } 15 } 16 17 public class ReversList { 18 19 public static int getReverseListHead(ListNode head) { 20 // 定義一個結點,用來保存找到的反轉鏈表的表頭結點 21 // 當前正在遍歷的結點p 22 ListNode pNode = head; 23 // 結點p的前一個結點 24 ListNode preNode = null; 25 // 結點p的后一個結點 26 ListNode reversHeadNode = null; 27 if (head == null) { 28 return 0; 29 } 30 if (head.next == null) { 31 return head.data; 32 } else { 33 while (pNode != null) { 34 ListNode nextNode = null; 35 nextNode = pNode.next; 36 if (nextNode == null) { 37 reversHeadNode = pNode; 38 } 39 pNode.next = preNode; 40 preNode = pNode; 41 pNode = nextNode; 42 } 43 } 44 return reversHeadNode.data; 45 46 } 47 48 /** 49 * @param args 50 */ 51 // 測試 52 public static void main(String[] args) { 53 ReversList test = new ReversList(); 54 ListNode node1 = new ListNode(1); 55 ListNode node2 = new ListNode(2); 56 ListNode node3 = new ListNode(3); 57 ListNode node4 = new ListNode(4); 58 node1.next = node2; 59 node2.next = node3; 60 node3.next = node4; 61 node4.next = null; 62 // 功能測試:鏈表中有多個結點、有一個結點 63 // 特殊輸入測試:鏈表頭結點為null指針 64 System.out.println(test.getReverseListHead(node1)); 65 } 66 67 }
解法二:遞歸實現
1 /* 2 public class ListNode { 3 int val; 4 ListNode next = null; 5 6 ListNode(int val) { 7 this.val = val; 8 } 9 }*/ 10 public class Solution { 11 public ListNode ReverseList(ListNode head) { 12 //鏈表只有一個節點或者到達了鏈表的尾部 13 if(head==null||head.next==null){ 14 return head; 15 } 16 ListNode newList=ReverseList(head.next); 17 18 head.next.next=head; 19 head.next=null; 20 return newList; 21 } 22 }
Problem17:合並兩個排序的鏈表
問題描述: 輸入兩個遞增排序的鏈表,合並這兩個鏈表並使新鏈表中的結點仍然是按照遞增排序的。
1 package Problem17; 2 3 /* 4 * 問題描述: 5 * 輸入兩個遞增排序的鏈表,合並這兩個鏈表並使新鏈表中的結點仍然是按照遞增排序的。 6 */ 7 8 //定義鏈表結點的結構 9 class ListNode { 10 ListNode next; 11 int data; 12 13 public ListNode() { 14 15 } 16 17 public ListNode(int data) { 18 this.data = data; 19 } 20 } 21 22 public class MergeList { 23 24 public static ListNode Merge(ListNode head1, ListNode head2) { 25 if (head1 == null) { 26 return head2; 27 } 28 if (head2 == null) { 29 return head1; 30 } 31 ListNode mergeNode = null; 32 ; 33 if (head1.data < head2.data) { 34 mergeNode = head1; 35 mergeNode.next = Merge(head1.next, head2); 36 } else { 37 mergeNode = head2; 38 mergeNode.next = Merge(head1, head2.next); 39 } 40 return mergeNode; 41 } 42 43 public static void printList(ListNode merge) { 44 ListNode head = merge; 45 while (head != null) { 46 System.out.print(head.data); 47 head = head.next; 48 } 49 System.out.println(); 50 } 51 52 /** 53 * @param args 54 */ 55 56 // 測試 57 public static void main(String[] args) { 58 // 功能測試:輸入的兩個鏈表有多個結點,結點的值互不相同或者存在相等的多個結點 59 // 特殊輸入測試:兩個鏈表中的一個或者兩個頭結點為null指針、兩個鏈表中只有一個結點 60 MergeList test = new MergeList(); 61 ListNode head1 = new ListNode(2); 62 ListNode head2 = new ListNode(4); 63 ListNode head3 = new ListNode(8); 64 head1.next = head2; 65 head2.next = head3; 66 head3.next = null; 67 ListNode sec1 = new ListNode(1); 68 ListNode sec2 = new ListNode(3); 69 ListNode sec3 = new ListNode(9); 70 sec1.next = sec2; 71 sec2.next = sec3; 72 sec3.next = null; 73 ListNode merge = new ListNode(); 74 merge = test.Merge(head1, sec1); 75 test.printList(merge); 76 } 77 78 }
Problem18:樹的子結構
題目描述:輸入兩棵二叉樹A和B,判斷B是不是A的子結構;
1 /** 2 public class TreeNode { 3 int val = 0; 4 TreeNode left = null; 5 TreeNode right = null; 6 7 public TreeNode(int val) { 8 this.val = val; 9 10 } 11 12 } 13 */ 14 public class Solution { 15 //空樹不是任何一個樹的子結構 16 public boolean HasSubtree(TreeNode root1,TreeNode root2) { 17 if(root1==null||root2==null){ 18 return false; 19 } 20 boolean result=false; 21 22 //第一步;在樹A中找到和樹B根結點值相同的節點,因此需要對二叉樹進行遍歷 23 if(root1!=null&&root2!=null){ 24 if(root1.val==root2.val){ 25 result=DoTheJudge(root1,root2); 26 } 27 if(!result){ 28 result=HasSubtree(root1.left,root2); 29 } 30 if(!result){ 31 result=HasSubtree(root1.right,root2); 32 } 33 } 34 return result; 35 } 36 private boolean DoTheJudge(TreeNode root1,TreeNode root2){ 37 //遍歷完樹A都沒有,其中都沒有完全匹配樹B的子結構 38 if(root1==null&&root2!=null){ 39 return false; 40 } 41 //root2的所有節點與root1中進行了匹配 42 if(root2==null){ 43 return true; 44 } 45 if(root1.val!=root2.val){ 46 return false; 47 }else{ 48 return DoTheJudge(root1.left,root2.left)&&DoTheJudge(root1.right,root2.right); 49 } 50 } 51 } 52
Problem19:二叉樹的鏡像
題目描述:請完成一個函數,輸入一個二叉樹,該函數輸出它的鏡像;
1 package Problem19; 2 3 /* 4 * 問題描述: 5 * 請完成一個函數,輸入一個二叉樹,該函數輸出它的鏡像; 6 */ 7 8 //定義二叉樹的結構 9 class BinaryTreeNode { 10 BinaryTreeNode leftNode; 11 BinaryTreeNode rightNode; 12 int value; 13 } 14 15 public class MirrorOfBinaryTree { 16 17 public static void mirroOfBinTree(BinaryTreeNode root) { 18 if (root == null) { 19 return; 20 } 21 if (root.leftNode == null || root.rightNode == null) { 22 return; 23 } 24 // 交換一個結點的左右子節點 25 int tempValue; 26 tempValue = root.leftNode.value; 27 root.leftNode.value = root.rightNode.value; 28 root.rightNode.value = tempValue; 29 // 遞歸操作左右子節點 30 if (root.leftNode != null) { 31 mirroOfBinTree(root.leftNode); 32 } 33 if (root.rightNode != null) { 34 mirroOfBinTree(root.rightNode); 35 } 36 } 37 38 /** 39 * @param args 40 */ 41 // 功能測試:普通的二叉樹,二叉樹的所有結點都沒有左子樹或者右子樹,只有一個結點的二叉樹 42 // 特殊輸入測試:二叉樹的根節點為null指針 43 public static void main(String[] args) { 44 BinaryTreeNode root1 = new BinaryTreeNode(); 45 BinaryTreeNode node1 = new BinaryTreeNode(); 46 BinaryTreeNode node2 = new BinaryTreeNode(); 47 BinaryTreeNode node3 = new BinaryTreeNode(); 48 BinaryTreeNode node4 = new BinaryTreeNode(); 49 BinaryTreeNode node5 = new BinaryTreeNode(); 50 BinaryTreeNode node6 = new BinaryTreeNode(); 51 root1.leftNode = node1; 52 root1.rightNode = node2; 53 node1.leftNode = node3; 54 node1.rightNode = node4; 55 node4.leftNode = node5; 56 node4.rightNode = node6; 57 root1.value = 8; 58 node1.value = 8; 59 node2.value = 7; 60 node3.value = 9; 61 node4.value = 2; 62 node5.value = 4; 63 node6.value = 7; 64 65 MirrorOfBinaryTree.mirroOfBinTree(root1); 66 System.out.println(root1.rightNode.value); 67 } 68 69 }
Problem20:順時針打印矩陣
題目描述:輸入一個矩陣,按照從外向里以順時針的順組依次打印出每一個數字。
解法一:
1 import java.util.ArrayList; 2 public class Solution { 3 public ArrayList<Integer> printMatrix(int [][] matrix) { 4 5 ArrayList<Integer> result=new ArrayList<>(); 6 if(matrix==null||matrix.length<0|matrix[0].length<0){ 7 return result; 8 } 9 int rows=matrix.length; 10 int columns=matrix[0].length; 11 int start=0; 12 //打印的起始位置 13 //循環中打印每一圈 14 while(rows>2*start&&columns>2*start){ 15 result=printMatrixCicle(matrix,rows,columns,start,result); 16 start++; 17 } 18 return result; 19 20 } 21 // 22 private ArrayList<Integer> printMatrixCicle(int matrix[][],int rows,int columns,int start,ArrayList<Integer> result){ 23 int endX=rows-1-start; 24 int endY=columns-1-start; 25 //從左到右打印一行 26 for(int i=start;i<=endY;i++){ 27 result.add(matrix[start][i]); 28 } 29 //從上到下打印一列:至少需要兩行,即終止行號需要大於起始行號 30 if(start<endX){ 31 for(int i=start+1;i<=endX;i++){ 32 result.add(matrix[i][endY]); 33 } 34 } 35 //從右到左打印一行,至少需要兩行兩列 36 if(start<endX&&start<endY){ 37 for(int i=endY-1;i>=start;i--){ 38 result.add(matrix[endX][i]); 39 } 40 } 41 //從下到上打印一列,至少需要三行兩列 42 if(endX>start+1&&endY>start){ 43 for(int i=endX-1;i>=start+1;i--){ 44 result.add(matrix[i][start]); 45 } 46 } 47 return result; 48 } 49 }
解法二:
1 import java.util.ArrayList; 2 public class Solution { 3 public ArrayList<Integer> printMatrix(int [][] matrix) { 4 ArrayList<Integer> result=new ArrayList<Integer>(); 5 if(matrix==null||matrix.length<=0||matrix[0].length<=0){ 6 return result; 7 } 8 int up=0; 9 int down=matrix.length-1; 10 int left=0; 11 int right=matrix[0].length-1; 12 while(left<=right&&up<=down){ 13 //從左到右打印一行 14 for(int i=left;i<=right;i++){ 15 result.add(matrix[up][i]); 16 } 17 up++; 18 //從上到下打印一列 19 for(int i=up;i<=down;i++){ 20 result.add(matrix[i][right]); 21 } 22 right--; 23 //從右到左打印一行,if判斷是否有下一行需要打印 24 if(up-1!=down){ 25 for(int i=right;i>=left;i--){ 26 result.add(matrix[down][i]); 27 } 28 } 29 down--; 30 //從下到上打印一列 ,if判斷是否還有下一列需要打印 31 if(left!=right+1){ 32 for(int i=down;i>=up;i--){ 33 result.add(matrix[i][left]); 34 } 35 } 36 left++; 37 38 } 39 return result; 40 41 } 42 }
Problem21:包含min函數的棧
題目描述:定義棧的數據結構,請在該類型中實現一個能夠得到棧的最小元素的min函數。在該棧中,調用min、push以及pop的時間復雜度為O(1)
1 import java.util.Stack; 2 3 4 public class Solution { 5 6 //數據棧 7 private Stack<Integer> stackData; 8 //輔助棧 9 private Stack<Integer> stackMin; 10 11 public Solution(){ 12 stackData=new Stack<Integer>(); 13 stackMin=new Stack<Integer>(); 14 } 15 16 //入棧操作 17 public void push(int node) { 18 stackData.push(node); 19 if(stackMin.empty()){ 20 stackMin.push(node); 21 }else{ 22 if(node<=stackMin.peek()){ 23 stackMin.push(node); 24 } 25 } 26 } 27 //出棧操作 28 public void pop() { 29 int data=stackData.pop(); 30 if(data==stackMin.peek()){ 31 stackMin.pop(); 32 } 33 34 } 35 //返回棧頂的元素 36 public int top() { 37 return stackData.peek(); 38 } 39 //得到棧的最小元素 40 public int min() { 41 return stackMin.peek(); 42 } 43 }
Problem22:棧的壓入、彈出序列
題目描述:輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否為該棧的彈出序列。假設壓入棧的所有數字均不相等。例如序列1/2/3/4/5是某棧的壓棧序列,序列4/5/3/2/1是該壓棧序列對應的一個彈出序列,但4/3/5/1/2就不可能是該壓棧序列的彈出序列;
1 package Problem22; 2 3 import java.util.Stack; 4 5 /* 6 * 問題描述:輸入兩個整數序列,第一個序列表示棧的壓入順序,請判斷第二個序列是否為該棧的彈出序列。假設壓入棧的所有數字均不相等。 7 * 例如序列1/2/3/4/5是某棧的壓棧序列,序列4/5/3/2/1是該壓棧序列對應的一個彈出序列,但4/3/5/1/2就不可能是該壓棧序列的彈出序列 8 */ 9 10 public class IsPopOrder { 11 /* 12 * 輸入兩個整數序列,第一個序列表示壓入順序,判斷第二個序列是否為彈出順序.假設入棧所有數字均不相等 13 */ 14 public boolean isPopOrder(int[] line1, int[] line2) { 15 if (line1 == null || line2 == null) 16 return false; 17 int point1 = 0; 18 Stack<Integer> stack = new Stack<Integer>(); 19 for (int i = 0; i < line2.length; i++) { 20 if (!stack.isEmpty() && stack.peek() == line2[i]) { 21 stack.pop(); 22 } else { 23 if (point1 == line1.length) 24 return false; 25 else { 26 do 27 stack.push(line1[point1++]); 28 while (stack.peek() != line2[i] && point1 != line1.length); 29 if (stack.peek() == line2[i]) 30 stack.pop(); 31 else 32 return false; 33 } 34 } 35 } 36 return true; 37 } 38 39 public static void main(String args[]) { 40 int[] array1 = { 1, 2, 3, 4, 5 }; 41 int[] array2 = { 4, 3, 5, 1, 2 }; 42 IsPopOrder test = new IsPopOrder(); 43 System.out.println(test.isPopOrder(array1, array2)); 44 } 45 }
Problem23:從上往下打印二叉樹
題目描述:
從上往下打印出二叉樹的每個節點,同層節點從左至右打印。
1 import java.util.ArrayList; 2 import java.util.LinkedList; 3 /** 4 public class TreeNode { 5 int val = 0; 6 TreeNode left = null; 7 TreeNode right = null; 8 9 public TreeNode(int val) { 10 this.val = val; 11 12 } 13 14 } 15 */ 16 public class Solution { 17 public ArrayList<Integer> PrintFromTopToBottom(TreeNode root) { 18 //定義一個輔助隊列 19 LinkedList<TreeNode> queue=new LinkedList<>(); 20 //存儲一層的打印結果 21 ArrayList<Integer> resultCur=new ArrayList<Integer>(); 22 //存儲所有的打印結果 23 //ArrayList<ArrayList<Integer>> result=new ArrayList<>(); 24 if(root==null){ 25 return resultCur; 26 } 27 //定義兩個變量last和nlast,分別記錄當前行的最右節點和下一行的最右節點 28 TreeNode last=root; 29 TreeNode nlast=root; 30 TreeNode cur=root; 31 queue.add(root); 32 while(queue.size()!=0){ 33 cur=queue.poll(); 34 resultCur.add(cur.val); 35 if(cur.left!=null){ 36 queue.add(cur.left); 37 nlast=cur.left; 38 } 39 if(cur.right!=null){ 40 queue.add(cur.right); 41 nlast=cur.right; 42 } 43 if(cur==last){ 44 //result.add(resultCur); 45 // resultCur=new ArrayList<>(); 46 last=nlast; 47 } 48 } 49 return resultCur; 50 } 51 }
Problem24 二叉搜索樹的后序遍歷序列
題目描述:
輸入一個整數數組,判斷該數組是不是某二叉搜索樹的后序遍歷的結果。如果是則輸出Yes,否則輸出No。假設輸入的數組的任意兩個數字都互不相同。
Problem29 數組中出現次數超過一半的數字
1 public class Solution { 2 public boolean VerifySquenceOfBST(int [] sequence) { 3 if(sequence.length == 0) return false; 4 return IsTreeBST(sequence, 0, sequence.length-1); 5 } 6 public boolean IsTreeBST(int [] sequence,int start,int end ){ 7 //if(end <= start) return true; 8 int i = start; 9 for (; i < end; i++) { 10 if(sequence[i] > sequence[end]) break; 11 } 12 int j; 13 for (j = i; j < end; j++) { 14 if(sequence[j] < sequence[end]) return false; 15 } 16 boolean left=true; 17 //根結點左子樹不為空 18 if(i>0){ 19 left=IsTreeBST(sequence, start, i-1); 20 } 21 boolean right=true; 22 //根結點右子樹不為空 23 if(j<end-1){ 24 return IsTreeBST(sequence, i, end-1); 25 } 26 return left&&right; 27 } 28 }
Problem24 二叉樹中和為某一值的路徑
題目描述:
輸入一顆二叉樹和一個整數,打印出二叉樹中結點值的和為輸入整數的所有路徑。路徑定義為從樹的根結點開始往下一直到葉結點所經過的結點形成一條路徑。
1 import java.util.ArrayList; 2 //import java.util.Stack; 3 /** 4 public class TreeNode { 5 int val = 0; 6 TreeNode left = null; 7 TreeNode right = null; 8 9 public TreeNode(int val) { 10 this.val = val; 11 12 } 13 14 } 15 */ 16 //需要注意的是遞歸函數的參數傳遞,如果是在FindPathCore函數中定義curResult和curSum時,不傳入該函數的話,它的下一級遞歸函數是無法看到這兩個值的 17 public class Solution { 18 public ArrayList<ArrayList<Integer>> FindPath(TreeNode root,int target) { 19 //定義result用於存儲找到的所有符合條件的路徑 20 ArrayList<ArrayList<Integer>> result=new ArrayList<>(); 21 ArrayList<Integer> curResult=new ArrayList<>(); 22 if(root==null){ 23 return result; 24 } 25 int curSum=0; 26 FindPathCore(root,target,curResult,result,curSum); 27 return result; 28 } 29 30 private void FindPathCore(TreeNode root,int target,ArrayList<Integer> curResult,ArrayList<ArrayList<Integer>> result,int curSum){ 31 if(root==null){ 32 return; 33 } 34 boolean isLeaf=(root.left==null&&root.right==null); 35 36 curSum+=root.val; 37 //如果讓前節點是葉子節點 38 if(isLeaf){ 39 if(curSum==target){ 40 curResult.add(root.val); 41 result.add(new ArrayList<Integer>(curResult)); 42 //路徑中取出該葉子節點 43 curResult.remove(curResult.size()-1); 44 } 45 //返回上層節點,並從當前路徑和中減去該葉子節點 46 curSum-=root.val; 47 return; 48 } 49 curResult.add(root.val); 50 FindPathCore(root.left,target,curResult,result,curSum); 51 FindPathCore(root.right,target,curResult,result,curSum); 52 curResult.remove(curResult.size()-1); 53 54 } 55 }
Problem28 字符串的排列
題目描述:
輸入描述:
輸入一個字符串,長度不超過9(可能有字符重復),字符只包括大小寫字母。
1 import java.util.*; 2 public class Solution { 3 public ArrayList<String> Permutation(String str) { 4 ArrayList<String> re = new ArrayList<String>(); 5 if (str == null || str.length() == 0) { 6 return re; 7 } 8 HashSet<String> set = new HashSet<String>(); 9 fun(set, str.toCharArray(), 0); 10 re.addAll(set); 11 Collections.sort(re); 12 return re; 13 } 14 void fun(HashSet<String> re, char[] str, int beginIndex) { 15 if (beginIndex == str.length) { 16 //找到了一個字符串 17 re.add(new String(str)); 18 return; 19 } 20 for (int i = beginIndex; i < str.length; i++) { 21 swap(str, i, beginIndex); 22 fun(re, str, beginIndex + 1); 23 swap(str, i, beginIndex); 24 } 25 } 26 void swap(char[] str, int i, int j) { 27 if (i != j) { 28 char t = str[i]; 29 str[i] = str[j]; 30 str[j] = t; 31 } 32 } 33 }
Problem29 數組中出現次數超過一半的數字
題目描述
數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。例如輸入一個長度為9的數組{1,2,3,2,2,2,5,4,2}。由於數字2在數組中出現了5次,超過數組長度的一半,因此輸出2。如果不存在則輸出0。
1 public class Solution { 2 boolean isInvalid=false; 3 4 public int MoreThanHalfNum_Solution(int [] array) { 5 6 if(CheckInvalidArray(array,array.length)){ 7 return -1; 8 } 9 int result=array[0]; 10 int count=1; 11 for(int i=1;i<array.length;i++){ 12 if(count==0){ 13 result=array[i]; 14 count=1; 15 }else if(array[i]==result){ 16 count++; 17 }else{ 18 count--; 19 } 20 } 21 if(!CheckMoreThanHalf(array,array.length,result)){ 22 result=0; 23 } 24 return result; 25 } 26 //判斷數組是否為null或者數組長度為0,我們在這里封裝成一個函數,以后多考慮這種用法 27 private boolean CheckInvalidArray(int[] arr,int length){ 28 29 isInvalid=false; 30 //輸入無效的情況 31 if(arr==null||length==0){ 32 isInvalid=true; 33 } 34 return isInvalid; 35 } 36 //判斷一個數字的出現次數是否超過數組元素的一半 37 private boolean CheckMoreThanHalf(int[] arr,int length,int number){ 38 int count=0; 39 for(int i=0;i<length;i++){ 40 if(arr[i]==number){ 41 count++; 42 } 43 } 44 boolean isMoreThanHalf=true; 45 if(count*2<=length){ 46 isInvalid=true; 47 isMoreThanHalf=false; 48 } 49 return isMoreThanHalf; 50 } 51 }
解法二:使用哈希表,時間復雜度和空間復雜度都為O(n)
1 public class Solution { 2 3 public int MoreThanHalfNum_Solution(int [] array) { 4 if(array==null||array.length==0){ 5 return -1; 6 } 7 //使用哈希表 8 int mapArr[]=new int[256]; 9 for(int i=0;i<mapArr.length;i++){ 10 mapArr[i]=0; 11 } 12 for(int i=0;i<array.length;i++){ 13 mapArr[array[i]]++; 14 } 15 for(int i=0;i<mapArr.length;i++){ 16 if(mapArr[i]>(array.length)/2){ 17 return i; 18 } 19 } 20 //沒有找到這樣的數字 21 return 0; 22 } 23 }
Problem31連續子數組的最大和
題目描述:
HZ偶爾會拿些專業問題來忽悠那些非計算機專業的同學。今天測試組開完會后,他又發話了:在古老的一維模式識別中,常常需要計算連續子向量的最大和,當向量全為正數的時候,問題很好解決。但是,如果向量中包含負數,是否應該包含某個負數,並期望旁邊的正數會彌補它呢?例如:{6,-3,-2,7,-15,1,2,2},連續子向量的最大和為8(從第0個開始,到第3個為止)。你會不會被他忽悠住?(子向量的長度至少是1)
1 public class Solution { 2 public int FindGreatestSumOfSubArray(int[] array)throws Exception{ 3 if(array==null||array.length==0){ 4 throw new Exception("重新考慮輸入"); 5 } 6 //用於保存已經找到的連續子數組的最大和 7 int maxSum=array[0]; 8 //當前最大和 9 int curSum=array[0]; 10 for(int i=1;i<array.length;i++){ 11 //curSum<=0;說明從開始的位置到i-1的位置的元素不可能屬於這個連續子數組的范圍 12 //因此從數組下標為i的元素繼續尋找 13 if(curSum<=0){ 14 curSum=array[i]; 15 }else{ 16 curSum+=array[i]; 17 } 18 //判斷此時經過一次循環我們找到的最大值與之前已經有的最大值的大小 19 if(curSum>maxSum){ 20 maxSum=curSum; 21 } 22 } 23 return maxSum; 24 } 25 }
Problem32 整數中1出現的次數
題目描述:
求出1~13的整數中1出現的次數,並算出100~1300的整數中1出現的次數?為此他特別數了一下1~13中包含1的數字有1、10、11、12、13因此共出現6次,但是對於后面問題他就沒轍了。ACMer希望你們幫幫他,並把問題更加普遍化,可以很快的求出任意非負整數區間中1出現的次數。
解法一:時間復雜度N*(logN)
1 public class Solution { 2 public int NumberOf1Between1AndN_Solution(int n) { 3 int count=0; 4 for(int i=1;i<=n;i++){ 5 6 count+=core(i); 7 } 8 9 return count; 10 } 11 private int core(int n){ 12 int num=0; 13 while(n!=0){ 14 if(n%10==1){ 15 num++; 16 } 17 n/=10; 18 } 19 return num; 20 } 21 }
Problem33 把數組排成最小的數
題目描述:
輸入一個正整數數組,把數組里所有數字拼接起來排成一個數,打印能拼接出的所有數字中最小的一個。例如輸入數組{3,32,321},則打印出這三個數字能排成的最小數字為321323。
1 import java.util.*; 2 3 /* 4 * 解題思路: 5 * 先將整型數組轉換成String數組,然后將String數組排序,最后將排好序的字符串數組拼接出來。關鍵就是制定排序規則。 6 * 排序規則如下: 7 * 若ab > ba 則 a > b, 8 * 若ab < ba 則 a < b, 9 * 若ab = ba 則 a = b; 10 * 解釋說明: 11 * 比如 "3" < "31"但是 "331" > "313",所以要將二者拼接起來進行比較 12 */ 13 public class Solution { 14 public String PrintMinNumber(int [] numbers) { 15 if(numbers==null||numbers.length<1){ 16 return ""; 17 } 18 int len=numbers.length; 19 //將數組元素轉換為字符串數組中的元素,即用字符串表示數字,應對大數溢出問題 20 String[] str=new String[len]; 21 for(int i=0;i<len;i++){ 22 str[i]=String.valueOf(numbers[i]); 23 } 24 Arrays.sort(str,new Comparator<String>(){ 25 @Override 26 public int compare(String c1,String c2){ 27 return (c1+c2).compareTo(c2+c1); 28 } 29 }); 30 StringBuilder builder=new StringBuilder(); 31 for(int i=0;i<len;i++){ 32 builder.append(str[i]); 33 } 34 return builder.toString(); 35 } 36 }
Problem34 丑數
題目描述:
把只包含因子2、3和5的數稱作丑數(Ugly Number)。例如6、8都是丑數,但14不是,因為它包含因子7。 習慣上我們把1當做是第一個丑數。求按從小到大的順序的第N個丑數。
解法1:
1 public class Solution { 2 public int GetUglyNumber_Solution(int index) { 3 4 if(index<=0){ 5 return 0; 6 } 7 int uglyCount=0; 8 int num=0; 9 while(uglyCount<index){ 10 ++num; 11 if(isUglyNumber(num)){ 12 ++uglyCount; 13 } 14 } 15 return num; 16 } 17 private boolean isUglyNumber(int num){ 18 19 while(num%2==0){ 20 num=num/2; 21 } 22 while(num%3==0){ 23 num/=3; 24 } 25 while(num%5==0){ 26 num/=5; 27 } 28 return (num==1)?true:false; 29 } 30 }
解法二:
1 public class Solution { 2 //用空間換時間的方法 3 public int GetUglyNumber_Solution(int index) { 4 if(index<=0){ 5 return 0; 6 } 7 //輔助數組,大小為index 8 int uglyArr[]=new int[index]; 9 //題目中描述的第一個丑數為1 10 uglyArr[0]=1; 11 //下一個丑數的位置 12 int nextUgly=1; 13 14 int index2=0; 15 int index3=0; 16 int index5=0; 17 18 int ugly2=uglyArr[index2]; 19 int ugly3=uglyArr[index3]; 20 int ugly5=uglyArr[index5]; 21 22 //找到的丑數的數目還不滿足要求 23 while(nextUgly<index){ 24 int min=Min(ugly2*2,ugly3*3,ugly5*5); 25 uglyArr[nextUgly]=min; 26 27 28 while(uglyArr[index2]*2<=uglyArr[nextUgly]){ 29 30 ugly2=uglyArr[++index2]; 31 } 32 33 while(uglyArr[index3]*3<=uglyArr[nextUgly]){ 34 35 ugly3=uglyArr[++index3]; 36 } 37 38 while(uglyArr[index5]*5<=uglyArr[nextUgly]){ 39 40 ugly5=uglyArr[++index5]; 41 } 42 ++nextUgly; 43 } 44 return uglyArr[nextUgly-1]; 45 } 46 //求三個數的最小值的Min函數 47 private int Min(int num1,int num2,int num3){ 48 int min=num1<num2?num1:num2; 49 return min<num3?min:num3; 50 } 51 }
Problem35 第一個只出現一次的字符
題目描述:
在一個字符串(1<=字符串長度<=10000,全部由字母組成)中找到第一個只出現一次的字符,並返回它的位置
1 public class Solution { 2 public int FirstNotRepeatingChar(String str) { 3 //哈希表的使用 4 int mapArr[]=new int[256]; 5 for(int i=0;i<mapArr.length;i++){ 6 mapArr[i]=0; 7 } 8 char chs[]=str.toCharArray(); 9 int lens=chs.length; 10 for(int i=0;i<lens;i++){ 11 mapArr[chs[i]]++; 12 } 13 14 for(int i=0;i<lens;i++){ 15 if(mapArr[chs[i]]==1){ 16 return i; 17 } 18 } 19 return -1; 20 } 21 }
Problem36數組中的逆序對
題目描述
輸入描述:
題目保證輸入的數組中沒有的相同的數字
數據范圍:
對於%50的數據,size<=10^4
對於%75的數據,size<=10^5
對於%100的數據,size<=2*10^5
輸入
1,2,3,4,5,6,7,0
輸出
7
1 /* 2 *歸並排序的思想,最后求得的逆序數進行取摸 % 1000000007 3 */ 4 public class Solution { 5 public int InversePairs(int [] array) { 6 if(array==null || array.length<=0){ 7 return 0; 8 } 9 int pairsNum=mergeSort(array,0,array.length-1); 10 return pairsNum; 11 } 12 13 public int mergeSort(int[] array,int left,int right){ 14 if(left==right){ 15 return 0; 16 } 17 int mid=(left+right)/2; 18 int leftNum=mergeSort(array,left,mid); 19 int rightNum=mergeSort(array,mid+1,right); 20 return (Sort(array,left,mid,right)+leftNum+rightNum)%1000000007; 21 } 22 23 public int Sort(int[] array,int left,int middle,int right){ 24 int current1=middle; 25 int current2=right; 26 int current3=right-left; 27 int temp[]=new int[right-left+1]; 28 int pairsnum=0; 29 while(current1>=left && current2>=middle+1){ 30 if(array[current1]>array[current2]){ 31 temp[current3--]=array[current1--]; 32 pairsnum+=(current2-middle); //這個地方是current2-middle!!!! 33 if(pairsnum>1000000007)//數值過大求余 34 { 35 pairsnum%=1000000007; 36 } 37 }else{ 38 temp[current3--]=array[current2--]; 39 } 40 } 41 while(current1>=left){ 42 temp[current3--]=array[current1--]; 43 } 44 while(current2>=middle+1){ 45 temp[current3--]=array[current2--]; 46 } 47 //將臨時數組賦值給原數組 48 int i=0; 49 while(left<=right){ 50 array[left++]=temp[i++]; 51 } 52 return pairsnum; 53 } 54 }
Problem37 兩個鏈表的第一個公共節點
題目描述:輸入兩個鏈表,找出它們的第一個公共結點。
解法一:蠻力法
碰到這道題,很多人的第一反應就是蠻力法:在第一鏈表上順序遍歷每個結點,每遍歷到一個結點的時候,在第二個鏈表上順序遍歷每個結點。如果在第二個鏈表上有一個結點和第一個鏈表上的結點一樣,說明兩個鏈表在這個結點上重合,於是就找到了它們的公共結點。如果第一個鏈表的長度為m,第二個鏈表的長度為n,顯然該方法的時間復雜度是O(mn)。
解法二:借助外部空間法
首先,經過分析我們發現兩個有公共結點而部分重合的鏈表,拓撲形狀看起來像一個Y,而不可能像X,如下圖所示,兩個鏈表在值為6的結點處交匯:
如果兩個鏈表有公共結點,那么公共結點出現在兩個鏈表的尾部。如果我們從兩個鏈表的尾部開始往前比較,最后一個相同的結點就是我們要找的結點。But,在單鏈表中只能從頭結點開始按順序遍歷,最后才能到達尾結點。最后到達的尾結點卻要最先被比較,這是“后進先出”的特性。於是,我們可以使用棧的特點來解決這個問題:分別把兩個鏈表的結點放入兩個棧里,這樣兩個鏈表的尾結點就位於兩個棧的棧頂,接下來比較兩個棧頂的結點是否相同。如果相同,則把棧頂彈出接着比較下一個棧頂,直到找到最后一個相同的結點。
1 import java.util.*; 2 /* 3 public class ListNode { 4 int val; 5 ListNode next = null; 6 7 ListNode(int val) { 8 this.val = val; 9 } 10 }*/ 11 public class Solution { 12 //時間復雜度為O(mn),空間復雜度為O(m+n)的方法 13 public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { 14 if(pHead1==null||pHead2==null){ 15 return null; 16 } 17 18 Stack<ListNode> stack1=new Stack<>(); 19 Stack<ListNode> stack2=new Stack<>(); 20 while(pHead1!=null){ 21 stack1.push(pHead1); 22 pHead1=pHead1.next; 23 } 24 while(pHead2!=null){ 25 stack2.push(pHead2); 26 pHead2=pHead2.next; 27 } 28 if(stack1.peek().val!=stack2.peek().val){ 29 return null; 30 } 31 ListNode node1=null; 32 ListNode node2=null; 33 ListNode common=null; 34 while(!stack1.empty()&&!stack2.empty()){ 35 node1=stack1.peek(); 36 node2=stack2.peek(); 37 if(node1.val==node2.val){ 38 stack1.pop(); 39 stack2.pop(); 40 common=node1; 41 }else{ 42 break; 43 } 44 } 45 46 return common; 47 } 48 }
解法三:不借助外部空間法
那么,可不可以不借助棧來實現了呢?答案是可以的,我們可以首先遍歷兩個鏈表得到它們的長度,就能知道哪個鏈表比較長,以及長的鏈表比短的鏈表多幾個結點。在第二次遍歷的時候,在較長的鏈表上先走若干步,接着再同時在兩個鏈表上遍歷,找到的第一個相同的結點就是它們的第一個公共結點。
比如在上圖的兩個鏈表中,我們可以先遍歷一次得到它們的長度分別為5和4,也就是較長的鏈表與較短的鏈表相比多一個結點。第二次先在長的鏈表上走1步,到達結點2。接下來分別從結點2和結點4出發同時遍歷兩個結點,直到找到它們第一個相同的結點6,這就是我們想要的結果。
1 /* 2 public class ListNode { 3 int val; 4 ListNode next = null; 5 6 ListNode(int val) { 7 this.val = val; 8 } 9 }*/ 10 public class Solution { 11 //時間復雜度為O(mn),空間復雜度為O(1)的方法 12 public ListNode FindFirstCommonNode(ListNode pHead1, ListNode pHead2) { 13 int len1=getLengthOfList(pHead1); 14 int len2=getLengthOfList(pHead2); 15 ListNode longList=null; 16 ListNode shortList=null; 17 //兩個鏈表的長度差 18 int diff=0; 19 if(len1<len2){ 20 diff=len2-len1; 21 longList=pHead2; 22 shortList=pHead1; 23 }else{ 24 diff=len1-len2; 25 longList=pHead1; 26 shortList=pHead2; 27 } 28 //長鏈表先走diff步 29 while(diff>0){ 30 longList=longList.next; 31 diff--; 32 } 33 while(longList!=null&&shortList!=null&&longList!=shortList){ 34 35 longList=longList.next; 36 shortList=shortList.next; 37 } 38 return longList; 39 } 40 private int getLengthOfList(ListNode head){ 41 int len=0; 42 while(head!=null){ 43 len++; 44 head=head.next; 45 } 46 return len; 47 } 48 }
\Problem39 二叉樹的深度&&平衡二叉樹判斷
題目一:
二叉樹的深度:輸入一棵二叉樹,求該樹的深度。從根結點到葉結點依次經過的結點(含根、葉結點)形成樹的一條路徑,最長路徑的長度為樹的深度。
1 /** 2 public class TreeNode { 3 int val = 0; 4 TreeNode left = null; 5 TreeNode right = null; 6 7 public TreeNode(int val) { 8 this.val = val; 9 10 } 11 12 } 13 */ 14 public class Solution { 15 public int TreeDepth(TreeNode root) { 16 if(root==null){ 17 return 0; 18 } 19 int lh=TreeDepth(root.left); 20 int rh=TreeDepth(root.right); 21 return lh>rh?(lh+1):(rh+1); 22 } 23 }
題目二:
平衡二叉樹判斷:輸入一棵二叉樹,判斷該二叉樹是否是平衡二叉樹。
解法一:遞歸實現(需要重復遍歷節點多次)
1 import java.util.*; 2 3 /* 4 public class TreeNode { 5 int val = 0; 6 TreeNode left = null; 7 TreeNode right = null; 8 public TreeNode(int val) { 9 this.val = val; 10 } 11 }*/ 12 public class CheckBalance { 13 public boolean check(TreeNode root) { 14 // write code here 15 if(root==null){ 16 return true; 17 } 18 int lh=getDepth(root.left); 19 int rh=getDepth(root.right); 20 int diff=lh-rh; 21 if(diff>1||diff<-1){ 22 return false; 23 } 24 return check(root.left)&&check(root.right); 25 } 26 //返回一個節點的深度,即該節點到葉子節點的路徑最大長度 27 private int getDepth(TreeNode root){ 28 if(root==null){ 29 return 0; 30 } 31 int lh=getDepth(root.left); 32 int rh=getDepth(root.right); 33 34 return lh>rh?(lh+1):rh+1; 35 } 36 }
解法二:
1 import java.util.*; 2 3 /* 4 public class TreeNode { 5 int val = 0; 6 TreeNode left = null; 7 TreeNode right = null; 8 public TreeNode(int val) { 9 this.val = val; 10 } 11 }*/ 12 public class CheckBalance { 13 public boolean check(TreeNode root) { 14 //定義一個引用類型的數據作為平衡標記,通過傳引用的方式在遞歸左右子樹時修改平衡標記 15 boolean[] res=new boolean[1]; 16 //從根節點開始遍歷樹,遍歷過程中修改平衡標記 17 res[0]=true; 18 postCheck(root,1,res); 19 20 return res[0]; 21 } 22 public int postCheck(TreeNode root,int depth,boolean[] res){ 23 if(root==null){ 24 return depth; 25 } 26 //遍歷一次左子樹,獲取深度(深度已經在參數改變了,目的是為了檢查左子樹是否平衡) 27 //若遍歷左子樹過程中修改了平衡標記為false,則子樹非平衡,所以當前結點為根的子樹非平衡,不再遞歸,直接返回 28 29 int left_depth=postCheck(root.left,depth+1,res); 30 if(res[0]==false){ 31 return depth; 32 } 33 //若左子樹是平衡的,則遍歷右子樹並獲取深度 34 //若遍歷右子樹過程中修改了平衡標記為false,則子樹非平衡,所以當前結點為根的子樹非平衡,不再遞歸,直接返回 35 int right_depth=postCheck(root.right,depth+1,res); 36 if(res[0]==false){ 37 return depth; 38 } 39 40 //若左右子樹都是平衡的,則對左右子樹深度進行比較,判斷當前結點為根的子樹是否平衡 41 if(Math.abs(left_depth-right_depth)>1){//高度差大於1,當前子樹不平衡,修改平衡標記 42 res[0]=false; 43 } 44 //用左右子樹深度最大者作為自己的高度 45 return Math.max(left_depth,right_depth); 46 } 47 }
Problem38 數字在排序數組中出現的次數
題目描述
1 public class Solution { 2 //需要充分利用排序數組這個特點 3 public int GetNumberOfK(int [] array , int k) { 4 5 if(array==null||array.length==0){ 6 return 0; 7 } 8 int firstIndexK=getTheIndexOfFirst(array,array.length,k,0,array.length-1); 9 int lastIndexK=getTheIndexOfLast(array,array.length,k,0,array.length-1); 10 if(firstIndexK>-1||lastIndexK>-1){ 11 return(lastIndexK-firstIndexK+1); 12 } 13 //數組中不存在數字k 14 return 0; 15 } 16 //找到第一次出現k的位置 17 private int getTheIndexOfFirst(int[] arr,int len,int k,int start,int end){ 18 if(start>end){ 19 return -1; 20 } 21 int mid=(start+end)/2; 22 int dataMid=arr[mid]; 23 if(dataMid>k){ 24 end=mid-1; 25 }else if(dataMid<k){ 26 start=mid+1; 27 }else{ 28 if(mid!=0){ 29 if(arr[mid-1]!=k){ 30 return mid; 31 }else{ 32 end=mid-1; 33 } 34 }else{ 35 return mid; 36 } 37 } 38 return getTheIndexOfFirst(arr,len,k,start,end); 39 } 40 //找到最后一次出現k的位置 41 private int getTheIndexOfLast(int[] arr,int len,int k,int start,int end){ 42 if(start>end){ 43 return -1; 44 } 45 int mid=(start+end)/2; 46 int dataMid=arr[mid]; 47 if(arr[mid]<k){ 48 start=mid+1; 49 }else if(arr[mid]>k){ 50 end=mid-1; 51 }else{ 52 if(mid!=len-1){ 53 if(arr[mid+1]!=k){ 54 return mid; 55 }else{ 56 start=mid+1; 57 } 58 }else{ 59 return mid; 60 } 61 } 62 return getTheIndexOfLast(arr,len,k,start,end); 63 } 64 65 }
Problem40 數組中只出現一次的數字
題目描述:
一個整型數組里除了兩個數字之外,其他的數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。
1 //num1,num2分別為長度為1的數組。傳出參數 2 //將num1[0],num2[0]設置為返回結果 3 public class Solution { 4 public void FindNumsAppearOnce(int [] array,int num1[] , int num2[]) { 5 //輸入不符合要求 6 if(array==null||array.length==0){ 7 return; 8 } 9 //int xor存放異或結果 10 int xor=0; 11 //flag用於尋找和標記第N位為1的位置 12 int flag=1; 13 //先對整個數組的元素進行異或運算 14 for(int i=0;i<array.length;i++){ 15 xor^=array[i]; 16 } 17 while((xor&flag)==0){ 18 flag=flag<<1; 19 } 20 for(int i=0;i<array.length;i++){ 21 if((array[i]&flag)==0){ 22 num1[0]^=array[i]; 23 }else{ 24 num2[0]^=array[i]; 25 } 26 } 27 } 28 }
Problem41 和為S的兩個數字VS和為S的連續正數序列
題目一描述:
輸入一個遞增排序的數組和一個數字S,在數組中查找兩個數,是的他們的和正好是S,如果有多對數字的和等於S,輸出兩個數的乘積最小的。
1 import java.util.ArrayList; 2 public class Solution { 3 public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) { 4 ArrayList<Integer> list=new ArrayList<Integer>(); 5 if(array==null||array.length<1){ 6 return list; 7 } 8 int small=0; 9 int big=array.length-1; 10 while(small<big){ 11 12 if(array[small]+array[big]>sum) 13 big--; 14 else if(array[small]+array[big]<sum) 15 small++; 16 else 17 { 18 list.add(array[small]); 19 list.add(array[big]); 20 return list; 21 } 22 } 23 return list; 24 } 25 }
題目二描述:和為S的連續正數序列
輸出所有和為S的連續正數序列。序列內按照從小至大的順序,序列間按照開始數字從小到大的順序
1 import java.util.ArrayList; 2 public class Solution { 3 public ArrayList<ArrayList<Integer> > FindContinuousSequence(int sum) { 4 5 ArrayList<ArrayList<Integer>> result = new ArrayList<ArrayList<Integer>>(); 6 7 int small = 1; 8 int big = 2; 9 int curSum = small+big; 10 while(small < big && small < (sum+1)/2){ 11 if(curSum == sum){ 12 ArrayList<Integer> list = new ArrayList<Integer>(); 13 14 for(int i=small;i<=big;i++){ 15 list.add(i); 16 } 17 result.add(list); 18 19 //更新 20 curSum -= small; 21 //區間右移 22 small ++; 23 big ++; 24 curSum += big; 25 }else if(curSum < sum){ //tmp_sum小,右側擴展 26 //區間右側 右移,包括更大的數字 27 big ++; 28 curSum += big; //更新 29 }else{ //tmp_sum大,左側緊縮 30 curSum -= small; 31 small ++; //左側緊縮 32 } 33 } 34 return result; 35 } 36 }
Problem42 翻轉單詞的順序
牛客最近來了一個新員工Fish,每天早晨總是會拿着一本英文雜志,寫些句子在本子上。同事Cat對Fish寫的內容頗感興趣,有一天他向Fish借來翻看,但卻讀不懂它的意思。例如,“student. a am I”。后來才意識到,這家伙原來把句子單詞的順序翻轉了,正確的句子應該是“I am a student.”。Cat對一一的翻轉這些單詞順序可不在行,你能幫助他么?
1 import java.util.*; 2 public class Solution { 3 public String ReverseSentence(String str) { 4 if(str==null||str.length()==0){ 5 //反復錯在這個位置,之前返回的是null值 6 return str; 7 } 8 char chas[]=str.toCharArray(); 9 rolateWord(chas); 10 return String.valueOf(chas); 11 } 12 private void rolateWord(char chas[]){ 13 if(chas==null||chas.length==0){ 14 return; 15 } 16 reverse(chas,0,chas.length-1); 17 //下面對每一個局部的單詞進行逆序 18 //標記一個單詞的開始 19 int start=0; 20 //標記一個單詞的結束 21 int end=0; 22 //遍歷字符數組 23 int i=0; 24 while(i<chas.length){ 25 while(i<chas.length&&chas[i]==' '){ 26 i++; 27 start=i; 28 } 29 while(i<chas.length&&chas[i]!=' '){ 30 i++; 31 end=i; 32 } 33 reverse(chas,start,end-1); 34 } 35 36 37 } 38 private void reverse(char chas[],int left,int right){ 39 while(left<right){ 40 char temp=chas[left]; 41 chas[left]=chas[right]; 42 chas[right]=temp; 43 left++; 44 right--; 45 } 46 } 47 }
Problem44 撲克牌的順子
題目描述:
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。
1 import java.util.*; 2 3 public class Solution { 4 5 public boolean isContinuous(int [] numbers) { 6 if(numbers==null||numbers.length<1){ 7 return false; 8 } 9 int numberOfZero=0; 10 int gapsOfNum=0; 11 for(int i=0;i<numbers.length;i++){ 12 if(numbers[i]==0){ 13 numberOfZero++; 14 } 15 } 16 Arrays.sort(numbers); 17 int small=numberOfZero; 18 int big=small+1; 19 while(big<numbers.length){ 20 //不能出現對子,否則不可能出現順子 21 if(numbers[small]==numbers[big]){ 22 return false; 23 } 24 gapsOfNum+=numbers[big]-numbers[small]-1;; 25 small=big; 26 big++; 27 } 28 return (gapsOfNum>numberOfZero)?false:true; 29 } 30 }
Problem45 y圓圈中最后剩下的數字(約瑟夫環問題)
題目描述:
每年六一兒童節,牛客都會准備一些小禮物去看望孤兒院的小朋友,今年亦是如此。HF作為牛客的資深元老,自然也准備了一些小游戲。其中,有個游戲是這樣的:首先,讓小朋友們圍成一個大圈。然后,他隨機指定一個數m,讓編號為0的小朋友開始報數。每次喊到m-1的那個小朋友要出列唱首歌,然后可以在禮品箱中任意的挑選禮物,並且不再回到圈中,從他的下一個小朋友開始,繼續0...m-1報數....這樣下去....直到剩下最后一個小朋友,可以不用表演,並且拿到牛客名貴的“名偵探柯南”典藏版(名額有限哦!!^_^)。請你試着想下,哪個小朋友會得到這份禮品呢?(注:小朋友的編號是從0到n-1)
1 import java.util.*; 2 3 public class Solution { 4 5 public int LastRemaining_Solution(int n, int m) { 6 //輸入不合法 7 if(n<1||m<1){ 8 return -1; 9 } 10 ArrayList<Integer> list=new ArrayList<Integer>(); 11 for(int i=0;i<n;i++){ 12 list.add(i); 13 } 14 int listSize=n; 15 Iterator<Integer> it=list.iterator(); 16 while(list.size()>1){ 17 for(int i=1;i<=m;i++){ 18 if(it.hasNext()){ 19 it.next(); 20 }else{ 21 //當迭代器掃描到鏈表尾部時,需要把迭代器移動到鏈表的頭部 22 it=list.iterator(); 23 it.next(); 24 } 25 } 26 it.remove(); 27 listSize--; 28 } 29 it=list.iterator(); 30 return it.next(); 31 } 32 }
Problem46 計算1+2+3+。。。n
題目描述:
求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等關鍵字及條件判斷語句(A?B:C)。
1 public class Solution { 2 //常用方法是使用循環或者遞歸實現 3 //循環只是讓相同代碼重復執行遍而已 4 public int Sum_Solution(int n) { 5 int sum=n; 6 boolean flag=(n>0)&&((sum+=Sum_Solution(n-1))>0); 7 return sum; 8 } 9 }
Problem47 不用加減乘除做加法
題目描述:寫一個函數,求兩個整數之和,要求在函數體內不得使用+、-、*、/四則運算符號。
1 public class Solution { 2 //使用位運算 3 //1.不考慮進位各位相加 2.考慮進位3.兩步結果相加 4 public int Add(int num1,int num2) { 5 int sum,carry; 6 if(num1==0){ 7 return num2; 8 } 9 if(num2==0){ 10 return num1; 11 } 12 while(num2!=0){ 13 sum=num1^num2; 14 carry=(num1&num2)<<1; 15 num1=sum; 16 num2=carry; 17 } 18 19 return num1; 20 } 21 }
Problem49 把字符串轉換為整數
題目描述:
輸入描述:
輸入一個字符串,包括數字字母符號,可以為空
輸出描述:
如果是合法的數值表達則返回該數字,否則返回0
輸入
+2147483647 1a33
輸出
2147483647 0
1 public class Solution { 2 public int StrToInt(String str) { 3 int sum =0; 4 //判斷非法輸入 5 if(str == "0" || str == "" ||str.length() == 0){ 6 7 return 0; 8 } 9 //將字符串轉換為對應的字符數組 10 char chs[]=str.toCharArray(); 11 for(int i = 0; i < chs.length;i++){ 12 //是正負號的話,跳出當前if循環,開始下一趟for循環 13 if(chs[i]== '+' || chs[i] == '-'){ 14 continue; 15 } 16 if(chs[i] >'9' || chs[i] <'0'){ 17 return 0; 18 }else{ 19 sum = (chs[i] - '0') + sum*10; 20 } 21 } 22 if( chs[0] == '-'){ 23 sum = sum * (-1); 24 } 25 return sum; 26 } 27 }
Problem51 數組中重復的數字
題目描述
1 public class Solution { 2 // Parameters: 3 // numbers: an array of integers 4 // length: the length of array numbers 5 // duplication: (Output) the duplicated number in the array number,length of duplication array is 1,so using duplication[0] = ? in implementation; 6 // Here duplication like pointor in C/C++, duplication[0] equal *duplication in C/C++ 7 // 這里要特別注意~返回任意重復的一個,賦值duplication[0] 8 // Return value: true if the input is valid, and there are some duplications in the array number 9 // otherwise false 10 public boolean duplicate(int numbers[],int length,int [] duplication) { 11 12 if(numbers==null||length==0){ 13 return false; 14 } 15 //條件判斷,保證數組中的元素值在0-n-1的范圍內 16 for(int i=0;i<length;i++){ 17 if(numbers[i]<0||numbers[i]>length-1){ 18 return false; 19 } 20 } 21 for(int i=0;i<length;i++){ 22 while(numbers[i]!=i){ 23 if(numbers[numbers[i]]==numbers[i]){ 24 duplication[0]=numbers[i]; 25 return true; 26 } 27 int temp=numbers[i]; 28 numbers[i]=numbers[temp]; 29 numbers[temp]=temp; 30 } 31 } 32 return false; 33 } 34 }
Proble52 構建乘積數組
題目描述:給定一個數組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]。不能使用除法。
1 import java.util.ArrayList;
2 public class Solution { 3 public int[] multiply(int[] A) { 4 //將B[i]的計算拆分成A[0]*A[1]...A[i-1]和A[i+1]*...A[n-1]兩部分,用一個矩陣來創建數組B 5 int len=A.length; 6 int B[]=new int[len]; 7 B[0]=1; 8 //先求矩陣上三角部分 9 for(int i=1;i<len;i++){ 10 B[i]=B[i-1]*A[i-1]; 11 } 12 //再求下三角部分 13 int temp=1; 14 for(int i=len-2;i>=0;i--){ 15 //temp隨着i的減小不斷變化 16 temp*=A[i+1]; 17 B[i]*=temp; 18 } 19 return B; 20 } 21 }
Problem53 正則表達式匹配
題目描述:
請實現一個函數用來匹配包括'.'和'*'的正則表達式。模式中的字符'.'表示任意一個字符,而'*'表示它前面的字符可以出現任意次(包含0次)。 在本題中,匹配是指字符串的所有字符匹配整個模式。例如,字符串"aaa"與模式"a.a"和"ab*ac*a"匹配,但是與"aa.a"和"ab*a"均不匹配
1 public class Solution { 2 public boolean match(char[] str, char[] pattern) 3 { 4 //條件判斷 5 if(str==null||pattern==null){ 6 return false; 7 } 8 return matchCore(str,0,pattern,0); 9 } 10 private boolean matchCore(char[] str,int strIndex,char[] pattern,int pIndex){ 11 //有效性檢驗 12 //str和pattern同時到達尾部,完成匹配,返回true 13 if(strIndex==str.length&&pIndex==pattern.length){ 14 return true; 15 } 16 //str不到尾,pattern到尾部,返回false 17 if(strIndex!=str.length&&pIndex==pattern.length){ 18 return false; 19 } 20 21 //模式第2個是*,且字符串第1個跟模式第1個匹配,分3種匹配模式;如不匹配,模式后移2位 22 if (pIndex + 1 < pattern.length && pattern[pIndex + 1] == '*') { 23 if(strIndex!=str.length&&str[strIndex]==pattern[pIndex]||strIndex!=str.length&&pattern[pIndex]=='.'){ 24 //1.模式串后后移兩位,相當於第一個匹配的字符被忽略掉,從字符串的下一個字符繼續開始匹配 25 //2.字符串后移一位,模式串后移兩位,相當於模式匹配一個字符 26 //3.字符串后移一位,模式串不動,因為模式串的第二個字符'*‘,可以匹配前面出現的多個字符 27 return matchCore(str,strIndex,pattern,pIndex+2)||matchCore(str,strIndex+1,pattern,pIndex+2)|| 28 matchCore(str,strIndex+1,pattern,pIndex); 29 }else{ 30 return matchCore(str,strIndex,pattern,pIndex+2); 31 } 32 } 33 //模式串第二個字符不是'*',並且兩個串的第一個字符是匹配的 34 if(strIndex!=str.length&&str[strIndex]==pattern[pIndex]||strIndex!=str.length&&pattern[pIndex]=='.'){ 35 return matchCore(str,strIndex+1,pattern,pIndex+1); 36 37 //否則,直接返回false 38 }else{ 39 return false; 40 } 41 } 42 }
Problem54 表示數值的字符串
題目描述:
請實現一個函數用來判斷字符串是否表示數值(包括整數和小數)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示數值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。
思路:使用正則表達式來解決
1 public class Solution { 2 public boolean isNumeric(char[] str) { 3 String string = String.valueOf(str); 4 return string.matches("[\\+-]?[0-9]*(\\.[0-9]*)?([eE][\\+-]?[0-9]+)?"); 5 } 6 }
Problem55 字符流中第一個不重復的字符
題目描述:
請實現一個函數用來找出字符流中第一個只出現一次的字符。例如,當從字符流中只讀出前兩個字符"go"時,第一個只出現一次的字符是"g"。當從該字符流中讀出前六個字符“google"時,第一個只出現一次的字符是"l"。
輸出描述:
如果當前字符流沒有存在出現一次的字符,返回#字符。
思路:定義一個數據容器來保存字符在字符流中的位置,當一個字符第一次從字符流中讀出來時,把它在字符流中的位置保存在數據容器中,當這個字符再次出現時,那么就吧它在數據容器中保存的值更新為一個特殊的值(比如負數值)
1 public class Solution { 2 //Insert one char from stringstream 3 //定義一個數組模擬哈希表 4 5 int mapArr[]=new int[256]; 6 int index=0; 7 8 public Solution(){ 9 //最開始,哈希表中所有元素都初始化為-1 10 for(int i=0;i<256;i++){ 11 mapArr[i]=-1; 12 } 13 } 14 public void Insert(char ch) 15 { 16 if(mapArr[ch]==-1){ 17 mapArr[ch]=index++; 18 }else{ 19 mapArr[ch]=-2; 20 } 21 } 22 //return the first appearence once char in current stringstream 23 public char FirstAppearingOnce() 24 { 25 int minIndex=256; 26 char ch='#'; 27 for(int i=0;i<256;i++){ 28 if(mapArr[i]>=0&&mapArr[i]<minIndex){ 29 minIndex=mapArr[i]; 30 ch=(char)i; 31 } 32 } 33 return ch; 34 } 35 }
Problem56 鏈表中環的入口結點
題目描述:
一個鏈表中包含環,請找出該鏈表的環的入口結點。
1 /* 2 public class ListNode { 3 int val; 4 ListNode next = null; 5 6 ListNode(int val) { 7 this.val = val; 8 } 9 } 10 */ 11 public class Solution { 12 13 //分成兩步:1.判斷是否存在環,並找到快慢兩個指針相遇的位置 14 // 2.根據找到的這個相遇位置,統計環中節點的數目n,先讓快指針走n步,然后 15 // 快慢兩個指針一起運動,快慢指針相遇時的節點就是環的入口節點 16 public ListNode EntryNodeOfLoop(ListNode pHead) 17 { 18 //getMeetingNode函數返回null或者環中的一個節點(快慢指針相遇的節點) 19 ListNode meetNode=getMeetingNode(pHead); 20 if(meetNode==null){ 21 return null; 22 } 23 //根據找到的這個節點統計環中節點的數目 24 int loopNodes=1; 25 ListNode cur=meetNode.next; 26 while(cur!=meetNode){ 27 loopNodes++; 28 cur=cur.next; 29 } 30 //快指針先走loopNodes步 31 ListNode fast=pHead; 32 for(int i=1;i<=loopNodes;i++){ 33 fast=fast.next; 34 } 35 //慢指針開始跟快指針一起移動 36 ListNode slow=pHead; 37 while(slow!=fast){ 38 slow=slow.next; 39 fast=fast.next; 40 } 41 return fast; 42 } 43 //先找兩個指針相遇的位置 44 private ListNode getMeetingNode(ListNode pHead){ 45 if(pHead==null){ 46 return null; 47 } 48 ListNode slow=pHead.next; 49 //只有一個結點 ,直接返回null 50 if(slow==null){ 51 return null; 52 } 53 ListNode fast=slow.next; 54 while(slow!=null&&fast!=null){ 55 if(slow==fast){ 56 return fast; 57 } 58 //slow指針在鏈表上一次移動一步 59 slow=slow.next; 60 //fast指針一次在鏈表上移動兩步 61 fast=fast.next; 62 if(fast!=null){ 63 fast=fast.next; 64 } 65 } 66 //鏈表中不存在環,則直接返回null; 67 return null; 68 } 69 70 }
Problem57刪除鏈表中重復的節點
題目描述:
在一個排序的鏈表中,存在重復的結點,請刪除該鏈表中重復的結點,重復的結點不保留,返回鏈表頭指針。 例如,鏈表1->2->3->3->4->4->5 處理后為 1->2->5
1 /* 2 public class ListNode { 3 int val; 4 ListNode next = null; 5 6 ListNode(int val) { 7 this.val = val; 8 } 9 } 10 */ 11 public class Solution { 12 public ListNode deleteDuplication(ListNode pHead) 13 { 14 //使用虛擬頭結點,方便在鏈表頭部進行的一些操作 15 ListNode visualHead = new ListNode(-1); 16 visualHead.next = pHead; 17 //當前節點的前一個節點 18 ListNode pre = visualHead; 19 while(pHead != null && pHead.next != null){ 20 if(pHead.val == pHead.next.val){ 21 int value = pHead.val; 22 while(pHead != null && pHead.val == value) 23 pHead = pHead.next; 24 pre.next = pHead; 25 }else{ 26 pre = pHead; 27 pHead = pHead.next; 28 } 29 } 30 return visualHead.next; 31 } 32 }
Problem58二叉樹的下一個節點
題目描述:
給定一個二叉樹和其中的一個結點,請找出中序遍歷順序的下一個結點並且返回。注意,樹中的結點不僅包含左右子結點,同時包含指向父結點的指針。
1 /* 2 public class TreeLinkNode { 3 int val; 4 TreeLinkNode left = null; 5 TreeLinkNode right = null; 6 TreeLinkNode next = null; 7 8 TreeLinkNode(int val) { 9 this.val = val; 10 } 11 } 12 */ 13 public class Solution { 14 public TreeLinkNode GetNext(TreeLinkNode pNode) 15 { 16 if(pNode==null){ 17 return null; 18 } 19 TreeLinkNode pNext=null; 20 if(pNode.right!=null){ 21 TreeLinkNode pRight=pNode.right; 22 while(pRight.left!=null){ 23 pRight=pRight.left; 24 } 25 pNext=pRight; 26 }else if(pNode.next!=null){ 27 TreeLinkNode pCur=pNode; 28 TreeLinkNode parent=pNode.next; 29 while(parent!=null&&pCur!=parent.left){ 30 pCur=parent; 31 parent=pCur.next; 32 } 33 pNext=parent; 34 } 35 return pNext; 36 } 37 }
Problem59二叉樹的鏡像(對稱的二叉樹)
操作給定的二叉樹,將其變換為源二叉樹的鏡像。
輸入描述:
二叉樹的鏡像定義:源二叉樹 8 / \ 6 10 / \ / \ 5 7 9 11 鏡像二叉樹 8 / \ 10 6 / \ / \ 11 9 7 5
1 /** 2 public class TreeNode { 3 int val = 0; 4 TreeNode left = null; 5 TreeNode right = null; 6 7 public TreeNode(int val) { 8 this.val = val; 9 10 } 11 12 } 13 */ 14 public class Solution { 15 public void Mirror(TreeNode root) { 16 if(root==null){ 17 return ; 18 } 19 TreeNode tempNode; 20 tempNode=root.left; 21 22 root.left=root.right; 23 root.right=tempNode; 24 25 Mirror(root.left); 26 Mirror(root.right); 27 } 28 }
劍指offer書上面對應的題目是判斷兩個二叉樹是否為彼此的鏡像二叉樹,可以通過二叉樹的前序遍歷和對稱前序遍歷來驗證;(根->左->右和根->右->左);兩個遍歷序列相同則說明是對稱二叉樹,反之則不是;
OJ在線:
題目描述
1 /* 2 public class TreeNode { 3 int val = 0; 4 TreeNode left = null; 5 TreeNode right = null; 6 7 public TreeNode(int val) { 8 this.val = val; 9 10 } 11 12 } 13 */ 14 public class Solution { 15 boolean isSymmetrical(TreeNode pRoot) 16 { 17 return isSymmetricalCore(pRoot,pRoot); 18 } 19 private boolean isSymmetricalCore(TreeNode pRoot1,TreeNode pRoot2){ 20 if(pRoot1==null&&pRoot2==null){ 21 return true; 22 } 23 if(pRoot1==null||pRoot2==null){ 24 return false; 25 } 26 if(pRoot1.val!=pRoot2.val){ 27 return false; 28 } 29 return isSymmetricalCore(pRoot1.left,pRoot2.right)&&isSymmetricalCore(pRoot1.right,pRoot2.left); 30 } 31 }
Problem60 把二叉樹打印成多行
題目描述:從上到下按層打印二叉樹,同一層結點從左至右輸出。每一層輸出一行。
1 import java.util.ArrayList; 2 import java.util.LinkedList; 3 4 class TreeNode { 5 int val = 0; 6 TreeNode left = null; 7 TreeNode right = null; 8 9 public TreeNode(int val) { 10 this.val = val; 11 12 } 13 14 } 15 16 public class Solution { 17 //層次遍歷二叉樹 18 ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) { 19 //定義一個輔助隊列 20 LinkedList<TreeNode> queue=new LinkedList<TreeNode>(); 21 //last表示打印當前行時的最右節點 22 TreeNode last=pRoot; 23 //nlast表示要打印的下一行的最右節點 24 TreeNode nlast=pRoot; 25 //當前正在打印的節點 26 TreeNode cur=pRoot; 27 28 queue.add(cur); 29 //result存放一層的打印結果 30 ArrayList<Integer> result=new ArrayList<Integer>(); 31 32 //存儲所有的打印結果 33 ArrayList<ArrayList<Integer>> resultAll=new ArrayList<>(); 34 if(cur==null){ 35 return resultAll; 36 } 37 while(queue.size()!=0){ 38 //彈出隊列中的一個節點 39 cur=queue.poll(); 40 result.add(cur.val); 41 if(cur.left!=null){ 42 queue.add(cur.left); 43 nlast=cur.left; 44 } 45 if(cur.right!=null){ 46 queue.add(cur.right); 47 nlast=cur.right; 48 } 49 //一層打印結束 50 if(cur==last){ 51 resultAll.add(result); 52 last=nlast; 53 result=new ArrayList<Integer>(); 54 } 55 } 56 return resultAll; 57 } 58 59 }
Problem61 按之字形順序打印二叉樹
題目描述:
請實現一個函數按照之字形打印二叉樹,即第一行按照從左到右的順序打印,第二層按照從右至左的順序打印,第三行按照從左到右的順序打印,其他行以此類推。
Problem62 序列化二叉樹
1 import java.util.*; 2 3 /* 4 public class TreeNode { 5 int val = 0; 6 TreeNode left = null; 7 TreeNode right = null; 8 9 public TreeNode(int val) { 10 this.val = val; 11 12 } 13 14 } 15 */ 16 public class Solution { 17 public ArrayList<ArrayList<Integer> > Print(TreeNode pRoot) { 18 19 ArrayList<ArrayList<Integer>> result=new ArrayList<>(); 20 if(pRoot==null){ 21 return result; 22 } 23 24 //需要使用兩個輔助棧 25 Stack<TreeNode> stack1=new Stack<>(); 26 Stack<TreeNode> stack2=new Stack<>(); 27 //先使用輔助棧1 28 stack1.push(pRoot); 29 while(!stack1.empty()||!stack2.empty()){ 30 if(!stack1.empty()){ 31 ArrayList<Integer> curResult=new ArrayList<>(); 32 while(!stack1.empty()){ 33 TreeNode dataPop=stack1.pop(); 34 curResult.add(dataPop.val); 35 if(dataPop.left!=null){ 36 stack2.push(dataPop.left); 37 } 38 if(dataPop.right!=null){ 39 stack2.push(dataPop.right); 40 } 41 } 42 result.add(curResult); 43 }else{ 44 ArrayList<Integer> curResult=new ArrayList<>(); 45 46 while(!stack2.empty()){ 47 TreeNode dataPop=stack2.pop(); 48 curResult.add(dataPop.val); 49 if(dataPop.right!=null){ 50 stack1.push(dataPop.right); 51 } 52 if(dataPop.left!=null){ 53 stack1.push(dataPop.left); 54 } 55 } 56 result.add(curResult); 57 } 58 } 59 return result; 60 61 } 62 63 }
Problem62 序列化二叉樹
題目描述:
請實現兩個函數,分別用來序列化和反序列化二叉樹
1 /* 2 public class TreeNode { 3 int val = 0; 4 TreeNode left = null; 5 TreeNode right = null; 6 7 public TreeNode(int val) { 8 this.val = val; 9 10 } 11 12 } 13 */ 14 public class Solution { 15 16 String Serialize(TreeNode root) { 17 if(root == null) 18 return ""; 19 StringBuilder builder = new StringBuilder(); 20 serializeCore(root, builder); 21 return builder.toString(); 22 } 23 24 void serializeCore(TreeNode root, StringBuilder builder) { 25 if(root == null) { 26 builder.append("#,"); 27 return; 28 } 29 builder.append(root.val).append(","); 30 serializeCore(root.left, builder); 31 serializeCore(root.right, builder); 32 } 33 34 35 TreeNode Deserialize(String str) { 36 if(str.length() == 0) 37 return null; 38 String[] strs = str.split(","); 39 return Deserialize2(strs); 40 } 41 int index = 0; 42 43 TreeNode Deserialize2(String[] strs) { 44 if(!strs[index].equals("#")) { 45 TreeNode root = new TreeNode(0); 46 root.val = Integer.parseInt(strs[index++]); 47 root.left = Deserialize2(strs); 48 root.right = Deserialize2(strs); 49 return root; 50 }else{ 51 index++; 52 return null; 53 } 54 } 55 }
Problem63 二叉搜索樹的第k個結點
題目描述:給定一顆二叉搜索樹,請找出其中的第k大的結點。例如, 5 / \ 3 7 /\ /\ 2 4 6 8 中,按結點數值大小順序第三個結點的值為4。
1 /* 2 public class TreeNode { 3 int val = 0; 4 TreeNode left = null; 5 TreeNode right = null; 6 7 public TreeNode(int val) { 8 this.val = val; 9 10 } 11 12 } 13 */ 14 public class Solution { 15 //對二叉搜索樹進行一次中序遍歷就可以找到第K大的數 16 TreeNode KthNode(TreeNode pRoot, int k) 17 { 18 if(pRoot==null||k==0){ 19 return null; 20 } 21 int result[]=new int[1]; 22 result[0]=k; 23 return KthNodeCore(pRoot,result); 24 } 25 private TreeNode KthNodeCore(TreeNode pRoot,int[] result){ 26 TreeNode target=null; 27 if(target==null&&pRoot.left!=null){ 28 target=KthNodeCore(pRoot.left,result); 29 } 30 if(target==null&&result[0]==1){ 31 target=pRoot; 32 }else{ 33 result[0]--; 34 } 35 if(target==null&&pRoot.right!=null){ 36 target=KthNodeCore(pRoot.right,result); 37 } 38 return target; 39 } 40 }
Problem65滑動窗口的最大值
題目描述:
給定一個數組和滑動窗口的大小,找出所有滑動窗口里數值的最大值。例如,如果輸入數組{2,3,4,2,6,2,5,1}及滑動窗口的大小3,那么一共存在6個滑動窗口,他們的最大值分別為{4,4,6,6,6,5}; 針對數組{2,3,4,2,6,2,5,1}的滑動窗口有以下6個: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。
1 import java.util.*; 2 public class Solution { 3 public ArrayList<Integer> maxInWindows(int [] num, int size) 4 { 5 ArrayList<Integer> result=new ArrayList<>(0); 6 if(num==null||num.length<1||num.length<size||size<1){ 7 return result; 8 } 9 //定義雙端隊列 10 ArrayDeque<Integer> queue=new ArrayDeque<>(); 11 for(int i=0;i<num.length;i++){ 12 13 while(!queue.isEmpty()&&num[queue.peekLast()]<=num[i]){ 14 queue.pollLast(); 15 } 16 queue.addLast(i); 17 //刪除隊頭失效的最大值 18 if(i-size>=queue.peekFirst()){ 19 queue.pollFirst(); 20 } 21 if(i>=size-1){ 22 result.add(num[queue.peekFirst()]); 23 } 24 } 25 return result; 26 27 } 28 }