做網(wǎng)站北京公司推廣產(chǎn)品的渠道
題目
????????給定一個(gè)數(shù)組,將數(shù)組中的元素向右移動(dòng)k個(gè)位置,其中k是非負(fù)數(shù)。要求如下:
????????(1)盡可能想出更多的解決方案,至少有三種不同的方法可以解決這個(gè)問(wèn)題。
????????(2)使用時(shí)間復(fù)雜度為O(n)和空間復(fù)雜度為O(1)的原地算法解決這個(gè)問(wèn)題。
????????示例 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)聘者從多個(gè)角度、多個(gè)維度分析和思考問(wèn)題的能力。
????????最直接、最簡(jiǎn)單的解決方案當(dāng)然是“暴力法”,也就是每次將數(shù)組向右移動(dòng)一個(gè)元素,一共旋轉(zhuǎn)k次。向右移動(dòng)一個(gè)元素,需要將最后一個(gè)元素移動(dòng)到數(shù)組開(kāi)頭,然后將其他元素依次右移?!氨┝Ψā钡臅r(shí)間復(fù)雜度為O(n*k),空間復(fù)雜度為O(1)。具體實(shí)現(xiàn),可參考下面的示例代碼。這里,我們使用了Rust標(biāo)準(zhǔn)庫(kù)中的rotate_right方法,它直接提供了按指定步數(shù)向右旋轉(zhuǎn)數(shù)組的功能,使得代碼更為簡(jiǎn)潔。
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);
}
????????“暴力法”的時(shí)間復(fù)雜度較高,我們可以通過(guò)以空間換時(shí)間的方式來(lái)優(yōu)化時(shí)間復(fù)雜度。具體做法為:使用一個(gè)額外的數(shù)組來(lái)將每個(gè)元素放到正確的位置上,也就是我們把原本數(shù)組里下標(biāo)為i的元素,放到(i+k)%數(shù)組長(zhǎng)度的位置;最后,我們把新的數(shù)組拷貝到原來(lái)的數(shù)組中。該方法的時(shí)間復(fù)雜度為O(n),空間復(fù)雜度也為O(n)。具體實(shí)現(xiàn),可參考下面的示例代碼。這里,我們使用to_vec()方法來(lái)創(chuàng)建原數(shù)組的一個(gè)拷貝,然后通過(guò)索引操作和copy_from_slice()方法來(lái)完成數(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);
}
????????實(shí)際上,解決旋轉(zhuǎn)數(shù)組的問(wèn)題還可以通過(guò)三次反轉(zhuǎn)數(shù)組來(lái)實(shí)現(xiàn)。第一次整體反轉(zhuǎn),使原數(shù)組后k個(gè)元素位于前k個(gè)元素中,但內(nèi)部順序正好相反。第二次反轉(zhuǎn),只需要反轉(zhuǎn)前k個(gè)元素。第三次反轉(zhuǎn),只需要反轉(zhuǎn)后n-k個(gè)元素。需要注意的是:如果k大于數(shù)組的長(zhǎng)度,需要對(duì)k取模,以保證不會(huì)超出數(shù)組的范圍。
????????接下來(lái),我們來(lái)看看如何反轉(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]。可以通過(guò)雙指針?lè)▉?lái)實(shí)現(xiàn)反轉(zhuǎn),先交換數(shù)組的第一個(gè)數(shù)和最后一個(gè)數(shù),然后交換第二個(gè)數(shù)和倒數(shù)第二個(gè)數(shù),一直到數(shù)組中間即可。該方法的時(shí)間復(fù)雜度為O(n),空間復(fù)雜度也為O(1)。具體實(shí)現(xiàn),可參考下面的示例代碼。這里,我們通過(guò)三次反轉(zhuǎn)數(shù)組的部分來(lái)完成整個(gè)數(shù)組的旋轉(zhuǎn)。我們還使用了Rust的swap方法來(lái)交換數(shù)組中的元素,并且利用了數(shù)組的可變引用&mut [i32]來(lái)直接修改原數(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é)
????????一個(gè)問(wèn)題的解決方案可能遠(yuǎn)不止一種,正所謂“條條大路通羅馬”,如何在眾多解決方案中找出最優(yōu)解,實(shí)際上非??简?yàn)軟件開(kāi)發(fā)工程師的綜合能力。從多個(gè)角度、多個(gè)維度分析和思考問(wèn)題,是一種非常有效的思維方式,可以幫助我們更全面地理解問(wèn)題,并找到更好更優(yōu)的解決方案。