Skip to content
This commit does not belong to any branch on this repository, and may belong to a fork outside of the repository.

Commit 8283453

Browse files
committedJan 13, 2019
support submission template generation
1 parent d8fd273 commit 8283453

11 files changed

+1625
-58
lines changed
 

‎Cargo.lock

+1,232
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

‎Cargo.toml

+5
Original file line numberDiff line numberDiff line change
@@ -4,3 +4,8 @@ version = "0.1.0"
44
authors = ["alei <rayingecho@gmail.com>"]
55
edition = "2018"
66

7+
[dependencies]
8+
reqwest = "0.9.8"
9+
serde = "1.0"
10+
serde_json = "1.0"
11+
serde_derive = "1.0"

‎README.md

+9-7
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,15 @@
11
# My Leetcode Solution in Rust
22

3-
Each `.rs` file consists of three parts:
3+
Run `cargo run {id}` to initialize the template submission file of "question #id".
44

5-
* problem description
6-
* my solution
7-
* test cases
5+
Run `cargo test test_{id}` to test the solution for "question #id".
86

9-
Run `cargo test test_{id}` to test the solution for problem #id.
7+
Working in progress, to do:
108

11-
Working in progress, solutions list:
9+
- [ ] auto generation of solution list
1210

13-
* [1 - two sum](src/n1_two_sum.rs)
11+
## Usage
12+
13+
* Remove all the solution .rs
14+
* Clean lib.rs file
15+
* Start your leetcode journey in rust by typing `cargo run {question_id}`

‎src/lib.rs

+4
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,4 @@
1+
mod n0001_two_sum;
2+
mod n0002_add_two_numbers;
3+
mod n0003_longest_substring;
4+
mod n0004_median_of_two_sorted_arrays;

‎src/main.rs

+71-3
Original file line numberDiff line numberDiff line change
@@ -1,7 +1,75 @@
1-
// make cargo happy
2-
pub mod n1_two_sum;
3-
pub mod n2_add_two_numbers;
1+
#[macro_use]
2+
extern crate serde_derive;
3+
#[macro_use]
4+
extern crate serde_json;
45

6+
mod problem;
7+
8+
use std::env;
9+
use std::fs;
10+
use std::path::{Path};
11+
use std::io::Write;
12+
13+
/// main() helps to generate the submission template .rs
514
fn main() {
15+
let args: Vec<String> = env::args().collect();
16+
if args.len() < 2 {
17+
panic!("problem id must be provided");
18+
}
19+
let id = &args[1];
20+
let id = id.parse::<u32>().expect(&format!("not a number: {}", id));
21+
22+
let problem = problem::get_problem(id)
23+
.expect(&format!("problem #{} not found", id));
24+
let code = problem.code_definition.iter()
25+
.filter(|&d| { d.value == "rust" })
26+
.next()
27+
.expect("problem has no rust support yet");
28+
29+
let file_name = format!("n{:04}_{}", id, problem.title_slug.replace("-", "_"));
30+
let file_path = Path::new("./src").join(format!("{}.rs", file_name));
31+
if file_path.exists() {
32+
panic!("problem already initialized");
33+
}
34+
35+
let template = fs::read_to_string("./template.rs").unwrap();
36+
let source = template
37+
.replace("__PROBLEM_TITLE__", &problem.title)
38+
.replace("__PROBLEM_DESC__", &build_desc(&problem.content))
39+
.replace("__PROBLEM_DEFAULT_CODE__", &code.default_code)
40+
.replace("__PROBLEM_ID__", &format!("{}", id));
41+
42+
let mut file = fs::OpenOptions::new()
43+
.write(true)
44+
.create(true)
45+
.truncate(true)
46+
.open(&file_path)
47+
.unwrap();
48+
49+
file.write_all(source.as_bytes()).unwrap();
50+
drop(file);
51+
52+
let mut lib_file = fs::OpenOptions::new()
53+
.write(true)
54+
.append(true)
55+
.open("./src/lib.rs")
56+
.unwrap();
57+
writeln!(lib_file, "mod {};", file_name);
58+
}
659

60+
fn build_desc(content: &str) -> String {
61+
content
62+
.replace("<strong>", "")
63+
.replace("</strong>", "")
64+
.replace("<em>", "")
65+
.replace("</em>", "")
66+
.replace("</p>", "")
67+
.replace("<p>", "")
68+
.replace("<b>", "")
69+
.replace("</b>", "")
70+
.replace("</pre>", "")
71+
.replace("<pre>", "")
72+
.replace("&nbsp;", "")
73+
.replace("\n\n", "\n")
74+
.replace("\n", "\n * ")
775
}

‎src/n1_two_sum.rs renamed to ‎src/n0001_two_sum.rs

+6-9
Original file line numberDiff line numberDiff line change
@@ -1,24 +1,21 @@
1-
/*
1+
/**
22
* [1] Two Sum
33
*
4-
* https://leetcode.com/problems/two-sum/description/
5-
*
64
* Given an array of integers, return indices of the two numbers such that they
75
* add up to a specific target.
8-
*
6+
*
97
* You may assume that each input would have exactly one solution, and you may
108
* not use the same element twice.
11-
*
9+
*
1210
* Example:
13-
*
14-
*
11+
*
12+
*
1513
* Given nums = [2, 7, 11, 15], target = 9,
16-
*
14+
*
1715
* Because nums[0] + nums[1] = 2 + 7 = 9,
1816
* return [0, 1].
1917
*
2018
*/
21-
2219
pub struct Solution {}
2320

2421
// submission codes start here

‎src/n2_add_two_numbers.rs renamed to ‎src/n0002_add_two_numbers.rs

+30-39
Original file line numberDiff line numberDiff line change
@@ -1,14 +1,6 @@
1-
/*
1+
/**
22
* [2] Add Two Numbers
33
*
4-
* https://leetcode.com/problems/add-two-numbers/description/
5-
*
6-
* algorithms
7-
* Medium (30.03%)
8-
* Total Accepted: 705.4K
9-
* Total Submissions: 2.3M
10-
* Testcase Example: '[2,4,3]\n[5,6,4]'
11-
*
124
* You are given two non-empty linked lists representing two non-negative
135
* integers. The digits are stored in reverse order and each of their nodes
146
* contain a single digit. Add the two numbers and return it as a linked list.
@@ -17,41 +9,13 @@
179
* number 0 itself.
1810
*
1911
* Example:
20-
*
21-
*
12+
*
13+
*
2214
* Input: (2 -> 4 -> 3) + (5 -> 6 -> 4)
2315
* Output: 7 -> 0 -> 8
2416
* Explanation: 342 + 465 = 807.
2517
*
2618
*/
27-
28-
#[derive(PartialEq, Eq, Debug)]
29-
pub struct ListNode {
30-
pub val: i32,
31-
pub next: Option<Box<ListNode>>
32-
}
33-
34-
impl ListNode {
35-
#[inline]
36-
fn new(val: i32) -> Self {
37-
ListNode {
38-
next: None,
39-
val
40-
}
41-
}
42-
}
43-
44-
// helper function for test
45-
pub fn to_list(vec: Vec<i32>) -> Option<Box<ListNode>> {
46-
let mut current = None;
47-
for &v in vec.iter().rev() {
48-
let mut node = ListNode::new(v);
49-
node.next = current;
50-
current = Some(Box::new(node));
51-
}
52-
current
53-
}
54-
5519
pub struct Solution {}
5620

5721
// submission codes start here
@@ -85,6 +49,33 @@ impl Solution {
8549

8650
// submission codes end
8751

52+
#[derive(PartialEq, Eq, Debug)]
53+
pub struct ListNode {
54+
pub val: i32,
55+
pub next: Option<Box<ListNode>>
56+
}
57+
58+
impl ListNode {
59+
#[inline]
60+
fn new(val: i32) -> Self {
61+
ListNode {
62+
next: None,
63+
val
64+
}
65+
}
66+
}
67+
68+
// helper function for test
69+
pub fn to_list(vec: Vec<i32>) -> Option<Box<ListNode>> {
70+
let mut current = None;
71+
for &v in vec.iter().rev() {
72+
let mut node = ListNode::new(v);
73+
node.next = current;
74+
current = Some(Box::new(node));
75+
}
76+
current
77+
}
78+
8879
#[cfg(test)]
8980
mod tests {
9081
use super::*;

‎src/n0003_longest_substring.rs

+40
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,40 @@
1+
/**
2+
* [3] Longest Substring Without Repeating Characters
3+
*
4+
* You are given two non-empty linked lists representing two non-negative
5+
* integers. The digits are stored in reverse order and each of their nodes
6+
* contain a single digit. Add the two numbers and return it as a linked list.
7+
*
8+
* You may assume the two numbers do not contain any leading zero, except the
9+
* number 0 itself.
10+
*
11+
* Example:
12+
*
13+
* Input: "abcabcbb"
14+
* Output: 3
15+
* Explanation: The answer is "abc", with the length of 3.
16+
*
17+
*/
18+
pub struct Solution {}
19+
20+
// submission codes start here
21+
22+
impl Solution {
23+
pub fn length_of_longest_substring(s: String) -> i32 {
24+
25+
}
26+
}
27+
28+
// submission codes end
29+
30+
#[cfg(test)]
31+
mod tests {
32+
use super::*;
33+
34+
#[test]
35+
fn test_3() {
36+
assert_eq!(Solution::length_of_longest_substring("abcabcbb".to_string()), 3);
37+
assert_eq!(Solution::length_of_longest_substring("bbbb".to_string()), 1);
38+
assert_eq!(Solution::length_of_longest_substring("pwwkew".to_string()), 3);
39+
}
40+
}
+48
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,48 @@
1+
/**
2+
* [4] Median of Two Sorted Arrays
3+
*
4+
* There are two sorted arrays nums1 and nums2 of size m and n respectively.
5+
*
6+
* Find the median of the two sorted arrays. The overall run time complexity should be O(log (m+n)).
7+
*
8+
* You may assume nums1 and nums2cannot be both empty.
9+
*
10+
* Example 1:
11+
*
12+
*
13+
* nums1 = [1, 3]
14+
* nums2 = [2]
15+
*
16+
* The median is 2.0
17+
*
18+
*
19+
* Example 2:
20+
*
21+
*
22+
* nums1 = [1, 2]
23+
* nums2 = [3, 4]
24+
*
25+
* The median is (2 + 3)/2 = 2.5
26+
*
27+
*
28+
*/
29+
pub struct Solution {}
30+
31+
// submission codes start here
32+
33+
impl Solution {
34+
pub fn find_median_sorted_arrays(nums1: Vec<i32>, nums2: Vec<i32>) -> f64 {
35+
36+
}
37+
}
38+
39+
// submission codes end
40+
41+
#[cfg(test)]
42+
mod tests {
43+
use super::*;
44+
45+
#[test]
46+
fn test_4() {
47+
}
48+
}

‎src/problem.rs

+159
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,159 @@
1+
extern crate serde_json;
2+
extern crate reqwest;
3+
4+
use std::fmt::{Display, Formatter, Error};
5+
6+
const PROBLEMS_URL: &str = "https://leetcode.com/api/problems/algorithms/";
7+
const GRAPHQL_URL: &str = "https://leetcode.com/graphql";
8+
const QUESTION_QUERY_STRING: &str = r#"
9+
query questionData($titleSlug: String!) {
10+
question(titleSlug: $titleSlug) {
11+
content
12+
stats
13+
codeDefinition
14+
sampleTestCase
15+
metaData
16+
}
17+
}"#;
18+
const QUESTION_QUERY_OPERATION: &str = "questionData";
19+
20+
pub fn get_problem(id: u32) -> Option<Problem> {
21+
let problems = get_problems().unwrap();
22+
for problem in problems.stat_status_pairs.iter() {
23+
if problem.stat.question_id == id {
24+
let client = reqwest::Client::new();
25+
let resp: RawProblem = client.post(GRAPHQL_URL)
26+
.json(&Query::question_query(problem.stat.question_title_slug.as_ref().unwrap()))
27+
.send().unwrap()
28+
.json().unwrap();
29+
return Some(Problem {
30+
title: problem.stat.question_title.clone().unwrap(),
31+
title_slug: problem.stat.question_title_slug.clone().unwrap(),
32+
code_definition: serde_json::from_str( & resp.data.question.code_definition).unwrap(),
33+
content: resp.data.question.content,
34+
sample_test_case: resp.data.question.sample_test_case,
35+
difficulty: problem.difficulty.to_string(),
36+
})
37+
}
38+
}
39+
None
40+
}
41+
42+
fn get_problems() -> Option<Problems> {
43+
reqwest::get(PROBLEMS_URL).unwrap().json().unwrap()
44+
}
45+
46+
#[derive(Serialize, Deserialize)]
47+
pub struct Problem {
48+
pub title: String,
49+
pub title_slug: String,
50+
pub content: String,
51+
#[serde(rename = "codeDefinition")]
52+
pub code_definition: Vec<CodeDefinition>,
53+
#[serde(rename = "sampleTestCase")]
54+
pub sample_test_case: String,
55+
pub difficulty: String,
56+
}
57+
58+
#[derive(Serialize, Deserialize)]
59+
pub struct CodeDefinition {
60+
pub value: String,
61+
pub text: String,
62+
#[serde(rename = "defaultCode")]
63+
pub default_code: String,
64+
}
65+
66+
67+
#[derive(Debug, Serialize, Deserialize)]
68+
struct Query {
69+
#[serde(rename = "operationName")]
70+
operation_name: String,
71+
variables: serde_json::Value,
72+
query: String,
73+
}
74+
75+
impl Query {
76+
fn question_query(title_slug: &str) -> Query {
77+
Query {
78+
operation_name: QUESTION_QUERY_OPERATION.to_owned(),
79+
variables: json!({"titleSlug": title_slug}),
80+
query: QUESTION_QUERY_STRING.to_owned(),
81+
}
82+
}
83+
}
84+
85+
#[derive(Debug, Serialize, Deserialize)]
86+
struct RawProblem {
87+
data: Data,
88+
}
89+
90+
#[derive(Debug, Serialize, Deserialize)]
91+
struct Data {
92+
question: Question,
93+
}
94+
95+
#[derive(Debug, Serialize, Deserialize)]
96+
struct Question {
97+
content: String,
98+
stats: String,
99+
#[serde(rename = "codeDefinition")]
100+
code_definition: String,
101+
#[serde(rename = "sampleTestCase")]
102+
sample_test_case: String,
103+
#[serde(rename = "metaData")]
104+
meta_data: String,
105+
}
106+
107+
#[derive(Debug, Serialize, Deserialize)]
108+
struct Problems {
109+
user_name: String,
110+
num_solved: u32,
111+
num_total: u32,
112+
ac_easy: u32,
113+
ac_medium: u32,
114+
ac_hard: u32,
115+
stat_status_pairs: Vec<StatWithStatus>,
116+
}
117+
118+
#[derive(Debug, Serialize, Deserialize)]
119+
struct StatWithStatus {
120+
stat: Stat,
121+
difficulty: Difficulty,
122+
paid_only: bool,
123+
is_favor: bool,
124+
frequency: u32,
125+
progress: u32,
126+
}
127+
128+
#[derive(Debug, Serialize, Deserialize)]
129+
struct Stat {
130+
question_id: u32,
131+
#[serde(rename = "question__article__slug")]
132+
question_article_slug: Option<String>,
133+
#[serde(rename = "question__title")]
134+
question_title: Option<String>,
135+
#[serde(rename = "question__title_slug")]
136+
question_title_slug: Option<String>,
137+
#[serde(rename = "question__hide")]
138+
question_hide: bool,
139+
total_acs: u32,
140+
total_submitted: u32,
141+
frontend_question_id: u32,
142+
is_new_question: bool,
143+
}
144+
145+
#[derive(Debug, Serialize, Deserialize)]
146+
struct Difficulty {
147+
level: u32,
148+
}
149+
150+
impl Display for Difficulty {
151+
fn fmt(&self, f: &mut Formatter) -> Result<(), Error> {
152+
match self.level {
153+
1 => f.write_str("Easy"),
154+
2 => f.write_str("Medium"),
155+
3 => f.write_str("Hard"),
156+
_ => f.write_str("Unknown"),
157+
}
158+
}
159+
}

‎template.rs

+21
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,21 @@
1+
/**
2+
* [__PROBLEM_ID__] __PROBLEM_TITLE__
3+
*
4+
* __PROBLEM_DESC__
5+
*/
6+
pub struct Solution {}
7+
8+
// submission codes start here
9+
10+
__PROBLEM_DEFAULT_CODE__
11+
12+
// submission codes end
13+
14+
#[cfg(test)]
15+
mod tests {
16+
use super::*;
17+
18+
#[test]
19+
fn test___PROBLEM_ID__() {
20+
}
21+
}

0 commit comments

Comments
 (0)
Please sign in to comment.