GoogleFoobarCode邀请挑战中篇

原文地址

原文链接

前言

继续来吧,前两个等级的难度基本上是考某个数据结构知识,或者某种应用。比如优先队列自定义比较,比如双指针判圈,我们继续看下之后等级的难度

解决方案

bomb-baby

Bomb, Baby!
===========

You're so close to destroying the LAMBCHOP doomsday device you can taste it! But in order to do so, you need to deploy special self-replicating bombs designed for you by the brightest scientists on Bunny Planet. There are two types: Mach bombs (M) and Facula bombs (F). The bombs, once released into the LAMBCHOP's inner workings, will automatically deploy to all the strategic points you've identified and destroy them at the same time. 

But there's a few catches. First, the bombs self-replicate via one of two distinct processes: 
Every Mach bomb retrieves a sync unit from a Facula bomb; for every Mach bomb, a Facula bomb is created;
Every Facula bomb spontaneously creates a Mach bomb.

For example, if you had 3 Mach bombs and 2 Facula bombs, they could either produce 3 Mach bombs and 5 Facula bombs, or 5 Mach bombs and 2 Facula bombs. The replication process can be changed each cycle. 

Second, you need to ensure that you have exactly the right number of Mach and Facula bombs to destroy the LAMBCHOP device. Too few, and the device might survive. Too many, and you might overload the mass capacitors and create a singularity at the heart of the space station - not good! 

And finally, you were only able to smuggle one of each type of bomb - one Mach, one Facula - aboard the ship when you arrived, so that's all you have to start with. (Thus it may be impossible to deploy the bombs to destroy the LAMBCHOP, but that's not going to stop you from trying!) 

You need to know how many replication cycles (generations) it will take to generate the correct amount of bombs to destroy the LAMBCHOP. Write a function solution(M, F) where M and F are the number of Mach and Facula bombs needed. Return the fewest number of generations (as a string) that need to pass before you'll have the exact number of bombs necessary to destroy the LAMBCHOP, or the string "impossible" if this can't be done! M and F will be string representations of positive integers no larger than 10^50. For example, if M = "2" and F = "1", one generation would need to pass, so the solution would be "1". However, if M = "2" and F = "4", it would not be possible.

Languages
=========

To provide a Java solution, edit Solution.java
To provide a Python solution, edit solution.py

Test cases
==========
Your code should pass the following test cases.
Note that it may also be run against hidden test cases not shown here.

-- Java cases --
Input:
Solution.solution('2', '1')
Output:
    1

Input:
Solution.solution('4', '7')
Output:
    4

-- Python cases --
Input:
solution.solution('4', '7')
Output:
    4

Input:
solution.solution('2', '1')
Output:
    1

Use verify [file] to test your solution and see how it does. When you are finished editing your code, use submit [file] to submit your answer. If your solution passes the test cases, it will be removed from your home folder.

这题感觉和代码没啥太大关系,对于java来说,使用BigInteger存储+辗转相除加快迭代,虽然说算是用到了两个知识点,但是似乎更像是一种小思考,不像是严格的数据算法题,没学过算法的人也能写出伪代码,有点奇怪

class KotomiApplicationTests {
    public static String solution(String x, String y) {
        BigInteger xBig = new BigInteger(x);
        BigInteger yBig = new BigInteger(y);
        int comp = xBig.compareTo(yBig);
        BigInteger min = comp > 0 ? yBig : xBig;
        BigInteger max = comp > 0 ? xBig : yBig;
        BigInteger count = BigInteger.ZERO;
        while (!min.equals(BigInteger.ONE) || !max.equals(BigInteger.ONE)) {
            BigInteger[] divide = max.divideAndRemainder(min);
            if (BigInteger.ZERO.equals(divide[1])) {
                if (BigInteger.ONE.equals(min)) {
                    count = count.add(divide[0]).subtract(BigInteger.ONE);
                    break;
                } else {
                    return "impossible";
                }
            }
            BigInteger remainder = divide[1];
            if (remainder.compareTo(min) > 0) {
                max = remainder;
            } else {
                max = min;
                min = remainder;
            }
            count = count.add(divide[0]);
        }
        return String.valueOf(count);
    }
}

prepare-the-bunnies-escape

Prepare the Bunnies' Escape
===========================

You're awfully close to destroying the LAMBCHOP doomsday device and freeing Commander Lambda's bunny workers, but once they're free of the work duties the bunnies are going to need to escape Lambda's space station via the escape pods as quickly as possible. Unfortunately, the halls of the space station are a maze of corridors and dead ends that will be a deathtrap for the escaping bunnies. Fortunately, Commander Lambda has put you in charge of a remodeling project that will give you the opportunity to make things a little easier for the bunnies. Unfortunately (again), you can't just remove all obstacles between the bunnies and the escape pods - at most you can remove one wall per escape pod path, both to maintain structural integrity of the station and to avoid arousing Commander Lambda's suspicions. 

You have maps of parts of the space station, each starting at a work area exit and ending at the door to an escape pod. The map is represented as a matrix of 0s and 1s, where 0s are passable space and 1s are impassable walls. The door out of the station is at the top left (0,0) and the door into an escape pod is at the bottom right (w-1,h-1). 

Write a function solution(map) that generates the length of the shortest path from the station door to the escape pod, where you are allowed to remove one wall as part of your remodeling plans. The path length is the total number of nodes you pass through, counting both the entrance and exit nodes. The starting and ending positions are always passable (0). The map will always be solvable, though you may or may not need to remove a wall. The height and width of the map can be from 2 to 20. Moves can only be made in cardinal directions; no diagonal moves are allowed.

Languages
=========

To provide a Python solution, edit solution.py
To provide a Java solution, edit Solution.java

Test cases
==========
Your code should pass the following test cases.
Note that it may also be run against hidden test cases not shown here.

-- Python cases --
Input:
solution.solution([[0, 1, 1, 0], [0, 0, 0, 1], [1, 1, 0, 0], [1, 1, 1, 0]])
Output:
    7

Input:
solution.solution([[0, 0, 0, 0, 0, 0], [1, 1, 1, 1, 1, 0], [0, 0, 0, 0, 0, 0], [0, 1, 1, 1, 1, 1], [0, 1, 1, 1, 1, 1], [0, 0, 0, 0, 0, 0]])
Output:
    11

-- Java cases --
Input:
Solution.solution({{0, 1, 1, 0}, {0, 0, 0, 1}, {1, 1, 0, 0}, {1, 1, 1, 0}})
Output:
    7

Input:
Solution.solution({{0, 0, 0, 0, 0, 0}, {1, 1, 1, 1, 1, 0}, {0, 0, 0, 0, 0, 0}, {0, 1, 1, 1, 1, 1}, {0, 1, 1, 1, 1, 1}, {0, 0, 0, 0, 0, 0}})
Output:
    11

Use verify [file] to test your solution and see how it does. When you are finished editing your code, use submit [file] to submit your answer. If your solution passes the test cases, it will be removed from your home folder.

这题就算是正常的算法题了,最短路径一般是迪杰斯特拉算法,但是这个有移动门的存在,我们需要针对移动门进行路径优化。这里我一开始对移动门的处理的想法从动态规划,到对每个墙体进行深入的迪杰斯特拉,或者直接上弗洛伊德,都不是特别好的处理方案,要么逻辑复杂,要么复杂度陡增,而且这些路径优化,对于迪杰斯特拉本身的结果没有很好的利用。但是当我们跳出已经学过的算法,使用和上题一样的普通小思考的方式来处理这个问题,我们很容易就能想到,只要判断在去除墙体之后上下左右的路径加速,然后再用结果减去路径加速即可,代码如下

class KotomiApplicationTests {

    private static int tryToRemoveObstacles(int m, int n, int[][] dist,
                                            int result, int speedBoostResult) {
        for (int i = 0; i < m; ++i) {
            for (int j = 0; j < n; ++j) {
                if (dist[i][j] > 500 && dist[i][j] < 1000) {
                    int top = Integer.MAX_VALUE, right = Integer.MAX_VALUE,
                            bottom = Integer.MAX_VALUE, left = Integer.MAX_VALUE;
                    if (i > 0) {
                        top = dist[i - 1][j];
                    }
                    if (i < m - 1) {
                        bottom = dist[i + 1][j];
                    }
                    if (j > 0) {
                        left = dist[i][j - 1];
                    }
                    if (j < n - 1) {
                        right = dist[i][j + 1];
                    }
                    Set<Integer> hashSet = new HashSet<>(Arrays.asList(top, bottom, left, right));
                    hashSet.removeIf(space -> space > 500);
                    if (hashSet.size() > 1) {
                        int speedBoost = Collections.max(hashSet) - Collections.min(hashSet) - 2;
                        speedBoostResult = Math.min(speedBoostResult, result - speedBoost);
                    }
                }
            }
        }
        return speedBoostResult;
    }

    public static int solution(int[][] map) {
        int m = map.length;
        int n = map[0].length;
        //Dijkstra
        int[][] dist = new int[m][n];
        int[][] set = new int[m][n];
        //init
        for (int i = 0; i < m; i++) {
            for (int j = 0; j < n; j++) {
                if (0 == i && 0 == j) {
                    dist[i][j] = 0;
                    set[i][j] = 1;
                } else {
                    dist[i][j] = Integer.MAX_VALUE;
                    set[i][j] = 0;
                }
            }
        }
        //max length littler than 500
        dist[0][1] = map[0][1] == 1 ? 501 : 1;
        dist[1][0] = map[1][0] == 1 ? 501 : 1;
        //write dist
        for (int count = 0; count < m * n; ++count) {
            int minLength = Integer.MAX_VALUE;
            int iMin = 0, jMin = 0;
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    if (0 == set[i][j] && dist[i][j] < minLength) {
                        minLength = dist[i][j];
                        iMin = i;
                        jMin = j;
                    }
                }
            }
            set[iMin][jMin] = 1;
            for (int i = 0; i < m; ++i) {
                for (int j = 0; j < n; ++j) {
                    if (set[i][j] == 1) {
                        continue;
                    }
                    boolean curLinkIJ = (1 == Math.abs(iMin - i) && 0 == Math.abs(jMin - j)) ||
                            (0 == Math.abs(iMin - i) && 1 == Math.abs(jMin - j));
                    int curToIJDist = curLinkIJ ? (1 == map[i][j] ? 501 : 1) : Integer.MAX_VALUE;
                    if (Integer.MAX_VALUE != curToIJDist && curToIJDist + dist[iMin][jMin] < dist[i][j]) {
                        dist[i][j] = curToIJDist + dist[iMin][jMin];
                    }
                }
            }
        }

        //tryToRemoveObstacles
        int result = dist[m - 1][n - 1] + 1;
        int speedBoostResult = Integer.MAX_VALUE;
        if (result < 500) {
            speedBoostResult = tryToRemoveObstacles(m, n, dist, result, speedBoostResult);
        }

        //compare
        result = result > 500 ? result - 500 : result;
        return Math.min(result, speedBoostResult);
    }
}

真是人越是工于心计,就越容易陷入意想不到的困境,有时候我们确实跳出算法的思想来解决问题

同时这里我们给出第二种解法,有小伙伴可能要问,这种层级问题不是用广度优先搜索会更好么,确实,但是由于我这里一开始的想法就是将墙体看成长距离的方法来做,所以从带距离的最短路径来说迪杰斯特拉算法是更好的

但是如果我们抛弃将墙体看成长距离的想法,使用带记录的广度优先检索也可以,而且这种方法更容易,而且逻辑相对也更简单,处理墙体问题的时候,我们甚至可以简单粗暴一点直接对每个墙体跑一次广度优先搜索,从时间复杂度来看两种解法都是m^2*n^2

class KotomiApplicationTests {

    public static int[] getLocation(int count, int n) {
        return new int[]{count / n, count % n};
    }

    private static int bfs(int[][] map, int m, int n, AtomicBoolean noRemoveFindExit) {
        int[][] set = new int[m][n];
        set[0][0] = 1;
        Queue<Integer> queue = new ArrayDeque<>();
        queue.add(0);
        int curLength = 0;
        while (!queue.isEmpty()) {
            List<int[]> curNodeList = new ArrayList<>();
            while (!queue.isEmpty()) {
                curNodeList.add(getLocation(queue.poll(), n));
            }
            for (int[] curNode : curNodeList) {
                int x = curNode[0];
                int y = curNode[1];
                if (1 == map[x][y]) {
                    continue;
                }
                if (x == m - 1 && y == n - 1) {
                    noRemoveFindExit.set(true);
                    break;
                }
                //top
                if (x > 0 && 0 == map[x - 1][y] && 0 == set[x - 1][y]) {
                    queue.add((x - 1) * n + y);
                    set[x - 1][y] = 1;
                }
                //bottom
                if (x < m - 1 && 0 == map[x + 1][y] && 0 == set[x + 1][y]) {
                    queue.add((x + 1) * n + y);
                    set[x + 1][y] = 1;
                }
                //left
                if (y > 0 && 0 == map[x][y - 1] && 0 == set[x][y - 1]) {
                    queue.add(x * n + y - 1);
                    set[x][y - 1] = 1;
                }
                //right
                if (y < n - 1 && 0 == map[x][y + 1] && 0 == set[x][y + 1]) {
                    queue.add(x * n + y + 1);
                    set[x][y + 1] = 1;
                }
            }
            ++curLength;
            if (noRemoveFindExit.get()) {
                break;
            }
        }
        return curLength;
    }
    
    public static int solution(int[][] map) {
        int m = map.length;
        int n = map[0].length;
        int minLength = Integer.MAX_VALUE;
        //BFS
        AtomicBoolean noRemoveFindExit = new AtomicBoolean(false);
        int noRemoveCurLength = bfs(map, m, n, noRemoveFindExit);
        if (noRemoveFindExit.get()) {
            minLength = noRemoveCurLength;
        }
        //remove
        for (int count = 1; count < m * n; ++count) {
            int[] curNode = getLocation(count, n);
            int x = curNode[0];
            int y = curNode[1];
            if (0 == map[x][y]) {
                continue;
            }
            map[x][y] = 0;
            AtomicBoolean findExit = new AtomicBoolean(false);
            int curLength = bfs(map, m, n, findExit);
            if (findExit.get()) {
                minLength = Math.min(minLength, curLength);
            }
            map[x][y] = 1;
        }
        return minLength;
    }
}

如果将两种解法合并到一起,可以先对头尾进行广度优先搜索,然后遍历所有墙节点进行提速,由于这题我已经提交了,不好校验,这里就不贴代码了。如果这样处理的话,可以将时间复杂度降至mn级别

find-the-access-codes

Find the Access Codes
=====================

In order to destroy Commander Lambda's LAMBCHOP doomsday device, you'll need access to it. But the only door leading to the LAMBCHOP chamber is secured with a unique lock system whose number of passcodes changes daily. Commander Lambda gets a report every day that includes the locks' access codes, but only the Commander knows how to figure out which of several lists contains the access codes. You need to find a way to determine which list contains the access codes once you're ready to go in. 

Fortunately, now that you're Commander Lambda's personal assistant, Lambda has confided to you that all the access codes are "lucky triples" in order to make it easier to find them in the lists. A "lucky triple" is a tuple (x, y, z) where x divides y and y divides z, such as (1, 2, 4). With that information, you can figure out which list contains the number of access codes that matches the number of locks on the door when you're ready to go in (for example, if there's 5 passcodes, you'd need to find a list with 5 "lucky triple" access codes).

Write a function solution(l) that takes a list of positive integers l and counts the number of "lucky triples" of (li, lj, lk) where the list indices meet the requirement i < j < k.  The length of l is between 2 and 2000 inclusive.  The elements of l are between 1 and 999999 inclusive.  The solution fits within a signed 32-bit integer. Some of the lists are purposely generated without any access codes to throw off spies, so if no triples are found, return 0. 

For example, [1, 2, 3, 4, 5, 6] has the triples: [1, 2, 4], [1, 2, 6], [1, 3, 6], making the solution 3 total.

Languages
=========

To provide a Java solution, edit Solution.java
To provide a Python solution, edit solution.py

Test cases
==========
Your code should pass the following test cases.
Note that it may also be run against hidden test cases not shown here.

-- Java cases --
Input:
Solution.solution([1, 1, 1])
Output:
    1

Input:
Solution.solution([1, 2, 3, 4, 5, 6])
Output:
    3

-- Python cases --
Input:
solution.solution([1, 2, 3, 4, 5, 6])
Output:
    3

Input:
solution.solution([1, 1, 1])
Output:
    1

Use verify [file] to test your solution and see how it does. When you are finished editing your code, use submit [file] to submit your answer. If your solution passes the test cases, it will be removed from your home folder.

这个比较简单,动态规划就完事了,没啥东西

class KotomiApplicationTests {
    public static int solution(int[] list) {
        int length = list.length;
        if (length < 3) {
            return 0;
        }
        int codeNum = 0;
        int[] dp = new int[length];
        dp[0] = 0;
        for (int index = 1; index < length; ++index) {
            for (int child = index - 1; child >= 0; --child) {
                if (0 == list[index] % list[child]) {
                    ++dp[index];
                    if (0 != dp[child]) {
                        codeNum += dp[child];
                    }
                }
            }
        }
        return codeNum;
    }
}

第三个等级完成后,你就可能收到谷歌的面试邀请了

Level 3 complete
You are now on level 4
Challenges left to complete level: 2

Level 1: 100% [==========================================]
Level 2: 100% [==========================================]
Level 3: 100% [==========================================]
Level 4:   0% [..........................................]
Level 5:   0% [..........................................]

Type request to request a new challenge now, or come back later.

The code is strong with this one...
You can now share your solutions with a Google recruiter!
If you opt in, Google Staffing may reach out to you regarding career opportunities, events, and programs.
We will use your information in accordance with our Applicant and Candidate Privacy Policy.
[#1] [Yes [N]o [A]sk me later:]

这里他会让你填写一些个人信息,比如当前状态,姓名邮箱等基本信息,然后仓库地址,或者是简历等技术信息,之后谷歌就有可能会和你联系进行先全英文的面试

最后

我觉得第三个等级和前两个等级没有本质的上的难度差别,一定要说差别的话,可能是就第三等级会涉及到两个知识点,或者需要在已有算法的基础上转个弯。难度基本都在leetcodeMedium左右,猜测后面的等级应该在Hard即以上了,总得来说,认真学过算法的应该都能做

原文地址

原文链接

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值