博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
对一道编程题的后续思考
阅读量:6580 次
发布时间:2019-06-24

本文共 3122 字,大约阅读时间需要 10 分钟。

  原题来自

  题目描述:给定一个整数 X,找到组成的数字和 X 完全相同的,且大于 X 的最小的那个数;若不存在这样的数,输出 0

  一开始把它想复杂了,后来想想只需将该数组成的数列从后往前枚举,然后判断当前位置往后的数列是否是降序即可,时间复杂度O(n),详细思路跟上文一致可以参考原文。

var a = 21544221; // 要求的数字var s = a.toString();var len = s.length;for(var i = len - 2; i >= 0; i--) {  if(s[i] >= s[i + 1]) continue;  for(var j = len - 1; j > i; j--) {    if(s[j] > s[i]) {      var index = j;      break;    }  }  break;}var arr = s.split('');if(i !== -1) {  arr[i] = [arr[index], arr[index] = arr[i]][0];  var ans = arr.slice(0, i + 1).concat(arr.slice(i + 1).reverse()).join('');}console.log(+ans);

  之后我陷入了思考:如果不是要求比原数大的最小的数,而是第k大的呢

  为了不至于复杂度太高以致cpu假死,我把所求数暂定在int32范围内,写了个计算第k大数的暴力程序用来验证,复杂度O(n!)

function dfs(a, index) {  if(index === len) {    if(hash_ans[a] || a < num)       return;    ans.push(a);    hash_ans[a] = true;    return;  }  for(var i = 0; i < len; i++) {    if(hash_pos[i]) continue;    hash_pos[i] = true;    dfs(~~a * 10 + ~~arr[i], index + 1);    hash_pos[i] = false;  }}var num = 131443134; // 要求的数字var k = 818; // 比num大的第k大数var arr = num.toString().split('');var len = num.toString().length;var ans = []; // 存放比num大的数var hash_pos = {};var hash_ans = {};dfs(0, 0);ans.sort();ans.length <= k ? console.log(0) : console.log(ans[k]);

  然后开始思索第k大解,发现后向扫描仍然可解,但是复杂度应该不低,在没有想到其他解法前先一试。后向扫描的依据是所组成的新的数从前往后跟原来的数比较,在经过一系列相等的比较后,肯定会出现一个大于原数的相同位置。于是我们根据此枚举该位置,枚举到的位置的数用位置后面的比它大的数代替(以保证新的数比原数大),确定该位置的数之后,后面的位置进行全排列即是确定该位置后的所有解(注意全排列后需除相同数字的全排列),同时我们需要维护一个变量保存当前枚举位置后的总的解个数,如果个数还没达到k,则继续在该位置枚举更大的数,或者枚举位置继续前移;当发现总个数大于k时,该位置就确定是这个数了,接着进行第二轮枚举,枚举过程相似。在枚举的过程中反复地出现某个临界点(大于小于k),而出现临界点的同时该位置的数确定。

var A = [];A[0] = 1;for(var i = 1; i <= 10; i++)  A[i] = A[i - 1] * i;var a = 131443134;var k = 818;var total = 0;var arr = a.toString().split(''); // 字符串数组var len = arr.length;var hash = [];  // 记录后向扫描中0~9的数量for(var i = 0; i <= 9; i++)  hash[i] = 0;hash[a % 10] = 1;var maxn = a % 10;  // 维护后向扫描中最大的数字for(var i = len - 2; i >= 0; i--) {  hash[~~arr[i]]++;  if(maxn > ~~arr[i]) { // 可以交换    for(var j = ~~arr[i] + 1; j <= 9; j++) {  // 该位置可以换的数字      if(!hash[j]) continue;      var add = A[len - i - 1];  // 全排列      for(var l = 0; l <= 9; l++) {        l === j ? add /= A[hash[l] - 1] : add /= A[hash[l]]; // 除去相同数字的全排列      }            if(total + add >= k) {  // 就是这个交换        hash[j]--;        // 第i位变成了j         var ans = a.toString().substring(0, i) + j + getAns(i);      } else {        total += add;      }      if(ans) break;    }  }  maxn = Math.max(maxn, ~~arr[i]);  if(ans) break;}function getAns(a) { // 第a位变成了b  var res = '';  for(var i = a + 1; i < len; i++) {    for(var j = 0; j <= 9; j++) { // 从小到大枚举i位置的数字      if(!hash[j]) continue;      var add = A[len - i - 1];  // 全排列      for(var l = 0; l <= 9; l++)         l === j ? add /= A[hash[l] - 1] : add /= A[hash[l]]; // 除去相同数字的全排列      if(total + add >= k) {  // 就是这个交换        hash[j]--;        res += j;        break;  // i位置确定是j      } else {        total += add;      }    }  }  return res;}ans ? console.log(ans) : console.log(0);

  解是有了,好像没涉及什么算法,倒是觉得像个复杂的模拟,看了下时间复杂度,最坏情况下应该会达到O(n*10*10),似乎效率还可以,但是我一开始想到这个问题的时候,似乎觉得会是一道动态规划,或者是按位dp?无奈对于算法了解不多,只能日后接触了再进行思考,也希望有更高效解法的博友留言交流

转载地址:http://jsnno.baihongyu.com/

你可能感兴趣的文章
我的友情链接
查看>>
Office365 之分配、回收License工具
查看>>
38线程1-Thread-local-Timer
查看>>
为Exchange server 2013 申请多域名证书
查看>>
处理svn的 File '/aa' is out of date
查看>>
解决 Ubuntu 16.04 LTSSublime text3中文问题
查看>>
mysql主从复制实现数据库同步
查看>>
日期类
查看>>
面试-1
查看>>
CentOS自动登录Gnome
查看>>
第一章,重点总结
查看>>
nmon 安装
查看>>
LeetCode - 49. Group Anagrams
查看>>
移动前端不得不了解的html5 head 头标签
查看>>
Tomcat 服务器性能优化
查看>>
【框架学习】ibatis DAO框架分析
查看>>
浏览器的DOM操作
查看>>
ZOJ 3640 Help Me Escape
查看>>
Eclipse开发工具介绍
查看>>
putty与emacs
查看>>