1. 程式人生 > >【京東】2016研發工程師(第一題沒做出來,動態規劃類似公共子串重點,反覆看;第三題沒有做出來自我檢討)

【京東】2016研發工程師(第一題沒做出來,動態規劃類似公共子串重點,反覆看;第三題沒有做出來自我檢討)

[程式設計題]年終獎

小東所在公司要發年終獎,而小東恰好獲得了最高福利,他要在公司年會上參與一個抽獎遊戲,遊戲在一個6*6的棋盤上進行,上面放著36個價值不等的禮物,每個小的棋盤上面放置著一個禮物,他需要從左上角開始遊戲,每次只能向下或者向右移動一步,到達右下角停止,一路上的格子裡的禮物小東都能拿到,請設計一個演算法使小東拿到價值最高的禮物。

給定一個6*6的矩陣board,其中每個元素為對應格子的禮物價值,左上角為[0,0],請返回能獲得的最大價值,保證每個禮物價值大於100小於1000。

這道題類似與公共子串那道題,一開始我以為是回溯法,就參考了滴滴小青蛙的題,結果通過率3.33%

錯誤解法如下:

import java.util.*;
public class Bonus {
    static int max = Integer.MIN_VALUE;
    public int getMost(int[][] board) {
        // write code here
        generate(board, 0, 0, board[0][0]);
        return max;
    }
    private  void generate(int[][] map, int x, int y, int salary) {
        if (x == map.length - 1 && y == map.length - 1) {
            if (salary > max) {
                max = salary;
                return;
            }
        }
        // 走過得用0標記
        int temp = map[x][y];// 記錄儀xy裡面的錢數
        map[x][y] = 0;
        // 右
        if (x < map.length - 1 && map[x + 1][y] != 0) {
            generate(map, x + 1, y, salary + map[x + 1][y]);
        }
        // 下
        if (y < map.length - 1 && map[x][y + 1] != 0) {
            generate(map, x, y + 1, salary + map[x][y + 1]);
        }
        // 還原回去
        map[x][y] = temp;
    }
}

正確思路:

連結:https://www.nowcoder.com/questionTerminal/72a99e28381a407991f2c96d8cb238ab
來源:牛客網
 

平面上有N*M個格子,每個格子中放著一定數量的蘋果。你從左上角的格子開始, 每一步只能向下走或是向右走,每次走到一個格子上就把格子裡的蘋果收集起來, 這樣下去,你最多能收集到多少個蘋果。

解這個問題與解其它的DP問題幾乎沒有什麼兩樣。第一步找到問題的“狀態”, 第二步找到“狀態轉移方程”,然後基本上問題就解決了。

首先,我們要找到這 個問題中的“狀態”是什麼?我們必須注意到的一點是, 到達一個格子的方式最多隻有兩種:從左邊來的(除了第一列)和從上邊來的(除了第一行)。 因此為了求出到達當前格子後最多能收集到多少個蘋果, 我們就要先去考察那些能到達當前這個格子的格子,到達它們最多能收集到多少個蘋果。 (是不是有點繞,但這句話的本質其實是DP的關鍵:欲求問題的解,先要去求子問題的解)

經過上面的分析,很容易可以得出問題的狀態和狀態轉移方程。 狀態S[i][j]表示我們走到(i, j)這個格子時,最多能收集到多少個蘋果。那麼, 狀態轉移方程如下:

S[i][j]=A[i][j] + max(S[i-1][j], if i>0 ; S[i][j-1], if j>0)

其中i代表行,j代表列,下標均從0開始;A[i][j]代表格子(i, j)處的蘋果數量。

S[i][j]有兩種計算方式:1.對於每一行,從左向右計算,然後從上到下逐行處理;2. 對於每一列,從上到下計算,然後從左向右逐列處理。 這樣做的目的是為了在計算S[i][j]時,S[i-1][j]和S[i][j-1]都已經計算出來了。


參考網上的。

正確的程式碼:

import java.util.*;

public class Bonus {
    public int getMost(int[][] board) {
        int n=board.length;
		int [][]dp=new int[n][n];
        dp[0][0] = board[0][0];
		//第一列,只能是從上面走下來的
		for(int i=1;i<n;i++){
			dp[i][0]=dp[i-1][0]+board[i][0];
		}
		//第一行,只能是從左邊走過來的
		for(int i=1;i<n;i++){
			dp[0][i]=dp[0][i-1]+board[0][i];
		}
		//其他行,既可能從上面來也可能從左邊來
		for(int i=1;i<n;i++){
			for(int j=1;j<n;j++){
				dp[i][j]=board[i][j]+Math.max(dp[i-1][j], dp[i][j-1]);
			}
		}
		return dp[n-1][n-1];
    }
}

[程式設計題]拋小球

小東和三個朋友一起在樓上拋小球,他們站在樓房的不同層,假設小東站的樓層距離地面N米,球從他手裡自由落下,每次落地後反跳回上次下落高度的一半,並以此類推直到全部落到地面不跳,求4個小球一共經過了多少米?(數字都為整數)

給定四個整數A,B,C,D,請返回所求結果。

測試樣例:

100,90,80,70
返回:1020

坑人,不難,但是描述的有問題,取整不是每一步都取整,是最後取整,還是向上取整,題目表述不清晰

import java.util.*;

public class Balls {
    public  int calcDistance(int A, int B, int C, int D) {
		// write code here
		int instance = 0;
		return (int)Math.ceil(fantan(A) + fantan(B) + fantan(C) + fantan(D));
	}

	public  double fantan(double num) {
		double instance = num;
		while (num / 2 != 0) {
			num = num / 2;
			instance += num * 2;
		}
		return instance;
	}
}

[程式設計題]小東分蘋果

果園裡有一堆蘋果,一共n頭(n大於1小於9)熊來分,第一頭為小東,它把蘋果均分n份後,多出了一個,它扔掉了這一個,拿走了自己的一份蘋果,接著第二頭熊重複這一過程,即先均分n份,扔掉一個然後拿走一份,以此類推直到最後一頭熊都是這樣(最後一頭熊扔掉後可以拿走0個,也算是n份均分)。問最初這堆蘋果最少有多少個。

給定一個整數n,表示熊的個數,返回最初的蘋果數。保證有解。

測試樣例:

2
返回:3

參考牛客網上的做法,從前向後推,這道題應該做出來的,靜下心來

import java.util.*;

public class Apples {
 public  int getInitial(int n) {
         for(int i=n+1;;i++) {
             int temp=i;
             int bear=n;
             while(bear>0) {
                  
                 if(temp%n==1){
                     temp=temp-temp/n-1;
                     bear--;
                 }else {
                     break;
                 }
                  
             }
             if(bear==0) {
                 return i;
             }
         }
     }
}