求数组中最长递增子序列
编程之美2.16
注意,所谓的递增子序列不一定是连续的
只要满足递增性即可。
方法:动态规划思想。
用dp[i]表示到i为止,最长的递增序列长度。(可能包含i,也可能不包含i)
那么dp[i+1]就是判断A[i+1]能否加上,即
dp[i+1]=max(dp[0~i]+A[0~i]
int calculong(int *A, int n)
{
int *dp = new int[n];
dp[0] = 1;
for (int i = 1;i < n;i++)
{
int tmp = INT_MIN;
for (int j = 0;j < i;j++)
{
if (A[i] > A[j] && tmp < dp[j] + 1)
tmp = dp[j] + 1;
else if (tmp<dp[j])
tmp = dp[j];
}
dp[i] = max(1, tmp);
}
int res = INT_MIN;
for (int i = 0;i < n;i++)
if (res < dp[i])
res = dp[i];
return res;
}
数组分割
对于一个无序数组,长度2n,如何把这个数组分割为两个长度为n的数组,使其和最接近。
先解决这样一个问题:
//1. 有一个无序、元素个数为2n的正整数数组,要求:如何能把这个数组分割为两个子数组,子数组的元素个数不限,并使两个子数组之和最接近。
#define MAXN 101
#define MAXSUM 1000
void ArrayDivision(int *A, int n)
{
bool dp[MAXN][MAXSUM];// dp[k][s]表示从前k个数中取任意个数的数,且这些数之和为s的取法是否存在
memset(dp, 0, sizeof(dp));
dp[0][0] = true;
int i, sum=0;
for (i = 0; i <= 2 * n-1; i++)
sum += A[i];
cout << sum << endl;
// 外阶段k1表示第k1个数
for (int k1 = 1;k1 <= 2 * n;k1++)
for (int s = 1;s <= sum / 2;s++)
{
// 有两个决策包含或不包含元素k1
if (dp[k1 - 1][s])
dp[k1][s] = true;
if (s >= A[k1-1] && dp[k1 - 1][s - A[k1-1]])
dp[k1][s] = true;
}
for (int s = sum / 2;s >= 1;s--)
{
if (dp[2 * n][s])
{
cout << s << endl;
break;
}
}
}
再回到原问题:
//2. 有一个无序、元素个数为2n的正整数数组,要求:如何能把这个数组分割为元素个数为n的两个数组,并使两个子数组之和最接近。
void ArrayDivision2(int *A, int n)
{
bool dp[MAXN][MAXSUM];// dp[k][s]表示是否可以找到k个数,其和为s
memset(dp, 0, sizeof(dp));
dp[0][0] = true;
int i, sum = 0;
for (i = 0; i <= 2 * n - 1; i++)
sum += A[i];
cout << sum << endl;
// 外阶段k1表示第k1个数
for (int k1 = 1;k1 <= 2 * n;k1++)
for (int k2 = min(k1, n);k2 >= 1;k2--)
for (int s = 1;s <= sum / 2;s++)
{
if (s >= A[k1 - 1] && dp[k2 - 1][s - A[k1 - 1]])//因为每次更新k1,我们就要判断新增加的A[k1]是否会影响前面的dp[0~k2][s]的值,所以只需更新加上A[k1]后影响的值就行了。
dp[k2][s] = true;
}
for (int s = sum / 2;s >= 1;s--)
{
if (dp[n][s])
{
cout << s << endl;
break;
}
}
}
第二种不太好想,看注释!
注意两个dp[k][s]表示的意思是不一样的。
数组循环移位
对数组循环向右移动k位
求解思路:
逆序前n-k个
逆序后k个
然后对整个逆序
区间重合判断
类似于阿里的一个面试题。
就是给你一个target线段,判断它是否被已给出的一些线段所包含。
思路:
先排序,然后遍历排序好的线段,对target的x进行更新判断。画图比划一下即可。
struct line
{
int x;
int y;
};
void swap(line &x, line &y)
{
line temp=x;
x = y;
y = temp;
}
void QuickSort(line *A,int left, int right)
{
if (left < right)
{
int lo = left, hi = right;
line key = A[lo];
while (lo < hi)
{
while (lo<hi&&A[hi].x >= key.x) hi--;
swap(A[lo], A[hi]);
while (lo < hi&&A[lo].x <= key.x) lo++;
swap(A[lo], A[hi]);
}
QuickSort(A, left, lo-1);
QuickSort(A, lo+1, right);
}
}
bool IsExist(line*A, int n,line target)
{
QuickSort(A,0,n-1);
for (int i = 0;i < n;i++)
{
if (target.x >= target.y)
return true;
if (A[i].y < target.x)
{
continue;
}
else
{
if (A[i].x > target.x)
continue;
else
target.x= A[i].y;
}
}
return false;
}