数组的子数组长度系列问题之四

最长的可整合子数组的长度

题目

可整合数组的定义:如果一个数组在排序之后,每相邻两个数差的绝对值都为1,则该数组为可整合数组。如[5, 3, 4, 6, 2]排序之后为[2, 3, 4, 5, 6]。符合每相邻两个数差的绝对值为1.所以这个数组为可整合数组。
给定一个整型数组arr,返回其中最大可整合子数组的长度。

代码

逐个子数组排序后进行判断的话复杂度比较高,达到O(N^3logN)。可以用max-min == j - i这种方式来判断。这样可以将排序的O(NlogN)降到O(1)

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

bool isIntegrated(vector<int> arr, int left, int right)
{
	int subLen = right - left + 1;
	vector<int> newArr(subLen, 0);
	for (int i = 0; i < subLen; i++)
		newArr[i] = arr[i + left];
	sort(newArr.begin(), newArr.end());
	for (int i = 1; i < subLen; i++)
	{
		if (newArr[i - 1] != newArr[i] - 1)
			return false;
	}
	return true;
}

int getLIL1(vector<int> arr)
{
	if (arr.size() < 1)
		return 0;
	int size = arr.size();
	int len = 0;
	for (int i = 0; i < size; i++)
	{
		for (int j = i; j < size; j++)
		{
			if (isIntegrated(arr, i, j))
				len = max(len, j - i + 1);
		}
	}
	return len;
}

int getLIL2(vector<int> arr)
{
	if (arr.size() < 1)
		return 0;
	int size = arr.size();
	int len = 0;
	int Max = 0;
	int Min = 0;
	set<int> s;
	for (int i = 0; i < size; i++)
	{
		Max = INT_MIN;
		Min = INT_MAX;
		for (int j = i; j < size; j++)
		{
			if (s.find(arr[j]) != s.end())
				break;
			s.emplace(arr[j]);
			Max = max(Max, arr[j]);
			Min = min(Min, arr[j]);
			if (Max - Min == j - i)
				len = max(len, j - i + 1);
		}
		s.clear();
	}
	return len;
}

int main()
{
	int len;
	cin >> len;
	vector<int> in(len, 0);
	for (int i = 0; i < len; i++)
		cin >> in[i];
	int res1 = getLIL1(in);
	int res2 = getLIL2(in);
	cout << res1 << " " << res2 << endl;
	getchar();
	return 0;
}

未完待续…(11.30)

不重复打印排序数组中相加和为给定值的所有二元组和三元组

题目

给定排序数组arr和整数k,不重复打印arr中所有相加和为k的不降序二元组。
补充题目:给定排序数组arr和整数k,不重复打印arr中所有相加和为k的不降序三元组。

代码

左右两个指针一次寻找合适的元组打印,不重复打印的话因为是已排序数组,只需加上一个判断即可。三元组的打印与二元组比较类似,将sum变为sum-arr[i]即可,详细参考书

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

void printUniquePair(int* arr, int k, int len)
{
	if (arr == NULL || len < 2)
		return;
	int left = 0;
	int right = len - 1;
	while (left < right)
	{
		if (arr[left] + arr[right] < k)
			left++;
		else if (arr[left] + arr[right] > k)
			right--;
		else
		{
			if (left == 0 || arr[left - 1] != arr[left])
				cout << arr[left] << "," << arr[right] << endl;
			left++;
			right--;
		}
	}
}

void printRest(int* arr, int f, int l, int r, int k)
{
	while (l < r)
	{
		if (arr[l] + arr[r] < k)
			l++;
		else if (arr[l] + arr[r] > k)
			r--;
		else
		{
			if (l == f + 1 || arr[l - 1] != arr[l])
				cout << arr[f] << "," << arr[l] << "," << arr[r] << endl;
			l++;
			r--;
		}
	}
}

void printUniqueTri(int* arr, int len, int k)
{
	if (arr == NULL || len < 3)
		return;
	for (int i = 0; i < len - 2; i++)
	{
		if (i == 0 || arr[i] != arr[i - 1])
			printRest(arr, i, i + 1, len - 1, k - arr[i]);
	}
}

int main()
{
	int k, len;
	cin >> k >> len;
	int* arr = new int[len];
	for (int i = 0; i < len; i++)
		cin >> arr[i];
	printUniquePair(arr, k, len);
	printUniqueTri(arr, len, k);
	getchar();
	return 0;
}

未排序正数数组中累加和为给定值的最长子数组长度

题目

给定数组arr,该数组无序,每个值均为正数,在给定一个整数k,求arr的所有子数组中所有元素相加和为k的最长子数组长度。
如:arr=[1, 2, 1, 1, 1],k=3;累加和为3的最长子数组为【1,1,1】,所以返回结果为3.

代码

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

int getMaxLen(int* arr, int len, int k)
{
	if (arr == NULL || len == 0 || k <= 0)
		return 0;
	int left = 0;
	int right = 0;
	int sum = arr[0];
	int maxSize = 0;
	while (right < len)
	{
		if (sum == k)
		{
			maxSize = max(maxSize, right - left + 1);
			sum -= arr[left++];
		}
		else if (sum < k)
		{
			right++;
			if (right == len)
				break;
			sum += arr[right];
		}
		else
			sum -= arr[left++];
	}
	return maxSize;
}

int main()
{
	int len, k;
	cin >> len >> k;
	int* in = new int[len];
	for (int i = 0; i < len; i++)
		cin >> in[i];
	int res = getMaxLen(in, len, k);
	cout << res << endl;
	getchar();
	return 0;
}

未排序数组中累加和为给定值的最长子数组系列问题

题目

给定一个无序数组arr,其中元素可正,可负,可0.给定一个整数k,求arr所有子数组中累加和为k的最长字数组长度
补充题目1:给定无序数组arr,其中元素可正,可负,可0.求arr所有子数组中正数与负数个数相等的最长子数组长度
补充题目2:给定一个无序数组arr,其中元素只是1或0.求arr中所有子数组0和1个数相等的最长子数组长度。

代码

两个补充题目可以根据原问题的原理将正数或负数做替换,进一步得到对应解。
原问题解如下:

#include<iostream>
#include<algorithm>
#include<map>
using namespace std;

int maxLen(int* arr, int len, int k)
{
	if (arr == NULL || len == 0)
		return 0;
	map<int, int> re;
	re[0] = -1;
	int maxSize = 0;
	int sum = 0;
	for (int i = 0; i < len; i++)
	{
		sum += arr[i];
		if (re.find(sum - k) != re.end())
			maxSize = max(maxSize, i - re[sum - k]);
		if (re.find(sum) == re.end())
			re[sum] = i;
	}
	return maxSize;
}

int main()
{
	int len, k;
	cin >> len >> k;
	int* arr = new int[len];
	for (int i = 0; i < len; i++)
		cin >> arr[i];
	int res = maxLen(arr, len, k);
	cout << res << endl;
	getchar();
	return 0;
}

未排序数组中累加和小于或等于给定值的最长子数组长度

题目

给定一个无序数组arr,其中元素可正,可负,可0.给定一个整数k,求arr所有的子数组中累加和小于或等于k的最长子数组长度。
如:arr=【3,-2,-4,0,6】,k=-2;相加和小于或等于-2的最长子数组为【-3,-2,-4,0】,长度为4.

代码

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

int getLessIndex(int* arr, int num, int len)
{
	int low = 0;
	int high = len - 1;
	int mid = 0;
	int res = -1;
	while (low <= high)
	{
		mid = (low + high) / 2;
		if (arr[mid] >= num)
		{
			res = mid;
			high = mid - 1;
		}
		else
		{
			low = mid + 1;
		}
	}
	return res;
}

int maxLength(int* arr, int k, int len)
{
	int* h = new int[len + 1];
	int sum = 0;
	h[0] = sum;
	for (int i = 0; i < len; i++)
	{
		sum += arr[i];
		h[i + 1] = max(sum, h[i]);
	}
	sum = 0;
	int res = 0;
	int pre = 0;
	int maxLen = 0;
	for (int i = 0; i < len; i++)
	{
		sum += arr[i];
		pre = getLessIndex(h, sum - k, len + 1);
		maxLen = pre == -1 ? 0 : i - pre + 1;
		res = max(res, maxLen);
	}
	return res;
}

int main()
{
	int len, k;
	cin >> len >> k;
	int* arr = new int[len];
	for (int i = 0; i < len; i++)
		cin >> arr[i];
	int res = maxLength(arr, k, len);
	cout << res << endl;
	getchar();
	return 0;
}

大失误,周末比较放松,学习不能!学校网速让我望课兴叹!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值