Rust每日一练(leetDay0001) 两数之和、两数相加、最长子串

简介: Rust每日一练(leetDay0001) 两数之和、两数相加、最长子串

1. 两数之和 Two Sum


给定一个整数数组 nums 和一个整数目标值 target,请你在该数组中找出 和为目标值 target  的那 两个 整数,并返回它们的数组下标。


你可以假设每种输入只会对应一个答案。但是,数组中同一个元素在答案里不能重复出现。


你可以按任意顺序返回答案。


示例 1:

输入:nums = [2,7,11,15], target = 9

输出:[0,1]

解释:因为 nums[0] + nums[1] == 9 ,返回 [0, 1] 。


示例 2:

输入:nums = [3,2,4], target = 6

输出:[1,2]


示例 3:

输入:nums = [3,3], target = 6

输出:[0,1]


提示:

   2 <= nums.length <= 10^4

   -10^9 <= nums[i] <= 10^9

   -10^9 <= target <= 10^9

   只会存在一个有效答案


进阶:你可以想出一个时间复杂度小于 O(n^2) 的算法吗?


代码1: 暴力枚举

fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> {
    let n = nums.len();
    for i in 0..n {
        for j in i+1..n {
            if nums[i] + nums[j] == target {
                return vec![i as i32, j as i32];
            }
        }
    }
    vec![]
}
fn main() {
    let nums = [2, 7, 11, 15];
    let target = 9;
    println!("{:?}", two_sum((&nums).to_vec(), target));
    let nums = [3, 2, 4];
    let target = 6;
    println!("{:?}", two_sum((&nums).to_vec(), target));
    let nums = [3, 3];
    println!("{:?}", two_sum((&nums).to_vec(), target));
}

代码2: 二分查找

fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> {
    let n = nums.len();
    for i in 0..n {
        let complement = target - nums[i];
        if let Ok(j) = nums.binary_search(&complement) {
            if i != j {
                return vec![i as i32, j as i32];
            }
        }
    }
    vec![]
}
fn main() {
    let nums = [2, 7, 11, 15];
    let target = 9;
    println!("{:?}", two_sum((&nums).to_vec(), target));
    let nums = [3, 2, 4];
    let target = 6;
    println!("{:?}", two_sum((&nums).to_vec(), target));
    let nums = [3, 3];
    println!("{:?}", two_sum((&nums).to_vec(), target));
}


代码3: 哈希表

use std::collections::HashMap;
fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> {
    let mut map = HashMap::new();
    for (i, num) in nums.iter().enumerate() {
        let complement = target - num;
        if let Some(j) = map.get(&complement) {
            return vec![*j as i32, i as i32];
        }
        map.insert(num, i);
    }
    vec![]
}
fn main() {
    let nums = [2, 7, 11, 15];
    let target = 9;
    println!("{:?}", two_sum((&nums).to_vec(), target));
    let nums = [3, 2, 4];
    let target = 6;
    println!("{:?}", two_sum((&nums).to_vec(), target));
    let nums = [3, 3];
    println!("{:?}", two_sum((&nums).to_vec(), target));
}


数组 + 哈希表

fn two_sum(nums: &[i32], target: i32) -> Vec<i32> {
    let mut imap = std::collections::HashMap::new();
    for (i, num) in nums.iter().enumerate() {
        let two = target - num;
        if let Some(&j) = imap.get(&two) {
            return vec![j as i32, i as i32];
        }
        imap.insert(num, i);
    }
    vec![]
}
fn main() {
    let nums = [2, 7, 11, 15];
    let target = 9;
    println!("{:?}", two_sum(&nums, target));
    let nums = [3, 2, 4];
    let target = 6;
    println!("{:?}", two_sum(&nums, target));
    let nums = [3, 3];
    println!("{:?}", two_sum(&nums, target));
}


代码4: 排序+双指针

fn two_sum(nums: Vec<i32>, target: i32) -> Vec<i32> {
    let mut nums = nums;
    let n = nums.len();
    for i in 0..n {
        nums[i] = nums[i].clone() as i32;
    }
    let mut pairs: Vec<(i32, usize)> = nums.iter()
        .enumerate()
        .map(|(i, &x)| (x, i))
        .collect();
    pairs.sort_unstable();
    let (mut i, mut j) = (0, n - 1);
    while i < j {
        let sum = pairs[i].0 + pairs[j].0;
        if sum == target {
            let (index1, index2) = (pairs[i].1 as i32, pairs[j].1 as i32);
            return vec![index1, index2];
        } else if sum < target {
            i += 1;
        } else {
            j -= 1;
        }
    }
    vec![]
}
fn main() {
    let nums = [2, 7, 11, 15];
    let target = 9;
    println!("{:?}", two_sum((&nums).to_vec(), target));
    let nums = [3, 2, 4];
    let target = 6;
    println!("{:?}", two_sum((&nums).to_vec(), target));
    let nums = [3, 3];
    println!("{:?}", two_sum((&nums).to_vec(), target));
}

输出:

[0, 1]

[1, 2]

[0, 1]


2. 两数相加 Add Two Numbers


给你两个 非空 的链表,表示两个非负的整数。它们每位数字都是按照 逆序 的方式存储的,并且每个节点只能存储 一位 数字。


请你将两个数相加,并以相同形式返回一个表示和的链表。


你可以假设除了数字 0 之外,这两个数都不会以 0 开头。


示例 1:

f8b428c94d52e0986b7d4b5a647b12e6.jpeg

输入:l1 = [2,4,3], l2 = [5,6,4]

输出:[7,0,8]

解释:342 + 465 = 807.


示例 2:

输入:l1 = [0], l2 = [0]

输出:[0]


示例 3:

输入:l1 = [9,9,9,9,9,9,9], l2 = [9,9,9,9]

输出:[8,9,9,9,0,0,0,1]


提示:

   每个链表中的节点数在范围 [1, 100] 内

   0 <= Node.val <= 9

   题目数据保证列表表示的数字不含前导零


代码1: 模拟竖式加法


use std::fmt;
struct ListNode {
    data: i32,
    next: Option<Box<ListNode>>,
}
impl ListNode {
    fn new(data: i32) -> Self {
        ListNode { data, next: None }
    }
    fn build(list: &[i32]) -> Option<Box<ListNode>> {
        let mut head = None;
        for i in (0..list.len()).rev() {
            head = Some(Box::new(ListNode {
                data: list[i],
                next: head,
            }));
        }
        head
    }
}
impl fmt::Debug for ListNode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut p = Some(self);
        while let Some(node) = p {
            write!(f, "{}->", node.data)?;
            p = node.next.as_ref().map(|x| x.as_ref());
        }
        write!(f, "<nil>")
    }
}
fn add_two_numbers(l1: Option<Box<ListNode>>, l2: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
    let mut dummy_head = ListNode::new(0);
    let (mut p1, mut p2, mut curr) = (l1, l2, &mut dummy_head);
    let mut carry = 0;
    while p1.is_some() || p2.is_some() || carry != 0 {
        let mut sum = carry;
        if let Some(node) = p1 {
            sum += node.data;
            p1 = node.next;
        }
        if let Some(node) = p2 {
            sum += node.data;
            p2 = node.next;
        }
        carry = sum / 10;
        curr.next = Some(Box::new(ListNode::new(sum % 10)));
        curr = curr.next.as_mut().unwrap();
    }
    dummy_head.next
}
fn main() {
    let l1 = ListNode::build(&[2, 4, 3]);
    let l2 = ListNode::build(&[5, 6, 4]);
    println!("{:?}", l1);
    println!("{:?}", l2);
    println!("{:?}", add_two_numbers(l1, l2));
    let l1 = ListNode::build(&[9,9,9,9,9,9,9]);
    let l2 = ListNode::build(&[9,9,9,9]);
    println!("{:?}", l1);
    println!("{:?}", l2);
    println!("{:?}", add_two_numbers(l1, l2));
}


代码2: 模拟竖式加法2

use std::fmt;
struct ListNode {
    data: i32,
    next: Option<Box<ListNode>>,
}
impl ListNode {
    fn new(data: i32) -> Self {
        ListNode { data, next: None }
    }
    fn build(list: &[i32]) -> Option<Box<ListNode>> {
        let mut head = None;
        for i in (0..list.len()).rev() {
            head = Some(Box::new(ListNode {
                data: list[i],
                next: head,
            }));
        }
        head
    }
}
impl fmt::Debug for ListNode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut p = Some(self);
        while let Some(node) = p {
            write!(f, "{}->", node.data)?;
            p = node.next.as_ref().map(|x| x.as_ref());
        }
        write!(f, "<nil>")
    }
}
fn add_two_numbers(l1: Option<Box<ListNode>>, l2: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
    let mut dummy_head = ListNode::new(0);
    let mut p = &mut dummy_head;
    let mut p1 = l1.as_ref();
    let mut p2 = l2.as_ref();
    let mut carry = 0;
    while p1.is_some() || p2.is_some() {
        let mut sum = carry;
        if let Some(node) = p1 {
            sum += node.data;
            p1 = node.next.as_ref();
        }
        if let Some(node) = p2 {
            sum += node.data;
            p2 = node.next.as_ref();
        }
        carry = sum / 10;
        p.next = Some(Box::new(ListNode::new(sum % 10)));
        p = p.next.as_mut().unwrap();
    }
    if carry > 0 {
        p.next = Some(Box::new(ListNode::new(carry)));
    }
    dummy_head.next
}
fn main() {
    let l1 = ListNode::build(&[2, 4, 3]);
    let l2 = ListNode::build(&[5, 6, 4]);
    println!("{:?}", l1);
    println!("{:?}", l2);
    println!("{:?}", add_two_numbers(l1, l2));
    let l1 = ListNode::build(&[9,9,9,9,9,9,9]);
    let l2 = ListNode::build(&[9,9,9,9]);
    println!("{:?}", l1);
    println!("{:?}", l2);
    println!("{:?}", add_two_numbers(l1, l2));
}


代码3: 递归法

use std::fmt;
struct ListNode {
    data: i32,
    next: Option<Box<ListNode>>,
}
impl ListNode {
    fn new(data: i32) -> Self {
        ListNode { data, next: None }
    }
    fn build(list: &[i32]) -> Option<Box<ListNode>> {
        let mut head = None;
        for i in (0..list.len()).rev() {
            head = Some(Box::new(ListNode {
                data: list[i],
                next: head,
            }));
        }
        head
    }
}
impl fmt::Debug for ListNode {
    fn fmt(&self, f: &mut fmt::Formatter) -> fmt::Result {
        let mut p = Some(self);
        while let Some(node) = p {
            write!(f, "{}->", node.data)?;
            p = node.next.as_ref().map(|x| x.as_ref());
        }
        write!(f, "<nil>")
    }
}
fn add_two_numbers(l1: Option<Box<ListNode>>, l2: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
    add_helper(l1.as_ref(), l2.as_ref(), 0)
}
fn add_helper(l1: Option<&Box<ListNode>>, l2: Option<&Box<ListNode>>, carry: i32) -> Option<Box<ListNode>> {
    if l1.is_none() && l2.is_none() && carry == 0 {
        return None;
    }
    let mut sum = carry;
    if let Some(node) = l1 {
        sum += node.data;
    }
    if let Some(node) = l2 {
        sum += node.data;
    }
    let mut node = ListNode::new(sum % 10);
    node.next = add_helper(l1.map(|x| x.next.as_ref()).flatten(), l2.map(|x| x.next.as_ref()).flatten(), sum / 10);
    Some(Box::new(node))
}
fn main() {
    let l1 = ListNode::build(&[2, 4, 3]);
    let l2 = ListNode::build(&[5, 6, 4]);
    println!("{:?}", l1);
    println!("{:?}", l2);
    println!("{:?}", add_two_numbers(l1, l2));
    let l1 = ListNode::build(&[9,9,9,9,9,9,9]);
    let l2 = ListNode::build(&[9,9,9,9]);
    println!("{:?}", l1);
    println!("{:?}", l2);
    println!("{:?}", add_two_numbers(l1, l2));
}


输出:

2->4->3-><nil>

5->6->4-><nil>

7->0->8-><nil>

9->9->9->9->9->9->9-><nil>

9->9->9->9-><nil>

8->9->9->9->0->0->0->1-><nil>




3. 无重复字符的最长子串 Longest substring without repeating characters


给定一个字符串 s ,请你找出其中不含有重复字符的 最长子串 的长度。


示例 1:

输入: s = "abcabcbb"

输出: 3  

解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。


示例 2:

输入: s = "bbbbb"

输出: 1

解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。


示例 3:

输入: s = "pwwkew"

输出: 3

解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。

    请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。


提示:

   0 <= s.length <= 5 * 10^4

   s 由英文字母、数字、符号和空格组成


代码1: 滑动窗口

use std::collections::HashSet;
fn length_of_longest_substring(s: String) -> i32 {
    let s = s.as_bytes();
    let mut set = HashSet::new();
    let mut left = 0;
    let mut right = 0;
    let mut max_len = 0;
    while right < s.len() {
        if !set.contains(&s[right]) {
            set.insert(s[right]);
            right += 1;
            max_len = max_len.max(right - left);
        } else {
            set.remove(&s[left]);
            left += 1;
        }
    }
    max_len as i32
}
fn main() {
    let str = String::from("abcabcbb");
    println!("{}", length_of_longest_substring(str));
    let str = "bbbbb".to_string();
    println!("{}", length_of_longest_substring(str));
    let str = "pwwkew".to_string();
    println!("{}", length_of_longest_substring(str));
}



代码2: 动态规划

fn length_of_longest_substring(s: String) -> i32 {
    let s = s.as_bytes();
    let mut dp = vec![0; s.len()];
    let mut max_len = 0;
    for i in 0..s.len() {
        if i == 0 || !s[0..i].contains(&s[i]) {
            dp[i] = if i == 0 { 1 } else { dp[i-1] + 1 };
        } else {
            let last_pos = s[0..i].iter().rposition(|&x| x == s[i]).unwrap();
            dp[i] = i - 1 - last_pos + 1;
        }
        max_len = max_len.max(dp[i]);
    }
    max_len as i32
}
fn main() {
    let str = String::from("abcabcbb");
    println!("{}", length_of_longest_substring(str));
    let str = "bbbbb".to_string();
    println!("{}", length_of_longest_substring(str));
    let str = "pwwkew".to_string();
    println!("{}", length_of_longest_substring(str));
}

代码3: 双指针

fn length_of_longest_substring(s: String) -> i32 {
    let s = s.as_bytes();
    let mut last_pos = vec![-1; 256];
    let mut left = 0;
    let mut right = 0;
    let mut max_len = 0;
    while right < s.len() {
        if last_pos[s[right] as usize] < left as i32 {
            last_pos[s[right] as usize] = right as i32;
            right += 1;
            max_len = max_len.max(right - left);
        } else {
            left += 1;
        }
    }
    max_len as i32
}
fn main() {
    let str = String::from("abcabcbb");
    println!("{}", length_of_longest_substring(str));
    let str = "bbbbb".to_string();
    println!("{}", length_of_longest_substring(str));
    let str = "pwwkew".to_string();
    println!("{}", length_of_longest_substring(str));
}

输出:

3

1

3

目录
相关文章
|
7月前
|
Java Go C++
Rust每日一练(Leetday0031) 解码方法、复原 IP 地址
Rust每日一练(Leetday0031) 解码方法、复原 IP 地址
68 0
Rust每日一练(Leetday0031) 解码方法、复原 IP 地址
|
7月前
|
Java Go Rust
Rust每日一练(Leetday0030) 合并有序数组、格雷编码、子集II
Rust每日一练(Leetday0030) 合并有序数组、格雷编码、子集II
90 0
Rust每日一练(Leetday0030) 合并有序数组、格雷编码、子集II
|
7月前
|
算法 Java Go
Rust每日一练(Leetday0029) 柱状图、最大矩形、扰乱字符串
Rust每日一练(Leetday0029) 柱状图、最大矩形、扰乱字符串
53 0
Rust每日一练(Leetday0029) 柱状图、最大矩形、扰乱字符串
|
7月前
|
Rust Java Go
Rust每日一练(Leetday0027) 单词搜索、删除重复项II、搜索旋转排序数组II
Rust每日一练(Leetday0027) 单词搜索、删除重复项II、搜索旋转排序数组II
63 0
Rust每日一练(Leetday0027) 单词搜索、删除重复项II、搜索旋转排序数组II
|
7月前
|
Java Go C++
Rust每日一练(Leetday0026) 最小覆盖子串、组合、子集
Rust每日一练(Leetday0026) 最小覆盖子串、组合、子集
67 0
Rust每日一练(Leetday0026) 最小覆盖子串、组合、子集
|
7月前
|
算法 Java Go
Rust每日一练(Leetday0025) 矩阵置零、搜索二维矩阵、颜色分类
Rust每日一练(Leetday0025) 矩阵置零、搜索二维矩阵、颜色分类
73 0
Rust每日一练(Leetday0025) 矩阵置零、搜索二维矩阵、颜色分类
|
7月前
|
Java Go C++
Rust每日一练(Leetday0024) 爬楼梯、简化路径、编辑距离
Rust每日一练(Leetday0024) 爬楼梯、简化路径、编辑距离
79 0
Rust每日一练(Leetday0024) 爬楼梯、简化路径、编辑距离
|
7月前
|
Java Go C++
Rust每日一练(leetDay0023) 二进制求和、左右对齐、平方根
Rust每日一练(leetDay0023) 二进制求和、左右对齐、平方根
83 0
Rust每日一练(leetDay0023) 二进制求和、左右对齐、平方根
|
7月前
|
Java Go C++
Rust每日一练(Leetday0022) 最小路径和、有效数字、加一
Rust每日一练(Leetday0022) 最小路径和、有效数字、加一
66 0
Rust每日一练(Leetday0022) 最小路径和、有效数字、加一
|
7月前
|
Python Rust Java
Rust每日一练(Leetday0020) 最后单词的长度、螺旋矩阵II、排列序列
Rust每日一练(Leetday0020) 最后单词的长度、螺旋矩阵II、排列序列
115 0
Rust每日一练(Leetday0020) 最后单词的长度、螺旋矩阵II、排列序列