Rust入门练习-Week1-LC387/1696/442/621/377

yyi
yyi
2023-12-29 / 0 评论 / 71 阅读 / 正在检测是否收录...
温馨提示:
本文最后更新于2024年02月16日,已超过245天没有更新,若内容或图片失效,请留言反馈。

LC377. Combination Sum IV Med

类似于一个完全背包方案数吧。DP

给定一系列数字a[i],求用它们组合为 target 的方案数,a[i]可以重复使用

状态:dp[i]表示目前已经加和到 i 的方案数

转移: dp[i] = sum(dp[i-a[j]])

边界条件:dp[0] = 1, ans = dp[target]

impl Solution {
    pub fn combination_sum4(nums: Vec<i32>, target: i32) -> i32 {
        let mut dp = vec![0; target as usize + 1];
        dp[0] = 1;
        for i in 0..target {
            for j in &nums {
                if i+j > target {
                    continue;
                }
                dp[(i+j)as usize] += dp[i as usize];
            }
        }
        dp[target as usize]
    }
}

LC621. Task Scheduler Med

题目一眼贪心,目的转化为使等待时间最少,考虑一种策略: 把任务 A-Z 按出现的次数排序,并从最多的任务(假设为 M,出现 m 次)开始排列

排列必为 M...M...M...M 这类的情况,其中.的数量为 n

只要在空缺中插入其他任务,且保证每个空缺不会出现两个相同任务,可知这类的排列必是满足题意的。

考虑有任务 X、Y、Z 在这种插入后分别剩 x、y、z 次(显然,任务 X、Y、Z 的总数量都要小于 m)

只需要扩充 每两个 M 之间的间隔,直到能插下即可,也必然符合题意,且不会使得等待时间更多。

因此问题转化为 (m-1)n > len(tasks)-m ? (m-1)(n+1) : len(tasks)

但是这个式子少考虑了如果有任务 K, k = m的情况,只要计数,并在最后累加一下即可(假设有 cnt 个任务都达到了最大值,我们先假设其中 cnt-1 个都只有最大值-1,然后按刚刚的逻辑贪心,最后补 cnt-1 即可)

所以我们要做的就是统计每个字母出现的数量并进行排序。我们同过 Rust 的 HashMap 实现该能力。

use std::collections::HashMap;

impl Solution {
    pub fn least_interval(tasks: Vec<char>, n: i32) -> i32 {
        let mut char_count = HashMap::new();
        let mut maxn = 0;
        let mut maxn_cnt = 0;
        for c in &tasks {
            let cnt = char_count.entry(*c).or_insert(0);
            *cnt += 1;
            maxn = std::cmp::max(*cnt, maxn)
        }

        for (_, &v) in &char_count {
            if v == maxn {
                maxn_cnt += 1;
            }
        }

        let lhs = (maxn-1) * n;
        let rhs = tasks.len() as i32 - maxn - maxn_cnt + 1;

        println!(" {} {} ", maxn, maxn_cnt);
        if lhs > rhs {
            return (maxn-1) * (n+1) + maxn_cnt;
        } else {
            return tasks.len() as i32;
        }

    }   
}

LC442. Find All Duplicates in an Array Med

裸的解法:直接扔进桶里,那就开个 Hashmap

use std::collections::HashMap;

impl Solution {
    pub fn find_duplicates(nums: Vec<i32>) -> Vec<i32> {
        let mut num_count = HashMap::new();
        let mut res = Vec::new();
        for num in nums {
            let cnt = num_count.entry(num).or_insert(0);
            *cnt += 1;
            if *cnt == 2 {
                res.push(num);
            }
        }
        res
    }
}

但是显然这也太没意思了,就算是面试也不会考你 Map 的使用。其实给了数据范围,开个普通的桶就行,不知道这题为啥也能算中等。。

LC1696. Jump Game VI Med

一眼 DP,先考虑最朴素的, 状态:f[i]表示已经跳到 i 的最大价值, 转移:f[i]从f[[i-k, i-1]]里更新即可,f[i] = max{f[max(i-k, 0)....i-1]} + nums[i]

边界条件:f[0] = nums[0],ans = f[nums.len()-1]

但是这东西是O(nk)的,肯定超时,考虑优化。

分析不下去了,这显然是维护前 k 个里最大的,维护一个单调线性结构即可。此结构中的f 的值需要单调减(每次用最左侧的最大值,如果右侧有一个更大的,左侧的值一定没用)。左边出右边进,单调队列即可。

use std::collections::VecDeque;

struct Node {
    cur: i32,
    val: i32,
}
impl Solution {
    pub fn max_result(nums: Vec<i32>, k: i32) -> i32 {
        let mut f = vec![0; nums.len()];
        let mut q = VecDeque::new();
        q.push_back(Node { cur: 0, val: nums[0] });
        f[0] = nums[0];
        for i in 1..nums.len() {
            while !q.is_empty() && q.front().unwrap().cur < i as i32 - k {
                q.pop_front();
            }
            f[i] = nums[i] + q.front().unwrap().val;
            while !q.is_empty() && q.back().unwrap().val < f[i] {
                q.pop_back();
            }
            q.push_back(Node { cur: i as i32, val: f[i] })
        }
        f[nums.len()-1]
    }
}

学语法中这块有个小点,就是 q.back() 这类的方法,返回的应该是个Option,我们直接 unwrap() 把 OK 中的值拿回来,如果拿不回来就直接 panic。

Option类型是Rust的一个枚举类型,它有两个值:Some(T)和None。Option类型常常用于表示可能存在也可能不存在的值。

q.back()和q.front()的返回值类型都是Option<&T>,其中T是队列中元素的类型。这是因为当队列为空时,back()和front()方法没有元素可以返回,所以它们返回的是None。当队列不为空时,back()和front()方法可以返回队列的尾部和头部元素,所以它们返回的是Some(&T)。

在处理Option类型时,除了模式匹配和unwrap()方法,还有很多其他的方法,比如unwrap_or()、unwrap_or_else()、map()、and_then()等等。

LC387 First Unique Character in a String Ez

impl Solution {
    pub fn first_uniq_char(s: String) -> i32 {
        let mut v = vec![0; 26];
        let s_chars: Vec<char> = s.chars().collect();
        for &ch in s_chars.iter() {
            v[(ch as i32 - 'a' as i32)as usize] += 1;
        }
        for (i, &ch) in s_chars.iter().enumerate() {
            if v[(ch as u32 - 'a' as u32) as usize] == 1 {
                return i as i32;
            }
        }
        -1
    }
}
0

评论 (0)

取消