做網(wǎng)站北京公司推廣產(chǎn)品的渠道
題目
????????給定一個數(shù)組,將數(shù)組中的元素向右移動k個位置,其中k是非負(fù)數(shù)。要求如下:
????????(1)盡可能想出更多的解決方案,至少有三種不同的方法可以解決這個問題。
????????(2)使用時間復(fù)雜度為O(n)和空間復(fù)雜度為O(1)的原地算法解決這個問題。
????????示例 1:
輸入: [1, 2, 3, 4, 5, 6, 7] 和 k = 3輸出: [5, 6, 7, 1, 2, 3, 4]解釋:向右旋轉(zhuǎn)1步: [7, 1, 2, 3, 4, 5, 6]向右旋轉(zhuǎn)2步: [6, 7, 1, 2, 3, 4, 5]向右旋轉(zhuǎn)3步: [5, 6, 7, 1, 2, 3, 4]
????????示例 2:
輸入: [-8, -100, 50, 66] 和 k = 2輸出: [50, 66, -8, -100]解釋:向右旋轉(zhuǎn)1步: [66, -8, -100, 50]向右旋轉(zhuǎn)2步: [50, 66, -8, -100]
解析
????????這道題主要考察應(yīng)聘者從多個角度、多個維度分析和思考問題的能力。
????????最直接、最簡單的解決方案當(dāng)然是“暴力法”,也就是每次將數(shù)組向右移動一個元素,一共旋轉(zhuǎn)k次。向右移動一個元素,需要將最后一個元素移動到數(shù)組開頭,然后將其他元素依次右移?!氨┝Ψā钡臅r間復(fù)雜度為O(n*k),空間復(fù)雜度為O(1)。具體實現(xiàn),可參考下面的示例代碼。這里,我們使用了Rust標(biāo)準(zhǔn)庫中的rotate_right方法,它直接提供了按指定步數(shù)向右旋轉(zhuǎn)數(shù)組的功能,使得代碼更為簡潔。
fn rotate_array(arr: &mut [i32], mut k: usize) {let n_len = arr.len();k %= n_len;arr.rotate_right(k);
}fn print_array(arr: &[i32]) {for &item in arr.iter() {print!("{} ", item);}println!();
}fn main() {let mut data = [1, 2, 3, 4, 5, 6, 7];rotate_array(&mut data, 3);print_array(&data);
}
????????“暴力法”的時間復(fù)雜度較高,我們可以通過以空間換時間的方式來優(yōu)化時間復(fù)雜度。具體做法為:使用一個額外的數(shù)組來將每個元素放到正確的位置上,也就是我們把原本數(shù)組里下標(biāo)為i的元素,放到(i+k)%數(shù)組長度的位置;最后,我們把新的數(shù)組拷貝到原來的數(shù)組中。該方法的時間復(fù)雜度為O(n),空間復(fù)雜度也為O(n)。具體實現(xiàn),可參考下面的示例代碼。這里,我們使用to_vec()方法來創(chuàng)建原數(shù)組的一個拷貝,然后通過索引操作和copy_from_slice()方法來完成數(shù)據(jù)的轉(zhuǎn)移。
fn rotate_array(arr: &mut [i32], k: usize) {let n_len = arr.len();let mut data_bak = arr.to_vec();for i in 0..n_len {data_bak[(i + k) % n_len] = arr[i];}arr.copy_from_slice(&data_bak);
}fn print_array(arr: &[i32]) {for &item in arr {print!("{} ", item);}println!();
}fn main() {let mut data = vec![1, 2, 3, 4, 5, 6, 7];rotate_array(&mut data, 3);print_array(&data);
}
????????實際上,解決旋轉(zhuǎn)數(shù)組的問題還可以通過三次反轉(zhuǎn)數(shù)組來實現(xiàn)。第一次整體反轉(zhuǎn),使原數(shù)組后k個元素位于前k個元素中,但內(nèi)部順序正好相反。第二次反轉(zhuǎn),只需要反轉(zhuǎn)前k個元素。第三次反轉(zhuǎn),只需要反轉(zhuǎn)后n-k個元素。需要注意的是:如果k大于數(shù)組的長度,需要對k取模,以保證不會超出數(shù)組的范圍。
????????接下來,我們來看看如何反轉(zhuǎn)數(shù)組。反轉(zhuǎn)數(shù)組指的是將數(shù)組的順序顛倒,比如:給定數(shù)組為[1, 2, 3, 4, 5, 6, 7],則反轉(zhuǎn)后的數(shù)組為[7, 6, 5, 4, 3, 2, 1]??梢酝ㄟ^雙指針法來實現(xiàn)反轉(zhuǎn),先交換數(shù)組的第一個數(shù)和最后一個數(shù),然后交換第二個數(shù)和倒數(shù)第二個數(shù),一直到數(shù)組中間即可。該方法的時間復(fù)雜度為O(n),空間復(fù)雜度也為O(1)。具體實現(xiàn),可參考下面的示例代碼。這里,我們通過三次反轉(zhuǎn)數(shù)組的部分來完成整個數(shù)組的旋轉(zhuǎn)。我們還使用了Rust的swap方法來交換數(shù)組中的元素,并且利用了數(shù)組的可變引用&mut [i32]來直接修改原數(shù)組內(nèi)容。
fn reverse_array(arr: &mut [i32], mut start: usize, mut end: usize) {while start < end {arr.swap(start, end);start += 1;end -= 1;}
}fn rotate_array(arr: &mut [i32], k: usize) {let n_len = arr.len();let actual_k = k % n_len;reverse_array(arr, 0, n_len - 1);reverse_array(arr, 0, actual_k - 1);reverse_array(arr, actual_k, n_len - 1);
}fn print_array(arr: &[i32]) {for &item in arr {print!("{} ", item);}println!();
}fn main() {let mut data = [1, 2, 3, 4, 5, 6, 7];rotate_array(&mut data, 3);print_array(&data);
}
總結(jié)
????????一個問題的解決方案可能遠不止一種,正所謂“條條大路通羅馬”,如何在眾多解決方案中找出最優(yōu)解,實際上非??简炣浖_發(fā)工程師的綜合能力。從多個角度、多個維度分析和思考問題,是一種非常有效的思維方式,可以幫助我們更全面地理解問題,并找到更好更優(yōu)的解決方案。