[C++算法] - 數組和矩陣《21道常見的題目》

千里之行,始於足下;代碼還是得自己寫,才能記憶深刻,這是一個需要累積時間的過程,不是說你在圖書館待上一週,看着書就會了的事情。也由此,在此總結數組合矩陣相關的問題,自己寫代碼實現(c++)

目錄

 

1. 快速排序

2. 歸併排序

3. 正數數組中累計和爲k的 最長子數組長度    (雙指針弄開頭)

4. 累計和爲k的 最長子數組長度    (k==arr[j+1,m]->sum[m]-sum[j])

5. 累計和<=k的 最長子數組長度    (helpArr存儲curMax,轉換爲>=sum-k的最短路徑)

6. 二分法find大於k的第一個數||find大於k的最後一個數    (上一題的基礎)

7. 奇數在奇數索引上,偶數在偶數索引上    (雙指針 odd=1;even=0;和arr[end]做就交換)

8. 奇數在前,偶數在後    (雙指針,前後各一個,各控制奇數和偶數)

9. 最長可整合子數組長度    (假設i-j滿足,for (int i=0...for (int j=i))

10. 子數組的最大累乘積    歸納法-動態規劃 (分析每個位置 i 的可能性,主要是從i-1已知了某些條件的角度出發)

11. 最大子數組

12. 最大子矩陣

13. 查找 局部最小值

14. 查找 最小的K個數【Partition or 大根堆小根堆】

15. 查找 N 個數組整體最大的 TopK【還沒有寫】

16. 查找 第K大的數

17. 查找 超過一半(N/2)的數    (構建一個map,記錄res和count)

18. 查找 超過N/K次的數    (構建一個map[num,count])k-1

19. 需要排序的最短子數組長度   (從右向左遍歷【左邊界】+從左向右遍歷【右邊界】)

20. 在兩個長度相等的排序數組中找到上中位數

21. 在兩個排序數組中找到第K小的數


1. 快速排序

主要思想:

  • 構造partition函數(返回一個pivot,左邊都是比pivot小的,右邊都是比pivot大的)
  • partition主要是弄一個small,記錄當前小於pivot的index在哪裏(small-start就是有幾個小的),如果小於pivot就和當前small位置交換(也就是不斷將小的數,放到前面)然後small++
  • qsort 調用partition,然後不斷遞歸qsort排pivot左邊和右邊。

==================================================================

需要注意:

  • 注意qsort參數(int arr[],int length,int start,int end)basecase記得加上
  • 隨機函數的 srand((unsigned)time(NULL)); rand%(end-start)+start
// Qsort.cpp : 定義控制檯應用程序的入口點。
//
#include "stdafx.h"
#include <iostream>
//#include <algorithm>
#include <time.h>
using namespace std;


int getRand(int start, int end) {
	srand((unsigned)time(NULL));//老是記不住
	return rand() % (end - start) + start;//注意是取餘數
}

int partition_my(int arr[], int length, int start, int end) {
	if (arr == nullptr || length <=0 || start < 0 || end >= length) throw new exception("invalid para");//沒有return
	int pivot = getRand(start, end);

	int small = start;
	std::swap(arr[pivot], arr[end]);
	for (int i = start; i < end; i++) {
		if (arr[i] < arr[end]) {
			if(small!=i){	
				std::swap(arr[i],arr[small]); 
			}
			small++;//交換一次,證明small確定一個,
		}
	}
	std::swap(arr[small], arr[end]);//最後small左邊都是小於arr【end】的數
	return small;
}

void qsort_my(int arr[], int length, int start, int end) {
	if (start == end) { return; }//注意basecase
	int pivot = partition_my(arr, length, start, end);
	if (pivot > start) {
		qsort_my(arr, length, start, pivot - 1);
	}
	if (pivot < end) {
		qsort_my(arr, length, pivot + 1,end);
	}
}

void qsort_m(int arr[], int length)
{
	qsort_my(arr, length, 0, length - 1);
}
int main()
{
	int arr[5] = { 5,3,1,2,4 };
	qsort_m(arr, 5);
    return 0;
}

2. 歸併排序

注意點:

  • 歸併排序,記住是先用黑盒,再解的黑盒。空間複雜度是O(N)
  • MergeSort(arr,L,mid,temp);//注意這裏是mid,不是mid-1,和qsort不一樣
  • while (i<=mid && j<=right){  //while裏兩個,沒用for,不滿足一個就退出,注意是=
/* Merge sort in C++ */
#include <cstdio>
#include <iostream>
using namespace std;
 
void MergeSort(int *arr,length){
    int *temp = new int[length];// int temp[length]
    MergeSort(arr,0,length-1,temp);
    delete[] temp ;
}
void MergeSort(int *arr,int L,int R,int *temp){
    if(L==R) return;
    mid=L+(R-L)>>2;
    if(L<R){
        MergeSort(arr,L,mid,temp);//注意這裏是mid,不是mid-1,和qsort不一樣
        MergeSort(arr,mid+1,R,temp);
        merge(arr,L,mid,R,temp);  
    }
}
void merge(int *arr,int left,int mid,int right,int *temp)
{
        int i = left;//左序列指針
        int j = mid+1;//右序列指針
        int t = 0;//臨時數組指針
        while (i<=mid && j<=right){//while裏兩個,不滿足一個就退出,注意是=
            if(arr[i]<=arr[j]){
                temp[t++] = arr[i++];
            }else {
                temp[t++] = arr[j++];
            }
        }
        while(i<=mid){//將左邊剩餘元素填充進temp中
            temp[t++] = arr[i++];
        }
        while(j<=right){//將右序列剩餘元素填充進temp中
            temp[t++] = arr[j++];
        }
        t = 0;
        //將temp中的元素全部拷貝到原數組中
        while(left <= right){
            arr[left++] = temp[t++];
        }
}

3. 正數數組中累計和爲k的 最長子數組長度    (雙指針弄開頭)

主要思想:

  • 雙指針L,R,弄到最左邊,然後看情況移動L和R,更新maxlen,和sum

int getMax(int arr[],int length,int k) {
	if (arr == nullptr || length <= 0 || k <= 0)return 0;
	int l = 0;int r = 0;
	int len = 0;int sum = 0;
	for (int i = 0; i < length - 1; i++) {
		if (sum == k) {
			len = max(len, r - l + 1);
			sum -= arr[l];
			l++;
		}
		if (sum < k) {
			if(r<length-1){
				r++;
				sum += arr[r];
			}
		}
		if (sum > k) {
			sum -= arr[l];
			l++;
		}
	}
	return len;//如果返回是0說明不存在
}

int main()
{
	int arr[5] = { 1,2,1,1,1 };
	int a = getMax(arr, 5,3);
    return 0;
}

4. 累計和爲k的 最長子數組長度    (k==arr[j+1,m]->sum[m]-sum[j])

主要思想:【可直接看代碼註釋】

  • 首先假設最終的所求數組是以m爲結尾的(這樣就是一個從左向右的遍歷的思維)arr[j+1,m]那麼sum怎麼球呢?
  • k?=arr[j+1,m]=sum[m]-sum[j],sum從0開始,m是遍歷用的,求最長的j+1,m,其實就是求滿足sum-k時最短的j,如下圖

==================================================================

  1. 討論的是以i爲結尾的滿足條件的最長子串(for (int i = 0; i < length; i++) )
  2. 如果 sum-k 存在,說明以i結尾有累積和 k
  3. 另外一個如果sum不存在在map中,加入map[sum]=i;

==================================================================

注意點:

  • 因爲數組是從0開始index的,比如0-2是最長,那麼返回長度3,所以首先需要將map.put(0,-1)進去

int getMax(int arr[], int length ,int k) {
	if (arr == nullptr || length < 0)return 0;
	map<int,int> temp;
	temp[0] = -1;
	int sum = 0;
	int len = 0;
	for (int i = 0; i < length; i++) {
		//sum-k是否存在
		sum += arr[i];
		map<int,int>::iterator find = temp.find(sum - k);
		if (find != temp.end()) {//如果sum - k存在!
			len=max(len,i- (find->second));//注意!!->second沒有();!
		}
		//注意這裏不能寫else
		if(temp.find(sum)==temp.end())//如果sum不存在!!
		{
			temp[sum] = i;//別寫反了
		}
	}
	return len;
}
int main() {
	int arr[6] = { 1,2,1,1,-1,2 };
	int a = getMax(arr, 5, 3);
	return 0;
}

5. 累計和<=k的 最長子數組長度    (helpArr存儲curMax,轉換爲>=sum-k的最短路徑

主要思想:

  1. 求出curSum
  2. <=k的 最長子數組長度那就是求>=curSum-k的最短路徑,所以需要一個輔助數組helpArr存儲目前爲止的最大值
  3. 然後在helpArr中找>=curSum-k的第一個(二分查找即可)

==================================================================

注意點:

helpArr最開頭都要加0,表示什麼也不加的情況。因爲helpArr多一個length長度,不用-1.

int getLessIndex(int* arr, int i, int k)
{// 求數組arr[0...i]內》k的第一個數字 a
// 注意返回值,就是arr中的第幾個 第一次滿足了》=k,
// 比如返回0,表示什麼都不加,返回1,表示第一個也是就是arr[0],滿足這個條件
	if (arr == nullptr || length < 0 )//注意length是有可能=1的
		return -1;
	int res = - 1, left = 0, right = i;
	while (left <= right)
	{
		int mid = left + (right - left) / 2;
		if (arr[mid] >= k)
		{
			res = mid;//值得注意的是不斷二分,最終卡住的就是第一個
			right = mid - 1;
		}
		else
			left = mid + 1;
	}
	return res;
}

int getMax(int arr[], int length ,int k) {
	if (arr == nullptr || length < 0)return 0;
	int res = 0;
	int *helparr = new int[length+1];
	helparr[0] = 0;//存儲此前最大值
	int sum=0;//存儲0-i的和
	for (int i = 0; i <= length; i++) {
		sum += arr[i];
		helparr[i + 1] = max(sum, helparr[i]);
	}
	sum = 0;
	int len = 0;
	int j = -1;
//注意:遍歷原數組arr的長度,求的是arr每個位置》sum-k的第一個數字
	for (int i = 0; i < length; i++) {
		sum += arr[i];//當前的sum 
		j = getLessIndex(helparr,i,sum-k);//求數組helparr[0...i]內》sum - k的第一個數字 
		if (j != -1)res = max(res, i - j + 1);
	}
	
	return res;
}
int main() {
	int arr[5] = { 1,2,-1,5,-2};
	int a = getMax(arr, 5, 3);
	return 0;
}
int getMax(int arr[], int length ,int k) {
	if (arr == nullptr || length < 0)return 0;
	int res = 0;
	int *helparr = new int[length+1];
	helparr[0] = 0;//存儲此前最大值
	int sum=0;//存儲0-i的和
	for (int i = 0; i <= length; i++) {
		sum += arr[i];
		helparr[i + 1] = max(sum, helparr[i]);
	}
	sum = 0;
	int len = 0;
	int j = 0;
	for (int i = 0; i <= length; i++) {
		sum += arr[i];//當前的sum 
		j = getLessIndex(helparr, i, sum - k);
		if (j != -1)res = max(res, i - j + 1);
	}
	delete[]helparr;
	return res;
}
int main() {
	int arr[5] = { 1,2,-1,5,-2};
	int a = getMax(arr, 5, 3);
	return 0;
}

6. 二分法find大於k的第一個數||find大於k的最後一個數    (上一題的基礎)

while (left <= right)//這裏的等於號很重要,只有這裏等於才能找到第一個,凡是有可能是最後只剩 一個數的情況,都是需要加=

比如0123你找大於=3的第一個數,只有有=才能包括某個數

int getLessIndex(int* arr, int length, int k)
{// 二分法find大於k的第一個數
	if (arr == nullptr || length <= 0 || arr[length - 1] <= k)
		return -1;
	int res = length - 1,left=0,right=length-1;
	while (left <= right)//這裏的等於號很重要,只有這裏等於才能找到第一個
	{
		int mid = left + (right - left) / 2;
		if (arr[mid] > k)
		{
		res = mid;//值得注意的是不斷二分,最終卡住的就是第一個
		right = mid - 1;
		}
		else
			left = mid + 1;
	}
	return res;
}

​
​int getLastIndex(int* arr, int length, int k)
{//二分法find大於k的最後一個數
	if (arr == nullptr || length <= 0 || arr[length - 1] <= k)
		return -1;
	int res = length - 1,left=0,right=length-1;
	while (left <= right)//這裏的等於號很重要,只有這裏等於才能找到第一個
	{
		int mid = left + (right - left) / 2;
		if (arr[mid] < k)
		{
            res=mid;
            left= mid + 1;
		}
		else
			right = mid - 1;
	}
	return res;
}

​

 

7. 奇數在奇數索引上,偶數在偶數索引上    (雙指針 odd=1;even=0;和arr[end]就交換

主要思路:

  1. while ((odd<=end)&&(even<=end))
  2. odd=1;even=0;和arr[end]就交換,如果是偶數,和arr[even]交換,然後even++

8. 奇數在前,偶數在後    (雙指針,前後各一個,各控制奇數和偶數)

主要思路:

  1. while(前指針<後指針)
  2. 前面的指針,while到偶數停下,後面的指針,while到奇數停下,然後交換

注意事項:

上面第2步中,while到偶數停下,需要while(begin<end && arr[begin]&1!=0) begin++; 

==================================================================

還可以用STL中的partition

bool IsOdd (int i) { return (i%2)==1; }//奇數優先,在左
 
int main () {
  std::vector<int> myvector;

  // set some values:
  for (int i=1; i<10; ++i) myvector.push_back(i); // 1 2 3 4 5 6 7 8 9
 
  std::vector<int>::iterator bound;//返回的bound是第一個偶數的地址
  bound = std::stable_partition (myvector.begin(), myvector.end(), IsOdd);//奇數在左

}

9. 最長可整合子數組長度    (假設i-j滿足,for (int i=0...for (int j=i))

題目:可整合:排序後相鄰數字差必須是1

輸入:5 5 3 4 6 2 3

解釋 :  2 3 4 5 6

返回長度: 5

==================================================================

主要思路:

這種題目,暴力解,窮舉也就是

for (int i = 0; i < length; i++) {

        ...<這裏纔是主要初始化的地方>
        for (int j = i; j < length; j++) {

==================================================================

主要改進是在:在不重複的數組裏面,如果最大值-最小值=size-1;就說明滿足條件,更新此時的res。

                          如果有重複的,直接break結束此次循環(終止條件放在正式賦值前頭

#include <algorithm>
#include <set>
using namespace std;

int getMax(int arr[], int length) {
	if (arr == nullptr || length < 0)return -1;
	int res = 0;
	set<int> temp;//去重用的,如果重複了直接GG重新構造
	//需要記錄i-j內的最大值和最小值
	for (int i = 0; i < length; i++) {
		int max = INT_MIN;//加入include <algorithm>纔有
		int min = INT_MAX;
		temp.clear();//每次都需要重新構建
		for (int j = i; j < length; j++) {
			if (temp.count(arr[j])) { break; }//如果重複了直接GG重新構造
			temp.insert(arr[j]);
			max = std::max(max, arr[j]);////加入include <algorithm>纔有
			min = std::min(min, arr[j]);
			if ((max - min) == j - i) {//注意是j-i,別寫反了
				res = std::max(res, j - i + 1);
			}
		}
	}
	return res;
}
int main() {
	int arr[7] = { 5,5,3,4,6,2,3};
	int a = getMax(arr, 7);
	return 0;
}

10. 子數組的最大累乘積    歸納法-動態規劃 (分析每個位置 i 的可能性,主要是從i-1已知了某些條件的角度出發)

有正有負的數組。

動態規劃 分析每個位置 i 的可能性,主要是從 i-1 已知了某些條件的角度出發。大的可分爲和i-1有關係和沒關係,小的還可細分。i處的可能:

1. 和上一步有關係

  • 上一步的max*arr[i]  i-1已知了max
  • 上一步的min*arr[i]   i-1已知了min

2. 和上一步沒關係 arr[i] 比如0.1 -1 100

看到需要已知min才行,所以還得分析min,min也是上面的三種可能。

凡是向上面這種需要 先已知 i-1 的某些條件的情況,我們初始化的時候就需要 先把初始化弄成是第一個的時候。其實就是歸納法

int getMax(int arr[], int length) {// 歸納法
	if (arr == nullptr || length < 0)return -1;
	int res = arr[0];
	int min = arr[0];// 先初始化一個min和max,下面p1 p2就可以直接先用,後期再更新,INT_MAX錯了;
	int max = arr[0];  //          INT_MIN;
	int p1 = INT_MIN;//第一種情況
	int p2 = INT_MIN;//第二種情況
	for (int i = 1; i < length; i++) {
		//先用着min和max
		p1 = max*arr[i];
		p2 = min*arr[i];

		max = std::max(std::max(p1, p2), arr[i]);
		min = std::min(std::min(p1, p2), arr[i]);
		res = std::max(res, max);
	}
	return res;
}
int main() {
	int arr[7] = { -2,4,0,3,1,8,-1};
	int a = getMax(arr, 7);
	return 0;
}

 

11. 最大子數組

O(N)弄一個當前和,if (cursum <= 0) cursum = arr[i]; else cursum += arr[i];

// 當前和<0,就重置
// 假設是i到j,最粗暴的,還可以用動態歸納法
int getMax(int arr[], int length) {
	if (arr == nullptr || length < 0)return -1;
	int res = INT_MIN;
	int cursum = INT_MIN;
	for (int i = 0; i < length; i++) {
		if (cursum <= 0)cursum = arr[i];
		else cursum += arr[i];
		res = std::max(res, cursum);
	}
	return res;
}
int main() {
	int arr[7] = { -2,4,0,3,1,8,-1};
	int a = getMax(arr, 7);
	return 0;
}
//動態規劃
int getMax(int arr[], int length) {
	if (arr == nullptr || length < 0)return -1;
	int res = arr[0];
	int last = arr[0];
	int cur = 0;

	for (int i = 1; i < length; i++) {
		if (last <= 0)cur = arr[i];//相當於f(n)=arr[i];
		else cur += arr[i];//f(n)+=arr[i];
		last = cur;//更新上一個f(n-1)
		res = std::max(res, cur);
	}
	return res;
}
int main() {
	int arr[7] = { -2,4,0,3,1,8,-1};
	int a = getMax(arr, 7);
	return 0;
}

12. 最大子矩陣

假設最終是 i-j行滿足,然後壓扁這i-j行[空間複雜度O(N),時間複雜度O(N 3)],變成子數組的問題

int n;
int a[110][110];
int b[110];

int main()
{
	while (scanf("%d", &n) != EOF)
	{
		for (int i = 0; i<n; i++)
			for (int j = 0; j<n; j++)
				scanf("%d", &a[i][j]);

		int Max = INT_MAX;
		for (int i = 0; i<n; i++)
		{//以i行開始算起,找j行
			memset(b, 0, sizeof(b));//每次輔助的數據都需要重新初始化,表示i變了
			for (int j = i; j<n; j++)
			{
				//下面是針對數組b求最大子段和的動態規劃算法
				int cursum = 0;
				for (int k = 0; k<n; k++)
				{
					b[k] += a[j][k];//至此化成了一維度的問題
					cursum += b[k];//
					if (cursum<0) cursum = b[k];
					if (cursum>Max) Max = cursum;
				}
			}
		}
		printf("%d\n", Max);
	}

	return 0;
}

13. 查找 局部最小值

14. 查找 最小的K個數【Partition or 大根堆小根堆】

主要思想:

  1. Partition(O(N))
  • int topK(int arr[], int length,int start, int end, int k)  //相對於普通的排序,多了一個參數k,也正常
  • 每次從start-end中隨機取出pivot進行Partition,然比較此處pivot和k的關係
  • int NumSmall = pivot-start+1 // 記錄 <=arr[pivot]的個數
  • if(NumSmall ==k)  //說明相等,直接返回此刻Partition後的arr的arr[start - pivot]閉區間
  • if(NumSmall >k) // 說明<=arr[pivot]的個數 大於100個,將end換成pivot-1,遞歸topK
  • if(NumSmall <k) // 說明<=arr[pivot]的個數 小於100個,將start換成pivot+1,而此刻的k也更新K-NumSmall,遞歸topK

     2.利用大根堆或者小根堆(O(N*logK)適用於海量數據)

首先,這裏存在一個背景知識,構建大根堆或者小根堆,此題應用小根堆。

=============================================================

構建大根堆,有兩種方式。基於STL

  • 1.利用函數和vector定義私有成員變量 ,
vector<int> max;
  • 利用push_heap pop_heap的方式結合vector.pop_back()的方法。每次改變vec之後,都進行
//大根堆
max.push_back(num);
push_heap(max.begin(), max.end(), less<T>());
pop_heap(max.begin(), max.end(), less<T>());##堆頂和最後的互換
max.pop_back();##彈出最後一個      上兩個結合heapify
  • 2.利用set或者multiset<允許重複>和比較器cmp進行構建。
typedef  multiset<int,greater<int>> intSet;#直接定義個大根堆

typedef multiset<int,greater<int>>::iterator intSetIter;

intSet& leastNumbers

如果 leastNumbers < k 直接插入,如果大於k,如果大於k,看當前加入的數*iter,

如果小於堆頂的數,刪除 erase 堆頂 leastNumbers.begin(),插入該數。

    vector<int>::const_iterator iter = data.begin();
    for(; iter != data.end(); ++ iter)
    {
        if((leastNumbers.size()) < k)
            leastNumbers.insert(*iter);
        else
        {
            setIterator iterGreatest = leastNumbers.begin();
            if(*iter < *(leastNumbers.begin()))
            {
                leastNumbers.erase(iterGreatest);
                leastNumbers.insert(*iter);
            }
        }
    }

=============================================================

回到正題:

// Partition的方法
int getrand(int start, int end) {
	srand((unsigned)time(NULL));
	return (start + (rand() % (end - start)));

}

int partition(int arr[], int length,int start, int end)
{
	int pivot = getrand(0, length - 1);
	int small = 0;//比pivot處小的索引
	std::swap(arr[pivot], arr[end]);
	for (int i = 0; i < length - 1; i++) {
		if (arr[i] < arr[pivot]) {
			if (small != i)std::swap(arr[small], arr[i]);
			small++;
		}
	}
	std::swap(arr[small], arr[end]);//最後small左邊都是小於arr【end】的數
	return small;
}

int topK(int A[], int length,int low, int high, int k)
{
	if (k <= 0)
		return -1;
	if (low == high)
		return low;
	//隨機返回一個
	int pos = partition(A, length, low, high);
	int i = pos - low + 1;// 看看前面有多少個數
	if (i == k)
		return pos;  // 返回前k個數的,此刻的0-pos就是前k的小的數
	else if (i > k)//如果大於100,把high變pos
		return topK(A, length, low, pos, k);
	else
		return topK(A, length, pos + 1, high, k - i);// 注意這裏的k-i
}
//第二種方法,就是遍歷一次arr,然後就出來了

15. 查找 N 個數組整體最大的 TopK【還沒有寫】

 

16. 查找 第K大的數

其實和14是一樣的,partition

 

17. 查找 超過一半(N/2)的數    (構建一個map,記錄res和count)

主要思路:

  1. 超過一半的數必定是排序好的中位數,可以利用partition找中位數(不寫了)
  2. 每次刪除兩個不同的數字,最後剩下的數就是那個超過一半的數。
  • 刪除兩個不同的數字,構建一個map,記錄res和count,或者像我下面代碼寫的,分開記錄,遍歷,如果和arr中的數一樣就count++,不一樣就--(刪除兩個不同的數字,體現在這裏,沒有對此處的值做反應+count-- 相當於減去兩個不一樣的值)
bool isExist = true;//避免歧義
int get(int arr[], int length) {
	if(arr==nullptr||length<0) isExist = false;
	int res = arr[0];
	int times = 1;
	for (int i = 1; i < length; i++) {
		if (arr[i] == res)times++;
		else if (times == 0) { //如果times已經爲0了。,更換res
			res = arr[i]; 
			times = 1; 
		}
		else times--;
	}
	if (isExist)return res;
}
int main()
{
	int arr[6] = { 1,2,3,2,2,2 };
	int res = get(arr, 6);
    return 0;
}

18. 查找 超過N/K次的數    (構建一個map[num,count])k-1

上一題的上級版本,每次刪除不同的K個數,最後落下的就是。k-1個key

注意遍歷的時候用到erase需要小心,執行語句裏直接break

//所有的key都減去一,如果count=1,直接刪除掉這個key即可
void alljianone(map<int, int>&input) {
	map<int, int>::iterator temp;
	for (temp= input.begin(); temp != input.end();)
	{
		if (input[temp->first] != 1){
			input[temp->first]--;
			temp++;//
		}
		else{
			input.erase(temp->first);
			break;//用到erase了遍歷需要小心,直接break
		    
		}
	}
}

// 表示記錄下超過N/k[最多k-1個,所以空間複雜度是O(k)],以map<num,counts>的形式
map<int,int> get(int arr[], int length,int k) {
	//
	map<int, int> res;
	for (int i = 0; i < length; i++) {
		if (res.count(arr[i]) != 0)//如果存在這個num
			res[arr[i]]++;//count++
		else {
//如果不存在,看下key是否已經k-1個了,如果是,那麼每個count--;如果不是弄進來,count=1
			if (res.size() != k - 1)
				res[arr[i]] = 1;
			else {
				alljianone(res);//每個count--
			}
		}
	}
	return res;
}


int main()
{
	int arr[6] = { 3,2,3,3,2,2 };
	map<int,int> res = get(arr, 6,3);
    return 0;
}

 

19. 需要排序的最短子數組長度   (從右向左遍歷【左邊界】+從左向右遍歷【右邊界】)

主要思路:

主體是找兩邊邊界的問題。

  1. 從右向左遍歷,一遍遍歷,一遍更新min_value,然後記錄比min_value大的最左的位置;
  2. 從左向右遍歷,一遍遍歷,一遍更新max_value,然後記錄比max_value小的最右的位置;
  3. 左右邊界就都可以得到了。

20. 在兩個長度相等的排序數組中找到上中位數

21. 在兩個排序數組中找到第K小的數

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