Solving shuffle the array problem on leetcode in Rust - rust

fn shuffle(nums: Vec<i32>, n: i32) -> Vec<i32> {
let mut res: Vec<i32>;
let mut i = 0;
while i < n {
res.push(nums[i]);
res.push(nums[n + i]);
i += 1;
}
res
}
When I try to index the nums array to get a value at [i], I get this error:
the type [i32] cannot be indexed by i32
the trait SliceIndex<[i32]> is not implemented for i32
required because of the requirements on the impl of Index<i32> for Vec<i32>
Any ideas how to solve this?

You can only index Vec using usizes, so you have to cast your i32s to usizes in order to index into nums:
fn shuffle(nums: Vec<i32>, n: i32) -> Vec<i32> {
let mut res = Vec::new();
let mut i = 0;
while i < n {
res.push(nums[i as usize]);
res.push(nums[(n + i) as usize]);
i += 1;
}
res
}
playground

Related

Mutable borrow occurs here [E0502]

How can I correct this behavior ?
P.S Now I am trying to implement a search for the number of page_faults when using the FIFO algorithm
fn page_fault(capacity: i32, n: i32, pages: &[i32]) -> i32 {
let mut s: HashSet<i32> = HashSet::new();
let mut indexes: VecDeque<i32> = VecDeque::new();
let mut page_faults: i32 = 0;
for i in 0..n {
if (s.len() as i32) < capacity {
if s.contains(&pages[(i) as usize]) {
s.insert(pages[(i) as usize]);
page_faults += 1;
indexes.insert(i as usize, pages[(i) as usize])
}
}
else {
if s.contains(&pages[(i) as usize]) {
let val = indexes.front();
indexes.pop_front();
s.remove(&val.unwrap());
s.insert(pages[(i) as usize]);
indexes.push_back(pages[(i) as usize]);
page_faults += 1;
}
}
}
return page_faults;
}
Terminal:
let val = indexes.front();
--------------- immutable borrow occurs here
indexes.pop_front();
^^^^^^^^^^^^^^^^^^^ mutable borrow occurs here
s.remove(&val.unwrap());
--- immutable borrow later used here
Calling indexes.front() seems redundant to me. You can simply use the result of indexes.pop_front() and assign it to a variable. So you can replace these two lines:
let val = indexes.front();
indexes.pop_front();
With this line:
let val = indexes.pop_front();
When calling indexes.front you are keeping a reference to it (&self), it can be easily solved by unwraping inmediatly and dereferencing it so the i32 is copied. Then the reference is freed.
use std::collections::VecDeque;
use std::collections::HashSet;
fn page_fault(capacity: i32, n: i32, pages: &[i32]) -> i32 {
let mut s: HashSet<i32> = HashSet::new();
let mut indexes: VecDeque<i32> = VecDeque::new();
let mut page_faults: i32 = 0;
for i in 0..n {
if (s.len() as i32) < capacity {
if s.contains(&pages[(i) as usize]) {
s.insert(pages[(i) as usize]);
page_faults += 1;
indexes.insert(i as usize, pages[(i) as usize])
}
}
else {
if s.contains(&pages[(i) as usize]) {
let val = *indexes.front().unwrap();
indexes.pop_front();
s.remove(&val);
s.insert(pages[(i) as usize]);
indexes.push_back(pages[(i) as usize]);
page_faults += 1;
}
}
}
return page_faults;
}
Playground

Mutable borrow inside loop

I have a vector of tuples, each containing two strings. I want to transfer (one of) the two strings as a mutable reference into a hashmap. The other string is also transferred, but does not have to be mutable. The background is that I want to overwrite one string with the value of the other one later.
Given the following code:
use std::collections::HashMap;
fn main() {
let mut foo = String::from("foo");
let mut bar = String::from("bar");
let mut v = vec![(foo, &mut bar)];
let mut counter: HashMap<&str, (&str, &mut String, u8)> = HashMap::new();
create_counter(&mut v, &mut counter);
}
fn create_counter<'a>(
rows: &'a mut Vec<(String, &'a mut String)>,
counter: &mut HashMap<&'a str, (&'a str, &'a mut String, u8)>,
) {
let mut skip_count = 0;
let len = rows.len();
for i in 0..len {
if i == len - 1 {
break;
}
if skip_count > 0 {
skip_count -= 1;
continue;
}
let r = rows[i..i + 3].as_mut();
if r[0].0 == r[1].0 && r[0].1 != r[1].1 {
if r.len() == 2 || r[0].0 != r[2].0 {
counter.entry(&r[0].0).or_insert((r[1].1, &mut r[0].1, 0)).2 += 1;
skip_count = 1;
} else {
skip_count = 2;
}
}
}
}
Unfortunately the borrow checker does not allow this and gives me two error messages:
cannot borrow `*rows` as mutable more than once at a time
cannot borrow `r[_].1` as mutable because it is also borrowed as immutable
I understand the problem, but unfortunately I have no idea how best to solve it.
Can someone please help me to solve these two problems?
Playground Link

How to have the .max() return the i32 datatype?

I have the following code:
impl Solution {
pub fn max_sliding_window(nums: Vec<i32>, k: i32) -> Vec<i32> {
let mut result = vec![];
for i in 0..nums.len() as i32 - (k - 1) {
//println!("{}", nums[i as usize..(i + k) as usize].iter().max());
result.push(nums[i as usize..(i + k) as usize].iter().max());
}
return result;
}
}
And I want to return the max value of each k sized window starting from the beginning of the nums vector to the end. However, the .iter().max() form is returning a std::option::Option type and not a i32 type. I also tried as i32 but that is not allowed. How to fix this?
max() returns an Option because there is no sensible value to return in the case of an empty iterator.
You need to deal with the Option and provide something reasonable in this case. For example 0:
pub fn max_sliding_window(nums: Vec<i32>, k: i32) -> Vec<i32> {
let mut result = vec![];
for i in 0..nums.len() as i32 - (k - 1) {
result.push(
nums[i as usize..(i + k) as usize]
.iter()
.max()
.copied() // because the iterator is over &i32 and you need i32
.unwrap_or(0),
);
}
return result;
}
n.b. as Denys Séguret commented above you also need to properly handle the case where k is negative: your code will panic as written.

How to fix rust operations not working as expected?

I have implemented a simple command-line calculator in Rust. The add function acts as normal but the subtract, multiply, and divide functions don't work. The rest of the code is on GitHub: https://github.com/henryboisdequin/rust-calculator.
calc.rs
impl Calc {
pub fn add(arr: Vec<i64>) -> f64 {
let mut total: f64 = 0.0;
for num in arr {
total += num as f64;
}
total
}
pub fn sub(arr: Vec<i64>) -> f64 {
let mut total: f64 = 0.0;
for num in arr {
total -= num as f64;
}
total
}
pub fn mul(arr: Vec<i64>) -> f64 {
let mut total: f64 = 0.0;
for num in arr {
total *= num as f64;
}
total
}
pub fn div(arr: Vec<i64>) -> f64 {
let mut total: f64 = 0.0;
for num in arr {
total /= num as f64;
}
total
}
}
Instead of having your functions take Vec<i64>, I would instead suggest &[i64], or even &[f64] to avoid the as f64. This wouldn't really break your existing code, as you can just borrow a Vec<i64>, to have it auto dereference into &[i64].
You can simplify add() by using sum(), and mul() by using product().
pub fn add(arr: &[i64]) -> f64 {
arr.iter().map(|&x| x as f64).sum()
}
pub fn mul(arr: &[i64]) -> f64 {
arr.iter().map(|&x| x as f64).product()
}
You can similarly simplify sub() and div() with next() and then fold().
pub fn sub(arr: &[i64]) -> f64 {
let mut it = arr.iter().map(|&x| x as f64);
it.next()
.map(|x| it.fold(x, |acc, x| acc - x))
.unwrap_or(0.0)
}
pub fn div(arr: &[i64]) -> f64 {
let mut it = arr.iter().map(|&x| x as f64);
it.next()
.map(|x| it.fold(x, |acc, x| acc / x))
.unwrap_or(0.0)
}
You can even simplify them further, by using fold_first(). However that is currently experimental and nightly only. Instead you can use fold1() from the itertools crate, or reduce() from the reduce crate.
// itertools = "0.10"
use itertools::Itertools;
pub fn sub(arr: &[i64]) -> f64 {
arr.iter().map(|&x| x as f64).fold1(|a, b| a - b).unwrap_or(0.0)
}
pub fn div(arr: &[i64]) -> f64 {
arr.iter().map(|&x| x as f64).fold1(|a, b| a / b).unwrap_or(0.0)
}
You can even replace the closures with Sub::sub and Div::div.
// itertools = "0.10"
use itertools::Itertools;
use std::ops::{Div, Sub};
pub fn sub(arr: &[i64]) -> f64 {
arr.iter().map(|&x| x as f64).fold1(Sub::sub).unwrap_or(0.0)
}
pub fn div(arr: &[i64]) -> f64 {
arr.iter().map(|&x| x as f64).fold1(Div::div).unwrap_or(0.0)
}
Siguza helped me fix this problem by specifying that my addition function only works because addition is commutative but the other operations are failing because they are not.
Here is the right code:
pub struct Calc;
impl Calc {
pub fn add(arr: Vec<i64>) -> f64 {
let mut total: f64 = 0.0;
for num in arr {
total += num as f64;
}
total
}
pub fn sub(arr: Vec<i64>) -> f64 {
let mut total: f64 = arr[0] as f64;
let mut counter = 0;
while counter != arr.len() - 1 {
total -= arr[counter + 1] as f64;
counter += 1;
}
total
}
pub fn mul(arr: Vec<i64>) -> f64 {
let mut total: f64 = arr[0] as f64;
let mut counter = 0;
while counter != arr.len() - 1 {
total *= arr[counter + 1] as f64;
counter += 1;
}
total
}
pub fn div(arr: Vec<i64>) -> f64 {
let mut total: f64 = arr[0] as f64;
let mut counter = 0;
while counter != arr.len() - 1 {
total /= arr[counter + 1] as f64;
counter += 1;
}
total
}
}
For the operations excluding 0, instead of assigning the total to 0.0, I assigned the total to the first element of the given array and -/*// the total with the rest of the elements in the array.

error: non-scalar cast: `core::option::Option<i32>` as `usize`

I am new to Rust. My code is given below:
use std::*;
fn DFS(A: i32, grid: &mut [[i32; 500]; 500], visited: &mut [i32; 500]) -> (usize, usize) {
let mut s = Vec::new();
s.push(A);
visited[A as usize] = 1;
let mut flag;
let mut max_height = 0;
let mut ans_vertex: usize = A as usize;
let mut x;
'outer: while let Some(top) = s.pop() {
s.push(top);
x = top as usize;
flag = 0;
'inner: for i in 1..500 {
if visited[grid[x][i] as usize] == 0 && grid[x][i] != 0 {
flag = 1;
s.push(grid[x][i]);
visited[grid[x][i] as usize] = 1;
break 'outer;
}
}
if s.len() > max_height {
max_height = s.len();
ans_vertex = s.pop() as usize;
}
if flag != 0 {
s.pop();
}
}
println!("{}, {}", ans_vertex, max_height);
return (ans_vertex, max_height);
}
fn fc(grid: &mut [[i32; 500]; 500]) {
for i in 1..500 {
for j in 1..500 {
grid[i][j] = 0;
}
}
grid[1][2] = 1;
grid[2][1] = 1;
grid[2][3] = 1;
grid[3][2] = 1;
grid[3][4] = 1;
grid[4][3] = 1;
}
fn main() {
let mut visited: [i32; 500] = [0; 500];
let mut grid: [[i32; 500]; 500] = [[0; 500]; 500];
fc(&mut grid);
let B = DFS(1, &mut grid, &mut visited);
println!("{}", B.0);
}
I already tried changing usize to u32 and other types, but I'm not getting any results. When I run rustc newdia.rs, it shows:
newdia.rs:26:17: 26:33 error: non-scalar cast: `core::option::Option<i32>` as `usize`
newdia.rs:26 ans_vertex = s.pop() as usize;
^~~~~~~~~~~~~~~~
error: aborting due to previous error
Vec::pop() returns an Option<T> because if the Vec is empty, there's no value present to pop. If you're sure your Vec contains atleast 1 value before you call Vec::pop(), you can use Option::unwrap(), which will convert your Option<i32> to i32 (and panic if Vec::pop returned None because the Vec was empty).
ans_vertex = s.pop().unwrap() as usize;
You can also choose to handle the cases differently using match or if let:
if let Some(popped) = s.pop() {
// Successfully popped `popped`. `popped` here is an i32.
} else {
// `s` was empty.
}

Resources