Google-HK-2012-interview-"pizza"(1)

来源:互联网 发布:非法网络彩票赌博 编辑:程序博客网 时间:2024/06/06 21:04
今晚万圣节,和汉堡“孤男寡男”吃完泰餐,从Downtown回来,看到I-80高速都堵了。果然是落单的人最怕过节,尤其是秋雨过后,冷冷的空气平添几分对单身狗的敌意。
汉堡吐了吐烟圈说:提起女神就闹心,女神都不理我。
我说为什么不换个别的。他说,喜欢,没办法。
他问我,你就没有喜欢得非她不可的么。
我说没有。也许曾经有。

早上和Parker大神讨论了一个新的idea,大概是想要做类似OJ的网站,Parker说太难,而且test case的validate工作量十分大,建议我找到工作之后有空去写这样的web。然后他提到他在面HK Google的一道题目,叫我解。我没有想出来,最后照着他得思路我做了一下。


=====================================================

#1 题目是这样的:(好吧,描述是我自己脑补的,毕竟万圣节一个人写代码,呵呵)

万圣节,你一个人在寝室写代码,突然饿了,冰箱没有吃的东西了,于是你订了一份pizza。开门的时候看到送外卖的小哥cosplay成Fin the Human(好吧,我承认我喜欢Adventure time),他看到我一脸寂寞就知道是程序员,说,小费少收一点。好吧,你赢了。

我准备吃pizza了,这时候两个寂寞的损友也过来我家了,说要蹭饭。好,现在问题来了:

pizza被切成了3 * n片,每一片pizza有大有小,假设大小用pizza[i]表示。每次我选择一片pizza[i]吃,两个损友就会吃pizza[i-1]和pizza[i+1],注意这是环,自动脑补。

那么我怎么可以保证我所吃到的pizza总和最大呢?


=====================================================

于是我想写个程序来解决这个问题。

孤独的我继续写代码,听着好久没有听过的豆瓣FM,不知道为什么douban的随机开始又符合自己口味了,开始尝试新花样了。估计machine learning又用了新的算法,或者库更加完善了。

"why did the blues go on singing."

原来邓紫棋唱的《后会无期》的主题曲是翻唱1997年的Julie London唱的<The end of the world>。

扯远了,实在太悲伤。赶紧回来。

=====================================================

#2 算法:

考虑这个ring,Greedy算法行不通,比方说{1, 1, 1, 9, 10, 9}。
考虑使用dp,当时Parker说使用一个3n-bit的flag去表明吃pizza的状态,那么这个dp的复杂度是O(2^n)。所以要选择更好的dp的状态。

好,我们换个思路。假设我们已知:dp[i][j]表示从第i块pizza到第j块pizza之间,自己能得到的最大值。注意,这里pizza(i)和pizza(j)不允许连成一个ring,只能是line。
那么之前的pizza问题就可以转换为线性问题:假设最后取的3块pizza分别是x, y, z。那么这3块pizza所分割成为的line就是之前dp[i][j]所表示的问题。

自己可以吃的pizza的最大值就是(假设x < y < z):
max{x, y, z} + dp[x+1][y-1] + dp[y+1][z-1] + dp[z+1][x-1+n]
最后这里从z+1回到x-1有个突变点,在处理数据的时候只要copy一份pizza的数据到原始的pizza的末端就可以了
只要枚举所有的x,y,z组合情况(O(n^3)复杂度),计算好dp,然后取n^3情况中的最大值就可以了。

于是问题变成如何求解dp[i][j]。其中必须满足(j - i + 1) % 3 == 0。否则无法取到最后3块pizza(每次吃的时候都是连续3块pizza被吃掉的)。

计算dp[i][j]的时候,有两种情况:
#1 pizza[i]和pizza[j]是在最后一次被其他两个朋友同时吃掉的。只需要枚举自己吃的最后一块k。
dp[i][j] = k + dp[i+1][k-1] + dp[k+1][j-1]。要求[(k-1)-(i+1)+1]%3==0,剩下另外一边当然也是3得倍数(因为i,j有限制)。
#2 pizza[i]和pizza[j]分别在两次被其他两个朋友吃掉的。那么枚举分割点k。
dp[i][j] = dp[i][k] + dp[k+1][j]。要求(k-i+1)%3==0


=====================================================

#3 数据结构:

dp[i][j]就足够了。

=====================================================

#4 代码:

大神们请轻拍,因为实在苦于没有test case,只能瞎猜了。。。

这里的代码是有误的,请看(2),我自己写了一些test case并且修改了一下代码。

public class Solution {// solve the problempublic static int maxPizzaValue(int[] pizza) {int n = pizza.length;int maxPizza = 0;// copy pizza to pizzaint[] bigPizza = new int[2*n];System.arraycopy(pizza, 0, bigPizza, 0, n);System.arraycopy(pizza, 0, bigPizza, n, n);int[][] dp = calDP(n, bigPizza);for (int x = 0; x < n-2; x++) {for (int y = x+1; y < n-1; y++) {for (int z = y+1; z < n; z++) {// check the valid divisionif ((y - x - 1) % 3 == 0 && (z - y - 1) % 3 == 0) {int val = max(x, y, z) + dp[x+1][y-1] + dp[y+1][z-1] + dp[z+1][x-1+n];if (val > maxPizza) maxPizza = val;}}}}return maxPizza;}// calculate dp elements// dp[i][j] means max value from index i to jpublic static int[][] calDP (int n, int[] A) {int[][] dp = new int[2*n][2*n]; // initfor (int i = 0; i < 2*n; i++) {for (int j = 0; j < 2*n; j++) {dp[i][j] = 0;}}// base casefor (int i = 0; i <= 2*n-3; i++) {dp[i][i+2] = max(A[i], A[i+1], A[i+2]); // base case}int len = 6;while (len <= n) {for (int i = 0; i <= 2*n-len; i++) {int j = i+len-1;// must take the i, j at the same roundfor (int k = i+1; k < j; k += 3) {int val = A[k];val += k-1 < i+1 ? 0 : dp[i+1][k-1];val += j-1 < k+1 ? 0 : dp[k+1][j-1];dp[i][j] = dp[i][j] > val ? dp[i][j] : val;}// take the i, j at different roundfor (int k = i; k <= j; k++) {if ((k - i + 1) % 3 == 0) {int val = dp[i][k] + dp[k+1][j];dp[i][j] = dp[i][j] > val ? dp[i][j] : val;}}}len += 3;}return dp;}// return the max of the 3public static int max(int x, int y, int z) {int max = x > y ? x : y;max = max > z ? max : z;return max;}}











0 0
原创粉丝点击