算法日常训练12.5

首先有个很大的进步,看见困难题我没选择做逃兵跑路,这点起码是进步了,虽然算法能力还是那么拉,但是起码敢不自量力地分析一下。。。还能看题解理解下。

 先找题解中最简单地一种超时方法开始理解,使用动态规划:

定义dp:dp[i]:前i个箱子所需的最小行程

初始化:明显有dp[0]=0,其他的需要选最大值,因为要维护最小值

状态转移公式:dp[i]=dp[j-1]+cost(j,i);cost(j,i)代表j到i范围内的箱子所需要的行程

cost(i,j)怎么求:首先出去和回来都需要一次行程,初始化为2,遍历范围的箱子,如果有相同连续码头的箱子,就可以一次性都放了,加1,没连续遇见一个新码头就要加1

箱子需要遍历,范围需要遍历两次,超时,但是比较好理解

class Solution {
    public int boxDelivering(int[][] boxes, int portsCount, int maxBoxes, int maxWeight) {
        int len=boxes.length;
        int[] dp=new int[len+1];//dp[i]:运送前i个箱子所需要的最少行程
        Arrays.fill(dp,Integer.MAX_VALUE);
        dp[0]=0;//初始化
        for(int i=1;i<=len;i++){
            int sum=0;//保证重量不超过最大值
            for(int j=i;j>=1&&j>=i-maxBoxes+1;j--){//保证数量不超过最大值
                sum+=boxes[j-1][1];//累加重量
                if(sum>maxWeight) break;
                dp[i]=Math.min(dp[i],dp[j-1]+cost(j,i,boxes));
            }
        }
        return dp[len];
    }
    public int cost(int l,int r,int[][] boxes){
        int port=2;//仓库出去和回来都要一次行程
        int pre=boxes[l-1][0];//记录前一个箱子目标码头
        while(++l<=r){//遍历这个范围的箱子
            if(boxes[l-1][0]==pre) continue;//和前面的箱子相同就不用行程
            port++;//不然就要一次行程
            pre=boxes[l-1][0];//更新前一个码头
        }
        return port;
    }
}

这里的dp可以发现是维护一个滑动窗口中的最小值,第一次见,详细分析见 力扣大佬题解 

总之就是需要优化每次找最小值的时间,我选择使用优先队列,感觉好理解一点,看了很久,这题有点超出我水平了,溜了,有缘回来再看。

class Solution {
    public int boxDelivering(int[][] boxes, int portsCount, int maxBoxes, int maxWeight) {
        int len=boxes.length;
        int[] dp=new int[len+1];//dp[i]:运送前i个箱子所需要的最少行程
        Arrays.fill(dp,Integer.MAX_VALUE);
        dp[0]=0;//初始化
        PriorityQueue<int[]> q = new PriorityQueue<int[]>((a, b)->a[1] - b[1]);//数组中保存的分别是i下标,最少次数,重量
        int dif=0;//差值
        int wei=0;//保存重量
        for(int i=1;i<=len;i++){
            int cur = dp[i-1] + 2;
            dif += i >= 2 && boxes[i - 1][0] != boxes[i - 2][0] ? 1 : 0;//如果相同,代表多加了一次行程
            wei += boxes[i - 1][1]; //保存重量
            q.add(new int[]{i, cur - dif, boxes[i - 1][1] - wei}); 
            while (q.peek()[0] <= i - maxBoxes || q.peek()[2] + wei > maxWeight) q.poll();//超载
            dp[i] = q.peek()[1] + dif;             
        }
        return dp[len];
    }
}

经典的搜索题,写了好几遍了

遍历所有城市,使用used标志该城市是否访问过,没访问过就进行深搜,找到和他相连的城市都搜一遍。 

class Solution {
    boolean[] used;
    public int findCircleNum(int[][] isConnected) {
        int res=0;//记录省份数量
        used=new boolean[isConnected.length];
        for(int i=0;i<isConnected.length;i++){
            if(!used[i]){
            dfs(i,isConnected);
            res++;}
        }
        return res;
    }
    
    public void dfs(int i,int[][] isConnected){
        used[i]=true;
        for(int j=0;j<isConnected[0].length;j++){
            if(!used[j]&&isConnected[i][j]==1) dfs(j,isConnected);
        }
    }
}

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值