Codewars 打怪日记 5星级kyu 数独游戏 我是否完成了数组 Did I Finish my Sudoku? 看小菜和大神循环的巧妙运用

史蒂夫·乔布斯说过,每个人都应该学习给电脑编写程序的技术,因为这一过程能够教你如何去思考!学习编程的渠道有很多种,比如你可以利用一些互动平台或者书籍去学习编程,无论是哪种,只要找到适合自己的就OK。编程极富有创造性,你可以创造出许多新奇有趣的想法。很多时候,开发者在相同的问题上花费了大量时间,而忽略了创造性。所以很多网站都发起编程挑战赛,找到千千万的实现方法,codewars就是这样一个在线编程社区,而且有奖励系统激励程序员们像打游戏升级一样地做习题,做的题目难度大,自己段位就升高。随着段位的升高,会获得相应的特权。

  只说不练假把式,编程更重要的实践,codewars提供的题目都有实际背景,不管初学者还是小牛,都可以去codewars挑战自己。 

  进入正题,编写一个函数,输入是一个数组,判断该数组是否是完成了的数独 ,如果是 返回'Finished!'  否则返回'Try again!';   数独游戏 ,我们从小都玩过,这里的规则是 输入一个9行9列的数组,每行每列都包含1-9个数字,数字不能重复,不能有完全相同的两行或者两列,除此之外,每个区域(小9宫格也要满足这个要求)。如图是一个完成的数独。


我的思路是:先判断每一行是否包含1-9,再判断每一列是否包含 1 -9 ,如果所有行和所有列都包含1-9 ,那么肯定不会有相同的行和列(如果输入的是9*9数组)。然后再去判断 小区域 ,区域是三行三列一个循环,所以在这里,对循环的访问嵌套了四层,时间复杂度达到o(n^4)。好吧,来看看小菜的代码吧。

var isValid = function(arrR){
     arrR.sort();
     for (var n = 1 ;n<= 9; ++n) 
       {
            if (arrR[n-1] != n) 
            {
              arrR.length = 0; 
               return  0;
             }
        }
      arrR.length = 0; 
      return 1;
     
}
function doneOrNot(board){
  //your code here
var rows = board.length;
var columns = board.length ;
if (rows  != columns  ||  rows != 9 ) {return "Try again!";};
var i,j;
var arrR = [];
    ///先检查行
      for(i = 0;i < rows ; ++ i)
      {
           for (j =0;j < columns ; ++ j)     
               {
                    arrR.push(board[i][j]) ;
                }
           if ( !isValid(arrR) ) { return "Try again!";} ;
         }
    arrR.length = 0;
    //在检查列,如果行列都满足,则满足
     for(j = 0;j < columns ; ++j)
      {
           for (i =0;i< rows ; ++ i)     
               {
                    arrR.push(board[i][j]) ;
                }
           if ( !isValid(arrR) ) { return "Try again!";} ;
         }
    //判断每一块是否满足
    arrR.length = 0;
   <span style="color:#ff0000;"> for (var count = 0; count < rows ; )           
       { 
           for(var countC = 0; countC < columns ; )
                 {
                    for ( i =count ;i < count + 3;++  i)
                      {
                         for( j = countC ; j <countC + 3; ++j)
                           {
                               arrR.push(board[i][j])  ;
                               }
                       }
                    if ( !isValid(arrR) ) {  return "Try again!";} ;
                     countC += 3;
                  }
            count  += 3;
         }   
<span style="font-family: monospace; white-space: pre; background-color: rgb(240, 240, 240);">/*为了判断每一块是否满足,我可谓是煞费苦心,但是最后搞出来四层嵌套循环也是很无奈 ,思路就是最外面两层,代表行和列,每次增加3,这样这样控制访问到9个小块,*/</span></span>
<span style="color:#ff0000;"><span style="font-family: monospace; white-space: pre; background-color: rgb(240, 240, 240);">/* 然后每个小块的填充又用了两层循环,第一层三行,第二层三列,这样组成3*3的数组,然后调用isValid()判断是否有效  */</span></span>
<span style="font-family: Arial, Helvetica, sans-serif;">     return "Finished!"; </span>
}
doneOrNot()函数思路就是
判断行的时候把每一行放到数组arrR里,然后调用isValid()判断每行是否符合要求 ; 然后判断列,控制循环把每一列放到数组里,。。。  然后就是块,再把块放到数组里,判断。   isValid()的函数就是用来判断一组数组是否包含1-9并且不重复的, 但是方法很笨,首先数组排序,i从1到9循环,看下标为i-1的数组的值是否为i,如果不是则返回0,

都通过了则返回真。

function doneOrNot(rows){

  var columns = []
  ,    blocks = [];
  
  for (var i = 0; i < 9; i++) {
    columns[i] = [];
    
    for (var j = 0; j < 9; j++) {
      var k = Math.floor(i / 3) + Math.floor(j / 3) * 3;
      blocks[k] = blocks[k] || [];
      
      blocks[k].push(rows[i][j]);
      columns[i].push(rows[j][i]);
    }
  }
  
  var is_valid_row = (row) => row.slice(0).sort((a, b) => a - b).join('') == '123456789';
  
  var is_valid = rows.every(is_valid_row) 
    && columns.every(is_valid_row) 
    && blocks.every(is_valid_row);
  
  return is_valid ? 'Finished!' : 'Try again!';
}
看看高分代码吧!首先也是把 判断一个数数组是否满足要求单独写一个函数,但是他的实现方法不用循环,很简洁,还用了es6的新的箭头函数。row.slice(0)复制数组,大概是为了不污染输入数组,row.slice(0).sort((a,b) => a-b) 排序,row.slice(0).sort((a,b) => a-b) .join('') == "123456789' 排序之后分割成字符串 ,看字符串是否等于1-9。 简单的代码,用原声的js方法代替了我的循环,效率肯定比我的循环快。   

    其次,判断行,rows.every(is_valid_row)  ,代替了我的两个for循环,对于Array类来说,二维数组其实还是按照一维的访问,只是每一个元素是一个数组,所以这里every的元素就是每一行。

   判断列和判断块。块和列分别申请两个二维数组,block的每一行是一个块,columns的每一行是一列。仅仅两个for循环,搞定块和列,然后同样适用every对每一行检测。代码非常简洁,重要的是并不晦涩难懂,所以很值得学习。

  最重要的感悟就是多用js原生对象的内置方法。可以减少很多不必要的循环。


ps : 如果比对数独游戏感兴趣点击这里   和 这里   。欢迎交流。关于前端,关于codewars,关于工作和面试。

/*为了判断每一块是否满足,我可谓是煞费苦心,但是最后搞出来四层嵌套循环也是很无奈 ,
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值