From fe5be6fae49ae6b27dca64fcc360c467c4785834 Mon Sep 17 00:00:00 2001
From: Xu Shaohua <shaohua@biofan.org>
Date: Tue, 5 Dec 2023 22:30:40 +0800
Subject: [PATCH] leetcode: Add remove duplicates from sorted list

---
 Cargo.lock                                    |  4 +
 .../Cargo.toml                                |  7 ++
 .../src/main.rs                               | 80 +++++++++++++++++++
 3 files changed, 91 insertions(+)
 create mode 100644 leetcode/0083.remove-duplicates-from-sorted-list/Cargo.toml
 create mode 100644 leetcode/0083.remove-duplicates-from-sorted-list/src/main.rs

diff --git a/Cargo.lock b/Cargo.lock
index 31180b51..42163e87 100644
--- a/Cargo.lock
+++ b/Cargo.lock
@@ -322,6 +322,10 @@ version = "0.1.0"
 name = "lc-0053-maximum-subarray"
 version = "0.1.0"
 
+[[package]]
+name = "lc-0083-remove-duplicates-from-sorted-list"
+version = "0.1.0"
+
 [[package]]
 name = "lc-0142-linked-list-cycle-ii"
 version = "0.1.0"
diff --git a/leetcode/0083.remove-duplicates-from-sorted-list/Cargo.toml b/leetcode/0083.remove-duplicates-from-sorted-list/Cargo.toml
new file mode 100644
index 00000000..0554f05d
--- /dev/null
+++ b/leetcode/0083.remove-duplicates-from-sorted-list/Cargo.toml
@@ -0,0 +1,7 @@
+[package]
+name = "lc-0083-remove-duplicates-from-sorted-list"
+version = "0.1.0"
+edition = "2021"
+publish = false
+
+[dependencies]
diff --git a/leetcode/0083.remove-duplicates-from-sorted-list/src/main.rs b/leetcode/0083.remove-duplicates-from-sorted-list/src/main.rs
new file mode 100644
index 00000000..5f3b1e59
--- /dev/null
+++ b/leetcode/0083.remove-duplicates-from-sorted-list/src/main.rs
@@ -0,0 +1,80 @@
+// Copyright (c) 2023 Xu Shaohua <shaohua@biofan.org>. All rights reserved.
+// Use of this source is governed by General Public License that can be
+// found in the LICENSE file.
+
+#![allow(dead_code)]
+
+#[derive(Debug, Clone, PartialEq, Eq)]
+struct ListNode {
+    pub val: i32,
+    pub next: Option<Box<ListNode>>,
+}
+
+impl ListNode {
+    #[inline]
+    #[must_use]
+    pub const fn new(val: i32) -> Self {
+        Self { val, next: None }
+    }
+
+    pub fn from_slice(slice: &[i32]) -> Option<Box<Self>> {
+        let mut list = None;
+        for item in slice.iter().rev() {
+            list = Self::cat(list, *item);
+        }
+        list
+    }
+
+    pub fn cat(list: Option<Box<Self>>, val: i32) -> Option<Box<Self>> {
+        Some(Box::new(Self { val, next: list }))
+    }
+}
+
+fn solution1(head: Option<Box<ListNode>>) -> Option<Box<ListNode>> {
+    if let Some(head) = head {
+        let val = head.val;
+        if let Some(next) = head.next {
+            if next.val == val {
+                ListNode::cat(solution1(next.next), val)
+            } else {
+                ListNode::cat(solution1(Some(next)), val)
+            }
+        } else {
+            Some(head)
+        }
+    } else {
+        None
+    }
+}
+
+fn main() {
+    let list = ListNode::from_slice(&[1, 1, 2]);
+    let result = solution1(list);
+    println!("result: {result:?}");
+    let expected_result = ListNode::from_slice(&[1, 2]);
+    assert_eq!(result, expected_result);
+
+    let list = ListNode::from_slice(&[1, 1, 2, 3, 3]);
+    let result = solution1(list);
+    println!("result: {result:?}");
+    let expected_result = ListNode::from_slice(&[1, 2, 3]);
+    assert_eq!(result, expected_result);
+}
+
+#[cfg(test)]
+mod tests {
+    use super::{solution1, ListNode};
+
+    #[test]
+    fn test_solution1() {
+        let list = ListNode::from_slice(&[1, 1, 2]);
+        let result = solution1(list);
+        let expected_result = ListNode::from_slice(&[1, 2]);
+        assert_eq!(result, expected_result);
+
+        let list = ListNode::from_slice(&[1, 1, 2, 3, 3]);
+        let result = solution1(list);
+        let expected_result = ListNode::from_slice(&[1, 2, 3]);
+        assert_eq!(result, expected_result);
+    }
+}