[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小的数

  • 1
    点赞
  • 8
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值