[Leetcode Weekly Contest]263

链接:LeetCode

[Leetcode]2042. 检查句子中的数字是否递增

句子是由若干 token 组成的一个列表,token 间用 单个 空格分隔,句子没有前导或尾随空格。每个 token 要么是一个由数字 0-9 组成的不含前导零的 正整数 ,要么是一个由小写英文字母组成的 单词 。

示例,"a puppy has 2 eyes 4 legs" 是一个由 7 个 token 组成的句子:"2" 和 "4" 是数字,其他像 "puppy" 这样的 tokens 属于单词。
给你一个表示句子的字符串 s ,你需要检查 s 中的 全部 数字是否从左到右严格递增(即,除了最后一个数字,s 中的 每个 数字都严格小于它 右侧 的数字)。

如果满足题目要求,返回 true ,否则,返回 false 。

遍历即可。

class Solution {
    public boolean areNumbersAscending(String s) {
        int last = -1;
        for(var ss:s.split(" ")) {
            if(isDigit(ss)) {
                int cur = Integer.parseInt(ss);
                if(cur <= last) return false;
                last = cur;
            }
        }
        return true;
    }

    public boolean isDigit(String s) {
        for(var ch:s.toCharArray()) {
            if (!Character.isDigit(ch)) return false;
        }
        return true;
    }
}

[Leetcode]2043. 简易银行系统

你的任务是为一个很受欢迎的银行设计一款程序,以自动化执行所有传入的交易(转账,存款和取款)。银行共有 n 个账户,编号从 1 到 n 。每个账号的初始余额存储在一个下标从 0 开始的整数数组 balance 中,其中第 (i + 1) 个账户的初始余额是 balance[i] 。

请你执行所有 有效的 交易。如果满足下面全部条件,则交易 有效 :

指定的账户数量在 1 和 n 之间,且
取款或者转账需要的钱的总数 小于或者等于 账户余额。
实现 Bank 类:

Bank(long[] balance) 使用下标从 0 开始的整数数组 balance 初始化该对象。
boolean transfer(int account1, int account2, long money) 从编号为 account1 的账户向编号为 account2 的账户转帐 money 美元。如果交易成功,返回 true ,否则,返回 false 。
boolean deposit(int account, long money) 向编号为 account 的账户存款 money 美元。如果交易成功,返回 true ;否则,返回 false 。
boolean withdraw(int account, long money) 从编号为 account 的账户取款 money 美元。如果交易成功,返回 true ;否则,返回 false 。

按照题意实现即可,注意判断账户是否有效。

class Bank {
    private long[] balance;
    private final int N;
    public Bank(long[] balance) {
        this.balance = balance;
        this.N = balance.length;
    }

    public boolean isAvailableAccount(int account) {
        return account >=1 && account <= this.N;
    }

    public boolean hasEnoughMoney(int account, long money) {
        return this.balance[account-1] >= money;
    }

    public boolean transfer(int account1, int account2, long money) {
        if(!isAvailableAccount(account1) || !isAvailableAccount(account2)) return false;
        if(!hasEnoughMoney(account1,money)) return false;
        this.balance[account1-1] -= money;
        this.balance[account2-1] += money;
        return true;
    }

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

    public boolean withdraw(int account, long money) {
        if(!isAvailableAccount(account) || !hasEnoughMoney(account,money)) return false;
        this.balance[account-1] -= money;
        return true;
    }
}

/**
 * Your Bank object will be instantiated and called as such:
 * Bank obj = new Bank(balance);
 * boolean param_1 = obj.transfer(account1,account2,money);
 * boolean param_2 = obj.deposit(account,money);
 * boolean param_3 = obj.withdraw(account,money);
 */

[Leetcode]2044. 统计按位或能得到最大值的子集数目

给你一个整数数组 nums ,请你找出 nums 子集 按位或 可能得到的 最大值 ,并返回按位或能得到最大值的 不同非空子集的数目 。

如果数组 a 可以由数组 b 删除一些元素(或不删除)得到,则认为数组 a 是数组 b 的一个 子集 。如果选中的元素下标位置不一样,则认为两个子集 不同 。

对数组 a 执行 按位或 ,结果等于 a[0] OR a[1] OR ... OR a[a.length - 1](下标从 0 开始)。

这道题中要找的是 子序列 中,包含几个可行解,很容易的可以想到 dfs:
观察数据规模, 1 ≤ n ≤ 16,最暴力的 dfs 也才 2^16 ,可以接受还需要找到 按位或 的 最大值 。观察到所有的数字都是正数,则显然有 \(a\ |\ b ≥ max(a, b)\),即一个正数A按位或另一个正数B,得到的结果C一定是不减的。
由此我们可以知道:我们要寻找的最大值 = 所有数字按位或结果。
另外,可用在回溯过程中剪枝,假设我们找到了一个组合,其位或结果为最大值,则接下来剩余的m个数都不需要再搜索了,因为我们想到这m个数加或者不加,其结果不变,则直接返回2**m即可。

class Solution {
    private int mx = 0;
    private int count = 0;
    public int countMaxOrSubsets(int[] nums) {
        for(var num:nums) {
            mx = mx | num;
        }
        dfs(nums,-1,0);
        return count;
    }

    public void dfs(int[] nums,int startIndex,int cur) {
        int n = nums.length;
        if(cur == mx) {
            // count += Math.pow(2, n-startIndex-1);
            count += 1<<(n-startIndex-1);
            return;
        }
        for(int i=startIndex+1;i<nums.length;++i) {
            dfs(nums,i,cur|nums[i]);
        }
    }
}

[Leetcode]2045. 到达目的地的第二短时间

城市用一个 双向连通 图表示,图中有 n 个节点,从 1 到 n 编号(包含 1 和 n)。图中的边用一个二维整数数组 edges 表示,其中每个 edges[i] = [ui, vi] 表示一条节点 ui 和节点 vi 之间的双向连通边。每组节点对由 最多一条 边连通,顶点不存在连接到自身的边。穿过任意一条边的时间是 time 分钟。

每个节点都有一个交通信号灯,每 change 分钟改变一次,从绿色变成红色,再由红色变成绿色,循环往复。所有信号灯都 同时 改变。你可以在 任何时候 进入某个节点,但是 只能 在节点 信号灯是绿色时 才能离开。如果信号灯是 绿色 ,你 不能 在节点等待,必须离开。

第二小的值 是 严格大于 最小值的所有值中最小的值。

例如,[2, 3, 4] 中第二小的值是 3 ,而 [2, 2, 4] 中第二小的值是 4 。
给你 n、edges、time 和 change ,返回从节点 1 到节点 n 需要的 第二短时间 。

注意:

你可以 任意次 穿过任意顶点,包括 1 和 n 。
你可以假设在 启程时 ,所有信号灯刚刚变成 绿色 。

BFS。由于 \(\textit{time}\)\(\textit{change}\) 是固定的,经过多少条边就知道花费了多少时间。因此这题本质上可以看成边权均为 1 的图,我们要求的就是 1 到 n 的严格次短路的长度,知道长度就知道花费的时间。

class Solution {

    public int secondMinimum(int n, int[][] edges, int time, int change) {
        List<Integer>[] adj = new ArrayList[n];
        for(int i = 0; i < n; ++i) adj[i] = new ArrayList<>();
        int[] dis = new int[n];
        boolean[] sec = new boolean[n];
        for(int[] edge : edges) {
            int v = edge[0] - 1, u = edge[1] - 1;
            adj[v].add(u);adj[u].add(v);
        }
        for(int i = 1; i < n; ++i) dis[i] = Integer.MAX_VALUE;
        Queue<Integer> q = new LinkedList<>();
        q.offer(0);
        while(!q.isEmpty()) {
            int head = q.poll();
            for(int u : adj[head]) {
                if(dis[u] > dis[head] + 1) {
                    dis[u] = dis[head] + 1;
                    q.offer(u);
                }
                else if(dis[u] == dis[head] || (sec[head] && dis[u] == dis[head] + 1)){
                    if(!sec[u]) q.offer(u);
                    sec[u] = true;
                }
            }
        }
        int path = dis[n - 1] + (sec[n - 1] ? 1 : 2);
        return lenToTime(path, time, change);
    }

    private int lenToTime(int len, int time, int change) {
        int cur = 0, tol = 0;
        for(int i = 0; i < len; i++) {
            tol += time;
            if(i == len - 1) break;
            int period = tol / change;
            if((period & 1) == 1) {
                tol += (period + 1) * change - tol;
            }
        }
        return tol;
    }
}

Leetcode

posted @ 2021-10-21 21:45  Jamest  阅读(63)  评论(0编辑  收藏  举报