1-剑指offer-1-剪绳子-DP-2-机器人的运动范围-DFS/BFS

1. 剪绳子

题目描述

Online

给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1,m<=n),每段绳子的长度记为k[1],…,k[m]。请问k[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

输入描述:

输入一个数n,意义见题面。(2 <= n <= 60)

输出描述:

输出答案。

示例1

输入

8

输出

18

题解

分析:对于长度n的绳子,我们都进行不剪、剪1、剪2…剪n-1。

对应结果应该是i*f[n-i],其中的f[i]代表长度为i的绳子的最优值。

所以对于任何长度的绳子,结果都可以表示成减去的长度*剩余长度最优值。去结果集中最大的,就是这个绳子的最优解。

可见这是一个递归求解的题。

使用暴力递归会超过限制。解决递归超限制的就是带备忘录的自顶向下DP或者自底向上的DP

import java.util.*;
public class Solution {
    private Map<Integer, Integer> map = new HashMap<>();
    public int cutRope(int target) {
        map.put(1,1);
        return back_t(target);
    }
    private int back_t (int target){
        if(target == 1){
            return 1;
        }
        if(target == 2){
            return 2;
        }
        if(map.containsKey(target)){
            return map.get(target);
        }
        int max = target;
        for(int i=1; i<target; i++){
            //int t = i*map.getOrDefault(target-i,back_t(target-i));
            int t = i*back_t(target-i);
            max = Math.max(max, t);
        }
        map.put(target, max);
        return max;
    }
}

单维度:

import java.util.*;
public class Solution {
    private Map<Integer, Integer> map = new HashMap<>();
    public int cutRope(int target) {
        // 记录长度为j时的最大值
        int [] dp = new int[target+1];
        dp[0] = 0;
        dp[1] = 1;
        //全部初始化为不剪
        for(int i = 1; i<=target; i++){
            dp[i] = i;
        }
        for(int i=1; i<=target ; i++){
            for(int j=1; j<=i; j++){
                dp[i] = Math.max(dp[i], dp[i-j]*j);
            }
        }
        return dp[target];
    }

}

2. 机器人的运动范围

在线

地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

题解

可以使用DFS

public class Solution {
    private int[][]mark ;
    public int movingCount(int threshold, int rows, int cols)
    {
        mark = new int[rows][cols];
        return dfs(0,0,rows,cols, threshold);
    }
    private int dfs(int rowIdx, int colIdx, int rows, int cols, int threshold){
        //递归出口:越界
        if(rowIdx>=rows || colIdx>=cols|| rowIdx<0 || colIdx<0){
            return 0;
        }
        //递归出口:已访问、超过坐标限制
        if(!check(rowIdx, colIdx, threshold) || mark[rowIdx][colIdx]==1){
            return 0;
        }
        //标记访问
        mark[rowIdx][colIdx] =1;
        int sum = 1;
        sum+=dfs(rowIdx+1, colIdx, rows, cols, threshold);
        sum+=dfs(rowIdx-1, colIdx, rows, cols, threshold);
        sum+=dfs(rowIdx, colIdx+1, rows, cols, threshold);
        sum+=dfs(rowIdx, colIdx-1, rows, cols, threshold);
        return sum;
    }
    
    private boolean check(int rowIdx, int colIdx, int threshold){
        int sum = 0;
        for(int i=1; i<=rowIdx; i=i*10){
            rowIdx = rowIdx/i;
            sum=sum+rowIdx%10;
        }
        for(int i=1; i<=colIdx; i*=10){
            colIdx = colIdx/i;
            sum = sum+ colIdx%10;
        }
        return sum>threshold? false:true;
    }
}

BFS:

import java.util.*;
public class Solution {
    
    public int movingCount(int threshold, int rows, int cols)
    {
        int sum=0;
        int[][]mark = new int[rows][cols];
        Queue<Integer> queueX = new LinkedList<>();
        Queue<Integer> queueY = new LinkedList<>();
        queueX.add(0);
        queueY.add(0);
        
        while(!queueX.isEmpty()){
            int x = queueX.poll();
            int y = queueY.poll();
            
            if(!check(x,y,threshold) || x<0 || y<0 || x>=rows || y>=cols){
                continue;
            }
            if(mark[x][y]==1)
                continue;
            // 标记已经访问
            mark[x][y] = 1;
            sum++;
            queueX.add(x+1);
            queueY.add(y);
            
            queueX.add(x-1);
            queueY.add(y);
            
            queueX.add(x);
            queueY.add(y+1);
            
            queueX.add(x);
            queueY.add(y-1);
        }
        return sum;
    }


    private boolean check(int rowIdx, int colIdx, int threshold){
        int sum = 0;
        for(int i=1; i<=rowIdx; i=i*10){
            rowIdx = rowIdx/i;
            sum=sum+rowIdx%10;
        }
        for(int i=1; i<=colIdx; i*=10){
            colIdx = colIdx/i;
            sum = sum+ colIdx%10;
        }
        return sum>threshold? false:true;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值