leetcode 279-Perfect Squares(medium)

Given a positive integer n, find the least number of perfect square numbers (for example, 1, 4, 9, 16, ...) which sum to n.

1. DP

Set an array, first initiate index=i^2 with 1.

Then calculate others with dp[j]=Math.min(dp[j],dp[j-i*i]+dp[i*i]) //注意,这里在自己第一次写的时候,最后一项写成了dp[i],要仔细!前面更新的是dp[i*i]为1,而不是dp[i]为1。

class Solution {
    public int numSquares(int n) {
        if(n<=0) return 0;
        int[] dp=new int[n+1];
        Arrays.fill(dp,Integer.MAX_VALUE);
        dp[0]=0;
        int sr=(int)Math.sqrt(n);
        for(int i=1;i<=sr;i++){
            dp[i*i]=1;
        }
        for(int i=1;i<=sr;i++){
            for(int j=i*i+1;j<=n;j++){
                dp[j]=Math.min(dp[j-i*i]+dp[i*i],dp[j]);
            }
        }
        return dp[n];
    }
}

2. BFS

按照bfs的思想,每轮依次入队需要1,2,3,……步到达的点,如果遇到n则直接返回这一轮对应的步数。

自己写的第一版。注意queue的size是会变的,一开始写的时候还出了低级错误,没有把queue的size先取出来然后在一轮循环中固定不变,而是直接写了queue.size(),忽视了这个量每个循环下来都会变的。以下这种方法会MLE,主要是在入队的时候没有判断这个数是否已经入队过,如果已经入队过就不需要再入队了,我们只关心一个数最小的组成成分个数,即到达该数最小的步数。(其实写的时候已经注意到了入队的元素会有重复,但都竟然没想到用一个set去避免,对数据结构的运用还是太不熟悉啊)

class Solution {
    public int numSquares(int n) {
        //bfs
        if(n==0) return 0;
        int sr=(int)Math.sqrt(n);
        Queue<Integer> queue=new LinkedList<>();
        queue.offer(0);
        int count=0;
        while(true){
            count++;
            int s=queue.size();
            for(int j=0;j<s;j++){
                int num=queue.poll();
                for(int i=1;i<=sr;i++){
                    if(num+i*i==n) return count;
                    if(num+i*i>n) continue;
                    queue.offer(num+i*i);
                }
            }
        }
    }
}

改进后:(加入set visited来记录是否入队过)(s-->0这种写法比较简洁)

class Solution {
    public int numSquares(int n) {
        //bfs
        if(n==0) return 0;
        int sr=(int)Math.sqrt(n);
        Queue<Integer> queue=new LinkedList<>();
        queue.offer(0);
        Set<Integer> visited=new HashSet<>();
        int count=0;
        while(true){
            count++;
            int s=queue.size();
            while(s-->0){
                int num=queue.poll();
                for(int i=1;i<=sr;i++){
                    if(num+i*i==n) return count;
                    if(num+i*i>n) break;//第一次写的时候写成了continue,当大于n的时候,后面的就不需要再考虑了,所以应该直接break
                    if(!visited.contains(num+i*i)){
                        queue.offer(num+i*i);
                        visited.add(num+i*i);
                    }
                }
            }
        }
    }
}

猜你喜欢

转载自www.cnblogs.com/yshi12/p/9721639.html