首頁 > 後端開發 > php教程 > php數組的一些常見操作匯總

php數組的一些常見操作匯總

高洛峰
發布: 2023-03-01 12:30:01
原創
874 人瀏覽過

數組求和 
給定一個含有n個元素的整數數組a,求a中所有元素的和。可能您會覺得很簡單,是的,的確簡單,但是為什麼還要說呢,原因有二,第一,這題要求用遞歸法,只用一行程式碼。第二,這是我人生第一次面試時候遇到的題,意義特殊。 

簡單說一下,兩種情況: 

如果陣列元素個數為0,那麼和為0。 
如果陣列元素個數為n,那麼先求出前n - 1個元素之和,再加上a[n - 1]即可。
複製程式碼 程式碼如下: 
// 陣列求和 
int sum(int *a, int n) 

return n == 0 ? 0 : sum(a, n - 1) + a[n - 1];


求數組的最大值和最小值 
給定一個含有n個元素的整數數組a,找出其中的最大值和最小值。

常規的做法是遍歷一次,分別求出最大值和最小值,但我這裡要說的是分治法(Divide and couquer),將數組分成左右兩部分,先求出左半部份的最大值和最小值,再求右半部的最大值和最小值,然後綜合起來求總體的最大值及最小值。這是個遞歸過程,對於分割後的左右兩部分,同樣重複這個過程,直到劃分區間內只剩下一個元素或兩個元素。
複製程式碼 程式碼如下: 
// 求陣列的最大值和最小值,回傳值在maxValue和minValue 
void MaxandMin(int *a, int l, int r, int& maxValue, int& minValue) 
{ == r) // l與r之間只有一個元素 

maxValue = a[l] ; 
minValue = a[l] ; 
return ; 


if(l + 1 == r) // l與r之間只有兩個元素 

if(a[l] >= a[r]) 

maxValue = a[l] ; 
minValue = a[r] ; } maxValue = a[r] ; 
minValue = a[l] ; 

return ; 


int m = (l + r) / 2 ; // 中點 

int m = (l + r) / 2 ; // 中點 

int lmax ;份最大值 
int lmin ; // 左半部最小值 
MaxandMin(a, l, m, lmax, lmin) ; // 遞迴計算左半部 

int rmax ; // 右半部最大值
int rmin ; // 右半部份最小值 
MaxandMin(a, m + 1, r, rmax, rmin) ; // 遞迴計算右半部份 

maxValue = max(lmax, rmax) ; // 總份 

maxValue = max(lmax, rmax) ; // 總份 

maxValue = max(lmax, rmax) ; // 總份 

maxValue = max(lmax, rmax) ; // 總份的最大值 
minValue = min(lmin, rmin) ; // 總的最小值 



求數組的最大值和次大值 
給定一個含有n個元素的整數數組,求其最大值和次大值。

思想和上一題類似,同樣是用分治法,不多說了,直接看代碼: 

複製代碼 代碼如下: 
// 求數組的最大值和次大值,返回值在max和second中 
void MaxandMin(int *a, int left, int right, int &max, int &second) 

if(left == right) 

max = a[leftd];

else if(left + 1 == right) 

max = a[left] > a[right] ? a[left] : a[right] ; 
second = a[left] second = a[left] } 
else 

int mid = left + (right - left) / 2 ; 

int leftmax ;lemid,midmmint lemin ; , leftmin) ; 

int rightmax ; 
int rightmin ; 
MaxandMin(a, mid + 1, right, rightmax, rightmin) ; 

max = leftmax > rightmax left max rightmax ; 




求數組中出現次數超過一半的元素 
給定一個n個整數元素的數組a,其中一個元素出現次數超過n / 2,求這個元素。據說是百度的面試題。 

設定一個目前值和目前值的計數器,初始化目前值為數組首元素,計數器值為1,然後從第二個元素開始遍歷整個數組,對於每個被遍歷到的值a[i]。 

如果a[i]==currentValue,則計數器值加1。 
如果a[i] != currentValue, 則計數器值減1,如果計數器值小於0,則更新目前值為a[i],並將計數器值重設為1。
複製程式碼 程式碼如下: 
// 找出陣列中出現次數超過一半的元素 
int Find(int* a, int n) 

int curValue = a[0] ; 
int count = 11 ; (int i = 1; i 

另一個方法是先對數組排序,然後取中間元素即可,因為如果某個元素的個數超過一半,那麼數組排序後該元素必定佔據數組的中間位置。 

求數組中元素的最短距離 
給定一個含有n個元素的整數數組,找出數組中的兩個元素x和y使得abs(x - y)值最小。

先對數組排序,然後遍歷一次即可: 

複製代碼 代碼如下: 
int compare(const void* a, const void* b) 

return *(int*)a - *(int*)a - *(int*)a - *(int*)a - *(int*)a - *(int*)a - * b ; 


void MinimumDistance(int* a, int n) 

// Sort 
qsort(a, n, sizeof(int), comp) ; 
qsort(a, n, sizeof(int), comp) ; 
q j ; // Index of number 2 

int minDistance = numeric_limits::max() ; 
for (int k = 0; k { 
if (a[k + 1] - a[k] { 
minDistance = a[k + 1] - a[k] ; 
i = a[k] ; 
j = a[k + 1] ; 
}
cout cout } 


序數組的共同元素 
給定兩個含有n個元素的有序(非降序)整數數組a和b,求其共同元素,例如:a = 0, 1, 2, 3, 4和b = 1, 3, 5, 7, 9,輸出1, 3。

充分利用數組有序的性質,用兩個指針i和j分別指向a和b,比較a[i]和b[j],根據比較結果移動指針,則有以下三種情況: 

a [i] a[i] == b[j],則i和j皆加1,繼續比較 
a[i] 
重複上述過程直到i或j到達數組末尾。

複製程式碼 程式碼如下: 
// 找出兩個陣列的共同元素 
void FindCommon(int* a, int* b, int n) 

int i = 05%
(i { 
if (a[i] ++i ; 
else if(a[i] == b[j]) 

cout ++i ; 
++j ; 

else// a[i] > b[j] 
++j ; 

}其他的解法,例如對於a中任一個元素,在b中對其進行Binary Search,因為a中有n個元素,而在b中進行Binary Search需要logn。所以找出全部相同元素的時間複雜度是O(nlogn)。 

另外,上面的方法,只要b有序即可,a是否有序無所謂,因為我們只是在b中做Binary Search。如果a也有秩序的話,那麼再用上面的方法就有點慢了,因為如果a中某個元素在b中的位置是k的話,那麼a中下一個元素在b中的位置一定位於k的右側,所以本次的搜尋空間可以根據上次的搜尋結果縮小,而不是仍在整個b中搜尋。也即如果a和b都有序的話,程式碼可以做如下修改,記錄上次搜尋時b中元素的位置,作為下一次搜尋的起始點。 

求三個陣列的共同元素 
給定三個含有n個元素的整數陣列a,b和c,求他們最小的共同元素。 

如果三個數組都有序,那麼可以設定三個指針指向三個數組的頭部,然後根據這三個指針所指的值進行比較來移動指針,直道找到共同元素。

複製程式碼 程式碼如下: 
// 三個陣列的共同元素-只找最小的 
void FindCommonElements(int a[], int b[], int c[], int x, int y, int z) int b[], int c[], int x, int y, int z) 

for(int i = 0, j = 0, k = 0; i { 
if(a[i] { 
i++ ;

else // a[i] >= b[j] 

if(b[j] { 
j++ ; 

else //[ 
j++ ; 

else // //[jjj++ k] 

if(c[k] { 
k++ ; 

else // c[k] >= a[i] 

else // c[k] >= a[i] 

cout return ; 





cout } 

都無序,如果可以先對數組對c中任一個元素都在b和c中做二分搜尋。
複製程式碼 程式碼如下: 
// Find the unique common element in 3 arrays 
// O(NlogN) 
int UniqueCommonItem(int *a, int *b, int *c, int n) a 
qsort(a, n, sizeof(int), compare) ; // NlogN 

// sort array b 
qsort(b, n, sizeof(int), compare) ; // NlogNqsort(b, n, sizeof(int), compare) ; // NlogN element in array c, do a binary search in a and b 
// This is up to a complexity of N*2*logN 
for (int i = 0; i { 
if(BinarySearch(a, n, c[i]) && BinarySearch(b, n , c[i])) 
return c[i] ; 


return - 1 ; // not found 


也可以對a進行排序,然後對於b和c中任意一個元素都在b和a中任意一個元素都在第一個元素中排序進行二分搜尋。
複製程式碼 程式碼如下: 
// Find the unique common element in 3 arrays 
// O(NlogN) 
int UniqueCommonItem1(int *a, int *b, int *c, int nort) eone/int * a 
qsort(a, n, sizeof(int), compare) ; // NlogN 

// Space for time 
bool *bb = new bool[n] ; 
memset(bb, 0, nool) ; *bc = new bool[n] ; 
memset(bb, 0, n) ; 

// for each element in b, do a BS in a and mark all the common element 
for (int i = 0; i { 
if(BinarySearch(a, n, b[i])) 
bb[i] = true ; 


// for each element in c, do a BS only if [i] is true 
for (int i = 0; i { 
if(b[i] && BinarySearch(a, n, c[i])) 
return c[i] ; 


return - 1 ; // not found 


排序與二分搜尋程式碼如下: 
複製程式碼 程式碼如下: 
// Determine whether a contains value. int k) 

int left = 0 ; 
int right = n - 1 ; 
while (left { 
int mid = (left + right) ; 

int mid = (left + right) ; 

int mid = (left + right) ;
left = mid + 1 ; 
if(a[mid] == k) 
return true ; 
else 
right = mid - 1 ; 

的compare(const void* a, const void* b) 

return *(int*)a - *(int*)b ; 


總結一下,對於在數組中進行查找的問題,可以分成以下兩點種情況處理: 

如果給定的陣列有序,那麼首先應該想到Binary Search,所需O(logn)。
如果給定的數組無序,那麼首先應該想到對數組進行排序,很多排序演算法都能在O(nlogn)時間內對數組進行排序,然後再使用二分搜索,總的時間複雜度仍是O( nlogn)。 
如果能做到以上兩點,大多數關於陣列的查找問題,都能迎刃而解。 

找出數組中唯一的重複元素 
給定含有1001個元素的數組,其中存放了1-1000之內的整數,只有一個整數是重複的,請找出這個數。 

求出整個陣列的和,再減去1-1000的和即可,代碼略。 

找出出現奇數次的元素 
給定一個含有n個元素的整數陣列a,其中只有一個元素出現奇數次,找出這個元素。

因為對任一個數k,有k ^ k = 0,k ^ 0 = k,所以將a中所有元素進行異或,那麼個數為偶數的元素異或後都變成了0,只留下了個數為奇數的那個元素。

int FindElementWithOddCount(int *a, int n) 

int r = a[0] ; 

for (int i = 1; i 
求數組中滿足給定和的數對 序整數數組a和b,各有n個元素,求兩個數組中滿足給定和的數對,即對a中元素i和b中元素j,滿足i + j = d(d已知) 。 FixedSum(int* a, int* b, int n, int d) 

for (int i = 0, j = n - 1; i = 0) 

if (a[i] + b[j] ++i ; 
else if (a[i] + b[j] == d) 

cout ++i ; 
--j ; 

else // a[i] + b[j] > d 
--j ; 



--j ; 



--j ; 
} 一個整數數組a,求最大連續子段之和,如果和為負數,則按0計算,例如1, 2, -5, 6, 8則輸出6 + 8 = 14。經典題目,不多說了。 int i = 0; i { 
if (curSum + a[i] curSum = 0; 
else 

curSum += a[i]max curSum); 


return maxSum; 


最大子段積 
給定一個整數數足a,求最大連續子段的乘積,例如 1, 2, -8, 12, 7則輸出12 * 7 = 84。 

與最大子段和類似,注意處理負數的情況。
複製程式碼 程式碼如下: 
// 子陣列的最大乘積 
int MaxProduct(int *a, int n) 

int maxProduct = 1; // max positive product at current position negative product at current position 
int r = 1; // result, max multiplication totally 

for (int i = 0; i { 
if (a[i] > 0)5 = a[i]; 
minProduct = min(minProduct * a[i], 1); 

else if (a[i] == 0) 
{ maxProduct = 1;Pro);Pro else // a[i] { 
int temp = maxProduct; 
maxProduct = max(minProduct * a[i], 1); 
minProduct = temp * a[i]; 
} r, maxProduct); 


return r; 


數組循環移位 
將一個含有n個元素的陣列向右循環移動k位,要求時間複雜度是O(n),且只能使用兩個額外的變量,這是在微軟的程式設計之美上看到的一題。

例如數組1 2 3 4循環右移1位將變成4 1 2 3, 觀察可知1 2 3 的順序在移位前後沒有改變,只是和4的位置交換了一下,所以等同於1 2 3 4 先分割為兩部分1 2 3 | 4,然後將1 2 3逆序,再將4 逆序得到3 2 1 4,最後整體逆序得到4 1 2 3。
複製程式碼 程式碼如下: 
// 將buffer中start與end之間的元素逆序 
void Reverse( int buffer[], int start, int end ) 

while (start { 
while (start { 
buffer[ start ] ; 
buffer[ start++ ] = buffer[ end ] ; 
buffer[ end-- ] = temp ; 



// 將含有n個元素的陣列 Shibufferbufferkuffer int buffer[], int n, int k ) 

k %= n ; 

Reverse( buffer, 0, n - k - 1) ; 
Reverse( buffer, n - k, n - 1 ) ; ( buffer, 0, n - 1 ) ; 


字串逆序 
給予一個含有n個元素的字元陣列a,將其原地逆序。 

可能您覺得這不是關於陣列的,而是關於字串的。是的。但別忘了題目要求的是原地逆序,也就是不允許額外分配空間,那麼參數肯定是字元陣列形式,因為字串是不能被修改的(這裡只C/C++中的字串常數),所以,和數組有關了吧,只不過不是整數數組,而是字元數組。用兩個指針分別指向字符數組的首位,交換其對應的字符,然後兩個指針分別向數組中央移動,直到交叉。
複製程式碼 程式碼如下: 
// 字串逆序 
void Reverse(char *a, int n) 

int left = 0; 
char temp = a[left] ; 
a[left++] = a[right] ; 
a[right--] = temp ; 



組合問題一個 
給予一個含有n個元素的整數陣列,從中任取m個元素,求所有組合。例如下面的範例: 

a = 1, 2, 3, 4, 5 
m = 3 

輸出: 

1 2 3, 1 2 4, 1 2 5, 11 3 4, 1 5 
2 3 4, 2 3 5, 2 4 5 
3 4 5 

典型的排列組合問題,首選回溯法,為了簡化問題,我們將a中n個元素值分別設定為1-n。
複製程式碼 程式碼如下: 
// n選m的所有組合 
int buffer[100] ; 

void PrintArray(int *a, int n) 

for (int i = ++; i cout cout } 

bool IsValid(int lastIndex, int value) 

for++ (

if (buffer[i] >= value) 
return false; 

return true; 


void Select(int t, intŜ, m PrintArray(buffer, m); 
else 

for (int i = 1; i { 
buffer[t] = i; 
if (IsValid(t, i i))Selectt, i, i + 1, n, m); 




合併兩個陣列 
給定含有n個元素的兩個有序(非降序)整數陣列a和b。合併兩個陣列中的元素到整數陣列c,要求移除重複元素並保持c有序(非降序)。例如下: 

a = 1, 2, 4, 8 
b = 1, 3, 5, 8 
c = 1, 2, 3, 4, 5, 8 

利用合併排序的思想,兩個指針i,j和k分別指向數組a和b,然後比較兩個指針對應元素的大小,有以下三種情況: 

a[i] 
a[i] == b[j],則c[k]等於a[i]或b[j]皆可。 
a[i] > b[j],則c[k] = b[j]。 
重複上述過程,直到i或j到達數組末尾,然後將剩餘的元素直接copy到數組c中即可。
複製程式碼 程式碼如下: 
// 合併兩個有序陣列 
void Merge(int *a, int *b, int *c, int n) 

int i = 0 ; 
int = 005pint k = 0 ; 

while (i { 
if (a[i] { 
c [k++] = a[i] ; 
++i ; 

else if (a[i] == b[j])// 若a和b元素相等,則插入二者皆可,這裡插入a

c[k++] = a[i] ; 
++i ; 
++j ; 

else // a[i] > b[j] // 元素若在b中小,則插入b中元素到c 

c[k++] = b[j] ; 
++j ; 



if (i == n) // 若a遍歷完畢,處理b中剩下的元素 
if (i == n) // 若a遍歷完畢,處理b中剩下的元素 
{
for (int m = j; m c[k++] = b[m] ; 

else//j == n, 若b遍歷完畢,處理a中剩下的元素

for (int m = i; m c[k++] = a[m] ; 



重排問題 
給定含有n個元素的整數組,其中包括0元素和非0元素,對數組進行排序,要求: 

排序後所有0元素在前,所有非零元素在後,且非零元素排序前後相對位置不變。 
不能使用額外儲存空間。 
範例如下:輸入 0, 3, 0, 2, 1, 0, 0,輸出 0, 0, 0, 0, 3, 2, 1。 

此排序非傳統意義上的排序,因為它要求排序前後非0元素的相對位置不變,或許叫做整理會更恰當一些。我們可以從後向前遍歷整個數組,遇到某個位置i上的元素是非0元素時,如果a[k]為0,則將a[i]賦值給a[k],a[k]賦值為0。實際上i是非0元素的下標,而k是0元素的下標。
複製程式碼 程式碼如下: 
void Arrange(int* a, int n) 

int k = n - 1 ; 
for (int i = n - 1; i >= 0; --i)


if (a[i] != 0) 

if (a[k] == 0) 

a[k] = a[i] ; 
a[i] = 0 ; 

--k ;

} 🎜
相關標籤:
來源:php.cn
本網站聲明
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn
熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板