Algorithm/문제풀이

[leetcode] 2451. Odd String Difference - Rust

Razelo 2024. 5. 3. 13:55

 

간만에 카페에서 쉬면서 평화로운 시간을 보낸다. 역시나 쉴때는 리트코드 푸는게 제일 재밌다. 

 

심심해서 Rust로 풀어봤다.  

 

재밌는 문제다. 문제 자체는 쉬운 편인데 Rust로 풀자니 Rust자체의 문법에서 살짝 걸려넘어지는 부분이 있었다. 정리해둘만한 부분이 있는데 같이 살펴보자. 

 

자 우선 for word in &words에서 &로 borrow해서 사용한다. 이렇게 사용하는 이유는 

borrow해서 사용하지 않으면 밑에서 words를 참조하려고 할때 위에서 소유권이 이미 이전되었기 때문에 컴파일 에러가 나기 때문에 borrow해서 사용해야 한다. 

또 재밌는 부분은 String타입은 개별 word를 접근하려고 할때 String타입 그 자체에서 [] indexing으로 접근할 수 없기 때문에 word.chars().collect()로 바꿔서 사용해야 한다. collect()를 해야 Vec<>으로 얻게 되는거다. 

 

그리고 python slicing같은 걸 써보고 싶었다. 

&vec[0..idx]로 idx전까지만 접근해서 앞단을 잘라주고, &vec[(idx + 1)..]으로 접근해서 뒷단을 잘라준다. 

그리고 나섯 extend_from_slice()로 하나씩 더해준다. 

 

여기서 +1때문에 범위쳌이 불안할 수 있는데 안전하다고 한다. 

 

idx + 1이 vec.len()이랑 같더라도 벡터의 끝을 넘는 것처럼 오해 가능한데 이러면 Rust에서는 이걸 빈 슬라이스로 처리한다고 한다. 시작 인덱스가 벡터 길이와 같거나 크면 그냥 빈 슬라이스로 처리한다고 한다. 

그러니까 문제없다. 그리고 빈 슬라이스는 어떤 메모리도 참조하지 않는다고 한다. 

 

contains라는 흥미로운 메서드가 있는데, 해당 요소가 포함되어 있는지 체크한다. 

.clone()으로 반환하는 이유는 소유권 때문인데 block내에서 이미 words의 String을 불변참조로 갖고 있기 때문에 밖으로 리턴해줬을때 block구간이 소멸되므로 dangling pointer가 된다. Rust는 이를 막기 위해 clone()해서 아예 데이터를 복사해서 준다. 즉 참조가 아닌 새 String 인스턴스의 소유권을 반환한다. 

 

재밌는 예제다. 

 

/*
0104 ~ 0142 
a <- 0 
z <- 25 

하나만 다른 애들과 다른 difference array를 가지고 있다고 함. 
그걸 찾아서 그 단어를 리턴하세요 

문제 자체는 쉬운데 Rust문법에서 좀 걸렸네요 
*/

impl Solution {
    pub fn odd_string(words: Vec<String>) -> String {
        let mut vec: Vec<Vec<i32>> = Vec::new(); 

        for word in &words  {  // 여기서 borrow해서 쓰지 않으면 밑에서 참조할때 소유권 에러 납니다. 
            let mut word_vec: Vec<i32> = Vec::new(); 
            let chars: Vec<char> = word.chars().collect();  // 역서 chars로 바꿔야 나중에 [] 인덱싱으로 접근 가능합니다. 
            
            for i in 1..chars.len() {  
                let a_idx = Solution::get_char_num(chars[i - 1]); 
                let b_idx = Solution::get_char_num(chars[i]);    
                word_vec.push(b_idx - a_idx); 
            }
            vec.push(word_vec); 
        }

        for idx in 0..vec.len() { 
            // 이 부분이 slicing을 하는 코드인데요 extend_from_slice를 씁니다.  
            let front_vec = &vec[0..idx]; 
            let back_vec = &vec[(idx + 1)..]; 

            let mut new_vec = Vec::new(); 
            new_vec.extend_from_slice(front_vec); 
            new_vec.extend_from_slice(back_vec); 
            if !new_vec.contains(&vec[idx]) { 
                return words[idx].clone(); 
            }
        }

        // Vector 중 혼자만 다른 요소 찾아내기. 
        return String::new(); 
    }

    pub fn get_char_num(c: char) -> i32 {  // 
        return (c as u8 - 'a' as u8) as i32;  // 타입 캐스팅을 반환 타입에 맞게 해줍시당 
    }
}
반응형