演算法-陣列與矩陣
簡介:演算法篇-陣列與矩陣。
知君何事淚縱橫,斷腸聲裡憶平生。
一、陣列中重複的數字
1、題目描述
在一個長度為 n 的陣列裡的所有數字都在 0 到 n-1 的範圍內。陣列中某些數字是重複的,但不知道有幾個數字是重複的,也不知道每個數字重複幾次。請找出陣列中任意一個重複的數字。
輸入:[2,3,1,0,2,5,3]
輸出:2
2、解題思路
要求時間複雜度 O(N),空間複雜度 O(1)。因此不能使用排序的方法,也不能使用額外的標記陣列。
對於這種陣列元素在 [0, n-1] 範圍內的問題,可以將值為 i 的元素調整到第 i 個位置上進行求解。在調整過程中,如果第 i 位置上已經有一個值為 i 的元素,就可以知道 i 值重複。
以 (2, 3, 1, 0, 2, 5) 為例,遍歷到位置 4 時,該位置上的數為 2,但是第 2 個位置上已經有一個 2 的值了,因此可以知道 2 重複:
3、程式碼示例
1 import java.util.*;
2
3 public class Solution {
4 public int duplicate (int[] numbers) {
5 int length = numbers.length;
6 if(length == 0 || length ==1){
7 return -1;
8 }
9 Arrays.sort(numbers); // 利用Arrays從小到大排序
10 for(int i = 0; i < length -1; i++){
11 if(numbers[i] == numbers[i + 1]){
12 return numbers[i];
13 }
14 }
15 return -1;
16 }
17 }
二、二維陣列中的查詢
1、題目描述
給定一個二維陣列,其每一行從左到右遞增排序,從上到下也是遞增排序。給定一個數,判斷這個數是否在該二維陣列中。
輸入:7,[[1,2,8,9],[2,4,9,12],[4,7,10,13],[6,8,11,15]]
輸出:true
2、解題思路
要求時間複雜度 O(M + N),空間複雜度 O(1)。其中 M 為行數,N 為 列數。
該二維陣列中的一個數,小於它的數一定在其左邊,大於它的數一定在其下邊。因此,從右上角開始查詢,就可以根據 target 和當前元素的大小關係來快速地縮小查詢區間,每次減少一行或者一列的元素。當前元素的查詢區間為左下角的所有元素。
3、程式碼示例
1 public class Solution {
2 public boolean Find(int target, int [][] array) {
3 boolean flag = false;
4 for(int i = 0; i < array.length; i++){
5 for(int j = 0; j < array[i].length; j++){
6 if(array[i][j] == target){
7 flag = true;
8 break;
9 }
10 }
11 if(flag){
12 break;
13 }
14 }
15 return flag;
16 }
17 }
三、替換空格
1、題目描述
將一個字串中的空格替換成 "%20"。
輸入:"We Are Happy"
輸出:"We%20Are%20Happy"
2、解題思路
① 在字串尾部填充任意字元,使得字串的長度等於替換之後的長度。因為一個空格要替換成三個字元(%20),所以當遍歷到一個空格時,需要在尾部填充兩個任意字元。
② 令 P1 指向字串原來的末尾位置,P2 指向字串現在的末尾位置。P1 和 P2 從後向前遍歷,當 P1 遍歷到一個空格時,就需要令 P2 指向的位置依次填充 02%(注意是逆序的),否則就填充上 P1 指向字元的值。從後向前遍是為了在改變 P2 所指向的內容時,不會影響到 P1 遍歷原來字串的內容。
③ 當 P2 遇到 P1 時(P2 <= P1),或者遍歷結束(P1 < 0),退出。
3、程式碼示例:
1 import java.util.*;
2
3
4 public class Solution {
5
6 public String replaceSpace (String s) {
7 return s.replace(" ", "%20");
8 }
9 }
四、順時針列印矩陣
1、題目描述
輸入一個矩陣,按照從外向裡以順時針的順序依次列印出每一個數字,例如,如果輸入如下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]
輸入:[[1,2],[3,4]]
輸出:[1,2,4,3]
2、解題思路
一層一層從外到裡列印,觀察可知每一層列印都有相同的處理步驟,唯一不同的是上下左右的邊界不同了。因此使用四個變數 r1, r2, c1, c2 分別儲存上下左右邊界值,從而定義當前最外層。列印當前最外層的順序:從左到右列印最上一行->從上到下列印最右一行->從右到左列印最下一行->從下到上列印最左一行。應當注意只有在 r1 != r2 時才列印最下一行,也就是在當前最外層的行數大於 1 時才列印最下一行,這是因為當前最外層只有一行時,繼續列印最下一行,會導致重複列印。列印最左一行也要做同樣處理。
3、程式碼示例
1 import java.util.ArrayList;
2
3 public class Solution {
4 public ArrayList<Integer> printMatrix(int [][] matrix) {
5 int n = matrix.length;
6 int m = matrix[0].length;
7 int left = 0;
8 int right = m - 1;
9 int top = 0;
10 int tail = n - 1;
11 ArrayList list = new ArrayList<>();
12 while(true){
13 for(int i = left; i <= right; i++){
14 list.add(matrix[top][i]);
15 }
16 if(++top > tail){
17 break;
18 }
19 for(int i = top; i <= tail; i++){
20 list.add(matrix[i][right]);
21 }
22 if(--right < left){
23 break;
24 }
25 for(int i = tail; i >= top; i--){
26 list.add(matrix[i][left]);
27 }
28 if(++left > right){
29 break;
30 }
31 }
32 return list;
33 }
34 }
五、第一個只出現一次的字元位置
1、題目描述
在一個字串中找到第一個只出現一次的字元,並返回它的位置。字串只包含 ASCII 碼字元。
輸入:"google"
輸出:4
2、解題思路
最直觀的解法是使用 HashMap 對出現次數進行統計:字元做為 key,出現次數作為 value,遍歷字串每次都將 key 對應的 value 加 1。最後再遍歷這個 HashMap 就可以找出出現次數為 1 的字元。
考慮到要統計的字元範圍有限,也可以使用整型陣列代替 HashMap。ASCII 碼只有 128 個字元,因此可以使用長度為 128 的整型陣列來儲存每個字元出現的次數。
3、程式碼示例
1 public class Solution {
2 public int FirstNotRepeatingChar(String str) {
3 for(int i = 0; i < str.length(); i++){
4 // str.charAt(i) 取ASC碼
5 // str.indexOf(str.charAt(i)) 取ASC碼第一次出現的索引下標位置
6 // str.lastIndexOf(str.charAt(i)) 取ASC碼最後一次出現的
7 if(str.indexOf(str.charAt(i)) != str.lastIndexOf(str.charAt(i))){
8 continue;
9 }
10 return i;
11 }
12 return -1;
13 }
14 }
知君何事淚縱橫
斷腸聲裡憶平生