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

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) >

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

發(fā)布時(shí)間:2024/3/12 33 豆豆
生活随笔 收集整理的這篇文章主要介紹了 数组面试题-大力出奇迹? 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

文章目錄

  • 數(shù)組中重復(fù)的數(shù)字
  • 二維數(shù)組中的查找
  • 旋轉(zhuǎn)數(shù)組的最小數(shù)字
  • 調(diào)整數(shù)字順序使奇數(shù)位于偶數(shù)前面
  • 數(shù)組中出現(xiàn)次數(shù)超過(guò)一半的數(shù)字
  • 最小的k個(gè)數(shù)
  • 連續(xù)子數(shù)組的最大和
  • 數(shù)字序列中某一位的數(shù)字
  • 把數(shù)組排成最小的數(shù)
  • 和為s的數(shù)字
  • 數(shù)組中數(shù)字出現(xiàn)的次數(shù)

相關(guān)推薦(面試專(zhuān)欄查看更多)

  • 鏈表面試題(動(dòng)圖詳解)-明明做出來(lái)了卻為什么沒(méi)有Offer?
  • 二叉樹(shù)面試題-你已經(jīng)是棵成熟的二叉樹(shù)了,要學(xué)會(huì)自己解題
  • 數(shù)組面試題-大力出奇跡?

數(shù)組中重復(fù)的數(shù)字


題目:在一個(gè)長(zhǎng)度為n的數(shù)組里的所有數(shù)字都在0~n-1的范圍內(nèi)。數(shù)組中某些數(shù)字時(shí)重復(fù)的,但不知道有幾個(gè)數(shù)字重復(fù)了,也不知道每個(gè)數(shù)字重復(fù)了幾次。請(qǐng)找出數(shù)組中任意一個(gè)重復(fù)的數(shù)字。

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

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

#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("重復(fù)數(shù)為%d", ans);else printf("無(wú)重復(fù)數(shù)");return 0; } //運(yùn)行結(jié)果:重復(fù)數(shù)為2

二維數(shù)組中的查找


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

對(duì)于排序數(shù)組中的查找,我們第一反應(yīng)是用二分查找,但是在這個(gè)二維數(shù)組中,二分會(huì)存在兩個(gè)區(qū)域(藍(lán)、黃),而且兩個(gè)區(qū)域間還會(huì)重疊(綠),處理起來(lái)較復(fù)雜。


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

#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; } /*運(yùn)行結(jié)果 1 2 找到了 */

旋轉(zhuǎn)數(shù)組的最小數(shù)字


題目:把一個(gè)數(shù)組最開(kāi)始的若干元素搬到數(shù)組的末尾,我們稱(chēng)之為數(shù)組的旋轉(zhuǎn)。輸入一個(gè)遞增排序的數(shù)組的一個(gè)旋轉(zhuǎn),輸出旋轉(zhuǎn)數(shù)組的最小元素。

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

其實(shí)旋轉(zhuǎn)數(shù)組可以看成由兩個(gè)有序子數(shù)組組成的,最小元素剛好就是這兩個(gè)子數(shù)組的分界線,而對(duì)于有序來(lái)說(shuō),可以嘗試二分。分別用兩個(gè)指針指向第一個(gè)元素和最后一個(gè)元素,然后求出中間元素,若中間元素位于前面子數(shù)組(大于等于第一個(gè)指針的值),說(shuō)明最小元素應(yīng)位于中間元素后面,把第一個(gè)指針移到中間;否則位于后面子數(shù)組(小于等于第二個(gè)指針)則移動(dòng)第二個(gè)指針,當(dāng)兩個(gè)指針相鄰時(shí),第二個(gè)指針值就是答案。復(fù)雜度是O(logn)O(logn)O(logn)

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

#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;//注意旋轉(zhuǎn)0個(gè)元素時(shí),答案是第0個(gè)元素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; } //運(yùn)行結(jié)果:1

調(diào)整數(shù)字順序使奇數(shù)位于偶數(shù)前面


題目:輸入一個(gè)整數(shù)數(shù)組,實(shí)現(xiàn)一個(gè)函數(shù)來(lái)調(diào)整該數(shù)組中數(shù)組的順序,使得所有奇數(shù)位于數(shù)組前半部分,所有偶數(shù)位于數(shù)組后半部分

最笨的方法無(wú)非就是遍歷數(shù)組,每當(dāng)遇到一個(gè)偶數(shù),就把他后面的數(shù)往前挪,時(shí)間復(fù)雜度時(shí)O(n2)O(n^2)O(n2)。

我們可以定義維護(hù)指針,一個(gè)從前向后維護(hù)奇數(shù),一個(gè)從后向前維護(hù)偶數(shù),當(dāng)?shù)谝粋€(gè)指針遇到偶數(shù)時(shí),就移動(dòng)第二個(gè)指針尋找一個(gè)奇數(shù),然后交換這兩個(gè)數(shù)字,當(dāng)兩指針相遇則退出。復(fù)雜度是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)//移動(dòng)第一個(gè)指針直到偶數(shù)l++;while (l < r && a[r] % 2 == 0)//移動(dòng)第一個(gè)指針直到奇數(shù)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; } //運(yùn)行結(jié)果:1 5 3 4 2 6

數(shù)組中出現(xiàn)次數(shù)超過(guò)一半的數(shù)字


題目:數(shù)組中有一個(gè)數(shù)字出現(xiàn)的次數(shù)超過(guò)數(shù)組長(zhǎng)度的一半,請(qǐng)找出這個(gè)數(shù)字。

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

解法二:
分析發(fā)現(xiàn),數(shù)組中一個(gè)數(shù)字出現(xiàn)次數(shù)超過(guò)數(shù)組一半,也就是說(shuō)其他所有數(shù)字出現(xiàn)次數(shù)加起來(lái)也沒(méi)有它多。因此當(dāng)我們遍歷下一個(gè)數(shù)字的時(shí)候,若和上一個(gè)數(shù)字相同則次數(shù)加一;若不同則次數(shù)減一,當(dāng)次數(shù)為0的時(shí)候,需要更新保存的數(shù)字并設(shè)次數(shù)為1。復(fù)雜度是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; } //運(yùn)行結(jié)果:2

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

最小的k個(gè)數(shù)


題目:輸入n個(gè)整數(shù),找出其中最小的k個(gè)數(shù)。

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

我們可以創(chuàng)建一個(gè)大小為k的數(shù)據(jù)容器來(lái)存儲(chǔ)最小的k個(gè)數(shù)字,每次讀入一個(gè)數(shù)的時(shí)候,判斷容器中是否已有k個(gè)數(shù)據(jù),沒(méi)有的話則放入,有的話則比較容器中的最大值,若大于當(dāng)前數(shù)則替換之,保持容器中是目前最小的k個(gè)數(shù),復(fù)雜度是O(nlogk)O(nlogk)O(nlogk),適合海量數(shù)據(jù)。

#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;//可重復(fù)大根堆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; } //運(yùn)行結(jié)果:2 2 1

連續(xù)子數(shù)組的最大和


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

當(dāng)前面累加的和小于0時(shí),則拋棄前面的,從當(dāng)前數(shù)開(kāi)始累加,否則加上前面的累加和,動(dòng)態(tài)的維護(hù)一個(gè)最大值。此外也可以用動(dòng)態(tài)規(guī)劃求解,設(shè)dp[i]dp[i]dp[i]表示第iii個(gè)數(shù)字結(jié)尾的子數(shù)組的最大和,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; } //運(yùn)行結(jié)果:6

數(shù)字序列中某一位的數(shù)字


題目:數(shù)字以0123456789101112131415…的格式序列化到一個(gè)字符序列中。在這個(gè)序列中第5位(從0開(kāi)始計(jì)數(shù))是5,第13位是1,第19位是4等等。請(qǐng)寫(xiě)一個(gè)函數(shù),求任意第n位對(duì)應(yīng)的數(shù)字。

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

首先只有0-9這10個(gè)一位數(shù),然后是10-99這90個(gè)兩位數(shù),然后是100-999這900個(gè)三位數(shù),以此類(lèi)推,不難發(fā)現(xiàn),n≠1時(shí),共有9*10n-1個(gè)n位數(shù),這樣我們就能跳過(guò)若干位,直接到第n位所對(duì)應(yīng)的數(shù)字,然后再去確定是這個(gè)數(shù)字的第幾位。

#include<bits/stdc++.h> using namespace std; int digitAtIndex(int index) {if (index < 0)return -1;int n = 1;//n位數(shù)while (1) {//找到位于幾位數(shù)之間int cnt = n == 1 ? 10 : 9 * pow(10, n - 1);//n位數(shù)個(gè)數(shù)if (index < cnt * n)break;index -= n * cnt;n++;}int num = n == 1 ? 0 : pow(10, n - 1);//n位數(shù)的第一個(gè)數(shù)num += index / n;//index位于第幾個(gè)數(shù)int r = n - index % n;//這個(gè)數(shù)的第幾位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; } /*運(yùn)行結(jié)果 第1位:1 第5位:5 第13位:1 第19位:4 */

把數(shù)組排成最小的數(shù)


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

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

#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; } //運(yùn)行結(jié)果:321323

和為s的數(shù)字


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

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

比如數(shù)組{2,4,5,7,11,15}求和為16的過(guò)程:

#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; } //運(yùn)行結(jié)果:5 11

數(shù)組中數(shù)字出現(xiàn)的次數(shù)


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

我們想到異或運(yùn)算的一個(gè)性質(zhì):任何一個(gè)數(shù)字異或他自己都等于0。也就是說(shuō),如果我們從頭到尾依次異或數(shù)組中的每個(gè)數(shù)字,那么最終結(jié)果剛好是那個(gè)只出現(xiàn)一次的數(shù)字,那些出現(xiàn)兩次以上的數(shù)字全部在異或中抵消了。

可這道題目是有兩個(gè)只出現(xiàn)一次的數(shù)字。怎么拆成兩個(gè)子數(shù)組呢?我們先遍歷數(shù)組全部異或一遍,得到的結(jié)果就是那兩個(gè)數(shù)字的異或結(jié)果,由于這兩個(gè)數(shù)字不同,所以異或結(jié)果不為0,在二進(jìn)制中至少有一位為1,那么我們就可以根據(jù)這一位是不是為1,把數(shù)字劃分成兩個(gè)子數(shù)組,然后就能求解了。而且相同的數(shù)不可能分別分配到兩個(gè)子數(shù)組中,因?yàn)樗鼈兊亩M(jìn)制也是相同的。

#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;//兩個(gè)子數(shù)組分別異或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; } //運(yùn)行結(jié)果:6 5

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

總結(jié)

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

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。