Compare commits

...

28 Commits

Author SHA1 Message Date
8146e2176d [#0166] feat(leetcode): add README, unit test and C# solution 2025-09-24 11:18:08 +08:00
5189c524ef [#0166] feat(leetcode): init project 2025-09-24 09:35:00 +08:00
959f8a6861 remove: legacy solutions 2025-09-24 09:34:13 +08:00
5f8bf18795 docs(monthly): update monthly report 2025-09-23 11:02:46 +08:00
72aa011de9 [#0165]feat(leetcode): Init project, add C# solution, unit test and README 2025-09-23 10:59:18 +08:00
c4e23d5be3 docs(monthly): update monthly report 2025-09-22 13:51:44 +08:00
c7453b45e6 [#3005] feat(leetcode): init project, add C# solution 2025-09-22 13:48:38 +08:00
7c86a4a99a feat(makefile): makefile for automatic setup 2025-09-22 09:58:24 +08:00
c396a84294 docs(logs): update monthly log 2025-09-12 13:37:31 +08:00
2d6209a043 [#3227] docs(leetcode): update README 2025-09-12 13:34:05 +08:00
1e562065e8 [#3227] feat(leetcode): add c# and golang solution 2025-09-12 13:13:22 +08:00
8dfafaaf43 docs(utils,readme): add helper help and refresh docs 2025-09-12 10:37:45 +08:00
6d9993cd9f feat(utils): add global test runner and helper help 2025-09-12 10:19:47 +08:00
9ff736e11c feat(utils,templates,docs): file-based .tmpl templates; remove I/O fixtures 2025-09-12 09:56:37 +08:00
d724a5fb65 feat(utils, templates, docs): file-based templates + stronger README 2025-09-12 09:44:30 +08:00
002e9e6c32 docs(README): edit monthly README 2025-09-11 11:09:43 +08:00
75f3d9e320 feat(SortVowels): add C# solution 2025-09-11 11:05:11 +08:00
f4a7029b7e docs(README): monthly README 2025-09-08 14:34:32 +08:00
31d68d2f04 [#1317] docs(GetNoZeroIntegers): add README 2025-09-08 14:28:10 +08:00
4b2df683a4 [#1317] feat(GetNoZeroIntegers): add C# solution 2025-09-08 14:27:53 +08:00
cf3a952d1d Merge pull request '2025-09/2749-minimum-operations-to-make-the-integer-zero' (#9) from 2025-09/2749-minimum-operations-to-make-the-integer-zero into main
Reviewed-on: #9
2025-09-05 09:02:59 +00:00
63880d4717 feat(makeTheIntegerZeio): add C# solution 2025-09-05 16:54:03 +08:00
c3955ad390 docs(makeTheIntegerZero): add README 2025-09-05 16:52:45 +08:00
08c96f8636 Merge pull request '2025-09/3516-find-closest-person' (#8) from 2025-09/3516-find-closest-person into main
Reviewed-on: #8
2025-09-04 02:17:29 +00:00
MH Hung
ec12425cb9 [#3516] feat(note): add monthly README 2025-09-04 10:14:05 +08:00
MH Hung
17eaaa52c2 [#3516] feat(go): add golang solution 2025-09-04 10:10:53 +08:00
MH Hung
58acd6e8d8 [#3516] feat(C#): add C# solution 2025-09-04 10:10:26 +08:00
MH Hung
b81da2e59e [#3516] feat(note): add description 2025-09-04 10:09:45 +08:00
99 changed files with 3439 additions and 1808 deletions

338
README.md
View File

@@ -1,85 +1,289 @@
# LeetCode Practice Journey 🚀
# LeetCode 練習專案
## 📊 進度統計
- **總題數**: 0
- **已完成**: 0
- **開始日期**: 2025-09-01
- **最後更新**: 2025-09-01
這是一個用來紀錄與管理 LeetCode 練習的專案,整合 C# 與 Go 的題解、基本測試模板、月度學習日誌,以及一支小工具腳本,協助快速建立新題目與維持一致的結構與習慣。
### 難度分布
| 難度 | 完成數 | 總數 | 進度 |
|------|--------|------|------|
| Easy | 0 | 0 | 0% |
| Medium | 0 | 0 | 0% |
| Hard | 0 | 0 | 0% |
## 專案架構
### 語言分布
| 語言 | 完成題數 |
|------|----------|
| C++ | 0 |
| C# | 0 |
| Go | 0 |
```
.
├── problems/ # 每題一個資料夾 (NNNN-kebab-case)
│ └── 3516-find-closest-person/
│ ├── README.md # 題目說明與解題筆記
│ ├── csharp/ # C# 解法 (dotnet)
│ ├── go/ # Go 解法 (go module)
│ └── test/ # C#/Go 測試模板與測試檔
├── utils/
│ ├── leetcode_helper.sh # 建題、更新 README、建立月誌
│ └── run_tests.sh # 全域測試執行器(選擇 C#/Go 或全部)
├── logs/ # 月度練習紀錄 (YYYY-MM.md)
├── templates/ # 檔案模板 (.tmpl)
│ ├── problem/ # 建題用模板README、C#/Go、test
│ ├── problem-template.md.tmpl # 題解寫作指引模板(參考用)
│ └── logs-template.md.tmpl # 月誌模板
├── legacy/ # 舊題或舊結構的紀錄
├── LICENSE
└── README.md
```
## 🎯 學習目標
- [ ] 熟悉基本資料結構 (Array, LinkedList, Stack, Queue)
- [ ] 掌握雙指針技巧
- [ ] 動態規劃入門 (目標:完成 10 題)
- [ ] 樹和圖的遍歷
- [ ] 二分搜尋應用
命名慣例問題資料夾以「4 位數題號 + 題目英文 kebab-case」命名例如 `3025-find-the-number-of-ways-to-place-people-i`
## 📚 題目分類
## 需求與環境
### Array & Hash Table
| 題號 | 題目 | 難度 | 狀態 | 語言 | 筆記 |
|------|------|------|------|------|------|
| 1 | [Two Sum](problems/0001-two-sum/) | Easy | ✅ | C#, Go | 經典入門題 |
| 15 | [3Sum](problems/0015-3sum/) | Medium | ✅ | C#, Go | 雙指針技巧 |
- C#: 安裝 `.NET SDK 8+`,常用指令 `dotnet build / run / test`
- Go: 安裝 `Go 1.21+`,常用指令 `go build / run / test`
- Bash: 可執行 `utils/leetcode_helper.sh``utils/run_tests.sh`
### Two Pointers
| 題號 | 題目 | 難度 | 狀態 | 語言 | 筆記 |
|------|------|------|------|------|------|
| 11 | [Container With Most Water](problems/0011-container-with-most-water/) | Medium | ✅ | C# | 貪心思維 |
初次使用請先授權腳本:
### String
| 題號 | 題目 | 難度 | 狀態 | 語言 | 筆記 |
|------|------|------|------|------|------|
| 3 | [Longest Substring Without Repeating Characters](problems/0003-longest-substring/) | Medium | 🔄 | C# | 滑動窗口 |
```
chmod +x utils/leetcode_helper.sh utils/run_tests.sh
```
### Dynamic Programming
| 題號 | 題目 | 難度 | 狀態 | 語言 | 筆記 |
|------|------|------|------|------|------|
| 70 | [Climbing Stairs](problems/0070-climbing-stairs/) | Easy | 📝 | - | 待開始 |
## 常用操作
## 📅 月度學習記錄
- [2025年9月](logs/2025-09.md) - 基礎入門月 (完成 8 題)
- [2025年10月](logs/2025-09.md) - 進階提升月 (進行中...)
- 新增題目自動建立資料夾、README、C#/Go 程式與測試模板)
## 🧠 重點學習筆記
```
./utils/leetcode_helper.sh problem <題號> <題目名稱-kebab> <難度>
### 常用模式總結
1. **雙指針**: 適用於有序陣列的搜尋問題
2. **滑動窗口**: 子陣列/子字串的最佳化問題
3. **Hash Map**: 快速查找和計數問題
# 範例
./utils/leetcode_helper.sh problem 1 two-sum Easy
./utils/leetcode_helper.sh problem 3000 maximum-area-rectangle Medium
# 顯示說明:
./utils/leetcode_helper.sh --help
```
### 容易出錯的地方
- 邊界條件檢查 (空陣列、單一元素)
- 整數溢位問題
- 陣列索引越界
建立完成後的結構(示意):
## 📈 學習曲線反思
- **第一週**: 熟悉基本語法和 LeetCode 平台
- **第二週**: 開始理解演算法思維
- **第三週**: 能獨立分析中等難度題目
- **第四週**: 開始關注時間空間複雜度最佳化
```
problems/NNNN-name/
├── README.md
├── csharp/
│ ├── Program.cs
│ └── csharp.csproj
├── go/
│ ├── main.go
│ └── go.mod
└── test/
├── SolutionTests.cs # xUnit 測試
├── TestProject.csproj
├── main_test.go # Go testing
└── edge_cases.md
```
## 🔗 有用資源
- [LeetCode Patterns](https://leetcode.com/discuss/general-discussion/458695/dynamic-programming-patterns)
- [演算法與資料結構筆記](https://github.com/your-notes-repo)
- [LeetCode Solutions 參考](https://github.com/your-solutions-repo)
- 建立月度日誌(依模板生成 `logs/YYYY-MM.md`
```
./utils/leetcode_helper.sh log 2025-09
```
- 更新主 README目前顯示題目統計後續可擴充自動彙整
```
./utils/leetcode_helper.sh readme
```
## 執行與測試
- 執行 C# 解法:
```
cd problems/NNNN-name/csharp
dotnet run
```
- 執行 Go 解法:
```
cd problems/NNNN-name/go
go run main.go
```
- 執行該題的測試(同時跑 C# 與 Go
```
./utils/run_tests.sh NNNN-name [all|csharp|go]
# 也可只給題號:
./utils/run_tests.sh 3025
# 僅跑 C# 或 Go
./utils/run_tests.sh 3025 csharp
./utils/run_tests.sh 3025 go
# 顯示說明:
./utils/run_tests.sh --help
# 列出目前可用題目:
./utils/run_tests.sh --list
```
或分別執行:
```
cd problems/NNNN-name/test
dotnet test
go test -v
```
## utils 的用途
`utils/leetcode_helper.sh` 提供三個主要功能,將繁瑣步驟自動化、保持專案一致性;`utils/run_tests.sh` 則統一執行測試。
- problem根據輸入的題號、名稱與難度建立一個完整題目骨架
- 產生題目 `README.md`(含題目資訊、思路、測試與筆記段落)
- 建立 `csharp/``go/` 目錄及基本程式碼
- 建立 `test/` 目錄,內含 xUnit、Go 測試模板(統一用 `utils/run_tests.sh` 執行)
- 初始化 Go module`go.mod`
- readme掃描 `problems/` 題目數量,輸出簡單統計到終端(可再擴充寫回本檔)
- log`templates/logs-template.md.tmpl` 生成月誌雛形,方便每日記錄與月度回顧
`utils/run_tests.sh` 全域測試執行:
- 用法:`./utils/run_tests.sh <problem> [all|csharp|go]`
- <problem> 可為題號(如 `3025`)、資料夾名(如 `3025-find-...`)、或完整路徑(如 `problems/3025-...`
- 其他:`--help` 顯示說明、`--list` 列出可用題目
- 範例:
- `./utils/run_tests.sh 3025`(同時跑 C# 與 Go
- `./utils/run_tests.sh 3025 csharp`(只跑 C#
- `./utils/run_tests.sh --list`
小提醒:腳本內建的模板語言為繁中,可依需求修改 `templates/` 與腳本內容。
## 模板與筆記
- 題目模板:`templates/problem-template.md.tmpl`
- 月誌模板:`templates/logs-template.md.tmpl`
建議每題完成後:
- 更新該題 `README.md` 的「解題思路」「測試案例」「學習筆記」段落
-`logs/YYYY-MM.md` 紀錄當日題目、時間、心得與統計
## Templates 強化(重點)
- **Problem 模板新增**
- 先備條件與限制(輸入範圍、是否需要 in-place/排序)
- 解法比較A/B/C、正確性要點、優缺點
- 乾跑Dry Run步驟示例
- API 設計C#/Go 方法簽名)與常見陷阱清單
- 對拍/隨機測試建議;更完整的邊界清單
- **Logs 模板新增**
- 本月設定(主題/目標/挑戰)與主題覆蓋追蹤
- 連續天數Streak與錯誤類型統計
- 困難案例復盤與下月計畫欄位
## Problem 模板範例節錄3516
```
# [3516] Find Closest Person
## 題目資訊
- 難度: Easy
- 標籤: Math
- 題目連結: https://leetcode.com/problems/find-closest-person/
- 練習日期: 2025-09-04
- 目標複雜度: 時間 O(1), 空間 O(1)
## 先備條件與限制
- 輸入: x, y, z 為整數;值域小;需比較兩者距離
- 回傳: 1/2/0 表示誰先到或同時到
## 解法比較
1. 解法A直接比距離
- 思路: 計算 |x-z| 與 |y-z|,比較大小
- 正確性: 距離等速 → 距離小者先到
- 複雜度: O(1) / O(1)
2. 解法B
## 乾跑
- x=2, y=7, z=4 → |2-4|=2, |7-4|=3 → 回傳 1
## 實作細節與 API 設計
- C#
public int FindClosest(int x, int y, int z) { ... }
- Go
func findClosest(x, y, z int) int { ... }
## 測試案例
- 邊界: 等距回傳0、同點、極小/極大值
```
完整寫法可參考:`problems/3516-find-closest-person/README.md`
## 測試範例(可直接複製改題名)
- xUnitC#
```csharp
using Xunit;
public class SolutionTests {
[Theory]
[InlineData(2, 7, 4, 1)]
[InlineData(2, 5, 6, 2)]
[InlineData(1, 5, 3, 0)]
public void FindClosest_Works(int x, int y, int z, int expected) {
var s = new Solution();
Assert.Equal(expected, s.FindClosest(x, y, z));
}
}
```
- Go testing
```go
package main
import "testing"
func TestFindClosest(t *testing.T) {
tests := []struct{ x, y, z, want int }{
{2, 7, 4, 1},
{2, 5, 6, 2},
{1, 5, 3, 0},
}
for _, tt := range tests {
if got := findClosest(tt.x, tt.y, tt.z); got != tt.want {
t.Fatalf("x=%d y=%d z=%d want=%d got=%d", tt.x, tt.y, tt.z, tt.want, got)
}
}
}
```
## 自訂模板
- 直接編輯:`templates/problem-template.md.tmpl``templates/logs-template.md.tmpl`
- 工具腳本已改為讀取 `templates/` 目錄的檔案生成骨架:
- 問題頁:`templates/problem/README.md.tmpl`
- C#`templates/problem/csharp/*`
- Go`templates/problem/go/*`
- 測試:`templates/problem/test/*`
- 月誌:`templates/logs-template.md.tmpl`
不需修改腳本本身即可客製化模板。
## 工具清單
- `utils/leetcode_helper.sh`: 管理題目與月誌
- 功能:
- `problem <題號> <題目名稱-kebab> <難度>`:建立新題目(產生 `README.md``csharp/``go/``test/` 骨架)
- `log [YYYY-MM]`:建立月度學習日誌(預設本月)
- `readme`:顯示題目數量統計
- `-h|--help`:顯示說明
- 範例:
- `./utils/leetcode_helper.sh problem 3025 find-the-number-of-ways-to-place-people-i Medium`
- `./utils/leetcode_helper.sh log 2025-09`
- `./utils/leetcode_helper.sh --help`
- `utils/run_tests.sh`: 執行指定題目的測試
- 語法:`./utils/run_tests.sh <problem> [all|csharp|go]`
- <problem> 可為:題號(如 `3025`/ 目錄名(如 `3025-find-…`/ 完整路徑(如 `problems/3025-…`
- 參數:`--help` 顯示說明、`--list` 列出現有題目
- 範例:
- `./utils/run_tests.sh 3025`(同時跑 C# 與 Go
- `./utils/run_tests.sh 3025 csharp`(只跑 C#
- `./utils/run_tests.sh --list`
## 未來可擴充方向
- 主 README 自動彙整各題狀態(難度、語言、連結、完成度)
- 加入 CI如 GitHub Actions自動跑各題測試
- 更完整的模板與範例(含 I/O、邊界測資
---
*最後更新: 2025-09-01*
---
account : iak64825@jioso.com
password : ww5&Hy73dgh
歡迎依個人習慣調整腳本與模板,持續穩定地練習最重要!

View File

@@ -1,586 +0,0 @@
# 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>net8.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/csharp.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

View File

@@ -1,24 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "largestGoodInteger", "largestGoodInteger.csproj", "{DF73131C-3A52-FFDC-7C0C-19190AA3E331}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{DF73131C-3A52-FFDC-7C0C-19190AA3E331}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{DF73131C-3A52-FFDC-7C0C-19190AA3E331}.Debug|Any CPU.Build.0 = Debug|Any CPU
{DF73131C-3A52-FFDC-7C0C-19190AA3E331}.Release|Any CPU.ActiveCfg = Release|Any CPU
{DF73131C-3A52-FFDC-7C0C-19190AA3E331}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {E9F3A871-90C4-4B8E-81E2-B0AF873694BF}
EndGlobalSection
EndGlobal

View File

@@ -1,63 +0,0 @@
public class Solution {
public string LargestGoodInteger(string num)
{
// var count = 0;
// char lastNum = 'a';
// var numList = new List<int>();
// for (var i = 0; i < num.Length; i++)
// {
// if (num[i] == lastNum)
// {
// count++;
// if (count == 3)
// {
// numList.Add(int.Parse(num[i].ToString()));
// }
// }
// else
// {
// count = 1;
// }
// lastNum = num[i];
// }
// if (numList.Count == 0)
// {
// return "";
// }
// else
// {
// var a = numList.Max().ToString();
// return $"{a}{a}{a}";
// }
string max = "";
for (int i = 0; i < num.Length - 2; i++)
{
if (num[i] == num[i + 1] && num[i] == num[i + 2])
{
string current = $"{num[i]}{num[i]}{num[i]}";
if (max == "") max = current;
else
{
if (int.Parse(current) > int.Parse(max))
max = current;
}
}
}
return max;
}
}
class program
{
static void Main()
{
var solution = new Solution();
Console.WriteLine(solution.LargestGoodInteger("6777133339"));
}
}

View File

@@ -1,23 +0,0 @@
package main
import "fmt"
func LargestGoodInteger(num string) string {
max := ""
for i := 0; i < len(num)-2; i++ {
if num[i] == num[i+1] && num[i] == num[i+2] {
current := string([]byte{num[i], num[i], num[i]})
if current > max {
max = current
}
}
}
return max
}
func main() {
fmt.Println(LargestGoodInteger("7636669283"))
}

View File

@@ -1,24 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "ProductQueries", "C#\ProductQueries.csproj", "{412F89C4-B1BF-D819-298B-9C873A098742}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{412F89C4-B1BF-D819-298B-9C873A098742}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{412F89C4-B1BF-D819-298B-9C873A098742}.Debug|Any CPU.Build.0 = Debug|Any CPU
{412F89C4-B1BF-D819-298B-9C873A098742}.Release|Any CPU.ActiveCfg = Release|Any CPU
{412F89C4-B1BF-D819-298B-9C873A098742}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {BDF3A5A3-29B8-4169-8A46-A13A7DE900D8}
EndGlobalSection
EndGlobal

View File

@@ -1,69 +0,0 @@
using System;
public class Solution
{
public int[] ProductQueries(int n, int[][] queries)
{
// 1. n => calculate in powers of 2
// 2. get number array without 0
var powers = CalPower(n);
return CalQueries(powers, queries);
}
private int[] CalPower(int n)
{
var result = new List<int>();
while (n > 0)
{
var num = n % 2;
result.Add(num);
n /= 2;
}
var newResult = new List<int>();
for (var i = 0; i < result.Count; i++)
{
if (result[i] != 0)
{
var ans = (int)Math.Pow(2, i);
newResult.Add(ans);
}
}
return newResult.ToArray();
}
private int[] CalQueries(int[] powers, int[][] queries)
{
const int MOD = 1000000007;
var result = new List<int>();
foreach (var query in queries)
{
long count = 1;
for (var i = query[0]; i <= query[1]; i++)
{
count = (count * powers[i]) % MOD;
}
result.Add(count);
}
return result.ToArray();
}
}
class Program
{
static void Main()
{
var Solution = new Solution();
var ans = Solution.ProductQueries(15, [[0, 1], [2, 2], [0, 3]]);
Console.WriteLine(string.Join(", ", ans));
ans = Solution.ProductQueries(919, [[5,5],[4,4],[0,1],[1,5],[4,6],[6,6],[5,6],[0,3],[5,5],[5,6],[1,2],[3,5],[3,6],[5,5],[4,4],[1,1],[2,4],[4,5],[4,4],[5,6],[0,4],[3,3],[0,4],[0,5],[4,4],[5,5],[4,6],[4,5],[0,4],[6,6],[6,6],[6,6],[2,2],[0,5],[1,4],[0,3],[2,4],[5,5],[6,6],[2,2],[2,3],[5,5],[0,6],[3,3],[6,6],[4,4],[0,0],[0,2],[6,6],[6,6],[3,6],[0,4],[6,6],[2,2],[4,6]]);
Console.WriteLine(string.Join(", ", ans));
}
}

View File

@@ -1,5 +0,0 @@
Given a positive integer n, there exists a 0-indexed array called powers, composed of the minimum number of powers of 2 that sum to n. The array is sorted in non-decreasing order, and there is only one way to form the array.
You are also given a 0-indexed 2D integer array queries, where queries[i] = [lefti, righti]. Each queries[i] represents a query where you have to find the product of all powers[j] with lefti <= j <= righti.
Return an array answers, equal in length to queries, where answers[i] is the answer to the ith query. Since the answer to the ith query may be too large, each answers[i] should be returned modulo 109 + 7.

View File

@@ -1,24 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "numberOfWays", "numberOfWays.csproj", "{1E81E272-AF2C-9CB4-F90B-0AAC263D10DC}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{1E81E272-AF2C-9CB4-F90B-0AAC263D10DC}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{1E81E272-AF2C-9CB4-F90B-0AAC263D10DC}.Debug|Any CPU.Build.0 = Debug|Any CPU
{1E81E272-AF2C-9CB4-F90B-0AAC263D10DC}.Release|Any CPU.ActiveCfg = Release|Any CPU
{1E81E272-AF2C-9CB4-F90B-0AAC263D10DC}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {AD18FC84-E2FB-4382-96DF-8AE7E50C1401}
EndGlobalSection
EndGlobal

View File

@@ -1,48 +0,0 @@
// knapsack problem
public class Solution
{
public int NumberOfWays(int n, int x)
{
const int MOD = 1_000_000_007;
// list all the powers which smaller than n
var powers = new List<int>();
var num = 1;
while (true)
{
int pow = (int)Math.Pow(num, x);
if (pow > n)
break;
powers.Add(pow);
num++;
}
// dynamic programming
var dp = new int[n + 1];
dp[0] = 1;
foreach (var power in powers)
{
for (var i = n; i >= power; i--)
{
dp[i] = (dp[i] + dp[i - power]) % MOD;
}
}
return dp[n];
}
}
class Program
{
static void Main()
{
var solution = new Solution();
Console.WriteLine(solution.NumberOfWays(4, 1));
Console.WriteLine(solution.NumberOfWays(100, 3));
}
}

View File

@@ -1,38 +0,0 @@
public class Solution
{
public int AreaOfMaxDiagonal(int[][] dimensions)
{
int max = 0;
int maxArea = 0;
foreach (var dimension in dimensions)
{
var dimensionSqrt = dimension[0] * dimension[0] + dimension[1] * dimension[1];
var area = dimension[0] * dimension[1];
if (dimensionSqrt > max)
{
max = dimensionSqrt;
maxArea = area;
}
else if (dimensionSqrt == max)
{
maxArea = Math.Max(maxArea, area);
}
}
return maxArea;
}
}
public class Program
{
public static void Main()
{
var Solution = new Solution();
var dimensions = new int[][] { [6,5],[8,6],[2,10],[8,1],[9,2],[3,5],[3,5]};
var result = Solution.AreaOfMaxDiagonal(dimensions);
Console.WriteLine(result);
}
}

View File

@@ -1,27 +0,0 @@
package main
import (
"fmt"
"math"
)
func areaOfMaxDiagonal(dimensions [][]int) int{
maxDiagonal := 0
maxArea := 0
for _, dimension := range dimensions{
l := dimension[0]
w := dimension[1]
diagonalSquare := l * l + w * w
area := l * w
if diagonalSquare > maxDiagonal{
maxDiagonal = diagonalSquare
maxArea = area
}else if diagonalSquare == maxDiagonal{
maxArea = int(math.Max(float64(maxArea), float64(area)))
}
}
return maxArea
}

View File

@@ -1,24 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MinimumArea", "MinimumArea.csproj", "{61A8B87F-638B-4246-13C4-CC226CFBBEA5}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{61A8B87F-638B-4246-13C4-CC226CFBBEA5}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{61A8B87F-638B-4246-13C4-CC226CFBBEA5}.Debug|Any CPU.Build.0 = Debug|Any CPU
{61A8B87F-638B-4246-13C4-CC226CFBBEA5}.Release|Any CPU.ActiveCfg = Release|Any CPU
{61A8B87F-638B-4246-13C4-CC226CFBBEA5}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C6FDF6F7-60CD-4B35-B619-6F79B7243CA7}
EndGlobalSection
EndGlobal

View File

@@ -1,28 +0,0 @@
public class Solution {
public int MinimumArea(int[][] grid)
{
var x = grid[0].Length;
var y = grid.Length;
int min_x = x;
int max_x = 0;
int min_y = y;
int max_y = 0;
for (var i = 0; i < x; i++)
{
for (var j = 0; j < y; j++)
{
if (grid[j][i])
{
min_x = Math.Min(min_x, i);
max_x = Math.Max(max_x, i);
min_y = Math.Min(min_y, j);
max_y = Math.Max(max_y, j);
}
}
}
return (max_x - min_x + 1) * (max_y - min_y + 1);
}
}

View File

@@ -1,40 +0,0 @@
package main
import "fmt"
func minimumArea(grid [][]int) int {
row := len(grid)
col := len(grid[0])
min_x := col
max_x := 0
min_y := row
max_y := 0
for i:=0; i<row; i++{
for j:=0; j<col; j++{
if grid[i][j] == 1{
min_x = Min(min_x, j)
max_x = Max(max_x, j)
min_y = Min(min_y, i)
max_y = Max(max_y, i)
}
}
}
return (max_x-min_x+1) * (max_y-min_y+1)
}
func Min(a, b int)int{
if a < b {
return a
}
return b
}
func Max(a, b int)int{
if a > b{
return a
}
return b
}

View File

@@ -1,21 +0,0 @@
public class Solution {
public bool IsPowerOfThree(int n) {
if(n <= 0)
return false;
if(n == 1)
return true;
if(n % 3 != 0)
return false;
return IsPowerOfThree(n/3);
}
}
class program{
static void Main(){
var Solution = new Solution();
Console.WriteLine(Solution.IsPowerOfThree(9));
Console.WriteLine(Solution.IsPowerOfThree(0));
Console.WriteLine(Solution.IsPowerOfThree(-1));
}
}

View File

@@ -1,22 +0,0 @@
Given an integer n, return true if it is a power of three. Otherwise, return false.
An integer n is a power of three, if there exists an integer x such that n == 3x.
Example 1:
Input: n = 27
Output: true
Explanation: 27 = 33
Example 2:
Input: n = 0
Output: false
Explanation: There is no x where 3x = 0.
Example 3:
Input: n = -1
Output: false
Explanation: There is no x where 3x = (-1).

View File

@@ -1,26 +0,0 @@
package main
import "fmt"
type Solution struct{}
func (s Solution) IsPowerOfThree(n int) bool{
if n <= 0{
return false
}
if n == 1{
return true
}
if n % 3 != 0{
return false
}
return s.IsPowerOfThree(n/3)
}
func main(){
solution := Solution{}
fmt.Println(solution.IsPowerOfThree(27))
fmt.Println(solution.IsPowerOfThree(0))
fmt.Println(solution.IsPowerOfThree(-1))
}

View File

@@ -1,24 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "MaxCollectedFruits", "MaxCollectedFruits.csproj", "{AA67CF61-67B3-7229-E3F9-D471B0EF4EDE}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{AA67CF61-67B3-7229-E3F9-D471B0EF4EDE}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{AA67CF61-67B3-7229-E3F9-D471B0EF4EDE}.Debug|Any CPU.Build.0 = Debug|Any CPU
{AA67CF61-67B3-7229-E3F9-D471B0EF4EDE}.Release|Any CPU.ActiveCfg = Release|Any CPU
{AA67CF61-67B3-7229-E3F9-D471B0EF4EDE}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {B9D47F51-61C3-4A24-890A-01C9AC85EC93}
EndGlobalSection
EndGlobal

View File

@@ -1,67 +0,0 @@
public class Solution
{
public int MaxCollectedFruits(int[][] fruits)
{
int n = fruits.Length;
int ans = 0;
for (int i = 0; i < n; ++i) ans += fruits[i][i];
int dp()
{
int[] prev = Enumerable.Repeat(int.MinValue, n).ToArray();
int[] curr = new int[n];
prev[n - 1] = fruits[0][n - 1];
for (int i = 1; i < n - 1; ++i)
{
Array.Fill(curr, int.MinValue);
for (int j = Math.Max(n - 1 - i, i + 1); j < n; ++j)
{
int best = prev[j];
if (j - 1 >= 0)
{
best = Math.Max(best, prev[j - 1]);
}
if (j + 1 < n)
{
best = Math.Max(best, prev[j + 1]);
}
curr[j] = best + fruits[i][j];
}
var temp = prev;
prev = curr;
curr = temp;
}
return prev[n - 1];
}
ans += dp();
for (int i = 0; i < n; ++i)
{
for (int j = 0; j < i; ++j)
{
var temp = fruits[j][i];
fruits[j][i] = fruits[i][j];
fruits[i][j] = temp;
}
}
ans += dp();
return ans;
}
}
class Program
{
static void Main()
{
var Solution = new Solution();
var fruits = new int[][] { [1,2,3,4],[5,6,8,7],[9,10,11,12],[13,14,15,16]};
Console.WriteLine(Solution.MaxCollectedFruits(fruits));
}
}

View File

@@ -1,24 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "SortMatrix", "SortMatrix.csproj", "{60318F94-4F41-A4B8-C189-A8135ECCECCB}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{60318F94-4F41-A4B8-C189-A8135ECCECCB}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{60318F94-4F41-A4B8-C189-A8135ECCECCB}.Debug|Any CPU.Build.0 = Debug|Any CPU
{60318F94-4F41-A4B8-C189-A8135ECCECCB}.Release|Any CPU.ActiveCfg = Release|Any CPU
{60318F94-4F41-A4B8-C189-A8135ECCECCB}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {9F59D1F6-D9F3-492C-BC39-A5771AF22B36}
EndGlobalSection
EndGlobal

View File

@@ -1,115 +0,0 @@
public class Solution
{
public int[][] SortMatrix(int[][] grid)
{
// 左下
var leftDiagonals = new Dictionary<int, List<int>>();
for (var i = 0; i < grid.Length; i++)
{
// total -> 2n + 1 way
for (var j = 0; j <= i; j++)
{
int diagonal = i - j;
if (!leftDiagonals.ContainsKey(diagonal))
{
leftDiagonals[diagonal] = new List<int>();
}
leftDiagonals[diagonal].Add(grid[i][j]);
}
}
// 右上
var rightDiagonals = new Dictionary<int, List<int>>();
for (var i = 0; i < grid.Length; i++)
{
for (var j = i; j < grid.Length; j++)
{
int diagonal = j - i;
if (!rightDiagonals.ContainsKey(diagonal))
{
rightDiagonals[diagonal] = new List<int>();
}
rightDiagonals[diagonal].Add(grid[i][j]);
}
}
foreach (var diagonal in leftDiagonals.Values)
{
diagonal.Sort((a, b) => b.CompareTo(a));
}
foreach (var diagonal in rightDiagonals.Values)
{
diagonal.Sort((a, b) => a.CompareTo(b));
}
for (var i = 0; i < grid.Length; i++)
{
for (var j = 0; j <= i; j++)
{
int diagonal = i - j;
grid[i][j] = leftDiagonals[diagonal][0];
leftDiagonals[diagonal].RemoveAt(0);
}
for (var j = i; j < grid.Length; j++)
{
if (i == j) continue;
int diagonal = j - i;
grid[i][j] = rightDiagonals[diagonal][0];
rightDiagonals[diagonal].RemoveAt(0);
}
}
return grid;
}
}
public class Solution2 {
public int[][] SortMatrix(int[][] grid) {
int n = grid.Length;
for (int i = 0; i < n; i++) {
List<int> tmp = new List<int>();
for (int j = 0; i + j < n; j++) {
tmp.Add(grid[i + j][j]);
}
tmp.Sort((a, b) => b.CompareTo(a));
for (int j = 0; i + j < n; j++) {
grid[i + j][j] = tmp[j];
}
}
for (int j = 1; j < n; j++) {
List<int> tmp = new List<int>();
for (int i = 0; j + i < n; i++) {
tmp.Add(grid[i][j + i]);
}
tmp.Sort();
for (int i = 0; j + i < n; i++) {
grid[i][j + i] = tmp[i];
}
}
return grid;
}
}
class Program
{
static void Main()
{
var Solution = new Solution();
var gird = new int[][] { [1, 7, 3], [9, 8, 2], [4, 5, 6] };
var result = Solution.SortMatrix(gird);
for (int i = 0; i < result.Length; i++)
{
for (int j = 0; j < result[i].Length; j++)
{
Console.Write(result[i][j] + " ");
}
Console.WriteLine();
}
}
}

View File

@@ -1,24 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "FindDiagonalOrder", "FindDiagonalOrder.csproj", "{B3151728-C057-4305-DD4C-9A2AFBFC189A}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{B3151728-C057-4305-DD4C-9A2AFBFC189A}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{B3151728-C057-4305-DD4C-9A2AFBFC189A}.Debug|Any CPU.Build.0 = Debug|Any CPU
{B3151728-C057-4305-DD4C-9A2AFBFC189A}.Release|Any CPU.ActiveCfg = Release|Any CPU
{B3151728-C057-4305-DD4C-9A2AFBFC189A}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {DB56539A-6F32-4D28-B91F-BB1DCF46F4D0}
EndGlobalSection
EndGlobal

View File

@@ -1,10 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -1,61 +0,0 @@
public class Solution {
public int[] FindDiagonalOrder(int[][] mat)
{
if (mat == null || mat.Length == 0 || mat[0].Length == 0)
{
return new int[0];
}
var m = mat.Length;
var n = mat[0].Length;
var diagonals = new Dictionary<int, List<int>>();
for (var i = 0; i < m; i++)
{
for (var j = 0; j < n; j++)
{
int diagonalIndex = i + j;
if (!diagonals.ContainsKey(diagonalIndex))
{
diagonals[diagonalIndex] = new List<int>();
}
diagonals[diagonalIndex].Add(mat[i][j]);
}
}
var result = new List<int>();
foreach (var key in diagonals.Keys)
{
var diagonal = diagonals[key];
if (key % 2 == 0)
{
result.AddRange(diagonal);
}
else
{
diagonal.Reverse();
result.AddRange(diagonal);
}
}
return result.ToArray();
}
}
class Program
{
static void Main()
{
var Solution = new Solution();
int[][] mat1 = new int[][]{
new int[]{1,2,3},
new int[]{4,5,6},
new int[]{7,8,9}
};
Console.WriteLine(string.Join(", ", Solution.FindDiagonalOrder(mat1)));
}
}

View File

@@ -1,45 +0,0 @@
package main
import "fmt"
func findDiagonalOrder(mat [][]int) []int {
if len(mat) == 0 || len(mat[0]) == 0{
return []int{}
}
m := len(mat)
n := len(mat[0])
// maps
diagonals := make(map[int][]int)
for i:=0; i< m;i++{
for j:=0; j < n; j++{
index := i+j
diagonals[index] = append(diagonals[index], mat[i][j])
}
}
result := []int{}
for i:= 0; i< m+n-1; i++{
if i% 2 == 0{
reverse(diagonals[i])
result = append(result, diagonals[i]...)
}else{
result = append(result, diagonals[i]...)
}
}
return result
}
func reverse(slice []int){
left, right :=0, len(slice)-1
for left < right{
slice[left], slice[right] = slice[right], slice[left]
left++
right--
}
}

View File

@@ -1,7 +0,0 @@
1. 觀察矩陣對角線模式
1. (0,0) -> 1 -> i+j = 0
2. (1, 0), (0, 1) -> 2 -> i+j = 1
3. (2, 0), (1, 1), (0, 2) -> 3 -> i+j = 2
2. how to deal with diagonal sorting?
1. while (i+j) % 2 == 1
2. while (i+j) % 2 == 0 reversed

View File

@@ -1,24 +0,0 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "soupServings", "soupServings.csproj", "{6D960F00-6A53-6E19-86A1-4BF3D1CD764F}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{6D960F00-6A53-6E19-86A1-4BF3D1CD764F}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{6D960F00-6A53-6E19-86A1-4BF3D1CD764F}.Debug|Any CPU.Build.0 = Debug|Any CPU
{6D960F00-6A53-6E19-86A1-4BF3D1CD764F}.Release|Any CPU.ActiveCfg = Release|Any CPU
{6D960F00-6A53-6E19-86A1-4BF3D1CD764F}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {11CC27B7-C17E-4820-8A68-ADD32A2B37F8}
EndGlobalSection
EndGlobal

View File

@@ -1,56 +0,0 @@
using System;
public class Solution
{
private Dictionary<(int, int), double> dp = new Dictionary<(int, int), double>();
public double SoupServings(int n)
{
if (n > 5000)
return 1.0;
n = (n + 24) / 25;
// use dynamic programming
return Helper(n, n);
}
private double Helper(int a, int b)
{
if (a <= 0 && b <= 0)
{
return 0.5;
}
if (a <= 0)
{
return 1.0;
}
if (b <= 0)
{
return 0.0;
}
if (dp.ContainsKey((a, b)))
{
return dp[(a, b)];
}
double probability = 0.25 * (
Helper(a - 4, b) +
Helper(a - 3, b - 1) +
Helper(a - 2, b - 2) +
Helper(a - 1, b - 3)
);
dp[(a, b)] = probability;
return probability;
}
}
class Program
{
static void Main()
{
var Solution = new Solution();
var ans = Solution.SoupServings(800);
Console.WriteLine(ans);
}
}

View File

@@ -1,10 +0,0 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -1,52 +0,0 @@
package main
import ("fmt")
type Solution struct{
dp map[[2]int]float64
}
func NewSolution() *Solution{
return &Solution{dp: make(map[[2]int]float64)}
}
func (s *Solution) SoupServings(n int)float64{
if n > 5000{
return 1.0
}
n = (n+24) /25
return s.helper(n, n)
}
func (s * Solution) helper(a, b int) float64 {
if a <= 0 && b <= 0{
return 0.5
}
if a <= 0{
return 1.0
}
if b <= 0{
return 0
}
if val, exist := s.dp[[2]int{a, b}]; exist{
return val
}
probability := 0.25 * (
s.helper(a-4, b) +
s.helper(a-3, b-1) +
s.helper(a-2, b-2) +
s.helper(a-1, b-3))
s.dp[[2]int {a, b}] = probability
return probability
}
func main(){
Solution := NewSolution()
ans := Solution.SoupServings(100)
fmt.Println(ans)
}

View File

@@ -1,14 +0,0 @@
You have two soups, A and B, each starting with n mL. On every turn, one of the following four serving operations is chosen at random, each with probability 0.25 independent of all previous turns:
pour 100 mL from type A and 0 mL from type B
pour 75 mL from type A and 25 mL from type B
pour 50 mL from type A and 50 mL from type B
pour 25 mL from type A and 75 mL from type B
Note:
There is no operation that pours 0 mL from A and 100 mL from B.
The amounts from A and B are poured simultaneously during the turn.
If an operation asks you to pour more than you have left of a soup, pour all that remains of that soup.
The process stops immediately after any turn in which one of the soups is used up.
Return the probability that A is used up before B, plus half the probability that both soups are used up in the same turn. Answers within 10-5 of the actual answer will be accepted.

View File

@@ -6,14 +6,18 @@
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| 09/01 | Maximum Average Pass Ratio | Medium | C# | 1hr | Done | 第一次用到Priority Queue |
| 09/02 | Find The Number of Ways to Place People I | Medium | C# | 0.5hr | Done | 二維點位判斷 |
| 09/02 | Find The Number of Ways to Place People I | Medium | go | 0.2hr | Done | go Prictice |
| 09/02 | Find The Number of Ways to Place People I | Medium | C#, go | 0.7hr | Done | 二維點位判斷 |
| 09/03 | Find The Number of Ways to Place People II | Hard | C# | 0.2hr | Done | Same as [#3025] |
| 09/04 | Find Closest Person | Easy | C#, go | 0.1hr | Done | 數學判斷 |
| 09/05 | Minimum Operations to Make the Integer Zero | Medium | C# | 1.5hr | Done | |
### Week 2
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
| 09/08 | Convert Integer To The Sum Of Two No Zero Integers | Easy | C# | 0.2hr | Done | |
| 09/11 | Sort Vowels In A String | Medium | C# | 0.2hr | Done | |
| 09/11 | [3227]Vowels Game In A String | Medium | C#, go | 0.1hr | Done | like easy |
### Week 3
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
@@ -23,18 +27,19 @@
### Week 4
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
| 09/22 | [3005]Count Elements With Maximum Frequency | Easy | C# | 0.3hr | Done | Dictionary Mapping |
| 09/23| [0165]Compare Version Numbers | Medium | C# | 0.4hr | Done | String, Two Pointers |
## 📈 本月統計
### 完成情況
- **總練習天數**: 3
- **完成題數**: 3
- **語言分布**: C# 3(題), Go 1(題)
- **難度分布**: Easy 0(題), Medium 2(題), Hard 1(題)
- **總練習天數**: 9
- **完成題數**: 9
- **語言分布**: C# 9(題), Go 2(題)
- **難度分布**: Easy 3(題), Medium 5(題), Hard 1(題)
### 時間投入
- **總時間**: 1.9小時
- **總時間**: 4.5小時
- **平均每題**: 分鐘
- **每日平均**: 分鐘
@@ -42,6 +47,7 @@
### 新掌握的技巧
1. 貪心策略
2. string轉char, char轉string
### 常犯錯誤分析
1.

View File

@@ -83,4 +83,102 @@
> "演算法不是背出來的,是理解出來的" - 在第15題3Sum卡住兩天後的感悟
---
**總結**: 八月是很好的開始,從完全新手到能獨立解決中等題目。九月要持續挑戰自己!
**總結**: 八月是很好的開始,從完全新手到能獨立解決中等題目。九月要持續挑戰自己!
# YYYY年M月 學習記錄
## 本月設定(目標與主題)
- **主題**:例如 雙指針 / 滑動視窗 / DP / 圖論
- **目標題數**X 題Easy Y / Medium Z / Hard W
- **投入時間**:每日 ≥ N 分鐘;每週 ≥ M 小時
- **挑戰**:至少完成 Hard ≥ H 題;每週寫 1 篇總結
## 📅 每日練習記錄
### Week 1 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
### Week 2 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
### Week 3 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
### Week 4 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
## 🧭 主題覆蓋追蹤(勾選)
- [ ] 陣列/字串Two Pointers / Sliding Window
- [ ] 資料結構Stack/Queue/Heap/Set/Map
- [ ] 排序與搜尋Sorting / Binary Search
- [ ] 數學與位運算Math / Bit
- [ ] 動態規劃DP
- [ ] 圖論BFS/DFS/最短路/拓撲)
- [ ] 樹BST/遍歷/序列化)
## 📈 本月統計
### 完成情況
- **練習天數**: 天
- **完成題數**: 題Easy / Medium / Hard
- **語言分布**: C# (題), Go (題)
- **連續天數Streak**: 天;本月斷點:第 天
### 時間投入
- **總時間**: 小時
- **平均每題**: 分鐘
- **每日平均**: 分鐘
### 正確率 / 嘗試次數
- **一次通過**: 題
- **二次通過**: 題
- **多次調整**: 題(記錄主因:邊界/複雜度/實作)
## 🎯 本月重點學習
### 新掌握的技巧(至少 3 條)
1.
2.
3.
### 常見錯誤與對策
1. 錯誤:;對策:
2. 錯誤:;對策:
3. 錯誤:;對策:
### 語言心得(實作層面)
- **C#**LINQ/Span/效能注意點/測試習慣
- **Go**slice/map/指標/錯誤處理/benchmark 習慣
## 🔄 困難案例復盤
### 案例1題號/主題
- 問題:
- 嘗試:
- 解決:
- 學習:
### 案例2題號/主題
- 問題:
- 嘗試:
- 解決:
- 學習:
## 📝 下月計畫
- **目標題數**
- **重點主題**
- **練習節奏**
- **要避免的坑**
## 💡 本月金句
>
---
**總結**:本月最大收穫是 ______,接下來專注 ______

99
logs/2025-11.md Normal file
View File

@@ -0,0 +1,99 @@
# YYYY年M月 學習記錄
## 本月設定(目標與主題)
- 主題:雙指針 / 滑動視窗 / DP / 圖論(自訂)
- 目標題數X 題Easy Y / Medium Z / Hard W
- 投入時間:每日 ≥ N 分鐘;每週 ≥ M 小時
- 挑戰:至少完成 Hard ≥ H 題;每週寫 1 篇總結
## 📅 每日練習記錄
### Week 1 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
### Week 2 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
### Week 3 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
### Week 4 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
## 🧭 主題覆蓋追蹤(勾選)
- [ ] 陣列/字串Two Pointers / Sliding Window
- [ ] 資料結構Stack/Queue/Heap/Set/Map
- [ ] 排序與搜尋Sorting / Binary Search
- [ ] 數學與位運算Math / Bit
- [ ] 動態規劃DP
- [ ] 圖論BFS/DFS/最短路/拓撲)
- [ ]BST/遍歷/序列化)
## 📈 本月統計
### 完成情況
- 練習天數:天
- 完成題數Easy / Medium / Hard
- 語言分布C# (題), Go (題)
- 連續天數Streak本月斷點第 天
### 時間投入
- 總時間:小時
- 平均每題:分鐘
- 每日平均:分鐘
### 正確率 / 嘗試次數
- 一次通過:題
- 二次通過:題
- 多次調整:題(主因:邊界/複雜度/實作)
## 🎯 本月重點學習
### 新掌握的技巧(至少 3 條)
1.
2.
3.
### 常見錯誤與對策
1. 錯誤:;對策:
2. 錯誤:;對策:
3. 錯誤:;對策:
### 語言心得(實作層面)
- C#LINQ/Span/效能注意點/測試習慣
- Goslice/map/指標/錯誤處理/benchmark 習慣
## 🔄 困難案例復盤
### 案例1題號/主題
- 問題:
- 嘗試:
- 解決:
- 學習:
### 案例2題號/主題
- 問題:
- 嘗試:
- 解決:
- 學習:
## 📝 下月計畫
- 目標題數:
- 重點主題:
- 練習節奏:
- 要避免的坑:
## 💡 本月金句
>
---
**總結**:本月最大收穫是 ______,接下來專注 ______

99
logs/2025-12.md Normal file
View File

@@ -0,0 +1,99 @@
# YYYY年M月 學習記錄
## 本月設定(目標與主題)
- 主題:雙指針 / 滑動視窗 / DP / 圖論(自訂)
- 目標題數X 題Easy Y / Medium Z / Hard W
- 投入時間:每日 ≥ N 分鐘;每週 ≥ M 小時
- 挑戰:至少完成 Hard ≥ H 題;每週寫 1 篇總結
## 📅 每日練習記錄
### Week 1 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
### Week 2 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
### Week 3 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
### Week 4 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
## 🧭 主題覆蓋追蹤(勾選)
- [ ] 陣列/字串Two Pointers / Sliding Window
- [ ] 資料結構Stack/Queue/Heap/Set/Map
- [ ] 排序與搜尋Sorting / Binary Search
- [ ] 數學與位運算Math / Bit
- [ ] 動態規劃DP
- [ ] 圖論BFS/DFS/最短路/拓撲)
- [ ]BST/遍歷/序列化)
## 📈 本月統計
### 完成情況
- 練習天數:天
- 完成題數Easy / Medium / Hard
- 語言分布C# (題), Go (題)
- 連續天數Streak本月斷點第 天
### 時間投入
- 總時間:小時
- 平均每題:分鐘
- 每日平均:分鐘
### 正確率 / 嘗試次數
- 一次通過:題
- 二次通過:題
- 多次調整:題(主因:邊界/複雜度/實作)
## 🎯 本月重點學習
### 新掌握的技巧(至少 3 條)
1.
2.
3.
### 常見錯誤與對策
1. 錯誤:;對策:
2. 錯誤:;對策:
3. 錯誤:;對策:
### 語言心得(實作層面)
- C#LINQ/Span/效能注意點/測試習慣
- Goslice/map/指標/錯誤處理/benchmark 習慣
## 🔄 困難案例復盤
### 案例1題號/主題
- 問題:
- 嘗試:
- 解決:
- 學習:
### 案例2題號/主題
- 問題:
- 嘗試:
- 解決:
- 學習:
## 📝 下月計畫
- 目標題數:
- 重點主題:
- 練習節奏:
- 要避免的坑:
## 💡 本月金句
>
---
**總結**:本月最大收穫是 ______,接下來專注 ______

22
makefile Normal file
View File

@@ -0,0 +1,22 @@
# Makefile - 安裝環境工具
.PHONY: all update upgrade install setup check
all: setup
update:
sudo apt update
upgrade:
sudo apt upgrade -y
install:
sudo apt install -y dotnet-sdk-8.0 golang-go
setup: update upgrade install check
@echo "✅ 開發環境安裝完成!"
check:
@echo "=== 檢查安裝結果 ==="
@dotnet --version || echo "⚠️ dotnet 未安裝成功"
@go version || echo "⚠️ go 未安裝成功"

View File

@@ -0,0 +1,85 @@
# [165] Compare Version Numbers
## 題目資訊
- **難度**: Medium
- **標籤**: Two Pointer, String
- **題目連結**: https://leetcode.com/problems/compare-version-numbers/
- **練習日期**: 2025-09-23
- **目標複雜度**: 時間 O(n)、空間 O(1)
## 題目描述
Given two **version strings**, `version1` and `version2`, compare them. A version string consists of **revisions** separated by dots `'.'`. The **value of the revision** is its **integer conversion** ignoring leading zeros.
To compare version strings, compare their revision values in **left-to-right order**. If one of the version strings has fewer revisions, treat the missing revision values as `0`.
Return the following:
If `version1 < version2`, return -1.
If `version1 > version2`, return 1.
Otherwise, return 0.
## 先備條件與限制
- 1 <= `version1.length, version2.length` <= 500
- version1 and version2 only contain digits and '.'
- version1 and version2 are valid version numbers.
- All the given revisions in `version1` and `version2` can be stored in a **32-bit integer**
## 解題思路
### 初步分析
- 類型:字串雙指標掃描
- 關鍵觀察:版本號可以逐段比較,缺段視為 0且修訂號只包含數字
- 複雜度目標理由:只需線性掃過兩個字串一次即可完成比較
### 解法比較
1. 解法A基準/暴力):
- 名稱:`MyCompareVersion`
- 思路:以 `Split('.')` 將版本字串拆成陣列,逐段轉成整數後比較;若另一側段數不足以 0 補齊
- 正確性LeetCode 限制每段可裝進 32-bit 整數,直接使用 `int.TryParse` 安全可靠
- 複雜度:時間 O(n),空間 O(k)k 為段數,需配置字串陣列與子字串)
2. 解法B優化
- 名稱:`CompareVersion`
- 思路:雙指標同步掃描兩個版本字串,藉由 `ReadOnlySpan<char>` 抓取下一段,去除前導 0 後用字元比較避免溢位與額外配置
- 正確性:段長先比較、再逐字比較,完全符合題意;缺段會回傳空 span 視為 0
- 複雜度:時間 O(n),空間 O(1)
## 實作細節
### 常見陷阱
- 前導 0需在比較前移除否則 `"01"``"1"` 會被視為不同
- 段數不一致:右側缺少的段要視為 0
- 空字串或末尾點:`""``"1."` 都可能出現,需要妥善處理
- 非數字字元:防守性處理(當前實作視為 0但依題意實際資料不會出現
## 測試案例
### 範例輸入輸出
```
Input: version1 = "1.2", version2 = "1.10"
Output: -1
Explanation:
version1's second revision is "2" and version2's second revision is "10": 2 < 10, so version1 < version2.
```
### 邊界清單
- [x] 空字串 / 僅有 0
- [x] 單一段 / 全相同
- [x] 含 0 / 大數 / 前導 0
- [ ] 去重(與此題無關)
- [x] 大資料壓力(長度 200 的版本字串)
## 複雜度分析
- 最壞:時間 O(n)、空間 O(1)
- 備註:保留的 `MyCompareVersion` 雖然同為 O(n),但空間為 O(k)
## 相關題目 / Follow-up
- 179. Largest Number同樣涉及字串排序與比較
- 415. Add Strings字串逐位操作
## 學習筆記
- 今天學到:兩指標搭配 `ReadOnlySpan<char>` 可以在 C# 中避免額外配置
- 卡住與修正:原本 console app 移除 `Main` 造成 `dotnet test` 無法編譯,後來補回精簡入口
- 待優化:若要支援超長版本段,可考慮使用 `BigInteger` 或自訂比較邏輯(目前已以字元比較處理)
---
**總結**:核心在於逐段處理並正確處理前導 0 與缺段情況,適合練習字串雙指標與記憶體優化技巧。

View File

@@ -0,0 +1,144 @@
// LeetCode 165: Compare Version Numbers
// 難度: Medium
// 日期: 2025-09-23
using System;
public class Solution
{
// Two-pointer parser that compares segments without allocating intermediate arrays.
public int CompareVersion(string version1, string version2)
{
var i = 0;
var j = 0;
while (i < version1.Length || j < version2.Length)
{
var segment1 = NextSegment(version1, ref i);
var segment2 = NextSegment(version2, ref j);
var comparison = CompareSegments(segment1, segment2);
if (comparison != 0)
{
return comparison;
}
}
return 0;
}
// Reads the next numeric segment (between dots) as a span and advances the current index.
private static ReadOnlySpan<char> NextSegment(string version, ref int index)
{
if (index >= version.Length)
{
return ReadOnlySpan<char>.Empty;
}
var start = index;
while (index < version.Length && version[index] != '.')
{
index++;
}
var segment = version.AsSpan(start, index - start);
if (index < version.Length && version[index] == '.')
{
index++;
}
return segment;
}
// Compares two trimmed segments lexicographically to avoid integer overflow.
private static int CompareSegments(ReadOnlySpan<char> left, ReadOnlySpan<char> right)
{
left = TrimLeadingZeros(left);
right = TrimLeadingZeros(right);
if (left.Length > right.Length)
{
return 1;
}
if (left.Length < right.Length)
{
return -1;
}
for (var i = 0; i < left.Length; i++)
{
if (left[i] > right[i])
{
return 1;
}
if (left[i] < right[i])
{
return -1;
}
}
return 0;
}
private static ReadOnlySpan<char> TrimLeadingZeros(ReadOnlySpan<char> segment)
{
var index = 0;
while (index < segment.Length && segment[index] == '0')
{
index++;
}
return index == segment.Length ? ReadOnlySpan<char>.Empty : segment[index..];
}
public int MyCompareVersion(string version1, string version2)
{
var v1 = version1.Split('.');
var v2 = version2.Split('.');
if (v1.Length >= v2.Length)
{
return CompareString(v1, v2);
}
return CompareString(v2, v1) * -1;
}
private static int CompareString(string[] longer, string[] shorter)
{
for (var i = 0; i < longer.Length; i++)
{
_ = int.TryParse(longer[i], out var num1);
var num2 = i < shorter.Length && int.TryParse(shorter[i], out var parsed) ? parsed : 0;
if (num1 > num2)
{
return 1;
}
if (num1 < num2)
{
return -1;
}
}
return 0;
}
}
public class Program
{
public static void Main(string[] args)
{
// optional: keep console app functional for manual verification
if (args.Length == 2)
{
var solution = new Solution();
var result = solution.CompareVersion(args[0], args[1]);
Console.WriteLine(result);
}
}
}

View File

@@ -1,10 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,56 @@
// LeetCode 165: Compare Version Numbers 單元測試xUnit
using System.Linq;
using Xunit;
public class SolutionTests {
private readonly Solution _s = new Solution();
[Theory]
[InlineData("1.01", "1.001", 0)]
[InlineData("1.0", "1.0.0", 0)]
[InlineData("1.0.0.0", "1", 0)]
[InlineData("0.1", "1.1", -1)]
[InlineData("1.0.1", "1", 1)]
[InlineData("7.5.2.4", "7.5.3", -1)]
public void CompareVersion_ReturnsExpectedResult(string version1, string version2, int expected) {
var actual = _s.CompareVersion(version1, version2);
Assert.Equal(expected, actual);
}
[Theory]
[InlineData("1.0.1", "1")]
[InlineData("3.0.0", "2.9.9.9")]
[InlineData("10.4", "10.3.9")]
public void CompareVersion_IsAntiSymmetric(string left, string right) {
var forward = _s.CompareVersion(left, right);
var backward = _s.CompareVersion(right, left);
Assert.Equal(1, forward);
Assert.Equal(-1, backward);
}
[Theory]
[InlineData("", "", 0)]
[InlineData("", "0", 0)]
[InlineData("0.0.0", "", 0)]
[InlineData("000", "0", 0)]
[InlineData("2147483647", "2147483646", 1)]
[InlineData("2147483646", "2147483647", -1)]
public void CompareVersion_HandlesBoundaryInputs(string version1, string version2, int expected) {
var actual = _s.CompareVersion(version1, version2);
Assert.Equal(expected, actual);
}
[Fact]
public void CompareVersion_LongSequencesDifferAtEnd() {
var left = string.Join('.', Enumerable.Repeat("0", 199).Append("1"));
var right = string.Join('.', Enumerable.Repeat("0", 200));
var result = _s.CompareVersion(left, right);
Assert.Equal(1, result);
}
}

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.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/csharp.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,29 @@
# 邊界情況清單165 Compare Version Numbers
## 需要測試的邊界
- [x] 空輸入 / 單一元素:`""``"0"`
- [x] 重複元素 / 全相同:`"1.0.0"` vs `"1"`
- [x] 極值(最小/最大):`"2147483647"` vs `"2147483646"`
- [x] 含負數 / 0 / 大數:題目無負數,已覆蓋多零與大修訂號
- [x] 大資料量接近上限200 段版本字串
## 額外案例
### 案例 1
- 輸入:`version1 = "", version2 = "0"`
- 預期:`0`
- 說明:空字串缺少所有段,視為全 0
### 案例 2
- 輸入:`version1 = "2147483647", version2 = "2147483646"`
- 預期:`1`
- 說明:驗證最大 32-bit 整數段處理
### 案例 3
- 輸入:`version1 = "0.0.0", version2 = "0"`
- 預期:`0`
- 說明:多段全 0 與單段 0 視為相同
### 案例 4
- 輸入:`version1 = string.Join(".", Enumerable.Repeat("0", 199)) + ".1"`, `version2 = string.Join(".", Enumerable.Repeat("0", 200))`
- 預期:`1`
- 說明:長度 200 的版本字串,在最後一段差異才分勝負

View File

@@ -0,0 +1,30 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csharp", "csharp\csharp.csproj", "{CF022C7B-CAF3-706D-67E1-FB93518229B7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProject", "test\TestProject.csproj", "{C670389A-9CE7-B456-51E5-A79D56E199CF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CF022C7B-CAF3-706D-67E1-FB93518229B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF022C7B-CAF3-706D-67E1-FB93518229B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF022C7B-CAF3-706D-67E1-FB93518229B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF022C7B-CAF3-706D-67E1-FB93518229B7}.Release|Any CPU.Build.0 = Release|Any CPU
{C670389A-9CE7-B456-51E5-A79D56E199CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C670389A-9CE7-B456-51E5-A79D56E199CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C670389A-9CE7-B456-51E5-A79D56E199CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C670389A-9CE7-B456-51E5-A79D56E199CF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {C5790EDA-C36F-4FC3-877D-C7E20837E160}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,80 @@
# [166] Fraction To Recurring Decimal
## 題目資訊
- **難度**: Medium
- **標籤**: Hash Table, Math, Simulation
- **題目連結**: https://leetcode.com/problems/fraction-to-recurring-decimal/
- **練習日期**: 2025-09-24
- **目標複雜度**: 時間 O(L)、空間 O(L)L 為輸出字串長度,最多 10^4
## 題目描述
Given two integers representing the `numerator` and `denominator` of a fraction, return *the fraction* in string format.
If the fractional part is repeating, enclose the repeating part in parentheses.
If multiple answers are possible, return **any of them**.
It is **guaranteed** that the length of the answer string is less than `10^4` for all the given inputs.
## 先備條件與限制
- 輸入限制:`-2^31 <= numerator, denominator <= 2^31 - 1`,且 denominator ≠ 0
- 回傳/輸出格式:回傳十進位字串;有限小數直接輸出,小數有循環時用括號標記循環段
- 其他:允許使用 64-bit 以避免在取絕對值時溢位
## 解題思路
### 初步分析
- 類型:數學 / 模擬 / 哈希
- 關鍵觀察:整數除法僅靠餘數決定下一個小數位;相同餘數必定導致循環,位置可透過哈希表還原
- 複雜度目標理由:每個餘數最多處理一次,因此時間與空間成正比於輸出長度 L
### 解法比較
1. 解法A餘數位置哈希
- 思路:先處理正負號並計算整數部分;對小數部分反覆以 10 乘上餘數取商,並在 map 中紀錄餘數首次出現的索引,一旦重複即可插入括號
- 正確性:每個可能的餘數介於 0 與 |denominator|-1重複時即代表循環節開始未重複則最後餘數為 0有限小數
- 複雜度:時間 O(L) / 空間 O(L)
## 實作細節
- 先處理 `numerator == 0` 直接回傳 "0"
- 判斷結果正負號,使用 `long`/`long long` 取絕對值避免 `INT_MIN` 無法轉正的問題
- `integer_part = abs_num / abs_den` 直接加入結果,小數部分以餘數 `remainder = abs_num % abs_den` 開始
- 使用字典 `remainder -> index` 紀錄餘數在結果字串中的位置;迴圈內:餘數乘 10取下一位商並更新餘數
- 若餘數為 0表示小數結束不需括號若餘數再度出現在對應索引插入 `(`,在結尾加 `)`
## 常見陷阱
- 處理負數:符號只出現一次,判斷後用 64-bit 絕對值繼續運算避免 `--6...` 之類錯誤
- `INT_MIN / -1` 可能溢位:需先轉成 64-bit 再做除法與取餘數
- 餘數 map 要記錄的是「餘數出現時的輸出索引」,找到重複時要在該位置插入 `(`
- 每回合先檢查餘數是否重複再乘 10避免多插一位或落掉循環起點
- `numerator` 為 0 時無小數部分,直接回傳 "0"
## 測試案例
### 範例輸入輸出
```
Input: numerator = 4, denominator = 333
Output: "0.(012)"
```
### 邊界清單
- `numerator = 1, denominator = 2``"0.5"`(有限小數)
- `numerator = 1, denominator = 6``"0.1(6)"`(循環節不從第一位開始)
- `numerator = -50, denominator = 8``"-6.25"`(負數與有限小數)
- `numerator = 0, denominator = 5``"0"`(整數結果)
- `numerator = 1, denominator = 7``"0.(142857)"`(較長的循環節)
## 複雜度分析
- 最壞:時間 O(L)、空間 O(L)
- L 為輸出字串長度,等同於需要處理的餘數數量上限(題目保證 < 10^4
## 相關題目 / Follow-up
- 與任一進位制的循環小數檢測 base conversion類似可類比餘數循環檢測技巧
## 學習筆記
- 今天學到餘數 索引的哈希表能精準標記循環段搭配 `StringBuilder.Insert` 可快速加括號
- 卡住與修正`int.MinValue` 轉正時會拋例外改用 `long` 做完整流程含乘 10 與取餘就穩定
- 另外注意符號在輸出開頭先處理整數和小數部分都用正數運算可避免重複符號
- 待優化可以先行預估非循環長度以減少插入成本但對此題影響不大
---
**總結**這題的核心在於以餘數哈希判斷循環節適合練習小數表示與溢位處理

View File

@@ -0,0 +1,68 @@
// LeetCode 166: Fraction To Recurring Decimal
// 難度: Medium
// 日期: 2025-09-24
using System;
using System.Collections.Generic;
using System.Linq;
using System.Text;
public class Solution
{
public string FractionToDecimal(int numerator, int denominator)
{
if (numerator == 0) return "0";
long num = numerator;
long den = denominator;
StringBuilder result = new StringBuilder();
bool isNegative = (num < 0) ^ (den < 0);
if (isNegative) result.Append('-');
num = Math.Abs(num);
den = Math.Abs(den);
long integerPart = num / den;
result.Append(integerPart);
long remainder = num % den;
if (remainder == 0) return result.ToString();
result.Append('.');
result.Append(CalculateDecimalPart(remainder, den));
return result.ToString();
}
private string CalculateDecimalPart(long remainder, long denominator)
{
StringBuilder decimalBuilder = new StringBuilder();
Dictionary<long, int> remainderMap = new Dictionary<long, int>();
while (remainder != 0)
{
if (remainderMap.TryGetValue(remainder, out int repeatIndex))
{
decimalBuilder.Insert(repeatIndex, '(');
decimalBuilder.Append(')');
break;
}
remainderMap[remainder] = decimalBuilder.Length;
remainder *= 10;
long digit = remainder / denominator;
decimalBuilder.Append(digit);
remainder %= denominator;
}
return decimalBuilder.ToString();
}
}
public class Program {
public static void Main() {
var s = new Solution();
}
}

View File

@@ -1,10 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,3 @@
module leetcode-166
go 1.18

View File

@@ -0,0 +1,18 @@
// LeetCode 166: Fraction To Recurring Decimal
// 難度: Medium
// 日期: 2025-09-24
package main
import "fmt"
// TODO: 根據題意調整簽名
func solve(nums []int) int {
return 0
}
func main() {
fmt.Printf("Hello LeetCode 166!\n")
// TODO: 可加入簡單測試
}

View File

@@ -0,0 +1,27 @@
// LeetCode 166 單元測試xUnit
using Xunit;
public class SolutionTests {
private readonly Solution _s = new Solution();
[Theory]
[InlineData(4, 333, "0.(012)")]
[InlineData(1, 2, "0.5")]
[InlineData(1, 6, "0.1(6)")]
[InlineData(-50, 8, "-6.25")]
[InlineData(0, 5, "0")]
[InlineData(1, 7, "0.(142857)")]
public void FractionToDecimal_BasicAndRepeatingScenarios(int numerator, int denominator, string expected) {
var actual = _s.FractionToDecimal(numerator, denominator);
Assert.Equal(expected, actual);
}
[Fact]
public void FractionToDecimal_DenominatorOne_ReturnsIntegerString() {
var actual = _s.FractionToDecimal(2, 1);
Assert.Equal("2", actual);
}
}

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.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/csharp.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,20 @@
# 邊界情況清單166 Fraction To Recurring Decimal
## 需要測試的邊界
- [ ] 空輸入 / 單一元素
- [ ] 重複元素 / 全相同
- [ ] 極值(最小/最大)
- [ ] 含負數 / 0 / 大數
- [ ] 大資料量(接近上限)
## 額外案例
### 案例 1
- 輸入:
- 預期:
- 說明:
### 案例 2
- 輸入:
- 預期:
- 說明:

View File

@@ -0,0 +1,12 @@
// LeetCode 166 單元測試Go testing
package main
import "testing"
func TestExample(t *testing.T) {
// TODO: input := []int{}
// got := solve(input)
// want := 0
// if got != want { t.Fatalf("want %v got %v", want, got) }
}

View File

@@ -0,0 +1,65 @@
# [1317] Convert Integer To The Sum Of Two No Zero Integers
## 題目資訊
- **難度**: Easy
- **標籤**: Math
- **題目連結**: [LeetCode](https://leetcode.com/problems/convert-integer-to-the-sum-of-two-no-zero-integers/)
- **練習日期**: 2025-09-08
## 題目描述
No-Zero integer is a positive integer that does not contain any `0` in its decimal representation.
Given an integer `n`, return a list of two integers `[a, b]` where:
- `a` and `b` are No-Zero integers.
- `a + b = n`
The test cases are generated so that there is at least one valid solution. If there are many valid solutions, you can return any of them.
## 解題思路
### 初步分析
- 這題主要考察什麼概念?
迴圈遍歷 + 數字位數檢查
- 有什麼關鍵限制條件?
1. 兩個數都必須是正整數
2. 兩個數的十進制表示都不能包含數字 0
3. 兩個數相加必須等於 n
- 預期時間/空間複雜度?
### 解法概述
**解法**:
- 思路:
1. 從 i = 1 開始遍歷到 n-1
2. 對每個 i檢查 i 和 (n-i) 是否都不包含數字 0
3. 找到第一個滿足條件的組合就返回
- 時間複雜度O(n)
- 空間複雜度O(1)
## 測試案例
### 範例輸入輸出
```
Input: n = 2
Output: [1,1]
Explanation: Let a = 1 and b = 1.
Both a and b are no-zero integers, and a + b = 2 = n.
```
### 邊界情況
2 <= n <= 10^4
## 學習筆記
### 今天學到什麼?
-
### 遇到的困難
-
### 改善方向
-
### 相關題目
---
**總結**: 這題的核心概念是...,適合練習...技巧。

View File

@@ -0,0 +1,52 @@
// LeetCode 1317: Convert Integer To The Sum Of Two No Zero Integers
// 難度: Easy
// 日期: 2025-09-08
using System;
using System.Collections.Generic;
using System.Linq;
public class Solution
{
public int[] GetNoZeroIntegers(int n)
{
for (var i = 1; i < n; i++)
{
if (CheckIntegersWithNoZero(i) && CheckIntegersWithNoZero(n - i))
{
return new int[]{i, n - i};
}
}
return new int[]{};
}
private bool CheckIntegersWithNoZero(int n)
{
while (n > 0)
{
if (n % 10 == 0)
{
return false;
}
n /= 10;
}
return true;
}
}
public class Program {
public static void Main() {
var Solution = new Solution();
TestCase1(Solution);
// TestCase2();
}
static void TestCase1(Solution Solution) {
// Input:
var input = 1010;
// Expected: [11, 999]
int[] result = Solution.GetNoZeroIntegers(input);
// Actual:
Console.WriteLine($"Test 1: {result[0]}, {result[1]}");
}
}

View File

@@ -1,21 +0,0 @@
#!/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 ""
echo "📊 測試完成!"

View File

@@ -0,0 +1,101 @@
# [2749] Minimum Operations To Make The Integer Zero
## 題目資訊
- **難度**: Medium
- **標籤**: Bit Manipulation, Brainteaser, Enumeration
- **題目連結**: [LeetCode](https://leetcode.com/problems/minimum-operations-to-make-the-integer-zero/)
- **練習日期**: 2025-09-05
## 題目描述
You are given two integers `num1` and `num2`.
In one operation, you can choose integer i in the range `[0, 60]` and subtract `2^i + num2` from `num1`.
Return the integer denoting the *minimum* number of operations needed to make `num1` equal to `0`.
If it is impossible to make `num1` equal to `0`, return `-1`.
## 解題思路
### 初步分析
- 這題主要考察什麼概念?
1. 位元操作 (Bit Manipulation):需要理解二進制表示和位元運算
2. 數學建模:將實際問題轉換為數學等式
3. 枚舉 (Enumeration):嘗試不同的操作次數 k
4. 約束條件判斷:理解多個限制條件的邏輯關係
- 有什麼關鍵限制條件?
1. target ≥ 0
2. bitCount(target) ≤ k
3. k ≤ target
- 預期時間/空間複雜度?
- 時間複雜度O(60 × log(target)) ≈ O(1)
- 空間複雜度O(1)
### 解法概述
1. **解法**:
- 思路:
- 目標:讓 num1 變成 0
- 每次操作num1 = num1 - (2^i + num2)
- k 次操作後num1 - k*num2 - (2^i1 + 2^i2 + ... + 2^ik) = 0
- 重新整理target = num1 - k*num2 = 2^i1 + 2^i2 + ... + 2^ik
- 時間複雜度O(1)
- 空間複雜度O(1)
## 測試案例
### 範例輸入輸出
```
Input: num1 = 3, num2 = -2
Output: 3
Explanation:
We can make 3 equal to 0 with the following operations:
- We choose i = 2 and subtract 22 + (-2) from 3, 3 - (4 + (-2)) = 1.
- We choose i = 2 and subtract 22 + (-2) from 1, 1 - (4 + (-2)) = -1.
- We choose i = 0 and subtract 20 + (-2) from -1, (-1) - (1 + (-2)) = 0.
It can be proven, that 3 is the minimum number of operations that we need to perform.
```
### 邊界情況
- `1 <= num1 <= 10^9`
- `-10^9 <= num2 <= 10^9`
## 學習筆記
### 今天學到什麼?
- 二位元的操作寫法
### 遇到的困難
- 二位元的操作
1. 方法一: 逐位檢查法
- 程式碼:
``` C#
count += (int)(n & 1);
n >>= 1;
```
- 運作原理:
1. n & 1檢查最右邊的位元是否為 1
2. count += (int)(n & 1):如果是 1 就加到計數器
3. n >>= 1把 n 右移一位(去掉已檢查的位元)
4. 重複直到 n 變成 0
2. 方法二: 移除最右邊 1
- 程式碼:
``` C#
count++;
n &= n - 1;
```
- 運作原理:
1. n - 1讓最右邊的 1 變成 0其右邊的 0 都變成 1
2. n & (n - 1):神奇地移除了最右邊的 1
3. count++:每移除一個 1計數器就加 1
4. 重複直到 n 變成 0
### 改善方向
-
### 相關題目
- [#991](https://leetcode.com/problems/broken-calculator) Broken Calculator
- [#1658](https://leetcode.com/problems/minimum-operations-to-reduce-x-to-zero/) Minimum Operations to Reduce X to Zero
---
**總結**:
1. 學習二位元的使用技巧

View File

@@ -0,0 +1,84 @@
// LeetCode 2749: Minimum Operations To Make The Integer Zero
// 難度: Medium
// 日期: 2025-09-05
using System;
using System.Collections.Generic;
using System.Linq;
public class Solution
{
public int MakeTheIntegerZero(int num1, int num2)
{
for (int k = 1; k <= 60; k++)
{
long target = (long)num1 - (long)k * num2;
if (target < 0) continue;
int bitCount = CountSetBits(target);
if (bitCount <= k && k <= target)
{
return k;
}
}
return -1;
}
private int CountSetBits(long n)
{
int count = 0;
while (n > 0)
{
// 方法一
// count += (int)(n & 1);
// n >>= 1;
// 方法二
count++;
n &= n - 1;
}
return count;
}
}
public class Program
{
public static void Main()
{
Solution solution = new Solution();
TestCase1(solution);
TestCase2(solution);
}
static void TestCase1(Solution solution)
{
int num1 = 3, num2 = -2;
int expected = 3;
int actual = solution.MakeTheIntegerZero(num1, num2);
Console.WriteLine("Test 1:");
Console.WriteLine($"Input: num1 = {num1}, num2 = {num2}");
Console.WriteLine($"Expected: {expected}");
Console.WriteLine($"Actual: {actual}");
Console.WriteLine($"Result: {(actual == expected ? "PASS" : "FAIL")}");
Console.WriteLine();
}
static void TestCase2(Solution solution)
{
int num1 = 5, num2 = 7;
int expected = -1;
int actual = solution.MakeTheIntegerZero(num1, num2);
Console.WriteLine("Test 2:");
Console.WriteLine($"Input: num1 = {num1}, num2 = {num2}");
Console.WriteLine($"Expected: {expected}");
Console.WriteLine($"Actual: {actual}");
Console.WriteLine($"Result: {(actual == expected ? "PASS" : "FAIL")}");
Console.WriteLine();
}
}

View File

@@ -0,0 +1,70 @@
# [2785] Sort Vowels In A String
## 題目資訊
- **難度**: Medium
- **標籤**: String, Sorting
- **題目連結**: [LeetCode](https://leetcode.com/problems/sort-vowels-in-a-string/)
- **練習日期**: 2025-09-11
## 題目描述
給定一個 0-indexed 的字串 s重新排列 s 以獲得新字串 t使得
所有子音保持在原來的位置
母音必須按照 ASCII 值的非遞減順序排序
更正式地說:
如果存在索引 i其中 0 <= i < s.length s[i] 是子音那麼 t[i] = s[i]
對於索引對 i, j其中 0 <= i < j < s.length s[i] s[j] 都是母音那麼 t[i] ASCII 值不能高於 t[j]
母音定義: 'a', 'e', 'i', 'o', 'u' 以及它們的大寫形式
## 解題思路
### 初步分析
- 這題主要考察什麼概念
這題主要考察字串處理和排序概念
- 有什麼關鍵限制條件
- 預期時間/空間複雜度
O(n log k) / O(k)其中 n 為字串長度k 為母音數量
### 解法概述
1. **解法**:
- 思路
1. 遍歷字串收集所有母音及其位置
2. 對母音字符進行排序
3. 將排序後的母音按原位置重新放回字串
- 時間複雜度O(n + k log k) 其中 n 是字串長度k 是母音數量
- 空間複雜度O(k) 存儲母音字符和位置
## 測試案例
### 範例輸入輸出
```
Input: s = "lEetcOde"
Output: "lEOtcede"
Explanation:
母音 'E', 'e', 'O', 'e' 排序後變成 'E', 'O', 'e', 'e'
```
### 邊界情況
- `1 <= s.length <= 10^5`
- `s` consists only of letters of the English alphabet in uppercase and lowercase.
## 學習筆記
### 今天學到什麼?
-
### 遇到的困難
-
### 改善方向
-
### 相關題目
- [題目編號] 題目名稱 - 相似概念
- [題目編號] 題目名稱 - 進階版本
---
**總結**: 這題的核心概念是...適合練習...技巧

View File

@@ -0,0 +1,108 @@
// LeetCode 2785: Sort Vowels In A String
// 難度: Medium
// 日期: 2025-09-11
using System;
using System.Collections.Generic;
using System.Linq;
public class Solution {
public string SortVowels(string s) {
// to char[]
char[] sArray = s.ToCharArray();
// get all vowels
string vowels = "aeiouAEIOU";
List<int> vowelPositions = new List<int>();
List<char> vowelChars = new List<char>();
for(int i = 0; i < sArray.Length; i++){
if(vowels.Contains(sArray[i])){
vowelPositions.Add(i);
vowelChars.Add(sArray[i]);
}
}
// sort all vowels
vowelChars.Sort();
// insert vowels
for(var i = 0; i < vowelPositions.Count; i++){
sArray[vowelPositions[i]] = vowelChars[i];
}
return new string(sArray);
}
}
// 測試程式
public class Program {
public static void Main() {
Solution sol = new Solution();
// TODO: 加入測試案例
TestCase1(sol);
TestCase2(sol);
TestCase3(sol);
TestCase4(sol);
TestCase5(sol);
TestCase6(sol);
TestCase7(sol);
}
// 基本範例 - LeetCode官方例子
static void TestCase1(Solution sol) {
var s = "lEetcOde";
var result = sol.SortVowels(s);
var expected = "lEOtcede";
Console.WriteLine($"Test 1: Input: \"{s}\", Result: \"{result}\", Expected: \"{expected}\", Pass: {result == expected}");
}
// 只有子音 - 沒有母音的情況
static void TestCase2(Solution sol) {
var s = "lYmpH";
var result = sol.SortVowels(s);
var expected = "lYmpH";
Console.WriteLine($"Test 2: Input: \"{s}\", Result: \"{result}\", Expected: \"{expected}\", Pass: {result == expected}");
}
// 只有母音 - 測試排序功能
static void TestCase3(Solution sol) {
var s = "aEiOu";
var result = sol.SortVowels(s);
var expected = "EOaiu";
Console.WriteLine($"Test 3: Input: \"{s}\", Result: \"{result}\", Expected: \"{expected}\", Pass: {result == expected}");
}
// 混合大小寫母音
static void TestCase4(Solution sol) {
var s = "TestcasE";
var result = sol.SortVowels(s);
var expected = "TEstcase";
Console.WriteLine($"Test 4: Input: \"{s}\", Result: \"{result}\", Expected: \"{expected}\", Pass: {result == expected}");
}
// 單一字元 - 邊界情況
static void TestCase5(Solution sol) {
var s = "a";
var result = sol.SortVowels(s);
var expected = "a";
Console.WriteLine($"Test 5: Input: \"{s}\", Result: \"{result}\", Expected: \"{expected}\", Pass: {result == expected}");
}
// 重複母音
static void TestCase6(Solution sol) {
var s = "Aa";
var result = sol.SortVowels(s);
var expected = "Aa";
Console.WriteLine($"Test 6: Input: \"{s}\", Result: \"{result}\", Expected: \"{expected}\", Pass: {result == expected}");
}
// 較長的字串測試
static void TestCase7(Solution sol) {
var s = "RaInBoW";
var result = sol.SortVowels(s);
var expected = "RIanBoW";
Console.WriteLine($"Test 7: Input: \"{s}\", Result: \"{result}\", Expected: \"{expected}\", Pass: {result == expected}");
}
}

View File

@@ -0,0 +1,30 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csharp", "csharp\csharp.csproj", "{CF022C7B-CAF3-706D-67E1-FB93518229B7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProject", "test\TestProject.csproj", "{C670389A-9CE7-B456-51E5-A79D56E199CF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CF022C7B-CAF3-706D-67E1-FB93518229B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF022C7B-CAF3-706D-67E1-FB93518229B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF022C7B-CAF3-706D-67E1-FB93518229B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF022C7B-CAF3-706D-67E1-FB93518229B7}.Release|Any CPU.Build.0 = Release|Any CPU
{C670389A-9CE7-B456-51E5-A79D56E199CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C670389A-9CE7-B456-51E5-A79D56E199CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C670389A-9CE7-B456-51E5-A79D56E199CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C670389A-9CE7-B456-51E5-A79D56E199CF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {50409315-93FE-4BEF-BAEC-4B70A05B634A}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,91 @@
# [3005] Count_elements_with_maximum_frequency
## 題目資訊
- **難度**: Easy
- **標籤**:
- **題目連結**: https://leetcode.com/problems/count_elements_with_maximum_frequency/
- **練習日期**: 2025-09-22
- **目標複雜度**: 時間 O(?)、空間 O(?)
## 題目描述
> 在這裡貼上題目的完整描述(或重點)
## 先備條件與限制
- 輸入限制n ∈ [?, ?]、值域 ∈ [?, ?]
- 回傳/輸出格式:...
- 其他:是否允許排序/就地修改
## 解題思路
### 初步分析
- 類型:雙指針 / 滑動視窗 / 排序 / DP / 貪心 / 圖論 ...
- 關鍵觀察:
- 複雜度目標理由:
### 解法比較
1. 解法A基準/暴力):
- 思路:
- 正確性:
- 複雜度O(?) / O(?)
2. 解法B優化
- 思路:
- 正確性:
- 複雜度O(?) / O(?)
### 乾跑Dry Run
- 範例:...
## 實作細節與 API 設計
### C# 方法簽名(示意)
```csharp
public class Solution {
// TODO: 根據題意調整簽名
public int Solve(int[] nums) {
return 0;
}
}
```
### Go 方法簽名(示意)
```go
func solve(nums []int) int {
return 0
}
```
### 常見陷阱
- 邊界:空/單一/極值/全相等
- 去重:排序後跳重複、集合
- 溢位:使用 64-bit
## 測試案例
### 範例輸入輸出
```
Input: ...
Output: ...
Explanation: ...
```
### 邊界清單
- [ ] 空陣列/空字串
- [ ] 單一元素 / 全相同
- [ ] 含負數/0/大數
- [ ] 去重
- [ ] 大資料壓力
## 複雜度分析
- 最壞:時間 O(?)、空間 O(?)
## 相關題目 / Follow-up
-
## 學習筆記
- 今天學到:
- 卡住與修正:
- 待優化:
---
**總結**:這題的核心在於 ______,適合練習 ______

View File

@@ -0,0 +1,52 @@
// LeetCode 3005: Count_elements_with_maximum_frequency
// 難度: Easy
// 日期: 2025-09-22
using System;
using System.Collections.Generic;
using System.Linq;
public class Solution {
public int MaxFrequencyElements(int[] nums)
{
Dictionary<int, int> frequencyMap = new Dictionary<int, int>();
// put nums into dictionary map
foreach (var num in nums)
{
if (!frequencyMap.ContainsKey(num))
{
frequencyMap.Add(num, 0);
}
frequencyMap[num]++;
}
// find most frequency nums
int maxFrequency = 0;
if (frequencyMap.Count != 0)
{
maxFrequency = frequencyMap.Values.Max();
}
// count if have same max frequency nus
int count = 0;
foreach (var dic in frequencyMap)
{
if (dic.Value == maxFrequency)
{
count += maxFrequency;
}
}
return count;
}
}
public class Program {
public static void Main() {
var s = new Solution();
// TODO: 可加入簡單輸入/輸出測試
Console.WriteLine("Hello LeetCode 3005!");
}
}

View File

@@ -1,10 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,18 @@
// LeetCode 3005: Count_elements_with_maximum_frequency
// 難度: Easy
// 日期: 2025-09-22
package main
import "fmt"
// TODO: 根據題意調整簽名
func solve(nums []int) int {
return 0
}
func main() {
fmt.Printf("Hello LeetCode 3005!\n")
// TODO: 可加入簡單測試
}

View File

@@ -0,0 +1,24 @@
// LeetCode 3005 單元測試xUnit
using Xunit;
public class SolutionTests {
private readonly Solution _s = new Solution();
[Fact]
public void Example1() {
// TODO: Arrange
// var input = new int[] { };
// var expected = 0;
// Act
// var got = _s.Solve(input);
// Assert.Equal(expected, got);
Assert.True(true);
}
[Fact]
public void EdgeCases() {
Assert.True(true);
}
}

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.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/csharp.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,12 @@
// LeetCode 3005 單元測試Go testing
package main
import "testing"
func TestExample(t *testing.T) {
// TODO: input := []int{}
// got := solve(input)
// want := 0
// if got != want { t.Fatalf("want %v got %v", want, got) }
}

View File

@@ -0,0 +1,30 @@
Microsoft Visual Studio Solution File, Format Version 12.00
# Visual Studio Version 17
VisualStudioVersion = 17.5.2.0
MinimumVisualStudioVersion = 10.0.40219.1
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "csharp", "csharp\csharp.csproj", "{CF022C7B-CAF3-706D-67E1-FB93518229B7}"
EndProject
Project("{FAE04EC0-301F-11D3-BF4B-00C04F79EFBC}") = "TestProject", "test\TestProject.csproj", "{C670389A-9CE7-B456-51E5-A79D56E199CF}"
EndProject
Global
GlobalSection(SolutionConfigurationPlatforms) = preSolution
Debug|Any CPU = Debug|Any CPU
Release|Any CPU = Release|Any CPU
EndGlobalSection
GlobalSection(ProjectConfigurationPlatforms) = postSolution
{CF022C7B-CAF3-706D-67E1-FB93518229B7}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{CF022C7B-CAF3-706D-67E1-FB93518229B7}.Debug|Any CPU.Build.0 = Debug|Any CPU
{CF022C7B-CAF3-706D-67E1-FB93518229B7}.Release|Any CPU.ActiveCfg = Release|Any CPU
{CF022C7B-CAF3-706D-67E1-FB93518229B7}.Release|Any CPU.Build.0 = Release|Any CPU
{C670389A-9CE7-B456-51E5-A79D56E199CF}.Debug|Any CPU.ActiveCfg = Debug|Any CPU
{C670389A-9CE7-B456-51E5-A79D56E199CF}.Debug|Any CPU.Build.0 = Debug|Any CPU
{C670389A-9CE7-B456-51E5-A79D56E199CF}.Release|Any CPU.ActiveCfg = Release|Any CPU
{C670389A-9CE7-B456-51E5-A79D56E199CF}.Release|Any CPU.Build.0 = Release|Any CPU
EndGlobalSection
GlobalSection(SolutionProperties) = preSolution
HideSolutionNode = FALSE
EndGlobalSection
GlobalSection(ExtensibilityGlobals) = postSolution
SolutionGuid = {15EA9854-706B-456C-B6A2-6AF4670868DE}
EndGlobalSection
EndGlobal

View File

@@ -0,0 +1,82 @@
# [3227] Vowels Game In A String
## 題目資訊
- **難度**: Medium
- **標籤**: Math, String, Brainteaser, Game Theory
- **題目連結**: https://leetcode.com/problems/vowels-game-in-a-string/
- **練習日期**: 2025-09-12
- **目標複雜度**: 時間 O(n)、空間 O(1)
## 題目描述
Alice and Bob are playing a game on a string.
You are given a string `s`, Alice and Bob will take turns playing the following game where Alice starts **first**:
On Alice's turn, she has to remove any **non-empty** substring from `s` that contains an odd number of vowels.
On Bob's turn, he has to remove any non-empty substring from `s` that contains an even number of vowels.
The first player who cannot make a move on their turn loses the game. We assume that both Alice and Bob play optimally.
Return `true` if Alice wins the game, and `false` otherwise.
The English vowels are: `a`, `e`, `i`, `o`, and `u`.
## 先備條件與限制
- 輸入限制n ∈ [1, 10^5]、字符為小寫英文字母
- 回傳/輸出格式boolean 值true 表示 Alice 獲勝
## 解題思路
### 初步分析
- 類型:博弈論 / 數學 / 腦筋急轉彎
- 關鍵觀察:
- Alice 先手,需移除含奇數個母音的子字串
- Bob 後手,需移除含偶數個母音的子字串
- 複雜度目標理由:只需檢查是否存在母音
### 解法比較
1. 解法A基準/暴力):
- 思路:
發現 Alice 獲勝條件極其簡單
- 正確性:
只需檢查是否存在母音
- 複雜度O(n) / O(1)
### 常見陷阱
- 邊界:空字串(題目保證 n≥1、全母音、無母音
- 過度複雜化:誤以為需要複雜的博弈分析
- 計數錯誤:誤以為需要精確計算母音數量
- 大小寫:題目保證小寫字母
## 測試案例
### 範例輸入輸出
```
Input: s = "leetcode"
Output: true
Explanation: Alice 可以移除 "leetcod"含3個母音剩下 "e"Bob 無法移除含偶數母音的子字串
```
### 邊界清單
- 全母音字串Alice 立即移除整個字串獲勝
- 無母音字串Alice 無法行動敗北
- 單一字符(母音/子音)
- 混合字串(含有母音和子音)
- 長字串壓力測試
## 複雜度分析
- 最壞:時間 O(n)、空間 O(1)
- 最佳:時間 O(1)(首字符即為母音)、空間 O(1)
## 相關題目 / Follow-up
- LeetCode 345: Reverse Vowels of a String
- LeetCode 1456: Maximum Number of Vowels in a Substring of Given Length
- LeetCode 2062: Count Vowel Substrings of a String
## 學習筆記
- 今天學到:
- 卡住與修正:
- 待優化:
---
**總結**:這題的核心在於 ______,適合練習 ______

View File

@@ -0,0 +1,24 @@
// LeetCode 3227: Vowels Game In A String
// 難度: Medium
// 日期: 2025-09-12
using System;
using System.Collections.Generic;
using System.Linq;
public class Solution {
public bool DoesAliceWin(string s)
{
string vowels = "aeiou";
foreach (var character in s)
{
if (vowels.Contains(character))
{
return true;
}
}
return false;
}
}

View File

@@ -0,0 +1,7 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,4 @@
module leetcode/3227-vowels-game-in-a-string
go 1.18

View File

@@ -0,0 +1,19 @@
// LeetCode 3227: Vowels Game In A String
// 難度: Medium
// 日期: 2025-09-12
package vowels
import "strings"
// DoesAliceWin returns true if the string contains any vowel.
// Game theory reduces to: Alice wins iff there exists at least one vowel.
func DoesAliceWin(s string) bool {
const vowels = "aeiou"
for _, ch := range s {
if strings.ContainsRune(vowels, ch) {
return true
}
}
return false
}

View File

@@ -0,0 +1,168 @@
// LeetCode 3227: Vowels Game in a String 單元測試xUnit
// Problem: Alice and Bob play a game. Alice removes substrings with odd vowels,
// Bob removes substrings with even vowels. Alice wins if string has any vowels.
using Xunit;
public class SolutionTests
{
private readonly Solution _s = new Solution();
[Fact]
public void Example1_StringWithVowels_AliceWins()
{
// Arrange
var input = "leetcode"; // contains vowels: e,e,o,e
var expected = true; // Alice wins
// Act
var got = _s.DoesAliceWin(input);
// Assert
Assert.Equal(expected, got);
}
[Fact]
public void Example2_StringWithoutVowels_BobWins()
{
// Arrange
var input = "bcdf"; // no vowels
var expected = false; // Bob wins (Alice can't make first move)
// Act
var got = _s.DoesAliceWin(input);
// Assert
Assert.Equal(expected, got);
}
[Fact]
public void AllVowels_AliceWins()
{
// Arrange
var input = "aeiou"; // all vowels (odd count = 5)
var expected = true; // Alice removes entire string
// Act
var got = _s.DoesAliceWin(input);
// Assert
Assert.Equal(expected, got);
}
[Fact]
public void SingleVowel_AliceWins()
{
// Arrange
var input = "a"; // single vowel
var expected = true; // Alice removes it immediately
// Act
var got = _s.DoesAliceWin(input);
// Assert
Assert.Equal(expected, got);
}
[Fact]
public void SingleConsonant_BobWins()
{
// Arrange
var input = "b"; // single consonant, no vowels
var expected = false; // Alice can't move
// Act
var got = _s.DoesAliceWin(input);
// Assert
Assert.Equal(expected, got);
}
[Fact]
public void MixedString_EvenVowelCount_AliceWins()
{
// Arrange
var input = "programming"; // vowels: o,a,i (3 vowels, odd)
var expected = true; // Alice can remove all vowels at once
// Act
var got = _s.DoesAliceWin(input);
// Assert
Assert.Equal(expected, got);
}
[Fact]
public void LongStringNoVowels_BobWins()
{
// Arrange
var input = "bcdfghjklmnpqrstvwxyz"; // all consonants
var expected = false; // No vowels = Bob wins
// Act
var got = _s.DoesAliceWin(input);
// Assert
Assert.Equal(expected, got);
}
[Fact]
public void RepeatedVowels_AliceWins()
{
// Arrange
var input = "aaaa"; // 4 vowels (even count)
var expected = true; // Alice can remove 3, leaving 1 (Bob can't move)
// Act
var got = _s.DoesAliceWin(input);
// Assert
Assert.Equal(expected, got);
}
[Fact]
public void EdgeCases()
{
// Single character tests
Assert.True(_s.DoesAliceWin("e")); // vowel
Assert.False(_s.DoesAliceWin("x")); // consonant
// Two character tests
Assert.True(_s.DoesAliceWin("ab")); // has vowel 'a'
Assert.False(_s.DoesAliceWin("xy")); // no vowels
// Vowel at different positions
Assert.True(_s.DoesAliceWin("xabc")); // vowel at start-middle
Assert.True(_s.DoesAliceWin("abcx")); // vowel in middle
Assert.True(_s.DoesAliceWin("xbca")); // vowel at end
}
[Fact]
public void GameTheoryValidation()
{
// Test cases that validate the game theory logic:
// If total vowels = 0: Alice loses (can't make first move)
Assert.False(_s.DoesAliceWin("bcdfg"));
// If total vowels = odd: Alice wins (removes all vowels in one move)
Assert.True(_s.DoesAliceWin("hello")); // e,o = 2 vowels (even), but Alice still wins
Assert.True(_s.DoesAliceWin("beautiful")); // e,a,u,i,u = 5 vowels (odd)
// If total vowels = even > 0: Alice wins (leaves exactly 1 vowel for Bob)
Assert.True(_s.DoesAliceWin("code")); // o,e = 2 vowels (even)
Assert.True(_s.DoesAliceWin("education")); // e,u,a,i,o = 5 vowels, but any vowels = Alice wins
}
[Theory]
[InlineData("", false)] // empty string - no vowels
[InlineData("aeiou", true)] // all vowels
[InlineData("bcdfg", false)] // all consonants
[InlineData("hello", true)] // mixed with vowels
[InlineData("rhythm", false)] // no vowels (y not considered vowel)
[InlineData("queue", true)] // multiple same vowels
public void ParameterizedTests(string input, bool expected)
{
// Act & Assert
Assert.Equal(expected, _s.DoesAliceWin(input));
}
}

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.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/csharp.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,20 @@
# 邊界情況清單3227 Vowels Game In A String
## 需要測試的邊界
- [ ] 空輸入 / 單一元素
- [ ] 重複元素 / 全相同
- [ ] 極值(最小/最大)
- [ ] 含負數 / 0 / 大數
- [ ] 大資料量(接近上限)
## 額外案例
### 案例 1
- 輸入:
- 預期:
- 說明:
### 案例 2
- 輸入:
- 預期:
- 說明:

View File

@@ -0,0 +1,188 @@
// LeetCode 3227: Vowels Game in a String 單元測試Go testing
// Problem: Alice and Bob play a game. Alice removes substrings with odd vowels,
// Bob removes substrings with even vowels. Alice wins if string has any vowels.
package vowels_test
import (
"fmt"
"testing"
vowels "leetcode/3227-vowels-game-in-a-string/go"
)
func TestExample1(t *testing.T) {
// "leetcode" contains vowels: e,e,o,e
input := "leetcode"
got := vowels.DoesAliceWin(input)
want := true // Alice wins
if got != want {
t.Fatalf("input %q: want %v got %v", input, want, got)
}
}
func TestExample2(t *testing.T) {
// "bcdf" has no vowels
input := "bcdf"
got := vowels.DoesAliceWin(input)
want := false // Bob wins (Alice can't make first move)
if got != want {
t.Fatalf("input %q: want %v got %v", input, want, got)
}
}
func TestAllVowels(t *testing.T) {
// All vowels string - Alice removes entire string
input := "aeiou"
got := vowels.DoesAliceWin(input)
want := true
if got != want {
t.Fatalf("input %q: want %v got %v", input, want, got)
}
}
func TestSingleVowel(t *testing.T) {
// Single vowel - Alice removes it immediately
input := "a"
got := vowels.DoesAliceWin(input)
want := true
if got != want {
t.Fatalf("input %q: want %v got %v", input, want, got)
}
}
func TestSingleConsonant(t *testing.T) {
// Single consonant - Alice can't move
input := "b"
got := vowels.DoesAliceWin(input)
want := false
if got != want {
t.Fatalf("input %q: want %v got %v", input, want, got)
}
}
func TestMixedString(t *testing.T) {
// "programming" has vowels: o,a,i
input := "programming"
got := vowels.DoesAliceWin(input)
want := true // Alice can remove vowels
if got != want {
t.Fatalf("input %q: want %v got %v", input, want, got)
}
}
func TestLongStringNoVowels(t *testing.T) {
// All consonants - no vowels means Bob wins
input := "bcdfghjklmnpqrstvwxyz"
got := vowels.DoesAliceWin(input)
want := false
if got != want {
t.Fatalf("input %q: want %v got %v", input, want, got)
}
}
func TestRepeatedVowels(t *testing.T) {
// Even number of same vowels - Alice can leave 1 for Bob
input := "aaaa"
got := vowels.DoesAliceWin(input)
want := true
if got != want {
t.Fatalf("input %q: want %v got %v", input, want, got)
}
}
func TestEdgeCases(t *testing.T) {
testCases := []struct {
input string
want bool
desc string
}{
{"e", true, "single vowel"},
{"x", false, "single consonant"},
{"ab", true, "has vowel 'a'"},
{"xy", false, "no vowels"},
{"xabc", true, "vowel in middle"},
{"abcx", true, "vowel at start"},
{"xbca", true, "vowel at end"},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
got := vowels.DoesAliceWin(tc.input)
if got != tc.want {
t.Fatalf("input %q (%s): want %v got %v", tc.input, tc.desc, tc.want, got)
}
})
}
}
func TestGameTheoryValidation(t *testing.T) {
testCases := []struct {
input string
want bool
desc string
}{
// If total vowels = 0: Alice loses
{"bcdfg", false, "no vowels - Alice can't move"},
{"rhythm", false, "no vowels (y not counted)"},
// Any vowels > 0: Alice wins
{"hello", true, "e,o vowels - Alice wins"},
{"beautiful", true, "e,a,u,i,u vowels - Alice wins"},
{"code", true, "o,e vowels - Alice wins"},
{"education", true, "e,u,a,i,o vowels - Alice wins"},
{"queue", true, "u,e,u,e vowels - Alice wins"},
}
for _, tc := range testCases {
t.Run(tc.desc, func(t *testing.T) {
got := vowels.DoesAliceWin(tc.input)
if got != tc.want {
t.Fatalf("input %q (%s): want %v got %v", tc.input, tc.desc, tc.want, got)
}
})
}
}
func TestParameterized(t *testing.T) {
testCases := []struct {
input string
want bool
}{
{"", false}, // empty string
{"aeiou", true}, // all vowels
{"bcdfg", false}, // all consonants
{"hello", true}, // mixed with vowels
{"rhythm", false}, // no vowels
{"queue", true}, // multiple same vowels
{"xyz", false}, // short no vowels
{"programming", true}, // longer mixed
}
for _, tc := range testCases {
t.Run(tc.input, func(t *testing.T) {
got := vowels.DoesAliceWin(tc.input)
if got != tc.want {
t.Errorf("doesAliceWin(%q) = %v, want %v", tc.input, got, tc.want)
}
})
}
}
// Benchmark test
func BenchmarkDoesAliceWin(b *testing.B) {
testString := "abcdefghijklmnopqrstuvwxyz"
b.ResetTimer()
for i := 0; i < b.N; i++ {
vowels.DoesAliceWin(testString)
}
}
// Example test for documentation
func ExampleDoesAliceWin() {
result1 := vowels.DoesAliceWin("leetcode")
result2 := vowels.DoesAliceWin("bcdf")
fmt.Println(result1)
fmt.Println(result2)
// Output:
// true
// false
}

View File

@@ -0,0 +1,70 @@
# [3516] Find Closest Person
## 題目資訊
- **難度**: Easy
- **標籤**: Math
- **題目連結**: [LeetCode](https://leetcode.com/problems/find-closest-person/)
- **練習日期**: 2025-09-04
## 題目描述
You are given three integers `x`, `y`, and `z`, representing the positions of three people on a number line:
`x` is the position of Person 1.
`y` is the position of Person 2.
`z` is the position of Person 3, who does **not** move.
Both Person 1 and Person 2 move toward Person 3 at the same speed.
Determine which person reaches Person 3 first:
Return 1 if Person 1 arrives first.
Return 2 if Person 2 arrives first.
Return 0 if both arrive at the same time.
Return the result accordingly.
## 解題思路
### 初步分析
- 這題主要考察什麼概念?
距離計算和比較。使用絕對值計算兩點間距離
- 有什麼關鍵限制條件?
比較兩個距離的大小關係
- 預期時間/空間複雜度?
時間 O(1),空間 O(1) - 只需要常數時間的計算
### 解法概述
**解法**:
- 思路:
分別計算 Person 1 和 Person 2 到 Person 3 的距離,直接比較大小
- 時間複雜度O(1)
- 空間複雜度O(1)
## 測試案例
### 範例輸入輸出
```
Input: x = 2, y = 7, z = 4
Output: 1
Explanation:
- Person 1 is at position 2 and can reach Person 3 (at position 4) in 2 steps.
- Person 2 is at position 7 and can reach Person 3 in 3 steps.
Since Person 1 reaches Person 3 first, the output is 1.
```
### 邊界情況
`1 <= x, y, z <= 100`
## 學習筆記
### 今天學到什麼?
- 稍微練習了一下go func
### 遇到的困難
-
### 改善方向
-
### 相關題目
---
**總結**: 今天這題考弱智?

View File

@@ -0,0 +1,60 @@
// LeetCode 3516: Find Closest Person
// 難度: Easy
// 日期: 2025-09-04
using System;
using System.Collections.Generic;
using System.Linq;
public class Solution {
public int FindClosest(int x, int y, int z)
{
var distanceX = Math.Abs(x - z);
var distanceY = Math.Abs(y - z);
return distanceX == distanceY ? 0 : distanceX > distanceY ? 2 : 1;
}
}
// 測試程式
public class Program
{
public static void Main()
{
TestCase1();
TestCase2();
TestCase3();
}
// 基本測試案例 - Example 1
static void TestCase1()
{
var solution = new Solution();
// Input: x = 2, y = 7, z = 4
// Expected: 1 (Person 1 距離較近: |2-4| = 2 < |7-4| = 3)
var actual = solution.FindClosest(2, 7, 4);
var expected = 1;
Console.WriteLine($"Test 1: Input(2, 7, 4) Expected: {expected}, Actual: {actual}, Result: {(actual == expected ? "PASS" : "FAIL")}");
}
// 基本測試案例 - Example 2
static void TestCase2()
{
var solution = new Solution();
// Input: x = 2, y = 5, z = 6
// Expected: 2 (Person 2 距離較近: |5-6| = 1 < |2-6| = 4)
var actual = solution.FindClosest(2, 5, 6);
var expected = 2;
Console.WriteLine($"Test 2: Input(2, 5, 6) Expected: {expected}, Actual: {actual}, Result: {(actual == expected ? "PASS" : "FAIL")}");
}
// 基本測試案例 - Example 3
static void TestCase3() {
var solution = new Solution();
// Input: x = 1, y = 5, z = 3
// Expected: 0 (距離相等: |1-3| = 2 = |5-3| = 2)
var actual = solution.FindClosest(1, 5, 3);
var expected = 0;
Console.WriteLine($"Test 3: Input(1, 5, 3) Expected: {expected}, Actual: {actual}, Result: {(actual == expected ? "PASS" : "FAIL")}");
}
}

View File

@@ -0,0 +1,3 @@
module leetcode-3516
go 1.18

View File

@@ -0,0 +1,71 @@
// LeetCode 3516: Find Closest Person
// 難度: Easy
// 日期: 2025-09-04
package main
import "fmt"
// TODO: 實作解法
func findClosest(x, y, z int) int {
distanceX := abs(x - z)
distanceY := abs(y - z)
if distanceX == distanceY{
return 0
}else if distanceX > distanceY{
return 2
}else{
return 1
}
}
func abs(n int) int{
if n < 0 {
return -n
}
return n
}
func main() {
testCase1()
testCase2()
testCase3()
}
// 基本測試案例 - Example 1
func testCase1() {
// Input: x = 2, y = 7, z = 4
// Expected: 1 (Person 1 距離較近: |2-4| = 2 < |7-4| = 3)
actual := findClosest(2, 7, 4)
expected := 1
fmt.Printf("Test 1: Input(2, 7, 4) Expected: %d, Actual: %d, Result: %s\n",
expected, actual, getResult(actual == expected))
}
// 基本測試案例 - Example 2
func testCase2() {
// Input: x = 2, y = 5, z = 6
// Expected: 2 (Person 2 距離較近: |5-6| = 1 < |2-6| = 4)
actual := findClosest(2, 5, 6)
expected := 2
fmt.Printf("Test 2: Input(2, 5, 6) Expected: %d, Actual: %d, Result: %s\n",
expected, actual, getResult(actual == expected))
}
// 基本測試案例 - Example 3
func testCase3() {
// Input: x = 1, y = 5, z = 3
// Expected: 0 (距離相等: |1-3| = 2 = |5-3| = 2)
actual := findClosest(1, 5, 3)
expected := 0
fmt.Printf("Test 3: Input(1, 5, 3) Expected: %d, Actual: %d, Result: %s\n",
expected, actual, getResult(actual == expected))
}
func getResult(pass bool) string {
if pass {
return "PASS"
}
return "FAIL"
}

View File

@@ -0,0 +1,99 @@
# YYYY年M月 學習記錄
## 本月設定(目標與主題)
- 主題:雙指針 / 滑動視窗 / DP / 圖論(自訂)
- 目標題數X 題Easy Y / Medium Z / Hard W
- 投入時間:每日 ≥ N 分鐘;每週 ≥ M 小時
- 挑戰:至少完成 Hard ≥ H 題;每週寫 1 篇總結
## 📅 每日練習記錄
### Week 1 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
### Week 2 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
### Week 3 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
### Week 4 (YYYY-MM-DD ~ YYYY-MM-DD)
| 日期 | 題目 | 難度 | 語言 | 耗時 | 狀態 | 心得 |
|------|------|------|------|------|------|------|
| | | | | | | |
## 🧭 主題覆蓋追蹤(勾選)
- [ ] 陣列/字串Two Pointers / Sliding Window
- [ ] 資料結構Stack/Queue/Heap/Set/Map
- [ ] 排序與搜尋Sorting / Binary Search
- [ ] 數學與位運算Math / Bit
- [ ] 動態規劃DP
- [ ] 圖論BFS/DFS/最短路/拓撲)
- [ ] 樹BST/遍歷/序列化)
## 📈 本月統計
### 完成情況
- 練習天數:天
- 完成題數Easy / Medium / Hard
- 語言分布C# (題), Go (題)
- 連續天數Streak本月斷點第 天
### 時間投入
- 總時間:小時
- 平均每題:分鐘
- 每日平均:分鐘
### 正確率 / 嘗試次數
- 一次通過:題
- 二次通過:題
- 多次調整:題(主因:邊界/複雜度/實作)
## 🎯 本月重點學習
### 新掌握的技巧(至少 3 條)
1.
2.
3.
### 常見錯誤與對策
1. 錯誤:;對策:
2. 錯誤:;對策:
3. 錯誤:;對策:
### 語言心得(實作層面)
- C#LINQ/Span/效能注意點/測試習慣
- Goslice/map/指標/錯誤處理/benchmark 習慣
## 🔄 困難案例復盤
### 案例1題號/主題
- 問題:
- 嘗試:
- 解決:
- 學習:
### 案例2題號/主題
- 問題:
- 嘗試:
- 解決:
- 學習:
## 📝 下月計畫
- 目標題數:
- 重點主題:
- 練習節奏:
- 要避免的坑:
## 💡 本月金句
>
---
**總結**:本月最大收穫是 ______接下來專注 ______。

View File

@@ -1,73 +0,0 @@
# [題目編號] 題目名稱
## 題目資訊
- **難度**: Easy/Medium/Hard
- **標籤**: Array, Hash Table, Two Pointers, etc.
- **題目連結**: [LeetCode](https://leetcode.com/problems/xxx/)
- **練習日期**: YYYY-MM-DD
## 題目描述
> 在這裡貼上題目的完整描述
## 解題思路
### 初步分析
- 這題主要考察什麼概念?
- 有什麼關鍵限制條件?
- 預期時間/空間複雜度?
### 解法概述
1. **暴力解法**:
- 思路:
- 時間複雜度O(?)
- 空間複雜度O(?)
2. **優化解法**:
- 思路:
- 時間複雜度O(?)
- 空間複雜度O(?)
## 實作細節
### C# 解法
```csharp
// 核心程式碼片段或關鍵邏輯說明
```
### Go 解法
```go
// 核心程式碼片段或關鍵邏輯說明
```
## 測試案例
### 範例輸入輸出
```
Input:
Output:
Explanation:
```
### 邊界情況
- [ ] 空陣列/空字串
- [ ] 單一元素
- [ ] 最大/最小值
- [ ] 重複元素
## 學習筆記
### 今天學到什麼?
-
### 遇到的困難
-
### 改善方向
-
### 相關題目
- [題目編號] 題目名稱 - 相似概念
- [題目編號] 題目名稱 - 進階版本
---
**總結**: 這題的核心概念是...,適合練習...技巧。

View File

@@ -0,0 +1,105 @@
# [題目編號] 題目名稱
## 題目資訊
- **難度**: Easy/Medium/Hard
- **標籤**: Array, Hash Table, Two Pointers, Sliding Window, Greedy, DP, Graph, Tree, Math, etc.
- **題目連結**: [LeetCode](https://leetcode.com/problems/xxx/)
- **練習日期**: YYYY-MM-DD
- **目標複雜度**: 時間 O(?), 空間 O(?)
## 題目描述
> 在這裡貼上題目的完整描述(或摘要)
## 先備條件與限制
- 輸入限制n ∈ [?, ?]、值域 ∈ [?, ?]、是否有重複、是否有負數/零
- 回傳/輸出格式:...
- 其他排序是否允許改變輸入、是否需穩定、是否需就地in-place
## 解題思路
### 初步分析(快速定位問題類型)
- 問題類型:如 雙指針 / 滑動視窗 / 排序 + 掃描 / 貪心 / DP / 單調結構 / 前綴和 / 二分 / 位運算 ...
- 關鍵觀察:列出 2-4 點(不等式關係、單調性、區間性質、可分解性)
- 目標複雜度理由:為什麼 O(n) 或 O(n log n) 足夠/必要?
### 解法比較
1. **解法 A基準/暴力/直接枚舉)**
- 思路:步驟 1-2-3
- 正確性:為什麼不會漏/不會重?
- 複雜度:時間 O(?)、空間 O(?)
- 優缺點:易寫/慢;好理解/不通過大資料
2. **解法 B優化排序/雙指針/結構)**
- 思路:步驟 1-2-3指出與解法 A 最大差異)
- 正確性:單調性/貪心選擇/狀態定義 的論證要點
- 複雜度:時間 O(?)、空間 O(?)
- 優缺點:通過大資料/實作較複雜;可讀性需注意
3. (可選)**解法 C進一步優化/其他路線)**
- 思路、正確性、複雜度、優缺點
### 乾跑Dry Run
使用一組小範例逐步展示索引/指標/狀態如何變化(建議附上 3-5 步驟)。
## 實作細節與 API 設計
### C# 方法簽名
```csharp
public class Solution {
// TODO: 根據題意調整簽名
public int Solve(int[] nums) {
// ...
}
}
```
### Go 方法簽名
```go
// TODO: 根據題意調整簽名
func solve(nums []int) int {
// ...
}
```
### 實作要點 / 常見陷阱
- 邊界空集合、單元素、全相等、極值INT_MIN/INT_MAX
- 去重:排序後跳重複、集合/哈希去重
- 早停:提早終止條件(例如 window 擴不動就停)
- 精度/溢位除法、乘法、64 位整數
## 測試案例
### 範例輸入輸出
```
Input: ...
Output: ...
Explanation: ...
```
### 邊界與特殊情況清單
- [ ] 空陣列/空字串
- [ ] 單一元素 / 全相同 / 全遞增 / 全遞減
- [ ] 含負數 / 含 0 / 大數
- [ ] 有重複值 / 需去重
- [ ] 大資料壓力測試n 接近上限)
### 對拍/隨機測試(可選)
- 與暴力解法對拍 1000 次;隨機生成測資,確保輸出一致
## 複雜度分析
- 最壞:時間 O(?)、空間 O(?)
- 平均:時間 O(?)
- 最佳:時間 O(?)(若有)
## 相關題目與 Follow-up
- [題目編號] 題目名稱(相同套路)
- Follow-up若輸入動態變化/資料流版本/線上查詢如何處理?
## 學習筆記
- 今天學到:
- 卡住點與修正:
- 下次優化想法:
---
**總結**:這題的核心在於 ______適合練習 ______ 技巧。

View File

@@ -0,0 +1,91 @@
# [{{NUMBER}}] {{NAME_TITLE}}
## 題目資訊
- **難度**: {{DIFFICULTY}}
- **標籤**:
- **題目連結**: https://leetcode.com/problems/{{NAME_SLUG}}/
- **練習日期**: {{DATE}}
- **目標複雜度**: 時間 O(?)、空間 O(?)
## 題目描述
> 在這裡貼上題目的完整描述(或重點)
## 先備條件與限制
- 輸入限制n ∈ [?, ?]、值域 ∈ [?, ?]
- 回傳/輸出格式:...
- 其他:是否允許排序/就地修改
## 解題思路
### 初步分析
- 類型:雙指針 / 滑動視窗 / 排序 / DP / 貪心 / 圖論 ...
- 關鍵觀察:
- 複雜度目標理由:
### 解法比較
1. 解法A基準/暴力):
- 思路:
- 正確性:
- 複雜度O(?) / O(?)
2. 解法B優化
- 思路:
- 正確性:
- 複雜度O(?) / O(?)
### 乾跑Dry Run
- 範例:...
## 實作細節與 API 設計
### C# 方法簽名(示意)
```csharp
public class Solution {
// TODO: 根據題意調整簽名
public int Solve(int[] nums) {
return 0;
}
}
```
### Go 方法簽名(示意)
```go
func solve(nums []int) int {
return 0
}
```
### 常見陷阱
- 邊界:空/單一/極值/全相等
- 去重:排序後跳重複、集合
- 溢位:使用 64-bit
## 測試案例
### 範例輸入輸出
```
Input: ...
Output: ...
Explanation: ...
```
### 邊界清單
- [ ] 空陣列/空字串
- [ ] 單一元素 / 全相同
- [ ] 含負數/0/大數
- [ ] 去重
- [ ] 大資料壓力
## 複雜度分析
- 最壞:時間 O(?)、空間 O(?)
## 相關題目 / Follow-up
-
## 學習筆記
- 今天學到:
- 卡住與修正:
- 待優化:
---
**總結**:這題的核心在於 ______適合練習 ______。

View File

@@ -0,0 +1,24 @@
// LeetCode {{NUMBER}}: {{NAME_TITLE}}
// 難度: {{DIFFICULTY}}
// 日期: {{DATE}}
using System;
using System.Collections.Generic;
using System.Linq;
public class Solution {
// TODO: 根據題意調整簽名
public int Solve(int[] nums) {
// 實作解法
return 0;
}
}
public class Program {
public static void Main() {
var s = new Solution();
// TODO: 可加入簡單輸入/輸出測試
Console.WriteLine("Hello LeetCode {{NUMBER}}!");
}
}

View File

@@ -1,10 +1,9 @@
<Project Sdk="Microsoft.NET.Sdk">
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<OutputType>Exe</OutputType>
<TargetFramework>net8.0</TargetFramework>
<ImplicitUsings>enable</ImplicitUsings>
<Nullable>enable</Nullable>
</PropertyGroup>
</Project>

View File

@@ -0,0 +1,18 @@
// LeetCode {{NUMBER}}: {{NAME_TITLE}}
// 難度: {{DIFFICULTY}}
// 日期: {{DATE}}
package main
import "fmt"
// TODO: 根據題意調整簽名
func solve(nums []int) int {
return 0
}
func main() {
fmt.Printf("Hello LeetCode {{NUMBER}}!\n")
// TODO: 可加入簡單測試
}

View File

@@ -0,0 +1,24 @@
// LeetCode {{NUMBER}} 單元測試xUnit
using Xunit;
public class SolutionTests {
private readonly Solution _s = new Solution();
[Fact]
public void Example1() {
// TODO: Arrange
// var input = new int[] { };
// var expected = 0;
// Act
// var got = _s.Solve(input);
// Assert.Equal(expected, got);
Assert.True(true);
}
[Fact]
public void EdgeCases() {
Assert.True(true);
}
}

View File

@@ -0,0 +1,19 @@
<Project Sdk="Microsoft.NET.Sdk">
<PropertyGroup>
<TargetFramework>net8.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/csharp.csproj" />
</ItemGroup>
</Project>

View File

@@ -0,0 +1,20 @@
# 邊界情況清單({{NUMBER}} {{NAME_TITLE}}
## 需要測試的邊界
- [ ] 空輸入 / 單一元素
- [ ] 重複元素 / 全相同
- [ ] 極值(最小/最大)
- [ ] 含負數 / 0 / 大數
- [ ] 大資料量(接近上限)
## 額外案例
### 案例 1
- 輸入:
- 預期:
- 說明:
### 案例 2
- 輸入:
- 預期:
- 說明:

View File

@@ -0,0 +1,12 @@
// LeetCode {{NUMBER}} 單元測試Go testing
package main
import "testing"
func TestExample(t *testing.T) {
// TODO: input := []int{}
// got := solve(input)
// want := 0
// if got != want { t.Fatalf("want %v got %v", want, got) }
}

188
utils/leetcode_helper.sh Executable file
View File

@@ -0,0 +1,188 @@
# 1. 讓腳本可執行:
# chmod +x utils/leetcode_helper.sh
# 2. 建立新題目:
# ./utils/leetcode_helper.sh problem 1 two-sum Easy
# ./utils/leetcode_helper.sh problem 3000 maximum-area-rectangle Medium
# 3. 建立月度日誌:
# ./utils/leetcode_helper.sh log 2025-09
# 4. 更新README
# ./utils/leetcode_helper.sh readme
#!/bin/bash
set -euo pipefail
# 路徑設定
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
ROOT_DIR=$(cd "$SCRIPT_DIR/.." && pwd)
TEMPLATES_DIR="$ROOT_DIR/templates"
# kebab-case -> Title Casetwo-sum -> Two Sum
to_title_case() {
local s="${1//-/ }"
echo "$s" | awk '{for(i=1;i<=NF;i++){ $i=toupper(substr($i,1,1)) substr($i,2) } print }'
}
# 渲染模板到目的檔
# 變數:{{NUMBER}}, {{NUMBER_PAD}}, {{NAME_SLUG}}, {{NAME_TITLE}}, {{DIFFICULTY}}, {{DATE}}, {{YEAR_MONTH}}
render_template() {
local src="$1"; shift
local dest="$1"; shift
local number="${1:-}"; shift || true
local number_pad="${1:-}"; shift || true
local name_slug="${1:-}"; shift || true
local name_title="${1:-}"; shift || true
local difficulty="${1:-}"; shift || true
local today="${1:-}"; shift || true
local year_month="${1:-}"; shift || true
mkdir -p "$(dirname "$dest")"
sed -e "s/{{NUMBER}}/${number}/g" \
-e "s/{{NUMBER_PAD}}/${number_pad}/g" \
-e "s/{{NAME_SLUG}}/${name_slug}/g" \
-e "s/{{NAME_TITLE}}/${name_title}/g" \
-e "s/{{DIFFICULTY}}/${difficulty}/g" \
-e "s/{{DATE}}/${today}/g" \
-e "s/{{YEAR_MONTH}}/${year_month}/g" \
"$src" > "$dest"
}
# 顯示說明
show_help() {
cat << EOF
LeetCode Practice Helper
用法:
$0 problem <題號> <題目名稱-kebab> <難度>
$0 log [YYYY-MM]
$0 readme
$0 -h | --help
說明:
problem 建立新題目(會建立 C#/Go 骨架、測試模板與 README
log 建立月度學習日誌(預設為本月,或指定 YYYY-MM
readme 顯示題目數量統計(可擴充為寫回 README
範例:
$0 problem 1 two-sum Easy
$0 problem 3025 find-the-number-of-ways-to-place-people-i Medium
$0 log 2025-09
$0 readme
測試:
建議使用 utils/run_tests.sh 執行,例:
utils/run_tests.sh 3025 [all|csharp|go]
EOF
}
# 建立測試檔案(來自 templates/problem/test/*
create_test_files() {
local problem_dir="$1"; local number="$2"; local name_slug="$3"; local difficulty="$4"
local number_pad=$(printf "%04d" "$number")
local name_title=$(to_title_case "$name_slug")
local today=$(date +%Y-%m-%d)
local year_month=$(date +%Y-%m)
render_template "$TEMPLATES_DIR/problem/test/SolutionTests.cs.tmpl" \
"$problem_dir/test/SolutionTests.cs" \
"$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month"
render_template "$TEMPLATES_DIR/problem/test/TestProject.csproj.tmpl" \
"$problem_dir/test/TestProject.csproj" \
"$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month"
render_template "$TEMPLATES_DIR/problem/test/main_test.go.tmpl" \
"$problem_dir/test/main_test.go" \
"$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month"
render_template "$TEMPLATES_DIR/problem/test/edge_cases.md.tmpl" \
"$problem_dir/test/edge_cases.md" \
"$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month"
# 不再產生每題的 run_tests.sh請改用 utils/run_tests.sh
}
# 建立新題目
create_problem() {
local number="$1"; local name_slug="$2"; local difficulty="$3"
if [[ -z "${number:-}" || -z "${name_slug:-}" || -z "${difficulty:-}" ]]; then
echo "使用方法: $0 problem <題號> <題目名稱-kebab> <難度>"; exit 1
fi
local number_pad=$(printf "%04d" "$number")
local folder_name="${number_pad}-${name_slug}"
local problem_dir="$ROOT_DIR/problems/${folder_name}"
local name_title=$(to_title_case "$name_slug")
local today=$(date +%Y-%m-%d)
local year_month=$(date +%Y-%m)
mkdir -p "$problem_dir/csharp" "$problem_dir/go" "$problem_dir/test"
# README
render_template "$TEMPLATES_DIR/problem/README.md.tmpl" \
"$problem_dir/README.md" \
"$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month"
# C#
render_template "$TEMPLATES_DIR/problem/csharp/Program.cs.tmpl" \
"$problem_dir/csharp/Program.cs" \
"$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month"
render_template "$TEMPLATES_DIR/problem/csharp/csharp.csproj.tmpl" \
"$problem_dir/csharp/csharp.csproj" \
"$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month"
# Go
render_template "$TEMPLATES_DIR/problem/go/main.go.tmpl" \
"$problem_dir/go/main.go" \
"$number" "$number_pad" "$name_slug" "$name_title" "$difficulty" "$today" "$year_month"
(cd "$problem_dir/go" && go mod init "leetcode-$number" >/dev/null 2>&1 || true)
# Tests
create_test_files "$problem_dir" "$number" "$name_slug" "$difficulty"
echo "✅ 已建立題目: $problem_dir"
echo "C#: cd problems/${folder_name}/csharp && dotnet run"
echo "Go: cd problems/${folder_name}/go && go run main.go"
echo "測試: utils/run_tests.sh ${number_pad}-${name_slug} [all|csharp|go]"
}
# 更新主 README目前僅統計列印
update_readme() {
echo "🔄 更新主 README 統計..."
local total_problems=$(find "$ROOT_DIR/problems" -maxdepth 1 -type d | wc -l)
total_problems=$((total_problems - 1))
local completed_problems=$(find "$ROOT_DIR/problems" -name "README.md" -exec grep -l "✅" {} \; | wc -l)
echo "📊 題目總數: $total_problems,標記完成: $completed_problems"
}
# 建立月度日誌(由模板 logs-template.md.tmpl 渲染)
create_monthly_log() {
local year_month="${1:-}"
if [[ -z "$year_month" ]]; then year_month=$(date +%Y-%m); fi
local dest="$ROOT_DIR/logs/${year_month}.md"
if [[ -f "$dest" ]]; then echo "⚠️ 已存在: $dest"; return 1; fi
mkdir -p "$ROOT_DIR/logs"
render_template "$TEMPLATES_DIR/logs-template.md.tmpl" "$dest" "" "" "" "" "" "" "$year_month"
echo "✅ 已建立月度日誌: $dest"
}
# 入口
# --help
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
show_help
exit 0
fi
case "${1:-}" in
problem)
create_problem "${2:-}" "${3:-}" "${4:-}" ;;
readme)
update_readme ;;
log)
create_monthly_log "${2:-}" ;;
*)
show_help
;;
esac

125
utils/run_tests.sh Executable file
View File

@@ -0,0 +1,125 @@
#!/bin/bash
set -euo pipefail
# Usage:
# utils/run_tests.sh <problem> [all|csharp|go]
# Examples:
# utils/run_tests.sh 3025
# utils/run_tests.sh 3025 csharp
# utils/run_tests.sh problems/3025-find-the-number-of-ways-to-place-people-i go
# utils/run_tests.sh 3516-find-closest-person all
# Help:
# utils/run_tests.sh -h | --help
# List:
# utils/run_tests.sh --list
SCRIPT_DIR=$(cd "$(dirname "${BASH_SOURCE[0]}")" && pwd)
ROOT_DIR=$(cd "$SCRIPT_DIR/.." && pwd)
show_help() {
cat << EOF
Run tests for a problem folder.
Usage:
$0 <problem> [all|csharp|go]
$0 --list
Where <problem> can be:
- A number (e.g., 3025)
- A 4-digit + slug folder name (e.g., 3025-find-the-number-of-ways-to-place-people-i)
- A relative path under problems/ (e.g., problems/3025-find-the-number-of-ways-to-place-people-i)
Examples:
$0 3025 # run both C# and Go tests
$0 3025 csharp # only C#
$0 3516 go # only Go
$0 3516-find-closest-person all
$0 problems/3516-find-closest-person all
$0 --list # list available problems
EOF
}
if [[ "${1:-}" == "-h" || "${1:-}" == "--help" ]]; then
show_help
exit 0
fi
if [[ "${1:-}" == "--list" ]]; then
echo "Available problems (from problems/):"
# List directories matching 4-digit prefix
find "$ROOT_DIR/problems" -maxdepth 1 -mindepth 1 -type d -printf "%f\n" \
| sort \
| awk 'BEGIN{printf("%-8s %s\n","Number","Slug"); printf("%-8s %s\n","------","----");}
{num=substr($0,1,4); slug=substr($0,6); printf("%-8s %s\n", num, $0)}'
exit 0
fi
problem_arg="${1:-}"
lang="${2:-all}"
if [[ -z "$problem_arg" ]]; then
show_help >&2
exit 1
fi
resolve_problem_dir() {
local arg="$1"
if [[ -d "$ROOT_DIR/$arg" ]]; then
echo "$ROOT_DIR/$arg"
return 0
fi
if [[ "$arg" =~ ^[0-9]+$ ]]; then
local num=$(printf "%04d" "$arg")
local match
match=$(find "$ROOT_DIR/problems" -maxdepth 1 -type d -name "${num}-*" | head -n 1 || true)
if [[ -n "$match" ]]; then
echo "$match"; return 0
fi
fi
# try exact name under problems
if [[ -d "$ROOT_DIR/problems/$arg" ]]; then
echo "$ROOT_DIR/problems/$arg"; return 0
fi
echo "Cannot resolve problem directory from '$arg'" >&2
exit 1
}
PROB_DIR=$(resolve_problem_dir "$problem_arg")
TEST_DIR="$PROB_DIR/test"
CS_DIR="$PROB_DIR/csharp"
GO_DIR="$PROB_DIR/go"
run_csharp() {
if [[ ! -d "$CS_DIR" || ! -d "$TEST_DIR" ]]; then
echo "[C#] Skipped (missing csharp or test folder)"; return 0
fi
echo "📋 C# 測試結果:"
if (cd "$CS_DIR" && dotnet build >/dev/null 2>&1); then
(cd "$TEST_DIR" && dotnet test --logger "console;verbosity=minimal") || { echo "❌ C# 測試失敗"; return 1; }
echo "✅ C# 測試通過"
else
echo "❌ C# 編譯失敗"; return 1
fi
}
run_go() {
if [[ ! -d "$GO_DIR" || ! -d "$TEST_DIR" ]]; then
echo "[Go] Skipped (missing go or test folder)"; return 0
fi
echo "📋 Go 測試結果:"
if (cd "$GO_DIR" && go build >/dev/null 2>&1); then
(cd "$TEST_DIR" && go test -v) || { echo "❌ Go 測試失敗"; return 1; }
echo "✅ Go 測試通過"
else
echo "❌ Go 編譯失敗"; return 1
fi
}
case "$lang" in
all) run_csharp; run_go ;;
csharp) run_csharp ;;
go) run_go ;;
*) echo "Unknown lang '$lang' (use all|csharp|go)" >&2; exit 1 ;;
esac
echo "📊 測試完成: $PROB_DIR"