常看到許多應用程式用Rust改寫後效率提升不少的消息,加上在刷題的過程中想挑一個編譯的程式來練習於是就選了Rust。
看了介紹文件和API文件,卡在知道但做不到所以從頭開始依照Rust關鍵字和Leetcode tag來邊解題邊學Rust,簡單介紹題目來源由後直接開始用刷題來練RUST。
在宣告字串時常用let s1 = "Hello";方式,Rust背後的機制是在編譯時先宣告好"Hello"記憶體大小,s1只是個 reference,存放Hello"指標和長度,由於已經宣告好了所以無法對原本字串做修改。
fn main() {
let s1: &str = "Hello";
println!("ptr = {:p}", s1.as_ptr()); // ptr = 0x62fe8a79a0ab
println!("len = {}", s1.len()); // len = 5
}
來源:https://rust-lang.tw/book-tw/ch04-01-what-is-ownership.html
在編譯時知道有固定記憶大小的會寫在堆疊(Stack),還不知道大小的會做堆積上配置(allocating on the heap)先把一塊夠大的空位,標記為已佔用,然後回傳一個指標(pointer),當進行一連串的操作讓原本空間不夠時,Rust會再去找一塊更大的空間來儲放,更詳細的內容可以參考,Vec<T>
就是一個堆積上配置例子,String
是以Vec<u8>
封裝的型別,因此我們可以對String
型別的字串做修改
fn main() {
let mut s = String::from("hello world");
println!("{:?}", s); //"hello world"
s.push_str(" !!!");
println!("{:?}", s); //"hello world !!!"
}
在&str中我們可以透過[start..end]來拿取想要的字串,String如果也想做切片(slice)可以先&String解參考成&str
fn main() {
let s = String::from("hello world");
let hello = &s[0..5];
let world = &s[6..11];
}
圖片來源:https://rust-lang.tw/book-tw/ch04-03-slices.html
有了String和slice的概念就能實作leetcode 1768.
題目:將兩個String型別的單字依序組合成新單字,如果一個單字長度用完了,剩下的全接在後面。
輸入:word1 = "abc", word2 = "pqr"
輸出:"apbqcr"
限制:
1 <= word1.length, word2.length <= 100
word1
and word2
只包含英文小寫字母
這題因為測資全都是英文小寫字母,每個字元正好佔 1 byte,可以用切片方式拿到每一個記憶體位置的字元。
use std::cmp::min;
impl Solution {
pub fn merge_alternately(word1: String, word2: String) -> String {
let mut new = String::new();
for i in 0..min(word1.len(),word2.len()) {
new.insert_str(i*2, &word1[i..i+1]);
new.insert_str(i*2+1, &word2[i..i+1]);
}
if word1.len()>word2.len(){
new.push_str(&word1[word2.len()..]);
} else {
new.push_str(&word2[word1.len()..]);
}
new
}
}
如果單字是UTF-8譬如繁體中文,因為一個字元佔3byte就無法用上面解法,需要用chars()將String
轉成迭代器再操作
fn main() {
let s = String::from("繁");
println!("{:?}", s.as_bytes());//印出[231, 185, 129]
println!("{}", &s[0..1]);
//切的位置不符合panic
//thread 'main' panicked at src/main.rs:4:22:
//byte index 1 is not a char boundary; it is inside '繁' (bytes 0..3) of `繁`
}
fn main() {
let s = String::from("繁");
println!("{:?}", s.as_bytes());//印出[231, 185, 129]
println!("{:?}", s.chars());//印出Chars(['繁'])
}
impl Solution {
pub fn merge_alternately(word1: String, word2: String) -> String {
let mut new = String::new();
let mut iter1 = word1.chars();
let mut iter2 = word2.chars();
loop {
match (iter1.next(), iter2.next()) {
(Some(c1), Some(c2)) => {
new.push(c1);
new.push(c2);
}
(Some(c1), None) => {
new.push(c1);
new.extend(iter1);
break;
}
(None, Some(c2)) => {
new.push(c2);
new.extend(iter2);
break;
}
(None, None) => break,
}
}
new
}
}
&str
編譯時就固定了不能修改,String可以修改char()
方法可以幫我們拿到字元