【LeetCode】120. Triangle

120. Triangle

Description:

Given a triangle, find the minimum path sum from top to bottom. Each step you may move to adjacent numbers on the row below.

For example, given the following triangle

[
     [2],
    [3,4],
   [6,5,7],
  [4,1,8,3]
]

The minimum path sum from top to bottom is 11 (i.e., 2 + 3 + 5 + 1 = 11).

Note:

Bonus point if you are able to do this using only O(n) extra space, where n is the total number of rows in the triangle.

解题思路:

(1)动态规划法

一道动态规划的经典题目。需要自底向上求解。

dp[i][j]表示走到第arr[i][j]时的最优解。

递推公式是: dp[i][j] = Min( dp[i+1][j] , dp[i+1][j+1] ) + arr[i][j],当前这个点的最小值,由它下面那一行临近的2个点的最小值与当前点的值相加得到。

由于是三角形,且历史数据只在计算最小值时应用一次,所以无需建立二维数组,每次更新1维数组值,最后那个值里存的就是最终结果。

已经AC的代码:

import java.util.ArrayList;
import java.util.List;

public class triangle_120 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub		
		List> triangle = new ArrayList<>();
		List line1 = new ArrayList<>();
		line1.add(2);
		triangle.add(line1);
		List line2 = new ArrayList<>();
		line2.add(3);
		line2.add(4);
		triangle.add(line2);
		List line3 = new ArrayList<>();
		line3.add(6);
		line3.add(5);
		line3.add(7);
		triangle.add(line3);
		List line4 = new ArrayList<>();
		line4.add(4);
		line4.add(1);
		line4.add(8);
		line4.add(3);
		triangle.add(line4);
		System.out.println(minimumTotal(triangle));
	}
	
    public static int minimumTotal(List> triangle) {
        if(triangle.size()==1)
            return triangle.get(0).get(0);
            
        int[] dp = new int[triangle.size()];

        //initial by last row 
        for (int i = 0; i < triangle.get(triangle.size() - 1).size(); i++) {
            dp[i] = triangle.get(triangle.size() - 1).get(i);
        }
     
        // iterate from last second row
        for (int i = triangle.size() - 2; i >= 0; i--) {
            for (int j = 0; j < triangle.get(i).size(); j++) {
                dp[j] = Math.min(dp[j], dp[j + 1]) + triangle.get(i).get(j);
            }
        }
     
        return dp[0];
    }
	
}

(2)递归解法

同样的动态规划,采用深度优先,很容易想到用递归法,但是这种方法在数据量很大时超时了。

不能AC的代码:

import java.util.ArrayList;
import java.util.List;

public class triangle_120 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub		
		List> triangle = new ArrayList<>();
		List line1 = new ArrayList<>();
		line1.add(2);
		triangle.add(line1);
		List line2 = new ArrayList<>();
		line2.add(3);
		line2.add(4);
		triangle.add(line2);
		List line3 = new ArrayList<>();
		line3.add(6);
		line3.add(5);
		line3.add(7);
		triangle.add(line3);
		List line4 = new ArrayList<>();
		line4.add(4);
		line4.add(1);
		line4.add(8);
		line4.add(3);
		triangle.add(line4);
		System.out.println(minimumTotal(triangle));
	}
	
    public static int minimumTotal(List> triangle) {
        return findMinPath(triangle, 0, Integer.MAX_VALUE, 0, 0);
    }
    
    /**
     * 递归求最小路径
     * @param triangle
     * @param curSum 当前最小值
     * @param min 全局最小值
     * @param index 每一行中的List元素下标
     * @param level 行下标
     * @return
     */
    public static int findMinPath(List> triangle, int curSum, int min, int index, int level) {
        curSum += triangle.get(level).get(index);
        if (level == triangle.size() - 1)
            return Math.min(min, curSum);
        return Math.min(findMinPath(triangle, curSum, min, index, level + 1),
                findMinPath(triangle, curSum, min, index + 1, level + 1));
    }
    
}

(3)对上面递归法的优化 - 递归法

上面递归法有一个问题就是,递归函数中无用的参数过多,导致看起来程序很复杂。下面的递归解法,优化了递归函数中的参数。

import java.util.ArrayList;
import java.util.List;

public class triangle_120 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub		
		List> triangle = new ArrayList<>();
		List line1 = new ArrayList<>();
		line1.add(2);
		triangle.add(line1);
		List line2 = new ArrayList<>();
		line2.add(3);
		line2.add(4);
		triangle.add(line2);
		List line3 = new ArrayList<>();
		line3.add(6);
		line3.add(5);
		line3.add(7);
		triangle.add(line3);
		List line4 = new ArrayList<>();
		line4.add(4);
		line4.add(1);
		line4.add(8);
		line4.add(3);
		triangle.add(line4);
		System.out.println(minimumTotal(triangle));
	}
	
    public static int minimumTotal(List> triangle) {
    	return findMinPath2(triangle, 0, 0);
    }
    
    public static int findMinPath2(List> triangle, int row, int col) {
    	if(row == triangle.size() - 1)
    		return triangle.get(row).get(col);
    	return Math.min(findMinPath2(triangle, row+1, col), 
    			findMinPath2(triangle, row+1, col+1)) + triangle.get(row).get(col);
    }
    
}

(4)记忆化搜索法

由于递归解法中有很多的重复计算,我们可以用数组保存已经计算过的结果,这样就不存在重复计算,时间效率会大大提高。

声名一个一维数组memo,数组的大小是这个三角形元素的个数。数组中每个元素代表的是三角形中到这个元素的最小路径和。

已经AC的代码:

import java.util.ArrayList;
import java.util.Arrays;
import java.util.List;

public class triangle_120 {

	public static void main(String[] args) {
		// TODO Auto-generated method stub		
		List> triangle = new ArrayList<>();
		List line1 = new ArrayList<>();
		line1.add(2);
		triangle.add(line1);
		List line2 = new ArrayList<>();
		line2.add(3);
		line2.add(4);
		triangle.add(line2);
		List line3 = new ArrayList<>();
		line3.add(6);
		line3.add(5);
		line3.add(7);
		triangle.add(line3);
		List line4 = new ArrayList<>();
		line4.add(4);
		line4.add(1);
		line4.add(8);
		line4.add(3);
		triangle.add(line4);
		System.out.println(minimumTotal(triangle));
	}
	
	public static int[] memo = null;
	
    public static int minimumTotal(List> triangle) {
        memo = new int[(triangle.size()*(1+triangle.size()))/2];
        Arrays.fill(memo, -1);
    	return findMinPath2(triangle, 0, 0);
    }
    
    public static int findMinPath2(List> triangle, int row, int col) {
    	
    	if(row == triangle.size() - 1) {
    		return triangle.get(row).get(col);
    	}
    	
    	if(memo[(row * (row + 1) / 2) + col] != -1)
    		return memo[(row * (row + 1) / 2) + col];
    	else {
    		int A = findMinPath2(triangle, row+1, col) + triangle.get(row).get(col);
    		int B = findMinPath2(triangle, row+1, col+1) + triangle.get(row).get(col);
    		int minValue = Math.min(A, B);
    		memo[(row * (row + 1) / 2) + col] = minValue;
    		return minValue;
    	}
    	
    }
    
}

 Reference:

【1】https://blog.csdn.net/happyaaaaaaaaaaa/article/details/50826642

【2】https://blog.csdn.net/zxzxzx0119/article/details/83155087

你可能感兴趣的:(算法,LeetCode)