剑指offer第二版——面试题47(java)

面试题:礼物的最大价值

题目:

在一个m×n的棋盘的每一格都放有一个礼物,每个礼物都有一定的价值(价值大于0)

可以从棋盘的左上角开始拿格子里的礼物,并每次向右或向下移动一格,直到到达棋盘的右下角

给定一个棋盘及其上面的礼物,计算你最多能拿到多少价值的礼物

即,给定一个二维矩阵,从左上角走到右下角,每次只能向右或者向下移动,经过的格子的数的最大总和

思路:

使用辅助数组maxa来记录每个位置到右下角的最大总和

1. 对于位置(i,j)= a,有两种走法,一种是(i+1,j),一种是(i,j+1),如果分别知道了从这两个位置开始,到右下角路径的最大总和b和c,就可以用max(a+b,a+c)得到从当前位置到右下角路径的最大总和

2. 采用自下向上的思想

可知从右下角开始到右下角,只包含其本身,所以可以得max[m-1][n-1] = a[m-1][n-1]

由1.得,知道了一个格子的值以后,可以计算其上面和左边的格子的值

左图为计算批次,

第一轮count=0,计算右下角的5

第二轮count=1,可由右下角5计算其上面和左边的格子

第三轮count=2,可由新计算出的两个数,计算其上面和左面的数

因此可以用一个循环来为maxa进行赋值

剑指offer第二版——面试题47(java)_第1张图片

具体做法:

1.

由左图可得规律,当用count来计数轮数时,当前轮数中所需要计算的坐标(i,j)总是满足i+j=m+n-2-count (-2是因为数组从0开始,所以是m-1+n-1-count)

因此,每次循环时,从最下面的格子开始计算(也就是最左,因为i+j是固定的数,i越大,j越小),依次往右上计算

注意:需要判断j的越界

2.

每个格子计算时需要注意:

    1)是否在最下面:如果是处于最下面的格子,则可供此位置选的路径只有往右走,所以直接用当前位置的值+右边格子的最大路径即可

    2)是否在最右边:如果是处于最右的格子,则可供此位置选的路径只有往下走,所以直接用当前位置的值+下面格子的最大路径即可

    3)不在最下面也不在最右边:处于中间的格子,可供此位置选的路径有往下走和往右走,此时选两个之中最大的值,相加即可

public class Q47 {
	public static void main(String[] args) {
		int[][] a = new int[][]{{1,10,3,9},{12,2,9,6},{5,7,4,11},{3,7,16,5}};
		System.out.printf("\nresult:%d",maxGift(a));
	}
	
	
	public static int maxGift(int[][] a) {
		if(a.length==0||a[0].length==0) {
			return 0;
		}
		
		int count=0;
		int m = a.length;
		int n = a[0].length;
		int[][] maxa = new int[m][n];
		maxa[m-1][n-1] = a[m-1][n-1];
		
		while(count=0;i--) {
				int j = loc-i;
				// 如果j<0 则直接i--
				if(j>=0) {
					// 判断j是否越界
					if(j==n) {
						break;
					}
					
					// 三种情况
					if(i==m-1) {
						maxa[i][j] = a[i][j]+maxa[i][j+1];
					}else 
					if(j==n-1) {
						maxa[i][j] = a[i][j]+maxa[i+1][j];
					}else {
						if(maxa[i+1][j]>maxa[i][j+1]) {
							maxa[i][j] = a[i][j]+maxa[i+1][j];
						}else {
							maxa[i][j] = a[i][j]+maxa[i][j+1];
						}
					}
					//System.out.printf("(%d,%d):%d\n",i,j,maxa[i][j]);
				}
			}	
		}
		return maxa[0][0];
	}
}

 

你可能感兴趣的:(剑指offer第二版)