您的位置:首页 > 其它

几道经典的递归(可以用动态规划优化)好题源码实现(2)

2017-11-10 12:04 260 查看
我们可以先写出递归,然后用数组或者map等存储之前出现过的状态(空间换时间,动态规划),达到时间上的优化目的。(假如是递归中的分治的这种情况,则不需要再优化为动态规划,因为分治的话中间不存在冗余,没有重复的中间状态,分治(例如二分查找,归并排序,快速排序等)的复杂度也很低)(教科书上基本都是直接用数组来实现,而不是先递归后优化的思想,本人觉得先递归后优化的思想比较容易想出来题目。两种方法本质一样,难的题目都是比较难以想出递归式子,想出来递归式子以后两种方法你哪种熟练就用哪种)(补充:还有很多动态规划高级技巧,滚动数组,四边形不等式等,这些高阶技巧很多很有用,适合喜欢钻研,竞赛的同学)
以下都是用本文思想写的代码来解决问题:

1.《剑指offer》里面一题目:最大连续子数组(用本文思想解决)
#include <iostream>
#include <vector>

#include <string>

using namespace std;

int max2(int a, int b)

{
if (a >= b) return a;
return b;

}

const int MAXint = 100;

int res[MAXint];

void init()

{
for (int i = 0; i < MAXint; i++)
res[i] = -1;

}

int n;//MAX: n 可以设置一个大一点的量。

int aa[1];

//int c[1][2];

int search(int i)

{
if (i==0)
return aa[0];
if (res[i] != -1) return res[i];

res[i] = max2(aa[i], search(i - 1) + aa[i]);
return res[i];

}

int main()

{
init();
cin>>n; //n=8

// aa = {1,-2,3,10,-4,7,2,-5}; 最终结果:18
for (int i = 0; i < n; i++)
{
cin >> aa[i];
}

int mymax = 0;
for (int i = 0; i <n; i++)
{
mymax = max2(mymax, search(i));
}
cout << "result:"<<mymax << endl;
system("pause");
return 0;

}

2.《剑指offer》里面一题目:最长重复子串(用本文思想解决)
#include <iostream>

#include <vector>

#include <string>

using namespace std;

int max2(int a, int b)

{
if (a >= b) return a;
return b;

}

const int MAXint = 100;

int res[MAXint];

void init()

{
for (int i = 0; i < MAXint; i++)
res[i] = -1;

}

int n=9;

string v="arabcacfr";

int search(int i)

{
if (i == 0)
{
res[0] = 1;
return 1;
}
if (res[i] != -1) return res[i];

int index=-1;
for (int j = 0; j < i; j++)
{
if (v[j] == v[i])
index = j;
}
if (index == -1 || (i - index) > search(i - 1))
{
res[i] = search(i - 1) + 1;
return res[i];
}
else
if ((i - index) <= search(i - 1))
{
res[i] = (i - index);
return (i - index);
}

}

int main()

{
init();
int mymax = 0;
for (int i = 0; i <n; i++)
{
mymax = max2(mymax, search(i));
//cout << search(i) << endl;
}
cout << "result:"<<mymax << endl;
system("pause");
return 0;

}

(3.4可以见链接中实现了常规只用数组的方式,没有通过递归再优化思想,而以下代码我是通过递归再优化思想实现的)

3.


括号匹配之添加最少括号匹配(具体题目描述见http://blog.csdn.net/u010056403/article/details/23378221)

#include <iostream>
#include <vector>
#include <string>
using namespace std;

////递归式子

////a[i][j + 1] = min(a[i][j] + 1, a[i][k - 1] + a[k + 1][j]) k属于i~j

int min2(int a, int b)

{
if (a <= b) return a;
return b;

}

string str;

const int n=10;//MAX: n 可以设置一个大一点的量。

int aa

;

void init()

{
for (unsigned int i = 0; i < n; i++)
{
for (unsigned int j = 0; j < n; j++)
{
aa[i][j] = -1;
}
}

}//

int search(int i, int j)

{
if (i>j)
return 0;
//if (i ==j && i>=0) 
// return 1;

if (aa[i][j] != -1)
return aa[i][j];

if (str[j] == '(')
{
aa[i][j] = 1 + search(i, j - 1);
return 1 + search(i, j - 1);
}
else
{
int a = search(i, j - 1) + 1;
int resMIN = a;
//vector
for (int hh = i; hh <=j - 1; hh++)//在属于i,j-1找K,K处的'('与j处的')'相匹配
{
if (str[hh] == '(')
{
if (hh == i)
{
int aa = search(hh + 1, j - 1);
resMIN = min2(resMIN, aa);
}
else
if (hh>i && hh<j-1)
{
int bb = search(i, hh - 1) + search(hh + 1, j - 1);
resMIN = min2(resMIN, bb);
}
else
if (hh == (j-1))
{
int cc = search(i, hh - 1);
resMIN = min2(resMIN, cc);
}
}

}
aa[i][j] = resMIN;
return resMIN;
}

}

int main()

{

init();
//str = "((()))((";
//str = "(()))()("; 
str = "(()))";
int myN = str.size() - 1;
cout << search(0, myN);
return 0;

}

4.给定待排序数组A,在最多反转K个A的不相交子数组后,对A采用冒泡排序,问最小的swap次数是多少?(具体分析可见:http://www.cnblogs.com/python27/p/3842114.html)

#include <iostream>
#include <vector>
#include <string>
using namespace std;

int min2(int a, int b)

{
if (a <= b) return a;
return b;

}

const int MAXn = 12;//MAXn: 可以设置一个大一点的量。

int aa[MAXn][MAXn];

void init()

{
for (unsigned int i = 0; i < MAXn; i++)
{
for (unsigned int j = 0; j < MAXn; j++)
{
aa[i][j] = -1;
}
}

}//

int h[9] = { 3,2,8,1,9,6,4,5,7};

vector<int> initA(h, h + 9);

int contribution(vector<int> A, int x)

{
int n = A.size();
int cnt = 0;
for (int i = x; i < n; ++i)
{
for (int j = 0; j < i; ++j)
{
if (A[j] > A[i])
{
cnt++;
}
}
}
return cnt;

}

int search(int x, int k)//定义子问题 search(x, k) 表示在最多reverse k个不重叠子数组后,由所有大于x的下标j贡献的逆序对数

{
if (x == initA.size())
return 0;

if (aa[x][k] != -1)
return aa[x][k];

vector<int> B1(initA.begin(), initA.begin() + x + 1);
int resMIN = contribution(B1,x) + search(x + 1, k);

for (int y = x+1; y <=initA.size()-1;y++)// x+1  =<y<= initA.size()-1
{
vector<int> B2(initA.begin(), initA.begin() + y + 1);
reverse(B2.begin() + x, B2.begin() + y + 1);
int tempRES = contribution(B2, x) + search(y + 1, k - 1);
resMIN = min2(resMIN, tempRES);
}
aa[x][k] = resMIN;
return resMIN;

}

int main()

{

init();
int K = 3;
cout << search(0, K);
system("pause");
return 0;

}

5.归并排序
#include <iostream>

#include <string>

#include <vector>

using namespace std;

int n = 5;

int a[5] = {3,2,1,5,5};

void merge(int left,int mid,int right)

{
int i = left; int iright = mid;
int j = mid + 1; int jright = right;
vector<int> temp;

while ((i != iright + 1) && (j != jright + 1))
{
if (a[i] <= a[j])
{
temp.push_back(a[i]);
i++;
}
else 
{
temp.push_back(a[j]);
j++;
}
}
if (i == iright + 1)
for (int jj = j; jj != jright + 1; jj++)
{
temp.push_back(a[jj]);
}

if (j == jright + 1)
for (int ii = i; ii != iright + 1; ii++)
{
temp.push_back(a[ii]);
}

//
int idx = 0;
for (int hh = left; hh <= right; hh++)
{
a[hh] = temp[idx];
idx++;
}

}

void MYmergeSort(int left, int right)

{
if (left>=right)
return;
int mid = (left + right) / 2;
MYmergeSort(left, mid);
MYmergeSort(mid + 1, right);
merge(left,mid,right);

}

int main()

{
MYmergeSort(0, n - 1);
//输出排序后的结果 
for (int i = 0; i <n; i++)
printf("%d ", a[i]);
system("pause");
return 0;

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