1. 程式人生 > 其它 >演算法-陣列與矩陣

演算法-陣列與矩陣

演算法-陣列與矩陣

簡介:演算法篇-陣列與矩陣。

    知君何事淚縱橫,斷腸聲裡憶平生。

一、陣列中重複的數字

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 }
View Code

二、二維陣列中的查詢

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 }
View Code

三、替換空格

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 }
View Code

四、順時針列印矩陣

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 }
View Code

五、第一個只出現一次的字元位置

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 }
View Code

    知君何事淚縱橫

斷腸聲裡憶平生