五道算法题
来源:互联网 发布:五笔打字软件 编辑:程序博客网 时间:2024/05/21 07:10
雅虎:
1.对于一个整数矩阵,存在一种运算,对矩阵中任意元素加一时,需要其相邻(上下左右)某一个元素也加一,现给出一正数矩阵,判断其是否能够由一个全零矩阵经过上述运算得到。
2.一个整数数组,长度为n,将其分为m份,使各份的和相等,求m的最大值
比如{3,2,4,3,6} 可以分成{3,2,4,3,6} m=1;
{3,6}{2,4,3} m=2
{3,3}{2,4}{6} m=3 所以m的最大值为3
解:poj 1011,搜索+强剪枝
Description
思路二:
1.len>=max{a[i]} && len|sum(a[i])
2.为了避免重复搜索,令每个大S的组成中,小S的长度依次递减,这样就需要在搜索之前对a[i]排序;全部的大S的第一段小S依次递减
3.如果在某层搜索中,尝试将a[j]加入到第i个大S的组成中,如果最终a[j]没有被使用,且a[j+1]==a[j],不需要继续尝试a[j+1]
4.如果此次是在尝试第i个大S的第一段小S a[j],a[j]为当前可以被使用的最长的小S,如果此次尝试失败,直接退出搜索,即退回到对第i-1个大S的搜索。试想:失败说明现在使用a[j]是不可行的,那么什么时候使用a[j]呢?如果没有退出搜索,肯定会在之后的搜索中使用a[j],因为所有的小S必须都使用。之后的a[j]和最初尝试的a[j]有什么不同呢?没有不同,它们等价,因此之后也不会成功,不需要继续搜索。
都一致:先对这些数进行排序;
- #include <iostream>
- #include <algorithm>
- using namespace std;
- int sticks[64], n, len, num; (num为可以得到多少对)
- bool used[64];
- bool compare(int a, int b)
- {
- return a > b;
- }
- bool dfs(int cur, int left, int level)
- { //cur: 当前已经计算的木棒编号,left:该段还剩的长度,level:已经成功的木棒数
- if(left == 0) {//匹配一根木棒成功
- if(level == num-2)
- return true;
- for(cur = 0; used[cur]; cur++) //找到第一个还没被用的
- ;
- used[cur] = true;
- if(dfs(cur+1, len-sticks[cur], level+1))
- return true;
- used[cur] = false;
- return false;
- } else {
- if(cur >= n-1) //最后一根了
- return false;
- for(int i = cur; i < n; i++) {
- if(used[i])
- continue;
- if((sticks[i] == sticks[i-1]) && !used[i-1]) //
- continue;
- if(sticks[i] > left)
- continue;
- used[i] = true;
- if(dfs(i, left-sticks[i], level))
- return true;
- used[i] = false;
- //不行的话,就不会使用这个
- }
- return false;
- }
- }
- int main()
- {
- while(cin>>n) {
- if(n == 0)
- break;
- int sum = 0;
- for(int i = 0; i < n; i++) {
- scanf("%d", &sticks[i]);
- sum += sticks[i];
- }
- sort(sticks, sticks+n, compare); //由大到小排序
- bool end = false;
- for(len = sticks[0]; len <= sum/2; len++) {
- if(sum%len == 0) {
- used[0] = true;
- num = sum/len;
- if(dfs(0, len-sticks[0], 0)) {
- end = true;
- printf("%d\n", len);
- break;
- }
- used[0] = false;
- }
- }
- if(!end)
- printf("%d\n", sum);
- memset(used, 0, sizeof(used));
- }
- //system("pause");
- return 0;
- }
搜狐:
3.四对括号可以有多少种匹配排列方式?比如两对括号可以有两种:()()和(())
卡特兰数(Catalan)
例子1:Cn= n对括号正确匹配组成的字符串数,例如 3对括号能够组成:((())) ()(()) ()()() (())() (()())例子2:Cn= n+1个数相乘,所有的括号方案数。例如, 4个数相乘的括号方案为:((ab)c)d (a(bc))d (ab)(cd) a((bc)d) a(b(cd))
例子3:Cn= 拥有 n+1 个叶子节点的二叉树的数量。例如 4个叶子节点的所有二叉树形态:
分析:“卡特兰数”除了可以使用公式计算Cn=C(n,2n)-C(n-1,2n),也可以采用“分级排列法”来求解。以 n对括弧的合法匹配为例,对于一个序列 (()而言,有两个左括弧,和一个右括弧,可以看成“抵消了一对括弧,还剩下一个左括弧等待抵消”,那么说明还可以在末尾增加一个右括弧,或者一个左括弧,没有左括弧剩余的时候,不能添加右括弧。
arr = new double[n + 1];//arr代表有 k个括弧的时候,剩余 "("个数为 i的排列方案个数 arr[1] = 1;
double Catalan(int n)
{
if (n == 0) return 1;
for (int i = 2; i <= 2 * n; i++)
{
var m = i <= n ? i : 2 * n + 1 - i;
for (int j = (i - 1) & 1; j <= m; j += 2)
{
if (j > 0) arr[j - 1] += arr[j];
if (j < n) arr[j + 1] += arr[j];
arr[j] = 0;
}
}
return arr[0];
}
创新工场:
4.求一个数组的最长递减子序列 比如{9,4,3,2,5,4,3,2}的最长递减子序列为{9,5,4,3,2}
微软:
5.一个数组是由一个递减数列左移若干位形成的,比如{4,3,2,1,6,5}是由{6,5,4,3,2,1}左移两位形成的,在这种数组中查找某一个数。
我的想法:
1.
说法一:
网上有人提出两个弱判断条件如下:(原题的必要条件,非充要)
1) 将矩阵分成黑白棋盘格, 所有黑色格子的数字和等于白色格子的.
2) 对任意一个位置, 他的值不大于周围(上下左右)4个临格的数值的和.
2. poj 1011,搜索+强剪枝
3. Catalon?没验证,但是DP可以:
dp[i][j]表示从i->j位置的这些括号的最大组成种数,
dp[i][j] = dp[i-1][j-1] //i是(,j是),并且他们搭配
+ sigama(dp[i][k] * dp[k+1][j]), i与k搭配,k+1与j搭配, i<k<j枚举
初始条件:dp[i][i+1] = 1 (长度为2只能是"()"),
dp[i][i] = 0 (长度为1不能搭配)
4.DP求LCS问题的变形
肯定用动态规划来做,想了一下:前n个元素组成的子数组中的最长递减子序列和前n+1个元素组成的子数组中最长递减子序列没有太大的关系;
需要把问题转化一下,再由 大问题 转化为 小问题;
可以发现以 数组第n+1个元素为结尾的最长递减子序列和以第1,2,3,。。。n个元素为结尾的最长递减子序列长度有关系;
而此序列的最长递减子序列的长度肯定是 以数组第1,2,3,4....n为结尾的最长递减子序列中的最大值,so记录一下最大值就可以了;
首先看该问题的子问题,对于第i(i>0 i<N)个元素而言,以其结尾的递增子序列长度由前i-1个数组成的所有递增子序列长度来决定。于是该问题就分为了i-1个子问题。
maxLenIncr[i] = max{ maxLenIncr[k]+1, 1} if (a[i]>a[k] && k>=0&&k<i && i>0)
maxLenIncr[0]=1;
maxLenIncr[i] 表示以i结尾的最长递增子序列长度。
代码如下:
/*maxLenIncr[i] 表示以i结尾的最大递增子串长度*/
maxLenIncr[i] = max{ maxLenIncr[k]+1 if a[i]>a[k] } ( k>=0&&k<I && i>0);
int maxLenIncr(int* p, int len)
{
int* maxLenIncr=new int[len];
int maxLen=1;
/*Default value=1*/
for(int i=0; i<len; i++)
{
maxLenIncr[i] = 1;
}
for(int i=1; i<len; i++)
{
for(int k=0; k<i; k++)
{
if(a[i] > a[k])
{
maxLenIncr[i]=max(maxLenIncr[k]+1, 1);
if(maxLenIncr[i]>maxLen)
maxLen=maxLenIncr[i];
}
}
}
return maxLen;
}
5. 一种分情况的二分:
首先观察这个序列,先下降,然后突然上升(暂且叫断点吧),接着又下降,而且有个性质
(*)断点前面的所有数都比断点后面的所有数小!
令当前二分的区间是[l,h],那么这个区间有3中可能性:
(1)落在断点前的那个下降区间里面;
(2)落在断点后的那个下降区间里面;
(3)跨区间。
我们看怎么判断当前落在哪个区间里,另a是原来的数组
如果a[l] > a[h],由性质(*)得到不可能是跨区间的(否则因为l在断点前的区间,h在断点后的区间,那么肯定有a[l]<a[h]),那么只可能是(1)或者(2),这样这个区间就是普通的下降区间,用常规的二分在这个区间里找数。
如果a[l] < a[h], 那么肯定是跨区间的,考虑中间值a[(l+h)/2],如果这个中间值>a[l],那么根据性质(*)中间值在断点后,否则就在断点之前。如果中间值是断点之后,那么[(l+h)/2, h]形成一个下降区间,看我们找的value是不是落在这里面,如果是下一部搜索区间就是[(l+h)/2, h],不然就是[l, (l+h)/2]。如果中间值是断点之前,那么[l, (l+h)/2]形成一个下降区间,value如果落在里面,下一步搜索区间就是[l, (l+h)/2],不然就是[(l+h)/2, h]。
- 五道算法题
- 雅虎搜狐创新工场微软_五道算法题
- 算法五
- 算法五
- 算法题的五种解法
- Java经典算法题(五)
- <五大经典算法> 五、分治算法
- 五大算法---分治算法
- 五大算法:分治算法
- 排序算法五例
- 排序算法五例
- 排序算法五例
- 排序算法五例
- 排序算法五例
- 排序算法五例
- 算法学习(五)---队列
- 算法面试题五
- 算法库(五)
- 一、MySql数据库在Unix/Linux C的使用
- In和oracle绑定变量机制
- setjmp 与 longjmp
- copy_from_user探讨
- C语言学习之指针详解
- 五道算法题
- getElementsByName在IE中的怪事
- spring实例化bean的三种方式
- 关于内存对其问题(三)
- 一位国企高管对年轻人的忠告
- JavaScript中的原型和对象机制
- 一个进程在内存中的布局
- yaffs2 文件系统 内核启动时 Failed to execute /linuxrc. 问题的解决
- 一个拦截系统消息的钩子程序事例