您的位置:首页 > 其它

求数组中最长递增子序列,数组分割,数组循环移位,区间重合判断

2017-03-31 22:45 190 查看

求数组中最长递增子序列

编程之美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
;
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
[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;

}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐