数组 array
在 Rust 中,数组是一种固定大小的数据结构,用于存储具有相同数据类型的元素的有序集合。
“固定大小”是指数组中的元素的类型和数量确定,也就确定了整数数组的大小。
声明
数组可以在声明时指定长度,声明语法:[T; N],T为数组中元素的类型,N为元素的个数。这两个类型参数在编译时就必须确定下来,数组长度是固定的、不可变的。数组中的元素可以通过索引来访问和修改,索引从 0 开始,最大值为 N-1。
声明语法举例:
let array: [u16; 3] = [1, 2, 3];
在上面的示例中,声明了一个名为 `array` 的数组,其元素类型为 `u16`,并指定长度为 3。
也可以使用以下省略语法来初始化数组:
let array = [1, 2, 3];
在这种情况下,编译器会自动推断数组的长度,同时默认的元素类型为 `i32`。
访问
使用索引访问数组元素:
let array = [1, 2, 3]; println!("{}", array[0]); // 输出 1 println!("{}", array[1]); // 输出 2 println!("{}", array[2]); // 输出 3
使用循环遍历数组元素:
let array = [1, 2, 3]; for i in 0..array.len() { println!("{}", array[i]); }
引用 Reference
引用是 Rust 中最常见的指针类型。引用是指向其他数据类型(如数组、切片或结构)的不可变或可变引用。以下是 Rust 中引用的语法:
let array = [1, 2, 3, 4, 5]; let reference = &array;
上例创建了一个不可变的引用,并将其指向数组 `array`。由于 Rust 具有所有权模型,因此引用的生命周期必须在引用的数据所有权范围内。如果引用的数据被释放,则引用将不再有效。
在 Rust 中,数组访问需要注意一些细节。由于 Rust 非常注重内存安全,因此它限制了数组访问的类型。具体来说,数组索引必须是 usize 类型或可以转换为 usize 类型的类型。以下是 Rust 中用于数组索引的数据类型:
- usize:代表指针大小的无符号整数类型。
- isize:代表指针大小的有符号整数类型。
- u8、u16、u32、u64、u128:无符号整数类型。
- i8、i16、i32、i64、i128:有符号整数类型。
在进行数组访问时,如果使用的数据类型不是上述类型之一,则编译器将显示错误。如果数组下标超过数组范围,则会发生访问越界错误。在 Rust 中,数组访问越界是一种非常严重的错误,因为它可能会导致对未初始化或未知内存进行访问。
为了避免访问越界错误,在 Rust 中,建议使用 `get` 方法来访问数组,而不是使用直接索引:
let array = [1, 2, 3]; match array.get(4) { Some(value) => println!("{}", value), None => println!("Value not found!") }
在上面的示例中,我们使用 `get` 方法来访问数组的第 4 个元素。如果元素存在,则输出其值。如果元素不存在,则输出“Value not found!”消息。
切片 Slice
在 Rust 中,数组是栈分配的内存,因此访问数组元素的速度非常快。但是,由于它们具有固定的大小,因此不能动态添加或删除元素。在实际开发中,这通常是不够灵活的。这就是 Rust 中的切片的用武之地。
在 Rust 中,切片是一种指向数组一部分或全部元素的动态长度引用。切片可以包含任何类型的元素,因此可以作为通用的数据结构。由于切片是动态长度的,因此它们可以增长和缩小,从而提供更大的灵活性。
切片的语法与数组相似,但我们不需要在定义时指定长度。以下是 Rust 中切片声明的语法:
let array = [1, 2, 3, 4, 5]; let slice = &array[1..4];
上例创建了一个名为 `slice` 的切片,它引用了数组 `array` 的第 1、2 和 3 个元素。注意,我们使用 `&` 符号创建一个指向数组一部分元素的引用。如果我们不使用 `&`,则会将切片视为静态数组。
有了切片,就可以轻松地对其进行遍历、截取、拼接和传递给函数等操作。
示例:使用切片进行循环遍历
let array = [1, 2, 3, 4, 5]; let slice = &array[1..4]; for i in slice { println!("{}", i); }
在 Rust 中,切片不仅限于数组。我们还可以从其他集合类型(如向量)中创建切片。以下是从向量中创建切片的示例代码:
let vector = vec![1, 2, 3, 4, 5]; let slice = &vector[1..4];
Rust 的切片还可以用作返回值,以允许函数返回指向某个区域的引用而不是分配新的数据结构。这可以提高性能并减少内存使用。
总之,Rust 的数组是一种简单、高效的数据结构,适合处理固定长度的数据。如果需要处理动态大小的数据,建议使用 Vector(Vec之后再讨论)。
属性、方法和函数
len()
:返回数组的长度。
let arr = [1, 2, 3, 4, 5]; assert_eq!(arr.len(), 5);
is_empty()
:判断数组是否为空,如果长度为 0 返回 true,否则返回 false。
let arr: [i32; 0] = []; assert_eq!(arr.is_empty(), true);
first()
:返回数组的第一个元素的引用,如果数组为空返回 None。
let arr = [1, 2, 3]; assert_eq!(arr.first(), Some(&1));
first_mut()
:返回数组的第一个元素的可变引用,如果数组为空,则返回 None。
let mut arr = [1, 2, 3]; if let Some(n) = arr.first_mut() { *n *= 2; } assert_eq!(arr, [2, 2, 3]);
last()
:返回数组的最后一个元素的引用,如果数组为空返回 None。
let arr = [1, 2, 3]; assert_eq!(arr.last(), Some(&3));
last_mut()
:返回数组的最后一个元素的可变引用,如果数组为空,则返回 None。
let mut arr = [1, 2, 3]; if let Some(n) = arr.last_mut() { *n *= 2; } assert_eq!(arr, [1, 2, 6]);
get()
:通过索引获取数组元素的引用,如果索引越界返回 None。
let arr = [1, 2, 3]; assert_eq!(arr.get(1), Some(&2)); assert_eq!(arr.get(3), None);
get_mut()
:返回给定索引处的元素的可变引用,如果索引越界,则返回 None。
let mut arr = [1, 2, 3]; if let Some(n) = arr.get_mut(1) { *n *= 2; } assert_eq!(arr, [1, 4, 3]);
contains()
:判断数组是否包含指定的元素。
let arr = [1, 2, 3, 4, 5]; assert!(arr.contains(&3)); assert!(!arr.contains(&6));
starts_with()
:判断数组是否以指定的前缀开头。
let arr = [1, 2, 3, 4, 5]; assert!(arr.starts_with(&[1, 2, 3])); assert!(!arr.starts_with(&[2, 3, 4]));
ends_with()
:判断数组是否以指定的后缀结尾。
let arr = [1, 2, 3, 4, 5]; assert!(arr.ends_with(&[4, 5])); assert!(!arr.ends_with(&[3, 4, 5]));
repeat()
:创建重复指定次数的数组。
let arr = [1, 2]; let repeated: Vec<i32> = arr.repeat(3); assert_eq!(repeated, [1, 2, 1, 2, 1, 2]);
fill()
:将数组中所有元素替换为给定的值。
let mut arr = [1, 2, 3]; arr.fill(0); assert_eq!(arr, [0, 0, 0]);
swap()
:交换数组中两个元素的位置。
let mut arr = [1, 2, 3]; arr.swap(0, 2); assert_eq!(arr, [3, 2, 1]);
binary_search()
:在有序数组中搜索(二分查找算法)指定的元素,在找到元素时返回其索引,否则返回应该插入元素的位置的索引,维持数组的有序状态。
let arr = [1, 2, 3, 4, 5]; assert_eq!(arr.binary_search(&3), Ok(2)); assert_eq!(arr.binary_search(&6), Err(5)); let arr = [1, 3, 5, 7, 9]; assert_eq!(arr.binary_search(&5), Ok(2)); assert_eq!(arr.binary_search(&4), Err(2)); assert_eq!(arr.binary_search(&10), Err(5));
binary_search_by()
:在有序数组中使用指定的比较函数搜索指定的元素,在找到元素时返回其索引,否则返回应该插入元素的位置的索引,维持数组的有序状态。
let arr = ["apple", "banana", "cherry", "pear", "watermelon"]; assert_eq!(arr.binary_search_by(|&x| x.cmp("banana")), Ok(1)); assert_eq!(arr.binary_search_by(|&x| x.cmp("orange")), Err(2));
binary_search_by_key()
:在有序数组中搜索指定键的元素,在找到元素时返回其索引,否则返回应该插入元素的位置的索引,维持数组的有序状态。
let arr = [(1, "one"), (3, "three"), (5, "five"), (7, "seven"), (9, "nine")]; let result = arr.binary_search_by_key(&7, |&(key, _)| key); assert_eq!(result, Ok(3)); let arr = [(1, "apple"), (3, "banana"), (5, "cherry"), (7, "pear"), (9, "watermelon")]; assert_eq!(arr.binary_search_by_key(&5, |&(k, _)| k), Ok(2)); assert_eq!(arr.binary_search_by_key(&4, |&(k, _)| k), Err(2)); assert_eq!(arr.binary_search_by_key(&10, |&(k, _)| k), Err(5));
iter()
:返回数组的迭代器,可用于遍历数组中的元素。
let arr = [1, 2, 3]; for i in arr.iter() { println!("{}", i); } // 输出:1 2 3
iter_mut()
:返回一个可变的迭代器,可以用于遍历和修改数组中的元素。
let mut arr = [1, 2, 3]; for i in arr.iter_mut() { *i += 1; } assert_eq!(arr, [2, 3, 4]);
into_iter()
:返回一个消耗性迭代器,可对数组进行所有权转移,在迭代过程中释放数组的所有权。
let arr = [1, 2, 3]; let v: Vec<i32> = arr.into_iter().map(|x| x * 2).collect(); assert_eq!(v, vec![2, 4, 6]);
as_mut()
:返回一个可变引用的切片,可以修改数组中的元素。
let mut arr = [1, 2, 3]; let s = arr.as_mut(); s[1] = 4; assert_eq!(arr, [1, 4, 3]);
as_ptr()
:返回数组的指针。
let arr = [1, 2, 3]; let p = arr.as_ptr(); unsafe { println!("{}", *p.offset(1)); } // 输出:2
split()
:根据条件分割数组,返回一个可迭代的切片集合。
let arr = [1, 2, 3, 4, 5]; let mut splits = arr.split(|x| x % 2 == 0); let s1 = splits.next().unwrap(); let s2 = splits.next().unwrap(); let s3 = splits.next().unwrap(); assert_eq!(s1, [1]); assert_eq!(s2, [3]); assert_eq!(s3, [5]);
split_at()
:从数组中分割出两个切片,将数组分成两部分。
let arr = [1, 2, 3, 4, 5]; let (left, right) = arr.split_at(2); assert_eq!(left, [1, 2]); assert_eq!(right, [3, 4, 5]);
split_first()
:返回数组中的第一个元素。
let arr = [1, 2, 3, 4, 5]; let (first, rest) = arr.split_first().unwrap(); assert_eq!(*first, 1); assert_eq!(rest, &[2, 3, 4, 5]);
split_first_mut()
:返回一个数组的第一个可变引用。
let mut arr = [1, 2, 3, 4, 5]; let (first, rest) = arr.split_first_mut().unwrap(); *first = 0; assert_eq!(arr, [0, 2, 3, 4, 5]);
split_last()
:返回数组中的最后一个元素。
let arr = [1, 2, 3, 4, 5]; let (last, rest) = arr.split_last().unwrap(); assert_eq!(*last, 5); assert_eq!(rest, &[1, 2, 3, 4]);
split_last_mut()
:返回一个数组的最后一个可变引用。
let mut arr = [1, 2, 3, 4, 5]; let (last, rest) = arr.split_last_mut().unwrap(); *last = 0; assert_eq!(arr, [1, 2, 3, 4, 0]);
chunks()
:返回一个可迭代的切片集合,每个切片包含指定大小的元素。
let arr = [1, 2, 3, 4, 5]; let mut chunks = arr.chunks(2); let c1 = chunks.next().unwrap(); let c2 = chunks.next().unwrap(); let c3 = chunks.next().unwrap(); assert_eq!(c1, [1, 2]); assert_eq!(c2, [3, 4]); assert_eq!(c3, [5]);
chunks_mut()
:返回一个可变的可迭代切片集合,每个切片包含指定大小的元素。
let mut arr = [1, 2, 3, 4, 5]; for chunk in arr.chunks_mut(2) { chunk[0] += 1; } assert_eq!(arr, [2, 2, 4, 4, 5]);
chunks_exact()
:返回一个可迭代的切片集合,每个切片包含指定大小的元素,最后不足一个切片的部分将被忽略。
let arr = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11]; let mut chunks = arr.chunks_exact(3); let c1 = chunks.next().unwrap(); let c2 = chunks.next().unwrap(); let c3 = chunks.next().unwrap(); let c4 = chunks.next().unwrap(); assert_eq!(c1, [1, 2, 3]); assert_eq!(c2, [4, 5, 6]); assert_eq!(c3, [7, 8, 9]); assert_eq!(c4, [10, 11]);
chunks_exact_mut()
:返回可变的可迭代的切片集合,每个切片包含指定大小的元素,最后不足一个切片的部分将被忽略。
let mut arr = [1, 2, 3, 4, 5, 6, 7, 8, 9]; for chunk in arr.chunks_exact_mut(3) { chunk[0] += 1; } assert_eq!(arr, [2, 2, 4, 5, 6, 8, 7, 8, 9]);
join()
:将数组中的元素按指定的分隔符连接成一个字符串。
let arr = [1, 2, 3]; let joined = arr.join(", "); assert_eq!(joined, "1, 2, 3"); let arr = ["one", "two", "three"]; let s = arr.join(", "); assert_eq!(s, "one, two, three");
reverse()
:反转数组中元素的顺序。
let mut arr = [1, 2, 3, 4, 5]; arr.reverse(); assert_eq!(arr, [5, 4, 3, 2, 1]);
sort()
:对数组进行排序,按元素大小升序排序。
let mut arr = [3, 1, 4, 2, 5]; arr.sort(); assert_eq!(arr, [1, 2, 3, 4, 5]);
sort_by()
:对数组进行排序,按指定的比较函数进行排序。
let mut arr = ["apple", "banana", "cherry", "pear", "watermelon"]; arr.sort_by(|a, b| a.len().cmp(&b.len())); assert_eq!(arr, ["pear", "apple", "banana", "cherry", "watermelon"]);
sort_by_key()
:对数组进行排序,按指定的键进行排序。
let mut arr = [(3, "banana"), (1, "apple"), (5, "cherry"), (7, "pear"), (9, "watermelon")]; arr.sort_by_key(|&(k, _)| k); assert_eq!(arr, [(1, "apple"), (3, "banana"), (5, "cherry"), (7, "pear"), (9, "watermelon")]);
逆序排列:
fn main() { let mut nums = [3, 1, 4, 2, 5]; nums.sort(); nums.reverse(); println!("{:?}", nums); let mut nums = [3, 1, 4, 2, 5]; nums.sort_by(|a, b| b.cmp(a)); println!("{:?}", nums); }
map()
:将数组中的每个元素应用给定的函数,并返回一个新的数组。
let arr = [1, 2, 3]; let arr2 = arr.map(|n| n * 2); assert_eq!(arr2, [2, 4, 6]);
rotate_left()
:循环移动数组元素,将第一个元素移动到数组末尾。
let mut arr = [1, 2, 3, 4, 5]; arr.rotate_left(2); assert_eq!(arr, [3, 4, 5, 1, 2]);
rotate_right()
:循环移动数组元素,将最后一个元素移动到数组开头。
let mut arr = [1, 2, 3, 4, 5]; arr.rotate_right(2); assert_eq!(arr, [4, 5, 1, 2, 3]);
to_string()
:将数组转换为字符串类型。
let arr = [1, 2, 3]; let s = arr.to_string(); assert_eq!(s, "[1, 2, 3]");
to_vec()
:将数组转换为向量类型(Vec)。
1. let arr = [1, 2, 3]; 2. let vec = arr.to_vec(); 3. assert_eq!(vec, vec![1, 2, 3]);
to_slice()
:将数组转换为切片类型,并且可以指定开始和结束位置。
let arr = [1, 2, 3]; let vec = arr.to_vec(); assert_eq!(vec, vec![1, 2, 3]);
into_iter()
:返回一个将数组转换为迭代器的方法。
let arr = [1, 2, 3]; for n in arr.into_iter() { println!("{}", n); }
try_fold()
:对数组中的每个元素应用给定的函数,并且在每次应用后返回一个 Result
类型,最后将所有 Ok
类型的值聚合在一起。
let arr = ["1", "2", "three", "4", "five"]; let result = arr.try_fold(0, |acc, n| { if let Ok(num) = n.parse::<i32>() { Ok(acc + num) } else { Err(()) } }); assert_eq!(result, Err(()));
try_for_each()
:对数组中的每个元素应用给定的函数,并且在每次应用后返回一个 Result
类型,如果所有应用都成功,则返回 Ok(())
。
let arr = ["1", "2", "3"]; let result = arr.try_for_each(|n| { if n.parse::<i32>().is_ok() { Ok(()) } else { Err(()) } }); assert_eq!(result, Ok(()));
permutations()
:返回一个可迭代的集合,包含数组中所有元素的所有可能的排列组合。
let arr = [1, 2, 3]; let mut permutations = arr.permutations(); assert_eq!(permutations.next(), Some([1, 2, 3])); assert_eq!(permutations.next(), Some([1, 3, 2])); assert_eq!(permutations.next(), Some([2, 1, 3])); assert_eq!(permutations.next(), Some([2, 3, 1])); assert_eq!(permutations.next(), Some([3, 1, 2])); assert_eq!(permutations.next(), Some([3, 2, 1]));
zip()
:将两个数组压缩成一个元组的集合。
let arr1 = [1, 2, 3]; let arr2 = [4, 5, 6]; let result: Vec<_> = arr1.iter().zip(arr2.iter()).collect(); assert_eq!(result, [(1, 4), (2, 5), (3, 6)]);
windows()
:返回一个可迭代的集合,包含指定大小的滑动窗口,每个窗口的元素由数组中相邻的元素组成。
let arr = [1, 2, 3, 4, 5]; let mut windows = arr.windows(2); assert_eq!(windows.next(), Some(&[1, 2][..])); assert_eq!(windows.next(), Some(&[2, 3][..])); assert_eq!(windows.next(), Some(&[3, 4][..])); assert_eq!(windows.next(), Some(&[4, 5][..])); let arr = [1, 2, 3, 4, 5]; let mut windows = arr.windows(3); let w1 = windows.next().unwrap(); let w2 = windows.next().unwrap(); let w3 = windows.next().unwrap(); assert_eq!(w1, [1, 2, 3]); assert_eq!(w2, [2, 3, 4]); assert_eq!(w3, [3, 4, 5]); let arr = [1, 2, 3, 4, 5, 6]; let mut windows = arr.windows(3); assert_eq!(windows.next(), Some(&[1, 2, 3][..])); assert_eq!(windows.next(), Some(&[2, 3, 4][..])); assert_eq!(windows.next(), Some(&[3, 4, 5][..])); assert_eq!(windows.next(), Some(&[4, 5, 6][..])); assert_eq!(windows.next(), None);
题目实例
长度最小的子数组
题目描述:
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的连续子数组 [numsl, numsl+1, ..., numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
示例:
输入:s = 7, nums = [2,3,1,2,4,3]
输出:2
解释:子数组 [4,3] 是该条件下的长度最小的子数组。
示例:
输入:s = 4, nums = [1,4,4]
输出:1
代码:
使用array方法windows()非常方便,不用写滑动窗口的具体代码
fn min_sub_array_len(target: i32, nums: &[i32]) -> i32 { for len in 1..=nums.len() { for window in nums.windows(len) { if target == window.iter().sum::<i32>() { return len as i32; } } } 0 } fn main() { let nums = [2, 3, 1, 2, 4, 3]; println!("{}", min_sub_array_len(7, &nums)); let nums = [1, 4, 4]; println!("{}", min_sub_array_len(4, &nums)); }
暂时更新至此,Array数组还有更多的方法有待补充,一晚上习惯性地误按了三次Ctrl-Z,杯具啊