586 lines
13 KiB
Bash
Executable File
586 lines
13 KiB
Bash
Executable File
# 1. 讓腳本可執行:
|
||
# chmod +x leetcode_helper.sh
|
||
# 2. 建立新題目:
|
||
# ./leetcode_helper.sh problem 1 two-sum Easy
|
||
# ./leetcode_helper.sh problem 3000 maximum-area-rectangle Medium
|
||
# 3. 建立月度日誌:
|
||
# ./leetcode_helper.sh log 2025-09
|
||
# 4. 更新README:
|
||
# ./leetcode_helper.sh readme
|
||
|
||
#!/bin/bash
|
||
|
||
# 建立測試檔案
|
||
function create_test_files() {
|
||
local problem_dir="$1"
|
||
local number="$2"
|
||
local name="$3"
|
||
|
||
# 建立 C# 單元測試 (xUnit)
|
||
cat > "$problem_dir/test/SolutionTests.cs" << EOF
|
||
// LeetCode $number 單元測試
|
||
// 使用 xUnit 框架
|
||
|
||
using Xunit;
|
||
using System;
|
||
using System.Collections.Generic;
|
||
|
||
public class SolutionTests {
|
||
private readonly Solution _solution;
|
||
|
||
public SolutionTests() {
|
||
_solution = new Solution();
|
||
}
|
||
|
||
[Fact]
|
||
public void TestCase1() {
|
||
// Arrange
|
||
// TODO: 設定輸入資料
|
||
// var input = ;
|
||
// var expected = ;
|
||
|
||
// Act
|
||
// var result = _solution.YourMethod(input);
|
||
|
||
// Assert
|
||
// Assert.Equal(expected, result);
|
||
|
||
Assert.True(true); // 暫時通過,等待實作
|
||
}
|
||
|
||
[Fact]
|
||
public void TestCase2() {
|
||
// TODO: 第二個測試案例
|
||
Assert.True(true);
|
||
}
|
||
|
||
[Fact]
|
||
public void TestEdgeCases() {
|
||
// TODO: 邊界情況測試
|
||
// 空陣列、單一元素、最大值、最小值等
|
||
Assert.True(true);
|
||
}
|
||
}
|
||
EOF
|
||
|
||
# 建立 C# 測試專案檔
|
||
cat > "$problem_dir/test/TestProject.csproj" << EOF
|
||
<Project Sdk="Microsoft.NET.Sdk">
|
||
|
||
<PropertyGroup>
|
||
<TargetFramework>net6.0</TargetFramework>
|
||
<Nullable>enable</Nullable>
|
||
<IsPackable>false</IsPackable>
|
||
</PropertyGroup>
|
||
|
||
<ItemGroup>
|
||
<PackageReference Include="Microsoft.NET.Test.Sdk" Version="17.1.0" />
|
||
<PackageReference Include="xunit" Version="2.4.1" />
|
||
<PackageReference Include="xunit.runner.visualstudio" Version="2.4.3">
|
||
<IncludeAssets>runtime; build; native; contentfiles; analyzers; buildtransitive</IncludeAssets>
|
||
<PrivateAssets>all</PrivateAssets>
|
||
</PackageReference>
|
||
</ItemGroup>
|
||
|
||
<ItemGroup>
|
||
<ProjectReference Include="../csharp/Problem$number.csproj" />
|
||
</ItemGroup>
|
||
|
||
</Project>
|
||
EOF
|
||
|
||
# 建立 Go 測試檔案
|
||
cat > "$problem_dir/test/main_test.go" << EOF
|
||
// LeetCode $number Go 單元測試
|
||
package main
|
||
|
||
import (
|
||
"testing"
|
||
"reflect"
|
||
)
|
||
|
||
func TestCase1(t *testing.T) {
|
||
// TODO: 設定測試資料
|
||
// input :=
|
||
// expected :=
|
||
|
||
// result := solve(input)
|
||
|
||
// if !reflect.DeepEqual(result, expected) {
|
||
// t.Errorf("TestCase1 failed. Expected: %v, Got: %v", expected, result)
|
||
// }
|
||
|
||
// 暫時通過測試
|
||
if false {
|
||
t.Errorf("請實作測試案例")
|
||
}
|
||
}
|
||
|
||
func TestCase2(t *testing.T) {
|
||
// TODO: 第二個測試案例
|
||
if false {
|
||
t.Errorf("請實作測試案例")
|
||
}
|
||
}
|
||
|
||
func TestEdgeCases(t *testing.T) {
|
||
// TODO: 邊界情況測試
|
||
if false {
|
||
t.Errorf("請實作邊界測試")
|
||
}
|
||
}
|
||
|
||
// 輔助函數:比較 slice
|
||
func equalSlices(a, b []int) bool {
|
||
if len(a) != len(b) {
|
||
return false
|
||
}
|
||
for i := range a {
|
||
if a[i] != b[i] {
|
||
return false
|
||
}
|
||
}
|
||
return true
|
||
}
|
||
EOF
|
||
|
||
# 建立測試資料檔案模板
|
||
cat > "$problem_dir/test/input1.txt" << EOF
|
||
# 測試案例 1 輸入
|
||
# TODO: 從 LeetCode 複製範例輸入
|
||
EOF
|
||
|
||
cat > "$problem_dir/test/output1.txt" << EOF
|
||
# 測試案例 1 期望輸出
|
||
# TODO: 從 LeetCode 複製範例輸出
|
||
EOF
|
||
|
||
cat > "$problem_dir/test/input2.txt" << EOF
|
||
# 測試案例 2 輸入
|
||
# TODO: 加入額外測試案例
|
||
EOF
|
||
|
||
cat > "$problem_dir/test/output2.txt" << EOF
|
||
# 測試案例 2 期望輸出
|
||
# TODO: 加入額外測試案例期望結果
|
||
EOF
|
||
|
||
cat > "$problem_dir/test/edge_cases.md" << EOF
|
||
# 邊界情況清單
|
||
|
||
## 需要測試的邊界情況
|
||
- [ ] 空輸入 (空陣列、空字串等)
|
||
- [ ] 單一元素
|
||
- [ ] 重複元素
|
||
- [ ] 最大值/最小值
|
||
- [ ] 負數情況
|
||
- [ ] 超大資料量
|
||
- [ ] 特殊字符 (如果是字串題目)
|
||
|
||
## 額外測試案例
|
||
### 案例 1:
|
||
**輸入**:
|
||
**輸出**:
|
||
**說明**:
|
||
|
||
### 案例 2:
|
||
**輸入**:
|
||
**輸出**:
|
||
**說明**:
|
||
EOF
|
||
|
||
# 建立測試執行腳本
|
||
cat > "$problem_dir/test/run_tests.sh" << 'EOF'
|
||
#!/bin/bash
|
||
|
||
echo "🧪 執行 LeetCode 題目測試"
|
||
echo "=========================="
|
||
|
||
# 執行 C# 測試
|
||
echo "📋 C# 測試結果:"
|
||
cd ../csharp
|
||
if dotnet build > /dev/null 2>&1; then
|
||
cd ../test
|
||
if dotnet test --logger "console;verbosity=minimal" 2>/dev/null; then
|
||
echo "✅ C# 測試通過"
|
||
else
|
||
echo "❌ C# 測試失敗"
|
||
fi
|
||
else
|
||
echo "❌ C# 編譯失敗"
|
||
fi
|
||
|
||
echo ""
|
||
|
||
# 執行 Go 測試
|
||
echo "📋 Go 測試結果:"
|
||
cd ../go
|
||
if go build > /dev/null 2>&1; then
|
||
cd ../test
|
||
if go test -v > /dev/null 2>&1; then
|
||
echo "✅ Go 測試通過"
|
||
else
|
||
echo "❌ Go 測試失敗"
|
||
echo "詳細輸出:"
|
||
go test -v
|
||
fi
|
||
else
|
||
echo "❌ Go 編譯失敗"
|
||
fi
|
||
|
||
echo ""
|
||
echo "📊 測試完成!"
|
||
EOF
|
||
|
||
chmod +x "$problem_dir/test/run_tests.sh"
|
||
}
|
||
|
||
# create_problem.sh - 建立新題目資料夾和檔案
|
||
|
||
function create_problem() {
|
||
local number="$1"
|
||
local name="$2"
|
||
local difficulty="$3"
|
||
|
||
if [[ -z "$number" || -z "$name" || -z "$difficulty" ]]; then
|
||
echo "使用方法: create_problem <題號> <題目名稱> <難度>"
|
||
echo "範例: create_problem 1 two-sum Easy"
|
||
exit 1
|
||
fi
|
||
|
||
# 格式化題號 (補零到4位數)
|
||
local formatted_number=$(printf "%04d" "$number")
|
||
local folder_name="${formatted_number}-${name}"
|
||
local problem_dir="problems/${folder_name}"
|
||
|
||
# 建立資料夾結構
|
||
mkdir -p "$problem_dir"
|
||
mkdir -p "$problem_dir/test"
|
||
|
||
# 建立 README.md
|
||
cat > "$problem_dir/README.md" << EOF
|
||
# [$number] $(echo "$name" | tr '-' ' ' | sed 's/\b\w/\u&/g')
|
||
|
||
## 題目資訊
|
||
- **難度**: $difficulty
|
||
- **標籤**:
|
||
- **題目連結**: [LeetCode](https://leetcode.com/problems/$name/)
|
||
- **練習日期**: $(date +%Y-%m-%d)
|
||
|
||
## 題目描述
|
||
>
|
||
|
||
## 解題思路
|
||
|
||
### 初步分析
|
||
- 這題主要考察什麼概念?
|
||
- 有什麼關鍵限制條件?
|
||
- 預期時間/空間複雜度?
|
||
|
||
### 解法概述
|
||
1. **暴力解法**:
|
||
- 思路:
|
||
- 時間複雜度:O(?)
|
||
- 空間複雜度:O(?)
|
||
|
||
2. **優化解法**:
|
||
- 思路:
|
||
- 時間複雜度:O(?)
|
||
- 空間複雜度:O(?)
|
||
|
||
## 實作細節
|
||
|
||
### C# 解法
|
||
\`\`\`csharp
|
||
// 核心程式碼片段或關鍵邏輯說明
|
||
\`\`\`
|
||
|
||
### Go 解法
|
||
\`\`\`go
|
||
// 核心程式碼片段或關鍵邏輯說明
|
||
\`\`\`
|
||
|
||
## 測試案例
|
||
|
||
### 範例輸入輸出
|
||
\`\`\`
|
||
Input:
|
||
Output:
|
||
Explanation:
|
||
\`\`\`
|
||
|
||
### 邊界情況
|
||
- [ ] 空陣列/空字串
|
||
- [ ] 單一元素
|
||
- [ ] 最大/最小值
|
||
- [ ] 重複元素
|
||
|
||
## 學習筆記
|
||
|
||
### 今天學到什麼?
|
||
-
|
||
|
||
### 遇到的困難
|
||
-
|
||
|
||
### 改善方向
|
||
-
|
||
|
||
### 相關題目
|
||
- [題目編號] 題目名稱 - 相似概念
|
||
- [題目編號] 題目名稱 - 進階版本
|
||
|
||
---
|
||
**總結**: 這題的核心概念是...,適合練習...技巧。
|
||
EOF
|
||
|
||
# 建立 C# 專案
|
||
mkdir -p "$problem_dir/csharp"
|
||
cd "$problem_dir/csharp"
|
||
dotnet new console --force > /dev/null 2>&1
|
||
|
||
# 覆寫自動生成的 Program.cs
|
||
cat > "Program.cs" << EOF
|
||
// LeetCode $number: $(echo "$name" | tr '-' ' ' | sed 's/\b\w/\u&/g')
|
||
// 難度: $difficulty
|
||
// 日期: $(date +%Y-%m-%d)
|
||
|
||
using System;
|
||
using System.Collections.Generic;
|
||
using System.Linq;
|
||
|
||
public class Solution {
|
||
public void Solve() {
|
||
// TODO: 實作解法
|
||
Console.WriteLine("Hello LeetCode $number!");
|
||
}
|
||
}
|
||
|
||
// 測試程式
|
||
public class Program {
|
||
public static void Main() {
|
||
Solution sol = new Solution();
|
||
sol.Solve();
|
||
|
||
// TODO: 加入測試案例
|
||
// TestCase1();
|
||
// TestCase2();
|
||
}
|
||
|
||
// 測試案例模板
|
||
/*
|
||
static void TestCase1() {
|
||
// Input:
|
||
// Expected:
|
||
// Actual:
|
||
Console.WriteLine("Test 1: ");
|
||
}
|
||
*/
|
||
}
|
||
EOF
|
||
cd - > /dev/null
|
||
|
||
# 建立 Go 解法檔案
|
||
mkdir -p "$problem_dir/go"
|
||
cat > "$problem_dir/go/main.go" << EOF
|
||
// LeetCode $number: $(echo "$name" | tr '-' ' ' | sed 's/\b\w/\u&/g')
|
||
// 難度: $difficulty
|
||
// 日期: $(date +%Y-%m-%d)
|
||
|
||
package main
|
||
|
||
import "fmt"
|
||
|
||
// TODO: 實作解法
|
||
func solve() {
|
||
fmt.Printf("Hello LeetCode %d!\n", $number)
|
||
}
|
||
|
||
// 測試程式
|
||
func main() {
|
||
solve()
|
||
|
||
// TODO: 加入測試案例
|
||
// testCase1()
|
||
// testCase2()
|
||
}
|
||
|
||
// 測試案例模板
|
||
/*
|
||
func testCase1() {
|
||
// Input:
|
||
// Expected:
|
||
// Actual:
|
||
fmt.Println("Test 1:")
|
||
}
|
||
*/
|
||
EOF
|
||
|
||
# 初始化 Go module
|
||
cd "$problem_dir/go"
|
||
go mod init "leetcode-$number" > /dev/null 2>&1
|
||
cd - > /dev/null
|
||
|
||
# 建立測試檔案
|
||
create_test_files "$problem_dir" "$number" "$name"
|
||
|
||
echo "✅ 已建立題目資料夾: $problem_dir"
|
||
echo "📁 檔案結構:"
|
||
echo "$problem_dir/"
|
||
echo "├── README.md"
|
||
echo "├── csharp/"
|
||
echo "│ ├── Program.cs"
|
||
echo "│ └── *.csproj"
|
||
echo "├── go/"
|
||
echo "│ ├── main.go"
|
||
echo "│ └── go.mod"
|
||
echo "└── test/"
|
||
echo " ├── SolutionTests.cs"
|
||
echo " ├── TestProject.csproj"
|
||
echo " ├── main_test.go"
|
||
echo " ├── input1.txt"
|
||
echo " ├── output1.txt"
|
||
echo " ├── input2.txt"
|
||
echo " ├── output2.txt"
|
||
echo " ├── edge_cases.md"
|
||
echo " └── run_tests.sh"
|
||
echo ""
|
||
echo "🚀 執行方式:"
|
||
echo "C#: cd $problem_dir/csharp && dotnet run"
|
||
echo "Go: cd $problem_dir/go && go run main.go"
|
||
echo "測試: cd $problem_dir/test && ./run_tests.sh"
|
||
}
|
||
|
||
# update_readme.sh - 更新主 README
|
||
function update_readme() {
|
||
echo "🔄 更新主 README.md..."
|
||
|
||
# 計算統計資料
|
||
local total_problems=$(find problems -maxdepth 1 -type d | wc -l)
|
||
total_problems=$((total_problems - 1)) # 排除 problems 資料夾本身
|
||
|
||
local completed_problems=$(find problems -name "README.md" -exec grep -l "✅" {} \; | wc -l)
|
||
|
||
echo "📊 發現 $total_problems 個題目,其中 $completed_problems 個已完成"
|
||
|
||
# 這裡可以加入更複雜的統計和README更新邏輯
|
||
# 暫時只顯示統計結果
|
||
}
|
||
|
||
# create_monthly_log.sh - 建立月度日誌
|
||
function create_monthly_log() {
|
||
local year_month="$1"
|
||
|
||
if [[ -z "$year_month" ]]; then
|
||
year_month=$(date +%Y-%m)
|
||
fi
|
||
|
||
local log_file="logs/${year_month}.md"
|
||
|
||
if [[ -f "$log_file" ]]; then
|
||
echo "⚠️ 月度日誌已存在: $log_file"
|
||
return 1
|
||
fi
|
||
|
||
mkdir -p logs
|
||
|
||
cat > "$log_file" << EOF
|
||
# ${year_month} 學習記錄
|
||
|
||
## 📅 每日練習記錄
|
||
|
||
### Week 1
|
||
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|
||
|------|------|------|------|------|------|------|
|
||
| | | | | | | |
|
||
|
||
### Week 2
|
||
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|
||
|------|------|------|------|------|------|------|
|
||
| | | | | | | |
|
||
|
||
### Week 3
|
||
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|
||
|------|------|------|------|------|------|------|
|
||
| | | | | | | |
|
||
|
||
### Week 4
|
||
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|
||
|------|------|------|------|------|------|------|
|
||
| | | | | | | |
|
||
|
||
## 📈 本月統計
|
||
|
||
### 完成情況
|
||
- **總練習天數**: 天
|
||
- **完成題數**: 題
|
||
- **語言分布**: C# (題), Go (題)
|
||
- **難度分布**: Easy (題), Medium (題), Hard (題)
|
||
|
||
### 時間投入
|
||
- **總時間**: 小時
|
||
- **平均每題**: 分鐘
|
||
- **每日平均**: 分鐘
|
||
|
||
## 🎯 本月重點學習
|
||
|
||
### 新掌握的技巧
|
||
1.
|
||
|
||
### 常犯錯誤分析
|
||
1.
|
||
|
||
### 語言學習心得
|
||
- **C#**:
|
||
- **Go**:
|
||
|
||
## 🔄 遇到的困難與解決
|
||
|
||
### 困難1:
|
||
- **問題**:
|
||
- **解決**:
|
||
- **學習**:
|
||
|
||
## 📝 改進計畫
|
||
|
||
### 下月目標
|
||
1.
|
||
|
||
### 學習方法調整
|
||
1.
|
||
|
||
## 💡 本月金句
|
||
>
|
||
|
||
---
|
||
**總結**:
|
||
EOF
|
||
|
||
echo "✅ 已建立月度日誌: $log_file"
|
||
}
|
||
|
||
# 主程式
|
||
case "$1" in
|
||
"problem")
|
||
create_problem "$2" "$3" "$4"
|
||
;;
|
||
"readme")
|
||
update_readme
|
||
;;
|
||
"log")
|
||
create_monthly_log "$2"
|
||
;;
|
||
*)
|
||
echo "LeetCode Practice Helper"
|
||
echo ""
|
||
echo "使用方法:"
|
||
echo " $0 problem <題號> <題目名稱> <難度> # 建立新題目"
|
||
echo " $0 readme # 更新主README"
|
||
echo " $0 log [年月] # 建立月度日誌"
|
||
echo ""
|
||
echo "範例:"
|
||
echo " $0 problem 1 two-sum Easy"
|
||
echo " $0 problem 15 3sum Medium"
|
||
echo " $0 log 2025-09"
|
||
;;
|
||
esac |