LeetCode 周赛263

检查句子中的数字是否递增

题目连接

使用Java字符串的split方法可以快速的将整个字符串按照空格分隔成字符串数组。

使用一个变量pre记录上一个出现的数字大小,初始值设为-1。

遍历每一个字符串,判断是否为数字,如果是则与pre比较大小,满足条件的话更新pre,否则返回false。

循环结束,返回true

class Solution {
    public boolean areNumbersAscending(String s) {

        String[] strs = s.split(" ");

        int prev = -1;

        for(int i = 0;i < strs.length;i++){
            if(!isNumber(strs[i])){
                continue;
            }
            int num = Integer.parseInt(strs[i]);
            if(num <= prev){
                return false;
            }
            prev = num;
        }

        return true;
    }
    private boolean isNumber(String str){

        for(int i = 0;i < str.length();i++){
            if(str.charAt(i) < '0' || str.charAt(i) > '9'){
                return false;
            }
        }
        return true;
    }
}

简易银行系统

题目连接

事务处理部分问题应该不大。有几个地方还是要注意以下,以防被卡:

  • 账户从1开始计数,转换成下标时要-1
  • 账户支出(取款或转款)时要校验余额。
  • 账户存在出界情况,进行任何事务前请先校验账户合法
class Bank {

    private long[] balance;

    public Bank(long[] balance) {
        this.balance = balance;
    }

    public boolean transfer(int account1, int account2, long money) {
        account1--;
        account2--;
        if(!checkAccount(account1) || !checkAccount(account2)){
            return false;
        }
        if(balance[account1] < money){
            return false;
        }
        balance[account1] -= money;
        balance[account2] += money;
        return true;

    }

    public boolean deposit(int account, long money) {
        account--;
        if(!checkAccount(account)){
            return false;
        }
        balance[account] += money;
        return true;
    }

    public boolean withdraw(int account, long money) {
        account--;
        if(!checkAccount(account)){
            return false;
        }
        if(balance[account] >= money){
            balance[account] -= money;
            return true;
        }
        return false;
    }
    private boolean checkAccount(int account){
        return account >= 0 && account < balance.length;
    }
}

统计按位或能得到最大值的子集数目

题目连接

这道题需要我们从集合中挑出所有子集,子集中的元素相或结果等于整个集合元素相或。

从每位的角度看,题目是希望挑出的子集的元素包含所有位置的1 。

不过由于数据规模非常小,可以选择使用枚举幂集合进行统计。

class Solution {
    private int ans = 0;
    private int orSum = 0;
    public int countMaxOrSubsets(int[] nums) {

        for(int i = 0;i < nums.length;i++){
            orSum |= nums[i];
        }
        dfs(nums,0,0);
        return ans;
    }

    private void dfs(int[] nums,int dep,int sum){
        if(dep == nums.length){
            ans += sum == orSum ? 1 : 0;
            return;
        }
        dfs(nums,dep + 1,sum);
        dfs(nums,dep + 1,sum | nums[dep]);
    }
}

到达目的地的第二短时间

题目链接

首先,对题目的分析,可以得出一个结论:由于经过每条边的时间都是一样的且每个节点灯的状态都同步,到达每个节点的时间只与步数有关,与路径无关,步数越多,耗时越长。

接着,可以知道,要求次少时间,实际上就是要求次少的步数。

那么,如果像题目给出样例一样只有一种长度的路径怎么办?

  • 题目允许我们反复到大某节点,所以这种情况应该在路径中的任意一条边折返一次达到次少步数,有 次 少 步 数 = 最 少 步 数 + 2 次少步数 = 最少步数 +2 =+2

接下来的问题就是,要如何求解每个点的最少步数和次少步数。

由于问题类似于求解单源最短路,我们可以考虑改造spfa算法或者dijkstra算法实现。

主要改造的点有:

  • 顶点最短路径有两个值,最小值和次小值
  • 比较节点距离时,最小值第一关键字,次小值第二关键字
  • 更新节点时,需要用该节点的最小和次小分别更新后继节点的最小和次小,任一值可以更新后继就将其加入队列(spfa)或堆(dijkstra)中。
  • 同一节点可能出现多次,不仅首次可能更新后续节点,第二次也可能更新后续节点的次小值,所以不要直接使用标记数组使节点仅出现一次。(可以不标记)

那么最后,就是根据我们拿到的次小步数计算答案了。这里由于步数不会很大( ≤ n + 1 \le n+1 n+1)可以直接使用模拟得出答案:

  • spfa实现
class Solution {

    private int[] dep1;	//最少次数
    private int[] dep2;	//次少次数

    private int[] head;	//邻接表头
    private Edge[] nxt;	//邻接表
    private int tot = 0;//邻接表计数

	//邻接表添加边
    private void link(int x,int y){
        nxt[++tot] = new Edge(y,head[x]);
        head[x] = tot;
        nxt[++tot] = new Edge(x,head[y]);
        head[y] = tot;
    }

	
    public int secondMinimum(int n, int[][] edges, int time, int change) {
        dep1 = new int[n + 1];
        dep2 = new int[n + 1];
        nxt = new Edge[edges.length * 3];
        head = new int[n + 1];
        //初始化
        for(int i = 1;i <= n;i++){
            dep1[i] = 1 << 30;
            dep2[i] = 1 << 30;
            head[i] = 0;
        }

		//建立邻接表
        for(int[] edge : edges){
            link(edge[0],edge[1]);
        }

		//spfa队列
        int queue[] = new int[n * 10];
        int l = 1,r = 0;
        //初始添加起点,步数为0
        queue[++r] = 1;
        dep1[1] = 0;
        
        while(l <= r){
            int k = queue[l++];
			
			//更新可能的后续节点
            for(int i = head[k];i != 0;i = nxt[i].next){
                Edge edge = nxt[i];
				
				//如果可以更新成功则加入队列
                if(setDep(edge.vertex,dep1[k] + 1) || setDep(edge.vertex,dep2[k] + 1)){
                    queue[++r] = edge.vertex;
                }

            }
        }

		//获取次少步数
        int steps = dep2[n];
        //无次少步数,则最少步数折返一次
        if(steps == 1 << 30){
            steps = dep1[n] + 2;
        }
		
		//计算次少步数时间
        return calc(time,change,steps);
    }

    private int calc(int time,int change,int steps){
        int curr = 0;
        for(int i = 0;i < steps;i++){
            if(isGreen(change,curr)){//当前为绿灯
                curr += time;
            }else{					 //红灯,等到绿灯
                curr = latestGreen(change,curr) + time;
            }
        }
        return curr;
    }
    private boolean isGreen(int change,int curr){
        curr %= (change * 2);
        return curr < change;
    }
    private int latestGreen(int change,int curr){
        return (curr / (change * 2) + 1) * (change * 2);
    }

	//更新步数,更新最少步数或次少步数都算更新成功
    private boolean setDep(int k,int dep){
        if(dep < dep1[k]){
            dep2[k] = dep1[k];
            dep1[k] = dep;
            return true;
        }else if(dep < dep2[k] && dep > dep1[k]){
            dep2[k] = dep;
            return true;
        }
        return false;

    }
}

class Edge{
    public int vertex;
    public int next;
    public Edge(int vertext,int next){
        this.vertex = vertext;
        this.next = next;
    }
}
  • dijkstra实现
class Solution {

    private int[] dep1;
    private int[] dep2;
    private int[] head;
    private Edge[] nxt;
    private int tot = 0;

    private void link(int x,int y){
        nxt[++tot] = new Edge(y,head[x]);
        head[x] = tot;
        nxt[++tot] = new Edge(x,head[y]);
        head[y] = tot;
    }


    public int secondMinimum(int n, int[][] edges, int time, int change) {
        dep1 = new int[n + 1];
        dep2 = new int[n + 1]
        nxt = new Edge[edges.length * 3];
        head = new int[n + 1];
        for(int i = 1;i <= n;i++){
            dep1[i] = 1 << 30;
            dep2[i] = 1 << 30;
            head[i] = 0;
        }

        for(int[] edge : edges){
            link(edge[0],edge[1]);
        }


        PriorityQueue<Node> pq = new PriorityQueue<>();

        pq.add(new Node(1,0,1 << 30));
        dep1[1] = 0;

        while(!pq.isEmpty()){

            Node node = pq.poll();

            for(int i = head[node.vertex];i > 0;i = nxt[i].next){
                Edge edge = nxt[i];
                if(setDep(edge.vertex,dep1[node.vertex] + 1) || setDep(edge.vertex,dep2[node.vertex] + 1)){
                    pq.add(new Node(edge.vertex,dep1[edge.vertex],dep2[edge.vertex]));
                }

            }

        }

        int steps = dep2[n];
        if(steps == 1 << 30){
            steps = dep1[n] + 2;
        }

        return calc(time,change,steps);
    }

    private int calc(int time,int change,int steps){
        int curr = 0;
        for(int i = 0;i < steps;i++){
            if(isGreen(change,curr)){
                curr += time;
            }else{
                curr = latestGreen(change,curr) + time;
            }
        }
        return curr;
    }
    private boolean isGreen(int change,int curr){
        curr %= (change * 2);
        return curr < change;
    }
    private int latestGreen(int change,int curr){
        return (curr / (change * 2) + 1) * (change * 2);
    }

    private boolean setDep(int k,int dep){
        if(dep < dep1[k]){
            dep2[k] = dep1[k];
            dep1[k] = dep;
            return true;
        }else if(dep < dep2[k] && dep > dep1[k]){
            dep2[k] = dep;
            return true;
        }
        return false;

    }
}

class Edge{
    public int vertex;
    public int next;
    public Edge(int vertext,int next){
        this.vertex = vertext;
        this.next = next;
    }
}

class Node implements Comparable<Node>{
    public int vertex;
    public int dep1;
    public int dep2;

    public Node(int vertex,int dep1,int dep2){
        this.vertex = vertex;
        this.dep1 = dep1;
        this.dep2 = dep2;
    }

    public int compareTo(Node node){
        if(this.dep1 == node.dep1){
            return dep2 - node.dep2;
        }
        return this.dep1 - node.dep1;
    }
}
  • 2
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值