LeetCode 279 完全平方数(BFS + 记忆化搜索)解法

题意说明

给定正整数n,找到若干个完全平方数(比如:1,4,9,16,……)使得它们的和等于n。找出组成和的完全平方数的最小个数。‘
在这里插入图片描述

思路

看到最XXX,第一反应一般是动态规划或贪心。不过这一题贪心不能采取不断选取范围内的最大完全平方数的策略。比如:12 = 4 + 4 + 4为最优解,但是若采取如上所示的贪心策略,则:12 = 9 + 1 + 1 + 1并不是最优解。
此题也可以采取广度优先搜索BFS的方式进行求解,大致思路如下:

  1. 设置ans = 0,max = Math.sqrt(n)来限制完全平方数的范围,queue用于进行BFS操作;
  2. 向queue中加入0,表示初始状态;
  3. 按照一般BFS的步骤来,每次遍历处理当前queue中所有的数字,弹出queue中的数字temp,将其加上一个完全平方数x,此时有如下几种情况:
    (1) temp + x < n :queue.add(temp + x);
    (2) temp + x == n :找到最佳答案返回ans,结束BFS过程;
    (3) temp + x > n:此时超出了n的范围,不需要继续取更大的完全平方数,因为此情况下怎样都不可能满足等于n的条件。
    参考代码:
class Solution {
    public int numSquares(int n) {
        int max = (int)Math.sqrt(n),ans = 1;
        if(max * max == n) return ans;
        Queue<Integer> queue = new LinkedList<>();
        for(int i = 1;i <= n;i++) {
            queue.add(i * i);
        }
        boolean flag = false;
        while(!queue.isEmpty()) {
            ans++;
            int len = queue.size();
            for(int i = 0;i < len;i++) {
                int temp = queue.remove();
                for(int j = 1;j <= n;j++) {
                    if(temp + j * j < n) {
                        queue.add(temp + j * j);
                    }
                    else if(temp + j * j == n) {
                        flag = true;break;
                    }
                    else break;
                }
                if(flag) break;
            }
            if(flag) break;
        }
        return ans;
    }
}

此代码提交结果超时,部分用例无法通过。在这里插入图片描述
说明所得结果基本正确,但是需要对时间复杂度进行小小的优化

记忆化搜索优化

在进行BFS的过程中,可以发现queue中多次出现重复的数字。比如,n = 12时:
第一轮:queue = [ 1, 4, 9 ]
第二轮:queue = [ 2, 5, 10, 5, 8, 10]
第三轮:queue = [ 3, 6, 11, 6, 9, 11, 6, 9, 9, 12 ] (此处找到12,结束BFS过程)
因为值相同的数字在BFS过程中产生的“新数字”完全一致,对重复数字的处理是一种无谓的开销。可以采取以空间换时间的策略,使用记忆化搜索优化BFS过程。
方法:创建一个HashSet存储至今遍历过的所有数字,若temp已在set中,直接跳过不做处理。

优化代码
class Solution {
    public int numSquares(int n) {
        int max = (int)Math.sqrt(n),ans = 0;
        Queue<Integer> queue = new LinkedList<>();
        Set<Integer> set = new HashSet<>();
        queue.add(0);set.add(0);
        while(!queue.isEmpty()) {
            ans++; // 每进行一层BFS就多一个完全平方数
            /* BFS一般过程 */
            int len = queue.size();
            for(int i = 0;i < len;i++) {
                int temp = queue.remove();
                for(int j = 1;j <= max;j++) {
                    if(set.contains(temp + j * j)) continue; // set中已存在temp,直接跳过
                    else if(!set.contains(temp + j * j) && temp + j * j < n) { // temp尚未出现过且满足要求
                        set.add(temp + j * j);
                        queue.add(temp + j * j);
                    }
                    else if(temp + j * j == n) { // 找到最优解
                        return ans;
                    }
                    else break; // temp + j * j > n
                }
            }
        }
        return ans;
    }
}

运行结果:
在这里插入图片描述
还是有点慢,可以尝试继续优化或者换动态规划的思路来解这一题。

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值