程序员代码面试指南刷题--第八章.加油站良好出发点问题

题目描述
N个加油站组成一个环形,给定两个长度都是N的非负数组oil和dis(N>1),oil[i]代表第i个加油站存的油可以跑多少千米,dis[i]代表第i个加油站到环中下一个加油站相隔多少千米。假设你有一辆油箱足够大的车,初始时车里没有油。如果车从第i个加油站出发,最终可以回到这个加油站,那么第i个加油站就算良好出发点,否则就不算。请返回长度为N的boolean型数组res,res[i]代表第i个加油站是不是良好出发点
规定只能按照顺时针走,也就是i只能走到i+1,N只能走到1
[要求]
时间复杂度为O(n),空间复杂度为O(1)
输入描述:

第一行一个整数N表示加油站数量。
第二行N个整数,表示oil数组。
第三行N个整数,表示dis数组。

输出描述:

输出N个整数。若第i个整数为0表示该位置不是良好出发点,为1表示该位置是良好出发点。

示例1

输入

9
4 2 0 4 5 2 3 6 2
6 1 3 1 6 4 1 1 6

输出

0 0 0 0 0 0 0 0 0

示例2

输入

8
4 5 3 1 5 1 1 9
1 9 1 2 6 0 2 0

输出

0 0 1 0 0 1 0 1

解法一:借助纯能数组

import java.io.*;
import java.util.*;
public class Main{
    public static void main(String[] args) throws Exception{
        BufferedReader br = new BufferedReader(new InputStreamReader(System.in));
        int len = Integer.parseInt(br.readLine());
        String[] ss1 = br.readLine().trim().split(" ");
        String[] ss2 = br.readLine().trim().split(" ");
        int[] oil = new int[len];
        int[] dis = new int[len];
        for(int i=0;i<len;i++){
            oil[i] = Integer.parseInt(ss1[i]);
            dis[i] = Integer.parseInt(ss2[i]);
        }
        boolean[] res = getRes(oil,dis);
        StringBuilder sb = new StringBuilder();
        for(int i=0;i<res.length;i++){
            int tmp = res[i]?1:0;
            sb.append(tmp+" ");
        }
        System.out.println(sb.toString().trim());
    }
    public static boolean[] getRes(int[] oil,int[] dis){
        if(dis==null||oil==null||dis.length<2||dis.length!=oil.length) return null;  
        int init = init(oil,dis);
        return init==-1?new boolean[dis.length]:enlargeArea(dis,init);        
    }
    public static boolean[] enlargeArea(int[] dis,int init){
        boolean[] res = new boolean[dis.length];
        int start = init;
        int end = nextIndex(init,dis.length);
        long need = 0;
        long rest = 0;
        do{
            //往后扩充已经没法扩充了
            if(start!=init&&start==lastIndex(end,dis.length)){
                break;
            }
            if(dis[start]<need){
                need -= dis[start];
            }else{
                //试着往前进
                rest += dis[start]-need;
                need = 0;
                while(rest>=0&&end!=start){
                    rest += dis[end];
                    end = nextIndex(end,dis.length);
                }
                if(rest>=0){
                    res[start] = true;
                    connectGood(dis,lastIndex(start,dis.length),init,res);
                    break;
                }
            }
            start  = lastIndex(start,dis.length);
        }while(start!=init);
        return res;
    }
    public static void connectGood(int[] dis,int start,int init,boolean[] res){
        long need = 0;
        while(start!=init){
            if(dis[start]<need){
                need -= dis[start];
            }else{
                res[start] = true;
                need = 0;
            }
            start = lastIndex(start,dis.length);
        }
    }
    public static int lastIndex(int init,int size){
        return init==0?size-1:(init-1);
    }
    public static int nextIndex(int init,int size){
        return init==size-1?0:(init+1);
    }
    public static int init(int[] oil,int[] dis){
        int init = -1;
        for(int i=0;i<oil.length;i++){
            dis[i] = oil[i] - dis[i];
            if(dis[i]>=0){
                init = i;
            }
        }
        return init;
    }
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值