LeetCode 1716. 计算力扣银行的钱 / 382. 链表随机节点(蓄水池抽样) / 1220. 统计元音字母序列的数目(动规,矩阵快速幂)

Posted Zephyr丶J

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了LeetCode 1716. 计算力扣银行的钱 / 382. 链表随机节点(蓄水池抽样) / 1220. 统计元音字母序列的数目(动规,矩阵快速幂)相关的知识,希望对你有一定的参考价值。

1716. 计算力扣银行的钱

2022.1.15 每日一题

题目描述

Hercy 想要为购买第一辆车存钱。他 每天 都往力扣银行里存钱。

最开始,他在周一的时候存入 1 块钱。从周二到周日,他每天都比前一天多存入 1 块钱。在接下来每一个周一,他都会比 前一个周一 多存入 1 块钱。

给你 n ,请你返回在第 n 天结束的时候他在力扣银行总共存了多少块钱。

示例 1:

输入:n = 4
输出:10
解释:第 4 天后,总额为 1 + 2 + 3 + 4 = 10 。

示例 2:

输入:n = 10
输出:37
解释:第 10 天后,总额为 (1 + 2 + 3 + 4 + 5 + 6 + 7) + (2 + 3 + 4) = 37 。注意到第二个星期一,Hercy 存入 2 块钱。

示例 3:

输入:n = 20
输出:96
解释:第 20 天后,总额为 (1 + 2 + 3 + 4 + 5 + 6 + 7) + (2 + 3 + 4 + 5 + 6 + 7 + 8) + (3 + 4 + 5 + 6 + 7 + 8) = 96 。

提示:

1 <= n <= 1000

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/calculate-money-in-leetcode-bank
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

简单模拟

class Solution 
    public int totalMoney(int n) 
        int cycle = n / 7;
        int mod = n % 7;
        int base = (1 + 7) * 7 / 2;
        int ans = 0;
        for(int i = 0; i < cycle; i++)
            ans += base;
            base += 7;
        
        for(int i = 0; i < mod; i++)
            ans += cycle + i + 1;
        
        return ans;
    

382. 链表随机节点

2022.1.16 每日一题

题目描述

给你一个单链表,随机选择链表的一个节点,并返回相应的节点值。每个节点 被选中的概率一样 。

实现 Solution 类:

Solution(ListNode head) 使用整数数组初始化对象。
int getRandom() 从链表中随机选择一个节点并返回该节点的值。链表中所有节点被选中的概率相等。

示例:


输入
[“Solution”, “getRandom”, “getRandom”, “getRandom”, “getRandom”, “getRandom”]
[[[1, 2, 3]], [], [], [], [], []]
输出
[null, 1, 3, 2, 2, 3]
解释
Solution solution = new Solution([1, 2, 3]);
solution.getRandom(); // 返回 1
solution.getRandom(); // 返回 3
solution.getRandom(); // 返回 2
solution.getRandom(); // 返回 2
solution.getRandom(); // 返回 3
// getRandom() 方法应随机返回 1、2、3中的一个,每个元素被返回的概率相等。

提示:

链表中的节点数在范围 [1, 10^4] 内
-10^4 <= Node.val <= 10^4
至多调用 getRandom 方法 10^4 次

进阶:

如果链表非常大且长度未知,该怎么处理?
你能否在不使用额外空间的情况下解决此问题?

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/linked-list-random-node
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

因为只让返回值,就很简单了

/**
 * Definition for singly-linked list.
 * public class ListNode 
 *     int val;
 *     ListNode next;
 *     ListNode() 
 *     ListNode(int val)  this.val = val; 
 *     ListNode(int val, ListNode next)  this.val = val; this.next = next; 
 * 
 */
class Solution 
    //感觉吧,因为要使用整数数组初始化对象,所以挺简单的
    //整数数组不算额外空间
    //就把每个数组里存放一个当前结点的指针就可以了
    int[] arr;
    int len;
    Random rd = new Random();
    public Solution(ListNode head) 
        int idx = 0;
        ListNode temp = head;
        while(temp != null)
            idx++;
            temp = temp.next;
        
        arr = new int[idx];
        temp = head;
        idx = 0;
        while(temp != null)
            arr[idx++] = temp.val;
            temp = temp.next;
        
        len = idx;
    
    
    public int getRandom() 
        int t = rd.nextInt(len);
        return arr[t];
    


/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(head);
 * int param_1 = obj.getRandom();
 */

还以为创建的数组不算额外空间呢,原来是要完全不使用任何空间
蓄水池抽样,从0到列表长度添加结点,每次加都会进行抽样,如果抽到0,那么就返回该结点
这样可以保证每个结点抽取到的概率都是1/n

水塘抽样由于空间小,时间复杂度低,可以用于大数据流中的随机抽样问题。

水塘抽样,适用于非常大的数据量,一般是流式的数据,你不知道大小有多少个,随机选取多个元素,这些被选取的元素放在一个池子中,随时有可能返回这个池子中的数。比如,在大数据领域,数据一直在处理,但是,在某个时间节点需要随机返回 5 个已经处理过的数据,我们就可以声明一个大小为 5 的池子来处理。

/**
 * Definition for singly-linked list.
 * public class ListNode 
 *     int val;
 *     ListNode next;
 *     ListNode() 
 *     ListNode(int val)  this.val = val; 
 *     ListNode(int val, ListNode next)  this.val = val; this.next = next; 
 * 
 */
class Solution 
    //传说中的蓄水池抽样
    //如果抽不到就一直抽
    //每次只有抽到0才返回当前结点
    //每次抽取都需要遍历链表

    ListNode head;
    Random rd;

    public Solution(ListNode head) 
        this.head = head;
        rd = new Random();
    
    
    public int getRandom() 
        int idx = 1;
        int ans = 0;
        ListNode temp = head;
        while(temp != null)
            if(rd.nextInt(idx) == 0)
                ans = temp.val;
            temp = temp.next;
            idx++;
        
        return ans;
    


/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(head);
 * int param_1 = obj.getRandom();
 */

1220. 统计元音字母序列的数目

2022.1.17 每日一题

题目描述

给你一个整数 n,请你帮忙统计一下我们可以按下述规则形成多少个长度为 n 的字符串:

字符串中的每个字符都应当是小写元音字母(‘a’, ‘e’, ‘i’, ‘o’, ‘u’)
每个元音 ‘a’ 后面都只能跟着 ‘e’
每个元音 ‘e’ 后面只能跟着 ‘a’ 或者是 ‘i’
每个元音 ‘i’ 后面 不能 再跟着另一个 ‘i’
每个元音 ‘o’ 后面只能跟着 ‘i’ 或者是 ‘u’
每个元音 ‘u’ 后面只能跟着 ‘a’

由于答案可能会很大,所以请你返回 模 10^9 + 7 之后的结果。

示例 1:

输入:n = 1
输出:5
解释:所有可能的字符串分别是:“a”, “e”, “i” , “o” 和 “u”。

示例 2:

输入:n = 2
输出:10
解释:所有可能的字符串分别是:“ae”, “ea”, “ei”, “ia”, “ie”, “io”, “iu”, “oi”, “ou” 和 “ua”。

示例 3:

输入:n = 5
输出:68

提示:

1 <= n <= 2 * 10^4

来源:力扣(LeetCode)
链接:https://leetcode-cn.com/problems/count-vowels-permutation
著作权归领扣网络所有。商业转载请联系官方授权,非商业转载请注明出处。

思路

一个简单的动态规划
可以用矩阵快速幂写

class Solution 
    int MOD = (int)1e9 + 7;
    public int countVowelPermutation(int n) 
        //感觉像那种状态机转移的方法
        //是不是动态规划
        //0 1 2 3 4 分别代表a e i o u结尾
        //

        int[][] f = new int[n][5];
        for(int i = 0; i < 5; i++)
            f[0][i] = 1;
        
        for(int i = 1; i < n; i++)
            f[i][0] = ((f[i - 1][1] + f[i - 1][2]) % MOD + f[i - 1][4]) % MOD;
            f[i][1] = (f[i - 1][0] + f[i - 1][2]) % MOD;
            f[i][2] = (f[i - 1][1] + f[i - 1][3]) % MOD;
            f[i][3] = f[i - 1][2];
            f[i][4] = (f[i - 1][2] + f[i - 1][3]) % MOD; 
        
        int ans = 0;
        for(int i = 0; i < 5; i++)
            ans = (ans + f[n - 1][i]) % MOD;
        
        return ans;
    

以上是关于LeetCode 1716. 计算力扣银行的钱 / 382. 链表随机节点(蓄水池抽样) / 1220. 统计元音字母序列的数目(动规,矩阵快速幂)的主要内容,如果未能解决你的问题,请参考以下文章

快乐水题1716. 计算力扣银行的钱

快乐水题1716. 计算力扣银行的钱

《LeetCode之每日一题》:267.计算力扣银行的钱

LeetCode Daily 12

leetcode-简易银行系统

LeetCode 2100. 适合打劫银行的日子