免费注册 查看新帖 |

Chinaunix

  平台 论坛 博客 文库
最近访问板块 发新帖
查看: 5472 | 回复: 4
打印 上一主题 下一主题

[算法] 【每日一题】相伴一生;及构造最大数分析 [复制链接]

论坛徽章:
8
巨蟹座
日期:2013-08-12 09:41:40IT运维版块每日发帖之星
日期:2015-12-09 06:20:00寅虎
日期:2013-12-25 14:59:40天秤座
日期:2013-12-06 14:04:55酉鸡
日期:2013-11-28 10:22:22水瓶座
日期:2013-08-26 15:40:54巨蟹座
日期:2013-08-12 09:42:01每日论坛发贴之星
日期:2015-12-09 06:20:00
跳转到指定楼层
1 [收藏(0)] [报告]
发表于 2013-08-21 10:37 |只看该作者 |倒序浏览
今日面试题:相伴一生

给定一个数组,数组中只包含0和1。请找到一个最长的子序列,其中0和1的数量是相同的。
例1:10101010 结果就是其本身。
例2:1101000    结果是110100
请大家展开自己的思路。



=========================
构造最大数分析
原题

给定只包含正数的数组,给出一个方法,将数组中的数拼接起来,得到的数,是最大的。 例如: [4, 94, 9, 14, 1] 拼接之后,所得最大数为:9944141



一个巧妙的方法

我们在上面的方法中,相当于,比较两个数字的时候,把两个数字拆开,逐位进行比较。那我们接下来,就是将这两个数字,作为一个整体,进行比较。然后一次排序,就得到了结果。给定例子:5,54,56

比较5和54,实际上就是比较545和554哪个大

比较5和56,实际上就是比较556和565哪个大

比较54和56,实际上就是比较5456和5654哪个大

那我们对快排程序做一下变化,当两个数字a和b进行比较时,比较的是ab和ba两个数字的大小即可。只是比较发生了变化,剩下的和快排都是一样的。

相比较而言,后面这种方法,更简单易懂一些,而且,看上去要美很多,但是确不容易那么直接的想到。我们在平时积累的过程中,就要尝试多多的方法,即使看起来不那么美的方法,这些思路的开拓,会帮助我们举一反三,帮助我们在遇到新的题目的时候,游刃有余。

【分析完毕】

论坛徽章:
0
2 [报告]
发表于 2013-08-22 00:20 |只看该作者
我感觉这个题就是 统计 1 和 0的数目,较小的那个 *2 就是 长度了。知道长度以后,再扫描一遍 验证一下就行了。 应该可以O(n) 解决。
  1. #include <iostream>
  2. #include <vector>
  3. #include <algorithm>

  4. using namespace std;

  5. string les(const string & str) {
  6.     int c[2] = {0, 0};
  7.     for (int i = 0; i < str.size();i++)
  8.         c[str[i] - '0']++;
  9.     int length = min (c[0], c[1]) * 2;
  10.     int begin = 0, end = 0;
  11.     c[0] = 0;
  12.     c[1] = 0;
  13.     while (end < length) {
  14.         c[str[end] - '0']++;
  15.         end++;
  16.     }
  17.     while (c[0] != c[1]) {
  18.         c[str[begin++] - '0']--;
  19.         c[str[end++] - '0']++;
  20.     }
  21.     return str.substr(begin, length);
  22. }

  23. int main() {

  24.     string case1 = "10101010";
  25.     string case2 = "1101000";

  26.     cout << les(case1) << endl;
  27.     cout << les(case2) << endl;

  28.     return 0;
  29. }
复制代码

论坛徽章:
0
3 [报告]
发表于 2013-08-22 00:20 |只看该作者
本帖最后由 dextercu 于 2013-08-22 02:55 编辑

才发现我的解法是错的,因为有10001这样的情况。
我觉得正确的解法是,扫描一遍数组,记下到目前为止多出的1的数目,把结果记在一个数组里,这个结果数组中 最大的 相同数字的跨度就是最长的01字符串。
  1. #include <iostream>
  2. #include <map>
  3. #include <algorithm>
  4. #include <map>

  5. using namespace std;

  6. string les(const string & str) {
  7.     int* table = new int[str.size() + 1];
  8.     table[0] = 0;
  9.     for (int i = 0; i < str.size(); i++)
  10.         table[i + 1] = table[i] + (str[i] == '1' ? 1 : -1);
  11.     map<int, int> m;
  12.     int begin = 0, end = 0, longest = 0;
  13.     for (int i = 0; i <= str.size(); i++) {
  14.         pair<map<int,int>::iterator, bool> result = m.insert(pair<int, int>(table[i], i));
  15.         if (!result.second) {
  16.             if (i - m[table[i]] > longest) {
  17.                 longest = i - m[table[i]];
  18.                 begin = m[table[i]];
  19.                 end = i;
  20.             }
  21.         }
  22.     }
  23.     delete [] table;
  24.     return str.substr(begin, end - begin);
  25. }

  26. int main() {

  27.     string case1 = "10101010";
  28.     string case2 = "1101000";
  29.     string case3 = "0001000100010001000";

  30.     cout << les(case1) << endl;
  31.     cout << les(case2) << endl;
  32.     cout << les(case3) << endl;

  33.     return 0;
  34. }
复制代码

论坛徽章:
1
2015年亚洲杯之巴林
日期:2015-02-05 20:34:47
4 [报告]
发表于 2013-08-22 09:18 |只看该作者
我怎么觉得原题中的分析,在比较两个数大小的时候,比如列举的,5和54,5只有一位,54两位,两个数第一位相同,那么5就应该比54大,因为5后面可以接任何数字。也就是说两个数a 和 b ,如果假设b的长度(n+x)比a(n)长,前面n位都一样,那么a就应该排在b前面。
不知道这样理解对不对。

论坛徽章:
0
5 [报告]
发表于 2013-11-02 00:18 |只看该作者
回复 1# arron刘

同样是O(n),感觉还是这样好一些:设置一个变量标志sum,从头开始遍历,遇到1,则sum +=1,遇到0,则sum -= 1,如果a之后sum = 0的时候,标志着从0到i的1和0的数目相等,这样子记录最大值的下标就是要求的子串


   
您需要登录后才可以回帖 登录 | 注册

本版积分规则 发表回复

  

北京盛拓优讯信息技术有限公司. 版权所有 京ICP备16024965号-6 北京市公安局海淀分局网监中心备案编号:11010802020122 niuxiaotong@pcpop.com 17352615567
未成年举报专区
中国互联网协会会员  联系我们:huangweiwei@itpub.net
感谢所有关心和支持过ChinaUnix的朋友们 转载本站内容请注明原作者名及出处

清除 Cookies - ChinaUnix - Archiver - WAP - TOP