Как вернуть сумму трех самых больших элементов массива?

Я пытаюсь вернуть сумму 3 самых больших чисел в таком массиве:

fn max_tri_sum(arr: &[i32]) -> i32 {
    arr.sort();
    arr[0]+arr[1]+arr[2]
}

но я продолжаю получать эту ошибку:

error[E0596]: cannot borrow `*arr` as mutable, as it is behind a `&` reference

fn max_tri_sum(arr: &[i32]) -> i32 {
                   ------ help: consider changing this to be a mutable reference: `&mut [i32]`

    arr.sort();
       ^^^ `arr` is a `&` reference, so the data it refers to cannot be borrowed as mutable

Я не должен менять arr: &[i32] на arr: &mut [i32] из-за некоторых ограничений. Итак, что я могу с этим поделать?

P.S. Я пытался клонировать arr в изменяемую переменную, но получил другие ошибки:

fn max_tri_sum(arr: &[i32]) -> i32 {
    let a: &mut [i32] = *arr.clone();
    a.sort();
    a[0]+a[1]+a[2]
}
Почему Python в конце концов умрет
Почему Python в конце концов умрет
Последние 20 лет были действительно хорошими для Python. Он прошел путь от "просто языка сценариев" до основного языка, используемого для написания...
1
0
771
2
Перейти к ответу Данный вопрос помечен как решенный

Ответы 2

Вы также можете использовать BinaryHeap для хранения трех самых больших значений и замены наименьшего значения при циклическом просмотре массива:

use std::collections::BinaryHeap;

fn max_tri_sum(arr: &[i32]) -> i32 {
    let mut heap = BinaryHeap::new();
    heap.push(-arr[0]);
    heap.push(-arr[1]);
    heap.push(-arr[2]);
    
    for e in arr[3..].iter() {
        if -e < *heap.peek().unwrap() {
            heap.pop();
            heap.push(-e);
        } 
    }
    -heap.drain().sum::<i32>()
}

Или, если вы предпочитаете вариант сортировки, вы можете преобразовать срез в вектор:

fn max_tri_sum(arr: &[i32]) -> i32 {
    let mut arr1 = arr.to_vec();
    arr1.sort_by(|a, b| b.cmp(a));
    arr1[0] + arr1[1] + arr1[2]
}

Детская площадка

Ответ принят как подходящий

В Rust у вас не может быть переменной, которая имеет как ссылку, так и изменяемую ссылку в одной и той же области видимости.

У вас есть несколько вариантов:

  • Вы можете просто сделать цикл на срезе, чтобы получить нужные значения. Что-то вроде этого (возможно, есть более элегантный способ с итераторами)
    fn max_tri_sum(arr: &[i32]) -> i32 {
    let mut maxes = [0, 0, 0];
    for &el in arr {
        if el > maxes[0] && el < maxes[1] {
            maxes[0] = el;
        } else if el > maxes[1] && el < maxes[2] {
            if maxes[1] > maxes[0] {
                maxes[0] = maxes[1];
            }
            maxes[1] = el;
        } else if el > maxes[2] {
            if maxes[2] > maxes[1] {
                maxes[1] = maxes[2];
            }
            maxes[2] = el;
        }
    }

    maxes[0] + maxes[1] + maxes[2]
    }
  • Вы можете создать новый Vec из фрагмента, а затем выполнить над ним все операции (что требует выделения, но должно подойти для небольших Vec).
    fn max_tri_sum(arr: &[i32]) -> i32 {
        let mut arr = Vec::from(arr);
        arr.sort();
        arr[0] + arr[1] + arr[2]
    }

Я также хотел бы отметить, что sort сортируется от меньшего к большему, поэтому индекс 0, 1, 2, ... будет наименьшим значением в массиве, а я не думаю, что вы хотите это сделать!

Ваша первая версия также требует выделения кучи. Лучше использовать let mut maxes = [0,0,0]; вместо vec!.

Angelicos Phosphoros 24.12.2020 20:40

@AngelicosPhosphoros Хороший вопрос! я обновлю свой ответ

ShadowMitia 26.12.2020 10:38

Другие вопросы по теме