自从保研后,就找个兼职做财务,闲的时候就看各种技术贴和面经,发现想进大型互联网公司,算法和数据结构就必须过关了。借用左神说的,国内好公司爱考算法和数据结构,国外互联网公司几乎只考算法和数据结构。所以我就决定好好刷算法了。
上题了:给定数组arr,返回arr的最长递增子序列。
解法一:常规的dp。
#include <stdio.h>
int main()
{
int n, max, m, k;
scanf("%d", &n);
int a[n], dp[n], b[n]; //a[i]表示序列,dp[i]表示以数组第i个数结尾时最长的递增子序列
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
dp[i] = 1; //初始化dp数组
}
for(int i = 1; i < n; i++)
{
for(int j = 0; j < i; j++)
{
if(a[i] > a[j] && dp[i] < dp[j] + 1) // O(N^2)复杂度主要在这里面的穷举
dp[i] = dp[j] + 1;
}
}
max = dp[0];
for(int i = 1; i < n; i++) //去找到dp数组里面最大的值
{
if(max < dp[i])
{
max = dp[i];
m = i; //同时记录下最大dp在数组中的下标
}
}
k = max;
printf("%d\n", max);
b[max] = a[m];
for(int i = m-1; i > 0; i--) //输出最长递增子序列,从后往前推满足此条件a[m] > a[m-1] && dp[m] = dp[i] + 1
{
if(a[m] > a[i] && dp[m] == dp[i] + 1)
{
b[--max] = a[i];
m = i;
}
}
for(int i = 1; i <= k; i++)
printf("%d ",b[i]);
return 0;
}
解法二:利用二分查找去加快穷举的速度,说白了就是以每个数结尾的最长递增子序列能放在哪
#include <stdio.h>
int binary_search(int c[], int l, int h, int key) //找到从左到右,第一个比它大的数的位置,多种思路
{
int mid;
while(l < h)
{
mid = l + (h-l)/2;
if(key <= c[mid])
l = mid + 1;
else
h = mid; //因为比它大,所以不能跳过
}
return l;
}
int main()
{
int n, max, m, k, len = 0, pos;
scanf("%d", &n);
int a[n], dp[n], b[n], h[n]; //a[i]表示序列,dp[i]表示以数组第i个数结尾时最长的递增子序列
for(int i = 0; i < n; i++)
{
scanf("%d", &a[i]);
dp[i] = 1; //初始化dp数组
}
h[len] = a[0];
for(int i = 1; i < n; i++)
{
if(a[i] > h[len])
{
h[++len] = a[i];
dp[i] = len + 1;
}
else
{
pos = binary_search(a,0,len,a[i]);
h[pos] = a[i];
dp[i] = pos + 1;
}
}
max = dp[0];
for(int i = 1; i < n; i++) //去找到dp数组里面最大的值
{
if(max < dp[i])
{
max = dp[i]; //同时记录下最大dp在数组中的下标
m = i;
}
}
k = max;
printf("%d\n", max);
b[max] = a[m];
for(int i = m-1; i > 0; i--) //输出最长递增子序列,从后往前推满足此条件a[m] > a[m-1] && dp[m] = dp[i] + 1
{
if(a[m] > a[i] && dp[m] == dp[i] + 1)
{
b[--max] = a[i];
m = i;
}
}
for(int i = 1; i <= k; i++)
printf("%d ",b[i]);
return 0;
}
对比下两者运行时间就知道了。下一题是最长公共子序列。我正在看这题,等理解透彻了,也写个博客。