leetcode279 最短路径解法

对问题建模: 
整个问题转化为一个图论问题。 
从n到0,每个数字表示一个节点; 
如果两个数字x到y相差一个完全平方数,则连接一条边。 
我们得到了一个无权图。 
原问题转化成,求这个无权图中从n到0的最短路径。 

package leetcode.search;

import java.util.ArrayList;
import java.util.LinkedList;
import java.util.List;
import java.util.Queue;

public class NumSquares_279 {
    int solution(int n){
        List<Integer> squares = generateSquares(n);
        //两个整数之间差值是平方数,从动态规划角度,或者从两个数间就有一条边的搜索.广度优先遍历即最短路径算法角度
        //广度优先遍历,能平方数组成的两个之间就有一条边,类似于最短路径问题
        Queue<Integer> queue = new LinkedList<>();
        int ret = 0;
        queue.add(n);
        boolean[] marked = new boolean[n+1];//标记已访问,不重复入队
        marked[n] = true;
        while (!queue.isEmpty()){
            ret +=1;
            int size = queue.size();
            while (size-->0){
                int i = queue.poll();
                for (int s : squares){
                    if (i-s<0){
                        break;
                    }
                    else if (i-s==0){
                        return ret;
                    }
                    else if (marked[i-s]){//标注
                        continue;
                    }
                    marked[i-s] = true;
                    queue.add(i);
                }
            }
        }
        return n;//负数?


    }


    private List<Integer> generateSquares(int n) {
//f(n+1)  = f(n) + 2(n-1)+3 = (n+1)^2 = (n)^2 + 2n+1
        List<Integer> ret = new ArrayList<>();
        int square = 1;
        int diff = 3;
        while (square <= n) {
            ret.add(square);
            square += diff;
            diff += 2;
        }
        return ret;
    }

    //dp[n] 表示以n为和的最少平方的和的个数(所求)。
    //
    //dp 数组所有下标已经为完全平方数的数(如1,4,9...)置为 1,加一层 j 遍历找到当前 i 下长度最小的组合。
    //
    //动态方程的意思是:对于每个 i ,比 i 小一个完全平方数的那些数中最小的个数+1就是所求,也就是 dp [ i - j * j ] + 1 。

    int solution2(int n){
        int[] dp = new int[n+1];

        for(int i=1;i*i<=n;i++){
            dp[i*i] = 1;
        }

        for (int j = 1;j<=n;j++){
            for (int k=1;k*k<j;k++){
                dp[j] = Math.min(dp[j],dp[j-k*k]+1);
            }
        }

        return dp[n];

    }

    //除8余7 必为4 判断能否有两个或一个,否则返回3 一个正数除4取余数,余数除8余7,必为4平方数

}

 

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值