【兔年创意投稿】兔兔的奇妙之旅(四)一场心理与智力的博弈

1,407 阅读5分钟

我正在参加「兔了个兔」创意投稿大赛,详情请看:「兔了个兔」创意投稿大赛

注:本系列文章以虚构的兔子世界为素材,适度改编算法原题,穿插悬疑侦探。博君一笑,请勿当真。如有雷同,实属巧合~

书接上回。

此时,刚才说话的那只小兔子正在暗处兴致勃勃地看着一行三兔。它发现,虽然火烧眉毛了,但是达达和突突依然能沉着冷静地分析线索、讨论推理,它对此刮目相看。

寻根究底,顺藤摸瓜

达达的社会经验最为丰富。它从纸条入手,提出了如下几点推断:

  • “MANHATTAN”是一个地名,但也可以理解为是数学上的“曼哈顿距离”。而结合01矩阵分析,这里指的大概率是后者。

(x0, y0) 和 (x1, y1) 这两点之间的曼哈顿距离是 |x0 - x1| + |y0 - y1|

  • max应该是指最大的曼哈顿距离。 那么是什么到什么的曼哈顿距离呢?
  • 第三个线索“0”,应该就是起点,那么终点是什么呢?

突突灵光一闪,直觉告诉他有可能是指“1”。

那么很显然,在这个给定的矩阵中,结果为2

那么新的问题又来了:就算算出了这个结果,又有什么用处?它只是一个个位数字,如何和解锁密码的四位数字关联起来呢?如果有,又是什么关联呢?

预期和惊喜哪一个先到来?

而就在它们一筹莫展的时候,一只兔子从暗处冒了出来,替它们开了门。还留下了一句“答案是4598,你们回家吧!”

三只兔子面面相觑,赶忙冲了出去。临走时,突突还不小心和那只兔子撞了一下。

原来,那只给三兔出难题的兔子的妈妈看到了这一幕,告诫兔子“来者皆是客,不要太过分”,“别族不承认我们,我们更不要落下把柄、惹兔诟病”。而这只兔子本身其实也没有要为难到底的意思,门上的锁其实本就形同虚设,当时若不是被唬住,三兔暴力冲冲,估计也就弄开了;而即使解不开,它最终也会放它们走的。它只是想要博个关注,希望有兔子来搭理它而已。

劫后余生,回顾谜题

回到家安顿下来后,突突又不由得想起了密码的事情,此刻它也已经明白了密林中的兔子并没有恶意。

它找来纸笔,写下之前算出来的2、锁上的数字5314以及最终的结果4598,试图找到它们之间的关联,之后陷入了长久的沉思。

而当它下意识用手揣了揣口袋时,发现里面有东西!

旧谜已平,新题又现

它掏出来一看,原来是一张纸。上面写着解锁的规则(详见附录中的拆炸弹题目)。它赶忙进行演算,最后发现完全正确!

它欣喜若狂,奔到达达它们家分享了这个消息。而达达接过纸条后,还留意到了最下面的一行字:你想用最快速度知道【杨辉三角】第20行甚至是任意一行是什么吗?欢迎到访共同讨论!

刚刚才被戏耍的三兔组是否会赴约呢?它们又是否会真的去算算杨辉三角的第20行呢?如果真的要算,密林深处的兔子们是不是掌握了什么秘诀呢?

欲知后事如何,请听下回分解!

附录——关卡出处及解答

力扣1162地图分析

题目

你现在手里有一份大小为 n x n 的 网格 grid,上面的每个 单元格 都用 0 和 1 标记好了。其中 0 代表海洋,1 代表陆地。

请你找出一个海洋单元格,这个海洋单元格到离它最近的陆地单元格的距离是最大的,并返回该距离。如果网格上只有陆地或者海洋,请返回 -1

我们这里说的距离是「曼哈顿距离」( Manhattan Distance):(x0, y0) 和 (x1, y1) 这两个单元格之间的距离是 |x0 - x1| + |y0 - y1| 。

代码实现

class Solution {
    public int maxDistance(int[][] grid) {
        //dijkstra算法
        int n=grid.length;
        int [][] dis=new int [n][n];
        //初始化dis
        for(int i=0;i<n;i++){
            Arrays.fill(dis[i],Integer.MAX_VALUE);
        }

        //优先队列
        PriorityQueue<int []> pq=new PriorityQueue<>(new Comparator<int []>(){
            public int compare(int [] a,int [] b){
                return a[0]-b[0];
            }
        });

        //dfs上下左右坐标
        int [] dx={-1,0,1,0};
        int [] dy={0,1,0,-1};
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(grid[i][j]==1){
                    dis[i][j]=0;
                    pq.offer(new int[]{0,i,j});
                }
            }
        }

        //优先队列不为空时,出队,上下左右找,注意边界条件处理
        while(!pq.isEmpty()){
            int [] t=pq.poll();
            for(int i=0;i<4;i++){
                int x=t[1]+dx[i];
                int y=t[2]+dy[i];
                if(x<0||x>=n||y<0||y>=n) continue;
                if(t[0]+1<dis[x][y]){
                    dis[x][y]=t[0]+1;
                    pq.offer(new int[]{dis[x][y],x,y});
                }
            }
        }

        int res=-1;
        for(int i=0;i<n;i++){
            for(int j=0;j<n;j++){
                if(grid[i][j]==0){
                    res=Math.max(res,dis[i][j]);
                }
            }
        }
        return res==Integer.MAX_VALUE?-1:res;
    }
}

力扣1652拆炸弹

题目

你有一个炸弹需要拆除,时间紧迫!你的情报员会给你一个长度为 n 的 循环 数组 code 以及一个密钥 k 。

为了获得正确的密码,你需要替换掉每一个数字。所有数字会 同时 被替换。

  • 如果 k > 0 ,将第 i 个数字用 接下来 k 个数字之和替换。
  • 如果 k < 0 ,将第 i 个数字用 之前 k 个数字之和替换。
  • 如果 k == 0 ,将第 i 个数字用 0 替换。

由于 code 是循环的, code[n-1] 下一个元素是 code[0] ,且 code[0] 前一个元素是 code[n-1] 。

给你 循环 数组 code 和整数密钥 k ,请你返回解密后的结果来拆除炸弹!

代码实现

class Solution {
    public int[] decrypt(int[] code, int k) {
        int n=code.length;
        int [] res=new int [n];
        if(k==0) return res;
        if(k>0){
            for(int i=0;i<n;i++){
                for(int j=1;j<=k;j++){
                    res[i]+=code[(i+j)%n];
                }
            }
        }
        else{
            for(int i=0;i<n;i++){
                for(int j=k;j<0;j++){
                    res[i]+=code[(i+j+n)%n];
                }
            } 
        }
        return res;
    }
}