文章目录
计算数组小和
题目
数组小和定义如下:
数组s=[1,3,5,2,4,6],在s[0]的左边小于等于s[0]的数的和为0,在s[1]的左边小于或等于s[1]的数的和为1,在s[2]的左边小于等于s[2]的数的和为1+3=4,以此类推,整个数组的小和为0+1+4+1+6+15=27
给定一个数组s,实现函数求解数组s的小和。
代码
简单的方法可以使用O(N2)空间复杂度求解,但使用归并排序的过程中求解可以将时间复杂度降至O(NlogN),空间复杂度为O(N)
#include<iostream>
#include<algorithm>
using namespace std;
int merge(int* &s, int left, int mid, int right)
{
int hLen = right - left + 1;
int* h = new int[hLen];
int hi = 0;
int i = left;
int j = mid + 1;
int smallSum = 0;
while (i <= mid && j <= right)
{
if (s[i] <= s[j])
{
smallSum += s[i] * (right - j + 1);
h[hi++] = s[i++];
}
else
h[hi++] = s[j++];
}
for (; (j < right + 1) || (i < mid + 1); j++, i++)
h[hi++] = i > mid ? s[j] : s[i];
for (int k = 0; k < hLen; k++)
s[left++] = h[k];
return smallSum;
}
int func(int* arr, int l, int r)
{
if (l == r)
return 0;
int mid = (l + r) / 2;
return func(arr, l, mid) + func(arr, mid + 1, r) + merge(arr, l, mid, r);
}
int getSmallSum(int* arr, int len)
{
if (arr == NULL || len < 1)
return 0;
return func(arr, 0, len - 1);
}
int main()
{
int len;
cin >> len;
int* in = new int[len];
for (int i = 0; i < len; i++)
cin >> in[i];
int smallS = getSmallSum(in, len);
cout << smallS << endl;
getchar();
return 0;
}
自然数数组的排序
题目
给定一个长度为N的整型数组arr,其中有N个互不相同的自然数1N,实现arr的排序,但是不能把下标0N-1位置上的数通过直接赋值的方式替换成1~N
要求:时间复杂度为O(N),额外空间复杂度为O(1)
代码
#include<iostream>
#include<algorithm>
using namespace std;
void print(int* arr, int len)
{
for (int i = 0; i < len; i++)
cout << arr[i] << " ";
cout << endl;
}
void nSort1(int* arr, int len)
{
int tmp = 0;
int next = 0;
for (int i = 0; i < len; i++)
{
tmp = arr[i];
while (arr[i] != i + 1)
{
next = arr[tmp - 1];
arr[tmp - 1] = tmp;
tmp = next;
}
}
print(arr, len);
}
void nSort2(int* arr, int len)
{
int tmp = 0;
for (int i = 0; i < len; i++)
{
while (arr[i] != i + 1)
{
tmp = arr[arr[i] - 1];
arr[arr[i] - 1] = arr[i];
arr[i] = tmp;
}
}
print(arr, len);
}
int main()
{
int len;
cin >> len;
int* in = new int[len];
for (int i = 0; i < len; i++)
cin >> in[i];
nSort1(in, len);
nSort2(in, len);
getchar();
return 0;
}
奇数下标都是奇数或者偶数下标都是偶数
题目
给定一个长度不小于2的数组arr,实现一个函数调整arr,要么让所有的偶数下标都是偶数,要么让所有的奇数下标都是奇数
要求:如果arr的长度为N,函数要求时间复杂度为O(N),额外空间复杂度为O(1)
代码
简单题目,可以固定数组最后一个数进行不断交换,知道奇数或偶数的下标大于或等于N
#include<iostream>
#include<algorithm>
using namespace std;
void swap(int* &arr, int index1, int index2)
{
int tmp = arr[index1];
arr[index1] = arr[index2];
arr[index2] = tmp;
}
void printNum(int* arr, int len)
{
for (int i = 0; i < len; i++)
cout << arr[i] << " ";
cout << endl;
}
void modifyEvenAndOdd(int* arr, int len)
{
if (arr == NULL || len < 2)
return;
int even = 0;
int odd = 1;
int right = len - 1;
while (even <= right && odd <= right)
{
if ((arr[right] & 1) == 0)
{
swap(arr, right, even);
even += 2;
}
else
{
swap(arr, right, odd);
odd += 2;
}
}
printNum(arr, len);
}
int main()
{
int len;
cin >> len;
int* input = new int[len];
for (int i = 0; i < len; i++)
cin >> input[i];
modifyEvenAndOdd(input, len);
getchar();
return 0;
}
子数组的最大累加和问题
题目
给定一个数组arr,返回子数组的最大累加和。
如arr=[1,-2,3,5,-2,6,-1],所有子数组中,[3,5,-2,6]可以累加出最大的和12,所以返回12.
要求:如果数组长度为N,要达到时间复杂度为O(N),额外空间复杂度为O(1)
进阶问题:求书矩阵中的子矩阵的最大累加和
代码
原问题较为简单,一个循环O(N)即可解决,进阶问题需要一次计算出子矩阵对应的数组,进一步求解累加和,时间复杂度会达到O(N^3)
#include<iostream>
#include<algorithm>
using namespace std;
int maxAccSumOfSubArr(int* arr, int len)
{
int curSum = arr[0];
int maxSum = INT_MIN;
for (int i = 1; i < len; i++)
{
if (curSum < 0)
curSum = arr[i];
else
curSum += arr[i];
maxSum = max(curSum, maxSum);
}
return maxSum;
}
/*求子矩阵的最大累加和,原理上基本与子数组的最大累加和一致*/
int maxSumOfSubMatrix(int** arr, int row, int col)
{
if (arr == NULL || row < 1 || col < 1)
return 0;
int maxS = INT_MIN;
int cur = 0;
int* s;
for (int i = 0; i < row; i++)
{
s = new int[col];
for (int i = 0; i < col; i++)
s[i] = 0;
for (int j = i; j < row; j++)
{
cur = 0;
for (int k = 0; k < col; k++)
{
s[k] += arr[j][k];
cur += s[k];
maxS = max(maxS, cur);
cur = cur < 0 ? 0 : cur;
}
}
}
return maxS;
}
int main()
{
/*int len;
cin >> len;
int* arr = new int[len];
for (int i = 0; i < len; i++)
cin >> arr[i];*/
int row, col;
cin >> row >> col;
int** in = new int* [row];
for (int i = 0; i < row; i++)
{
in[i] = new int[col];
}
for (int i = 0; i < row; i++)
{
for (int j = 0; j < col; j++)
cin >> in[i][j];
}
int res = maxSumOfSubMatrix(in, row, col);
cout << res << endl;
getchar();
return 0;
}
在数组中找到一个局部最小的位置
题目
定义局部最小的概念。arr长度为1时,arr[0]是局部最小。arr长度为N(N>1)时,如果arr[0]<arr[1],那么arr[0]是局部最小;如果arr[N-1]<arr[N-2],那么arr[N-1]是局部最小,如果0<i<N-1,既有arr[i]<arr[i-1],又有arr[i]<arr[i+1],那么arr[i]是局部最小。
给定无序数组arr,已知arr中任意两个相邻的数都不相等,实现函数返回arr中任意一个局部最小出现的位置即可
代码
可以使用二分查找的方法达到O(NlogN)的时间复杂度,空间复杂度可以达到O(1),具体分析可见书籍
#include<iostream>
#include<algorithm>
using namespace std;
int getLessIndex(int* arr, int len)
{
if (arr == NULL || len == 0)
return -1;
if (len == 1 || arr[0] < arr[1])
return 0;
if (arr[len - 1] < arr[len - 2])
return len - 1;
int left = 1;
int right = len - 2;
int mid = 0;
while (left < right)
{
mid = (left + right) / 2;
if (arr[mid] > arr[mid - 1])
right = mid - 1;
else if (arr[mid] > arr[mid + 1])
left = mid + 1;
else
return mid;
}
return left;
}
int main()
{
int len;
cin >> len;
int* input = new int[len];
for (int i = 0; i < len; i++)
cin >> input[i];
int Index = getLessIndex(input, len);
cout << Index << endl;
getchar();
return 0;
}
数组中子数组的最大累乘积
题目
给定一个double类型的数组arr,其中元素可正可负可0,返回子数组累乘的最大乘积。例如,arr=[-2.5,4,0,3,0.5,8,-1],子数组[3,0.5,8]累乘可以获得最大乘积12,返回12 即可
代码
时间复杂度可达到O(N),空间复杂度可达到O(1);以arr[i]结尾的最大累乘积有以下几种可能:
maxarr[i];max表示以arr[i-1]结尾数组的最大累乘积;
minarr[i],min表示以arr[i-1]结尾数组的最小累乘积,(min是负数,arr[i-1]也是负数)
arr[i],arr[i]为当前最大累乘积;
#include<iostream>
#include<algorithm>
using namespace std;
double maxAccM(double* arr, int len)
{
if (arr == NULL || len < 1)
return 0;
double Max = arr[0];
double Min = arr[0];
double res = arr[0];
double maxEnd = 0;
double minEnd = 0;
for (int i = 1; i < len; i++)
{
maxEnd = Max * arr[i];
minEnd = Min* arr[i];
Max = max(max(maxEnd, minEnd), arr[i]);
Min = min(min(maxEnd, minEnd), arr[i]);
res = max(res, Max);
}
return res;
}
int main()
{
int len;
cin >> len;
double* arr = new double[len];
for (int i = 0; i < len; i++)
cin >> arr[i];
double res = maxAccM(arr, len);
cout << res << endl;
getchar();
return 0;
}