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

歡迎訪問 生活随笔!

生活随笔

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

编程问答

数组面试题-大力出奇迹?

發布時間:2024/3/12 编程问答 40 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数组面试题-大力出奇迹? 小編覺得挺不錯的,現在分享給大家,幫大家做個參考.

文章目錄

  • 數組中重復的數字
  • 二維數組中的查找
  • 旋轉數組的最小數字
  • 調整數字順序使奇數位于偶數前面
  • 數組中出現次數超過一半的數字
  • 最小的k個數
  • 連續子數組的最大和
  • 數字序列中某一位的數字
  • 把數組排成最小的數
  • 和為s的數字
  • 數組中數字出現的次數

相關推薦(面試專欄查看更多)

  • 鏈表面試題(動圖詳解)-明明做出來了卻為什么沒有Offer?
  • 二叉樹面試題-你已經是棵成熟的二叉樹了,要學會自己解題
  • 數組面試題-大力出奇跡?

數組中重復的數字


題目:在一個長度為n的數組里的所有數字都在0~n-1的范圍內。數組中某些數字時重復的,但不知道有幾個數字重復了,也不知道每個數字重復了幾次。請找出數組中任意一個重復的數字。

一般做法可能是吧數組排序,然后只需從頭到尾掃描排序后的數組就可以了,復雜度是O(nlogn)O(nlogn)O(nlogn)。還可以借助哈希表,判斷是否存在重復數字,時間復雜度是O(n)O(n)O(n)但是也需要O(n)O(n)O(n)大小的空間。

我們來看一種時間復雜度是O(n)O(n)O(n)且空間復雜度是O(1)O(1)O(1)的做法。因為數字范圍是0~n-1,當沒有重復數字時,數字i將出現在下標為i的位置,當有重復數字時有些位置就可能存在多個數字。從頭到尾掃描這個數字中的每個數字,當掃描到下標為i的數字是,比較這個數字(設為m)是否和i相同,若相同則繼續掃描下一個數字;否則拿它和下標為m的數字比較,如果相同就找到了一個重復的數字,否則交換這兩個數字。

#include<bits/stdc++.h> using namespace std; bool duplicate(int numbers[], int length, int* dulication) {if (numbers == nullptr || length <= 0) //空return false;for (int i = 0; i < length; i++)if (numbers[i] < 0 || numbers[i] >= length)//非0~n-1return false;for (int i = 0; i < length; i++) {while (numbers[i] != i) {if (numbers[i] == numbers[numbers[i]]) {*dulication = numbers[i];return true;}swap(numbers[i], numbers[numbers[i]]);}}return false; } int main() {int a[7] = { 3,0,2,1,2,4,0 };int ans = -1;if (duplicate(a, 7, &ans))printf("重復數為%d", ans);else printf("無重復數");return 0; } //運行結果:重復數為2

二維數組中的查找


題目:在一個二維數組中,每一行都是按照從左到右遞增的順序排序,每一列都按照從上到下遞增的順序排序。請完成一個函數,輸入這樣一個二維數組和一個整數,判斷數組中是否含有該整數

對于排序數組中的查找,我們第一反應是用二分查找,但是在這個二維數組中,二分會存在兩個區域(藍、黃),而且兩個區域間還會重疊(綠),處理起來較復雜。


我們考慮選取右上角(15)作為起點,設查找的數字是10,首先15大于10,那15這一列后面的數是比15還大的,所以15這一列排除;然后分析剩下的列,仍取右上角(9),9小于10,那9這一行前面的數也是比9小的,排除9這一行;然后分析11,11大于10同樣排除這一列,接下來的右上角就是我們需要找的數10,退出循環。

#include<bits/stdc++.h> using namespace std; bool find(int *a, int n, int m, int num) {bool found = false;int i = 0, j = m - 1;while (i < n && j >= 0) {if (*(a+i*n+j) > num)j--;else if (*(a + i * n + j) < num)i++;else {found = true;printf("%d %d\n", i, j);break;}}return found; } int main() {int a[5][4] = { 1,3,8,9,15,2,4,10,11,16,4,6,11,12,17,6,11,12,15,21 };if (find((int*)a, 5, 4, 10))printf("找到了");else printf("找不到");return 0; } /*運行結果 1 2 找到了 */

旋轉數組的最小數字


題目:把一個數組最開始的若干元素搬到數組的末尾,我們稱之為數組的旋轉。輸入一個遞增排序的數組的一個旋轉,輸出旋轉數組的最小元素。

直觀做法可能就是遍歷數組找到最小數字即可,復雜度是O(n)O(n)O(n),但就完全沒用到給定條件,事情不會這么簡單。

其實旋轉數組可以看成由兩個有序子數組組成的,最小元素剛好就是這兩個子數組的分界線,而對于有序來說,可以嘗試二分。分別用兩個指針指向第一個元素和最后一個元素,然后求出中間元素,若中間元素位于前面子數組(大于等于第一個指針的值),說明最小元素應位于中間元素后面,把第一個指針移到中間;否則位于后面子數組(小于等于第二個指針)則移動第二個指針,當兩個指針相鄰時,第二個指針值就是答案。復雜度是O(logn)O(logn)O(logn)

但這樣還存在一個BUG,就是判斷中間指針既大于等于第一個指針,又小于等于第二個指針的情況,此時就無法判斷屬于哪一個子數組,移動哪一個指針,這種情況下只能采用順序查找暴力的方法了。

#include<bits/stdc++.h> using namespace std; int Min(int* a, int len) {if (a == nullptr || len <= 0)throw new exception();int l = 0, r = len - 1;int mid = 0;//注意旋轉0個元素時,答案是第0個元素while (a[l] >= a[r]) {if (r - l == 1) {mid = r;break;}mid = (l + r) >> 1;if (a[l] == a[mid] && a[mid] == a[r]) {int rtn = a[0]; //三指針相等則暴力for (int k = 1; k < len; k++)rtn = min(rtn, a[k]);mid = rtn;break;}if (a[l] <= a[mid])l = mid;else if (a[r] >= a[mid])r = mid;}return a[mid]; } int main() {int a[6] = {4,5,6,1,2,3 };printf("%d", Min(a, 6));return 0; } //運行結果:1

調整數字順序使奇數位于偶數前面


題目:輸入一個整數數組,實現一個函數來調整該數組中數組的順序,使得所有奇數位于數組前半部分,所有偶數位于數組后半部分

最笨的方法無非就是遍歷數組,每當遇到一個偶數,就把他后面的數往前挪,時間復雜度時O(n2)O(n^2)O(n2)

我們可以定義維護指針,一個從前向后維護奇數,一個從后向前維護偶數,當第一個指針遇到偶數時,就移動第二個指針尋找一個奇數,然后交換這兩個數字,當兩指針相遇則退出。復雜度是O(n)O(n)O(n)

#include<bits/stdc++.h> using namespace std; void Reorder(int* a, int len) {if (a == nullptr || len <= 0)return;int l = 0, r = len - 1;while (l < r) {while (l < r && a[l] % 2 == 1)//移動第一個指針直到偶數l++;while (l < r && a[r] % 2 == 0)//移動第一個指針直到奇數r--;swap(a[l], a[r]);} } int main() {int a[6] = { 1,2,3,4,5,6 };Reorder(a, 6);for (int i = 0; i < 6; i++)printf("%d ", a[i]);return 0; } //運行結果:1 5 3 4 2 6

數組中出現次數超過一半的數字


題目:數組中有一個數字出現的次數超過數組長度的一半,請找出這個數字。

一般做法是把數組排序,然后中位數就是答案,時間復雜度是O(nlogn)O(nlogn)O(nlogn)

解法二:
分析發現,數組中一個數字出現次數超過數組一半,也就是說其他所有數字出現次數加起來也沒有它多。因此當我們遍歷下一個數字的時候,若和上一個數字相同則次數加一;若不同則次數減一,當次數為0的時候,需要更新保存的數字并設次數為1。復雜度是O(n)O(n)O(n)

#include<bits/stdc++.h> using namespace std; int moreThanHalf(int* a, int len) {if (a == nullptr || len <= 0)throw new exception();int num = a[0];int cnt = 1;for (int i = 1; i < len; i++) {if (cnt == 0) {num = a[i];cnt = 1;}else if (a[i] == num)cnt++;else cnt--;}return num; } int main() {int a[6] = { 1,2,2,2,3 };printf("%d", moreThanHalf(a, 5));return 0; } //運行結果:2

(插播反爬信息 )博主CSDN地址:https://wzlodq.blog.csdn.net/

最小的k個數


題目:輸入n個整數,找出其中最小的k個數。

一般做法還是排序,然后輸出前k的數即可,復雜度是O(nlogn)O(nlogn)O(nlogn)。

我們可以創建一個大小為k的數據容器來存儲最小的k個數字,每次讀入一個數的時候,判斷容器中是否已有k個數據,沒有的話則放入,有的話則比較容器中的最大值,若大于當前數則替換之,保持容器中是目前最小的k個數,復雜度是O(nlogk)O(nlogk)O(nlogk),適合海量數據。

#include<bits/stdc++.h> using namespace std; void getLeastK(int* a,int len, int k) {if (a == nullptr || k <= 0 || k > len)return;multiset<int,greater<int>>s;//可重復大根堆multiset<int, greater<int>>::iterator it;for (int i = 0; i < len; i++) {if (s.size() < k)s.insert(a[i]);else {it = s.begin();if (*it > a[i]) {s.erase(it);s.insert(a[i]);}}}for (it = s.begin(); it != s.end(); it++)printf("%d ", *it); } int main() {int a[6] = { 1,4,5,2,2 };getLeastK(a, 5, 3);return 0; } //運行結果:2 2 1

連續子數組的最大和


題目:輸入一個整型數組,數組里有正數也有負數。數組中一個或連續多個整數組成一個子數組。求所有數組的和的最大值,要求時間復雜度是O(n)O(n)O(n)。

當前面累加的和小于0時,則拋棄前面的,從當前數開始累加,否則加上前面的累加和,動態的維護一個最大值。此外也可以用動態規劃求解,設dp[i]dp[i]dp[i]表示第iii個數字結尾的子數組的最大和,dp[i]=max(a[i],dp[i?1]+a[i])dp[i]=max(a[i],dp[i-1]+a[i])dp[i]=max(a[i],dp[i?1]+a[i])。

#include<bits/stdc++.h> using namespace std; int getMaxSub(int* a,int len) {int* dp = new int[len];dp[0] = a[0];for (int i = 1; i < len; i++) {dp[i] = max(a[i], dp[i - 1] + a[i]);}int mx = dp[0];for (int i = 1; i < len; i++)mx = max(mx, dp[i]);return mx; } int main() {int a[7] = { 1,4,-5,2,2 ,-1,3 };printf("%d", getMaxSub(a, 7));return 0; } //運行結果:6

數字序列中某一位的數字


題目:數字以0123456789101112131415…的格式序列化到一個字符序列中。在這個序列中第5位(從0開始計數)是5,第13位是1,第19位是4等等。請寫一個函數,求任意第n位對應的數字。

笨方法就是直接構造序列,然后求出第n位。但是我們有更快的方法,找出某些規律從而跳過若干數字。

首先只有0-9這10個一位數,然后是10-99這90個兩位數,然后是100-999這900個三位數,以此類推,不難發現,n≠1時,共有9*10n-1個n位數,這樣我們就能跳過若干位,直接到第n位所對應的數字,然后再去確定是這個數字的第幾位。

#include<bits/stdc++.h> using namespace std; int digitAtIndex(int index) {if (index < 0)return -1;int n = 1;//n位數while (1) {//找到位于幾位數之間int cnt = n == 1 ? 10 : 9 * pow(10, n - 1);//n位數個數if (index < cnt * n)break;index -= n * cnt;n++;}int num = n == 1 ? 0 : pow(10, n - 1);//n位數的第一個數num += index / n;//index位于第幾個數int r = n - index % n;//這個數的第幾位for (int i = 1; i < r; i++)num /= 10;return num % 10; } int main() {printf("第1位:%d\n", digitAtIndex(1));printf("第5位:%d\n", digitAtIndex(5));printf("第13位:%d\n", digitAtIndex(13));printf("第19位:%d\n", digitAtIndex(19));return 0; } /*運行結果 第1位:1 第5位:5 第13位:1 第19位:4 */

把數組排成最小的數


題目:輸入一個正整數數組,把數組里所有數字拼接起來排成一個數,打印能拼接處的所有數字中最小的一個。例如,輸入數組{3,32,321},則能排成最小數字是321323。

直接用全排列的話,肯定超時,而且還是一個隱形的大數問題。一個直觀的解決方法就是先把數字轉成成字符串,把數字n和m拼接起來的到nm和mn,它們的位數是相同的,因此比較他們的大小只需要按照字符串大小的比較規則就可以了,排序之后的順序組成的數字就是最小的數,證明略。

#include<bits/stdc++.h> using namespace std; bool cmp(string a,string b){string c=a+b;string d=b+a;return c<d; } void printMin(int* a, int len) {if (a == nullptr || len <= 0)return;string* s = new string[len];char* c = new char[len];for (int i = 0; i < len; i++) {sprintf(c, "%d", a[i]);s[i] = c;}sort(s, s + len,cmp);for (int i = 0; i < len; i++)cout << s[i]; } int main() {int a[3] = { 3,32,321 };printMin(a, 3);return 0; } //運行結果:321323

和為s的數字


題目:輸入一個遞增排序的數組和一個數字s,在數組中查找兩個數,使得它們的和正好是s。如果有多對數字的和等于s,則輸出任意一對即可。

由于數組是遞增的(也可以自己排序下),那我們可以用雙指針類似尺取法的思路來求解。定義兩個指針,指向第一個和最后一個元素,當這兩個元素的和大于s時,則把第二個指針向前移動,否則向后移動第二個指針即可。

比如數組{2,4,5,7,11,15}求和為16的過程:

#include<bits/stdc++.h> using namespace std; void findSum(int* a, int len,int s) {if (a == nullptr || len <= 0)return;int l = 0, r = len - 1;while (l < r) {int cur = a[l] + a[r];if (cur == s) {printf("%d %d", a[l], a[r]);return;}if (cur > s)r--;else l++;}printf("找不到"); } int main() {int a[6] = { 2,4,5,7,11,15 };findSum(a, 6, 16);return 0; } //運行結果:5 11

數組中數字出現的次數


題目:求數組中只出現一次的兩個數字。
一個整型數組里除了兩個數字之外,其他數字都出現了兩次。請寫程序找出這兩個只出現一次的數字。要求是否復雜度時O(n)O(n)O(n),空間復雜度是O(1)O(1)O(1)。

我們想到異或運算的一個性質:任何一個數字異或他自己都等于0。也就是說,如果我們從頭到尾依次異或數組中的每個數字,那么最終結果剛好是那個只出現一次的數字,那些出現兩次以上的數字全部在異或中抵消了。

可這道題目是有兩個只出現一次的數字。怎么拆成兩個子數組呢?我們先遍歷數組全部異或一遍,得到的結果就是那兩個數字的異或結果,由于這兩個數字不同,所以異或結果不為0,在二進制中至少有一位為1,那么我們就可以根據這一位是不是為1,把數字劃分成兩個子數組,然后就能求解了。而且相同的數不可能分別分配到兩個子數組中,因為它們的二進制也是相同的。

#include<bits/stdc++.h> using namespace std; void findOnce(int* a, int len) {if (a == nullptr || len <= 0)return;int XOR = 0;for (int i = 0; i < len; i++) //求異或值XOR ^= a[i];int idx = 0;while ((XOR & 1) == 0) {//求最右的1XOR >>= 1;idx++;}int n=0, m=0;//兩個子數組分別異或for (int i = 0; i < len; i++) {if (((a[i] >> idx) & 1) == 0)n ^= a[i];else m ^= a[i];}printf("%d %d", n, m); } int main() {int a[8] = { 2,4,3,4,6,3,5,2 };findOnce(a, 8);return 0; } //運行結果:6 5

原創不易,請勿轉載(本不富裕的訪問量雪上加霜 )
博主首頁:https://wzlodq.blog.csdn.net/
微信公眾號:吾仄lo咚鏘
如果文章對你有幫助,記得一鍵三連?

總結

以上是生活随笔為你收集整理的数组面试题-大力出奇迹?的全部內容,希望文章能夠幫你解決所遇到的問題。

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