套路
純數組問題通常分為兩類解決:
- 單純考察代碼實現能力,(新建數組)往往是對現實的抽象建模。只要注意中間不出數組越界問題把所有可能的分支和邊界情況處理好就可以了。
- 新要保存的標記或建數組作為容器,存放一些需者值來輔助運算。
注意點
- 小心數組下標越界問題
- 邏輯復雜時,帶入簡單的通用demo和特殊情況demo輔助檢驗
- 返回值要求為數組的題目里,盡量不要直接返回null,這樣不好。我們可以返回一個空數組,即長度為0的數組,寫法是:return new int[0];
- 返回動態數組也是,如果可以返回空的動態數組,盡量不要返回null,返回null值不是一個好的習慣。
- 如果要求答案為不止一個值時,如果其他值可以通過前面的值得到幫助,縮短求值步驟,那么盡量不要重新計算,利用已求得的答案求解,可以使代碼的時間復雜度達到最低。
目錄
- 構建乘積數組(最優解還需要練習)
- 順時針打印矩陣
- 旋轉數組的最小數字
- 和為S的兩個數字
- 孩子們的游戲(圓圈中最后剩下的數)(代碼實現還需要練習)
構建乘積數組
給定一個數組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]。不能使用除法。
- 常規解法:窮舉法。時間復雜度 O(n^2)
- 最優解法:B [ i ] 利用現成的 B [ i - 1 ] 的結果進行計算,從而降低時間復雜度。時間復雜度 O(n)
public int[] multiply(int[] A) {
if (A == null || A.length == 0) {
return new int[0];
}
int n = A.length, temp = 1;
int[] B = new int[n];
B[0] = 1;
for (int i = 1; i < n; i++) {
B[i] = B[i - 1] * A[i - 1];
}
for (int j = n - 2; j >= 0; j--) {
temp *= A[j + 1];
B[j] *= temp;
}
return B;
}
順時針打印矩陣
輸入一個矩陣,按照從外向里以順時針的順序依次打印出每一個數字,例如,如果輸入如下矩陣: 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.
- 考察代碼實現能力
public ArrayList<Integer> printMatrix(int [][] matrix) {
ArrayList<Integer> list = new ArrayList<>();
if (matrix == null || matrix[0] == null) {
return list;
}
int i = 0, j = 0;
int iMax = matrix.length, jMax = matrix[0].length;
int iCur = iMax - 1, jCur = jMax - 1;
// 矩陣寬高大于1
while (iCur > 0 && jCur > 0) {
for (int k = 0; k < jCur; k++) {
list.add(matrix[i][j++]);
}
for (int k = 0; k < iCur; k++) {
list.add(matrix[i++][j]);
}
for (int k = 0; k < jCur; k++) {
list.add(matrix[i][j--]);
}
for (int k = 0; k < iCur; k++) {
list.add(matrix[i--][j]);
}
i++;
j++;
iCur -= 2;
jCur -= 2;
}
// 矩陣寬高等于1
if (iCur == 0 && jCur == 0) {
list.add(matrix[i][j]);
// 矩陣高為1
} else if (iCur == 0) {
for (int k = 0; k <= jCur; k++) {
list.add(matrix[i][j++]);
}
// 矩陣寬為1
} else if (jCur == 0) {
for (int k = 0; k <= iCur; k++) {
list.add(matrix[i++][j]);
}
}
return list;
}
旋轉數組的最小數字
把一個數組最開始的若干個元素搬到數組的末尾,我們稱之為數組的旋轉。 輸入一個非遞減排序的數組的一個旋轉,輸出旋轉數組的最小元素。 例如數組{3,4,5,1,2}為{1,2,3,4,5}的一個旋轉,該數組的最小值為1。 NOTE:給出的所有元素都大于0,若數組大小為0,請返回0。
- 最優解:時間復雜度 O(n),平均執行時間是數組長度的一半。
public int minNumberInRotateArray(int [] array) {
if (array == null || array.length == 0) {
return 0;
}
for (int i = 1; i < array.length; i++) {
if (array[i] < array[i - 1]) {
return array[i];
}
}
return array[0];
}
和為S的兩個數字
輸入一個遞增排序的數組和一個數字S,在數組中查找兩個數,是的他們的和正好是S,如果有多對數字的和等于S,輸出兩個數的乘積最小的。
輸出描述:
對應每個測試案例,輸出兩個數,小的先輸出。
public ArrayList<Integer> FindNumbersWithSum(int [] array,int sum) {
ArrayList<Integer> res = new ArrayList<>();
if (array == null || array.length < 2) {
return res;
}
int left = 0, right = array.length - 1;
while (left < right) {
int ans = array[left] + array[right];
if (ans < sum) {
left++;
} else if (ans > sum) {
right--;
} else {
res.add(array[left]);
res.add(array[right]);
return res;
}
}
return res;
}
孩子們的游戲(圓圈中最后剩下的數)
每年六一兒童節,牛客都會準備一些小禮物去看望孤兒院的小朋友,今年亦是如此。HF作為牛客的資深元老,自然也準備了一些小游戲。其中,有個游戲是這樣的:首先,讓小朋友們圍成一個大圈。然后,他隨機指定一個數m,讓編號為0的小朋友開始報數。每次喊到m-1的那個小朋友要出列唱首歌,然后可以在禮品箱中任意的挑選禮物,并且不再回到圈中,從他的下一個小朋友開始,繼續0...m-1報數....這樣下去....直到剩下最后一個小朋友,可以不用表演,并且拿到牛客名貴的“名偵探柯南”典藏版(名額有限哦!!_)。請你試著想下,哪個小朋友會得到這份禮品呢?(注:小朋友的編號是從0到n-1)
public int LastRemaining_Solution(int n, int m) {
if (n <= 0 || m <= 0) {
return -1;
}
// 模擬0~n-1個孩子
int[] arr = new int[n];
// count代表圈中孩子的個數,i代表報數的位置, step代表每輪報數的孩子個數
int count = n, i = 0, step = 1;
while (count > 0) {
i++;
if (i == n) {
i = 0;
}
if (arr[i] == -1) {
continue;
}
step++;
if (step == m) {
// 賦值為-1代表出列
arr[i] = -1;
count--;
step = 0;
}
}
return i;
}