程序員面試題目總結--數組(四)【數列中符合條件數對的個數、數組是否存在重複元素、重新排列數組使數組左邊爲奇數,右邊爲偶數、數組中的第二大數、數組中的最小值和最大值】

16、找出數列中符合條件的數對的個數

題目:一個整型數組,元素取值可能爲1~N(N是一個較大的正整數)中的任意一個數,相同數值不會重複出現,找出數列中符合條件的數對的個數,滿足數對中兩數的和爲N+1

分析:先對數組進行排序,然後使用二分查找方法,用兩個指針分別指向第一個和最後一個元素,然後從兩端同時向中間遍歷,直到連個指針交叉。

(1)如果A[front]+A[back]>N+1 則back--

(2)如果A[front]+A[back]=N+1 則計數器加1,back--,同時front++

(3)如果A[front]+A[back]<N+1 則front++

void FixedSum(int a[],int n,int d)
{
	for(int i=0,j=n-1;i<n && j>=0 && i<j;)
	{
		if(a[i]+a[j] <d)
			++i;
		else if(a[i]+a[j]==d)
		{
			cout << a[i] << ' ' << a[j] <<endl;
			++i;
			--j;
		}
		else
			--j;
	}
}

引申:已知大小分別爲m,n的兩個無序數組A,B和一個常數C,求滿足A[i]+B[j]=C的所有A[i]和B[j]
方法1:排序+線性掃描法,對A和B進行排序,然後用指針P從頭掃描A,用指針q從尾掃描B,
如果A[P]+B[q]==c 則輸出A[p]和B[q],且p++,q--;如果A[P]+B[q]>c,則q--;否則p++    ( O(mlogm+nlongn) )
void Print_Pairs_With_Sum(int a[],int b[],int m,int n,int sum)
{
	sort(a,a+m);
	sort(b,b+n);
	int p=0;
	int q=n-1;
	while(p<m && q>=0)
	{
		if(a[p]+b[q] == sum)
		{
			cout << '(' << a[p] <<',' << b[q] << ')' << endl;
			p++;
			q--;
		}
		else if(a[p]+b[q] > sum)
			q--;
		else
			p++;
	}
}
方法二:Hash法,首先將兩個數組中較小的數組保存到HashTable中,然後,對於B中每個元素B[i],也採用相同的hash算法。在HashTable中查找c-B[i]是否存在,如果存在,則輸出,時間複雜度:O(m+n)
void Print_Pairs_With_Sum2(int a[],int b[],int m,int n,int sum)
{
	map<int,bool> hash_table;
	int *psmall=a;
	int *pbig=b;
	int nsmall=(m>=n) ? n :m;
	int nbig=(m>=n) ? m : n;
	if(m>n)
	{
		psmall=b;
		pbig=a;
	}
	for(int i=0;i<nsmall;i++)
	{
		hash_table.insert(pair<int,bool>(psmall[i],true));
	}
	for(int i=0;i<nbig;i++)
	{
		if(hash_table.find(sum-pbig[i])!=hash_table.end())
			cout << '(' << pbig[i] << ',' << sum-pbig[i] << ')' << endl;

	}
}


17、判定數組是否存在重複元素
題目:假設數組a有n個元素,元素取值範圍爲1~n,如何判定數組是否存在重複元素
分析:
方法一:對數組進行排序,然後比較相鄰的元素是否相同。 時間複雜度O(nlogn)
int isArrayRepeat(int a[],int n)
{
	if(a==NULL || n <=0)
		return -1;
	sort(a,a+n);
	for(int i=0;i<n-1;i++)
	{
		if(a[i] == a[i+1])
			return 1;
	}
	return 0;
}
方法二:遍歷數組,假設第i個位置的數字爲j,則通過交換將j換到下標爲j的位置,直到所有的數字都出現在自己對應的下標處,或發生了衝突。時間複雜度爲O(n)
int isArrayRepeat1(int a[], int n)
{
	int i=0;
	int j=-1;
	for(i=0;i<n;i++)
	{
		j=a[i];
		if(i==j)
			continue;
		if(a[i]==a[j])
			return 1;
		a[i]=a[j];
		a[j]=j;
	}
	return 0;
}


18、重新排列數組使得數組左邊爲奇數,右邊爲偶數
題目:給定一個整型數組,如何重新排列數組使得數組的左邊爲奇數,右邊爲偶數。 要求時間複雜度爲O(N),空間複雜度爲O(1)
分析:類似快速排序,可以用兩個指針分別指向數組的頭和尾。頭指針正向遍歷數組,找到第一個偶數,尾指針逆向遍歷數組,找到第一個奇數,交換兩個指針指向的數字,然後兩個指針繼續移動直到頭指針大於等於尾指針爲止
void AdjustArray(int a[], int n)
{
	int begin=0;
	int end=n-1;
	while(begin < end)
	{
		while(a[begin]%2 == 1 && begin < end)
			++begin;
		while(a[end]%2 == 0 && begin < end)
			--end;
		swap(a[begin],a[end]);
	}
}

19、找出數組中的第二大數
題目:找出數組中的第二大數
分析: 只通過一次遍歷求出數組中的第二大數,通過設置兩個變量來進行判斷,首先定義一個變量來存儲數組的最大數,初始值是數組首元素,另一個變量存儲第二大數,初始值爲最小負數,然後遍歷數組元素,如果數組元素比最大值變量大,則將第二大變量的值設爲最大數變量的值,最大數變量的值爲該元素,如果比最大值小,則和第二大值比較;如果大,則更新第二大數的值爲該數組元素的值
const int MINNUM = -2147483647-1;
int FinfSecMax(int a[],int n)
{
	int max=a[0];
	int sec_max=MINNUM;
	for(int i=0;i<n;i++)
	{
		if(a[i] > max)
		{
			sec_max=max;
			max=a[i];
		}
		else
		{
			if(a[i] > sec_max)
				sec_max=a[i];
		}
	}
	return sec_max;
}

注: 上式 const int MINNUM = -2147483647-1 寫成 const int MINNUM = -2147483648 會有警告
原因如下:一元負運算符應用於無符號類型,結果仍爲無符號類型。無符號類型只能保存非負值,所以一元負(非)應用於無符號類型時通常無意義。操作數和結果都是非負的。 實際上,當程序員試圖表達最小整數值-2147483648 時,發生此問題。該值不能寫爲-2147483648,因爲表達式處理分兩個步驟: 計算數字2147483648。因爲2147483648 大於最大整數值2147483647,所以其類型不是int,而是unsigned int。

20、尋找數組中的最小值和最大值
題目:尋找數組中的最小值和最大值
分析:
方法一:維持兩個變量min和max,min標記最小值,max標記最大值,每次比較相鄰兩個數,較大者與max比較,較小者與min比較,找出最大值和最小值
void FindMaxAndMin(int a[], int n, int& max, int& min)
{
	max=a[0];
	min=a[0];
	for(int i=1;i<n-1;i=i+2)
	{
		if(a[i]==a[i+1])
		{
			if(a[i]>max)
				max=a[i];
			if(a[i]<min)
				min=a[i];
		}
		else if(a[i]>a[i+1])
		{
			if(a[i]>max)
				max=a[i];
			if(a[i+1]<min)
				min=a[i+1];
		}
		else
			if(a[i+1]>max)
				max=a[i+1];
			if(a[i]<min)
				min=a[i];
	}
}
方法二:分治法:將數組劃分爲兩半,分別找出兩邊的最小值和最大值,則最大值,最小值分別是兩邊最小值的較小值、兩邊最大值的較大者 
void FindMaxAndMin1(int a[],int begin,int end,int& max,int& min)
{
	int k,max1,min1,max2,min2;
	if(end-begin == 1 || end-begin==0)
		a[begin] > a[end] ? (max=a[begin],min=a[end]) : (max=a[end],min=a[begin]);
	else
	{
		k=(begin+end)/2;
		FindMaxAndMin1(a,begin,k,max1,min1);
		FindMaxAndMin1(a,k+1,end,max2,min2);
		max=max1>max2 ? max1 : max2;
		min=min1<min2 ? min1:min2;
	}
}




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章