日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問 生活随笔!

生活随笔

當前位置: 首頁 > 编程资源 > 编程问答 >内容正文

编程问答

超硬核!躺进BAT以后我总结了出现最多的15道数组题

發布時間:2023/12/13 编程问答 34 豆豆
生活随笔 收集整理的這篇文章主要介紹了 超硬核!躺进BAT以后我总结了出现最多的15道数组题 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

作為一個硬核作者,絕不和你扯廢話,干貨無套路送你

題目一:

? ? 給定一個數組arr,求出需要排序的最短子數組長度

要求:

? ? 時間o(n),空間o(1)

思路:

? ? 有序的數組中,任意一個數字,一定小于左邊的數大于右邊的數。

? ? 我們找到的需要排序的子數組,顯然是比右邊最小的值大,或比左邊最大的值小。

? ? 我們初始化變量noMinindex=-1;從右往左遍歷,記錄經過的最小值為min,若當前數大于min,說明,如果要有序,min一定要放? ? ? 在當前數左邊,我們更新noMinindex。

? ? 也就是說,我們的noMinindex是負責記錄最左邊出現這種情況的位置。我們反方向處理出noMaxindex

? ? 他們組成的區間就是最短需要排序的部分了

public class MinLengthForSort {public static int getMinLength(int[] arr) {if (arr == null || arr.length < 2) {return 0;}int min = arr[arr.length - 1];int noMinIndex = -1;for (int i = arr.length - 2; i != -1; i--) {if (arr[i] > min) {noMinIndex = i;} else {min = Math.min(min, arr[i]);}}if (noMinIndex == -1) {return 0;}int max = arr[0];int noMaxIndex = -1;for (int i = 1; i != arr.length; i++) {if (arr[i] < max) {noMaxIndex = i;} else {max = Math.max(max, arr[i]);}}return noMaxIndex - noMinIndex + 1;}public static void main(String[] args) {int[] arr = { 1, 2, 4, 7, 10, 11, 7, 12, 6, 7, 16, 18, 19 };System.out.println(getMinLength(arr));}}

?

題目二:

? ? 給定一個數組,找出出現次數超過一半的數字

蠢思路:排序找中間

思路:

? ? DP:掃一遍一個變量count記錄解出現的次數,是當前解就++,否則--,count為負就換掉當前解。(解釋:想象解全都挨在? ? ? ? ?一起(前面),count先達到最大,然后減為1或0,而其他數字先出現,可能會使正確解的count減為負數,但都會使正確解? ? ? ? 在后面更多,從而保證了結束時肯定為正確解)

int main() {int n;//個數scanf("%d",&n);int temp,k,count=0;while(n--){scanf("%d",&temp);if(temp==k)count++;else{count--;if(count<0){count=0;k=temp;}}}printf("%d\n",k); }

?

?

題目三:

給定一個有N×M的整型矩陣matrix和一個整數K,matrix的每一行和每一列都是排好序的。實現一個函數,判斷K是否在matrix中。

例如:

0???????1???????2???????5

2???????3???????4???????7

4???????4???????4???????8

5???????7???????7???????9

如果K為7,返回true,如果K為6,返回false

要求:

時間復雜度為O(N+M),額外空間復雜度為O(1)。

思路:

1.從矩陣最右上角的數開始尋找(row=0,col=M-1)。

2.比較當前數matrix[row][col]與K的關系:

如果與K相等,說明已找到,直接返回true

如果比K大,因為矩陣每一列都已排好序,所以在當前數所在的列中,處于當前數下方的數都會比K大,則沒有必要繼續在第col列上尋找,令col=col-1,重復步驟2.

如果比K小,因為矩陣每一行都已排好序,所以在當前數所在的行中,處于當前數左方的數都會比K小,則沒有必要繼續在第row行上尋找,令row=row+1,重復步驟2.

3.如果找到越界都沒有發現與K相等的數,則返回false。

或者可以從矩陣的最左下角的數開始尋找(row=N-1,col=0),具體過程類似。

代碼:
?

/*** 在行列都排好序的矩陣中找數*/ public class IsContains {public boolean isContains(int[][] matrix, int K) {int row = 0;int col = matrix[0].length - 1;while (row < matrix.length && col > -1) {if (matrix[row][col] == K) {return true;} else if (matrix[row][col] > K) {col--;} else {row++;}}return false;} }

題目四:轉圈打印矩陣


題目:

給定一個整型矩陣matrix,請按照轉圈的方式打印它。例如:1,2,3,4,5,6,7,8,9,10,11,12,13,14,15,16,打印結果為:1,2,3,4,5,12,16,15,14,13,9,5,6,7,11,10

要求:

額外空間復雜度為O(1)

?思路:

矩陣分圈處理。在矩陣中用左上角的坐標(tR,tC)和右下角的坐標(dR,dC)就可以表示一個矩陣,比如,題目中的矩陣,當(tR,tC)=(0,0),(dR,dC)=(3,3)時,表示的子矩陣就是整個矩陣,那么這個子矩陣的最外層的部分如下:

1??????????2??????????3??????????4

5??????????????????????????????????8

9?????????????????????????????????12

13???????14????????15????????16

如果能把這個子矩陣的外層轉圈打印出來,那么在(tR,tC)=(0,0)、(dR,dC)=(3,3)時,打印結果為:1,2,3,4,8,12,16,15,14,13,9,5。接下來令tR和tC加1,即(tR,tC)=(1,1),令dR和dC減1,即(dR,dC)=(2,2),此時表示的子矩陣如下:

6????????7

10??????11

再把這個子矩陣轉圈打印出來,結果為:6,7,11,10。把tR和tC加1,即(tR,tC)=(2,2),令dR和dC減1,即(dR,dC)=(1,1)。如果發現左上角坐標跑到右下角坐標的右方或下方,整個過程就停止。已經打印的所有結果連接起來就是我們要求的打印結果。

代碼:

/*** 轉圈打印矩陣*/ public class PrintMatrixSpiralOrder {public void spiralOrderPrint(int[][] matrix) {int tR = 0;int tC = 0;int dR = matrix.length - 1;int dC = matrix[0].length - 1;while (tR <= dR && tC <= dC) {printEdge(matrix, tR++, tC++, dR--, dC--);}}//轉圈打印一個子矩陣的外層,左上角點(tR,tC),右下角點(dR,dC)private void printEdge(int[][] matrix, int tR, int tC, int dR, int dC) {if (tR == dR) {//子矩陣只有一行時for (int i = tC; i <= dC; i++) {System.out.print(matrix[tR][i] + " ");}} else if (tC == dC) {//子矩陣只有一列時for (int i = tR; i <= dR; i++) {System.out.print(matrix[i][tC] + " ");}} else {//一般情況int curCol = tC;int curRow = tR;while (curCol != dC) {//從左向右System.out.print(matrix[tR][curCol] + " ");curCol++;}while (curRow != dR) {//從上到下System.out.print(matrix[curRow][dC] + " ");curRow++;}while (curCol != tC) {//從右到左System.out.print(matrix[dR][curCol] + " ");curCol--;}while (curRow != tR) {//從下到上System.out.print(matrix[curRow][tC] + " ");curRow--;}}} }


題目五:將正方形矩陣順時針轉動90°


題目:

給定一個N×N的矩陣matrix,把這個矩陣調整成順時針轉動90°后的形式。

例如:

1????????2????????3????????4

5????????6????????7????????8

9????????10??????11??????12

13??????14??????15??????16

順時針轉動90°后為:

13??????9???????5??????1

14??????10?????6??????2

15??????11?????7??????3

16??????12?????8??????4

要求:

額外空間復雜度為O(1).

思路:

仍然使用分圈處理的方式,

在矩陣中用左上角的坐標(tR,tC)和右下角的坐標(dR,dC)就可以表示一個矩陣,比如,題目中的矩陣,當(tR,tC)=(0,0),(dR,dC)=(3,3)時,表示的子矩陣就是整個矩陣,那么這個子矩陣的最外層的部分如下:

1??????????2??????????3??????????4

5??????????????????????????????????8

9?????????????????????????????????12

13???????14????????15????????16

在這個外圈中,1,4,16,13為一組,然后讓1占據4的位置,4占據16的位置,16占據13的位置,13占據1的位置,一組就調整完了。然后2,8,15,9為一組,繼續占據調整的過程,最后3,12,14,5為一組,繼續占據調整的過程。然后(tR,tC)=(0,0)、(dR,dC)=(3,3)的子矩陣外層就調整完畢,接下來令tR和tC加1,即(tR,tC)=(1,1),令dR和dC減1,即(dR,dC)=(2,2),此時表示的子矩陣如下:

6???????7

10?????11

這個外層只有一組,就是6,7,11,10,占據調整之后即可。所以,如果子矩陣的大小是M×M,一共就有M-1組,分別進行占據調整即可。

代碼:

/*** 將正方形矩陣順時針旋轉90°*/ public class RotateMatrix {public static void rotate(int[][] matrix) {int tR = 0;int tC = 0;int dR = matrix.length - 1;int dC = matrix[0].length - 1;while (tR < dR) {rotateEdge(matrix, tR++, tC++, dR--, dC--);}}private static void rotateEdge(int[][] matrix, int tR, int tC, int dR, int dC) {int times = dC - tC;//times就是總的組數int temp = 0;for (int i = 0; i != times; i++) {//一次循環就是一組占據調整temp = matrix[tR][tC + i];matrix[tR][tC + i] = matrix[dR - i][tC];matrix[dR - i][tC] = matrix[dR][dC - i];matrix[dR][dC - i] = matrix[tR - i][dC];matrix[tR - i][dC] = temp;}} }


題目六:“之”字形打印矩陣


題目:

給定一個矩陣matrix,按照“之”字形的方式打印矩陣,例如:

1????????2????????3????????4

5????????6????????7????????8

9????????10??????11??????12

“之”字形打印的結果為:1,2,5,9,6,3,4,7,10,11,8,12

要求:

額外空間復雜度為O(1)

思路;

上坐標(tR,tC)初始化為(0,0),先沿著矩陣第一行移動(tC++),當到達第一行最右邊的元素后,在沿著矩陣最后一列移動(tR++)。
下坐標(dR,dC)初始為(0,0),先沿著矩陣第一列移動(dR++),當到達第一列最下邊的元素時,再沿著矩陣最后一行移動(dC++)。
上坐標與下坐標同步移動,每次移動后的上坐標與下坐標的連線就是矩陣中的一條斜線,打印斜線上的元素即可。
如果上次斜線是從左下向右上打印的,這次一定是從右上向左下打印,反之亦然。總之,可以把打印的方向用boolean值表示,每次取反即可。
代碼:

/*** 之字形打印矩陣*/ public class PrintMatrixZigZag {public static void printMatrixZigZag(int[][] matrix) {int tR = 0;int tC = 0;int dR = 0;int dC = 0;int endRow = matrix.length - 1;int endCol = matrix[0].length - 1;boolean fromUp = false;while (tR != endRow + 1) {printLevel(matrix, tR, tC, dR, dC, fromUp);tR = tC == endCol ? tR + 1 : tR;tC = tC == endCol ? tC : tC + 1;dR = dR == endRow ? dR : dR + 1;dC = dR == endRow ? dC + 1 : dC;fromUp = !fromUp;}System.out.println();}private static void printLevel(int[][] matrix, int tR, int tC, int dR, int dC, boolean fromUp) {if (fromUp) {while (tR != dR + 1) {//從左下到右上System.out.print(matrix[tR++][tC--] + " ");}} else {while (dR != tR - 1) {//從右上到左下System.out.print(matrix[dR--][dC++] + " ");}}} }

題目七

給定一個長度為N的整型數組arr,其中有N個互不相等的自然數1~N

請實現arr的排序

但是不要把下標0~N-1位置上的數值通過直接賦值的方式替換成1~N。

要求:時間復雜度為O(N),額外空間復雜度為O(1)。

?

思路:從左向右檢查,檢查到需要換的以后,就直接把它放到該去的位置,然后被換掉的數,位置肯定也不對,繼續重復相同的方法,最后肯定會跳回來(原因懶得說了自己想想),然后繼續往下檢查即可。

public static void sort1(int[] arr) {int tmp = 0;int next = 0;for (int i = 0; i != arr.length; i++) {tmp = arr[i];while (arr[i] != i + 1) {next = arr[tmp - 1];arr[tmp - 1] = tmp;tmp = next;}}}

題目八

本題一般思路:依次查找找到比前后都小的數;或者選出最小數,他肯定是局部最小的;等等

但這些都是O(n)的方法,而用二分可以做到O(logn).

二分思路:

??考慮最左和最右的元素:如果arr[0]<arr[1] ?return?0; arr[N-1]<arr[N-2] return?N-1;

???考慮最中間元素,如果中間元素大于它左邊的元素,那么局部最小值就應該在數組的左半部分

???如果中間元素小于大于它右邊的元素,那么局部最小值就應該在數組的右半部分

???中間元素既小于它左邊的值又小于它右邊的值,那么它就是局部最小
?

題目九

?

給定一個整數數組arr,返回不包含本位置的累乘數組。

比如2 3 1 4返回12 8 24 6

方法一:算出所有數的乘積,每個位置除以自己即可。要注意坑:如果數組中有一個0,那么0這個位置就是其他數的乘積,其他位置全為0;如果有多個0,那么所有位置都是0.

public int[] product1(int[] arr) {if(arr==null || arr.length<2) {return null;}int count=0;//0的個數int all=1;//除0以外的數的乘積for(int i=0;i!=arr.length;i++) {if(arr[i]!=0) {all*=arr[i];}else {count++;}}int[] res=new int[arr.length];if(count==0) {for(int i=0;i!=arr.length;i++) {res[i]=all/res[i];}}else if(count==1) {for(int i=0;i!=arr.length;i++) {if(arr[i]==0) {res[i]=all;}}}return res;}

?

題目十:子數組的最大累加和問題

輸入一個整形數組,求數組中連續的子數組使其和最大。比如,數組x

應該返回 x[2..6]的和187.

?

這四個代碼完成的功能都是求最大子數組(注意用詞準確,子數組連續,子序列可以不連續)。

1)

for(i = 1; i <= n; i++)scanf("%d", &num[i]); ans = num[1]; for(i = 1; i <= n; i++) {for(j = i; j <= n; j++) {s = 0;for(k = i; k <= j; k++)s += num[k];if(s > ans)ans = s;} }

分別枚舉每一個子數組的起點和終點,也就是i和j,對于每一個起點和終點,對中間部分求和,也就是k循環。顯然有n個起點n個終點(去重減半,不影響復雜度),所以子數組數量為O(N^2),對于每個子數組,我們要遍歷一下求和,子數組長度1-n不等,遍歷一遍平均O(N),乘起來O(N^3).(注意可能產生時間更大的錯覺)。找出所有子數組中最大的即可。

2)

for(i = 1; i <= n; i++)scanf("%d", &num[i]); sum[0] = 0; for(i = 1; i <= n; i++) {sum[i] = num[i] + sum[i - 1]; } ans = num[1]; for(i = 1; i <= n; i++) {for(j = i; j <= n; j++) {s = sum[j] - sum[i - 1];if(s > ans) ans = s;} }

預處理出每一個以第一個元素開始,第i個元素結尾的子數組和,還是枚舉每個起點終點,但是我們求和時直接減就可以了,不用遍歷。對于每個子數組,操作為O(1),子數組數量O(N^2),所以總時間O(N^2).

3)

int solve(int left, int right) {if(left == right)return num[left];mid = (left + right) / 2;lans = solve(left, mid);rans = solve(mid + 1, right);sum = 0, lmax = num[mid], rmax = num[mid + 1];for(i = mid; i >= left; i--) {sum += num[i];if(sum > lmax) lmax = sum;}sum = 0;for(i = mid + 1; i <= right; i++) {sum += num[i];if(sum > rmax) rmax = sum;}ans = lmax + rmax;if(lans > ans) ans = lans;if(rans > ans) ans = rans;return ans; }int main(void) {scanf("%d", &n);for(i = 1; i <= n; i++)scanf("%d", &num[i]);printf("%d\n", solve(1, n));return 0; }

二分,求左右兩邊最大子數組,取最大。但是還有一種情況:包含斷點的那些子數組也要考慮,請思考那兩個那兩個循環為什么那么寫?最后邏輯為何正確?

4)動態規劃入門思想

沒有枚舉,num[i]的含義是以下標i結尾的所有子數組中最大的。

遍歷數組,對于第i個元素,它的所有子數組下標范圍有[1,i],[2,i].....[i-1,i],還有它自己,我們看i-1個元素,他的子數組為[1,i-1],[2,i-1].....[i-1]。請想num[i]的含義,我們求i結尾的,只要把i-1結尾的最大加上i就好了,當然如果i-1結尾最大子數組是負的,i結尾最大子數組就是它本身。

為什么O(N)?時間省在哪里了?我們省掉了許多沒必要的計算,計算i時,之前的數組和已經都計算過,樸素算法并沒有記錄下來,而是重復計算,造成時間浪費。算法優化的過程就是去掉重復計算的過程。
?

for(i = 1; i <= n; i++)scanf("%d", &num[i]);num[0] = 0; ans = num[1]; for(i = 1; i <= n; i++) {if(num[i - 1] > 0) num[i] += num[i - 1];elsenum[i] += 0;if(num[i] > ans) ans = num[i]; }

題目十一、子矩陣的最大累加和問題

給一個矩陣,請找出一個矩陣中,和最大的子矩陣。

?

?

?

如果大家看懂了上一題的講解,我給個提示:利用第二個代碼和第四個代碼思想的結合

?

?

解釋:

1???2??3???4

-1 -2??1???2

1???3???-2??1

-1??-2??-1??-3

如圖是前三行整體最大

怎么做呢?

先用第二個代碼的思想,我們進行預處理

每個數代表這一列到這個數位置截止,累加和。

1??2??3??4

0??0??4??6

1??3??2??7

0??1??1??4

然后,我們枚舉每一列的起點和終點分別為第0,1,2,3行

然后壓縮成一維來做

比如求1-3行的這個矩形,我們拿0和3行減一下就行了

0-1,1-2,1-3,4-4=-1,-1,-2,0就是1-3行壓縮后的結果

然后按一維dp來做就好
?

public class SubMatrixMaxSum {public static int maxSum(int[][] m) {if (m == null || m.length == 0 || m[0].length == 0) {return 0;}int max = Integer.MIN_VALUE;int cur = 0;int[] s = null; // 累加數組for (int i = 0; i != m.length; i++) {s = new int[m[0].length];for (int j = i; j != m.length; j++) {cur = 0;for (int k = 0; k != s.length; k++) {s[k] += m[j][k];cur += s[k];max = Math.max(max, cur);cur = cur < 0 ? 0 : cur;}}}return max;}public static void main(String[] args) {int[][] matrix = { { -90, 48, 78 }, { 64, -40, 64 }, { -81, -7, 66 } };System.out.println(maxSum(matrix));}}

題目十二、子數組的最大累乘積

題目:

給定一個double類型的數組arr,其中的元素可正、可負、可為0。返回子數組累乘的最大乘積。

思路:

假設以arr[i-1]結尾的數組最小累乘積為min,最大累乘積為max,那么以arr[i]結尾的數組的最大累乘積可能有三種情況。

  • max*arr[i]//本身乘之前的最大累乘
  • min*arr[i]//可能是負負得正變成最大的
  • arr[i]//可能就是它本身,比如之前的max小于1
public class SubArrayMaxProduct {public static double maxProduct(double[] arr) {if (arr == null || arr.length == 0) {return 0;}double max = arr[0];double min = arr[0];double res = arr[0];double maxEnd = 0;double minEnd = 0;for (int i = 1; i < arr.length; ++i) {maxEnd = max * arr[i];minEnd = min * arr[i];max = Math.max(Math.max(maxEnd, minEnd), arr[i]);min = Math.min(Math.min(maxEnd, minEnd), arr[i]);res = Math.max(res, max);}return res;}public static void main(String[] args) {double[] arr = { -2.5, 4, 0, 3, 0.5, 8, -1 };System.out.println(maxProduct(arr));}}

題目十三:調整有序的arr數組,使得左半部分有序且不重復,不用保證右邊是否有序。

思路:
?? ? ? ? ? ? ?u : 左邊的最后位置,即0---u為答案
?? ? ? ? ? ? ?i : 從u到右遍歷
?? ? ? ? ? ? ?當arr[i]和arr[u]不相等時,說明是目前遇到的最大的數,此時調換arr[u+1]和arr[i]

public static void leftUnique(int[] arr) {if (arr == null || arr.length < 2) {return;}int u = 0;int i = 1;while (i != arr.length) {if (arr[i++] != arr[u]) {swap(arr, ++u, i - 1);}}} public static void swap(int[] arr, int index1, int index2) {int tmp = arr[index1];arr[index1] = arr[index2];arr[index2] = tmp;}

題目十四:數組arr中只有三種值:0,1,2,請排序

思路:荷蘭國旗問題:https://blog.csdn.net/hebtu666/article/details/81772701

上面的網址介紹了思路和c++實現,本文給出java實現。

public static void sort(int[] arr) {if (arr == null || arr.length < 2) {return;}int left = -1;int index = 0;int right = arr.length;while (index < right) {if (arr[index] == 0) {swap(arr, ++left, index++);} else if (arr[index] == 2) {swap(arr, index, --right);} else {index++;}}}

?

題目十五:數組arr,給定k,請實現比k小的放左邊,等于k的放中間,大于k的放右邊

同樣的分三區,只是條件改一下,<k,=k,>k即可。

?

總結

以上是生活随笔為你收集整理的超硬核!躺进BAT以后我总结了出现最多的15道数组题的全部內容,希望文章能夠幫你解決所遇到的問題。

如果覺得生活随笔網站內容還不錯,歡迎將生活随笔推薦給好友。