From 325a5491130ed296b5a3eaa29315ed90d788cca3 Mon Sep 17 00:00:00 2001 From: Simon McKenna Date: Sun, 18 Oct 2026 12:24:56 +1030 Subject: [PATCH 1/5] Normalise line endings to LF and drop UTF-8 BOMs Adds .gitattributes so checkouts stay LF. No content changes. --- .dockerignore | 2 +- .editorconfig | 86 +- .gitattributes | 1 + .github/dependabot.yml | 42 +- .github/workflows/workflow.yml | 160 +- .gitignore | 2 +- Directory.Build.props | 36 +- LeetCode.CSharp/Benchmark.cs | 126 +- LeetCode.CSharp/BenchmarkConfig.cs | 28 +- .../Benchmarks/AddTwoNumbersBenchmark.cs | 52 +- .../Benchmarks/BinarySearchBenchmark.cs | 24 +- .../Benchmarks/CanAttendMeetingsBenchmark.cs | 58 +- .../Benchmarks/ClimbStairsBenchmark.cs | 14 +- .../Benchmarks/ContainsDuplicateBenchmark.cs | 24 +- .../Benchmarks/CountBitsBenchmark.cs | 12 +- .../DiameterOfBinaryTreeBenchmark.cs | 42 +- .../Benchmarks/EncodeDecodeBenchmark.cs | 92 +- .../FindMedianSortedArraysBenchmark.cs | 14 +- .../Benchmarks/FizzBuzzBenchmark.cs | 14 +- .../Benchmarks/GroupAnagramsBenchmark.cs | 40 +- .../Benchmarks/HammingWeightBenchmark.cs | 14 +- LeetCode.CSharp/Benchmarks/InsertBenchmark.cs | 72 +- .../Benchmarks/InvertTreeBenchmark.cs | 42 +- .../Benchmarks/IsAnagramBenchmark.cs | 40 +- .../Benchmarks/IsBalancedBenchmark.cs | 42 +- .../Benchmarks/IsHappyBenchmark.cs | 14 +- .../Benchmarks/IsPalindromeBenchmark.cs | 44 +- .../Benchmarks/IsSameTreeBenchmark.cs | 46 +- .../Benchmarks/IsSubtreeBenchmark.cs | 46 +- .../Benchmarks/IsValidSudokuBenchmark.cs | 46 +- .../Benchmarks/KWeakestRowsBenchmark.cs | 48 +- .../Benchmarks/KthLargestBenchmark.cs | 44 +- .../Benchmarks/LRUCacheBenchmark.cs | 50 +- .../Benchmarks/LastStoneWeightBenchmark.cs | 24 +- .../LengthOfLongestSubstringBenchmark.cs | 24 +- .../LowestCommonAncestorBenchmark.cs | 56 +- .../Benchmarks/MaxDepthBenchmark.cs | 42 +- .../Benchmarks/MaxProfitBenchmark.cs | 24 +- .../Benchmarks/MaxSubarrayBenchmark.cs | 30 +- .../Benchmarks/MaximumWealthBenchmark.cs | 48 +- .../Benchmarks/MergeTwoListsBenchmark.cs | 54 +- .../Benchmarks/MiddleNodeBenchmark.cs | 26 +- .../MinCostClimbingStairsBenchmark.cs | 30 +- .../Benchmarks/MissingNumberBenchmark.cs | 26 +- .../Benchmarks/NumIslandsBenchmark.cs | 54 +- .../Benchmarks/NumberOfStepsBenchmark.cs | 12 +- .../Benchmarks/PlusOneBenchmark.cs | 30 +- .../Benchmarks/ProductExceptSelfBenchmark.cs | 24 +- .../Benchmarks/RansomNoteBenchmark.cs | 40 +- .../Benchmarks/ReverseBitsBenchmark.cs | 12 +- .../Benchmarks/ReverseListBenchmark.cs | 28 +- .../Benchmarks/RomanToIntBenchmark.cs | 14 +- .../Benchmarks/SingleNumberBenchmark.cs | 30 +- .../Benchmarks/SubsetsBenchmark.cs | 40 +- .../Benchmarks/TopKFrequentBenchmark.cs | 24 +- LeetCode.CSharp/Benchmarks/TrieBenchmark.cs | 54 +- LeetCode.CSharp/Benchmarks/TwoSumBenchmark.cs | 42 +- .../Benchmarks/UniquePathsBenchmark.cs | 12 +- .../Benchmarks/ValidParenthesesBenchmark.cs | 54 +- LeetCode.CSharp/Category.cs | 88 +- LeetCode.CSharp/Difficulty.cs | 26 +- LeetCode.CSharp/Interval.cs | 8 +- LeetCode.CSharp/LeetCode.CSharp.csproj | 58 +- LeetCode.CSharp/LeetCodeAttribute.cs | 58 +- LeetCode.CSharp/ListNode.cs | 84 +- LeetCode.CSharp/Problems/AddTwoNumbers.cs | 172 +- LeetCode.CSharp/Problems/BinarySearch.cs | 88 +- LeetCode.CSharp/Problems/CanAttendMeetings.cs | 92 +- LeetCode.CSharp/Problems/ClimbStairs.cs | 62 +- LeetCode.CSharp/Problems/ContainsDuplicate.cs | 46 +- LeetCode.CSharp/Problems/CountBits.cs | 66 +- .../Problems/DiameterOfBinaryTree.cs | 96 +- LeetCode.CSharp/Problems/EncodeDecode.cs | 124 +- .../Problems/FindMedianSortedArrays.cs | 44 +- LeetCode.CSharp/Problems/FizzBuzz.cs | 92 +- LeetCode.CSharp/Problems/GroupAnagrams.cs | 160 +- LeetCode.CSharp/Problems/HammingWeight.cs | 62 +- LeetCode.CSharp/Problems/Insert.cs | 172 +- LeetCode.CSharp/Problems/InvertTree.cs | 94 +- LeetCode.CSharp/Problems/IsAnagram.cs | 42 +- LeetCode.CSharp/Problems/IsBalanced.cs | 96 +- LeetCode.CSharp/Problems/IsHappy.cs | 96 +- LeetCode.CSharp/Problems/IsPalindrone.cs | 102 +- LeetCode.CSharp/Problems/IsSameTree.cs | 94 +- LeetCode.CSharp/Problems/IsSubtree.cs | 90 +- LeetCode.CSharp/Problems/IsValidSudoku.cs | 216 +-- LeetCode.CSharp/Problems/KWeakestRows.cs | 70 +- LeetCode.CSharp/Problems/KthLargest.cs | 116 +- LeetCode.CSharp/Problems/LRUCache.cs | 300 ++-- LeetCode.CSharp/Problems/LastStoneWeight.cs | 84 +- .../Problems/LengthOfLongestSubstring.cs | 76 +- .../Problems/LowestCommonAncestor.cs | 98 +- LeetCode.CSharp/Problems/MaxDepth.cs | 62 +- LeetCode.CSharp/Problems/MaxProfit.cs | 84 +- LeetCode.CSharp/Problems/MaxSubarrary.cs | 78 +- LeetCode.CSharp/Problems/MaximumWealth.cs | 56 +- LeetCode.CSharp/Problems/MergeTwoLists.cs | 106 +- LeetCode.CSharp/Problems/MiddleNode.cs | 64 +- .../Problems/MinCostClimbingStairs.cs | 60 +- LeetCode.CSharp/Problems/MissingNumber.cs | 50 +- LeetCode.CSharp/Problems/NumIslands.cs | 242 +-- LeetCode.CSharp/Problems/NumberOfSteps.cs | 72 +- LeetCode.CSharp/Problems/PlusOne.cs | 116 +- LeetCode.CSharp/Problems/ProductExceptSelf.cs | 94 +- LeetCode.CSharp/Problems/RansomNote.cs | 100 +- LeetCode.CSharp/Problems/ReverseBits.cs | 62 +- LeetCode.CSharp/Problems/ReverseList.cs | 76 +- LeetCode.CSharp/Problems/RomanToInt.cs | 102 +- LeetCode.CSharp/Problems/SingleNumber.cs | 46 +- LeetCode.CSharp/Problems/Subsets.cs | 132 +- LeetCode.CSharp/Problems/TopKFrequent.cs | 144 +- LeetCode.CSharp/Problems/Trie.cs | 166 +- LeetCode.CSharp/Problems/TwoSum.cs | 86 +- LeetCode.CSharp/Problems/UniquePaths.cs | 98 +- LeetCode.CSharp/Problems/ValidParentheses.cs | 106 +- LeetCode.CSharp/TreeNode.cs | 130 +- .../Benchmarks/ContainsDuplicateBenchmark.fs | 26 +- .../Benchmarks/FizzBuzzBenchmark.fs | 20 +- LeetCode.FSharp/LeetCode.FSharp.fsproj | 70 +- LeetCode.FSharp/ListNode.fs | 6 +- LeetCode.FSharp/Problems/AddTwoNumbers.fs | 86 +- LeetCode.FSharp/Problems/ContainsDuplicate.fs | 62 +- LeetCode.FSharp/Problems/FizzBuzz.fs | 104 +- LeetCode.FSharp/Program.fs | 4 +- LeetCode.sln.DotSettings | 2 +- LeetCode.slnx | 2 +- LeetCode/BenchmarkRunner.cs | 226 +-- LeetCode/Commands/AppCommand.cs | 38 +- LeetCode/Commands/BenchmarkCommand.cs | 72 +- LeetCode/Commands/BenchmarkSettings.cs | 242 +-- LeetCode/Commands/InfoCommand.cs | 64 +- LeetCode/Commands/ListCommand.cs | 130 +- LeetCode/Commands/ProblemSettings.cs | 46 +- LeetCode/Commands/WorkflowCommand.cs | 178 +-- LeetCode/ConsoleWriter.cs | 82 +- LeetCode/Dockerfile | 44 +- LeetCode/Extensions.cs | 134 +- LeetCode/LeetCode.csproj | 142 +- LeetCode/Menus/MainMenu.cs | 66 +- LeetCode/Menus/MenuBase.cs | 14 +- LeetCode/Menus/ProblemMenu.cs | 66 +- LeetCode/Menus/Selections/AboutSelection.cs | 36 +- .../Selections/BenchmarkListSelection.cs | 96 +- .../Menus/Selections/BenchmarkSelection.cs | 74 +- LeetCode/Menus/Selections/ExitSelection.cs | 28 +- .../Menus/Selections/ProblemListSelection.cs | 112 +- LeetCode/Menus/Selections/Selection.cs | 18 +- LeetCode/Problem.cs | 56 +- LeetCode/Program.cs | 56 +- LeetCode/Reflection.cs | 160 +- LeetCode/Resources.Designer.cs | 1394 ++++++++--------- LeetCode/Resources.resx | 630 ++++---- LeetCode/SpectreLogger.cs | 106 +- LeetCode/SpectreReportBuilder.cs | 240 +-- README.md | 168 +- Run.ps1 | 2 +- docker-compose.yml | 12 +- nuget.config | 12 +- version.json | 14 +- 159 files changed, 6458 insertions(+), 6457 deletions(-) create mode 100644 .gitattributes diff --git a/.dockerignore b/.dockerignore index c756957..cbbd0b5 100644 --- a/.dockerignore +++ b/.dockerignore @@ -1,2 +1,2 @@ -bin/ +bin/ obj/ \ No newline at end of file diff --git a/.editorconfig b/.editorconfig index b10fda9..798c817 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,43 +1,43 @@ -root = true - -[*] -indent_style = space -trim_trailing_whitespace = true - -[{*.yml,*.props, *.*proj}] -indent_size = 2 - -[*.cs] -indent_size = 4 - -# CA1822: Mark members as static -dotnet_diagnostic.ca1822.severity = silent - -csharp_style_expression_bodied_methods = true:suggestion -csharp_style_namespace_declarations = file_scoped - -# Microsoft .NET properties -csharp_new_line_before_members_in_object_initializers = false -csharp_preferred_modifier_order = public, private, protected, internal, new, sealed, abstract, virtual, static, readonly, override, extern, unsafe, volatile, async:suggestion -csharp_using_directive_placement = inside_namespace:silent -dotnet_sort_system_directives_first = false - -# ReSharper properties -resharper_blank_lines_after_block_statements = 0 -resharper_blank_lines_around_auto_property = 0 -resharper_blank_lines_around_local_method = 0 -resharper_braces_for_for = required -resharper_braces_for_foreach = required -resharper_braces_for_ifelse = required -resharper_csharp_blank_lines_around_field = 0 -resharper_csharp_blank_lines_around_invocable = 0 -resharper_csharp_indent_invocation_pars = none -resharper_csharp_insert_final_newline = true -resharper_csharp_max_line_length = 100 -resharper_csharp_wrap_arguments_style = chop_if_long -resharper_instance_members_qualify_declared_in = base_class -resharper_parentheses_redundancy_style = remove -resharper_place_expr_method_on_single_line = true -resharper_remove_blank_lines_near_braces_in_declarations = false -resharper_wrap_array_initializer_style = chop_if_long -resharper_wrap_object_and_collection_initializer_style = wrap_if_long +root = true + +[*] +indent_style = space +trim_trailing_whitespace = true + +[{*.yml,*.props, *.*proj}] +indent_size = 2 + +[*.cs] +indent_size = 4 + +# CA1822: Mark members as static +dotnet_diagnostic.ca1822.severity = silent + +csharp_style_expression_bodied_methods = true:suggestion +csharp_style_namespace_declarations = file_scoped + +# Microsoft .NET properties +csharp_new_line_before_members_in_object_initializers = false +csharp_preferred_modifier_order = public, private, protected, internal, new, sealed, abstract, virtual, static, readonly, override, extern, unsafe, volatile, async:suggestion +csharp_using_directive_placement = inside_namespace:silent +dotnet_sort_system_directives_first = false + +# ReSharper properties +resharper_blank_lines_after_block_statements = 0 +resharper_blank_lines_around_auto_property = 0 +resharper_blank_lines_around_local_method = 0 +resharper_braces_for_for = required +resharper_braces_for_foreach = required +resharper_braces_for_ifelse = required +resharper_csharp_blank_lines_around_field = 0 +resharper_csharp_blank_lines_around_invocable = 0 +resharper_csharp_indent_invocation_pars = none +resharper_csharp_insert_final_newline = true +resharper_csharp_max_line_length = 100 +resharper_csharp_wrap_arguments_style = chop_if_long +resharper_instance_members_qualify_declared_in = base_class +resharper_parentheses_redundancy_style = remove +resharper_place_expr_method_on_single_line = true +resharper_remove_blank_lines_near_braces_in_declarations = false +resharper_wrap_array_initializer_style = chop_if_long +resharper_wrap_object_and_collection_initializer_style = wrap_if_long diff --git a/.gitattributes b/.gitattributes new file mode 100644 index 0000000..6313b56 --- /dev/null +++ b/.gitattributes @@ -0,0 +1 @@ +* text=auto eol=lf diff --git a/.github/dependabot.yml b/.github/dependabot.yml index b0de7ea..b9574a6 100644 --- a/.github/dependabot.yml +++ b/.github/dependabot.yml @@ -1,21 +1,21 @@ -version: 2 -updates: - - package-ecosystem: "docker" - directory: "/LeetCode" - schedule: - interval: "weekly" - - package-ecosystem: "github-actions" - directory: "/" - schedule: - interval: "weekly" - - package-ecosystem: "nuget" - directory: "/" - schedule: - interval: "weekly" - groups: - xunit: - patterns: - - "xunit*" - spectre: - patterns: - - "Spectre*" +version: 2 +updates: + - package-ecosystem: "docker" + directory: "/LeetCode" + schedule: + interval: "weekly" + - package-ecosystem: "github-actions" + directory: "/" + schedule: + interval: "weekly" + - package-ecosystem: "nuget" + directory: "/" + schedule: + interval: "weekly" + groups: + xunit: + patterns: + - "xunit*" + spectre: + patterns: + - "Spectre*" diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index b6500d4..1521b57 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -1,80 +1,80 @@ -name: Build and Benchmark - -on: - push: - branches: [main] - pull_request: - branches: [main] - -env: - DOTNET_NOLOGO: true - DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true - DOTNET_CLI_TELEMETRY_OPTOUT: true - DOTNET_VERSION: 10.0.x - -jobs: - build: - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@main - with: - fetch-depth: 0 - - - name: Setup dotnet - uses: actions/setup-dotnet@v6 - with: - dotnet-version: ${{ env.DOTNET_VERSION }} - - - name: Run dotnet build - id: build - run: dotnet build --configuration Release - - - name: Run dotnet format - id: format - run: dotnet format --verbosity diagnostic --verify-no-changes --no-restore - - - name: Run dotnet test - id: test - run: dotnet test --configuration Release --no-restore - - benchmark: - needs: [ build ] - if: github.event_name == 'push' && github.ref == 'refs/heads/main' - runs-on: ubuntu-latest - steps: - - name: Checkout - uses: actions/checkout@main - with: - fetch-depth: 0 - - - name: Setup dotnet - uses: actions/setup-dotnet@v6 - with: - dotnet-version: ${{ env.DOTNET_VERSION }} - - - name: List problems - id: list-problems - run: | - dotnet run \ - --project ./LeetCode/LeetCode.csproj \ - list - - - name: Run benchmarks - id: run-benchmarks - run: | - dotnet run \ - --project ./LeetCode/LeetCode.csproj \ - --configuration Release \ - workflow - - - name: Store benchmark results - id: store-benchmarks - if: ${{ github.event_name == 'push' }} - uses: benchmark-action/github-action-benchmark@v1.22.1 - with: - name: Benchmarks - tool: benchmarkdotnet - output-file-path: BenchmarkDotNet.Artifacts/results/LeetCode.Benchmarks.json - github-token: ${{ secrets.GITHUB_TOKEN }} - auto-push: true +name: Build and Benchmark + +on: + push: + branches: [main] + pull_request: + branches: [main] + +env: + DOTNET_NOLOGO: true + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + DOTNET_VERSION: 10.0.x + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@main + with: + fetch-depth: 0 + + - name: Setup dotnet + uses: actions/setup-dotnet@v6 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: Run dotnet build + id: build + run: dotnet build --configuration Release + + - name: Run dotnet format + id: format + run: dotnet format --verbosity diagnostic --verify-no-changes --no-restore + + - name: Run dotnet test + id: test + run: dotnet test --configuration Release --no-restore + + benchmark: + needs: [ build ] + if: github.event_name == 'push' && github.ref == 'refs/heads/main' + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@main + with: + fetch-depth: 0 + + - name: Setup dotnet + uses: actions/setup-dotnet@v6 + with: + dotnet-version: ${{ env.DOTNET_VERSION }} + + - name: List problems + id: list-problems + run: | + dotnet run \ + --project ./LeetCode/LeetCode.csproj \ + list + + - name: Run benchmarks + id: run-benchmarks + run: | + dotnet run \ + --project ./LeetCode/LeetCode.csproj \ + --configuration Release \ + workflow + + - name: Store benchmark results + id: store-benchmarks + if: ${{ github.event_name == 'push' }} + uses: benchmark-action/github-action-benchmark@v1.22.1 + with: + name: Benchmarks + tool: benchmarkdotnet + output-file-path: BenchmarkDotNet.Artifacts/results/LeetCode.Benchmarks.json + github-token: ${{ secrets.GITHUB_TOKEN }} + auto-push: true diff --git a/.gitignore b/.gitignore index eadfb07..939daf1 100644 --- a/.gitignore +++ b/.gitignore @@ -1,4 +1,4 @@ -.idea +.idea .plan .vs *.DotSettings.user diff --git a/Directory.Build.props b/Directory.Build.props index 86c7227..0911ba9 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,18 +1,18 @@ - - - - - Simon McKenna - true - true - enable - latest - enable - net10.0 - true - - - - - - + + + + + Simon McKenna + true + true + enable + latest + enable + net10.0 + true + + + + + + diff --git a/LeetCode.CSharp/Benchmark.cs b/LeetCode.CSharp/Benchmark.cs index db28e96..31f89a2 100644 --- a/LeetCode.CSharp/Benchmark.cs +++ b/LeetCode.CSharp/Benchmark.cs @@ -1,63 +1,63 @@ -namespace LeetCode.CSharp; - -[Config(typeof(BenchmarkConfig))] -public abstract class Benchmark -{ - protected char[][] CharArrayMulti { get; set; } = [[char.MinValue]]; - - protected int Int1 { get; set; } - protected int Int2 { get; set; } - - protected int[] IntArray1 { get; set; } = []; - protected int[] IntArray2 { get; set; } = []; - protected int[][] IntArrayMulti1 { get; set; } = []; - protected int?[] IntArrayNullable { get; set; } = []; - - protected List Intervals1 { get; } = []; - - protected ListNode ListNode1 { get; set; } = new(); - protected ListNode ListNode2 { get; set; } = new(); - - protected string String1 { get; set; } = string.Empty; - protected string String2 { get; set; } = string.Empty; - protected string[] StringArray1 { get; set; } = []; - - protected TreeNode TreeNode1 { get; set; } = new(); - protected TreeNode TreeNode2 { get; set; } = new(); - - internal static readonly Random Random = new(42); - - /// - /// Build a pseudo random string - /// - /// - /// allows space character to be injected - /// 0 space uses a-z so 26 chars, so word is entire length of string for given size - /// 1 space gives ~1 in 27 chance of being space, so average word length of ~27 - /// 2 space gives ~2 in 28 chance of being space, so average word length of ~14 - /// etc. - /// - /// The size of the string to return - /// How frequently should space occur - /// Pseudo random string - internal static string BuildPseudoRandomString(int size, int frequencyOfSpace = 0) - { - var stringBuilder = new StringBuilder(size); - var range = 26 + frequencyOfSpace; - var previous = char.MinValue; - - for (var i = 0; i < size; i++) - { - // Avoid double spaces by checking the previously generated character - var next = previous == ' ' ? Random.Next(0, 26) : Random.Next(0, range); - - // Any character past z is considered a space - var value = next >= 26 ? ' ' : (char)('a' + next); - stringBuilder.Append(value); - - previous = value; - } - - return stringBuilder.ToString(); - } -} +namespace LeetCode.CSharp; + +[Config(typeof(BenchmarkConfig))] +public abstract class Benchmark +{ + protected char[][] CharArrayMulti { get; set; } = [[char.MinValue]]; + + protected int Int1 { get; set; } + protected int Int2 { get; set; } + + protected int[] IntArray1 { get; set; } = []; + protected int[] IntArray2 { get; set; } = []; + protected int[][] IntArrayMulti1 { get; set; } = []; + protected int?[] IntArrayNullable { get; set; } = []; + + protected List Intervals1 { get; } = []; + + protected ListNode ListNode1 { get; set; } = new(); + protected ListNode ListNode2 { get; set; } = new(); + + protected string String1 { get; set; } = string.Empty; + protected string String2 { get; set; } = string.Empty; + protected string[] StringArray1 { get; set; } = []; + + protected TreeNode TreeNode1 { get; set; } = new(); + protected TreeNode TreeNode2 { get; set; } = new(); + + internal static readonly Random Random = new(42); + + /// + /// Build a pseudo random string + /// + /// + /// allows space character to be injected + /// 0 space uses a-z so 26 chars, so word is entire length of string for given size + /// 1 space gives ~1 in 27 chance of being space, so average word length of ~27 + /// 2 space gives ~2 in 28 chance of being space, so average word length of ~14 + /// etc. + /// + /// The size of the string to return + /// How frequently should space occur + /// Pseudo random string + internal static string BuildPseudoRandomString(int size, int frequencyOfSpace = 0) + { + var stringBuilder = new StringBuilder(size); + var range = 26 + frequencyOfSpace; + var previous = char.MinValue; + + for (var i = 0; i < size; i++) + { + // Avoid double spaces by checking the previously generated character + var next = previous == ' ' ? Random.Next(0, 26) : Random.Next(0, range); + + // Any character past z is considered a space + var value = next >= 26 ? ' ' : (char)('a' + next); + stringBuilder.Append(value); + + previous = value; + } + + return stringBuilder.ToString(); + } +} diff --git a/LeetCode.CSharp/BenchmarkConfig.cs b/LeetCode.CSharp/BenchmarkConfig.cs index 749d455..11c902d 100644 --- a/LeetCode.CSharp/BenchmarkConfig.cs +++ b/LeetCode.CSharp/BenchmarkConfig.cs @@ -1,14 +1,14 @@ -namespace LeetCode.CSharp; - -public sealed class BenchmarkConfig : ManualConfig -{ - public BenchmarkConfig() - { - // FsUnit.xUnit has DEBUG reference - WithOption(ConfigOptions.DisableOptimizationsValidator, true); - - AddDiagnoser(MemoryDiagnoser.Default); - - AddColumn(StatisticColumn.OperationsPerSecond); - } -} +namespace LeetCode.CSharp; + +public sealed class BenchmarkConfig : ManualConfig +{ + public BenchmarkConfig() + { + // FsUnit.xUnit has DEBUG reference + WithOption(ConfigOptions.DisableOptimizationsValidator, true); + + AddDiagnoser(MemoryDiagnoser.Default); + + AddColumn(StatisticColumn.OperationsPerSecond); + } +} diff --git a/LeetCode.CSharp/Benchmarks/AddTwoNumbersBenchmark.cs b/LeetCode.CSharp/Benchmarks/AddTwoNumbersBenchmark.cs index afba9a5..9431a06 100644 --- a/LeetCode.CSharp/Benchmarks/AddTwoNumbersBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/AddTwoNumbersBenchmark.cs @@ -1,27 +1,27 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class AddTwoNumbersBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(AddTwoNumbers))] - public void AddTwoNumbersSetup() - { - IntArray1 = new int[50_000]; - IntArray2 = new int[10_000]; - Array.Fill(IntArray1, 9); - Array.Fill(IntArray2, 9); - ListNode1 = new ListNode(IntArray1); - ListNode2 = new ListNode(IntArray2); - } - - [Benchmark] - public ListNode AddTwoNumbers() => Problem.AddTwoNumbers(ListNode1, ListNode2); - - [GlobalCleanup(Target = nameof(AddTwoNumbers))] - public void AddTwoNumbersCleanup() - { - IntArray1 = []; - IntArray2 = []; - ListNode1 = new ListNode(IntArray1); - ListNode2 = new ListNode(IntArray2); - } +namespace LeetCode.CSharp.Benchmarks; + +public class AddTwoNumbersBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(AddTwoNumbers))] + public void AddTwoNumbersSetup() + { + IntArray1 = new int[50_000]; + IntArray2 = new int[10_000]; + Array.Fill(IntArray1, 9); + Array.Fill(IntArray2, 9); + ListNode1 = new ListNode(IntArray1); + ListNode2 = new ListNode(IntArray2); + } + + [Benchmark] + public ListNode AddTwoNumbers() => Problem.AddTwoNumbers(ListNode1, ListNode2); + + [GlobalCleanup(Target = nameof(AddTwoNumbers))] + public void AddTwoNumbersCleanup() + { + IntArray1 = []; + IntArray2 = []; + ListNode1 = new ListNode(IntArray1); + ListNode2 = new ListNode(IntArray2); + } } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/BinarySearchBenchmark.cs b/LeetCode.CSharp/Benchmarks/BinarySearchBenchmark.cs index 25e2363..28fd8c5 100644 --- a/LeetCode.CSharp/Benchmarks/BinarySearchBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/BinarySearchBenchmark.cs @@ -1,13 +1,13 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class BinarySearchBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(BinarySearch))] - public void BinarySearchSetup() => IntArray1 = [.. Enumerable.Range(0, 1_000_000)]; - - [Benchmark] - public int BinarySearch() => Problem.BinarySearch(IntArray1, 1_000); - - [GlobalCleanup(Target = nameof(BinarySearch))] - public void BinarySearchCleanup() => IntArray1 = []; +namespace LeetCode.CSharp.Benchmarks; + +public class BinarySearchBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(BinarySearch))] + public void BinarySearchSetup() => IntArray1 = [.. Enumerable.Range(0, 1_000_000)]; + + [Benchmark] + public int BinarySearch() => Problem.BinarySearch(IntArray1, 1_000); + + [GlobalCleanup(Target = nameof(BinarySearch))] + public void BinarySearchCleanup() => IntArray1 = []; } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/CanAttendMeetingsBenchmark.cs b/LeetCode.CSharp/Benchmarks/CanAttendMeetingsBenchmark.cs index 3bcccbc..1260f03 100644 --- a/LeetCode.CSharp/Benchmarks/CanAttendMeetingsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/CanAttendMeetingsBenchmark.cs @@ -1,30 +1,30 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class CanAttendMeetingsBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(CanAttendMeetings))] - public void CanAttendMeetingsSetup() - { - Int1 = 0; - Int2 = 100_000; - Intervals1.Clear(); - - for (var i = 0; i < Int2; i++) - { - Int1 = Random.Next(Int1, 10); - Int2 = Random.Next(Random.Next(Int1, 10), 20); - Intervals1.Add(new Interval(Int1, Int2)); - } - } - - [Benchmark] - public void CanAttendMeetings() => Problem.CanAttendMeetings(Intervals1); - - [GlobalCleanup(Target = nameof(CanAttendMeetings))] - public void CanAttendMeetingsCleanup() - { - Int1 = 0; - Int2 = 0; - Intervals1.Clear(); - } +namespace LeetCode.CSharp.Benchmarks; + +public class CanAttendMeetingsBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(CanAttendMeetings))] + public void CanAttendMeetingsSetup() + { + Int1 = 0; + Int2 = 100_000; + Intervals1.Clear(); + + for (var i = 0; i < Int2; i++) + { + Int1 = Random.Next(Int1, 10); + Int2 = Random.Next(Random.Next(Int1, 10), 20); + Intervals1.Add(new Interval(Int1, Int2)); + } + } + + [Benchmark] + public void CanAttendMeetings() => Problem.CanAttendMeetings(Intervals1); + + [GlobalCleanup(Target = nameof(CanAttendMeetings))] + public void CanAttendMeetingsCleanup() + { + Int1 = 0; + Int2 = 0; + Intervals1.Clear(); + } } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/ClimbStairsBenchmark.cs b/LeetCode.CSharp/Benchmarks/ClimbStairsBenchmark.cs index 2e85b00..1a7e19f 100644 --- a/LeetCode.CSharp/Benchmarks/ClimbStairsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/ClimbStairsBenchmark.cs @@ -1,7 +1,7 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class ClimbStairsBenchmark : Benchmark -{ - [Benchmark] - public int ClimbStairs() => Problem.ClimbStairs(1_000_000); -} +namespace LeetCode.CSharp.Benchmarks; + +public class ClimbStairsBenchmark : Benchmark +{ + [Benchmark] + public int ClimbStairs() => Problem.ClimbStairs(1_000_000); +} diff --git a/LeetCode.CSharp/Benchmarks/ContainsDuplicateBenchmark.cs b/LeetCode.CSharp/Benchmarks/ContainsDuplicateBenchmark.cs index 6945051..d8357a5 100644 --- a/LeetCode.CSharp/Benchmarks/ContainsDuplicateBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/ContainsDuplicateBenchmark.cs @@ -1,13 +1,13 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class ContainsDuplicateBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(ContainsDuplicate))] - public void ContainsDuplicateSetup() => IntArray1 = [.. Enumerable.Range(0, 100_000)]; - - [Benchmark] - public bool ContainsDuplicate() => Problem.ContainsDuplicate(IntArray1); - - [GlobalCleanup(Target = nameof(ContainsDuplicate))] - public void ContainsDuplicateCleanup() => IntArray1 = []; +namespace LeetCode.CSharp.Benchmarks; + +public class ContainsDuplicateBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(ContainsDuplicate))] + public void ContainsDuplicateSetup() => IntArray1 = [.. Enumerable.Range(0, 100_000)]; + + [Benchmark] + public bool ContainsDuplicate() => Problem.ContainsDuplicate(IntArray1); + + [GlobalCleanup(Target = nameof(ContainsDuplicate))] + public void ContainsDuplicateCleanup() => IntArray1 = []; } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/CountBitsBenchmark.cs b/LeetCode.CSharp/Benchmarks/CountBitsBenchmark.cs index 00489f7..a50f756 100644 --- a/LeetCode.CSharp/Benchmarks/CountBitsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/CountBitsBenchmark.cs @@ -1,7 +1,7 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class CountBitsBenchmark : Benchmark -{ - [Benchmark] - public int[] CountBits() => Problem.CountBits(10_000); +namespace LeetCode.CSharp.Benchmarks; + +public class CountBitsBenchmark : Benchmark +{ + [Benchmark] + public int[] CountBits() => Problem.CountBits(10_000); } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/DiameterOfBinaryTreeBenchmark.cs b/LeetCode.CSharp/Benchmarks/DiameterOfBinaryTreeBenchmark.cs index a67e6a6..f65a9ab 100644 --- a/LeetCode.CSharp/Benchmarks/DiameterOfBinaryTreeBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/DiameterOfBinaryTreeBenchmark.cs @@ -1,21 +1,21 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class DiameterOfBinaryTreeBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(DiameterOfBinaryTree))] - public void DiameterOfBinaryTreeSetup() - { - IntArrayNullable = [.. Enumerable.Range(1, 1_000_000).Cast()]; - TreeNode1 = TreeNode.Deserialize(IntArrayNullable)!; - } - - [Benchmark] - public int DiameterOfBinaryTree() => Problem.DiameterOfBinaryTree(TreeNode1); - - [GlobalCleanup(Target = nameof(DiameterOfBinaryTree))] - public void DiameterOfBinaryTreeCleanup() - { - IntArrayNullable = []; - TreeNode1 = new TreeNode(); - } -} +namespace LeetCode.CSharp.Benchmarks; + +public class DiameterOfBinaryTreeBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(DiameterOfBinaryTree))] + public void DiameterOfBinaryTreeSetup() + { + IntArrayNullable = [.. Enumerable.Range(1, 1_000_000).Cast()]; + TreeNode1 = TreeNode.Deserialize(IntArrayNullable)!; + } + + [Benchmark] + public int DiameterOfBinaryTree() => Problem.DiameterOfBinaryTree(TreeNode1); + + [GlobalCleanup(Target = nameof(DiameterOfBinaryTree))] + public void DiameterOfBinaryTreeCleanup() + { + IntArrayNullable = []; + TreeNode1 = new TreeNode(); + } +} diff --git a/LeetCode.CSharp/Benchmarks/EncodeDecodeBenchmark.cs b/LeetCode.CSharp/Benchmarks/EncodeDecodeBenchmark.cs index b8e4d48..6b21b24 100644 --- a/LeetCode.CSharp/Benchmarks/EncodeDecodeBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/EncodeDecodeBenchmark.cs @@ -1,47 +1,47 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class EncodeBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(Encode))] - public void EncodeSetup() - { - StringArray1 = new string[1_000]; - - for (var i = 0; i < StringArray1.Length; i++) - { - StringArray1[i] = BuildPseudoRandomString(Random.Next(1_000), 2); - } - } - - [Benchmark] - public string Encode() => Problem.Encode(StringArray1); - - [GlobalCleanup(Target = nameof(Encode))] - public void EncodeCleanup() => StringArray1 = []; -} - -public class DecodeBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(Decode))] - public void DecodeSetup() - { - StringArray1 = new string[1_000]; - - for (var i = 0; i < StringArray1.Length; i++) - { - StringArray1[i] = BuildPseudoRandomString(Random.Next(1_000), 2); - } - - String1 = Problem.Encode(StringArray1); - } - - [Benchmark] - public List Decode() => [.. Problem.Decode(String1)]; - - [GlobalCleanup(Target = nameof(Decode))] - public void DecodeCleanup() - { - String1 = string.Empty; - StringArray1 = []; - } +namespace LeetCode.CSharp.Benchmarks; + +public class EncodeBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(Encode))] + public void EncodeSetup() + { + StringArray1 = new string[1_000]; + + for (var i = 0; i < StringArray1.Length; i++) + { + StringArray1[i] = BuildPseudoRandomString(Random.Next(1_000), 2); + } + } + + [Benchmark] + public string Encode() => Problem.Encode(StringArray1); + + [GlobalCleanup(Target = nameof(Encode))] + public void EncodeCleanup() => StringArray1 = []; +} + +public class DecodeBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(Decode))] + public void DecodeSetup() + { + StringArray1 = new string[1_000]; + + for (var i = 0; i < StringArray1.Length; i++) + { + StringArray1[i] = BuildPseudoRandomString(Random.Next(1_000), 2); + } + + String1 = Problem.Encode(StringArray1); + } + + [Benchmark] + public List Decode() => [.. Problem.Decode(String1)]; + + [GlobalCleanup(Target = nameof(Decode))] + public void DecodeCleanup() + { + String1 = string.Empty; + StringArray1 = []; + } } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/FindMedianSortedArraysBenchmark.cs b/LeetCode.CSharp/Benchmarks/FindMedianSortedArraysBenchmark.cs index 4e92308..cc3b1f5 100644 --- a/LeetCode.CSharp/Benchmarks/FindMedianSortedArraysBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/FindMedianSortedArraysBenchmark.cs @@ -1,7 +1,7 @@ -// namespace LeetCode.CSharp.Benchmarks; -// -// public class FindMedianSortedArraysBenchmark : Benchmark -// { -// //[Benchmark] -// //public double FindMedianSortedArrays() => Problem.FindMedianSortedArrays(IntArray1, _intArray2); -// } +// namespace LeetCode.CSharp.Benchmarks; +// +// public class FindMedianSortedArraysBenchmark : Benchmark +// { +// //[Benchmark] +// //public double FindMedianSortedArrays() => Problem.FindMedianSortedArrays(IntArray1, _intArray2); +// } diff --git a/LeetCode.CSharp/Benchmarks/FizzBuzzBenchmark.cs b/LeetCode.CSharp/Benchmarks/FizzBuzzBenchmark.cs index bf7d56a..d5b060b 100644 --- a/LeetCode.CSharp/Benchmarks/FizzBuzzBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/FizzBuzzBenchmark.cs @@ -1,7 +1,7 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class FizzBuzzBenchmark : Benchmark -{ - [Benchmark] - public IList FizzBuzz() => Problem.FizzBuzz(1_000); -} +namespace LeetCode.CSharp.Benchmarks; + +public class FizzBuzzBenchmark : Benchmark +{ + [Benchmark] + public IList FizzBuzz() => Problem.FizzBuzz(1_000); +} diff --git a/LeetCode.CSharp/Benchmarks/GroupAnagramsBenchmark.cs b/LeetCode.CSharp/Benchmarks/GroupAnagramsBenchmark.cs index 9bca599..d6e983c 100644 --- a/LeetCode.CSharp/Benchmarks/GroupAnagramsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/GroupAnagramsBenchmark.cs @@ -1,21 +1,21 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class GroupAnagramsBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(GroupAnagrams))] - public void GroupAnagramsSetup() - { - StringArray1 = new string[10_000]; - - for (var i = 0; i < StringArray1.Length; i++) - { - StringArray1[i] = BuildPseudoRandomString(Random.Next(100)); - } - } - - [Benchmark] - public IList> GroupAnagrams() => Problem.GroupAnagrams(StringArray1); - - [GlobalCleanup(Target = nameof(GroupAnagrams))] - public void GroupAnagramsCleanup() => StringArray1 = []; +namespace LeetCode.CSharp.Benchmarks; + +public class GroupAnagramsBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(GroupAnagrams))] + public void GroupAnagramsSetup() + { + StringArray1 = new string[10_000]; + + for (var i = 0; i < StringArray1.Length; i++) + { + StringArray1[i] = BuildPseudoRandomString(Random.Next(100)); + } + } + + [Benchmark] + public IList> GroupAnagrams() => Problem.GroupAnagrams(StringArray1); + + [GlobalCleanup(Target = nameof(GroupAnagrams))] + public void GroupAnagramsCleanup() => StringArray1 = []; } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/HammingWeightBenchmark.cs b/LeetCode.CSharp/Benchmarks/HammingWeightBenchmark.cs index a6a7b6b..fd344d5 100644 --- a/LeetCode.CSharp/Benchmarks/HammingWeightBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/HammingWeightBenchmark.cs @@ -1,7 +1,7 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class HammingWeightBenchmark : Benchmark -{ - [Benchmark] - public int HammingWeight() => Problem.HammingWeight(uint.MaxValue); -} +namespace LeetCode.CSharp.Benchmarks; + +public class HammingWeightBenchmark : Benchmark +{ + [Benchmark] + public int HammingWeight() => Problem.HammingWeight(uint.MaxValue); +} diff --git a/LeetCode.CSharp/Benchmarks/InsertBenchmark.cs b/LeetCode.CSharp/Benchmarks/InsertBenchmark.cs index 4e21ebb..6643d95 100644 --- a/LeetCode.CSharp/Benchmarks/InsertBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/InsertBenchmark.cs @@ -1,37 +1,37 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class InsertBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(Insert))] - public void InsertSetup() - { - Int1 = 0; - Int2 = 10_000; - IntArrayMulti1 = new int[10_000][]; - - for (var i = 0; i < 10_000; i++) - { - Int1 = Random.Next(0, 10_000); - Int2 = Random.Next(Int1, Int1 + 10_000); - IntArrayMulti1[i] = [Int1, Int2]; - } - - IntArray2 = - [ - IntArrayMulti1[9_999][0] + 1, - IntArrayMulti1[9_999][0] + 10 - ]; - } - - [Benchmark] - public void Insert() => Problem.Insert(IntArrayMulti1, IntArray2); - - [GlobalCleanup(Target = nameof(Insert))] - public void InsertCleanup() - { - Int1 = 0; - Int2 = 0; - IntArrayMulti1 = []; - IntArray2 = []; - } +namespace LeetCode.CSharp.Benchmarks; + +public class InsertBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(Insert))] + public void InsertSetup() + { + Int1 = 0; + Int2 = 10_000; + IntArrayMulti1 = new int[10_000][]; + + for (var i = 0; i < 10_000; i++) + { + Int1 = Random.Next(0, 10_000); + Int2 = Random.Next(Int1, Int1 + 10_000); + IntArrayMulti1[i] = [Int1, Int2]; + } + + IntArray2 = + [ + IntArrayMulti1[9_999][0] + 1, + IntArrayMulti1[9_999][0] + 10 + ]; + } + + [Benchmark] + public void Insert() => Problem.Insert(IntArrayMulti1, IntArray2); + + [GlobalCleanup(Target = nameof(Insert))] + public void InsertCleanup() + { + Int1 = 0; + Int2 = 0; + IntArrayMulti1 = []; + IntArray2 = []; + } } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/InvertTreeBenchmark.cs b/LeetCode.CSharp/Benchmarks/InvertTreeBenchmark.cs index a92acee..e32a280 100644 --- a/LeetCode.CSharp/Benchmarks/InvertTreeBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/InvertTreeBenchmark.cs @@ -1,21 +1,21 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class InvertTreeBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(InvertTree))] - public void InvertTreeSetup() - { - IntArrayNullable = [.. Enumerable.Range(1, 1_000_000).Cast()]; - TreeNode1 = TreeNode.Deserialize(IntArrayNullable)!; - } - - [Benchmark] - public TreeNode? InvertTree() => Problem.InvertTree(TreeNode1); - - [GlobalCleanup(Target = nameof(InvertTree))] - public void InvertTreeCleanup() - { - IntArrayNullable = []; - TreeNode1 = new TreeNode(); - } -} +namespace LeetCode.CSharp.Benchmarks; + +public class InvertTreeBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(InvertTree))] + public void InvertTreeSetup() + { + IntArrayNullable = [.. Enumerable.Range(1, 1_000_000).Cast()]; + TreeNode1 = TreeNode.Deserialize(IntArrayNullable)!; + } + + [Benchmark] + public TreeNode? InvertTree() => Problem.InvertTree(TreeNode1); + + [GlobalCleanup(Target = nameof(InvertTree))] + public void InvertTreeCleanup() + { + IntArrayNullable = []; + TreeNode1 = new TreeNode(); + } +} diff --git a/LeetCode.CSharp/Benchmarks/IsAnagramBenchmark.cs b/LeetCode.CSharp/Benchmarks/IsAnagramBenchmark.cs index 815040d..8db8fad 100644 --- a/LeetCode.CSharp/Benchmarks/IsAnagramBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/IsAnagramBenchmark.cs @@ -1,21 +1,21 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class IsAnagramBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(IsAnagram))] - public void IsAnagramSetup() - { - String1 = BuildPseudoRandomString(1_000_000); - String2 = String1.Reverse().ToString()!; - } - - [Benchmark] - public bool IsAnagram() => Problem.IsAnagram(String1, String2); - - [GlobalCleanup(Target = nameof(IsAnagram))] - public void IsAnagramCleanup() - { - String1 = string.Empty; - String2 = string.Empty; - } +namespace LeetCode.CSharp.Benchmarks; + +public class IsAnagramBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(IsAnagram))] + public void IsAnagramSetup() + { + String1 = BuildPseudoRandomString(1_000_000); + String2 = String1.Reverse().ToString()!; + } + + [Benchmark] + public bool IsAnagram() => Problem.IsAnagram(String1, String2); + + [GlobalCleanup(Target = nameof(IsAnagram))] + public void IsAnagramCleanup() + { + String1 = string.Empty; + String2 = string.Empty; + } } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/IsBalancedBenchmark.cs b/LeetCode.CSharp/Benchmarks/IsBalancedBenchmark.cs index 51bc71c..e169fbe 100644 --- a/LeetCode.CSharp/Benchmarks/IsBalancedBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/IsBalancedBenchmark.cs @@ -1,21 +1,21 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class IsBalancedBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(IsBalanced))] - public void IsBalancedSetup() - { - IntArrayNullable = [.. Enumerable.Range(1, 1_000_000).Cast()]; - TreeNode1 = TreeNode.Deserialize(IntArrayNullable)!; - } - - [Benchmark] - public bool IsBalanced() => Problem.IsBalanced(TreeNode1); - - [GlobalCleanup(Target = nameof(IsBalanced))] - public void IsBalancedCleanup() - { - IntArrayNullable = []; - TreeNode1 = new TreeNode(); - } -} +namespace LeetCode.CSharp.Benchmarks; + +public class IsBalancedBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(IsBalanced))] + public void IsBalancedSetup() + { + IntArrayNullable = [.. Enumerable.Range(1, 1_000_000).Cast()]; + TreeNode1 = TreeNode.Deserialize(IntArrayNullable)!; + } + + [Benchmark] + public bool IsBalanced() => Problem.IsBalanced(TreeNode1); + + [GlobalCleanup(Target = nameof(IsBalanced))] + public void IsBalancedCleanup() + { + IntArrayNullable = []; + TreeNode1 = new TreeNode(); + } +} diff --git a/LeetCode.CSharp/Benchmarks/IsHappyBenchmark.cs b/LeetCode.CSharp/Benchmarks/IsHappyBenchmark.cs index d0348a8..70c044e 100644 --- a/LeetCode.CSharp/Benchmarks/IsHappyBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/IsHappyBenchmark.cs @@ -1,7 +1,7 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class IsHappyBenchmark : Benchmark -{ - [Benchmark] - public bool IsHappy() => Problem.IsHappy(int.MaxValue); -} +namespace LeetCode.CSharp.Benchmarks; + +public class IsHappyBenchmark : Benchmark +{ + [Benchmark] + public bool IsHappy() => Problem.IsHappy(int.MaxValue); +} diff --git a/LeetCode.CSharp/Benchmarks/IsPalindromeBenchmark.cs b/LeetCode.CSharp/Benchmarks/IsPalindromeBenchmark.cs index d440305..a60269b 100644 --- a/LeetCode.CSharp/Benchmarks/IsPalindromeBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/IsPalindromeBenchmark.cs @@ -1,23 +1,23 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class IsPalindromeBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(IsPalindrome))] - public void IsPalindromeSetup() - { - IntArray1 = [.. Enumerable.Range(1, 10_000)]; - IntArray2 = [.. IntArray1.Reverse()]; - ListNode1 = new ListNode(IntArray1.Concat(IntArray2).ToArray()); - } - - [Benchmark] - public bool IsPalindrome() => Problem.IsPalindrome(ListNode1); - - [GlobalCleanup(Target = nameof(IsPalindrome))] - public void IsPalindromeCleanup() - { - IntArray1 = []; - IntArray2 = []; - ListNode1 = new ListNode(); - } +namespace LeetCode.CSharp.Benchmarks; + +public class IsPalindromeBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(IsPalindrome))] + public void IsPalindromeSetup() + { + IntArray1 = [.. Enumerable.Range(1, 10_000)]; + IntArray2 = [.. IntArray1.Reverse()]; + ListNode1 = new ListNode(IntArray1.Concat(IntArray2).ToArray()); + } + + [Benchmark] + public bool IsPalindrome() => Problem.IsPalindrome(ListNode1); + + [GlobalCleanup(Target = nameof(IsPalindrome))] + public void IsPalindromeCleanup() + { + IntArray1 = []; + IntArray2 = []; + ListNode1 = new ListNode(); + } } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/IsSameTreeBenchmark.cs b/LeetCode.CSharp/Benchmarks/IsSameTreeBenchmark.cs index 8d2f50b..3b83ba6 100644 --- a/LeetCode.CSharp/Benchmarks/IsSameTreeBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/IsSameTreeBenchmark.cs @@ -1,23 +1,23 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class IsSameTreeBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(IsSameTree))] - public void IsSameTreeSetup() - { - IntArrayNullable = [.. Enumerable.Range(1, 1_000_000).Cast()]; - TreeNode1 = TreeNode.Deserialize(IntArrayNullable)!; - TreeNode2 = TreeNode.Deserialize(IntArrayNullable)!; - } - - [Benchmark] - public bool IsSameTree() => Problem.IsSameTree(TreeNode1, TreeNode2); - - [GlobalCleanup(Target = nameof(IsSameTree))] - public void IsSameTreeCleanup() - { - IntArrayNullable = []; - TreeNode1 = new TreeNode(); - TreeNode2 = new TreeNode(); - } -} +namespace LeetCode.CSharp.Benchmarks; + +public class IsSameTreeBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(IsSameTree))] + public void IsSameTreeSetup() + { + IntArrayNullable = [.. Enumerable.Range(1, 1_000_000).Cast()]; + TreeNode1 = TreeNode.Deserialize(IntArrayNullable)!; + TreeNode2 = TreeNode.Deserialize(IntArrayNullable)!; + } + + [Benchmark] + public bool IsSameTree() => Problem.IsSameTree(TreeNode1, TreeNode2); + + [GlobalCleanup(Target = nameof(IsSameTree))] + public void IsSameTreeCleanup() + { + IntArrayNullable = []; + TreeNode1 = new TreeNode(); + TreeNode2 = new TreeNode(); + } +} diff --git a/LeetCode.CSharp/Benchmarks/IsSubtreeBenchmark.cs b/LeetCode.CSharp/Benchmarks/IsSubtreeBenchmark.cs index 12ca236..67454ba 100644 --- a/LeetCode.CSharp/Benchmarks/IsSubtreeBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/IsSubtreeBenchmark.cs @@ -1,23 +1,23 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class IsSubtreeBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(IsSubtree))] - public void IsSubtreeSetup() - { - IntArrayNullable = [.. Enumerable.Range(1, 1_000_000).Cast()]; - TreeNode1 = TreeNode.Deserialize(IntArrayNullable)!; - TreeNode2 = TreeNode.Deserialize(IntArrayNullable)!; - } - - [Benchmark] - public bool IsSubtree() => Problem.IsSubtree(TreeNode1, TreeNode2); - - [GlobalCleanup(Target = nameof(IsSubtree))] - public void IsSubtreeCleanup() - { - IntArrayNullable = []; - TreeNode1 = new TreeNode(); - TreeNode2 = new TreeNode(); - } -} +namespace LeetCode.CSharp.Benchmarks; + +public class IsSubtreeBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(IsSubtree))] + public void IsSubtreeSetup() + { + IntArrayNullable = [.. Enumerable.Range(1, 1_000_000).Cast()]; + TreeNode1 = TreeNode.Deserialize(IntArrayNullable)!; + TreeNode2 = TreeNode.Deserialize(IntArrayNullable)!; + } + + [Benchmark] + public bool IsSubtree() => Problem.IsSubtree(TreeNode1, TreeNode2); + + [GlobalCleanup(Target = nameof(IsSubtree))] + public void IsSubtreeCleanup() + { + IntArrayNullable = []; + TreeNode1 = new TreeNode(); + TreeNode2 = new TreeNode(); + } +} diff --git a/LeetCode.CSharp/Benchmarks/IsValidSudokuBenchmark.cs b/LeetCode.CSharp/Benchmarks/IsValidSudokuBenchmark.cs index a80d4a5..25864a2 100644 --- a/LeetCode.CSharp/Benchmarks/IsValidSudokuBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/IsValidSudokuBenchmark.cs @@ -1,24 +1,24 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class IsValidSudokuBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(IsValidSudoku))] - public void IsValidSudokuSetup() => CharArrayMulti = - [ - ['5', '3', '.', '.', '7', '.', '.', '.', '.'], - ['6', '.', '.', '1', '9', '5', '.', '.', '.'], - ['.', '9', '8', '.', '.', '.', '.', '6', '.'], - ['8', '.', '.', '.', '6', '.', '.', '.', '3'], - ['4', '.', '.', '8', '.', '3', '.', '.', '1'], - ['7', '.', '.', '.', '2', '.', '.', '.', '6'], - ['.', '6', '.', '.', '.', '.', '2', '8', '.'], - ['.', '.', '.', '4', '1', '9', '.', '.', '5'], - ['.', '.', '.', '.', '8', '.', '.', '7', '9'] - ]; - - [Benchmark] - public bool IsValidSudoku() => Problem.IsValidSudoku(CharArrayMulti); - - [GlobalCleanup(Target = nameof(IsValidSudoku))] - public void IsValidSudokuCleanup() => CharArrayMulti = [[char.MinValue]]; +namespace LeetCode.CSharp.Benchmarks; + +public class IsValidSudokuBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(IsValidSudoku))] + public void IsValidSudokuSetup() => CharArrayMulti = + [ + ['5', '3', '.', '.', '7', '.', '.', '.', '.'], + ['6', '.', '.', '1', '9', '5', '.', '.', '.'], + ['.', '9', '8', '.', '.', '.', '.', '6', '.'], + ['8', '.', '.', '.', '6', '.', '.', '.', '3'], + ['4', '.', '.', '8', '.', '3', '.', '.', '1'], + ['7', '.', '.', '.', '2', '.', '.', '.', '6'], + ['.', '6', '.', '.', '.', '.', '2', '8', '.'], + ['.', '.', '.', '4', '1', '9', '.', '.', '5'], + ['.', '.', '.', '.', '8', '.', '.', '7', '9'] + ]; + + [Benchmark] + public bool IsValidSudoku() => Problem.IsValidSudoku(CharArrayMulti); + + [GlobalCleanup(Target = nameof(IsValidSudoku))] + public void IsValidSudokuCleanup() => CharArrayMulti = [[char.MinValue]]; } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/KWeakestRowsBenchmark.cs b/LeetCode.CSharp/Benchmarks/KWeakestRowsBenchmark.cs index c72f9e9..69e5315 100644 --- a/LeetCode.CSharp/Benchmarks/KWeakestRowsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/KWeakestRowsBenchmark.cs @@ -1,25 +1,25 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class KWeakestRowsBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(KWeakestRows))] - public void KWeakestRowsSetup() - { - IntArray1 = [.. Enumerable.Range(1, 1_000)]; - IntArrayMulti1 = new int[1_000][]; - for (var i = 0; i < IntArrayMulti1.Length; i++) - { - IntArrayMulti1[i] = IntArray1; - } - } - - [Benchmark] - public int[] KWeakestRows() => Problem.KWeakestRows(IntArrayMulti1, 999); - - [GlobalCleanup(Target = nameof(KWeakestRows))] - public void KWeakestRowsCleanup() - { - IntArray1 = []; - IntArrayMulti1 = []; - } +namespace LeetCode.CSharp.Benchmarks; + +public class KWeakestRowsBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(KWeakestRows))] + public void KWeakestRowsSetup() + { + IntArray1 = [.. Enumerable.Range(1, 1_000)]; + IntArrayMulti1 = new int[1_000][]; + for (var i = 0; i < IntArrayMulti1.Length; i++) + { + IntArrayMulti1[i] = IntArray1; + } + } + + [Benchmark] + public int[] KWeakestRows() => Problem.KWeakestRows(IntArrayMulti1, 999); + + [GlobalCleanup(Target = nameof(KWeakestRows))] + public void KWeakestRowsCleanup() + { + IntArray1 = []; + IntArrayMulti1 = []; + } } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/KthLargestBenchmark.cs b/LeetCode.CSharp/Benchmarks/KthLargestBenchmark.cs index 620e2e1..5f97dbf 100644 --- a/LeetCode.CSharp/Benchmarks/KthLargestBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/KthLargestBenchmark.cs @@ -1,23 +1,23 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class KthLargestBenchmark : Benchmark -{ - private Problem.KthLargest _kthLargest = null!; - - [GlobalSetup(Target = nameof(KthLargest))] - public void KthLargestSetup() - { - IntArray1 = [.. Enumerable.Range(1, 100_000_000)]; - _kthLargest = new Problem.KthLargest(50_000_000, IntArray1); - } - - [Benchmark] - public int KthLargest() => _kthLargest.Add(75_000_000); - - [GlobalCleanup(Target = nameof(KthLargest))] - public void KthLargestCleanup() - { - IntArray1 = []; - _kthLargest = null!; - } +namespace LeetCode.CSharp.Benchmarks; + +public class KthLargestBenchmark : Benchmark +{ + private Problem.KthLargest _kthLargest = null!; + + [GlobalSetup(Target = nameof(KthLargest))] + public void KthLargestSetup() + { + IntArray1 = [.. Enumerable.Range(1, 100_000_000)]; + _kthLargest = new Problem.KthLargest(50_000_000, IntArray1); + } + + [Benchmark] + public int KthLargest() => _kthLargest.Add(75_000_000); + + [GlobalCleanup(Target = nameof(KthLargest))] + public void KthLargestCleanup() + { + IntArray1 = []; + _kthLargest = null!; + } } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/LRUCacheBenchmark.cs b/LeetCode.CSharp/Benchmarks/LRUCacheBenchmark.cs index c8fec7e..0fe260d 100644 --- a/LeetCode.CSharp/Benchmarks/LRUCacheBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/LRUCacheBenchmark.cs @@ -1,26 +1,26 @@ -namespace LeetCode.CSharp.Benchmarks; - -[SuppressMessage("ReSharper", "InconsistentNaming")] -public class LRUCacheBenchmark : Benchmark -{ - private Problem.LRUCache _lruCache = null!; - - [GlobalSetup(Target = nameof(LRUCache))] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public void LRUCacheSetup() - { - _lruCache = new Problem.LRUCache(1_000_000); - for (var i = 0; i < 1_000_000; i++) - { - _lruCache.Put(i, i); - } - } - - [Benchmark] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public int LRUCache() => _lruCache.Get(500_000); - - [GlobalCleanup(Target = nameof(LRUCache))] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public void LRUCacheCleanup() => _lruCache = null!; +namespace LeetCode.CSharp.Benchmarks; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +public class LRUCacheBenchmark : Benchmark +{ + private Problem.LRUCache _lruCache = null!; + + [GlobalSetup(Target = nameof(LRUCache))] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public void LRUCacheSetup() + { + _lruCache = new Problem.LRUCache(1_000_000); + for (var i = 0; i < 1_000_000; i++) + { + _lruCache.Put(i, i); + } + } + + [Benchmark] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public int LRUCache() => _lruCache.Get(500_000); + + [GlobalCleanup(Target = nameof(LRUCache))] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public void LRUCacheCleanup() => _lruCache = null!; } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/LastStoneWeightBenchmark.cs b/LeetCode.CSharp/Benchmarks/LastStoneWeightBenchmark.cs index a27da4e..d741467 100644 --- a/LeetCode.CSharp/Benchmarks/LastStoneWeightBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/LastStoneWeightBenchmark.cs @@ -1,13 +1,13 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class LastStoneWeightBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(LastStoneWeight))] - public void LastStoneWeightSetup() => IntArray1 = [.. Enumerable.Range(1, 1_000_000)]; - - [Benchmark] - public int LastStoneWeight() => Problem.LastStoneWeight(IntArray1); - - [GlobalCleanup(Target = nameof(LastStoneWeight))] - public void LastStoneWeightCleanup() => IntArray1 = []; +namespace LeetCode.CSharp.Benchmarks; + +public class LastStoneWeightBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(LastStoneWeight))] + public void LastStoneWeightSetup() => IntArray1 = [.. Enumerable.Range(1, 1_000_000)]; + + [Benchmark] + public int LastStoneWeight() => Problem.LastStoneWeight(IntArray1); + + [GlobalCleanup(Target = nameof(LastStoneWeight))] + public void LastStoneWeightCleanup() => IntArray1 = []; } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/LengthOfLongestSubstringBenchmark.cs b/LeetCode.CSharp/Benchmarks/LengthOfLongestSubstringBenchmark.cs index 4cf9896..6a2cce3 100644 --- a/LeetCode.CSharp/Benchmarks/LengthOfLongestSubstringBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/LengthOfLongestSubstringBenchmark.cs @@ -1,13 +1,13 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class LengthOfLongestSubstringBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(LengthOfLongestSubstring))] - public void LengthOfLongestSubstringSetup() => String1 = BuildPseudoRandomString(1_000_000); - - [Benchmark] - public int LengthOfLongestSubstring() => Problem.LengthOfLongestSubstring(String1); - - [GlobalCleanup(Target = nameof(LengthOfLongestSubstring))] - public void LengthOfLongestSubstringCleanup() => String1 = string.Empty; +namespace LeetCode.CSharp.Benchmarks; + +public class LengthOfLongestSubstringBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(LengthOfLongestSubstring))] + public void LengthOfLongestSubstringSetup() => String1 = BuildPseudoRandomString(1_000_000); + + [Benchmark] + public int LengthOfLongestSubstring() => Problem.LengthOfLongestSubstring(String1); + + [GlobalCleanup(Target = nameof(LengthOfLongestSubstring))] + public void LengthOfLongestSubstringCleanup() => String1 = string.Empty; } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/LowestCommonAncestorBenchmark.cs b/LeetCode.CSharp/Benchmarks/LowestCommonAncestorBenchmark.cs index 66b4278..54e4167 100644 --- a/LeetCode.CSharp/Benchmarks/LowestCommonAncestorBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/LowestCommonAncestorBenchmark.cs @@ -1,28 +1,28 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class LowestCommonAncestorBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(LowestCommonAncestor))] - public void LowestCommonAncestorSetup() - { - IntArrayNullable = [.. Enumerable.Range(1, 10_000_000).Cast()]; - TreeNode1 = TreeNode.Deserialize(IntArrayNullable)!; - TreeNode2 = TreeNode1.left!; - while (TreeNode2.left is not null) - { - TreeNode2 = TreeNode2.left; - } - } - - [Benchmark] - public TreeNode LowestCommonAncestor() => - Problem.LowestCommonAncestor(TreeNode1, TreeNode1, TreeNode2); - - [GlobalCleanup(Target = nameof(LowestCommonAncestor))] - public void LowestCommonAncestorCleanup() - { - IntArrayNullable = []; - TreeNode1 = new TreeNode(); - TreeNode2 = new TreeNode(); - } -} +namespace LeetCode.CSharp.Benchmarks; + +public class LowestCommonAncestorBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(LowestCommonAncestor))] + public void LowestCommonAncestorSetup() + { + IntArrayNullable = [.. Enumerable.Range(1, 10_000_000).Cast()]; + TreeNode1 = TreeNode.Deserialize(IntArrayNullable)!; + TreeNode2 = TreeNode1.left!; + while (TreeNode2.left is not null) + { + TreeNode2 = TreeNode2.left; + } + } + + [Benchmark] + public TreeNode LowestCommonAncestor() => + Problem.LowestCommonAncestor(TreeNode1, TreeNode1, TreeNode2); + + [GlobalCleanup(Target = nameof(LowestCommonAncestor))] + public void LowestCommonAncestorCleanup() + { + IntArrayNullable = []; + TreeNode1 = new TreeNode(); + TreeNode2 = new TreeNode(); + } +} diff --git a/LeetCode.CSharp/Benchmarks/MaxDepthBenchmark.cs b/LeetCode.CSharp/Benchmarks/MaxDepthBenchmark.cs index 17e4dd6..498b4f3 100644 --- a/LeetCode.CSharp/Benchmarks/MaxDepthBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/MaxDepthBenchmark.cs @@ -1,21 +1,21 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class MaxDepthBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(MaxDepth))] - public void MaxDepthSetup() - { - IntArrayNullable = [.. Enumerable.Range(1, 10_000_000).Cast()]; - TreeNode1 = TreeNode.Deserialize(IntArrayNullable)!; - } - - [Benchmark] - public int MaxDepth() => Problem.MaxDepth(TreeNode1); - - [GlobalCleanup(Target = nameof(MaxDepth))] - public void MaxDepthCleanup() - { - IntArrayNullable = []; - TreeNode1 = new TreeNode(); - } -} +namespace LeetCode.CSharp.Benchmarks; + +public class MaxDepthBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(MaxDepth))] + public void MaxDepthSetup() + { + IntArrayNullable = [.. Enumerable.Range(1, 10_000_000).Cast()]; + TreeNode1 = TreeNode.Deserialize(IntArrayNullable)!; + } + + [Benchmark] + public int MaxDepth() => Problem.MaxDepth(TreeNode1); + + [GlobalCleanup(Target = nameof(MaxDepth))] + public void MaxDepthCleanup() + { + IntArrayNullable = []; + TreeNode1 = new TreeNode(); + } +} diff --git a/LeetCode.CSharp/Benchmarks/MaxProfitBenchmark.cs b/LeetCode.CSharp/Benchmarks/MaxProfitBenchmark.cs index 857c733..0301912 100644 --- a/LeetCode.CSharp/Benchmarks/MaxProfitBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/MaxProfitBenchmark.cs @@ -1,13 +1,13 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class MaxProfitBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(MaxProfit))] - public void MaxProfitSetup() => IntArray1 = [.. Enumerable.Range(1, 10_000_000)]; - - [Benchmark] - public int MaxProfit() => Problem.MaxProfit(IntArray1); - - [GlobalCleanup(Target = nameof(MaxProfit))] - public void MaxProfitCleanup() => IntArray1 = []; +namespace LeetCode.CSharp.Benchmarks; + +public class MaxProfitBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(MaxProfit))] + public void MaxProfitSetup() => IntArray1 = [.. Enumerable.Range(1, 10_000_000)]; + + [Benchmark] + public int MaxProfit() => Problem.MaxProfit(IntArray1); + + [GlobalCleanup(Target = nameof(MaxProfit))] + public void MaxProfitCleanup() => IntArray1 = []; } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/MaxSubarrayBenchmark.cs b/LeetCode.CSharp/Benchmarks/MaxSubarrayBenchmark.cs index 1385a05..d291e3a 100644 --- a/LeetCode.CSharp/Benchmarks/MaxSubarrayBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/MaxSubarrayBenchmark.cs @@ -1,15 +1,15 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class MaxSubarrayBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(MaxSubarray))] - public void MaxSubarraySetup() => - IntArray1 = [.. Enumerable.Range(1, 1_000_000) -, .. Enumerable.Range(1, 1_000_000)]; - - [Benchmark] - public int MaxSubarray() => Problem.MaxSubarray(IntArray1); - - [GlobalCleanup(Target = nameof(MaxSubarray))] - public void MaxSubarrayCleanup() => IntArray1 = []; -} +namespace LeetCode.CSharp.Benchmarks; + +public class MaxSubarrayBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(MaxSubarray))] + public void MaxSubarraySetup() => + IntArray1 = [.. Enumerable.Range(1, 1_000_000) +, .. Enumerable.Range(1, 1_000_000)]; + + [Benchmark] + public int MaxSubarray() => Problem.MaxSubarray(IntArray1); + + [GlobalCleanup(Target = nameof(MaxSubarray))] + public void MaxSubarrayCleanup() => IntArray1 = []; +} diff --git a/LeetCode.CSharp/Benchmarks/MaximumWealthBenchmark.cs b/LeetCode.CSharp/Benchmarks/MaximumWealthBenchmark.cs index 8a05331..fce1c93 100644 --- a/LeetCode.CSharp/Benchmarks/MaximumWealthBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/MaximumWealthBenchmark.cs @@ -1,25 +1,25 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class MaximumWealthBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(MaximumWealth))] - public void MaximumWealthSetup() - { - IntArray1 = [.. Enumerable.Range(1, 1_000)]; - IntArrayMulti1 = new int[10_000][]; - for (var i = 0; i < IntArrayMulti1.Length; i++) - { - IntArrayMulti1[i] = IntArray1; - } - } - - [Benchmark] - public int MaximumWealth() => Problem.MaximumWealth(IntArrayMulti1); - - [GlobalCleanup(Target = nameof(MaximumWealth))] - public void MaximumWealthCleanup() - { - IntArray1 = []; - IntArrayMulti1 = []; - } +namespace LeetCode.CSharp.Benchmarks; + +public class MaximumWealthBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(MaximumWealth))] + public void MaximumWealthSetup() + { + IntArray1 = [.. Enumerable.Range(1, 1_000)]; + IntArrayMulti1 = new int[10_000][]; + for (var i = 0; i < IntArrayMulti1.Length; i++) + { + IntArrayMulti1[i] = IntArray1; + } + } + + [Benchmark] + public int MaximumWealth() => Problem.MaximumWealth(IntArrayMulti1); + + [GlobalCleanup(Target = nameof(MaximumWealth))] + public void MaximumWealthCleanup() + { + IntArray1 = []; + IntArrayMulti1 = []; + } } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/MergeTwoListsBenchmark.cs b/LeetCode.CSharp/Benchmarks/MergeTwoListsBenchmark.cs index 29e15a1..56a4c63 100644 --- a/LeetCode.CSharp/Benchmarks/MergeTwoListsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/MergeTwoListsBenchmark.cs @@ -1,27 +1,27 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class MergeTwoListsBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(MergeTwoLists))] - public void MergeTwoListsSetup() - { - ListNode1 = new ListNode(Enumerable.Range(1, 100_000).ToArray()); - ListNode2 = new ListNode(Enumerable.Range(1, 50_000).ToArray()); - } - - [Benchmark] - public ListNode? MergeTwoLists() - { - // TODO Work out why ListNode1 and ListNode2 bork on GlobalSetup - var listNode1 = new ListNode(Enumerable.Range(1, 100_000).ToArray()); - var listNode2 = new ListNode(Enumerable.Range(1, 50_000).ToArray()); - return Problem.MergeTwoLists(listNode1, listNode2); - } - - [GlobalCleanup(Target = nameof(MergeTwoLists))] - public void MergeTwoListsCleanup() - { - ListNode1 = new ListNode(); - ListNode2 = new ListNode(); - } -} +namespace LeetCode.CSharp.Benchmarks; + +public class MergeTwoListsBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(MergeTwoLists))] + public void MergeTwoListsSetup() + { + ListNode1 = new ListNode(Enumerable.Range(1, 100_000).ToArray()); + ListNode2 = new ListNode(Enumerable.Range(1, 50_000).ToArray()); + } + + [Benchmark] + public ListNode? MergeTwoLists() + { + // TODO Work out why ListNode1 and ListNode2 bork on GlobalSetup + var listNode1 = new ListNode(Enumerable.Range(1, 100_000).ToArray()); + var listNode2 = new ListNode(Enumerable.Range(1, 50_000).ToArray()); + return Problem.MergeTwoLists(listNode1, listNode2); + } + + [GlobalCleanup(Target = nameof(MergeTwoLists))] + public void MergeTwoListsCleanup() + { + ListNode1 = new ListNode(); + ListNode2 = new ListNode(); + } +} diff --git a/LeetCode.CSharp/Benchmarks/MiddleNodeBenchmark.cs b/LeetCode.CSharp/Benchmarks/MiddleNodeBenchmark.cs index a978b3c..ab15158 100644 --- a/LeetCode.CSharp/Benchmarks/MiddleNodeBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/MiddleNodeBenchmark.cs @@ -1,14 +1,14 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class MiddleNodeBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(MiddleNode))] - public void MiddleNodeSetup() => - ListNode1 = new ListNode(Enumerable.Range(1, 1_000_000).ToArray()); - - [Benchmark] - public ListNode MiddleNode() => Problem.MiddleNode(ListNode1); - - [GlobalCleanup(Target = nameof(MiddleNode))] - public void MiddleNodeCleanup() => ListNode1 = new ListNode(); +namespace LeetCode.CSharp.Benchmarks; + +public class MiddleNodeBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(MiddleNode))] + public void MiddleNodeSetup() => + ListNode1 = new ListNode(Enumerable.Range(1, 1_000_000).ToArray()); + + [Benchmark] + public ListNode MiddleNode() => Problem.MiddleNode(ListNode1); + + [GlobalCleanup(Target = nameof(MiddleNode))] + public void MiddleNodeCleanup() => ListNode1 = new ListNode(); } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/MinCostClimbingStairsBenchmark.cs b/LeetCode.CSharp/Benchmarks/MinCostClimbingStairsBenchmark.cs index f6e479b..c63383d 100644 --- a/LeetCode.CSharp/Benchmarks/MinCostClimbingStairsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/MinCostClimbingStairsBenchmark.cs @@ -1,15 +1,15 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class MinCostClimbingStairsBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(MinCostClimbingStairs))] - public void MinCostClimbingStairsSetup() => - IntArray1 = [.. Enumerable.Range(1, 1_000_000) -, .. Enumerable.Range(1, 1_000_000)]; - - [Benchmark] - public int MinCostClimbingStairs() => Problem.MinCostClimbingStairs(IntArray1); - - [GlobalCleanup(Target = nameof(MinCostClimbingStairs))] - public void MinCostClimbingStairsCleanup() => IntArray1 = []; -} +namespace LeetCode.CSharp.Benchmarks; + +public class MinCostClimbingStairsBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(MinCostClimbingStairs))] + public void MinCostClimbingStairsSetup() => + IntArray1 = [.. Enumerable.Range(1, 1_000_000) +, .. Enumerable.Range(1, 1_000_000)]; + + [Benchmark] + public int MinCostClimbingStairs() => Problem.MinCostClimbingStairs(IntArray1); + + [GlobalCleanup(Target = nameof(MinCostClimbingStairs))] + public void MinCostClimbingStairsCleanup() => IntArray1 = []; +} diff --git a/LeetCode.CSharp/Benchmarks/MissingNumberBenchmark.cs b/LeetCode.CSharp/Benchmarks/MissingNumberBenchmark.cs index 010e6be..4d5dfe2 100644 --- a/LeetCode.CSharp/Benchmarks/MissingNumberBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/MissingNumberBenchmark.cs @@ -1,14 +1,14 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class MissingNumberBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(MissingNumber))] - public void MissingNumberSetup() => - IntArray1 = [.. Enumerable.Range(0, 1_000_000).Except([100_000])]; - - [Benchmark] - public int MissingNumber() => Problem.MissingNumber(IntArray1); - - [GlobalCleanup(Target = nameof(MissingNumber))] - public void MissingNumberCleanup() => IntArray1 = []; +namespace LeetCode.CSharp.Benchmarks; + +public class MissingNumberBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(MissingNumber))] + public void MissingNumberSetup() => + IntArray1 = [.. Enumerable.Range(0, 1_000_000).Except([100_000])]; + + [Benchmark] + public int MissingNumber() => Problem.MissingNumber(IntArray1); + + [GlobalCleanup(Target = nameof(MissingNumber))] + public void MissingNumberCleanup() => IntArray1 = []; } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/NumIslandsBenchmark.cs b/LeetCode.CSharp/Benchmarks/NumIslandsBenchmark.cs index 6d11049..c7214fa 100644 --- a/LeetCode.CSharp/Benchmarks/NumIslandsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/NumIslandsBenchmark.cs @@ -1,27 +1,27 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class NumIslandsBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(NumIslands))] - public void NumIslandsSetup() - { - var random = new Random(618); - - CharArrayMulti = new char[1_000][]; - for (var i = 0; i < CharArrayMulti.Length; i++) - { - CharArrayMulti[i] = new char[1_000]; - for (var j = 0; j < CharArrayMulti[i].Length; j++) - { - var isLand = j % random.Next(1, 10) == 0; - CharArrayMulti[i][j] = isLand ? '1' : '0'; - } - } - } - - [Benchmark] - public int NumIslands() => Problem.NumIslands(CharArrayMulti); - - [GlobalCleanup(Target = nameof(NumIslands))] - public void NumIslandsCleanup() => CharArrayMulti = [[char.MinValue]]; -} +namespace LeetCode.CSharp.Benchmarks; + +public class NumIslandsBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(NumIslands))] + public void NumIslandsSetup() + { + var random = new Random(618); + + CharArrayMulti = new char[1_000][]; + for (var i = 0; i < CharArrayMulti.Length; i++) + { + CharArrayMulti[i] = new char[1_000]; + for (var j = 0; j < CharArrayMulti[i].Length; j++) + { + var isLand = j % random.Next(1, 10) == 0; + CharArrayMulti[i][j] = isLand ? '1' : '0'; + } + } + } + + [Benchmark] + public int NumIslands() => Problem.NumIslands(CharArrayMulti); + + [GlobalCleanup(Target = nameof(NumIslands))] + public void NumIslandsCleanup() => CharArrayMulti = [[char.MinValue]]; +} diff --git a/LeetCode.CSharp/Benchmarks/NumberOfStepsBenchmark.cs b/LeetCode.CSharp/Benchmarks/NumberOfStepsBenchmark.cs index 5827ad4..ffda485 100644 --- a/LeetCode.CSharp/Benchmarks/NumberOfStepsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/NumberOfStepsBenchmark.cs @@ -1,7 +1,7 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class NumberOfStepsBenchmark : Benchmark -{ - [Benchmark] - public int NumberOfSteps() => Problem.NumberOfSteps(1_000_000_000); +namespace LeetCode.CSharp.Benchmarks; + +public class NumberOfStepsBenchmark : Benchmark +{ + [Benchmark] + public int NumberOfSteps() => Problem.NumberOfSteps(1_000_000_000); } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/PlusOneBenchmark.cs b/LeetCode.CSharp/Benchmarks/PlusOneBenchmark.cs index 7fcd827..1eea578 100644 --- a/LeetCode.CSharp/Benchmarks/PlusOneBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/PlusOneBenchmark.cs @@ -1,15 +1,15 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class PlusOneBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(PlusOne))] - public void PlusOneSetup() => - IntArray1 = [.. Enumerable.Range(1, 1_000_000) -, .. Enumerable.Range(1, 1_000_000)]; - - [Benchmark] - public int[] PlusOne() => Problem.PlusOne(IntArray1); - - [GlobalCleanup(Target = nameof(PlusOne))] - public void PlusOneCleanup() => IntArray1 = []; -} +namespace LeetCode.CSharp.Benchmarks; + +public class PlusOneBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(PlusOne))] + public void PlusOneSetup() => + IntArray1 = [.. Enumerable.Range(1, 1_000_000) +, .. Enumerable.Range(1, 1_000_000)]; + + [Benchmark] + public int[] PlusOne() => Problem.PlusOne(IntArray1); + + [GlobalCleanup(Target = nameof(PlusOne))] + public void PlusOneCleanup() => IntArray1 = []; +} diff --git a/LeetCode.CSharp/Benchmarks/ProductExceptSelfBenchmark.cs b/LeetCode.CSharp/Benchmarks/ProductExceptSelfBenchmark.cs index eb45ec8..d26499d 100644 --- a/LeetCode.CSharp/Benchmarks/ProductExceptSelfBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/ProductExceptSelfBenchmark.cs @@ -1,13 +1,13 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class ProductExceptSelfBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(ProductExceptSelf))] - public void ProductExceptSelfSetup() => IntArray1 = [.. Enumerable.Range(1, 100_000)]; - - [Benchmark] - public int[] ProductExceptSelf() => Problem.ProductExceptSelf(IntArray1); - - [GlobalCleanup(Target = nameof(ProductExceptSelf))] - public void ProductExceptSelfCleanup() => StringArray1 = []; +namespace LeetCode.CSharp.Benchmarks; + +public class ProductExceptSelfBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(ProductExceptSelf))] + public void ProductExceptSelfSetup() => IntArray1 = [.. Enumerable.Range(1, 100_000)]; + + [Benchmark] + public int[] ProductExceptSelf() => Problem.ProductExceptSelf(IntArray1); + + [GlobalCleanup(Target = nameof(ProductExceptSelf))] + public void ProductExceptSelfCleanup() => StringArray1 = []; } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/RansomNoteBenchmark.cs b/LeetCode.CSharp/Benchmarks/RansomNoteBenchmark.cs index 9a7bf5b..28a3a0d 100644 --- a/LeetCode.CSharp/Benchmarks/RansomNoteBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/RansomNoteBenchmark.cs @@ -1,21 +1,21 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class RansomNoteBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(RansomNote))] - public void RansomNoteSetup() - { - String1 = BuildPseudoRandomString(100); - String2 = BuildPseudoRandomString(1_000_000); - } - - [Benchmark] - public bool RansomNote() => Problem.RansomNote(String1, String2); - - [GlobalCleanup(Target = nameof(RansomNote))] - public void RansomNoteCleanup() - { - String1 = string.Empty; - String2 = string.Empty; - } +namespace LeetCode.CSharp.Benchmarks; + +public class RansomNoteBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(RansomNote))] + public void RansomNoteSetup() + { + String1 = BuildPseudoRandomString(100); + String2 = BuildPseudoRandomString(1_000_000); + } + + [Benchmark] + public bool RansomNote() => Problem.RansomNote(String1, String2); + + [GlobalCleanup(Target = nameof(RansomNote))] + public void RansomNoteCleanup() + { + String1 = string.Empty; + String2 = string.Empty; + } } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/ReverseBitsBenchmark.cs b/LeetCode.CSharp/Benchmarks/ReverseBitsBenchmark.cs index 6b42669..083ebf6 100644 --- a/LeetCode.CSharp/Benchmarks/ReverseBitsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/ReverseBitsBenchmark.cs @@ -1,7 +1,7 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class ReverseBitsBenchmark : Benchmark -{ - [Benchmark] - public uint ReverseBits() => Problem.ReverseBits(0b00100010100101000001111010011100); +namespace LeetCode.CSharp.Benchmarks; + +public class ReverseBitsBenchmark : Benchmark +{ + [Benchmark] + public uint ReverseBits() => Problem.ReverseBits(0b00100010100101000001111010011100); } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/ReverseListBenchmark.cs b/LeetCode.CSharp/Benchmarks/ReverseListBenchmark.cs index ad89f01..66c6e94 100644 --- a/LeetCode.CSharp/Benchmarks/ReverseListBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/ReverseListBenchmark.cs @@ -1,14 +1,14 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class ReverseListBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(ReverseList))] - public void ReverseListSetup() => - ListNode1 = new ListNode(Enumerable.Range(1, 1_000_000).ToArray()); - - [Benchmark] - public ListNode? ReverseList() => Problem.ReverseList(ListNode1); - - [GlobalCleanup(Target = nameof(ReverseList))] - public void ReverseListCleanup() => ListNode1 = new ListNode(); -} +namespace LeetCode.CSharp.Benchmarks; + +public class ReverseListBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(ReverseList))] + public void ReverseListSetup() => + ListNode1 = new ListNode(Enumerable.Range(1, 1_000_000).ToArray()); + + [Benchmark] + public ListNode? ReverseList() => Problem.ReverseList(ListNode1); + + [GlobalCleanup(Target = nameof(ReverseList))] + public void ReverseListCleanup() => ListNode1 = new ListNode(); +} diff --git a/LeetCode.CSharp/Benchmarks/RomanToIntBenchmark.cs b/LeetCode.CSharp/Benchmarks/RomanToIntBenchmark.cs index 8283b07..80d0c88 100644 --- a/LeetCode.CSharp/Benchmarks/RomanToIntBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/RomanToIntBenchmark.cs @@ -1,8 +1,8 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class RomanToIntBenchmark : Benchmark -{ - [Benchmark] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public int RomanToInt() => Problem.RomanToInt("MMMCMXCIXCMXCIX"); +namespace LeetCode.CSharp.Benchmarks; + +public class RomanToIntBenchmark : Benchmark +{ + [Benchmark] + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public int RomanToInt() => Problem.RomanToInt("MMMCMXCIXCMXCIX"); } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/SingleNumberBenchmark.cs b/LeetCode.CSharp/Benchmarks/SingleNumberBenchmark.cs index d7f5fca..96ece15 100644 --- a/LeetCode.CSharp/Benchmarks/SingleNumberBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/SingleNumberBenchmark.cs @@ -1,15 +1,15 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class SingleNumberBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(SingleNumber))] - public void SingleNumberSetup() => - IntArray1 = [.. Enumerable.Range(1, 1_000_000) -, .. Enumerable.Range(1, 1_000_001)]; - - [Benchmark] - public int SingleNumber() => Problem.SingleNumber(IntArray1); - - [GlobalCleanup(Target = nameof(SingleNumber))] - public void SingleNumberCleanup() => IntArray1 = []; -} +namespace LeetCode.CSharp.Benchmarks; + +public class SingleNumberBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(SingleNumber))] + public void SingleNumberSetup() => + IntArray1 = [.. Enumerable.Range(1, 1_000_000) +, .. Enumerable.Range(1, 1_000_001)]; + + [Benchmark] + public int SingleNumber() => Problem.SingleNumber(IntArray1); + + [GlobalCleanup(Target = nameof(SingleNumber))] + public void SingleNumberCleanup() => IntArray1 = []; +} diff --git a/LeetCode.CSharp/Benchmarks/SubsetsBenchmark.cs b/LeetCode.CSharp/Benchmarks/SubsetsBenchmark.cs index 3d39751..9e7243f 100644 --- a/LeetCode.CSharp/Benchmarks/SubsetsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/SubsetsBenchmark.cs @@ -1,21 +1,21 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class SubsetsBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(Subsets))] - public void SubsetsSetup() - { - var random = new Random(42); - IntArray1 = new int[100_000]; - for (var i = 0; i < IntArray1.Length; i++) - { - IntArray1[i] = i % random.Next(1, 10); - } - } - - [Benchmark] - public IList> Subsets() => Problem.Subsets([1, 2, 3]); - - [GlobalCleanup(Target = nameof(Subsets))] - public void SubsetsCleanup() => IntArray1 = []; +namespace LeetCode.CSharp.Benchmarks; + +public class SubsetsBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(Subsets))] + public void SubsetsSetup() + { + var random = new Random(42); + IntArray1 = new int[100_000]; + for (var i = 0; i < IntArray1.Length; i++) + { + IntArray1[i] = i % random.Next(1, 10); + } + } + + [Benchmark] + public IList> Subsets() => Problem.Subsets([1, 2, 3]); + + [GlobalCleanup(Target = nameof(Subsets))] + public void SubsetsCleanup() => IntArray1 = []; } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/TopKFrequentBenchmark.cs b/LeetCode.CSharp/Benchmarks/TopKFrequentBenchmark.cs index 1f2a7d0..f0a8ff2 100644 --- a/LeetCode.CSharp/Benchmarks/TopKFrequentBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/TopKFrequentBenchmark.cs @@ -1,13 +1,13 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class TopKFrequentBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(TopKFrequent))] - public void TopKFrequentSetup() => IntArray1 = [.. Enumerable.Range(0, 100_000)]; - - [Benchmark] - public int[] TopKFrequent() => Problem.TopKFrequent(IntArray1, IntArray1.Length); - - [GlobalCleanup(Target = nameof(TopKFrequent))] - public void TopKFrequentCleanup() => IntArray1 = []; +namespace LeetCode.CSharp.Benchmarks; + +public class TopKFrequentBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(TopKFrequent))] + public void TopKFrequentSetup() => IntArray1 = [.. Enumerable.Range(0, 100_000)]; + + [Benchmark] + public int[] TopKFrequent() => Problem.TopKFrequent(IntArray1, IntArray1.Length); + + [GlobalCleanup(Target = nameof(TopKFrequent))] + public void TopKFrequentCleanup() => IntArray1 = []; } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/TrieBenchmark.cs b/LeetCode.CSharp/Benchmarks/TrieBenchmark.cs index e8c642e..00f5a64 100644 --- a/LeetCode.CSharp/Benchmarks/TrieBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/TrieBenchmark.cs @@ -1,27 +1,27 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class TrieBenchmark : Benchmark -{ - private readonly Problem.Trie _trie = new(); - - [GlobalSetup(Target = nameof(Trie))] - public void TrieSetup() - { - String1 = BuildPseudoRandomString(1_000_000, 2); - String2 = BuildPseudoRandomString(10); - } - - [Benchmark] - public bool Trie() - { - _trie.Insert(String1); - return _trie.Search(String2); - } - - [GlobalCleanup(Target = nameof(Trie))] - public void TrieCleanup() - { - String1 = string.Empty; - String2 = string.Empty; - } -} +namespace LeetCode.CSharp.Benchmarks; + +public class TrieBenchmark : Benchmark +{ + private readonly Problem.Trie _trie = new(); + + [GlobalSetup(Target = nameof(Trie))] + public void TrieSetup() + { + String1 = BuildPseudoRandomString(1_000_000, 2); + String2 = BuildPseudoRandomString(10); + } + + [Benchmark] + public bool Trie() + { + _trie.Insert(String1); + return _trie.Search(String2); + } + + [GlobalCleanup(Target = nameof(Trie))] + public void TrieCleanup() + { + String1 = string.Empty; + String2 = string.Empty; + } +} diff --git a/LeetCode.CSharp/Benchmarks/TwoSumBenchmark.cs b/LeetCode.CSharp/Benchmarks/TwoSumBenchmark.cs index b829ee3..8ab8b83 100644 --- a/LeetCode.CSharp/Benchmarks/TwoSumBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/TwoSumBenchmark.cs @@ -1,22 +1,22 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class TwoSumBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(TwoSum))] - public void TwoSumSetup() - { - IntArray1 = [.. Enumerable.Range(1, 10_000)]; - // Force full iteration by making target last two items in array - Int1 = IntArray1[^1] + IntArray1[^2]; - } - - [Benchmark] - public int[] TwoSum() => Problem.TwoSum(IntArray1, Int1); - - [GlobalCleanup(Target = nameof(TwoSum))] - public void TwoSumCleanup() - { - IntArray1 = []; - Int1 = 0; - } +namespace LeetCode.CSharp.Benchmarks; + +public class TwoSumBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(TwoSum))] + public void TwoSumSetup() + { + IntArray1 = [.. Enumerable.Range(1, 10_000)]; + // Force full iteration by making target last two items in array + Int1 = IntArray1[^1] + IntArray1[^2]; + } + + [Benchmark] + public int[] TwoSum() => Problem.TwoSum(IntArray1, Int1); + + [GlobalCleanup(Target = nameof(TwoSum))] + public void TwoSumCleanup() + { + IntArray1 = []; + Int1 = 0; + } } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/UniquePathsBenchmark.cs b/LeetCode.CSharp/Benchmarks/UniquePathsBenchmark.cs index a4549c3..7480c1b 100644 --- a/LeetCode.CSharp/Benchmarks/UniquePathsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/UniquePathsBenchmark.cs @@ -1,7 +1,7 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class UniquePathsBenchmark : Benchmark -{ - [Benchmark] - public int UniquePaths() => Problem.UniquePaths(10_000, 100); +namespace LeetCode.CSharp.Benchmarks; + +public class UniquePathsBenchmark : Benchmark +{ + [Benchmark] + public int UniquePaths() => Problem.UniquePaths(10_000, 100); } \ No newline at end of file diff --git a/LeetCode.CSharp/Benchmarks/ValidParenthesesBenchmark.cs b/LeetCode.CSharp/Benchmarks/ValidParenthesesBenchmark.cs index 9f6a160..b126cd6 100644 --- a/LeetCode.CSharp/Benchmarks/ValidParenthesesBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/ValidParenthesesBenchmark.cs @@ -1,28 +1,28 @@ -namespace LeetCode.CSharp.Benchmarks; - -public class ValidParenthesesBenchmark : Benchmark -{ - [GlobalSetup(Target = nameof(ValidParentheses))] - public void ValidParenthesesSetup() - { - Int1 = 10_000; - String1 = new StringBuilder() - .Append(new string('(', Int1)) - .Append(new string('[', Int1)) - .Append(new string('{', Int1)) - .Append(new string('}', Int1)) - .Append(new string(']', Int1)) - .Append(new string(')', Int1)) - .ToString(); - } - - [Benchmark] - public bool ValidParentheses() => Problem.ValidParentheses(String1); - - [GlobalCleanup(Target = nameof(ValidParentheses))] - public void ValidParenthesesCleanup() - { - Int1 = 0; - String1 = string.Empty; - } +namespace LeetCode.CSharp.Benchmarks; + +public class ValidParenthesesBenchmark : Benchmark +{ + [GlobalSetup(Target = nameof(ValidParentheses))] + public void ValidParenthesesSetup() + { + Int1 = 10_000; + String1 = new StringBuilder() + .Append(new string('(', Int1)) + .Append(new string('[', Int1)) + .Append(new string('{', Int1)) + .Append(new string('}', Int1)) + .Append(new string(']', Int1)) + .Append(new string(')', Int1)) + .ToString(); + } + + [Benchmark] + public bool ValidParentheses() => Problem.ValidParentheses(String1); + + [GlobalCleanup(Target = nameof(ValidParentheses))] + public void ValidParenthesesCleanup() + { + Int1 = 0; + String1 = string.Empty; + } } \ No newline at end of file diff --git a/LeetCode.CSharp/Category.cs b/LeetCode.CSharp/Category.cs index 92bc658..4eb424a 100644 --- a/LeetCode.CSharp/Category.cs +++ b/LeetCode.CSharp/Category.cs @@ -1,44 +1,44 @@ -namespace LeetCode.CSharp; - -/// NeetCode category -public enum Category -{ - /// Arrays & Hashing - ArraysAndHashing, - /// Two Pointers - TwoPointers, - /// Sliding Window - SlidingWindow, - /// Stack - Stack, - /// Binary Search - BinarySearch, - /// Linked List - LinkedList, - /// Trees - Trees, - /// Tries - Tries, - /// Heap / Priority Queue - HeapPriorityQueue, - /// Back Tracking - BackTracking, - /// Graphs - Graphs, - /// Advanced Graphs - AdvancedGraphs, - /// 1-D Dynamic Programming - OneDDynamicProgramming, - /// 2-D Dynamic Programming - TwoDDynamicProgramming, - /// Greedy - Greedy, - /// Intervals1 - Intervals, - /// Math and Geometry - MathAndGeometry, - /// Bit Manipulation - BitManipulation, - /// Not in NeetCode - NotInNeetCode -} +namespace LeetCode.CSharp; + +/// NeetCode category +public enum Category +{ + /// Arrays & Hashing + ArraysAndHashing, + /// Two Pointers + TwoPointers, + /// Sliding Window + SlidingWindow, + /// Stack + Stack, + /// Binary Search + BinarySearch, + /// Linked List + LinkedList, + /// Trees + Trees, + /// Tries + Tries, + /// Heap / Priority Queue + HeapPriorityQueue, + /// Back Tracking + BackTracking, + /// Graphs + Graphs, + /// Advanced Graphs + AdvancedGraphs, + /// 1-D Dynamic Programming + OneDDynamicProgramming, + /// 2-D Dynamic Programming + TwoDDynamicProgramming, + /// Greedy + Greedy, + /// Intervals1 + Intervals, + /// Math and Geometry + MathAndGeometry, + /// Bit Manipulation + BitManipulation, + /// Not in NeetCode + NotInNeetCode +} diff --git a/LeetCode.CSharp/Difficulty.cs b/LeetCode.CSharp/Difficulty.cs index 82f7612..8d884d8 100644 --- a/LeetCode.CSharp/Difficulty.cs +++ b/LeetCode.CSharp/Difficulty.cs @@ -1,13 +1,13 @@ -namespace LeetCode.CSharp; - -/// LeetCode difficulty -[SuppressMessage("ReSharper", "UnusedMember.Global")] -public enum Difficulty -{ - /// Easy - Easy, - /// Medium - Medium, - /// Hard - Hard -} +namespace LeetCode.CSharp; + +/// LeetCode difficulty +[SuppressMessage("ReSharper", "UnusedMember.Global")] +public enum Difficulty +{ + /// Easy + Easy, + /// Medium + Medium, + /// Hard + Hard +} diff --git a/LeetCode.CSharp/Interval.cs b/LeetCode.CSharp/Interval.cs index 0d72051..5ace68c 100644 --- a/LeetCode.CSharp/Interval.cs +++ b/LeetCode.CSharp/Interval.cs @@ -1,4 +1,4 @@ -namespace LeetCode.CSharp; - -// ReSharper disable InconsistentNaming -public readonly record struct Interval(int start, int end); +namespace LeetCode.CSharp; + +// ReSharper disable InconsistentNaming +public readonly record struct Interval(int start, int end); diff --git a/LeetCode.CSharp/LeetCode.CSharp.csproj b/LeetCode.CSharp/LeetCode.CSharp.csproj index 9bb829d..0aafb17 100644 --- a/LeetCode.CSharp/LeetCode.CSharp.csproj +++ b/LeetCode.CSharp/LeetCode.CSharp.csproj @@ -1,29 +1,29 @@ - - - - false - LeetCode.CSharp - - - - - - - - - - - - - - - - - - - - - - - - + + + + false + LeetCode.CSharp + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LeetCode.CSharp/LeetCodeAttribute.cs b/LeetCode.CSharp/LeetCodeAttribute.cs index 91b5898..d11b1db 100644 --- a/LeetCode.CSharp/LeetCodeAttribute.cs +++ b/LeetCode.CSharp/LeetCodeAttribute.cs @@ -1,29 +1,29 @@ -namespace LeetCode.CSharp; - -[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] -public sealed class LeetCodeAttribute : Attribute -{ - /// Challenge description - public string Description { get; } - - /// LeetCode difficulty - public Difficulty Difficulty { get; } - - /// NeetCode category - public Category Category { get; } - - /// Link to NeetCode video - public Uri? Link { get; } - - public LeetCodeAttribute( - string description, - Difficulty difficulty, - Category category, - string uri = "") - { - Description = description; - Difficulty = difficulty; - Category = category; - Link = string.IsNullOrEmpty(uri) ? null : new Uri($"{uri}", UriKind.Absolute); - } -} +namespace LeetCode.CSharp; + +[AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] +public sealed class LeetCodeAttribute : Attribute +{ + /// Challenge description + public string Description { get; } + + /// LeetCode difficulty + public Difficulty Difficulty { get; } + + /// NeetCode category + public Category Category { get; } + + /// Link to NeetCode video + public Uri? Link { get; } + + public LeetCodeAttribute( + string description, + Difficulty difficulty, + Category category, + string uri = "") + { + Description = description; + Difficulty = difficulty; + Category = category; + Link = string.IsNullOrEmpty(uri) ? null : new Uri($"{uri}", UriKind.Absolute); + } +} diff --git a/LeetCode.CSharp/ListNode.cs b/LeetCode.CSharp/ListNode.cs index e5b8910..a49fcc1 100644 --- a/LeetCode.CSharp/ListNode.cs +++ b/LeetCode.CSharp/ListNode.cs @@ -1,42 +1,42 @@ -namespace LeetCode.CSharp; - -[SuppressMessage("ReSharper", "InconsistentNaming")] -public class ListNode -{ - public readonly int val; - public ListNode? next; - - public ListNode(int val = 0, ListNode? next = null) - { - this.val = val; - this.next = next; - } - - public ListNode(IReadOnlyList list) - { - var lastNode = Deserialize(list); - - if (lastNode is null) - { - return; - } - - val = lastNode.val; - next = lastNode.next; - } - private static ListNode? Deserialize(IReadOnlyList list) - { - ListNode? lastNode = null; - - for (var i = list.Count - 1; i >= 0; i--) - { - var node = new ListNode(list[i]) - { - next = lastNode - }; - lastNode = node; - } - - return lastNode; - } -} +namespace LeetCode.CSharp; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +public class ListNode +{ + public readonly int val; + public ListNode? next; + + public ListNode(int val = 0, ListNode? next = null) + { + this.val = val; + this.next = next; + } + + public ListNode(IReadOnlyList list) + { + var lastNode = Deserialize(list); + + if (lastNode is null) + { + return; + } + + val = lastNode.val; + next = lastNode.next; + } + private static ListNode? Deserialize(IReadOnlyList list) + { + ListNode? lastNode = null; + + for (var i = list.Count - 1; i >= 0; i--) + { + var node = new ListNode(list[i]) + { + next = lastNode + }; + lastNode = node; + } + + return lastNode; + } +} diff --git a/LeetCode.CSharp/Problems/AddTwoNumbers.cs b/LeetCode.CSharp/Problems/AddTwoNumbers.cs index 2b79818..2a064d1 100644 --- a/LeetCode.CSharp/Problems/AddTwoNumbers.cs +++ b/LeetCode.CSharp/Problems/AddTwoNumbers.cs @@ -1,86 +1,86 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Add Two Numbers", - Difficulty.Easy, - Category.LinkedList, - "https://www.youtube.com/watch?v=wgFPrzTjm7s")] - public static ListNode AddTwoNumbers(ListNode l1, ListNode l2) - { - // Placeholder node to store result - var result = new ListNode(); - // Node to store sum of nodes - var answer = result; - var carry = 0; - - // Process until both nodes are fully evaluated - while (l1 is not null || l2 is not null) - { - var l1Val = 0; - if (l1 is not null) - { - l1Val = l1.val; - l1 = l1.next!; - } - var l2Val = 0; - if (l2 is not null) - { - l2Val = l2.val; - l2 = l2.next!; - } - var sum = l1Val + l2Val + carry; - carry = sum / 10; - // New node only stores first digit as carry is saved - var node = new ListNode(sum % 10); - // Update both current and next answer to new node - answer = answer.next = node; - } - - if (carry > 0) - { - answer.next = new ListNode(carry); - } - - // Answer is guaranteed to be non-null - return result.next!; - } - - [Theory] - [InlineData(new[] { 2, 4, 3 }, new[] { 5, 6, 4 }, new[] { 7, 0, 8 })] - [InlineData(new int[] { }, new int[] { }, new int[] { })] - [InlineData( - new[] { 9, 9, 9, 9, 9, 9, 9 }, - new[] { 9, 9, 9, 9 }, - new[] { 8, 9, 9, 9, 0, 0, 0, 1 })] - public void AddTwoNumbersTest(int[] list1, int[] list2, int[] expectedList) - { - var listNode1 = new ListNode(list1); - var listNode2 = new ListNode(list2); - var expectedNode = new ListNode(expectedList); - var result = AddTwoNumbers(listNode1, listNode2); - result.ShouldNotBeNull(); - AssertEqual(result, expectedNode); - - return; - - static void AssertEqual(ListNode? l1, ListNode? l2) - { - while (true) - { - if (l1 is null && l2 is null) - { - return; - } - if (l1 is null || l2 is null) - { - Assert.Fail("Either both nodes or neither node should be null"); - return; - } - l1.val.ShouldBe(l2.val); - l1 = l1.next; - l2 = l2.next; - } - } - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Add Two Numbers", + Difficulty.Easy, + Category.LinkedList, + "https://www.youtube.com/watch?v=wgFPrzTjm7s")] + public static ListNode AddTwoNumbers(ListNode l1, ListNode l2) + { + // Placeholder node to store result + var result = new ListNode(); + // Node to store sum of nodes + var answer = result; + var carry = 0; + + // Process until both nodes are fully evaluated + while (l1 is not null || l2 is not null) + { + var l1Val = 0; + if (l1 is not null) + { + l1Val = l1.val; + l1 = l1.next!; + } + var l2Val = 0; + if (l2 is not null) + { + l2Val = l2.val; + l2 = l2.next!; + } + var sum = l1Val + l2Val + carry; + carry = sum / 10; + // New node only stores first digit as carry is saved + var node = new ListNode(sum % 10); + // Update both current and next answer to new node + answer = answer.next = node; + } + + if (carry > 0) + { + answer.next = new ListNode(carry); + } + + // Answer is guaranteed to be non-null + return result.next!; + } + + [Theory] + [InlineData(new[] { 2, 4, 3 }, new[] { 5, 6, 4 }, new[] { 7, 0, 8 })] + [InlineData(new int[] { }, new int[] { }, new int[] { })] + [InlineData( + new[] { 9, 9, 9, 9, 9, 9, 9 }, + new[] { 9, 9, 9, 9 }, + new[] { 8, 9, 9, 9, 0, 0, 0, 1 })] + public void AddTwoNumbersTest(int[] list1, int[] list2, int[] expectedList) + { + var listNode1 = new ListNode(list1); + var listNode2 = new ListNode(list2); + var expectedNode = new ListNode(expectedList); + var result = AddTwoNumbers(listNode1, listNode2); + result.ShouldNotBeNull(); + AssertEqual(result, expectedNode); + + return; + + static void AssertEqual(ListNode? l1, ListNode? l2) + { + while (true) + { + if (l1 is null && l2 is null) + { + return; + } + if (l1 is null || l2 is null) + { + Assert.Fail("Either both nodes or neither node should be null"); + return; + } + l1.val.ShouldBe(l2.val); + l1 = l1.next; + l2 = l2.next; + } + } + } +} diff --git a/LeetCode.CSharp/Problems/BinarySearch.cs b/LeetCode.CSharp/Problems/BinarySearch.cs index 12f9b9e..1c068fa 100644 --- a/LeetCode.CSharp/Problems/BinarySearch.cs +++ b/LeetCode.CSharp/Problems/BinarySearch.cs @@ -1,44 +1,44 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Binary Search", - Difficulty.Easy, - Category.BinarySearch, - "https://www.youtube.com/watch?v=s4DPM8ct1pI")] - public static int BinarySearch(int[] nums, int target) - { - var leftPtr = 0; - var rightPtr = nums.Length - 1; - - while (leftPtr <= rightPtr) - { - // Find mid-point without risk of overflowing - var midPtr = leftPtr + (rightPtr - leftPtr) / 2; - var midVal = nums[midPtr]; - - if (midVal > target) - { - rightPtr = midPtr - 1; - } - else if (midVal < target) - { - leftPtr = midPtr + 1; - } - else - { - return midPtr; - } - } - - // Target not found - return -1; - } - - [Theory] - [InlineData(new[] { -1, 0, 3, 5, 9, 12 }, 9, 4)] - [InlineData(new[] { -1, 0, 3, 5, 9, 12 }, 2, -1)] - [InlineData(new int[] { }, 0, -1)] - public void BinarySearchTest(int[] nums, int target, int expected) => - BinarySearch(nums, target).ShouldBe(expected); -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Binary Search", + Difficulty.Easy, + Category.BinarySearch, + "https://www.youtube.com/watch?v=s4DPM8ct1pI")] + public static int BinarySearch(int[] nums, int target) + { + var leftPtr = 0; + var rightPtr = nums.Length - 1; + + while (leftPtr <= rightPtr) + { + // Find mid-point without risk of overflowing + var midPtr = leftPtr + (rightPtr - leftPtr) / 2; + var midVal = nums[midPtr]; + + if (midVal > target) + { + rightPtr = midPtr - 1; + } + else if (midVal < target) + { + leftPtr = midPtr + 1; + } + else + { + return midPtr; + } + } + + // Target not found + return -1; + } + + [Theory] + [InlineData(new[] { -1, 0, 3, 5, 9, 12 }, 9, 4)] + [InlineData(new[] { -1, 0, 3, 5, 9, 12 }, 2, -1)] + [InlineData(new int[] { }, 0, -1)] + public void BinarySearchTest(int[] nums, int target, int expected) => + BinarySearch(nums, target).ShouldBe(expected); +} diff --git a/LeetCode.CSharp/Problems/CanAttendMeetings.cs b/LeetCode.CSharp/Problems/CanAttendMeetings.cs index 88ce3bf..00c1687 100644 --- a/LeetCode.CSharp/Problems/CanAttendMeetings.cs +++ b/LeetCode.CSharp/Problems/CanAttendMeetings.cs @@ -1,46 +1,46 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Can Attend Meetings", - Difficulty.Easy, - Category.Intervals, - "https://www.youtube.com/watch?v=PaJxqZVPhbg")] - // ReSharper disable once ParameterTypeCanBeEnumerable.Global - public static bool CanAttendMeetings(List intervals) - { - var sortedIntervals = intervals.OrderBy(i => i.start).ToArray(); - - for (var i = 1; i < sortedIntervals.Length;) - { - var previousInterval = sortedIntervals[i - 1]; - var currentInterval = sortedIntervals[i++]; - - if (currentInterval.start < previousInterval.end) - { - return false; - } - } - - return true; - } - - [Fact] - public void CanAttendMeetingsTest() - { - var ex1 = new List - { - new(0, 30), - new(5, 10), - new(15, 20) - }; - var ex2 = new List - { - new(5, 8), - new(9, 15) - }; - - CanAttendMeetings(ex1).ShouldBeFalse(); - CanAttendMeetings(ex2).ShouldBeTrue(); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Can Attend Meetings", + Difficulty.Easy, + Category.Intervals, + "https://www.youtube.com/watch?v=PaJxqZVPhbg")] + // ReSharper disable once ParameterTypeCanBeEnumerable.Global + public static bool CanAttendMeetings(List intervals) + { + var sortedIntervals = intervals.OrderBy(i => i.start).ToArray(); + + for (var i = 1; i < sortedIntervals.Length;) + { + var previousInterval = sortedIntervals[i - 1]; + var currentInterval = sortedIntervals[i++]; + + if (currentInterval.start < previousInterval.end) + { + return false; + } + } + + return true; + } + + [Fact] + public void CanAttendMeetingsTest() + { + var ex1 = new List + { + new(0, 30), + new(5, 10), + new(15, 20) + }; + var ex2 = new List + { + new(5, 8), + new(9, 15) + }; + + CanAttendMeetings(ex1).ShouldBeFalse(); + CanAttendMeetings(ex2).ShouldBeTrue(); + } +} diff --git a/LeetCode.CSharp/Problems/ClimbStairs.cs b/LeetCode.CSharp/Problems/ClimbStairs.cs index 202b827..de2d425 100644 --- a/LeetCode.CSharp/Problems/ClimbStairs.cs +++ b/LeetCode.CSharp/Problems/ClimbStairs.cs @@ -1,31 +1,31 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Climbing Stairs", - Difficulty.Easy, - Category.OneDDynamicProgramming, - "https://www.youtube.com/watch?v=Y0lT9Fck7qI")] - public static int ClimbStairs(int n) - { - // End of decision tree always has one step as two steps would be out of bounds - var oneStep = 1; - var twoStep = 1; - - // Start from the top of the stairs and work backwards to solve each sub-problem - for (var i = 0; i < n - 1; i++) - { - // Memoize result to avoid recalculation - var previousStep = oneStep; - oneStep += twoStep; - twoStep = previousStep; - } - - return oneStep; - } - - [Theory] - [InlineData(2, 2)] - [InlineData(3, 3)] - public void ClimbStairsTest(int n, int expected) => ClimbStairs(n).ShouldBe(expected); -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Climbing Stairs", + Difficulty.Easy, + Category.OneDDynamicProgramming, + "https://www.youtube.com/watch?v=Y0lT9Fck7qI")] + public static int ClimbStairs(int n) + { + // End of decision tree always has one step as two steps would be out of bounds + var oneStep = 1; + var twoStep = 1; + + // Start from the top of the stairs and work backwards to solve each sub-problem + for (var i = 0; i < n - 1; i++) + { + // Memoize result to avoid recalculation + var previousStep = oneStep; + oneStep += twoStep; + twoStep = previousStep; + } + + return oneStep; + } + + [Theory] + [InlineData(2, 2)] + [InlineData(3, 3)] + public void ClimbStairsTest(int n, int expected) => ClimbStairs(n).ShouldBe(expected); +} diff --git a/LeetCode.CSharp/Problems/ContainsDuplicate.cs b/LeetCode.CSharp/Problems/ContainsDuplicate.cs index 061e977..1408b9a 100644 --- a/LeetCode.CSharp/Problems/ContainsDuplicate.cs +++ b/LeetCode.CSharp/Problems/ContainsDuplicate.cs @@ -1,23 +1,23 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Contains Duplicate", - Difficulty.Easy, - Category.ArraysAndHashing, - "https://www.youtube.com/watch?v=3OamzN90kPg")] - [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] - public static bool ContainsDuplicate(int[] nums) - { - var set = new HashSet(); - - return nums.Any(num => !set.Add(num)); - } - - [Theory] - [InlineData(new[] { 1, 2, 3, 1 }, true)] - [InlineData(new[] { 1, 2, 3, 4 }, false)] - [InlineData(new[] { 1, 1, 1, 3, 3, 4, 3, 2, 4, 2 }, true)] - public void ContainsDuplicateTest(int[] nums, bool expected) => - ContainsDuplicate(nums).ShouldBe(expected); -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Contains Duplicate", + Difficulty.Easy, + Category.ArraysAndHashing, + "https://www.youtube.com/watch?v=3OamzN90kPg")] + [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] + public static bool ContainsDuplicate(int[] nums) + { + var set = new HashSet(); + + return nums.Any(num => !set.Add(num)); + } + + [Theory] + [InlineData(new[] { 1, 2, 3, 1 }, true)] + [InlineData(new[] { 1, 2, 3, 4 }, false)] + [InlineData(new[] { 1, 1, 1, 3, 3, 4, 3, 2, 4, 2 }, true)] + public void ContainsDuplicateTest(int[] nums, bool expected) => + ContainsDuplicate(nums).ShouldBe(expected); +} diff --git a/LeetCode.CSharp/Problems/CountBits.cs b/LeetCode.CSharp/Problems/CountBits.cs index 0f34c34..21afa5e 100644 --- a/LeetCode.CSharp/Problems/CountBits.cs +++ b/LeetCode.CSharp/Problems/CountBits.cs @@ -1,33 +1,33 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Counting Bits", - Difficulty.Easy, - Category.BitManipulation, - "https://www.youtube.com/watch?v=RyBM56RIWrM")] - [SuppressMessage("ReSharper", "ReturnTypeCanBeEnumerable.Global")] - public static int[] CountBits(int n) - { - var result = new int[n + 1]; - var offset = 1; - - for (var i = 1; i <= n; i++) - { - if (offset * 2 == i) - { - // i is power of two, meaning a new most significant bit - offset = i; - } - - result[i] = 1 + result[i - offset]; - } - - return result; - } - - [Theory] - [InlineData(2, new[] { 0, 1, 1 })] - [InlineData(5, new[] { 0, 1, 1, 2, 1, 2 })] - public void CountBitsTest(int n, int[] expected) => CountBits(n).ShouldBe(expected); -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Counting Bits", + Difficulty.Easy, + Category.BitManipulation, + "https://www.youtube.com/watch?v=RyBM56RIWrM")] + [SuppressMessage("ReSharper", "ReturnTypeCanBeEnumerable.Global")] + public static int[] CountBits(int n) + { + var result = new int[n + 1]; + var offset = 1; + + for (var i = 1; i <= n; i++) + { + if (offset * 2 == i) + { + // i is power of two, meaning a new most significant bit + offset = i; + } + + result[i] = 1 + result[i - offset]; + } + + return result; + } + + [Theory] + [InlineData(2, new[] { 0, 1, 1 })] + [InlineData(5, new[] { 0, 1, 1, 2, 1, 2 })] + public void CountBitsTest(int n, int[] expected) => CountBits(n).ShouldBe(expected); +} diff --git a/LeetCode.CSharp/Problems/DiameterOfBinaryTree.cs b/LeetCode.CSharp/Problems/DiameterOfBinaryTree.cs index b817d3c..42cdd14 100644 --- a/LeetCode.CSharp/Problems/DiameterOfBinaryTree.cs +++ b/LeetCode.CSharp/Problems/DiameterOfBinaryTree.cs @@ -1,48 +1,48 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Diameter of Binary Tree", - Difficulty.Easy, - Category.Trees, - "https://www.youtube.com/watch?v=bkxqA8Rfv04")] - public static int DiameterOfBinaryTree(TreeNode root) - { - var maxDiameter = 0; - - DepthFirstSearch(root); - - return maxDiameter; - - // Calculates height and stores maximum diameter - int DepthFirstSearch(TreeNode? node) - { - if (node is null) - { - return 0; - } - - var left = DepthFirstSearch(node.left); - var right = DepthFirstSearch(node.right); - - maxDiameter = Math.Max(left + right, maxDiameter); - - // Add 1 to include current node's height - return Math.Max(left, right) + 1; - } - } - - [Fact] - public void DiameterOfBinaryTreeTest() - { - var root1 = new TreeNode(1, - left: new TreeNode(2, - left: new TreeNode(4), right: new TreeNode(5)), - right: new TreeNode(3)); - var root2 = new TreeNode(1, left: new TreeNode(2)); - - DiameterOfBinaryTree(new TreeNode()).ShouldBe(0); - DiameterOfBinaryTree(root1).ShouldBe(3); - DiameterOfBinaryTree(root2).ShouldBe(1); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Diameter of Binary Tree", + Difficulty.Easy, + Category.Trees, + "https://www.youtube.com/watch?v=bkxqA8Rfv04")] + public static int DiameterOfBinaryTree(TreeNode root) + { + var maxDiameter = 0; + + DepthFirstSearch(root); + + return maxDiameter; + + // Calculates height and stores maximum diameter + int DepthFirstSearch(TreeNode? node) + { + if (node is null) + { + return 0; + } + + var left = DepthFirstSearch(node.left); + var right = DepthFirstSearch(node.right); + + maxDiameter = Math.Max(left + right, maxDiameter); + + // Add 1 to include current node's height + return Math.Max(left, right) + 1; + } + } + + [Fact] + public void DiameterOfBinaryTreeTest() + { + var root1 = new TreeNode(1, + left: new TreeNode(2, + left: new TreeNode(4), right: new TreeNode(5)), + right: new TreeNode(3)); + var root2 = new TreeNode(1, left: new TreeNode(2)); + + DiameterOfBinaryTree(new TreeNode()).ShouldBe(0); + DiameterOfBinaryTree(root1).ShouldBe(3); + DiameterOfBinaryTree(root2).ShouldBe(1); + } +} diff --git a/LeetCode.CSharp/Problems/EncodeDecode.cs b/LeetCode.CSharp/Problems/EncodeDecode.cs index 4efdd4a..d0c3c9e 100644 --- a/LeetCode.CSharp/Problems/EncodeDecode.cs +++ b/LeetCode.CSharp/Problems/EncodeDecode.cs @@ -1,62 +1,62 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - private const char EncodeDecodeDelimiter = ':'; - - [LeetCode("Encode and Decode Strings (Encode)", - Difficulty.Medium, - Category.ArraysAndHashing, - "https://www.youtube.com/watch?v=B1k_sxOSgv8")] - public static string Encode(IEnumerable strs) => - string.Concat(strs.SelectMany(s => $"{s.Length}{EncodeDecodeDelimiter}{s}")); - - [LeetCode("Encode and Decode Strings (Decode)", - Difficulty.Medium, - Category.ArraysAndHashing, - "https://www.youtube.com/watch?v=B1k_sxOSgv8")] - public static IEnumerable Decode(string str) - { - var result = new List(); - var i = 0; - - while (i < str.Length) - { - var j = i; - - // Find length of encoded string - while (str[j] != EncodeDecodeDelimiter) - { - j++; - } - - // Assumes string is correctly encoded - var length = int.Parse(str.AsSpan(i, j - i)); - - // Move past delimiter - j++; - - // Extract substring - result.Add(str.AsSpan(j, length).ToString()); - - // Move to next encoded string or end - i = j + length; - } - - return result; - } - - [Theory] - [InlineData(new string[] { }, "")] - [InlineData(new[] { "" }, "0:")] - [InlineData(new[] { "abc" }, "3:abc")] - [InlineData(new[] { "abc", "c : a" }, "3:abc5:c : a")] - public void EncodeTest(string[] strs, string expected) => Encode(strs).ShouldBe(expected); - - [Theory] - [InlineData("", new string[] { })] - [InlineData("0:", new[] { "" })] - [InlineData("3:abc", new[] { "abc" })] - [InlineData("3:abc5:c : a", new[] { "abc", "c : a" })] - public void DecodeTest(string str, string[] expected) => Decode(str).ShouldBe(expected); -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + private const char EncodeDecodeDelimiter = ':'; + + [LeetCode("Encode and Decode Strings (Encode)", + Difficulty.Medium, + Category.ArraysAndHashing, + "https://www.youtube.com/watch?v=B1k_sxOSgv8")] + public static string Encode(IEnumerable strs) => + string.Concat(strs.SelectMany(s => $"{s.Length}{EncodeDecodeDelimiter}{s}")); + + [LeetCode("Encode and Decode Strings (Decode)", + Difficulty.Medium, + Category.ArraysAndHashing, + "https://www.youtube.com/watch?v=B1k_sxOSgv8")] + public static IEnumerable Decode(string str) + { + var result = new List(); + var i = 0; + + while (i < str.Length) + { + var j = i; + + // Find length of encoded string + while (str[j] != EncodeDecodeDelimiter) + { + j++; + } + + // Assumes string is correctly encoded + var length = int.Parse(str.AsSpan(i, j - i)); + + // Move past delimiter + j++; + + // Extract substring + result.Add(str.AsSpan(j, length).ToString()); + + // Move to next encoded string or end + i = j + length; + } + + return result; + } + + [Theory] + [InlineData(new string[] { }, "")] + [InlineData(new[] { "" }, "0:")] + [InlineData(new[] { "abc" }, "3:abc")] + [InlineData(new[] { "abc", "c : a" }, "3:abc5:c : a")] + public void EncodeTest(string[] strs, string expected) => Encode(strs).ShouldBe(expected); + + [Theory] + [InlineData("", new string[] { })] + [InlineData("0:", new[] { "" })] + [InlineData("3:abc", new[] { "abc" })] + [InlineData("3:abc5:c : a", new[] { "abc", "c : a" })] + public void DecodeTest(string str, string[] expected) => Decode(str).ShouldBe(expected); +} diff --git a/LeetCode.CSharp/Problems/FindMedianSortedArrays.cs b/LeetCode.CSharp/Problems/FindMedianSortedArrays.cs index 780ece1..6989563 100644 --- a/LeetCode.CSharp/Problems/FindMedianSortedArrays.cs +++ b/LeetCode.CSharp/Problems/FindMedianSortedArrays.cs @@ -1,22 +1,22 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - // TODO: Waiting until other easy and medium binary search submissions - //[LeetCode("Median of Two Sorted Arrays", Difficulty.Hard, Category.BinarySearch)] - //public static double FindMedianSortedArrays(int[] nums1, int[] nums2) - //{ - // return 0; - //} - - //[Fact] - //public void FindMedianSortedArraysTest() - //{ - // var ex1nums1 = new[] { 1, 3 }; - // var ex1nums2 = new[] { 2 }; - // var ex2nums1 = new[] { 1, 2 }; - // var ex2nums2 = new[] { 3, 4 }; - // FindMedianSortedArrays(ex1nums1, ex1nums2).ShouldBe(2d); - // FindMedianSortedArrays(ex2nums1, ex2nums2).ShouldBe(2.5d); - //} -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + // TODO: Waiting until other easy and medium binary search submissions + //[LeetCode("Median of Two Sorted Arrays", Difficulty.Hard, Category.BinarySearch)] + //public static double FindMedianSortedArrays(int[] nums1, int[] nums2) + //{ + // return 0; + //} + + //[Fact] + //public void FindMedianSortedArraysTest() + //{ + // var ex1nums1 = new[] { 1, 3 }; + // var ex1nums2 = new[] { 2 }; + // var ex2nums1 = new[] { 1, 2 }; + // var ex2nums2 = new[] { 3, 4 }; + // FindMedianSortedArrays(ex1nums1, ex1nums2).ShouldBe(2d); + // FindMedianSortedArrays(ex2nums1, ex2nums2).ShouldBe(2.5d); + //} +} diff --git a/LeetCode.CSharp/Problems/FizzBuzz.cs b/LeetCode.CSharp/Problems/FizzBuzz.cs index c2fa5d3..8893e34 100644 --- a/LeetCode.CSharp/Problems/FizzBuzz.cs +++ b/LeetCode.CSharp/Problems/FizzBuzz.cs @@ -1,46 +1,46 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Fizz Buzz", Difficulty.Easy, Category.NotInNeetCode)] - public static IList FizzBuzz(int n) - { - var result = new List(); - - for (var i = 1; i <= n; i++) - { - var value = string.Empty; - - if (i % 3 == 0) - { - value = "Fizz"; - } - - if (i % 5 == 0) - { - value += "Buzz"; - } - - if (string.IsNullOrEmpty(value)) - { - value = i.ToString(); - } - - result.Add(value); - } - - return result; - } - - [Fact] - public void FizzBuzzTest() - { - var output1 = new List { "1", "2", "Fizz" }; - var output2 = new List { "1", "2", "Fizz", "4", "Buzz" }; - var output3 = new List { "1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz" }; - - FizzBuzz(3).ShouldBe(output1); - FizzBuzz(5).ShouldBe(output2); - FizzBuzz(15).ShouldBe(output3); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Fizz Buzz", Difficulty.Easy, Category.NotInNeetCode)] + public static IList FizzBuzz(int n) + { + var result = new List(); + + for (var i = 1; i <= n; i++) + { + var value = string.Empty; + + if (i % 3 == 0) + { + value = "Fizz"; + } + + if (i % 5 == 0) + { + value += "Buzz"; + } + + if (string.IsNullOrEmpty(value)) + { + value = i.ToString(); + } + + result.Add(value); + } + + return result; + } + + [Fact] + public void FizzBuzzTest() + { + var output1 = new List { "1", "2", "Fizz" }; + var output2 = new List { "1", "2", "Fizz", "4", "Buzz" }; + var output3 = new List { "1", "2", "Fizz", "4", "Buzz", "Fizz", "7", "8", "Fizz", "Buzz", "11", "Fizz", "13", "14", "FizzBuzz" }; + + FizzBuzz(3).ShouldBe(output1); + FizzBuzz(5).ShouldBe(output2); + FizzBuzz(15).ShouldBe(output3); + } +} diff --git a/LeetCode.CSharp/Problems/GroupAnagrams.cs b/LeetCode.CSharp/Problems/GroupAnagrams.cs index 2b693fd..c50acec 100644 --- a/LeetCode.CSharp/Problems/GroupAnagrams.cs +++ b/LeetCode.CSharp/Problems/GroupAnagrams.cs @@ -1,80 +1,80 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Group Anagrams", - Difficulty.Medium, - Category.ArraysAndHashing, - "https://www.youtube.com/watch?v=vzdNOK2oB2E")] - [SuppressMessage("ReSharper", "ReturnTypeCanBeEnumerable.Global")] - [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] - public static IList> GroupAnagrams(string[] strs) - { - var dictionary = new Dictionary>(); - - foreach (var str in strs) - { - var hash = new char[26]; - - foreach (var c in str) - { - hash[c - 'a']++; - } - - var key = new string(hash); - - if (dictionary.TryGetValue(key, out var list)) - { - list.Add(str); - } - else - { - dictionary.Add(key, [str]); - } - } - - return [.. dictionary.Values]; - } - - [Fact] - public void GroupAnagramsTest() - { - var ex1 = new[] { "eat", "tea", "tan", "ate", "nat", "bat" }; - var ex1Expected = new List> - { - new() { "eat", "tea", "ate" }, - new() { "tan", "nat" }, - new() { "bat" } - }; - var ex2 = new[] { "" }; - var ex2Expected = new List> { new() { "" } }; - var ex3 = new[] { "a" }; - var ex3Expected = new List> { new() { "a" } }; - var ex4 = new[] { "cab", "tin", "pew", "duh", "may", "ill", "buy", "bar", "max", "doc" }; - var ex4Expected = new List> - { - new() { "cab" }, - new() { "tin" }, - new() { "pew" }, - new() { "duh" }, - new() { "may" }, - new() { "ill" }, - new() { "buy" }, - new() { "bar" }, - new() { "max" }, - new() { "doc" } - }; - - // ReSharper disable once CollectionNeverQueried.Local - var strs = new string[100_000]; - for (var i = 0; i < strs.Length; i++) - { - strs[i] = Benchmark.BuildPseudoRandomString(Benchmark.Random.Next(100)); - } - - GroupAnagrams(ex1).ShouldBe(ex1Expected); - GroupAnagrams(ex2).ShouldBe(ex2Expected); - GroupAnagrams(ex3).ShouldBe(ex3Expected); - GroupAnagrams(ex4).ShouldBe(ex4Expected); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Group Anagrams", + Difficulty.Medium, + Category.ArraysAndHashing, + "https://www.youtube.com/watch?v=vzdNOK2oB2E")] + [SuppressMessage("ReSharper", "ReturnTypeCanBeEnumerable.Global")] + [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] + public static IList> GroupAnagrams(string[] strs) + { + var dictionary = new Dictionary>(); + + foreach (var str in strs) + { + var hash = new char[26]; + + foreach (var c in str) + { + hash[c - 'a']++; + } + + var key = new string(hash); + + if (dictionary.TryGetValue(key, out var list)) + { + list.Add(str); + } + else + { + dictionary.Add(key, [str]); + } + } + + return [.. dictionary.Values]; + } + + [Fact] + public void GroupAnagramsTest() + { + var ex1 = new[] { "eat", "tea", "tan", "ate", "nat", "bat" }; + var ex1Expected = new List> + { + new() { "eat", "tea", "ate" }, + new() { "tan", "nat" }, + new() { "bat" } + }; + var ex2 = new[] { "" }; + var ex2Expected = new List> { new() { "" } }; + var ex3 = new[] { "a" }; + var ex3Expected = new List> { new() { "a" } }; + var ex4 = new[] { "cab", "tin", "pew", "duh", "may", "ill", "buy", "bar", "max", "doc" }; + var ex4Expected = new List> + { + new() { "cab" }, + new() { "tin" }, + new() { "pew" }, + new() { "duh" }, + new() { "may" }, + new() { "ill" }, + new() { "buy" }, + new() { "bar" }, + new() { "max" }, + new() { "doc" } + }; + + // ReSharper disable once CollectionNeverQueried.Local + var strs = new string[100_000]; + for (var i = 0; i < strs.Length; i++) + { + strs[i] = Benchmark.BuildPseudoRandomString(Benchmark.Random.Next(100)); + } + + GroupAnagrams(ex1).ShouldBe(ex1Expected); + GroupAnagrams(ex2).ShouldBe(ex2Expected); + GroupAnagrams(ex3).ShouldBe(ex3Expected); + GroupAnagrams(ex4).ShouldBe(ex4Expected); + } +} diff --git a/LeetCode.CSharp/Problems/HammingWeight.cs b/LeetCode.CSharp/Problems/HammingWeight.cs index 0219044..14c06ed 100644 --- a/LeetCode.CSharp/Problems/HammingWeight.cs +++ b/LeetCode.CSharp/Problems/HammingWeight.cs @@ -1,31 +1,31 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Number of 1 Bits", - Difficulty.Easy, - Category.BitManipulation, - "https://www.youtube.com/watch?v=5Km3utixwZs")] - public static int HammingWeight(uint n) - { - // return System.Numerics.BitOperations.PopCount(n); - - var count = (uint)0; - - while (n != 0) - { - count += n % 2; - n >>= 1; - } - - return (int)count; - } - - [Fact] - public void HammingWeightTest() - { - HammingWeight(0b00000000000000000000000000001011).ShouldBe(3); - HammingWeight(0b00000000000000000000000010000000).ShouldBe(1); - HammingWeight(0b11111111111111111111111111111101).ShouldBe(31); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Number of 1 Bits", + Difficulty.Easy, + Category.BitManipulation, + "https://www.youtube.com/watch?v=5Km3utixwZs")] + public static int HammingWeight(uint n) + { + // return System.Numerics.BitOperations.PopCount(n); + + var count = (uint)0; + + while (n != 0) + { + count += n % 2; + n >>= 1; + } + + return (int)count; + } + + [Fact] + public void HammingWeightTest() + { + HammingWeight(0b00000000000000000000000000001011).ShouldBe(3); + HammingWeight(0b00000000000000000000000010000000).ShouldBe(1); + HammingWeight(0b11111111111111111111111111111101).ShouldBe(31); + } +} diff --git a/LeetCode.CSharp/Problems/Insert.cs b/LeetCode.CSharp/Problems/Insert.cs index 5bf1731..5c0358c 100644 --- a/LeetCode.CSharp/Problems/Insert.cs +++ b/LeetCode.CSharp/Problems/Insert.cs @@ -1,86 +1,86 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Insert Interval", - Difficulty.Medium, - Category.Intervals, - "https://www.youtube.com/watch?v=A8NUOmlwOlM")] - public static int[][] Insert(int[][] intervals, int[] newInterval) - { - var result = new List(); - - for (var i = 0; i < intervals.Length; i++) - { - var intervalStart = intervals[i][0]; - var newIntervalEnd = newInterval[1]; - - if (newIntervalEnd < intervalStart) - { - result.Add(newInterval); - result.AddRange(intervals[i..]); - - // Best case of non-overlapping new interval ends before intervals start - return [.. result]; - } - - var intervalEnd = intervals[i][1]; - var newIntervalStart = newInterval[0]; - - if (newIntervalStart > intervalEnd) - { - // New interval is non-overlapping with current interval - result.Add(intervals[i]); - } - else - { - // New interval is overlapping so merge with current interval - newInterval = - [ - Math.Min(intervalStart, newIntervalStart), - Math.Max(intervalEnd, newIntervalEnd) - ]; - } - } - - // New interval must be the last interval in list - result.Add(newInterval); - - return [.. result]; - } - - [Fact] - public void InsertTest() - { - var ex1Intervals = new[] - { - new[] { 1, 3 }, - new[] { 6, 9 } - }; - var ex1NewInterval = new[] { 2, 5 }; - var ex1Expected = new[] - { - new[] { 1, 5 }, - new[] { 6, 9 } - }; - - var ex2Intervals = new[] - { - new[] { 1, 2 }, - new[] { 3, 5 }, - new[] { 6, 7 }, - new[] { 8, 10 }, - new[] { 12, 16 } - }; - var ex2NewInterval = new[] { 4, 8 }; - var ex2Expected = new[] - { - new[] { 1, 2 }, - new[] { 3, 10 }, - new[] { 12, 16 } - }; - - Insert(ex1Intervals, ex1NewInterval).ShouldBe(ex1Expected); - Insert(ex2Intervals, ex2NewInterval).ShouldBe(ex2Expected); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Insert Interval", + Difficulty.Medium, + Category.Intervals, + "https://www.youtube.com/watch?v=A8NUOmlwOlM")] + public static int[][] Insert(int[][] intervals, int[] newInterval) + { + var result = new List(); + + for (var i = 0; i < intervals.Length; i++) + { + var intervalStart = intervals[i][0]; + var newIntervalEnd = newInterval[1]; + + if (newIntervalEnd < intervalStart) + { + result.Add(newInterval); + result.AddRange(intervals[i..]); + + // Best case of non-overlapping new interval ends before intervals start + return [.. result]; + } + + var intervalEnd = intervals[i][1]; + var newIntervalStart = newInterval[0]; + + if (newIntervalStart > intervalEnd) + { + // New interval is non-overlapping with current interval + result.Add(intervals[i]); + } + else + { + // New interval is overlapping so merge with current interval + newInterval = + [ + Math.Min(intervalStart, newIntervalStart), + Math.Max(intervalEnd, newIntervalEnd) + ]; + } + } + + // New interval must be the last interval in list + result.Add(newInterval); + + return [.. result]; + } + + [Fact] + public void InsertTest() + { + var ex1Intervals = new[] + { + new[] { 1, 3 }, + new[] { 6, 9 } + }; + var ex1NewInterval = new[] { 2, 5 }; + var ex1Expected = new[] + { + new[] { 1, 5 }, + new[] { 6, 9 } + }; + + var ex2Intervals = new[] + { + new[] { 1, 2 }, + new[] { 3, 5 }, + new[] { 6, 7 }, + new[] { 8, 10 }, + new[] { 12, 16 } + }; + var ex2NewInterval = new[] { 4, 8 }; + var ex2Expected = new[] + { + new[] { 1, 2 }, + new[] { 3, 10 }, + new[] { 12, 16 } + }; + + Insert(ex1Intervals, ex1NewInterval).ShouldBe(ex1Expected); + Insert(ex2Intervals, ex2NewInterval).ShouldBe(ex2Expected); + } +} diff --git a/LeetCode.CSharp/Problems/InvertTree.cs b/LeetCode.CSharp/Problems/InvertTree.cs index f8d5c2f..d4d6045 100644 --- a/LeetCode.CSharp/Problems/InvertTree.cs +++ b/LeetCode.CSharp/Problems/InvertTree.cs @@ -1,47 +1,47 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Invert Binary Tree", - Difficulty.Easy, - Category.Trees, - "https://www.youtube.com/watch?v=OnSn2XEQ4MY")] - public static TreeNode? InvertTree(TreeNode? root) - { - if (root is null) - { - return null; - } - - (root.left, root.right) = (root.right, root.left); - - if (root.left is not null) - { - InvertTree(root.left); - } - if (root.right is not null) - { - InvertTree(root.right); - } - - return root; - } - - [Fact] - public void InvertTreeTest() - { - var root1 = new TreeNode(4, - left: new TreeNode(2, left: new TreeNode(1), right: new TreeNode(3)), - right: new TreeNode(7, left: new TreeNode(6), right: new TreeNode(9))); - var exp1 = new TreeNode(4, - left: new TreeNode(7, left: new TreeNode(9), right: new TreeNode(6)), - right: new TreeNode(2, left: new TreeNode(3), right: new TreeNode(1))); - var root2 = new TreeNode(2, left: new TreeNode(1), right: new TreeNode(3)); - var exp2 = new TreeNode(2, left: new TreeNode(3), right: new TreeNode(1)); - - InvertTree(root1).ShouldBeEquivalentTo(exp1); - InvertTree(root2).ShouldBeEquivalentTo(exp2); - InvertTree(new TreeNode()).ShouldBeEquivalentTo(new TreeNode()); - InvertTree(null).ShouldBeNull(); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Invert Binary Tree", + Difficulty.Easy, + Category.Trees, + "https://www.youtube.com/watch?v=OnSn2XEQ4MY")] + public static TreeNode? InvertTree(TreeNode? root) + { + if (root is null) + { + return null; + } + + (root.left, root.right) = (root.right, root.left); + + if (root.left is not null) + { + InvertTree(root.left); + } + if (root.right is not null) + { + InvertTree(root.right); + } + + return root; + } + + [Fact] + public void InvertTreeTest() + { + var root1 = new TreeNode(4, + left: new TreeNode(2, left: new TreeNode(1), right: new TreeNode(3)), + right: new TreeNode(7, left: new TreeNode(6), right: new TreeNode(9))); + var exp1 = new TreeNode(4, + left: new TreeNode(7, left: new TreeNode(9), right: new TreeNode(6)), + right: new TreeNode(2, left: new TreeNode(3), right: new TreeNode(1))); + var root2 = new TreeNode(2, left: new TreeNode(1), right: new TreeNode(3)); + var exp2 = new TreeNode(2, left: new TreeNode(3), right: new TreeNode(1)); + + InvertTree(root1).ShouldBeEquivalentTo(exp1); + InvertTree(root2).ShouldBeEquivalentTo(exp2); + InvertTree(new TreeNode()).ShouldBeEquivalentTo(new TreeNode()); + InvertTree(null).ShouldBeNull(); + } +} diff --git a/LeetCode.CSharp/Problems/IsAnagram.cs b/LeetCode.CSharp/Problems/IsAnagram.cs index d957103..42e74e7 100644 --- a/LeetCode.CSharp/Problems/IsAnagram.cs +++ b/LeetCode.CSharp/Problems/IsAnagram.cs @@ -1,21 +1,21 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Valid Anagram", - Difficulty.Easy, - Category.ArraysAndHashing, - "https://www.youtube.com/watch?v=9UtInBqnCgA")] - public static bool IsAnagram(string s, string t) => - s.Length == t.Length && s.OrderBy(c => c).SequenceEqual(t.OrderBy(c => c)); - - [Fact] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public void IsAnagramTest() - { - IsAnagram("anagram", "nagaram").ShouldBeTrue(); - IsAnagram("rat", "cat").ShouldBeFalse(); - IsAnagram("ratty", "rat").ShouldBeFalse(); - IsAnagram("rat", "aat").ShouldBeFalse(); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Valid Anagram", + Difficulty.Easy, + Category.ArraysAndHashing, + "https://www.youtube.com/watch?v=9UtInBqnCgA")] + public static bool IsAnagram(string s, string t) => + s.Length == t.Length && s.OrderBy(c => c).SequenceEqual(t.OrderBy(c => c)); + + [Fact] + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public void IsAnagramTest() + { + IsAnagram("anagram", "nagaram").ShouldBeTrue(); + IsAnagram("rat", "cat").ShouldBeFalse(); + IsAnagram("ratty", "rat").ShouldBeFalse(); + IsAnagram("rat", "aat").ShouldBeFalse(); + } +} diff --git a/LeetCode.CSharp/Problems/IsBalanced.cs b/LeetCode.CSharp/Problems/IsBalanced.cs index ae3bbe2..48f467c 100644 --- a/LeetCode.CSharp/Problems/IsBalanced.cs +++ b/LeetCode.CSharp/Problems/IsBalanced.cs @@ -1,48 +1,48 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Balanced Binary Tree", - Difficulty.Easy, - Category.Trees, - "https://www.youtube.com/watch?v=QfJsau0ItOY")] - public static bool IsBalanced(TreeNode root) - { - return DepthFirstSearch(root).IsBalanced; - - static (bool IsBalanced, int Height) DepthFirstSearch(TreeNode? node) - { - if (node is null) - { - return (true, 0); - } - - var left = DepthFirstSearch(node.left); - var right = DepthFirstSearch(node.right); - - var isBalanced = left.IsBalanced && right.IsBalanced - && Math.Abs(left.Height - right.Height) <= 1; - - // Add 1 to include current node's height - var height = Math.Max(left.Height, right.Height) + 1; - - return (isBalanced, height); - } - } - - [Fact] - public void IsBalancedTest() - { - var root1 = new TreeNode([3, 9, 20, null, null, 15, 7]); - var root2 = new TreeNode([1, 2, 2, 3, 3, null, null, 4, 4]); - var root3 = new TreeNode([1, 2, null, 3]); - var root4 = new TreeNode([1, 2, 3, 4, 5, null, 6, 7, null, null, null, null, 8]); - var root5 = new TreeNode(); - - IsBalanced(root1).ShouldBeTrue(); - IsBalanced(root2).ShouldBeFalse(); - IsBalanced(root3).ShouldBeFalse(); - IsBalanced(root4).ShouldBeFalse(); - IsBalanced(root5).ShouldBeTrue(); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Balanced Binary Tree", + Difficulty.Easy, + Category.Trees, + "https://www.youtube.com/watch?v=QfJsau0ItOY")] + public static bool IsBalanced(TreeNode root) + { + return DepthFirstSearch(root).IsBalanced; + + static (bool IsBalanced, int Height) DepthFirstSearch(TreeNode? node) + { + if (node is null) + { + return (true, 0); + } + + var left = DepthFirstSearch(node.left); + var right = DepthFirstSearch(node.right); + + var isBalanced = left.IsBalanced && right.IsBalanced + && Math.Abs(left.Height - right.Height) <= 1; + + // Add 1 to include current node's height + var height = Math.Max(left.Height, right.Height) + 1; + + return (isBalanced, height); + } + } + + [Fact] + public void IsBalancedTest() + { + var root1 = new TreeNode([3, 9, 20, null, null, 15, 7]); + var root2 = new TreeNode([1, 2, 2, 3, 3, null, null, 4, 4]); + var root3 = new TreeNode([1, 2, null, 3]); + var root4 = new TreeNode([1, 2, 3, 4, 5, null, 6, 7, null, null, null, null, 8]); + var root5 = new TreeNode(); + + IsBalanced(root1).ShouldBeTrue(); + IsBalanced(root2).ShouldBeFalse(); + IsBalanced(root3).ShouldBeFalse(); + IsBalanced(root4).ShouldBeFalse(); + IsBalanced(root5).ShouldBeTrue(); + } +} diff --git a/LeetCode.CSharp/Problems/IsHappy.cs b/LeetCode.CSharp/Problems/IsHappy.cs index 107f218..7696f94 100644 --- a/LeetCode.CSharp/Problems/IsHappy.cs +++ b/LeetCode.CSharp/Problems/IsHappy.cs @@ -1,48 +1,48 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Happy Number", - Difficulty.Easy, - Category.MathAndGeometry, - "https://www.youtube.com/watch?v=ljz85bxOYJ0")] - public static bool IsHappy(int n) - { - var visited = new HashSet(); - - while (!visited.Contains(n)) - { - visited.Add(n); - - n = SumOfSquares(n); - - if (n == 1) - { - return true; // :) - } - } - - return false; // :( - - static int SumOfSquares(int i) - { - var result = 0; - - while (i != 0) - { - var digit = i % 10; - digit *= digit; - result += digit; - i /= 10; - } - return result; - } - } - - [Fact] - public void IsHappyTest() - { - IsHappy(19).ShouldBeTrue(); - IsHappy(2).ShouldBeFalse(); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Happy Number", + Difficulty.Easy, + Category.MathAndGeometry, + "https://www.youtube.com/watch?v=ljz85bxOYJ0")] + public static bool IsHappy(int n) + { + var visited = new HashSet(); + + while (!visited.Contains(n)) + { + visited.Add(n); + + n = SumOfSquares(n); + + if (n == 1) + { + return true; // :) + } + } + + return false; // :( + + static int SumOfSquares(int i) + { + var result = 0; + + while (i != 0) + { + var digit = i % 10; + digit *= digit; + result += digit; + i /= 10; + } + return result; + } + } + + [Fact] + public void IsHappyTest() + { + IsHappy(19).ShouldBeTrue(); + IsHappy(2).ShouldBeFalse(); + } +} diff --git a/LeetCode.CSharp/Problems/IsPalindrone.cs b/LeetCode.CSharp/Problems/IsPalindrone.cs index 95fb8d2..c567904 100644 --- a/LeetCode.CSharp/Problems/IsPalindrone.cs +++ b/LeetCode.CSharp/Problems/IsPalindrone.cs @@ -1,51 +1,51 @@ -namespace LeetCode.CSharp.Problems; - -using System.Collections.Generic; -using System.Linq; - -public sealed partial class Problem -{ - [LeetCode("Palindrome Linked List", - Difficulty.Easy, - Category.TwoPointers, - "https://www.youtube.com/watch?v=jJXJ16kPFWg")] - public static bool IsPalindrome(ListNode head) - { - if (head.next is null) - { - return true; - } - - var list = new List { head.val }; - - while (head.next is not null) - { - head = head.next; - list.Add(head.val); - } - - var isOdd = list.Count % 2 != 0; - var take = isOdd ? (list.Count - 1) / 2 : list.Count / 2; - var skip = isOdd ? take + 1 : take; - var firstHalf = list.Take(take).ToArray(); - var secondHalf = list.Skip(skip).Take(take).Reverse().ToArray(); - - return !firstHalf.Where((t, i) => t != secondHalf[i]).Any(); - } - - [Fact] - public void IsPalindromeTest() - { - var single = new ListNode(1); - var even = new ListNode([1, 2, 2, 1]); - var odd = new ListNode([1, 2, 3, 2, 1]); - var notEven = new ListNode([2, 1, 2, 1]); - var notOdd = new ListNode([2, 1, 3, 2, 1]); - - IsPalindrome(single).ShouldBeTrue(); - IsPalindrome(even).ShouldBeTrue(); - IsPalindrome(odd).ShouldBeTrue(); - IsPalindrome(notEven).ShouldBeFalse(); - IsPalindrome(notOdd).ShouldBeFalse(); - } -} +namespace LeetCode.CSharp.Problems; + +using System.Collections.Generic; +using System.Linq; + +public sealed partial class Problem +{ + [LeetCode("Palindrome Linked List", + Difficulty.Easy, + Category.TwoPointers, + "https://www.youtube.com/watch?v=jJXJ16kPFWg")] + public static bool IsPalindrome(ListNode head) + { + if (head.next is null) + { + return true; + } + + var list = new List { head.val }; + + while (head.next is not null) + { + head = head.next; + list.Add(head.val); + } + + var isOdd = list.Count % 2 != 0; + var take = isOdd ? (list.Count - 1) / 2 : list.Count / 2; + var skip = isOdd ? take + 1 : take; + var firstHalf = list.Take(take).ToArray(); + var secondHalf = list.Skip(skip).Take(take).Reverse().ToArray(); + + return !firstHalf.Where((t, i) => t != secondHalf[i]).Any(); + } + + [Fact] + public void IsPalindromeTest() + { + var single = new ListNode(1); + var even = new ListNode([1, 2, 2, 1]); + var odd = new ListNode([1, 2, 3, 2, 1]); + var notEven = new ListNode([2, 1, 2, 1]); + var notOdd = new ListNode([2, 1, 3, 2, 1]); + + IsPalindrome(single).ShouldBeTrue(); + IsPalindrome(even).ShouldBeTrue(); + IsPalindrome(odd).ShouldBeTrue(); + IsPalindrome(notEven).ShouldBeFalse(); + IsPalindrome(notOdd).ShouldBeFalse(); + } +} diff --git a/LeetCode.CSharp/Problems/IsSameTree.cs b/LeetCode.CSharp/Problems/IsSameTree.cs index c55929c..81a8c6d 100644 --- a/LeetCode.CSharp/Problems/IsSameTree.cs +++ b/LeetCode.CSharp/Problems/IsSameTree.cs @@ -1,47 +1,47 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Same Tree", - Difficulty.Easy, - Category.Trees, - "https://www.youtube.com/watch?v=vRbbcKXCxOw")] - public static bool IsSameTree(TreeNode? p, TreeNode? q) - { - // Null tree nodes are equal - if (p is null && q is null) - { - return true; - } - - // One must now be non-null - if (p is null || q is null) - { - return false; - } - - // Both must now be non-null - if (p.val != q.val) - { - return false; - } - - return IsSameTree(p.left, q.left) && IsSameTree(p.right, q.right); - } - - [Fact] - public void IsSameTreeTest() - { - var p1 = new TreeNode([1, 2, 3]); - var q1 = new TreeNode([1, 2, 3]); - var p2 = new TreeNode([1, 2]); - var q2 = new TreeNode([1, null, 2]); - var p3 = new TreeNode([1, 2, 1]); - var q3 = new TreeNode([1, 1, 2]); - - IsSameTree(p1, q1).ShouldBeTrue(); - IsSameTree(p2, q2).ShouldBeFalse(); - IsSameTree(p3, q3).ShouldBeFalse(); - IsSameTree(null, null).ShouldBeTrue(); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Same Tree", + Difficulty.Easy, + Category.Trees, + "https://www.youtube.com/watch?v=vRbbcKXCxOw")] + public static bool IsSameTree(TreeNode? p, TreeNode? q) + { + // Null tree nodes are equal + if (p is null && q is null) + { + return true; + } + + // One must now be non-null + if (p is null || q is null) + { + return false; + } + + // Both must now be non-null + if (p.val != q.val) + { + return false; + } + + return IsSameTree(p.left, q.left) && IsSameTree(p.right, q.right); + } + + [Fact] + public void IsSameTreeTest() + { + var p1 = new TreeNode([1, 2, 3]); + var q1 = new TreeNode([1, 2, 3]); + var p2 = new TreeNode([1, 2]); + var q2 = new TreeNode([1, null, 2]); + var p3 = new TreeNode([1, 2, 1]); + var q3 = new TreeNode([1, 1, 2]); + + IsSameTree(p1, q1).ShouldBeTrue(); + IsSameTree(p2, q2).ShouldBeFalse(); + IsSameTree(p3, q3).ShouldBeFalse(); + IsSameTree(null, null).ShouldBeTrue(); + } +} diff --git a/LeetCode.CSharp/Problems/IsSubtree.cs b/LeetCode.CSharp/Problems/IsSubtree.cs index 7cd98a0..fa4d69c 100644 --- a/LeetCode.CSharp/Problems/IsSubtree.cs +++ b/LeetCode.CSharp/Problems/IsSubtree.cs @@ -1,45 +1,45 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Subtree of Another Tree", - Difficulty.Easy, - Category.Trees, - "https://www.youtube.com/watch?v=E36O5SWp-LE")] - public static bool IsSubtree(TreeNode? root, TreeNode? subRoot) - { - // A null root or null root edge means a null subRoot is a subtree - if (subRoot is null) - { - return true; - } - - // SubRoot is non-null therefore a null root means it's not a subtree - if (root is null) - { - return false; - } - - // Use code from previous challenge - if (IsSameTree(root, subRoot)) - { - return true; - } - - // Recursively check if either left or right node is a subtree - return IsSubtree(root.left, subRoot) || IsSubtree(root.right, subRoot); - } - - [Fact] - public void IsSubtreeTest() - { - var root1 = new TreeNode([3, 4, 5, 1, 2]); - var subRoot1 = new TreeNode([4, 1, 2]); - var root2 = new TreeNode([3, 4, 5, 1, 2, null, null, null, null, 0]); - var subRoot2 = new TreeNode([4, 1, 2]); - - IsSubtree(root1, subRoot1).ShouldBeTrue(); - IsSubtree(root2, subRoot2).ShouldBeFalse(); - IsSubtree(null, null).ShouldBeTrue(); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Subtree of Another Tree", + Difficulty.Easy, + Category.Trees, + "https://www.youtube.com/watch?v=E36O5SWp-LE")] + public static bool IsSubtree(TreeNode? root, TreeNode? subRoot) + { + // A null root or null root edge means a null subRoot is a subtree + if (subRoot is null) + { + return true; + } + + // SubRoot is non-null therefore a null root means it's not a subtree + if (root is null) + { + return false; + } + + // Use code from previous challenge + if (IsSameTree(root, subRoot)) + { + return true; + } + + // Recursively check if either left or right node is a subtree + return IsSubtree(root.left, subRoot) || IsSubtree(root.right, subRoot); + } + + [Fact] + public void IsSubtreeTest() + { + var root1 = new TreeNode([3, 4, 5, 1, 2]); + var subRoot1 = new TreeNode([4, 1, 2]); + var root2 = new TreeNode([3, 4, 5, 1, 2, null, null, null, null, 0]); + var subRoot2 = new TreeNode([4, 1, 2]); + + IsSubtree(root1, subRoot1).ShouldBeTrue(); + IsSubtree(root2, subRoot2).ShouldBeFalse(); + IsSubtree(null, null).ShouldBeTrue(); + } +} diff --git a/LeetCode.CSharp/Problems/IsValidSudoku.cs b/LeetCode.CSharp/Problems/IsValidSudoku.cs index b5836fd..475190c 100644 --- a/LeetCode.CSharp/Problems/IsValidSudoku.cs +++ b/LeetCode.CSharp/Problems/IsValidSudoku.cs @@ -1,108 +1,108 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Valid Sudoku", - Difficulty.Medium, - Category.ArraysAndHashing, - "https://www.youtube.com/watch?v=TjFXEUCMqI8")] - public static bool IsValidSudoku(char[][] board) - { - var columns = new Dictionary>(); - var subBoxes = new Dictionary<(int, int), HashSet>(); - - for (var r = 0; r < 9; r++) - { - var row = new HashSet(); - - for (var c = 0; c < 9; c++) - { - if (!columns.TryGetValue(c, out var column)) - { - column = []; - columns[c] = column; - } - - // Integer division rounds down creating sub-boxes: - // row 0 column 0 | row 0 column 1 | row 0 column 2 - // row 1 column 0 | row 1 column 1 | row 1 column 2 - // row 2 column 0 | row 2 column 1 | row 2 column 2 - var subBoxKey = (r / 3, c / 3); - if (!subBoxes.TryGetValue(subBoxKey, out var subBox)) - { - subBox = []; - subBoxes.Add(subBoxKey, subBox); - } - - var cell = board[r][c]; - - // Ignore empty cells - if (cell == '.') - { - continue; - } - - // Cell must be integer between 1 and 9 - var digit = Convert.ToInt16(cell); - - if (row.TryGetValue(digit, out _) || - column.TryGetValue(digit, out _) || - subBox.Contains(digit)) - { - return false; - } - - row.Add(digit); - column.Add(digit); - subBox.Add(digit); - } - } - - return true; - } - - [Fact] - public void IsValidSudokuTest() - { - var ex1 = new char[][] - { - ['5', '3', '.', '.', '7', '.', '.', '.', '.'], - ['6', '.', '.', '1', '9', '5', '.', '.', '.'], - ['.', '9', '8', '.', '.', '.', '.', '6', '.'], - ['8', '.', '.', '.', '6', '.', '.', '.', '3'], - ['4', '.', '.', '8', '.', '3', '.', '.', '1'], - ['7', '.', '.', '.', '2', '.', '.', '.', '6'], - ['.', '6', '.', '.', '.', '.', '2', '8', '.'], - ['.', '.', '.', '4', '1', '9', '.', '.', '5'], - ['.', '.', '.', '.', '8', '.', '.', '7', '9'] - }; - var ex2 = new char[][] - { - ['8', '3', '.', '.', '7', '.', '.', '.', '.'], - ['6', '.', '.', '1', '9', '5', '.', '.', '.'], - ['.', '9', '8', '.', '.', '.', '.', '6', '.'], - ['8', '.', '.', '.', '6', '.', '.', '.', '3'], - ['4', '.', '.', '8', '.', '3', '.', '.', '1'], - ['7', '.', '.', '.', '2', '.', '.', '.', '6'], - ['.', '6', '.', '.', '.', '.', '2', '8', '.'], - ['.', '.', '.', '4', '1', '9', '.', '.', '5'], - ['.', '.', '.', '.', '8', '.', '.', '7', '9'] - }; - var ex3 = new char[][] - { - ['.', '.', '4', '.', '.', '.', '6', '3', '.'], - ['.', '.', '.', '.', '.', '.', '.', '.', '.'], - ['5', '.', '.', '.', '.', '.', '.', '9', '.'], - ['.', '.', '.', '5', '6', '.', '.', '.', '.'], - ['4', '.', '3', '.', '.', '.', '.', '.', '1'], - ['.', '.', '.', '7', '.', '.', '.', '.', '.'], - ['.', '.', '.', '5', '.', '.', '.', '.', '.'], - ['.', '.', '.', '.', '.', '.', '.', '.', '.'], - ['.', '.', '.', '.', '.', '.', '.', '.', '.'] - }; - - IsValidSudoku(ex1).ShouldBeTrue(); - IsValidSudoku(ex2).ShouldBeFalse(); - IsValidSudoku(ex3).ShouldBeFalse(); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Valid Sudoku", + Difficulty.Medium, + Category.ArraysAndHashing, + "https://www.youtube.com/watch?v=TjFXEUCMqI8")] + public static bool IsValidSudoku(char[][] board) + { + var columns = new Dictionary>(); + var subBoxes = new Dictionary<(int, int), HashSet>(); + + for (var r = 0; r < 9; r++) + { + var row = new HashSet(); + + for (var c = 0; c < 9; c++) + { + if (!columns.TryGetValue(c, out var column)) + { + column = []; + columns[c] = column; + } + + // Integer division rounds down creating sub-boxes: + // row 0 column 0 | row 0 column 1 | row 0 column 2 + // row 1 column 0 | row 1 column 1 | row 1 column 2 + // row 2 column 0 | row 2 column 1 | row 2 column 2 + var subBoxKey = (r / 3, c / 3); + if (!subBoxes.TryGetValue(subBoxKey, out var subBox)) + { + subBox = []; + subBoxes.Add(subBoxKey, subBox); + } + + var cell = board[r][c]; + + // Ignore empty cells + if (cell == '.') + { + continue; + } + + // Cell must be integer between 1 and 9 + var digit = Convert.ToInt16(cell); + + if (row.TryGetValue(digit, out _) || + column.TryGetValue(digit, out _) || + subBox.Contains(digit)) + { + return false; + } + + row.Add(digit); + column.Add(digit); + subBox.Add(digit); + } + } + + return true; + } + + [Fact] + public void IsValidSudokuTest() + { + var ex1 = new char[][] + { + ['5', '3', '.', '.', '7', '.', '.', '.', '.'], + ['6', '.', '.', '1', '9', '5', '.', '.', '.'], + ['.', '9', '8', '.', '.', '.', '.', '6', '.'], + ['8', '.', '.', '.', '6', '.', '.', '.', '3'], + ['4', '.', '.', '8', '.', '3', '.', '.', '1'], + ['7', '.', '.', '.', '2', '.', '.', '.', '6'], + ['.', '6', '.', '.', '.', '.', '2', '8', '.'], + ['.', '.', '.', '4', '1', '9', '.', '.', '5'], + ['.', '.', '.', '.', '8', '.', '.', '7', '9'] + }; + var ex2 = new char[][] + { + ['8', '3', '.', '.', '7', '.', '.', '.', '.'], + ['6', '.', '.', '1', '9', '5', '.', '.', '.'], + ['.', '9', '8', '.', '.', '.', '.', '6', '.'], + ['8', '.', '.', '.', '6', '.', '.', '.', '3'], + ['4', '.', '.', '8', '.', '3', '.', '.', '1'], + ['7', '.', '.', '.', '2', '.', '.', '.', '6'], + ['.', '6', '.', '.', '.', '.', '2', '8', '.'], + ['.', '.', '.', '4', '1', '9', '.', '.', '5'], + ['.', '.', '.', '.', '8', '.', '.', '7', '9'] + }; + var ex3 = new char[][] + { + ['.', '.', '4', '.', '.', '.', '6', '3', '.'], + ['.', '.', '.', '.', '.', '.', '.', '.', '.'], + ['5', '.', '.', '.', '.', '.', '.', '9', '.'], + ['.', '.', '.', '5', '6', '.', '.', '.', '.'], + ['4', '.', '3', '.', '.', '.', '.', '.', '1'], + ['.', '.', '.', '7', '.', '.', '.', '.', '.'], + ['.', '.', '.', '5', '.', '.', '.', '.', '.'], + ['.', '.', '.', '.', '.', '.', '.', '.', '.'], + ['.', '.', '.', '.', '.', '.', '.', '.', '.'] + }; + + IsValidSudoku(ex1).ShouldBeTrue(); + IsValidSudoku(ex2).ShouldBeFalse(); + IsValidSudoku(ex3).ShouldBeFalse(); + } +} diff --git a/LeetCode.CSharp/Problems/KWeakestRows.cs b/LeetCode.CSharp/Problems/KWeakestRows.cs index 25835b0..047df3d 100644 --- a/LeetCode.CSharp/Problems/KWeakestRows.cs +++ b/LeetCode.CSharp/Problems/KWeakestRows.cs @@ -1,35 +1,35 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("The K Weakest Rows in a Matrix", Difficulty.Easy, Category.NotInNeetCode)] - [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] - public static int[] KWeakestRows(int[][] mat, int k) => - [.. mat.Select((row, index) => (Strength: row.Count(x => x == 1), Index: index)) - .OrderBy(x => x.Strength) - .Take(k) - .Select(x => x.Index)]; - - [Fact] - public void KWeakestRowsTest() - { - var ex1 = new int[][] - { - [1, 1, 0, 0, 0], - [1, 1, 1, 1, 0], - [1, 0, 0, 0, 0], - [1, 1, 0, 0, 0], - [1, 1, 1, 1, 1] - }; - var ex2 = new int[][] - { - [1, 0, 0, 0], - [1, 1, 1, 1], - [1, 0, 0, 0], - [1, 0, 0, 0] - }; - - KWeakestRows(ex1, 3).ShouldBe([2, 0, 3]); - KWeakestRows(ex2, 2).ShouldBe([0, 2]); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("The K Weakest Rows in a Matrix", Difficulty.Easy, Category.NotInNeetCode)] + [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] + public static int[] KWeakestRows(int[][] mat, int k) => + [.. mat.Select((row, index) => (Strength: row.Count(x => x == 1), Index: index)) + .OrderBy(x => x.Strength) + .Take(k) + .Select(x => x.Index)]; + + [Fact] + public void KWeakestRowsTest() + { + var ex1 = new int[][] + { + [1, 1, 0, 0, 0], + [1, 1, 1, 1, 0], + [1, 0, 0, 0, 0], + [1, 1, 0, 0, 0], + [1, 1, 1, 1, 1] + }; + var ex2 = new int[][] + { + [1, 0, 0, 0], + [1, 1, 1, 1], + [1, 0, 0, 0], + [1, 0, 0, 0] + }; + + KWeakestRows(ex1, 3).ShouldBe([2, 0, 3]); + KWeakestRows(ex2, 2).ShouldBe([0, 2]); + } +} diff --git a/LeetCode.CSharp/Problems/KthLargest.cs b/LeetCode.CSharp/Problems/KthLargest.cs index 32772ec..218434e 100644 --- a/LeetCode.CSharp/Problems/KthLargest.cs +++ b/LeetCode.CSharp/Problems/KthLargest.cs @@ -1,58 +1,58 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Kth Largest Element in a Stream", - Difficulty.Easy, - Category.HeapPriorityQueue, - "https://www.youtube.com/watch?v=hOjcdrqMoQ8")] - public class KthLargest - { - private readonly PriorityQueue _queue = new(); - private readonly int _k; - - [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Local")] - public KthLargest(int k, int[] nums) - { - _k = k; - nums - .OrderBy(n => n) - .TakeLast(k) - .ToList() - .ForEach(n => _queue.Enqueue(n, n)); - } - - public int Add(int val) - { - if (_queue.Count < _k) - { - _queue.Enqueue(val, val); - } - else if (val > _queue.Peek()) - { - _queue.Dequeue(); - _queue.Enqueue(val, val); - } - return _queue.Peek(); - } - } - - [Fact] - public void KthLargestTest() - { - var ex1 = new KthLargest(3, [4, 5, 8, 2]); - var ex2 = new KthLargest(3, [4, 5]); - - ex1.Add(3).ShouldBe(4, "3 shouldn't replace 4"); - ex1.Add(5).ShouldBe(5, "5 should replace 4"); - ex1.Add(10).ShouldBe(5, "10 should replace 5"); - ex1.Add(9).ShouldBe(8, "9 should replace 8"); - ex1.Add(4).ShouldBe(8, "4 shouldn't replace 8"); - - ex2.Add(3).ShouldBe(3, "3 should be added"); - ex2.Add(5).ShouldBe(4, "5 should replace 3"); - ex2.Add(10).ShouldBe(5, "10 should replace 5"); - ex2.Add(9).ShouldBe(5, "9 should replace 5"); - ex2.Add(4).ShouldBe(5, "4 shouldn't replace 5"); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Kth Largest Element in a Stream", + Difficulty.Easy, + Category.HeapPriorityQueue, + "https://www.youtube.com/watch?v=hOjcdrqMoQ8")] + public class KthLargest + { + private readonly PriorityQueue _queue = new(); + private readonly int _k; + + [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Local")] + public KthLargest(int k, int[] nums) + { + _k = k; + nums + .OrderBy(n => n) + .TakeLast(k) + .ToList() + .ForEach(n => _queue.Enqueue(n, n)); + } + + public int Add(int val) + { + if (_queue.Count < _k) + { + _queue.Enqueue(val, val); + } + else if (val > _queue.Peek()) + { + _queue.Dequeue(); + _queue.Enqueue(val, val); + } + return _queue.Peek(); + } + } + + [Fact] + public void KthLargestTest() + { + var ex1 = new KthLargest(3, [4, 5, 8, 2]); + var ex2 = new KthLargest(3, [4, 5]); + + ex1.Add(3).ShouldBe(4, "3 shouldn't replace 4"); + ex1.Add(5).ShouldBe(5, "5 should replace 4"); + ex1.Add(10).ShouldBe(5, "10 should replace 5"); + ex1.Add(9).ShouldBe(8, "9 should replace 8"); + ex1.Add(4).ShouldBe(8, "4 shouldn't replace 8"); + + ex2.Add(3).ShouldBe(3, "3 should be added"); + ex2.Add(5).ShouldBe(4, "5 should replace 3"); + ex2.Add(10).ShouldBe(5, "10 should replace 5"); + ex2.Add(9).ShouldBe(5, "9 should replace 5"); + ex2.Add(4).ShouldBe(5, "4 shouldn't replace 5"); + } +} diff --git a/LeetCode.CSharp/Problems/LRUCache.cs b/LeetCode.CSharp/Problems/LRUCache.cs index ceb6c18..e5d256c 100644 --- a/LeetCode.CSharp/Problems/LRUCache.cs +++ b/LeetCode.CSharp/Problems/LRUCache.cs @@ -1,150 +1,150 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Least Recently Used Cache", - Difficulty.Medium, - Category.LinkedList, - "https://www.youtube.com/watch?v=7ABFKPK2hD4")] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public class LRUCache - { - private record Node(int Key = 0, int Value = 0) - { - public Node? Previous { get; set; } - - public Node? Next { get; set; } - } - - private readonly int _capacity; - - // Value is node rather than int to update double linked list (left and right nodes) - private readonly Dictionary _cache = []; - - // Left node is pointer least recently used - private readonly Node _left = new(); - - // Right node is pointer to most recently used - private readonly Node _right = new(); - - public LRUCache(int capacity) - { - _capacity = capacity; - - // Double link pointers to each other - _left.Next = _right; - _right.Previous = _left; - } - - /// - /// Remove by updating its pointers to other nodes - /// - /// The node to be removed - private static void Remove(Node node) - { - var previous = node.Previous; - var next = node.Next; - - previous?.Next = next; - next?.Previous = previous; - } - - /// - /// Insert by updating pointers and marking as most recently used - /// - /// - private void Insert(Node node) - { - var previous = _right.Previous; - if (previous is not null) - { - // Set previous MRU pointer to new node - previous.Next = node; - node.Previous = previous; - } - - // Mark node as most recently used - _right.Previous = node; - node.Next = _right; - } - - public int Get(int key) - { - if (!_cache.TryGetValue(key, out var node)) - { - return -1; - } - - // No need to update linked lists if key was already most recently used - if (_right.Key == key) - { - return node.Value; - } - - // Clear out "middle" node pointers - Remove(node); - - // Update most recently used pointers - Insert(node); - - return node.Value; - } - - public void Put(int key, int value) - { - if (_cache.TryGetValue(key, out var existing)) - { - if (existing == _right) - { - // Nothing to do as key and value were already most recently used - return; - } - - // Remove existing node as it's now the most recently used but wasn't previously - Remove(existing); - } - - var node = new Node(key, value); - - if (!_cache.TryAdd(key, node)) - { - // Replace node in cache as its value or pointers may have changed - _cache[key] = node; - } - - Insert(node); - - if (_cache.Count <= _capacity || _left.Next is null) - { - return; - } - - // Capacity exceeded so remove LRU from linked list and evict from cache - var lru = _left.Next; - Remove(lru); - _cache.Remove(lru.Key); - } - } - - [Fact] - [SuppressMessage("ReSharper", "InconsistentNaming")] - public void LRUCacheTest() - { - var lru = new LRUCache(2); - lru.Put(1, 1); - lru.Put(2, 2); - var firstGet = lru.Get(1); - lru.Put(3, 3); - var secondGet = lru.Get(2); - lru.Put(4, 4); - var thirdGet = lru.Get(1); - var forthGet = lru.Get(3); - var fifthGet = lru.Get(4); - - firstGet.ShouldBe(1); - secondGet.ShouldBe(-1); - thirdGet.ShouldBe(-1); - forthGet.ShouldBe(3); - fifthGet.ShouldBe(4); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Least Recently Used Cache", + Difficulty.Medium, + Category.LinkedList, + "https://www.youtube.com/watch?v=7ABFKPK2hD4")] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public class LRUCache + { + private record Node(int Key = 0, int Value = 0) + { + public Node? Previous { get; set; } + + public Node? Next { get; set; } + } + + private readonly int _capacity; + + // Value is node rather than int to update double linked list (left and right nodes) + private readonly Dictionary _cache = []; + + // Left node is pointer least recently used + private readonly Node _left = new(); + + // Right node is pointer to most recently used + private readonly Node _right = new(); + + public LRUCache(int capacity) + { + _capacity = capacity; + + // Double link pointers to each other + _left.Next = _right; + _right.Previous = _left; + } + + /// + /// Remove by updating its pointers to other nodes + /// + /// The node to be removed + private static void Remove(Node node) + { + var previous = node.Previous; + var next = node.Next; + + previous?.Next = next; + next?.Previous = previous; + } + + /// + /// Insert by updating pointers and marking as most recently used + /// + /// + private void Insert(Node node) + { + var previous = _right.Previous; + if (previous is not null) + { + // Set previous MRU pointer to new node + previous.Next = node; + node.Previous = previous; + } + + // Mark node as most recently used + _right.Previous = node; + node.Next = _right; + } + + public int Get(int key) + { + if (!_cache.TryGetValue(key, out var node)) + { + return -1; + } + + // No need to update linked lists if key was already most recently used + if (_right.Key == key) + { + return node.Value; + } + + // Clear out "middle" node pointers + Remove(node); + + // Update most recently used pointers + Insert(node); + + return node.Value; + } + + public void Put(int key, int value) + { + if (_cache.TryGetValue(key, out var existing)) + { + if (existing == _right) + { + // Nothing to do as key and value were already most recently used + return; + } + + // Remove existing node as it's now the most recently used but wasn't previously + Remove(existing); + } + + var node = new Node(key, value); + + if (!_cache.TryAdd(key, node)) + { + // Replace node in cache as its value or pointers may have changed + _cache[key] = node; + } + + Insert(node); + + if (_cache.Count <= _capacity || _left.Next is null) + { + return; + } + + // Capacity exceeded so remove LRU from linked list and evict from cache + var lru = _left.Next; + Remove(lru); + _cache.Remove(lru.Key); + } + } + + [Fact] + [SuppressMessage("ReSharper", "InconsistentNaming")] + public void LRUCacheTest() + { + var lru = new LRUCache(2); + lru.Put(1, 1); + lru.Put(2, 2); + var firstGet = lru.Get(1); + lru.Put(3, 3); + var secondGet = lru.Get(2); + lru.Put(4, 4); + var thirdGet = lru.Get(1); + var forthGet = lru.Get(3); + var fifthGet = lru.Get(4); + + firstGet.ShouldBe(1); + secondGet.ShouldBe(-1); + thirdGet.ShouldBe(-1); + forthGet.ShouldBe(3); + fifthGet.ShouldBe(4); + } +} diff --git a/LeetCode.CSharp/Problems/LastStoneWeight.cs b/LeetCode.CSharp/Problems/LastStoneWeight.cs index e056936..a896a3b 100644 --- a/LeetCode.CSharp/Problems/LastStoneWeight.cs +++ b/LeetCode.CSharp/Problems/LastStoneWeight.cs @@ -1,42 +1,42 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Last Stone Weight", - Difficulty.Easy, - Category.HeapPriorityQueue, - "https://www.youtube.com/watch?v=B-QCq79-Vfw")] - [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] - public static int LastStoneWeight(int[] stones) - { - PriorityQueue queue = new(); - foreach (var stone in stones) - { - queue.Enqueue(stone, -stone); - } - - while (queue.Count > 1) - { - var heaviest = queue.Dequeue(); - var nextHeaviest = queue.Dequeue(); - if (heaviest == nextHeaviest) - { - continue; - } - var remainder = heaviest - nextHeaviest; - queue.Enqueue(remainder, -remainder); - } - - return queue.Count == 0 ? 0 : queue.Peek(); - } - - [Fact] - public void LastStoneWeightTest() - { - var ex1 = new[] { 2, 7, 4, 1, 8, 1 }; - var ex2 = new[] { 1 }; - - LastStoneWeight(ex1).ShouldBe(1); - LastStoneWeight(ex2).ShouldBe(1); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Last Stone Weight", + Difficulty.Easy, + Category.HeapPriorityQueue, + "https://www.youtube.com/watch?v=B-QCq79-Vfw")] + [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] + public static int LastStoneWeight(int[] stones) + { + PriorityQueue queue = new(); + foreach (var stone in stones) + { + queue.Enqueue(stone, -stone); + } + + while (queue.Count > 1) + { + var heaviest = queue.Dequeue(); + var nextHeaviest = queue.Dequeue(); + if (heaviest == nextHeaviest) + { + continue; + } + var remainder = heaviest - nextHeaviest; + queue.Enqueue(remainder, -remainder); + } + + return queue.Count == 0 ? 0 : queue.Peek(); + } + + [Fact] + public void LastStoneWeightTest() + { + var ex1 = new[] { 2, 7, 4, 1, 8, 1 }; + var ex2 = new[] { 1 }; + + LastStoneWeight(ex1).ShouldBe(1); + LastStoneWeight(ex2).ShouldBe(1); + } +} diff --git a/LeetCode.CSharp/Problems/LengthOfLongestSubstring.cs b/LeetCode.CSharp/Problems/LengthOfLongestSubstring.cs index ecbfa27..76e2c7e 100644 --- a/LeetCode.CSharp/Problems/LengthOfLongestSubstring.cs +++ b/LeetCode.CSharp/Problems/LengthOfLongestSubstring.cs @@ -1,38 +1,38 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Longest Substring Without Repeating Characters", - Difficulty.Medium, - Category.SlidingWindow, - "https://www.youtube.com/watch?v=wiGpQwVHdE0")] - public static int LengthOfLongestSubstring(string s) - { - var list = new List(); - var left = 0; - var max = 0; - - for (var right = 0; right < s.Length; right++) - { - while (list.Contains(s[right])) - { - list.Remove(s[left]); - left++; - } - - list.Add(s[right]); - max = Math.Max(max, right - left + 1); - } - - return max; - } - - [Fact] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public void LengthOfLongestSubstringTest() - { - LengthOfLongestSubstring("abcabcbb").ShouldBe(3); - LengthOfLongestSubstring("bbbbb").ShouldBe(1); - LengthOfLongestSubstring("pwwkew").ShouldBe(3); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Longest Substring Without Repeating Characters", + Difficulty.Medium, + Category.SlidingWindow, + "https://www.youtube.com/watch?v=wiGpQwVHdE0")] + public static int LengthOfLongestSubstring(string s) + { + var list = new List(); + var left = 0; + var max = 0; + + for (var right = 0; right < s.Length; right++) + { + while (list.Contains(s[right])) + { + list.Remove(s[left]); + left++; + } + + list.Add(s[right]); + max = Math.Max(max, right - left + 1); + } + + return max; + } + + [Fact] + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public void LengthOfLongestSubstringTest() + { + LengthOfLongestSubstring("abcabcbb").ShouldBe(3); + LengthOfLongestSubstring("bbbbb").ShouldBe(1); + LengthOfLongestSubstring("pwwkew").ShouldBe(3); + } +} diff --git a/LeetCode.CSharp/Problems/LowestCommonAncestor.cs b/LeetCode.CSharp/Problems/LowestCommonAncestor.cs index a9662dd..ca328ab 100644 --- a/LeetCode.CSharp/Problems/LowestCommonAncestor.cs +++ b/LeetCode.CSharp/Problems/LowestCommonAncestor.cs @@ -1,49 +1,49 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Lowest Common Ancestor of a Binary Search Tree", - Difficulty.Easy, - Category.Trees, - "https://www.youtube.com/watch?v=gs2LMfuOR9k")] - public static TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) - { - var current = root; - - while (true) - { - ArgumentNullException.ThrowIfNull(current); - - if (p.val < current.val && q.val < current.val) - { - // Both p and q are lower so search left subtree - current = current.left; - } - else if (p.val > current.val && q.val > current.val) - { - // Both p and q are higher so search right subtree - current = current.right; - } - else - { - // Node either sits between p and q or equals p or q so we're at the LCA - return current; - } - } - } - - [Fact] - public void LowestCommonAncestorTest() - { - var root1 = new TreeNode([6, 2, 8, 0, 4, 7, 9, null, null, 3, 5]); - var p1 = root1.left!; - var q1 = root1.right!; - var q2 = p1.right!; - var root3 = new TreeNode([2, 1]); - var q3 = root3.left!; - - LowestCommonAncestor(root1, p1, q1).ShouldBe(root1); - LowestCommonAncestor(root1, p1, q2).ShouldBe(p1); - LowestCommonAncestor(root3, root3, q3).ShouldBe(root3); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Lowest Common Ancestor of a Binary Search Tree", + Difficulty.Easy, + Category.Trees, + "https://www.youtube.com/watch?v=gs2LMfuOR9k")] + public static TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) + { + var current = root; + + while (true) + { + ArgumentNullException.ThrowIfNull(current); + + if (p.val < current.val && q.val < current.val) + { + // Both p and q are lower so search left subtree + current = current.left; + } + else if (p.val > current.val && q.val > current.val) + { + // Both p and q are higher so search right subtree + current = current.right; + } + else + { + // Node either sits between p and q or equals p or q so we're at the LCA + return current; + } + } + } + + [Fact] + public void LowestCommonAncestorTest() + { + var root1 = new TreeNode([6, 2, 8, 0, 4, 7, 9, null, null, 3, 5]); + var p1 = root1.left!; + var q1 = root1.right!; + var q2 = p1.right!; + var root3 = new TreeNode([2, 1]); + var q3 = root3.left!; + + LowestCommonAncestor(root1, p1, q1).ShouldBe(root1); + LowestCommonAncestor(root1, p1, q2).ShouldBe(p1); + LowestCommonAncestor(root3, root3, q3).ShouldBe(root3); + } +} diff --git a/LeetCode.CSharp/Problems/MaxDepth.cs b/LeetCode.CSharp/Problems/MaxDepth.cs index 63df086..b027db0 100644 --- a/LeetCode.CSharp/Problems/MaxDepth.cs +++ b/LeetCode.CSharp/Problems/MaxDepth.cs @@ -1,31 +1,31 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Maximum Depth of Binary Tree", - Difficulty.Easy, - Category.Trees, - "https://www.youtube.com/watch?v=hTM3phVI6YQ")] - public static int MaxDepth(TreeNode? root) - { - if (root is null) - { - return 0; - } - - return Math.Max(MaxDepth(root.left), MaxDepth(root.right)) + 1; - } - - [Fact] - public void MaxDepthTest() - { - var root1 = new TreeNode(3, - left: new TreeNode(9, left: new TreeNode(1), right: null), - right: new TreeNode(20, left: new TreeNode(15), right: new TreeNode(7))); - var root2 = new TreeNode(1, left: null, right: new TreeNode(2)); - - MaxDepth(null).ShouldBe(0); - MaxDepth(root1).ShouldBe(3); - MaxDepth(root2).ShouldBe(2); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Maximum Depth of Binary Tree", + Difficulty.Easy, + Category.Trees, + "https://www.youtube.com/watch?v=hTM3phVI6YQ")] + public static int MaxDepth(TreeNode? root) + { + if (root is null) + { + return 0; + } + + return Math.Max(MaxDepth(root.left), MaxDepth(root.right)) + 1; + } + + [Fact] + public void MaxDepthTest() + { + var root1 = new TreeNode(3, + left: new TreeNode(9, left: new TreeNode(1), right: null), + right: new TreeNode(20, left: new TreeNode(15), right: new TreeNode(7))); + var root2 = new TreeNode(1, left: null, right: new TreeNode(2)); + + MaxDepth(null).ShouldBe(0); + MaxDepth(root1).ShouldBe(3); + MaxDepth(root2).ShouldBe(2); + } +} diff --git a/LeetCode.CSharp/Problems/MaxProfit.cs b/LeetCode.CSharp/Problems/MaxProfit.cs index 59c5e3c..0b02241 100644 --- a/LeetCode.CSharp/Problems/MaxProfit.cs +++ b/LeetCode.CSharp/Problems/MaxProfit.cs @@ -1,42 +1,42 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Best Time to Buy and Sell Stock", Difficulty.Easy, Category.NotInNeetCode)] - public static int MaxProfit(int[] prices) - { - var left = 0; - var right = 1; - var maxProfit = 0; - - while (right < prices.Length) - { - var buyPrice = prices[left]; - var sellPrice = prices[right]; - - if (buyPrice < sellPrice) - { - var profit = sellPrice - buyPrice; - if (profit > maxProfit) - { - maxProfit = profit; - } - } - else - { - left = right; - } - - right++; - } - - return maxProfit; - } - - [Fact] - public void MaxProfitTest() - { - MaxProfit([7, 1, 5, 3, 6, 4]).ShouldBe(5); - MaxProfit([7, 6, 4, 3, 1]).ShouldBe(0); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Best Time to Buy and Sell Stock", Difficulty.Easy, Category.NotInNeetCode)] + public static int MaxProfit(int[] prices) + { + var left = 0; + var right = 1; + var maxProfit = 0; + + while (right < prices.Length) + { + var buyPrice = prices[left]; + var sellPrice = prices[right]; + + if (buyPrice < sellPrice) + { + var profit = sellPrice - buyPrice; + if (profit > maxProfit) + { + maxProfit = profit; + } + } + else + { + left = right; + } + + right++; + } + + return maxProfit; + } + + [Fact] + public void MaxProfitTest() + { + MaxProfit([7, 1, 5, 3, 6, 4]).ShouldBe(5); + MaxProfit([7, 6, 4, 3, 1]).ShouldBe(0); + } +} diff --git a/LeetCode.CSharp/Problems/MaxSubarrary.cs b/LeetCode.CSharp/Problems/MaxSubarrary.cs index 4cf43dd..06dcc99 100644 --- a/LeetCode.CSharp/Problems/MaxSubarrary.cs +++ b/LeetCode.CSharp/Problems/MaxSubarrary.cs @@ -1,39 +1,39 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Maximum Subarray", - Difficulty.Medium, - Category.Greedy, - "https://www.youtube.com/watch?v=5WZl3MMT0Eg")] - public static int MaxSubarray(int[] nums) - { - var maxSub = nums[0]; - var curSum = 0; - - foreach (var i in nums) - { - // Reset if previous calculation was negative - if (curSum < 0) - { - curSum = 0; - } - curSum += i; - maxSub = Math.Max(curSum, maxSub); - } - - return maxSub; - } - - [Fact] - public void MaxSubarrayTest() - { - var ex1 = new[] { -2, 1, -3, 4, -1, 2, 1, -5, 4 }; - var ex2 = new[] { 1 }; - var ex3 = new[] { 5, 4, -1, 7, 8 }; - - MaxSubarray(ex1).ShouldBe(6); - MaxSubarray(ex2).ShouldBe(1); - MaxSubarray(ex3).ShouldBe(23); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Maximum Subarray", + Difficulty.Medium, + Category.Greedy, + "https://www.youtube.com/watch?v=5WZl3MMT0Eg")] + public static int MaxSubarray(int[] nums) + { + var maxSub = nums[0]; + var curSum = 0; + + foreach (var i in nums) + { + // Reset if previous calculation was negative + if (curSum < 0) + { + curSum = 0; + } + curSum += i; + maxSub = Math.Max(curSum, maxSub); + } + + return maxSub; + } + + [Fact] + public void MaxSubarrayTest() + { + var ex1 = new[] { -2, 1, -3, 4, -1, 2, 1, -5, 4 }; + var ex2 = new[] { 1 }; + var ex3 = new[] { 5, 4, -1, 7, 8 }; + + MaxSubarray(ex1).ShouldBe(6); + MaxSubarray(ex2).ShouldBe(1); + MaxSubarray(ex3).ShouldBe(23); + } +} diff --git a/LeetCode.CSharp/Problems/MaximumWealth.cs b/LeetCode.CSharp/Problems/MaximumWealth.cs index aa43d8e..e0e5bdc 100644 --- a/LeetCode.CSharp/Problems/MaximumWealth.cs +++ b/LeetCode.CSharp/Problems/MaximumWealth.cs @@ -1,28 +1,28 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Richest Customer Wealth", Difficulty.Easy, Category.NotInNeetCode)] - [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] - public static int MaximumWealth(int[][] accounts) => - accounts.Select(account => account.Sum()).Max(); - - [Fact] - public void MaximumWealthTest() - { - var ex1 = new int[][] - { - [1, 2, 3], - [3, 2, 1] - }; - var ex2 = new int[][] - { - [1, 5], - [7, 3], - [3, 5] - }; - - MaximumWealth(ex1).ShouldBe(6); - MaximumWealth(ex2).ShouldBe(10); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Richest Customer Wealth", Difficulty.Easy, Category.NotInNeetCode)] + [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] + public static int MaximumWealth(int[][] accounts) => + accounts.Select(account => account.Sum()).Max(); + + [Fact] + public void MaximumWealthTest() + { + var ex1 = new int[][] + { + [1, 2, 3], + [3, 2, 1] + }; + var ex2 = new int[][] + { + [1, 5], + [7, 3], + [3, 5] + }; + + MaximumWealth(ex1).ShouldBe(6); + MaximumWealth(ex2).ShouldBe(10); + } +} diff --git a/LeetCode.CSharp/Problems/MergeTwoLists.cs b/LeetCode.CSharp/Problems/MergeTwoLists.cs index d5c76da..4b9f102 100644 --- a/LeetCode.CSharp/Problems/MergeTwoLists.cs +++ b/LeetCode.CSharp/Problems/MergeTwoLists.cs @@ -1,53 +1,53 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Merge Two Sorted Lists", - Difficulty.Easy, - Category.LinkedList, - "https://www.youtube.com/watch?v=XIdigk956u0")] - public static ListNode? MergeTwoLists(ListNode? list1, ListNode? list2) - { - var dummy = new ListNode(); - var tail = dummy; - - while (list1 is not null && list2 is not null) - { - if (list1.val < list2.val) - { - tail.next = list1; - list1 = list1.next; - } - else - { - tail.next = list2; - list2 = list2.next; - } - tail = tail.next; - } - - if (list1 is not null) - { - tail.next = list1; - } - else if (list2 is not null) - { - tail.next = list2; - } - - return dummy.next; - } - - [Fact] - public void MergeTwoListsTest() - { - var ex11 = new ListNode([1, 2, 4]); - var ex12 = new ListNode([1, 3, 4]); - var ep1 = new ListNode([1, 1, 2, 3, 4, 4]); - var ex3 = new ListNode(); - - MergeTwoLists(ex11, ex12).ShouldBeEquivalentTo(ep1); - MergeTwoLists(null, null).ShouldBeNull(); - MergeTwoLists(null, ex3).ShouldBeEquivalentTo(ex3); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Merge Two Sorted Lists", + Difficulty.Easy, + Category.LinkedList, + "https://www.youtube.com/watch?v=XIdigk956u0")] + public static ListNode? MergeTwoLists(ListNode? list1, ListNode? list2) + { + var dummy = new ListNode(); + var tail = dummy; + + while (list1 is not null && list2 is not null) + { + if (list1.val < list2.val) + { + tail.next = list1; + list1 = list1.next; + } + else + { + tail.next = list2; + list2 = list2.next; + } + tail = tail.next; + } + + if (list1 is not null) + { + tail.next = list1; + } + else if (list2 is not null) + { + tail.next = list2; + } + + return dummy.next; + } + + [Fact] + public void MergeTwoListsTest() + { + var ex11 = new ListNode([1, 2, 4]); + var ex12 = new ListNode([1, 3, 4]); + var ep1 = new ListNode([1, 1, 2, 3, 4, 4]); + var ex3 = new ListNode(); + + MergeTwoLists(ex11, ex12).ShouldBeEquivalentTo(ep1); + MergeTwoLists(null, null).ShouldBeNull(); + MergeTwoLists(null, ex3).ShouldBeEquivalentTo(ex3); + } +} diff --git a/LeetCode.CSharp/Problems/MiddleNode.cs b/LeetCode.CSharp/Problems/MiddleNode.cs index 21d9baa..7b07020 100644 --- a/LeetCode.CSharp/Problems/MiddleNode.cs +++ b/LeetCode.CSharp/Problems/MiddleNode.cs @@ -1,32 +1,32 @@ -namespace LeetCode.CSharp.Problems; - -using System.Collections.Generic; -using System.Linq; - -public sealed partial class Problem -{ - [LeetCode("Middle of the Linked List", Difficulty.Easy, Category.NotInNeetCode)] - public static ListNode MiddleNode(ListNode head) - { - var list = new List { head }; - while (head.next is not null) - { - head = head.next; - list.Add(head); - } - var skip = list.Count / 2; - return list.Skip(skip).First(); - } - - [Fact] - public void MiddleNodeTest() - { - var single = new ListNode(1); - var even = new ListNode([1, 2, 3, 4]); - var odd = new ListNode([1, 2, 3, 4, 5]); - - MiddleNode(single).ShouldBeSameAs(single); - MiddleNode(even).ShouldBeSameAs(even.next!.next); - MiddleNode(odd).ShouldBeSameAs(odd.next!.next); - } -} +namespace LeetCode.CSharp.Problems; + +using System.Collections.Generic; +using System.Linq; + +public sealed partial class Problem +{ + [LeetCode("Middle of the Linked List", Difficulty.Easy, Category.NotInNeetCode)] + public static ListNode MiddleNode(ListNode head) + { + var list = new List { head }; + while (head.next is not null) + { + head = head.next; + list.Add(head); + } + var skip = list.Count / 2; + return list.Skip(skip).First(); + } + + [Fact] + public void MiddleNodeTest() + { + var single = new ListNode(1); + var even = new ListNode([1, 2, 3, 4]); + var odd = new ListNode([1, 2, 3, 4, 5]); + + MiddleNode(single).ShouldBeSameAs(single); + MiddleNode(even).ShouldBeSameAs(even.next!.next); + MiddleNode(odd).ShouldBeSameAs(odd.next!.next); + } +} diff --git a/LeetCode.CSharp/Problems/MinCostClimbingStairs.cs b/LeetCode.CSharp/Problems/MinCostClimbingStairs.cs index bf32103..d4f88ac 100644 --- a/LeetCode.CSharp/Problems/MinCostClimbingStairs.cs +++ b/LeetCode.CSharp/Problems/MinCostClimbingStairs.cs @@ -1,30 +1,30 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Min Cost Climbing Stairs", - Difficulty.Easy, - Category.OneDDynamicProgramming, - "https://www.youtube.com/watch?v=ktmzAZWkEZ0")] - [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] - public static int MinCostClimbingStairs(int[] cost) - { - // Add zero to end of array with no cost to cater for last step - var minCost = cost.Append(0).ToArray(); - - // Start from the top of the stairs and work backwards to solve each sub-problem - for (var i = minCost.Length - 3; i >= 0; i--) - { - // Memoize the minimum cost to avoid recalculation - minCost[i] += Math.Min(minCost[i + 1], minCost[i + 2]); - } - - return Math.Min(minCost[0], minCost[1]); - } - - [Theory] - [InlineData(new[] { 10, 15, 20 }, 15)] - [InlineData(new[] { 1, 100, 1, 1, 1, 100, 1, 1, 100, 1 }, 6)] - public void MinCostClimbingStairsTest(int[] cost, int expected) => - MinCostClimbingStairs(cost).ShouldBe(expected); -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Min Cost Climbing Stairs", + Difficulty.Easy, + Category.OneDDynamicProgramming, + "https://www.youtube.com/watch?v=ktmzAZWkEZ0")] + [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] + public static int MinCostClimbingStairs(int[] cost) + { + // Add zero to end of array with no cost to cater for last step + var minCost = cost.Append(0).ToArray(); + + // Start from the top of the stairs and work backwards to solve each sub-problem + for (var i = minCost.Length - 3; i >= 0; i--) + { + // Memoize the minimum cost to avoid recalculation + minCost[i] += Math.Min(minCost[i + 1], minCost[i + 2]); + } + + return Math.Min(minCost[0], minCost[1]); + } + + [Theory] + [InlineData(new[] { 10, 15, 20 }, 15)] + [InlineData(new[] { 1, 100, 1, 1, 1, 100, 1, 1, 100, 1 }, 6)] + public void MinCostClimbingStairsTest(int[] cost, int expected) => + MinCostClimbingStairs(cost).ShouldBe(expected); +} diff --git a/LeetCode.CSharp/Problems/MissingNumber.cs b/LeetCode.CSharp/Problems/MissingNumber.cs index 7934785..8753124 100644 --- a/LeetCode.CSharp/Problems/MissingNumber.cs +++ b/LeetCode.CSharp/Problems/MissingNumber.cs @@ -1,25 +1,25 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode( - "Missing Number", - Difficulty.Easy, - Category.BitManipulation, - "https://www.youtube.com/watch?v=WnPLSRLSANE")] - [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] - public static int MissingNumber(int[] nums) => - nums.Length + Enumerable.Range(0, nums.Length).Sum(i => i - nums[i]); - - [Fact] - public void MissingNumberTest() - { - var ex1 = new[] { 3, 0, 1 }; - var ex2 = new[] { 0, 1 }; - var ex3 = new[] { 9, 6, 4, 2, 3, 5, 7, 0, 1 }; - - MissingNumber(ex1).ShouldBe(2); - MissingNumber(ex2).ShouldBe(2); - MissingNumber(ex3).ShouldBe(8); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode( + "Missing Number", + Difficulty.Easy, + Category.BitManipulation, + "https://www.youtube.com/watch?v=WnPLSRLSANE")] + [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] + public static int MissingNumber(int[] nums) => + nums.Length + Enumerable.Range(0, nums.Length).Sum(i => i - nums[i]); + + [Fact] + public void MissingNumberTest() + { + var ex1 = new[] { 3, 0, 1 }; + var ex2 = new[] { 0, 1 }; + var ex3 = new[] { 9, 6, 4, 2, 3, 5, 7, 0, 1 }; + + MissingNumber(ex1).ShouldBe(2); + MissingNumber(ex2).ShouldBe(2); + MissingNumber(ex3).ShouldBe(8); + } +} diff --git a/LeetCode.CSharp/Problems/NumIslands.cs b/LeetCode.CSharp/Problems/NumIslands.cs index 6922c44..9c27676 100644 --- a/LeetCode.CSharp/Problems/NumIslands.cs +++ b/LeetCode.CSharp/Problems/NumIslands.cs @@ -1,121 +1,121 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Number of Islands", - Difficulty.Medium, - Category.Graphs, - "https://www.youtube.com/watch?v=pV2kpPD66nE")] - public static int NumIslands(char[][]? grid) - { - if (grid is null || grid.Length == 0) - { - return 0; - } - - const char sea = '0'; - var rows = grid.Length; - var columns = grid[0].Length; - var visited = new HashSet<(int, int)>(); - var queue = new Queue<(int, int)>(); - var directions = new - { - Up = (1, 0), - Left = (-1, 0), - Right = (0, 1), - Down = (0, -1) - }; - - var islands = 0; - - for (var row = 0; row < rows; row++) - { - for (var column = 0; column < columns; column++) - { - if (grid[row][column] == sea) - { - continue; - } - - var position = (row, column); - if (visited.Contains(position)) - { - continue; - } - - BreadthFirstSearch(position); - - islands++; - } - } - - return islands; - - void TestDirection((int row, int column) position, (int row, int column) direction) - { - var row = position.row + direction.row; - var column = position.column + direction.column; - if (row < 0 || row >= rows || column < 0 || column >= columns) - { - // Out of map infers sea - return; - } - - if (grid[row][column] == sea) - { - return; - } - - var testDirection = (row, column); - if (!visited.Add(testDirection)) - { - return; - } - - // Non-visited land found - queue.Enqueue(testDirection); - } - - void BreadthFirstSearch((int, int) position) - { - // Position is guaranteed to be land - visited.Add(position); - - // Add to position to be searched in all directions - queue.Enqueue(position); - - while (queue.Count != 0) - { - var test = queue.Dequeue(); - TestDirection(test, directions.Up); - TestDirection(test, directions.Left); - TestDirection(test, directions.Right); - TestDirection(test, directions.Down); - } - } - } - - [Fact] - public void NumIslandsTest() - { - var ex1 = new char[][] - { - ['1', '1', '1', '1', '0'], - ['1', '1', '0', '1', '0'], - ['1', '1', '0', '0', '0'], - ['0', '0', '0', '0', '0'] - }; - var ex2 = new char[][] - { - ['1', '1', '0', '0', '0'], - ['1', '1', '0', '0', '0'], - ['0', '0', '1', '0', '0'], - ['0', '0', '0', '1', '1'] - }; - - NumIslands(null).ShouldBe(0); - NumIslands([]).ShouldBe(0); - NumIslands(ex1).ShouldBe(1); - NumIslands(ex2).ShouldBe(3); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Number of Islands", + Difficulty.Medium, + Category.Graphs, + "https://www.youtube.com/watch?v=pV2kpPD66nE")] + public static int NumIslands(char[][]? grid) + { + if (grid is null || grid.Length == 0) + { + return 0; + } + + const char sea = '0'; + var rows = grid.Length; + var columns = grid[0].Length; + var visited = new HashSet<(int, int)>(); + var queue = new Queue<(int, int)>(); + var directions = new + { + Up = (1, 0), + Left = (-1, 0), + Right = (0, 1), + Down = (0, -1) + }; + + var islands = 0; + + for (var row = 0; row < rows; row++) + { + for (var column = 0; column < columns; column++) + { + if (grid[row][column] == sea) + { + continue; + } + + var position = (row, column); + if (visited.Contains(position)) + { + continue; + } + + BreadthFirstSearch(position); + + islands++; + } + } + + return islands; + + void TestDirection((int row, int column) position, (int row, int column) direction) + { + var row = position.row + direction.row; + var column = position.column + direction.column; + if (row < 0 || row >= rows || column < 0 || column >= columns) + { + // Out of map infers sea + return; + } + + if (grid[row][column] == sea) + { + return; + } + + var testDirection = (row, column); + if (!visited.Add(testDirection)) + { + return; + } + + // Non-visited land found + queue.Enqueue(testDirection); + } + + void BreadthFirstSearch((int, int) position) + { + // Position is guaranteed to be land + visited.Add(position); + + // Add to position to be searched in all directions + queue.Enqueue(position); + + while (queue.Count != 0) + { + var test = queue.Dequeue(); + TestDirection(test, directions.Up); + TestDirection(test, directions.Left); + TestDirection(test, directions.Right); + TestDirection(test, directions.Down); + } + } + } + + [Fact] + public void NumIslandsTest() + { + var ex1 = new char[][] + { + ['1', '1', '1', '1', '0'], + ['1', '1', '0', '1', '0'], + ['1', '1', '0', '0', '0'], + ['0', '0', '0', '0', '0'] + }; + var ex2 = new char[][] + { + ['1', '1', '0', '0', '0'], + ['1', '1', '0', '0', '0'], + ['0', '0', '1', '0', '0'], + ['0', '0', '0', '1', '1'] + }; + + NumIslands(null).ShouldBe(0); + NumIslands([]).ShouldBe(0); + NumIslands(ex1).ShouldBe(1); + NumIslands(ex2).ShouldBe(3); + } +} diff --git a/LeetCode.CSharp/Problems/NumberOfSteps.cs b/LeetCode.CSharp/Problems/NumberOfSteps.cs index 53e9911..b90b12b 100644 --- a/LeetCode.CSharp/Problems/NumberOfSteps.cs +++ b/LeetCode.CSharp/Problems/NumberOfSteps.cs @@ -1,36 +1,36 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Number of Steps to Reduce a Number to Zero", - Difficulty.Easy, - Category.NotInNeetCode)] - public static int NumberOfSteps(int num) - { - var steps = 0; - - while (num != 0) - { - steps++; - - if (num % 2 == 0) - { - num /= 2; - } - else - { - num -= 1; - } - } - - return steps; - } - - [Fact] - public void NumberOfStepsTest() - { - NumberOfSteps(14).ShouldBe(6); - NumberOfSteps(8).ShouldBe(4); - NumberOfSteps(123).ShouldBe(12); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Number of Steps to Reduce a Number to Zero", + Difficulty.Easy, + Category.NotInNeetCode)] + public static int NumberOfSteps(int num) + { + var steps = 0; + + while (num != 0) + { + steps++; + + if (num % 2 == 0) + { + num /= 2; + } + else + { + num -= 1; + } + } + + return steps; + } + + [Fact] + public void NumberOfStepsTest() + { + NumberOfSteps(14).ShouldBe(6); + NumberOfSteps(8).ShouldBe(4); + NumberOfSteps(123).ShouldBe(12); + } +} diff --git a/LeetCode.CSharp/Problems/PlusOne.cs b/LeetCode.CSharp/Problems/PlusOne.cs index 74d40c4..b2c0027 100644 --- a/LeetCode.CSharp/Problems/PlusOne.cs +++ b/LeetCode.CSharp/Problems/PlusOne.cs @@ -1,58 +1,58 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Plus One", - Difficulty.Easy, - Category.MathAndGeometry, - "https://www.youtube.com/watch?v=jIaA8boiG1s")] - [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] - public static int[] PlusOne(int[] digits) - { - var list = digits.Reverse().ToList(); - var carry = 1; - var i = 0; - - while (carry == 1) - { - if (i < list.Count) - { - if (list[i] == 9) - { - list[i] = 0; - carry = 1; - } - else - { - list[i] += 1; - carry = 0; - } - } - else - { - list.Add(1); - carry = 0; - } - - i++; - } - - list.Reverse(); - - return [.. list]; - } - - [Fact] - public void PlusOneTest() - { - var ex1 = new[] { 1, 2, 3 }; - var ex2 = new[] { 4, 3, 2, 1 }; - var ex3 = new[] { 9 }; - var ex4 = new[] { 9, 9 }; - - PlusOne(ex1).ShouldBe([1, 2, 4]); - PlusOne(ex2).ShouldBe([4, 3, 2, 2]); - PlusOne(ex3).ShouldBe([1, 0]); - PlusOne(ex4).ShouldBe([1, 0, 0]); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Plus One", + Difficulty.Easy, + Category.MathAndGeometry, + "https://www.youtube.com/watch?v=jIaA8boiG1s")] + [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] + public static int[] PlusOne(int[] digits) + { + var list = digits.Reverse().ToList(); + var carry = 1; + var i = 0; + + while (carry == 1) + { + if (i < list.Count) + { + if (list[i] == 9) + { + list[i] = 0; + carry = 1; + } + else + { + list[i] += 1; + carry = 0; + } + } + else + { + list.Add(1); + carry = 0; + } + + i++; + } + + list.Reverse(); + + return [.. list]; + } + + [Fact] + public void PlusOneTest() + { + var ex1 = new[] { 1, 2, 3 }; + var ex2 = new[] { 4, 3, 2, 1 }; + var ex3 = new[] { 9 }; + var ex4 = new[] { 9, 9 }; + + PlusOne(ex1).ShouldBe([1, 2, 4]); + PlusOne(ex2).ShouldBe([4, 3, 2, 2]); + PlusOne(ex3).ShouldBe([1, 0]); + PlusOne(ex4).ShouldBe([1, 0, 0]); + } +} diff --git a/LeetCode.CSharp/Problems/ProductExceptSelf.cs b/LeetCode.CSharp/Problems/ProductExceptSelf.cs index d77c304..4bd75b1 100644 --- a/LeetCode.CSharp/Problems/ProductExceptSelf.cs +++ b/LeetCode.CSharp/Problems/ProductExceptSelf.cs @@ -1,47 +1,47 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Product of Array Except Self", - Difficulty.Medium, - Category.ArraysAndHashing, - "https://www.youtube.com/watch?v=bNvIQI2wAjk")] - public static int[] ProductExceptSelf(int[] nums) - { - var length = nums.Length; - if (length == 0) return nums; - - var prefix = 1; - var productArray = new int[length]; - - for (var i = 0; i < length; i++) - { - productArray[i] = prefix; - prefix *= nums[i]; - } - - var postfix = 1; - - for (var i = length - 1; i >= 0; i--) - { - productArray[i] *= postfix; - postfix *= nums[i]; - } - - return productArray; - } - - [Fact] - public void ProductExceptSelfTest() - { - var ex1 = new[] { 1, 2, 3, 4 }; - var ex1Expected = new[] { 24, 12, 8, 6 }; - var ex2 = new[] { -1, 1, 0, -3, 3 }; - var ex2Expected = new[] { 0, 0, 9, 0, 0 }; - var ex3 = Array.Empty(); - - ProductExceptSelf(ex1).ShouldBe(ex1Expected); - ProductExceptSelf(ex2).ShouldBe(ex2Expected); - ProductExceptSelf(ex3).ShouldBe(ex3); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Product of Array Except Self", + Difficulty.Medium, + Category.ArraysAndHashing, + "https://www.youtube.com/watch?v=bNvIQI2wAjk")] + public static int[] ProductExceptSelf(int[] nums) + { + var length = nums.Length; + if (length == 0) return nums; + + var prefix = 1; + var productArray = new int[length]; + + for (var i = 0; i < length; i++) + { + productArray[i] = prefix; + prefix *= nums[i]; + } + + var postfix = 1; + + for (var i = length - 1; i >= 0; i--) + { + productArray[i] *= postfix; + postfix *= nums[i]; + } + + return productArray; + } + + [Fact] + public void ProductExceptSelfTest() + { + var ex1 = new[] { 1, 2, 3, 4 }; + var ex1Expected = new[] { 24, 12, 8, 6 }; + var ex2 = new[] { -1, 1, 0, -3, 3 }; + var ex2Expected = new[] { 0, 0, 9, 0, 0 }; + var ex3 = Array.Empty(); + + ProductExceptSelf(ex1).ShouldBe(ex1Expected); + ProductExceptSelf(ex2).ShouldBe(ex2Expected); + ProductExceptSelf(ex3).ShouldBe(ex3); + } +} diff --git a/LeetCode.CSharp/Problems/RansomNote.cs b/LeetCode.CSharp/Problems/RansomNote.cs index dc783c5..1bceeb7 100644 --- a/LeetCode.CSharp/Problems/RansomNote.cs +++ b/LeetCode.CSharp/Problems/RansomNote.cs @@ -1,50 +1,50 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Ransom Note", Difficulty.Easy, Category.NotInNeetCode)] - public static bool RansomNote(string ransomNote, string magazine) - { - var frequency = new Dictionary(); - - foreach (var mc in magazine) - { - if (!frequency.TryGetValue(mc, out var value)) - { - frequency.Add(mc, 1); - } - else - { - frequency[mc] = ++value; - } - } - - foreach (var rc in ransomNote) - { - if (!frequency.TryGetValue(rc, out var value) || value == 0) - { - return false; - } - - frequency[rc] = --value; - } - - return true; - } - - [Fact] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public void RansomNoteTest() - { - const string m1 = "a"; - const string r1 = "b"; - const string m2 = "aa"; - const string r2 = "ab"; - const string r3 = "bg"; - const string m3 = "aabefjbdfbdgfjhhaiigfhbaejahgfbbgbjagbddfgdiaigdadhcfcj"; - - RansomNote(r1, m1).ShouldBeFalse(); - RansomNote(r2, m2).ShouldBeFalse(); - RansomNote(r3, m3).ShouldBeTrue(); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Ransom Note", Difficulty.Easy, Category.NotInNeetCode)] + public static bool RansomNote(string ransomNote, string magazine) + { + var frequency = new Dictionary(); + + foreach (var mc in magazine) + { + if (!frequency.TryGetValue(mc, out var value)) + { + frequency.Add(mc, 1); + } + else + { + frequency[mc] = ++value; + } + } + + foreach (var rc in ransomNote) + { + if (!frequency.TryGetValue(rc, out var value) || value == 0) + { + return false; + } + + frequency[rc] = --value; + } + + return true; + } + + [Fact] + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public void RansomNoteTest() + { + const string m1 = "a"; + const string r1 = "b"; + const string m2 = "aa"; + const string r2 = "ab"; + const string r3 = "bg"; + const string m3 = "aabefjbdfbdgfjhhaiigfhbaejahgfbbgbjagbddfgdiaigdadhcfcj"; + + RansomNote(r1, m1).ShouldBeFalse(); + RansomNote(r2, m2).ShouldBeFalse(); + RansomNote(r3, m3).ShouldBeTrue(); + } +} diff --git a/LeetCode.CSharp/Problems/ReverseBits.cs b/LeetCode.CSharp/Problems/ReverseBits.cs index d12eb23..77a880c 100644 --- a/LeetCode.CSharp/Problems/ReverseBits.cs +++ b/LeetCode.CSharp/Problems/ReverseBits.cs @@ -1,31 +1,31 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Reverse Bits", - Difficulty.Easy, - Category.BitManipulation, - "https://www.youtube.com/watch?v=UcoN6UjAI64")] - public static uint ReverseBits(uint n) - { - uint result = 0; - - for (var i = 0; i < 32; i++) - { - var bit = n >> i & 1; - result |= bit << 31 - i; - } - - return result; - } - - [Fact] - public void ReverseBitsTest() - { - const uint ex1 = 0b00000010100101000001111010011100; - const uint ex2 = 0b11111111111111111111111111111101; - - ReverseBits(ex1).ShouldBe(0b00111001011110000010100101000000U); - ReverseBits(ex2).ShouldBe(0b10111111111111111111111111111111U); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Reverse Bits", + Difficulty.Easy, + Category.BitManipulation, + "https://www.youtube.com/watch?v=UcoN6UjAI64")] + public static uint ReverseBits(uint n) + { + uint result = 0; + + for (var i = 0; i < 32; i++) + { + var bit = n >> i & 1; + result |= bit << 31 - i; + } + + return result; + } + + [Fact] + public void ReverseBitsTest() + { + const uint ex1 = 0b00000010100101000001111010011100; + const uint ex2 = 0b11111111111111111111111111111101; + + ReverseBits(ex1).ShouldBe(0b00111001011110000010100101000000U); + ReverseBits(ex2).ShouldBe(0b10111111111111111111111111111111U); + } +} diff --git a/LeetCode.CSharp/Problems/ReverseList.cs b/LeetCode.CSharp/Problems/ReverseList.cs index 1eede02..95d47fb 100644 --- a/LeetCode.CSharp/Problems/ReverseList.cs +++ b/LeetCode.CSharp/Problems/ReverseList.cs @@ -1,38 +1,38 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Reverse Linked List", - Difficulty.Easy, - Category.LinkedList, - "https://www.youtube.com/watch?v=G0_I-ZF0S38")] - public static ListNode? ReverseList(ListNode? head) - { - ListNode? previous = null; - var current = head; - - while (current is not null) - { - var next = current.next; - current.next = previous; - previous = current; - current = next; - } - - return previous; - } - - [Fact] - public void ReverseListTest() - { - var ex1 = new ListNode([1, 2, 3, 4, 5]); - var ep1 = new ListNode([5, 4, 3, 2, 1]); - var ex2 = new ListNode(1, new ListNode(2)); - var ep2 = new ListNode(2, new ListNode(1)); - ListNode? ex3 = null; - - ReverseList(ex1).ShouldBeEquivalentTo(ep1); - ReverseList(ex2).ShouldBeEquivalentTo(ep2); - ReverseList(ex3).ShouldBeNull(); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Reverse Linked List", + Difficulty.Easy, + Category.LinkedList, + "https://www.youtube.com/watch?v=G0_I-ZF0S38")] + public static ListNode? ReverseList(ListNode? head) + { + ListNode? previous = null; + var current = head; + + while (current is not null) + { + var next = current.next; + current.next = previous; + previous = current; + current = next; + } + + return previous; + } + + [Fact] + public void ReverseListTest() + { + var ex1 = new ListNode([1, 2, 3, 4, 5]); + var ep1 = new ListNode([5, 4, 3, 2, 1]); + var ex2 = new ListNode(1, new ListNode(2)); + var ep2 = new ListNode(2, new ListNode(1)); + ListNode? ex3 = null; + + ReverseList(ex1).ShouldBeEquivalentTo(ep1); + ReverseList(ex2).ShouldBeEquivalentTo(ep2); + ReverseList(ex3).ShouldBeNull(); + } +} diff --git a/LeetCode.CSharp/Problems/RomanToInt.cs b/LeetCode.CSharp/Problems/RomanToInt.cs index 75ae20e..4c74c7d 100644 --- a/LeetCode.CSharp/Problems/RomanToInt.cs +++ b/LeetCode.CSharp/Problems/RomanToInt.cs @@ -1,51 +1,51 @@ -namespace LeetCode.CSharp.Problems; - -using System.Collections.Generic; - -public sealed partial class Problem -{ - [LeetCode("Roman to Integer", Difficulty.Easy, Category.NotInNeetCode)] - public static int RomanToInt(string s) - { - var romanValues = new Dictionary - { - { 'I', 1 }, - { 'V', 5 }, - { 'X', 10 }, - { 'L', 50 }, - { 'C', 100 }, - { 'D', 500 }, - { 'M', 1_000 } - }; - var result = 0; - var length = s.Length - 1; - - for (var i = length; i >= 0; i--) - { - var romanCharAsInt = romanValues[s[i]]; - - if (i < length) - { - result = romanCharAsInt >= romanValues[s[i + 1]] - ? result + romanCharAsInt - : result - romanCharAsInt; - } - else - { - result += romanCharAsInt; - } - } - - return result; - } - - [Fact] - [SuppressMessage("ReSharper", "StringLiteralTypo")] - public void RomanToIntTest() - { - RomanToInt("III").ShouldBe(3); - RomanToInt("LVIII").ShouldBe(58); - RomanToInt("MCMXCIV").ShouldBe(1994); - RomanToInt("MMXXII").ShouldBe(2022); - } -} +namespace LeetCode.CSharp.Problems; + +using System.Collections.Generic; + +public sealed partial class Problem +{ + [LeetCode("Roman to Integer", Difficulty.Easy, Category.NotInNeetCode)] + public static int RomanToInt(string s) + { + var romanValues = new Dictionary + { + { 'I', 1 }, + { 'V', 5 }, + { 'X', 10 }, + { 'L', 50 }, + { 'C', 100 }, + { 'D', 500 }, + { 'M', 1_000 } + }; + var result = 0; + var length = s.Length - 1; + + for (var i = length; i >= 0; i--) + { + var romanCharAsInt = romanValues[s[i]]; + + if (i < length) + { + result = romanCharAsInt >= romanValues[s[i + 1]] + ? result + romanCharAsInt + : result - romanCharAsInt; + } + else + { + result += romanCharAsInt; + } + } + + return result; + } + + [Fact] + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public void RomanToIntTest() + { + RomanToInt("III").ShouldBe(3); + RomanToInt("LVIII").ShouldBe(58); + RomanToInt("MCMXCIV").ShouldBe(1994); + RomanToInt("MMXXII").ShouldBe(2022); + } +} diff --git a/LeetCode.CSharp/Problems/SingleNumber.cs b/LeetCode.CSharp/Problems/SingleNumber.cs index 3ba563d..6d9a641 100644 --- a/LeetCode.CSharp/Problems/SingleNumber.cs +++ b/LeetCode.CSharp/Problems/SingleNumber.cs @@ -1,23 +1,23 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Single Number", - Difficulty.Easy, - Category.BitManipulation, - "https://www.youtube.com/watch?v=qMPX1AOa83k")] - [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] - public static int SingleNumber(int[] digits) => digits.Aggregate((x, y) => x ^ y); - - [Fact] - public void SingleNumberTest() - { - var ex1 = new[] { 2, 2, 1 }; - var ex2 = new[] { 4, 1, 2, 1, 2 }; - var ex3 = new[] { 1 }; - - SingleNumber(ex1).ShouldBe(1); - SingleNumber(ex2).ShouldBe(4); - SingleNumber(ex3).ShouldBe(1); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Single Number", + Difficulty.Easy, + Category.BitManipulation, + "https://www.youtube.com/watch?v=qMPX1AOa83k")] + [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] + public static int SingleNumber(int[] digits) => digits.Aggregate((x, y) => x ^ y); + + [Fact] + public void SingleNumberTest() + { + var ex1 = new[] { 2, 2, 1 }; + var ex2 = new[] { 4, 1, 2, 1, 2 }; + var ex3 = new[] { 1 }; + + SingleNumber(ex1).ShouldBe(1); + SingleNumber(ex2).ShouldBe(4); + SingleNumber(ex3).ShouldBe(1); + } +} diff --git a/LeetCode.CSharp/Problems/Subsets.cs b/LeetCode.CSharp/Problems/Subsets.cs index 716b579..ab270c0 100644 --- a/LeetCode.CSharp/Problems/Subsets.cs +++ b/LeetCode.CSharp/Problems/Subsets.cs @@ -1,66 +1,66 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Subsets", - Difficulty.Medium, - Category.BackTracking, - "https://www.youtube.com/watch?v=REOH22Xwdkk")] - public static IList> Subsets(int[] nums) - { - var subsets = new List>(); - var subset = new List(); - - DepthFirstSearch(0); - - return subsets; - - // NeetCode explanation: https://youtu.be/REOH22Xwdkk?t=163 - void DepthFirstSearch(int index) - { - if (index >= nums.Length) - { - // Add copy to result as reached end of leaf nodes - subsets.Add([.. subset]); - return; - } - - // Add current item and continue backtracking - subset.Add(nums[index]); - DepthFirstSearch(index + 1); - - // Remove current item and continue backtracking - subset.Remove(nums[index]); - - // ReSharper disable once TailRecursiveCall - // For clarity - minimal difference found in benchmark - DepthFirstSearch(index + 1); - } - } - - [Fact] - public void SubsetsTest() - { - var ex1 = new[] { 1, 2, 3 }; - var ep1 = new List> - { - new List { 1, 2, 3 }, - new List { 1, 2 }, - new List { 1, 3 }, - new List { 1 }, - new List { 2, 3 }, - new List { 2 }, - new List { 3 }, - new List() - }; - var ex2 = new[] { 0 }; - var ep2 = new List> - { - new List{ 0 }, - new List() - }; - - Subsets(ex1).ShouldBe(ep1); - Subsets(ex2).ShouldBe(ep2); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Subsets", + Difficulty.Medium, + Category.BackTracking, + "https://www.youtube.com/watch?v=REOH22Xwdkk")] + public static IList> Subsets(int[] nums) + { + var subsets = new List>(); + var subset = new List(); + + DepthFirstSearch(0); + + return subsets; + + // NeetCode explanation: https://youtu.be/REOH22Xwdkk?t=163 + void DepthFirstSearch(int index) + { + if (index >= nums.Length) + { + // Add copy to result as reached end of leaf nodes + subsets.Add([.. subset]); + return; + } + + // Add current item and continue backtracking + subset.Add(nums[index]); + DepthFirstSearch(index + 1); + + // Remove current item and continue backtracking + subset.Remove(nums[index]); + + // ReSharper disable once TailRecursiveCall + // For clarity - minimal difference found in benchmark + DepthFirstSearch(index + 1); + } + } + + [Fact] + public void SubsetsTest() + { + var ex1 = new[] { 1, 2, 3 }; + var ep1 = new List> + { + new List { 1, 2, 3 }, + new List { 1, 2 }, + new List { 1, 3 }, + new List { 1 }, + new List { 2, 3 }, + new List { 2 }, + new List { 3 }, + new List() + }; + var ex2 = new[] { 0 }; + var ep2 = new List> + { + new List{ 0 }, + new List() + }; + + Subsets(ex1).ShouldBe(ep1); + Subsets(ex2).ShouldBe(ep2); + } +} diff --git a/LeetCode.CSharp/Problems/TopKFrequent.cs b/LeetCode.CSharp/Problems/TopKFrequent.cs index 4275801..a4ca2cd 100644 --- a/LeetCode.CSharp/Problems/TopKFrequent.cs +++ b/LeetCode.CSharp/Problems/TopKFrequent.cs @@ -1,72 +1,72 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Top K Frequent Elements", - Difficulty.Medium, - Category.ArraysAndHashing, - "https://www.youtube.com/watch?v=YPTqKIgVk-k")] - [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] - public static int[] TopKFrequent(int[] nums, int k) - { - // Benchmarking showed setting capacity to maximum resulted in faster execution and around - // half the memory allocation for large length of nums - var frequency = new Dictionary(nums.Length); - - foreach (var num in nums) - { - // ContainsKey will warn on CA1854 and benchmarking showed virtually no difference - if (frequency.TryGetValue(num, out _)) - { - frequency[num]++; - } - else - { - frequency.Add(num, 1); - } - } - - // Benchmarking showed linq solution around twice as slow but slightly more memory efficient - // return dictionary - // .OrderByDescending(n => n.Value) - // .Take(k) - // .Select(n => n.Key) - // .ToArray(); - - var sortedFrequency = new PriorityQueue(frequency.Count); - - foreach (var kvp in frequency) - { - sortedFrequency.Enqueue(kvp.Key, kvp.Value); - - // Remove unwanted result after sorting is done - if (sortedFrequency.Count > k) - { - sortedFrequency.Dequeue(); - } - } - - var result = new int[k]; - - // Loop backwards as priority queue dequeues lowest frequencies first - for (var i = sortedFrequency.Count - 1; i >= 0; i--) - { - result[i] = sortedFrequency.Dequeue(); - } - - return result; - } - - [Fact] - public void TopKFrequentTest() - { - var ex1 = new[] { 1, 1, 1, 2, 2, 3 }; - var ex1Expected = new[] { 1, 2 }; - var ex2 = new[] { 1 }; - var ex3 = Array.Empty(); - - TopKFrequent(ex1, 2).ShouldBe(ex1Expected); - TopKFrequent(ex2, 1).ShouldBe(ex2); - TopKFrequent(ex3, 0).ShouldBe(ex3); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Top K Frequent Elements", + Difficulty.Medium, + Category.ArraysAndHashing, + "https://www.youtube.com/watch?v=YPTqKIgVk-k")] + [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] + public static int[] TopKFrequent(int[] nums, int k) + { + // Benchmarking showed setting capacity to maximum resulted in faster execution and around + // half the memory allocation for large length of nums + var frequency = new Dictionary(nums.Length); + + foreach (var num in nums) + { + // ContainsKey will warn on CA1854 and benchmarking showed virtually no difference + if (frequency.TryGetValue(num, out _)) + { + frequency[num]++; + } + else + { + frequency.Add(num, 1); + } + } + + // Benchmarking showed linq solution around twice as slow but slightly more memory efficient + // return dictionary + // .OrderByDescending(n => n.Value) + // .Take(k) + // .Select(n => n.Key) + // .ToArray(); + + var sortedFrequency = new PriorityQueue(frequency.Count); + + foreach (var kvp in frequency) + { + sortedFrequency.Enqueue(kvp.Key, kvp.Value); + + // Remove unwanted result after sorting is done + if (sortedFrequency.Count > k) + { + sortedFrequency.Dequeue(); + } + } + + var result = new int[k]; + + // Loop backwards as priority queue dequeues lowest frequencies first + for (var i = sortedFrequency.Count - 1; i >= 0; i--) + { + result[i] = sortedFrequency.Dequeue(); + } + + return result; + } + + [Fact] + public void TopKFrequentTest() + { + var ex1 = new[] { 1, 1, 1, 2, 2, 3 }; + var ex1Expected = new[] { 1, 2 }; + var ex2 = new[] { 1 }; + var ex3 = Array.Empty(); + + TopKFrequent(ex1, 2).ShouldBe(ex1Expected); + TopKFrequent(ex2, 1).ShouldBe(ex2); + TopKFrequent(ex3, 0).ShouldBe(ex3); + } +} diff --git a/LeetCode.CSharp/Problems/Trie.cs b/LeetCode.CSharp/Problems/Trie.cs index 1c62863..790900e 100644 --- a/LeetCode.CSharp/Problems/Trie.cs +++ b/LeetCode.CSharp/Problems/Trie.cs @@ -1,83 +1,83 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Implement Trie (Prefix Tree)", - Difficulty.Medium, - Category.Tries, - "https://www.youtube.com/watch?v=oobqoCJlHA0")] - public class Trie - { - public Trie() - { - Root = new TrieChild(); - } - - private TrieChild Root { get; } - - public void Insert(string word) - { - var current = Root; - - foreach (var c in word) - { - current.Children.TryAdd(c, new TrieChild()); - current = current.Children[c]; - } - - current.EndOfWord = true; - } - - public bool Search(string word) - { - var current = Root; - - foreach (var c in word) - { - if (!current.Children.TryGetValue(c, out var value)) - { - return false; - } - current = value; - } - - return current.EndOfWord; - } - - public bool StartsWith(string prefix) - { - var current = Root; - - foreach (var c in prefix) - { - if (!current.Children.TryGetValue(c, out var value)) - { - return false; - } - current = value; - } - - return true; - } - } - - public record TrieChild - { - public Dictionary Children { get; } = []; - public bool EndOfWord { get; set; } - } - - [Fact] - public void TrieTest() - { - var trie = new Trie(); - - trie.Insert("apple"); - trie.Search("apple").ShouldBeTrue(); - trie.Search("app").ShouldBeFalse(); - trie.StartsWith("app").ShouldBeTrue(); - - trie.Insert("app"); - trie.Search("app").ShouldBeTrue(); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Implement Trie (Prefix Tree)", + Difficulty.Medium, + Category.Tries, + "https://www.youtube.com/watch?v=oobqoCJlHA0")] + public class Trie + { + public Trie() + { + Root = new TrieChild(); + } + + private TrieChild Root { get; } + + public void Insert(string word) + { + var current = Root; + + foreach (var c in word) + { + current.Children.TryAdd(c, new TrieChild()); + current = current.Children[c]; + } + + current.EndOfWord = true; + } + + public bool Search(string word) + { + var current = Root; + + foreach (var c in word) + { + if (!current.Children.TryGetValue(c, out var value)) + { + return false; + } + current = value; + } + + return current.EndOfWord; + } + + public bool StartsWith(string prefix) + { + var current = Root; + + foreach (var c in prefix) + { + if (!current.Children.TryGetValue(c, out var value)) + { + return false; + } + current = value; + } + + return true; + } + } + + public record TrieChild + { + public Dictionary Children { get; } = []; + public bool EndOfWord { get; set; } + } + + [Fact] + public void TrieTest() + { + var trie = new Trie(); + + trie.Insert("apple"); + trie.Search("apple").ShouldBeTrue(); + trie.Search("app").ShouldBeFalse(); + trie.StartsWith("app").ShouldBeTrue(); + + trie.Insert("app"); + trie.Search("app").ShouldBeTrue(); + } +} diff --git a/LeetCode.CSharp/Problems/TwoSum.cs b/LeetCode.CSharp/Problems/TwoSum.cs index 6f760e6..1247907 100644 --- a/LeetCode.CSharp/Problems/TwoSum.cs +++ b/LeetCode.CSharp/Problems/TwoSum.cs @@ -1,43 +1,43 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Two Sum", - Difficulty.Easy, - Category.ArraysAndHashing, - "https://www.youtube.com/watch?v=KLlXCFG5TnA")] - public static int[] TwoSum(int[] nums, int target) - { - if (nums.Length < 2) - { - throw new ArgumentOutOfRangeException(nameof(nums)); - } - for (var i = 0; i < nums.Length; i++) - { - // Test all remaining indexes for target match - for (var j = i + 1; j < nums.Length; j++) - { - if (nums[i] + nums[j] == target) - { - return [i, j]; - } - } - } - throw new ArgumentOutOfRangeException(nameof(target)); - } - - [Fact] - public void TwoSumTest() - { - var ex1 = new[] { 2, 7, 11, 15 }; - var ex2 = new[] { 3, 2, 4 }; - var ex3 = new[] { 3, 3 }; - var ex4 = new[] { 3 }; - - TwoSum(ex1, 9).ShouldBe([0, 1]); - TwoSum(ex2, 6).ShouldBe([1, 2]); - TwoSum(ex3, 6).ShouldBe([0, 1]); - var action = () => TwoSum(ex4, 0); - action.ShouldThrow(); - } -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Two Sum", + Difficulty.Easy, + Category.ArraysAndHashing, + "https://www.youtube.com/watch?v=KLlXCFG5TnA")] + public static int[] TwoSum(int[] nums, int target) + { + if (nums.Length < 2) + { + throw new ArgumentOutOfRangeException(nameof(nums)); + } + for (var i = 0; i < nums.Length; i++) + { + // Test all remaining indexes for target match + for (var j = i + 1; j < nums.Length; j++) + { + if (nums[i] + nums[j] == target) + { + return [i, j]; + } + } + } + throw new ArgumentOutOfRangeException(nameof(target)); + } + + [Fact] + public void TwoSumTest() + { + var ex1 = new[] { 2, 7, 11, 15 }; + var ex2 = new[] { 3, 2, 4 }; + var ex3 = new[] { 3, 3 }; + var ex4 = new[] { 3 }; + + TwoSum(ex1, 9).ShouldBe([0, 1]); + TwoSum(ex2, 6).ShouldBe([1, 2]); + TwoSum(ex3, 6).ShouldBe([0, 1]); + var action = () => TwoSum(ex4, 0); + action.ShouldThrow(); + } +} diff --git a/LeetCode.CSharp/Problems/UniquePaths.cs b/LeetCode.CSharp/Problems/UniquePaths.cs index d802c30..f24210b 100644 --- a/LeetCode.CSharp/Problems/UniquePaths.cs +++ b/LeetCode.CSharp/Problems/UniquePaths.cs @@ -1,49 +1,49 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Unique Paths", - Difficulty.Medium, - Category.TwoDDynamicProgramming, - "https://www.youtube.com/watch?v=IlEsdxuD4lY")] - public static int UniquePaths(int m, int n) - { - // Last row will only have one move (right) for each position - var row = CreateRow(); - - // Start from second last row as last row is already initialised - for (var r = m - 2; r >= 0; r--) - { - var newRow = CreateRow(); - - // Last column will only have one move (down) for each position which - // is already initialised in new row so start from second last column - // and move from right to left summing value of previous row position - for (var c = n - 2; c >= 0; c--) - { - newRow[c] = newRow[c + 1] + row[c]; - } - - row = newRow; - } - - // First item in current row is start which is the sum of all unique paths - return row[0]; - - int[] CreateRow() - { - var r = new int[n]; - for (var i = 0; i < n; i++) - { - r[i] = 1; - } - return r; - } - } - - [Theory] - [InlineData(3, 7, 28)] - [InlineData(3, 3, 6)] - public void UniquePathsTest(int m, int n, int expected) => - UniquePaths(m, n).ShouldBe(expected); -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Unique Paths", + Difficulty.Medium, + Category.TwoDDynamicProgramming, + "https://www.youtube.com/watch?v=IlEsdxuD4lY")] + public static int UniquePaths(int m, int n) + { + // Last row will only have one move (right) for each position + var row = CreateRow(); + + // Start from second last row as last row is already initialised + for (var r = m - 2; r >= 0; r--) + { + var newRow = CreateRow(); + + // Last column will only have one move (down) for each position which + // is already initialised in new row so start from second last column + // and move from right to left summing value of previous row position + for (var c = n - 2; c >= 0; c--) + { + newRow[c] = newRow[c + 1] + row[c]; + } + + row = newRow; + } + + // First item in current row is start which is the sum of all unique paths + return row[0]; + + int[] CreateRow() + { + var r = new int[n]; + for (var i = 0; i < n; i++) + { + r[i] = 1; + } + return r; + } + } + + [Theory] + [InlineData(3, 7, 28)] + [InlineData(3, 3, 6)] + public void UniquePathsTest(int m, int n, int expected) => + UniquePaths(m, n).ShouldBe(expected); +} diff --git a/LeetCode.CSharp/Problems/ValidParentheses.cs b/LeetCode.CSharp/Problems/ValidParentheses.cs index eb0e87f..73b5f89 100644 --- a/LeetCode.CSharp/Problems/ValidParentheses.cs +++ b/LeetCode.CSharp/Problems/ValidParentheses.cs @@ -1,53 +1,53 @@ -namespace LeetCode.CSharp.Problems; - -public sealed partial class Problem -{ - [LeetCode("Valid Parentheses", - Difficulty.Easy, - Category.Stack, - "https://www.youtube.com/watch?v=WTzjTskDFMg")] - public static bool ValidParentheses(string s) - { - if (string.IsNullOrWhiteSpace(s)) - { - return false; - } - - var pairs = new Dictionary - { - { ')', '(' }, - { ']', '[' }, - { '}', '{' } - }; - var stack = new Stack(); - - foreach (var c in s) - { - if (pairs.TryGetValue(c, out var pair)) - { - if (!stack.TryPop(out var top) || pair != top) - { - return false; - } - } - else - { - stack.Push(c); - } - } - - return stack.Count == 0; - } - - [Theory] - [InlineData("()", true)] - [InlineData("()[]{}", true)] - [InlineData("([{}])", true)] - [InlineData("{[[((()))]]}", true)] - [InlineData("(())[[[]]]{{{{}}}}", true)] - [InlineData("", false)] - [InlineData("(", false)] - [InlineData("(]", false)] - [InlineData("][", false)] - public void ValidParenthesesTest(string s, bool expected) => ValidParentheses(s).ShouldBe(expected); -} +namespace LeetCode.CSharp.Problems; + +public sealed partial class Problem +{ + [LeetCode("Valid Parentheses", + Difficulty.Easy, + Category.Stack, + "https://www.youtube.com/watch?v=WTzjTskDFMg")] + public static bool ValidParentheses(string s) + { + if (string.IsNullOrWhiteSpace(s)) + { + return false; + } + + var pairs = new Dictionary + { + { ')', '(' }, + { ']', '[' }, + { '}', '{' } + }; + var stack = new Stack(); + + foreach (var c in s) + { + if (pairs.TryGetValue(c, out var pair)) + { + if (!stack.TryPop(out var top) || pair != top) + { + return false; + } + } + else + { + stack.Push(c); + } + } + + return stack.Count == 0; + } + + [Theory] + [InlineData("()", true)] + [InlineData("()[]{}", true)] + [InlineData("([{}])", true)] + [InlineData("{[[((()))]]}", true)] + [InlineData("(())[[[]]]{{{{}}}}", true)] + [InlineData("", false)] + [InlineData("(", false)] + [InlineData("(]", false)] + [InlineData("][", false)] + public void ValidParenthesesTest(string s, bool expected) => ValidParentheses(s).ShouldBe(expected); +} diff --git a/LeetCode.CSharp/TreeNode.cs b/LeetCode.CSharp/TreeNode.cs index b5c16de..fb5f52c 100644 --- a/LeetCode.CSharp/TreeNode.cs +++ b/LeetCode.CSharp/TreeNode.cs @@ -1,65 +1,65 @@ -namespace LeetCode.CSharp; - -[SuppressMessage("ReSharper", "InconsistentNaming")] -public class TreeNode -{ - public readonly int val; - public TreeNode? left; - public TreeNode? right; - - public TreeNode(int val = 0, TreeNode? left = null, TreeNode? right = null) - { - this.val = val; - this.left = left; - this.right = right; - } - - public TreeNode(IReadOnlyList values) - { - var root = Deserialize(values); - - if (root is null) - { - return; - } - - val = root.val; - left = root.left; - right = root.right; - } - - public static TreeNode? Deserialize(IReadOnlyList values) - { - var count = values.Count; - var nodes = new TreeNode?[count]; - var stack = new Stack(); - var n = 0; - - for (var i = count - 1; i >= 0; i--) - { - var node = values[i].HasValue ? new TreeNode(values[i]!.Value) : null; - nodes[count - 1 - n++] = node; - stack.Push(node); - } - - var root = stack.Pop(); - - foreach (var node in nodes) - { - if (node is null) - { - continue; - } - if (stack.TryPop(out var leftNode)) - { - node.left = leftNode; - } - if (stack.TryPop(out var rightNode)) - { - node.right = rightNode; - } - } - - return root; - } -} +namespace LeetCode.CSharp; + +[SuppressMessage("ReSharper", "InconsistentNaming")] +public class TreeNode +{ + public readonly int val; + public TreeNode? left; + public TreeNode? right; + + public TreeNode(int val = 0, TreeNode? left = null, TreeNode? right = null) + { + this.val = val; + this.left = left; + this.right = right; + } + + public TreeNode(IReadOnlyList values) + { + var root = Deserialize(values); + + if (root is null) + { + return; + } + + val = root.val; + left = root.left; + right = root.right; + } + + public static TreeNode? Deserialize(IReadOnlyList values) + { + var count = values.Count; + var nodes = new TreeNode?[count]; + var stack = new Stack(); + var n = 0; + + for (var i = count - 1; i >= 0; i--) + { + var node = values[i].HasValue ? new TreeNode(values[i]!.Value) : null; + nodes[count - 1 - n++] = node; + stack.Push(node); + } + + var root = stack.Pop(); + + foreach (var node in nodes) + { + if (node is null) + { + continue; + } + if (stack.TryPop(out var leftNode)) + { + node.left = leftNode; + } + if (stack.TryPop(out var rightNode)) + { + node.right = rightNode; + } + } + + return root; + } +} diff --git a/LeetCode.FSharp/Benchmarks/ContainsDuplicateBenchmark.fs b/LeetCode.FSharp/Benchmarks/ContainsDuplicateBenchmark.fs index 0ba3cbd..77e9c87 100644 --- a/LeetCode.FSharp/Benchmarks/ContainsDuplicateBenchmark.fs +++ b/LeetCode.FSharp/Benchmarks/ContainsDuplicateBenchmark.fs @@ -1,13 +1,13 @@ -namespace LeetCode.FSharp.Benchmarks - -open BenchmarkDotNet.Attributes -open LeetCode.FSharp.Problems - -[)>] -type ContainsDuplicateBenchmark() = - - let array = seq { 1..100_000 } - - [] - member _.ContainsDuplicate() = - [ ContainsDuplicate.ContainsDuplicate array ] +namespace LeetCode.FSharp.Benchmarks + +open BenchmarkDotNet.Attributes +open LeetCode.FSharp.Problems + +[)>] +type ContainsDuplicateBenchmark() = + + let array = seq { 1..100_000 } + + [] + member _.ContainsDuplicate() = + [ ContainsDuplicate.ContainsDuplicate array ] diff --git a/LeetCode.FSharp/Benchmarks/FizzBuzzBenchmark.fs b/LeetCode.FSharp/Benchmarks/FizzBuzzBenchmark.fs index 99f33a2..c32bd9e 100644 --- a/LeetCode.FSharp/Benchmarks/FizzBuzzBenchmark.fs +++ b/LeetCode.FSharp/Benchmarks/FizzBuzzBenchmark.fs @@ -1,10 +1,10 @@ -namespace LeetCode.FSharp.Benchmarks - -open BenchmarkDotNet.Attributes -open LeetCode.FSharp.Problems - -[)>] -type FizzBuzzBenchmark() = - - [] - member _.FizzBuzz() = [ FizzBuzz.FizzBuzz 1_000 ] +namespace LeetCode.FSharp.Benchmarks + +open BenchmarkDotNet.Attributes +open LeetCode.FSharp.Problems + +[)>] +type FizzBuzzBenchmark() = + + [] + member _.FizzBuzz() = [ FizzBuzz.FizzBuzz 1_000 ] diff --git a/LeetCode.FSharp/LeetCode.FSharp.fsproj b/LeetCode.FSharp/LeetCode.FSharp.fsproj index 7781cc9..f7947db 100644 --- a/LeetCode.FSharp/LeetCode.FSharp.fsproj +++ b/LeetCode.FSharp/LeetCode.FSharp.fsproj @@ -1,35 +1,35 @@ - - - - false - false - false - LeetCode.FSharp - false - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + false + false + false + LeetCode.FSharp + false + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/LeetCode.FSharp/ListNode.fs b/LeetCode.FSharp/ListNode.fs index 303d2b1..3faf45c 100644 --- a/LeetCode.FSharp/ListNode.fs +++ b/LeetCode.FSharp/ListNode.fs @@ -1,3 +1,3 @@ -namespace LeetCode.FSharp - -type ListNode = { value: int; next: ListNode } +namespace LeetCode.FSharp + +type ListNode = { value: int; next: ListNode } diff --git a/LeetCode.FSharp/Problems/AddTwoNumbers.fs b/LeetCode.FSharp/Problems/AddTwoNumbers.fs index f33a657..f939654 100644 --- a/LeetCode.FSharp/Problems/AddTwoNumbers.fs +++ b/LeetCode.FSharp/Problems/AddTwoNumbers.fs @@ -1,43 +1,43 @@ -namespace LeetCode.FSharp.Problems - -open FsUnit.Xunit -open LeetCode.CSharp - -module AddTwoNumbers = - - [] - let AddTwoNumbers l1 l2 = throwWithMessage "TODO" - - let ex11 = - ListNode(2, ListNode(4, ListNode(3, null))) - - let ex12 = - ListNode(5, ListNode(6, ListNode(4, null))) - - let ex1expected = - ListNode(7, ListNode(0, ListNode(8, null))) - // TODO: [] - let ``When passing example 1 it should return expected result`` () = - AddTwoNumbers(ex11, ex12) - |> should equal ex1expected - - let ex21 = ListNode(0, null) - let ex22 = ListNode(0, null) - let ex2expected = ListNode(0, null) - // TODO: [] - let ``When passing example 2 it should return expected result`` () = - AddTwoNumbers(ex21, ex22) - |> should equal ex2expected - - let ex31 = - ListNode(9, ListNode(9, ListNode(9, ListNode(9, ListNode(9, ListNode(9, ListNode(9, null))))))) - - let ex32 = - ListNode(9, ListNode(9, ListNode(9, ListNode(9, null)))) - - let ex3expected = - ListNode(8, ListNode(9, ListNode(9, ListNode(9, ListNode(0, ListNode(0, ListNode(0, ListNode(1, null)))))))) - // TODO: [] - let ``When passing example 3 it should return expected result`` () = - AddTwoNumbers(ex31, ex32) - |> should equal ex3expected +namespace LeetCode.FSharp.Problems + +open FsUnit.Xunit +open LeetCode.CSharp + +module AddTwoNumbers = + + [] + let AddTwoNumbers l1 l2 = throwWithMessage "TODO" + + let ex11 = + ListNode(2, ListNode(4, ListNode(3, null))) + + let ex12 = + ListNode(5, ListNode(6, ListNode(4, null))) + + let ex1expected = + ListNode(7, ListNode(0, ListNode(8, null))) + // TODO: [] + let ``When passing example 1 it should return expected result`` () = + AddTwoNumbers(ex11, ex12) + |> should equal ex1expected + + let ex21 = ListNode(0, null) + let ex22 = ListNode(0, null) + let ex2expected = ListNode(0, null) + // TODO: [] + let ``When passing example 2 it should return expected result`` () = + AddTwoNumbers(ex21, ex22) + |> should equal ex2expected + + let ex31 = + ListNode(9, ListNode(9, ListNode(9, ListNode(9, ListNode(9, ListNode(9, ListNode(9, null))))))) + + let ex32 = + ListNode(9, ListNode(9, ListNode(9, ListNode(9, null)))) + + let ex3expected = + ListNode(8, ListNode(9, ListNode(9, ListNode(9, ListNode(0, ListNode(0, ListNode(0, ListNode(1, null)))))))) + // TODO: [] + let ``When passing example 3 it should return expected result`` () = + AddTwoNumbers(ex31, ex32) + |> should equal ex3expected diff --git a/LeetCode.FSharp/Problems/ContainsDuplicate.fs b/LeetCode.FSharp/Problems/ContainsDuplicate.fs index 688923c..a73f84c 100644 --- a/LeetCode.FSharp/Problems/ContainsDuplicate.fs +++ b/LeetCode.FSharp/Problems/ContainsDuplicate.fs @@ -1,31 +1,31 @@ -namespace LeetCode.FSharp.Problems - -open FsUnit -open LeetCode.CSharp -open Xunit - -module ContainsDuplicate = - - [] - let ContainsDuplicate nums = - // TODO: Inefficient compared to C# solution - let numsArray = Seq.toArray nums - let distinct = Seq.distinct nums - let result = Seq.toArray distinct - result.Length < numsArray.Length - - let ex1 = [| 1; 2; 3; 1 |] - let ex2 = [| 1; 2; 3; 4 |] - let ex3 = [| 1; 1; 1; 3; 3; 4; 3; 2; 4; 2 |] - - [] - let ``When passing ex1 ContainsDuplicate should return true`` () = - ContainsDuplicate(ex1) |> should equal true - - [] - let ``When passing ex2 ContainsDuplicate should return false`` () = - ContainsDuplicate(ex2) |> should equal false - - [] - let ``When passing ex3 ContainsDuplicate should return true`` () = - ContainsDuplicate(ex3) |> should equal true +namespace LeetCode.FSharp.Problems + +open FsUnit +open LeetCode.CSharp +open Xunit + +module ContainsDuplicate = + + [] + let ContainsDuplicate nums = + // TODO: Inefficient compared to C# solution + let numsArray = Seq.toArray nums + let distinct = Seq.distinct nums + let result = Seq.toArray distinct + result.Length < numsArray.Length + + let ex1 = [| 1; 2; 3; 1 |] + let ex2 = [| 1; 2; 3; 4 |] + let ex3 = [| 1; 1; 1; 3; 3; 4; 3; 2; 4; 2 |] + + [] + let ``When passing ex1 ContainsDuplicate should return true`` () = + ContainsDuplicate(ex1) |> should equal true + + [] + let ``When passing ex2 ContainsDuplicate should return false`` () = + ContainsDuplicate(ex2) |> should equal false + + [] + let ``When passing ex3 ContainsDuplicate should return true`` () = + ContainsDuplicate(ex3) |> should equal true diff --git a/LeetCode.FSharp/Problems/FizzBuzz.fs b/LeetCode.FSharp/Problems/FizzBuzz.fs index 9d49ac7..559cb8c 100644 --- a/LeetCode.FSharp/Problems/FizzBuzz.fs +++ b/LeetCode.FSharp/Problems/FizzBuzz.fs @@ -1,52 +1,52 @@ -namespace LeetCode.FSharp.Problems - -open FsUnit.Xunit -open LeetCode.CSharp -open Xunit - -module FizzBuzz = - - [] - let FizzBuzz n = - [ 1..n ] - |> - // TODO: Append Buzz to Fizz instead multiple operations - Seq.map (function - | x when x % 5 = 0 && x % 3 = 0 -> "FizzBuzz" - | x when x % 3 = 0 -> "Fizz" - | x when x % 5 = 0 -> "Buzz" - | x -> string x) - - [] - let ``When passing 3 FizzBuzz should return expected result`` () = - FizzBuzz(3) - |> Seq.toList - |> should equal [ "1"; "2"; "Fizz" ] - - [] - let ``When passing 5 FizzBuzz should return expected result`` () = - FizzBuzz(5) - |> Seq.toList - |> should equal [ "1"; "2"; "Fizz"; "4"; "Buzz" ] - - [] - let ``When passing 15 FizzBuzz should return expected result`` () = - FizzBuzz(15) - |> Seq.toList - |> should - equal - [ "1" - "2" - "Fizz" - "4" - "Buzz" - "Fizz" - "7" - "8" - "Fizz" - "Buzz" - "11" - "Fizz" - "13" - "14" - "FizzBuzz" ] +namespace LeetCode.FSharp.Problems + +open FsUnit.Xunit +open LeetCode.CSharp +open Xunit + +module FizzBuzz = + + [] + let FizzBuzz n = + [ 1..n ] + |> + // TODO: Append Buzz to Fizz instead multiple operations + Seq.map (function + | x when x % 5 = 0 && x % 3 = 0 -> "FizzBuzz" + | x when x % 3 = 0 -> "Fizz" + | x when x % 5 = 0 -> "Buzz" + | x -> string x) + + [] + let ``When passing 3 FizzBuzz should return expected result`` () = + FizzBuzz(3) + |> Seq.toList + |> should equal [ "1"; "2"; "Fizz" ] + + [] + let ``When passing 5 FizzBuzz should return expected result`` () = + FizzBuzz(5) + |> Seq.toList + |> should equal [ "1"; "2"; "Fizz"; "4"; "Buzz" ] + + [] + let ``When passing 15 FizzBuzz should return expected result`` () = + FizzBuzz(15) + |> Seq.toList + |> should + equal + [ "1" + "2" + "Fizz" + "4" + "Buzz" + "Fizz" + "7" + "8" + "Fizz" + "Buzz" + "11" + "Fizz" + "13" + "14" + "FizzBuzz" ] diff --git a/LeetCode.FSharp/Program.fs b/LeetCode.FSharp/Program.fs index ee07d34..b6443e9 100644 --- a/LeetCode.FSharp/Program.fs +++ b/LeetCode.FSharp/Program.fs @@ -1,3 +1,3 @@ -module LeetCode.FSharp.Program - +module LeetCode.FSharp.Program + // No entry point needed - xUnit generates one automatically \ No newline at end of file diff --git a/LeetCode.sln.DotSettings b/LeetCode.sln.DotSettings index 4ad5033..e9cde8e 100644 --- a/LeetCode.sln.DotSettings +++ b/LeetCode.sln.DotSettings @@ -1,3 +1,3 @@ - + True True \ No newline at end of file diff --git a/LeetCode.slnx b/LeetCode.slnx index cad9cc4..72f8601 100644 --- a/LeetCode.slnx +++ b/LeetCode.slnx @@ -1,4 +1,4 @@ - + diff --git a/LeetCode/BenchmarkRunner.cs b/LeetCode/BenchmarkRunner.cs index 3f22ade..df8db71 100644 --- a/LeetCode/BenchmarkRunner.cs +++ b/LeetCode/BenchmarkRunner.cs @@ -1,113 +1,113 @@ -namespace LeetCode; - -internal static class BenchmarkRunner -{ - public static IEnumerable BuildSummaries(BenchmarkSettings settings) - { - var args = settings.BuildArgs(); - if (args.Length < 2) - { - // ReSharper disable once LocalizableElement - Exceptions in English - throw new ArgumentOutOfRangeException(nameof(settings), "Invalid arguments"); - } - - AnsiConsole.Cursor.Move(CursorDirection.Up, 1); - - Console.SetOut(TextWriter.Null); - - var summaries = new List(); - AnsiConsole.Status() - .Spinner(Spinner.Known.Dots) - .Start(WaitingMessage(settings, args), _ => - summaries.AddRange(RunBenchmarks(settings.BenchmarkTypes(), args))); - - Console.SetOut(Console.Out); - - AnsiConsole.Cursor.Move(CursorDirection.Down, 1); - - return summaries; - } - - public static IEnumerable RunBenchmarks(Type[] types, string[] args) => - BenchmarkSwitcher.FromTypes(types).Run(args); - - internal static bool IsDebugConfiguration(bool warnRatherThanFail = false) - { - // ReSharper disable once JoinDeclarationAndInitializer - bool debug; - -#if DEBUG - debug = true; -#else - debug = false; -#endif - - if (!debug) - { - return false; - } - - if (warnRatherThanFail) - { - AnsiConsole.MarkupLine( - "[orange1]Warning:[/] App should be in [yellow]RELEASE[/] configuration to run benchmarks"); - - AnsiConsole.WriteLine(); - - return false; - } - - AnsiConsole.MarkupLine( - "[red]Error:[/] App must be in [yellow]RELEASE[/] configuration to run benchmarks"); - - AnsiConsole.WriteLine(); - - return true; - } - - private static string WaitingMessage(BenchmarkSettings settings, string[] args) - { - var message = new StringBuilder(); - - if (args.Length > 2) - { - message.Append(Resources.BenchmarkRunner_Running_SelectedBenchmarks); - } - else if (Reflection.TryGetProblem(ParseFilterForBenchmark(args[1]), out var problem)) - { - var language = problem.Language($" {Resources.Problem_Language_Separator} "); - var benchmark = problem.CSharp & problem.FSharp - ? Resources.Benchmark_Plural.ToLower() : Resources.Benchmark_Singular.ToLower(); - message.AppendFormat(Resources.BenchmarkRunner_SingleProblem_Markup, - language, benchmark, problem.Description); - if (!problem.HasSimilarNameAndDescription()) - { - message.AppendFormat(Resources.BenchmarkRunner_SingleProblem_Name, problem.Name); - } - } - else - { - message.Append(settings is { CSharp: false, FSharp: false } - ? Resources.BenchmarkRunner_Running_BothBenchmarks - : settings.CSharp - ? Resources.BenchmarkRunner_Running_CSharpBenchmarks - : Resources.BenchmarkRunner_Running_FSharpBenchmarks); - - if (settings.Filter?.Length > 0) - { - message.AppendFormat( - Resources.BenchmarkRunner_Running_FilterSuffix_Markup, settings.Filter!); - } - } - - return message.ToString(); - } - - private static string ParseFilterForBenchmark(string filter) - { - var benchmark = filter.Trim('*'); - var found = Reflection.GetCSharpBenchmarks() - .FirstOrDefault(b => b.Equals(benchmark, StringComparison.OrdinalIgnoreCase)); - return found ?? filter; - } -} +namespace LeetCode; + +internal static class BenchmarkRunner +{ + public static IEnumerable BuildSummaries(BenchmarkSettings settings) + { + var args = settings.BuildArgs(); + if (args.Length < 2) + { + // ReSharper disable once LocalizableElement - Exceptions in English + throw new ArgumentOutOfRangeException(nameof(settings), "Invalid arguments"); + } + + AnsiConsole.Cursor.Move(CursorDirection.Up, 1); + + Console.SetOut(TextWriter.Null); + + var summaries = new List(); + AnsiConsole.Status() + .Spinner(Spinner.Known.Dots) + .Start(WaitingMessage(settings, args), _ => + summaries.AddRange(RunBenchmarks(settings.BenchmarkTypes(), args))); + + Console.SetOut(Console.Out); + + AnsiConsole.Cursor.Move(CursorDirection.Down, 1); + + return summaries; + } + + public static IEnumerable RunBenchmarks(Type[] types, string[] args) => + BenchmarkSwitcher.FromTypes(types).Run(args); + + internal static bool IsDebugConfiguration(bool warnRatherThanFail = false) + { + // ReSharper disable once JoinDeclarationAndInitializer + bool debug; + +#if DEBUG + debug = true; +#else + debug = false; +#endif + + if (!debug) + { + return false; + } + + if (warnRatherThanFail) + { + AnsiConsole.MarkupLine( + "[orange1]Warning:[/] App should be in [yellow]RELEASE[/] configuration to run benchmarks"); + + AnsiConsole.WriteLine(); + + return false; + } + + AnsiConsole.MarkupLine( + "[red]Error:[/] App must be in [yellow]RELEASE[/] configuration to run benchmarks"); + + AnsiConsole.WriteLine(); + + return true; + } + + private static string WaitingMessage(BenchmarkSettings settings, string[] args) + { + var message = new StringBuilder(); + + if (args.Length > 2) + { + message.Append(Resources.BenchmarkRunner_Running_SelectedBenchmarks); + } + else if (Reflection.TryGetProblem(ParseFilterForBenchmark(args[1]), out var problem)) + { + var language = problem.Language($" {Resources.Problem_Language_Separator} "); + var benchmark = problem.CSharp & problem.FSharp + ? Resources.Benchmark_Plural.ToLower() : Resources.Benchmark_Singular.ToLower(); + message.AppendFormat(Resources.BenchmarkRunner_SingleProblem_Markup, + language, benchmark, problem.Description); + if (!problem.HasSimilarNameAndDescription()) + { + message.AppendFormat(Resources.BenchmarkRunner_SingleProblem_Name, problem.Name); + } + } + else + { + message.Append(settings is { CSharp: false, FSharp: false } + ? Resources.BenchmarkRunner_Running_BothBenchmarks + : settings.CSharp + ? Resources.BenchmarkRunner_Running_CSharpBenchmarks + : Resources.BenchmarkRunner_Running_FSharpBenchmarks); + + if (settings.Filter?.Length > 0) + { + message.AppendFormat( + Resources.BenchmarkRunner_Running_FilterSuffix_Markup, settings.Filter!); + } + } + + return message.ToString(); + } + + private static string ParseFilterForBenchmark(string filter) + { + var benchmark = filter.Trim('*'); + var found = Reflection.GetCSharpBenchmarks() + .FirstOrDefault(b => b.Equals(benchmark, StringComparison.OrdinalIgnoreCase)); + return found ?? filter; + } +} diff --git a/LeetCode/Commands/AppCommand.cs b/LeetCode/Commands/AppCommand.cs index afdd416..e128578 100644 --- a/LeetCode/Commands/AppCommand.cs +++ b/LeetCode/Commands/AppCommand.cs @@ -1,19 +1,19 @@ -namespace LeetCode.Commands; - -internal sealed class AppCommand : Command -{ - public override int Execute(CommandContext context, CancellationToken cancellationToken) - { - try - { - new MainMenu().Render(); - - return 0; - } - catch (Exception ex) - { - AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything); - return -99; - } - } -} +namespace LeetCode.Commands; + +internal sealed class AppCommand : Command +{ + public override int Execute(CommandContext context, CancellationToken cancellationToken) + { + try + { + new MainMenu().Render(); + + return 0; + } + catch (Exception ex) + { + AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything); + return -99; + } + } +} diff --git a/LeetCode/Commands/BenchmarkCommand.cs b/LeetCode/Commands/BenchmarkCommand.cs index 9bb7d6b..a900d02 100644 --- a/LeetCode/Commands/BenchmarkCommand.cs +++ b/LeetCode/Commands/BenchmarkCommand.cs @@ -1,36 +1,36 @@ -namespace LeetCode.Commands; - -internal sealed class BenchmarkCommand : Command -{ - [SuppressMessage("ReSharper", "RedundantNullableFlowAttribute")] - public override int Execute( - [NotNull] CommandContext context, - [NotNull] BenchmarkSettings settings, - CancellationToken cancellationToken) - { - try - { - ConsoleWriter.WriteHeader(); - - if (BenchmarkRunner.IsDebugConfiguration(settings.Debug)) - { - return 1; - } - - var summaries = BenchmarkRunner.BuildSummaries(settings); - var builder = new SpectreReportBuilder(summaries); - var report = builder.Build(); - - AnsiConsole.Write(report); - - AnsiConsole.WriteLine(); - - return 0; - } - catch (Exception ex) - { - AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything); - return -99; - } - } -} +namespace LeetCode.Commands; + +internal sealed class BenchmarkCommand : Command +{ + [SuppressMessage("ReSharper", "RedundantNullableFlowAttribute")] + public override int Execute( + [NotNull] CommandContext context, + [NotNull] BenchmarkSettings settings, + CancellationToken cancellationToken) + { + try + { + ConsoleWriter.WriteHeader(); + + if (BenchmarkRunner.IsDebugConfiguration(settings.Debug)) + { + return 1; + } + + var summaries = BenchmarkRunner.BuildSummaries(settings); + var builder = new SpectreReportBuilder(summaries); + var report = builder.Build(); + + AnsiConsole.Write(report); + + AnsiConsole.WriteLine(); + + return 0; + } + catch (Exception ex) + { + AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything); + return -99; + } + } +} diff --git a/LeetCode/Commands/BenchmarkSettings.cs b/LeetCode/Commands/BenchmarkSettings.cs index f76fb24..1bec58a 100644 --- a/LeetCode/Commands/BenchmarkSettings.cs +++ b/LeetCode/Commands/BenchmarkSettings.cs @@ -1,121 +1,121 @@ -namespace LeetCode.Commands; - -internal sealed class BenchmarkSettings : CommandSettings -{ - [Description("Filter by LeetCode.Sharp.Benchmarks. (* wildcards accepted)")] - [CommandArgument(0, "[filter]")] - public string? Filter { get; init; } - - [Description("Only run C# benchmarks")] - [CommandOption("--csharp")] - public bool CSharp { get; init; } - - [Description("Only run F# benchmarks")] - [CommandOption("--fsharp")] - public bool FSharp { get; init; } - - [Description("Allow debug configuration to run - use only for development")] - [CommandOption("--debug")] - public bool Debug { get; init; } - - [Description("BenchmarkDotNet Exporters: GitHub/StackOverflow/RPlot/CSV/JSON/HTML/XML")] - [CommandOption("--exporters")] - public string? Exporters { get; init; } - - public override ValidationResult Validate() - { - if (CSharp && FSharp) - { - return ValidationResult.Error(Resources.BenchmarkSettings_Error_MutuallyExclusive); - } - - if (!string.IsNullOrEmpty(Filter) && !BenchmarkFound()) - { - return ValidationResult.Error( - string.Format(Resources.BenchmarkSettings_Error_BenchmarkNotFound, Filter)); - } - - return ValidationResult.Success(); - } - - public Type[] BenchmarkTypes() - { - var types = new List(); - var all = !CSharp && !FSharp; - - if (all || CSharp) - { - types.AddRange(Reflection.GetCSharpBenchmarkTypes()); - } - - if (all || FSharp) - { - types.AddRange(Reflection.GetFSharpBenchmarkTypes()); - } - - return [.. types - .OrderBy(t => t.Name) - .ThenBy(t => t.Namespace)]; - } - - public string[] BuildArgs() - { - var args = new List { "--filter" }; - - // No filter means run all benchmarks for specified options - if (string.IsNullOrEmpty(Filter)) - { - if (CSharp) - { - args.Add("LeetCode.CSharp*"); - } - else if (FSharp) - { - args.Add("LeetCode.FSharp*"); - } - else - { - args.Add("LeetCode*"); - } - } - else - { - var benchmarks = Filter.Split(' '); - - foreach (var benchmark in benchmarks) - { - if (benchmark.Contains('*')) - { - // User added wildcard so use whatever was passed - args.Add(benchmark); - } - else if (benchmark.Contains('.')) - { - // User added namespace but no wildcard so add suffix - args.Add($"{benchmark}*"); - } - else - { - // No wildcard or namespace so add wildcard prefix - args.Add($"*{benchmark}"); - } - } - } - - if (string.IsNullOrEmpty(Exporters)) - { - return [.. args]; - } - - args.Add("--exporters"); - args.Add(Exporters); - - return [.. args]; - } - - private bool BenchmarkFound() => - Reflection - .GetCSharpBenchmarks() - .Union(Reflection.GetFSharpBenchmarks()) - .Contains(Filter, StringComparer.InvariantCultureIgnoreCase); -} +namespace LeetCode.Commands; + +internal sealed class BenchmarkSettings : CommandSettings +{ + [Description("Filter by LeetCode.Sharp.Benchmarks. (* wildcards accepted)")] + [CommandArgument(0, "[filter]")] + public string? Filter { get; init; } + + [Description("Only run C# benchmarks")] + [CommandOption("--csharp")] + public bool CSharp { get; init; } + + [Description("Only run F# benchmarks")] + [CommandOption("--fsharp")] + public bool FSharp { get; init; } + + [Description("Allow debug configuration to run - use only for development")] + [CommandOption("--debug")] + public bool Debug { get; init; } + + [Description("BenchmarkDotNet Exporters: GitHub/StackOverflow/RPlot/CSV/JSON/HTML/XML")] + [CommandOption("--exporters")] + public string? Exporters { get; init; } + + public override ValidationResult Validate() + { + if (CSharp && FSharp) + { + return ValidationResult.Error(Resources.BenchmarkSettings_Error_MutuallyExclusive); + } + + if (!string.IsNullOrEmpty(Filter) && !BenchmarkFound()) + { + return ValidationResult.Error( + string.Format(Resources.BenchmarkSettings_Error_BenchmarkNotFound, Filter)); + } + + return ValidationResult.Success(); + } + + public Type[] BenchmarkTypes() + { + var types = new List(); + var all = !CSharp && !FSharp; + + if (all || CSharp) + { + types.AddRange(Reflection.GetCSharpBenchmarkTypes()); + } + + if (all || FSharp) + { + types.AddRange(Reflection.GetFSharpBenchmarkTypes()); + } + + return [.. types + .OrderBy(t => t.Name) + .ThenBy(t => t.Namespace)]; + } + + public string[] BuildArgs() + { + var args = new List { "--filter" }; + + // No filter means run all benchmarks for specified options + if (string.IsNullOrEmpty(Filter)) + { + if (CSharp) + { + args.Add("LeetCode.CSharp*"); + } + else if (FSharp) + { + args.Add("LeetCode.FSharp*"); + } + else + { + args.Add("LeetCode*"); + } + } + else + { + var benchmarks = Filter.Split(' '); + + foreach (var benchmark in benchmarks) + { + if (benchmark.Contains('*')) + { + // User added wildcard so use whatever was passed + args.Add(benchmark); + } + else if (benchmark.Contains('.')) + { + // User added namespace but no wildcard so add suffix + args.Add($"{benchmark}*"); + } + else + { + // No wildcard or namespace so add wildcard prefix + args.Add($"*{benchmark}"); + } + } + } + + if (string.IsNullOrEmpty(Exporters)) + { + return [.. args]; + } + + args.Add("--exporters"); + args.Add(Exporters); + + return [.. args]; + } + + private bool BenchmarkFound() => + Reflection + .GetCSharpBenchmarks() + .Union(Reflection.GetFSharpBenchmarks()) + .Contains(Filter, StringComparer.InvariantCultureIgnoreCase); +} diff --git a/LeetCode/Commands/InfoCommand.cs b/LeetCode/Commands/InfoCommand.cs index 94a7356..e706ae7 100644 --- a/LeetCode/Commands/InfoCommand.cs +++ b/LeetCode/Commands/InfoCommand.cs @@ -1,32 +1,32 @@ -namespace LeetCode.Commands; - -internal sealed class InfoCommand : Command -{ - [SuppressMessage("ReSharper", "RedundantNullableFlowAttribute")] - public override int Execute( - [NotNull] CommandContext context, - [NotNull] ProblemSettings settings, - CancellationToken cancellationToken) - { - try - { - ConsoleWriter.WriteHeader(); - - if (!Reflection.TryGetProblem(settings.Name, out var problem)) - { - throw new InvalidOperationException("Problem settings validation failed"); - } - - AnsiConsole.Write(problem.Markup()); - - AnsiConsole.WriteLine(); - - return 0; - } - catch (Exception ex) - { - AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything); - return -99; - } - } -} +namespace LeetCode.Commands; + +internal sealed class InfoCommand : Command +{ + [SuppressMessage("ReSharper", "RedundantNullableFlowAttribute")] + public override int Execute( + [NotNull] CommandContext context, + [NotNull] ProblemSettings settings, + CancellationToken cancellationToken) + { + try + { + ConsoleWriter.WriteHeader(); + + if (!Reflection.TryGetProblem(settings.Name, out var problem)) + { + throw new InvalidOperationException("Problem settings validation failed"); + } + + AnsiConsole.Write(problem.Markup()); + + AnsiConsole.WriteLine(); + + return 0; + } + catch (Exception ex) + { + AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything); + return -99; + } + } +} diff --git a/LeetCode/Commands/ListCommand.cs b/LeetCode/Commands/ListCommand.cs index 5a48832..eb8c6c9 100644 --- a/LeetCode/Commands/ListCommand.cs +++ b/LeetCode/Commands/ListCommand.cs @@ -1,65 +1,65 @@ -namespace LeetCode.Commands; - -internal sealed class ListCommand : Command -{ - [SuppressMessage("ReSharper", "RedundantNullableFlowAttribute")] - public override int Execute([NotNull] CommandContext context, CancellationToken cancellationToken) - { - try - { - ConsoleWriter.WriteHeader(); - - AnsiConsole.Cursor.Move(CursorDirection.Up, 1); - - WriteProblemList(); - - return 0; - } - catch (Exception ex) - { - AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything); - return -99; - } - } - - private static void WriteProblemList() - { - var table = new Table(); - - table.AddColumn(Resources.Problem_Name, config => config.NoWrap = true); - table.AddColumn(Resources.Problem_Category); - table.AddColumn(Resources.Problem_Difficulty); - table.AddColumn(Resources.Problem_Language); - table.SimpleBorder(); - table.BorderColor(Color.Grey); - - var cSharpBenchmarks = Reflection.GetCSharpBenchmarks().ToArray(); - var fSharpBenchmarks = Reflection.GetFSharpBenchmarks().ToArray(); - var categories = Reflection.GetProblemsByCategory(); - - foreach (var category in categories) - { - foreach (var problem in category.ToArray()) - { - var missing = cSharpBenchmarks.Contains(problem.Name) - ? string.Empty - : $" {Resources.ListCommand_Missing_CSharpBenchmark_Markup}"; - - if (problem.FSharp && !fSharpBenchmarks.Contains(problem.Name)) - { - missing = string.IsNullOrEmpty(missing) - ? $" {Resources.ListCommand_Missing_FSharpBenchmark_Markup}" - : $" {Resources.ListCommand_Missing_BothBenchmarks_Markup}"; - } - - table.AddRow( - problem.Description + missing, - problem.Category.Description(), - problem.Difficulty.Markup(), - problem.LanguageMarkup()); - } - } - - AnsiConsole.Write(table); - } -} +namespace LeetCode.Commands; + +internal sealed class ListCommand : Command +{ + [SuppressMessage("ReSharper", "RedundantNullableFlowAttribute")] + public override int Execute([NotNull] CommandContext context, CancellationToken cancellationToken) + { + try + { + ConsoleWriter.WriteHeader(); + + AnsiConsole.Cursor.Move(CursorDirection.Up, 1); + + WriteProblemList(); + + return 0; + } + catch (Exception ex) + { + AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything); + return -99; + } + } + + private static void WriteProblemList() + { + var table = new Table(); + + table.AddColumn(Resources.Problem_Name, config => config.NoWrap = true); + table.AddColumn(Resources.Problem_Category); + table.AddColumn(Resources.Problem_Difficulty); + table.AddColumn(Resources.Problem_Language); + table.SimpleBorder(); + table.BorderColor(Color.Grey); + + var cSharpBenchmarks = Reflection.GetCSharpBenchmarks().ToArray(); + var fSharpBenchmarks = Reflection.GetFSharpBenchmarks().ToArray(); + var categories = Reflection.GetProblemsByCategory(); + + foreach (var category in categories) + { + foreach (var problem in category.ToArray()) + { + var missing = cSharpBenchmarks.Contains(problem.Name) + ? string.Empty + : $" {Resources.ListCommand_Missing_CSharpBenchmark_Markup}"; + + if (problem.FSharp && !fSharpBenchmarks.Contains(problem.Name)) + { + missing = string.IsNullOrEmpty(missing) + ? $" {Resources.ListCommand_Missing_FSharpBenchmark_Markup}" + : $" {Resources.ListCommand_Missing_BothBenchmarks_Markup}"; + } + + table.AddRow( + problem.Description + missing, + problem.Category.Description(), + problem.Difficulty.Markup(), + problem.LanguageMarkup()); + } + } + + AnsiConsole.Write(table); + } +} diff --git a/LeetCode/Commands/ProblemSettings.cs b/LeetCode/Commands/ProblemSettings.cs index 5e47009..fbe9b74 100644 --- a/LeetCode/Commands/ProblemSettings.cs +++ b/LeetCode/Commands/ProblemSettings.cs @@ -1,24 +1,24 @@ -namespace LeetCode.Commands; - -internal sealed class ProblemSettings : CommandSettings -{ - [Description("Name of LeetCode problem")] - [CommandArgument(0, "[name]")] - public string Name { get; init; } = string.Empty; - - public override ValidationResult Validate() - { - if (string.IsNullOrWhiteSpace(Name)) - { - return ValidationResult.Error(Resources.ProblemSettings_Error_NoArgumentPassed); - } - - if (!Reflection.TryGetProblem(Name, out _)) - { - return ValidationResult.Error( - string.Format(Resources.ProblemSettings_Error_ProblemNotFound, Name)); - } - - return ValidationResult.Success(); - } +namespace LeetCode.Commands; + +internal sealed class ProblemSettings : CommandSettings +{ + [Description("Name of LeetCode problem")] + [CommandArgument(0, "[name]")] + public string Name { get; init; } = string.Empty; + + public override ValidationResult Validate() + { + if (string.IsNullOrWhiteSpace(Name)) + { + return ValidationResult.Error(Resources.ProblemSettings_Error_NoArgumentPassed); + } + + if (!Reflection.TryGetProblem(Name, out _)) + { + return ValidationResult.Error( + string.Format(Resources.ProblemSettings_Error_ProblemNotFound, Name)); + } + + return ValidationResult.Success(); + } } \ No newline at end of file diff --git a/LeetCode/Commands/WorkflowCommand.cs b/LeetCode/Commands/WorkflowCommand.cs index f18b098..b8520ba 100644 --- a/LeetCode/Commands/WorkflowCommand.cs +++ b/LeetCode/Commands/WorkflowCommand.cs @@ -1,89 +1,89 @@ -namespace LeetCode.Commands; - -internal sealed class WorkflowCommand : Command -{ - [SuppressMessage("ReSharper", "RedundantNullableFlowAttribute")] - public override int Execute([NotNull] CommandContext context, CancellationToken cancellationToken) - { - try - { - ConsoleWriter.WriteHeader(); - - if (BenchmarkRunner.IsDebugConfiguration(true)) - { - return 1; - } - - var settings = new BenchmarkSettings { Exporters = "json" }; - - BenchmarkRunner.RunBenchmarks(settings.BenchmarkTypes(), settings.BuildArgs()); - - CombineBenchmarkResults(); - - return 0; - } - catch (Exception ex) - { - AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything); - return -99; - } - } - - private static void CombineBenchmarkResults( - string resultsDir = "./BenchmarkDotNet.Artifacts/results", - string resultsFile = "LeetCode.Benchmarks", - string searchPattern = "LeetCode.*.json") - { - var resultsPath = Path.Combine(resultsDir, $"{resultsFile}.json"); - - if (!Directory.Exists(resultsDir)) - { - throw new DirectoryNotFoundException($"Directory not found '{resultsDir}'"); - } - - if (File.Exists(resultsPath)) - { - File.Delete(resultsPath); - } - - const string ns = "LeetCode.XSharp.Benchmarks."; - var reports = Directory - .GetFiles(resultsDir, searchPattern, SearchOption.TopDirectoryOnly) - .OrderBy(report => report[ns.Length..]) - .ToArray(); - if (reports.Length == 0) - { - throw new FileNotFoundException($"Reports not found '{searchPattern}'"); - } - - var firstReport = reports.First(); - var combinedReport = JsonNode.Parse(File.ReadAllText(firstReport))!; - var title = combinedReport["Title"]!; - var benchmarks = combinedReport["Benchmarks"]!.AsArray(); - SetBenchmarkName(firstReport, combinedReport["Benchmarks"]![0]!); - - // Rename title whilst keeping original timestamp - combinedReport["Title"] = $"{resultsFile}{title.GetValue()[^16..]}"; - - foreach (var report in reports.Skip(1)) - { - var node = JsonNode.Parse(File.ReadAllText(report))!["Benchmarks"]!; - SetBenchmarkName(report, node[0]!); - - foreach (var benchmark in node.AsArray()) - { - // Double parse avoids "The node already has a parent" exception - benchmarks.Add(JsonNode.Parse(benchmark!.ToJsonString())!); - } - } - - File.WriteAllText(resultsPath, combinedReport.ToString()); - } - - private static void SetBenchmarkName(string report, JsonNode benchmark) - { - // Make pretty as only one method per benchmark - or tweak index.html? - var language = report.Contains("CSharp") ? "C#" : "F#"; - benchmark["FullName"] = $"{benchmark["Method"]} in {language}"; - } -} +namespace LeetCode.Commands; + +internal sealed class WorkflowCommand : Command +{ + [SuppressMessage("ReSharper", "RedundantNullableFlowAttribute")] + public override int Execute([NotNull] CommandContext context, CancellationToken cancellationToken) + { + try + { + ConsoleWriter.WriteHeader(); + + if (BenchmarkRunner.IsDebugConfiguration(true)) + { + return 1; + } + + var settings = new BenchmarkSettings { Exporters = "json" }; + + BenchmarkRunner.RunBenchmarks(settings.BenchmarkTypes(), settings.BuildArgs()); + + CombineBenchmarkResults(); + + return 0; + } + catch (Exception ex) + { + AnsiConsole.WriteException(ex, ExceptionFormats.ShortenEverything); + return -99; + } + } + + private static void CombineBenchmarkResults( + string resultsDir = "./BenchmarkDotNet.Artifacts/results", + string resultsFile = "LeetCode.Benchmarks", + string searchPattern = "LeetCode.*.json") + { + var resultsPath = Path.Combine(resultsDir, $"{resultsFile}.json"); + + if (!Directory.Exists(resultsDir)) + { + throw new DirectoryNotFoundException($"Directory not found '{resultsDir}'"); + } + + if (File.Exists(resultsPath)) + { + File.Delete(resultsPath); + } + + const string ns = "LeetCode.XSharp.Benchmarks."; + var reports = Directory + .GetFiles(resultsDir, searchPattern, SearchOption.TopDirectoryOnly) + .OrderBy(report => report[ns.Length..]) + .ToArray(); + if (reports.Length == 0) + { + throw new FileNotFoundException($"Reports not found '{searchPattern}'"); + } + + var firstReport = reports.First(); + var combinedReport = JsonNode.Parse(File.ReadAllText(firstReport))!; + var title = combinedReport["Title"]!; + var benchmarks = combinedReport["Benchmarks"]!.AsArray(); + SetBenchmarkName(firstReport, combinedReport["Benchmarks"]![0]!); + + // Rename title whilst keeping original timestamp + combinedReport["Title"] = $"{resultsFile}{title.GetValue()[^16..]}"; + + foreach (var report in reports.Skip(1)) + { + var node = JsonNode.Parse(File.ReadAllText(report))!["Benchmarks"]!; + SetBenchmarkName(report, node[0]!); + + foreach (var benchmark in node.AsArray()) + { + // Double parse avoids "The node already has a parent" exception + benchmarks.Add(JsonNode.Parse(benchmark!.ToJsonString())!); + } + } + + File.WriteAllText(resultsPath, combinedReport.ToString()); + } + + private static void SetBenchmarkName(string report, JsonNode benchmark) + { + // Make pretty as only one method per benchmark - or tweak index.html? + var language = report.Contains("CSharp") ? "C#" : "F#"; + benchmark["FullName"] = $"{benchmark["Method"]} in {language}"; + } +} diff --git a/LeetCode/ConsoleWriter.cs b/LeetCode/ConsoleWriter.cs index 3c1abaf..db5bedd 100644 --- a/LeetCode/ConsoleWriter.cs +++ b/LeetCode/ConsoleWriter.cs @@ -1,41 +1,41 @@ -namespace LeetCode; - -internal static class ConsoleWriter -{ - private static readonly Rainbow Lolcat = new(new RainbowStyle(EscapeSequence.Spectre)); - private static readonly AnimationStyle AnimationStyle = new( - Duration: TimeSpan.FromSeconds(1.42), - PadToWindowSize: false, - Speed: 42, - StopOnResize: true); - - public static void WriteHeader(bool clearConsole = false) - { - if (clearConsole) - { - AnsiConsole.Clear(); - } - - Lolcat.WriteLineWithMarkup(Resources.LeetCode_Figlet); - } - - public static void AnimateHeader() - { - AnsiConsole.Clear(); - - Lolcat.Animate(Resources.LeetCode_Figlet, AnimationStyle); - - AnsiConsole.WriteLine(); - } - - public static void WaitForKeyPress() - { - AnsiConsole.WriteLine(); - - AnsiConsole.MarkupLine(Resources.Console_ReturnToMainMenu_Markup); - - AnsiConsole.Cursor.Hide(); - - Console.ReadKey(); - } -} +namespace LeetCode; + +internal static class ConsoleWriter +{ + private static readonly Rainbow Lolcat = new(new RainbowStyle(EscapeSequence.Spectre)); + private static readonly AnimationStyle AnimationStyle = new( + Duration: TimeSpan.FromSeconds(1.42), + PadToWindowSize: false, + Speed: 42, + StopOnResize: true); + + public static void WriteHeader(bool clearConsole = false) + { + if (clearConsole) + { + AnsiConsole.Clear(); + } + + Lolcat.WriteLineWithMarkup(Resources.LeetCode_Figlet); + } + + public static void AnimateHeader() + { + AnsiConsole.Clear(); + + Lolcat.Animate(Resources.LeetCode_Figlet, AnimationStyle); + + AnsiConsole.WriteLine(); + } + + public static void WaitForKeyPress() + { + AnsiConsole.WriteLine(); + + AnsiConsole.MarkupLine(Resources.Console_ReturnToMainMenu_Markup); + + AnsiConsole.Cursor.Hide(); + + Console.ReadKey(); + } +} diff --git a/LeetCode/Dockerfile b/LeetCode/Dockerfile index dad4f45..d35ebc2 100644 --- a/LeetCode/Dockerfile +++ b/LeetCode/Dockerfile @@ -1,22 +1,22 @@ -FROM mcr.microsoft.com/dotnet/runtime:10.0 AS base -WORKDIR /app - -FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build -WORKDIR /src - -# Needed for target framework -COPY Directory.Build.props ./ - -COPY LeetCode/LeetCode.csproj LeetCode/ -COPY LeetCode.CSharp/LeetCode.CSharp.csproj LeetCode.CSharp/ -COPY LeetCode.FSharp/LeetCode.FSharp.fsproj LeetCode.FSharp/ - -COPY . . - -WORKDIR /src/LeetCode - -RUN dotnet restore LeetCode.csproj -RUN dotnet build LeetCode.csproj -c release - -# Benchmarks require release configuration -ENTRYPOINT ["dotnet", "run", "-c", "release"] +FROM mcr.microsoft.com/dotnet/runtime:10.0 AS base +WORKDIR /app + +FROM mcr.microsoft.com/dotnet/sdk:10.0 AS build +WORKDIR /src + +# Needed for target framework +COPY Directory.Build.props ./ + +COPY LeetCode/LeetCode.csproj LeetCode/ +COPY LeetCode.CSharp/LeetCode.CSharp.csproj LeetCode.CSharp/ +COPY LeetCode.FSharp/LeetCode.FSharp.fsproj LeetCode.FSharp/ + +COPY . . + +WORKDIR /src/LeetCode + +RUN dotnet restore LeetCode.csproj +RUN dotnet build LeetCode.csproj -c release + +# Benchmarks require release configuration +ENTRYPOINT ["dotnet", "run", "-c", "release"] diff --git a/LeetCode/Extensions.cs b/LeetCode/Extensions.cs index d008714..51cced6 100644 --- a/LeetCode/Extensions.cs +++ b/LeetCode/Extensions.cs @@ -1,67 +1,67 @@ -namespace LeetCode; - -public static partial class Extensions -{ - extension(Category category) - { - public string Description() => - $"Category_{category}".GetResource(); - } - - extension(Difficulty difficulty) - { - public string Markup() => - $"Difficulty_{difficulty}_Markup".GetResource(); - } - - extension(Problem problem) - { - internal bool HasSimilarNameAndDescription() => - problem.Description.ReplaceWhitespace(string.Empty) == problem.Name; - - internal Table Markup() - { - var table = new Table - { - Border = TableBorder.None, - ShowHeaders = false - }; - - table.AddColumn(new TableColumn("-").PadRight(3)); - table.AddColumn("-"); - - table.AddRow(Resources.Problem_Benchmark_Markup, problem.Name); - - if (problem.Name != problem.Description) - { - table.AddRow(Resources.Problem_Description_Markup, problem.Description); - } - - table.AddRow(Resources.Problem_Category_Markup, problem.Category.Description()); - table.AddRow(Resources.Problem_Difficulty_Markup, problem.Difficulty.Markup()); - table.AddRow(Resources.Problem_Language_Markup, problem.LanguageMarkup()); - - if (problem.Link is not null) - { - table.AddRow(Resources.Problem_Link_Markup, problem.Link.ToString()); - } - - return table; - } - } - - extension(string input) - { - private string ReplaceWhitespace(string replacement) => - MatchWhitespace.Replace(input, replacement); - - private string GetResource() => - Resources.ResourceManager.GetString(input) ?? - throw new InvalidOperationException($"Missing resource '{input}'"); - } - - private static readonly Regex MatchWhitespace = MatchWhitespaceRegex(); - - [GeneratedRegex(@"\s+")] - private static partial Regex MatchWhitespaceRegex(); -} +namespace LeetCode; + +public static partial class Extensions +{ + extension(Category category) + { + public string Description() => + $"Category_{category}".GetResource(); + } + + extension(Difficulty difficulty) + { + public string Markup() => + $"Difficulty_{difficulty}_Markup".GetResource(); + } + + extension(Problem problem) + { + internal bool HasSimilarNameAndDescription() => + problem.Description.ReplaceWhitespace(string.Empty) == problem.Name; + + internal Table Markup() + { + var table = new Table + { + Border = TableBorder.None, + ShowHeaders = false + }; + + table.AddColumn(new TableColumn("-").PadRight(3)); + table.AddColumn("-"); + + table.AddRow(Resources.Problem_Benchmark_Markup, problem.Name); + + if (problem.Name != problem.Description) + { + table.AddRow(Resources.Problem_Description_Markup, problem.Description); + } + + table.AddRow(Resources.Problem_Category_Markup, problem.Category.Description()); + table.AddRow(Resources.Problem_Difficulty_Markup, problem.Difficulty.Markup()); + table.AddRow(Resources.Problem_Language_Markup, problem.LanguageMarkup()); + + if (problem.Link is not null) + { + table.AddRow(Resources.Problem_Link_Markup, problem.Link.ToString()); + } + + return table; + } + } + + extension(string input) + { + private string ReplaceWhitespace(string replacement) => + MatchWhitespace.Replace(input, replacement); + + private string GetResource() => + Resources.ResourceManager.GetString(input) ?? + throw new InvalidOperationException($"Missing resource '{input}'"); + } + + private static readonly Regex MatchWhitespace = MatchWhitespaceRegex(); + + [GeneratedRegex(@"\s+")] + private static partial Regex MatchWhitespaceRegex(); +} diff --git a/LeetCode/LeetCode.csproj b/LeetCode/LeetCode.csproj index ee5e54b..0c9677e 100644 --- a/LeetCode/LeetCode.csproj +++ b/LeetCode/LeetCode.csproj @@ -1,71 +1,71 @@ - - - - LeetCode via NeetCode - LeetCode - Exe - false - - - - - - - - - - - - - - - - - - - - - - - - - - - - runtime; build; native; contentfiles; analyzers; buildtransitive - all - - - - - - - compile;build - runtime - - - - - - - Dockerfile - .dockerignore - - - - - - True - True - Resources.resx - - - - - - ResXFileCodeGenerator - Resources.Designer.cs - - - - + + + + LeetCode via NeetCode + LeetCode + Exe + false + + + + + + + + + + + + + + + + + + + + + + + + + + + + runtime; build; native; contentfiles; analyzers; buildtransitive + all + + + + + + + compile;build + runtime + + + + + + + Dockerfile + .dockerignore + + + + + + True + True + Resources.resx + + + + + + ResXFileCodeGenerator + Resources.Designer.cs + + + + diff --git a/LeetCode/Menus/MainMenu.cs b/LeetCode/Menus/MainMenu.cs index 286ebf8..82ffda1 100644 --- a/LeetCode/Menus/MainMenu.cs +++ b/LeetCode/Menus/MainMenu.cs @@ -1,33 +1,33 @@ -namespace LeetCode.Menus; - -internal sealed class MainMenu : MenuBase -{ - public MainMenu() - { - Choices = - [ - new ProblemListSelection(1), - new BenchmarkListSelection(2), - new AboutSelection(3), - new ExitSelection(4) - ]; - } - public int Render() - { - var selected = Choices.First(); - var prompt = new SelectionPrompt() - .AddChoices(GetChoices()) - .UseConverter(m => m.Name); - - var exitCode = 0; - while (selected.Name != Resources.Selection_Exit) - { - ConsoleWriter.WriteHeader(clearConsole: true); - - selected = AnsiConsole.Prompt(prompt); - - exitCode = selected.Execute(); - } - return exitCode; - } -} +namespace LeetCode.Menus; + +internal sealed class MainMenu : MenuBase +{ + public MainMenu() + { + Choices = + [ + new ProblemListSelection(1), + new BenchmarkListSelection(2), + new AboutSelection(3), + new ExitSelection(4) + ]; + } + public int Render() + { + var selected = Choices.First(); + var prompt = new SelectionPrompt() + .AddChoices(GetChoices()) + .UseConverter(m => m.Name); + + var exitCode = 0; + while (selected.Name != Resources.Selection_Exit) + { + ConsoleWriter.WriteHeader(clearConsole: true); + + selected = AnsiConsole.Prompt(prompt); + + exitCode = selected.Execute(); + } + return exitCode; + } +} diff --git a/LeetCode/Menus/MenuBase.cs b/LeetCode/Menus/MenuBase.cs index aa63366..f3235b8 100644 --- a/LeetCode/Menus/MenuBase.cs +++ b/LeetCode/Menus/MenuBase.cs @@ -1,8 +1,8 @@ -namespace LeetCode.Menus; - -internal abstract class MenuBase -{ - protected IEnumerable Choices { get; init; } = []; - - protected IEnumerable GetChoices() => Choices.OrderBy(m => m.Order); +namespace LeetCode.Menus; + +internal abstract class MenuBase +{ + protected IEnumerable Choices { get; init; } = []; + + protected IEnumerable GetChoices() => Choices.OrderBy(m => m.Order); } \ No newline at end of file diff --git a/LeetCode/Menus/ProblemMenu.cs b/LeetCode/Menus/ProblemMenu.cs index b170bae..4cdaf34 100644 --- a/LeetCode/Menus/ProblemMenu.cs +++ b/LeetCode/Menus/ProblemMenu.cs @@ -1,33 +1,33 @@ -namespace LeetCode.Menus; - -internal sealed class ProblemMenu : MenuBase -{ - private Problem Problem { get; } - - public ProblemMenu(Problem problem) - { - Problem = problem; - Choices = - [ - new BenchmarkSelection(Problem, 1), - new ExitSelection(2) - ]; - } - - public int Render() - { - ConsoleWriter.WriteHeader(clearConsole: true); - - AnsiConsole.Write(Problem.Markup()); - AnsiConsole.WriteLine(); - - var prompt = new SelectionPrompt() - .AddChoices(GetChoices()) - .UseConverter(m => m.Name); - - var selected = AnsiConsole.Prompt(prompt); - var exitCode = selected.Execute(); - - return exitCode; - } -} +namespace LeetCode.Menus; + +internal sealed class ProblemMenu : MenuBase +{ + private Problem Problem { get; } + + public ProblemMenu(Problem problem) + { + Problem = problem; + Choices = + [ + new BenchmarkSelection(Problem, 1), + new ExitSelection(2) + ]; + } + + public int Render() + { + ConsoleWriter.WriteHeader(clearConsole: true); + + AnsiConsole.Write(Problem.Markup()); + AnsiConsole.WriteLine(); + + var prompt = new SelectionPrompt() + .AddChoices(GetChoices()) + .UseConverter(m => m.Name); + + var selected = AnsiConsole.Prompt(prompt); + var exitCode = selected.Execute(); + + return exitCode; + } +} diff --git a/LeetCode/Menus/Selections/AboutSelection.cs b/LeetCode/Menus/Selections/AboutSelection.cs index b18c4c6..d8af98f 100644 --- a/LeetCode/Menus/Selections/AboutSelection.cs +++ b/LeetCode/Menus/Selections/AboutSelection.cs @@ -1,19 +1,19 @@ -namespace LeetCode.Menus.Selections; - -internal sealed record AboutSelection : Selection -{ - internal AboutSelection(int order) : base(Resources.Selection_About, order) - { - } - - public override int Execute() - { - ConsoleWriter.WriteHeader(clearConsole: true); - - AnsiConsole.WriteLine(Resources.About); - - ConsoleWriter.WaitForKeyPress(); - - return 0; - } +namespace LeetCode.Menus.Selections; + +internal sealed record AboutSelection : Selection +{ + internal AboutSelection(int order) : base(Resources.Selection_About, order) + { + } + + public override int Execute() + { + ConsoleWriter.WriteHeader(clearConsole: true); + + AnsiConsole.WriteLine(Resources.About); + + ConsoleWriter.WaitForKeyPress(); + + return 0; + } } \ No newline at end of file diff --git a/LeetCode/Menus/Selections/BenchmarkListSelection.cs b/LeetCode/Menus/Selections/BenchmarkListSelection.cs index 2129377..8ae6339 100644 --- a/LeetCode/Menus/Selections/BenchmarkListSelection.cs +++ b/LeetCode/Menus/Selections/BenchmarkListSelection.cs @@ -1,49 +1,49 @@ -namespace LeetCode.Menus.Selections; - -internal sealed record BenchmarkListSelection : Selection -{ - internal BenchmarkListSelection(int order) : base(Resources.Selection_RunBenchmarks, order) - { - } - - public override int Execute() - { - ConsoleWriter.WriteHeader(clearConsole: true); - - var categories = Reflection.GetProblemsByCategory().ToArray(); - - var prompt = new MultiSelectionPrompt() - .Title(Resources.Selection_Benchmark_Title) - .PageSize(16) - .MoreChoicesText(Resources.Selection_Benchmark_MoreChoicesText) - .InstructionsText(Resources.Selection_Benchmark_InstructionsText); - - foreach (var category in categories) - { - prompt.AddChoiceGroup(category.Key.Description(), - category.Select(p => p.Description)); - } - - var selectedProblems = AnsiConsole.Prompt(prompt); - if (selectedProblems.Count == 0) - { - return 0; - } - - var names = categories - .SelectMany(group => group) - .Where(problem => selectedProblems.Contains(problem.Description)) - .Select(problem => problem.Name); - - var settings = new BenchmarkSettings { Filter = string.Join(" ", names) }; - var summaries = BenchmarkRunner.BuildSummaries(settings); - var builder = new SpectreReportBuilder(summaries); - var report = builder.Build(); - - AnsiConsole.Write(report); - - ConsoleWriter.WaitForKeyPress(); - - return 0; - } +namespace LeetCode.Menus.Selections; + +internal sealed record BenchmarkListSelection : Selection +{ + internal BenchmarkListSelection(int order) : base(Resources.Selection_RunBenchmarks, order) + { + } + + public override int Execute() + { + ConsoleWriter.WriteHeader(clearConsole: true); + + var categories = Reflection.GetProblemsByCategory().ToArray(); + + var prompt = new MultiSelectionPrompt() + .Title(Resources.Selection_Benchmark_Title) + .PageSize(16) + .MoreChoicesText(Resources.Selection_Benchmark_MoreChoicesText) + .InstructionsText(Resources.Selection_Benchmark_InstructionsText); + + foreach (var category in categories) + { + prompt.AddChoiceGroup(category.Key.Description(), + category.Select(p => p.Description)); + } + + var selectedProblems = AnsiConsole.Prompt(prompt); + if (selectedProblems.Count == 0) + { + return 0; + } + + var names = categories + .SelectMany(group => group) + .Where(problem => selectedProblems.Contains(problem.Description)) + .Select(problem => problem.Name); + + var settings = new BenchmarkSettings { Filter = string.Join(" ", names) }; + var summaries = BenchmarkRunner.BuildSummaries(settings); + var builder = new SpectreReportBuilder(summaries); + var report = builder.Build(); + + AnsiConsole.Write(report); + + ConsoleWriter.WaitForKeyPress(); + + return 0; + } } \ No newline at end of file diff --git a/LeetCode/Menus/Selections/BenchmarkSelection.cs b/LeetCode/Menus/Selections/BenchmarkSelection.cs index d529df1..f096b9d 100644 --- a/LeetCode/Menus/Selections/BenchmarkSelection.cs +++ b/LeetCode/Menus/Selections/BenchmarkSelection.cs @@ -1,38 +1,38 @@ -namespace LeetCode.Menus.Selections; - -internal sealed record BenchmarkSelection : Selection -{ - private Problem Problem { get; } - - internal BenchmarkSelection(Problem problem, int order) - : this(problem, Resources.Selection_RunBenchmark, order) - { - } - - private BenchmarkSelection(Problem problem, string name, int order) - : base(name, order) - { - Problem = problem; - } - - public override int Execute() - { - ConsoleWriter.WriteHeader(clearConsole: true); - - if (BenchmarkRunner.IsDebugConfiguration(true)) - { - return 1; - } - - var settings = new BenchmarkSettings { Filter = Problem.Name }; - var summaries = BenchmarkRunner.BuildSummaries(settings); - var builder = new SpectreReportBuilder(summaries); - var report = builder.Build(); - - AnsiConsole.Write(report); - - ConsoleWriter.WaitForKeyPress(); - - return 0; - } +namespace LeetCode.Menus.Selections; + +internal sealed record BenchmarkSelection : Selection +{ + private Problem Problem { get; } + + internal BenchmarkSelection(Problem problem, int order) + : this(problem, Resources.Selection_RunBenchmark, order) + { + } + + private BenchmarkSelection(Problem problem, string name, int order) + : base(name, order) + { + Problem = problem; + } + + public override int Execute() + { + ConsoleWriter.WriteHeader(clearConsole: true); + + if (BenchmarkRunner.IsDebugConfiguration(true)) + { + return 1; + } + + var settings = new BenchmarkSettings { Filter = Problem.Name }; + var summaries = BenchmarkRunner.BuildSummaries(settings); + var builder = new SpectreReportBuilder(summaries); + var report = builder.Build(); + + AnsiConsole.Write(report); + + ConsoleWriter.WaitForKeyPress(); + + return 0; + } } \ No newline at end of file diff --git a/LeetCode/Menus/Selections/ExitSelection.cs b/LeetCode/Menus/Selections/ExitSelection.cs index ba74909..3e58e72 100644 --- a/LeetCode/Menus/Selections/ExitSelection.cs +++ b/LeetCode/Menus/Selections/ExitSelection.cs @@ -1,15 +1,15 @@ -namespace LeetCode.Menus.Selections; - -internal sealed record ExitSelection : Selection -{ - internal ExitSelection(int order) : base(Resources.Selection_Exit, order) - { - } - - public override int Execute() - { - ConsoleWriter.AnimateHeader(); - - return 0; - } +namespace LeetCode.Menus.Selections; + +internal sealed record ExitSelection : Selection +{ + internal ExitSelection(int order) : base(Resources.Selection_Exit, order) + { + } + + public override int Execute() + { + ConsoleWriter.AnimateHeader(); + + return 0; + } } \ No newline at end of file diff --git a/LeetCode/Menus/Selections/ProblemListSelection.cs b/LeetCode/Menus/Selections/ProblemListSelection.cs index c3e21da..3cf0699 100644 --- a/LeetCode/Menus/Selections/ProblemListSelection.cs +++ b/LeetCode/Menus/Selections/ProblemListSelection.cs @@ -1,57 +1,57 @@ -namespace LeetCode.Menus.Selections; - -internal sealed record ProblemListSelection : Selection -{ - internal ProblemListSelection(int order) : base(Resources.Selection_ProblemList, order) - { - } - - public override int Execute() - { - ConsoleWriter.WriteHeader(clearConsole: true); - - var problems = Reflection - .GetProblemsByCategory() - .SelectMany(g => g) - .ToArray(); - - var padding = new ProblemPadding( - problems.Max(problem => problem.Description.Length), - problems.Max(problem => problem.Category.Description().Length)); - - var prompt = new SelectionPrompt() - .AddChoices(problems) - .PageSize(16) - .UseConverter(problem => ConvertProblem(problem, padding)) - .MoreChoicesText(Resources.Selection_Benchmark_MoreChoicesText); - - var table = new Table - { - Border = TableBorder.Simple, - UseSafeBorder = true - }; - table.AddColumns(Resources.Problem_Name, Resources.Problem_Category, Resources.Problem_Difficulty); - table.Columns[0].Width = padding.DescriptionPad; - table.Columns[1].Width = padding.CategoryPad; - - AnsiConsole.Cursor.MoveUp(); - AnsiConsole.Write(table); - - // TODO Capture X (or whatever) to return to main menu instead of forcing selection - // It would also be good to filter by keyboard input - var problem = AnsiConsole.Prompt(prompt); - - new ProblemMenu(problem).Render(); - - return 0; - } - - private sealed record ProblemPadding(int DescriptionPad, int CategoryPad); - - private static string ConvertProblem(Problem problem, ProblemPadding padding) - => new StringBuilder() - .Append($"{problem.Description.PadRight(padding.DescriptionPad + 3)}") - .Append($"{problem.Category.Description().PadRight(padding.CategoryPad + 3)}") - .Append($"{problem.Difficulty.Markup()}") - .ToString(); +namespace LeetCode.Menus.Selections; + +internal sealed record ProblemListSelection : Selection +{ + internal ProblemListSelection(int order) : base(Resources.Selection_ProblemList, order) + { + } + + public override int Execute() + { + ConsoleWriter.WriteHeader(clearConsole: true); + + var problems = Reflection + .GetProblemsByCategory() + .SelectMany(g => g) + .ToArray(); + + var padding = new ProblemPadding( + problems.Max(problem => problem.Description.Length), + problems.Max(problem => problem.Category.Description().Length)); + + var prompt = new SelectionPrompt() + .AddChoices(problems) + .PageSize(16) + .UseConverter(problem => ConvertProblem(problem, padding)) + .MoreChoicesText(Resources.Selection_Benchmark_MoreChoicesText); + + var table = new Table + { + Border = TableBorder.Simple, + UseSafeBorder = true + }; + table.AddColumns(Resources.Problem_Name, Resources.Problem_Category, Resources.Problem_Difficulty); + table.Columns[0].Width = padding.DescriptionPad; + table.Columns[1].Width = padding.CategoryPad; + + AnsiConsole.Cursor.MoveUp(); + AnsiConsole.Write(table); + + // TODO Capture X (or whatever) to return to main menu instead of forcing selection + // It would also be good to filter by keyboard input + var problem = AnsiConsole.Prompt(prompt); + + new ProblemMenu(problem).Render(); + + return 0; + } + + private sealed record ProblemPadding(int DescriptionPad, int CategoryPad); + + private static string ConvertProblem(Problem problem, ProblemPadding padding) + => new StringBuilder() + .Append($"{problem.Description.PadRight(padding.DescriptionPad + 3)}") + .Append($"{problem.Category.Description().PadRight(padding.CategoryPad + 3)}") + .Append($"{problem.Difficulty.Markup()}") + .ToString(); } \ No newline at end of file diff --git a/LeetCode/Menus/Selections/Selection.cs b/LeetCode/Menus/Selections/Selection.cs index d197cb4..88a5031 100644 --- a/LeetCode/Menus/Selections/Selection.cs +++ b/LeetCode/Menus/Selections/Selection.cs @@ -1,10 +1,10 @@ -namespace LeetCode.Menus.Selections; - -internal abstract record Selection(string Name, int Order) -{ - /// - /// Execute a menu item when selected - /// - /// Status code - public abstract int Execute(); +namespace LeetCode.Menus.Selections; + +internal abstract record Selection(string Name, int Order) +{ + /// + /// Execute a menu item when selected + /// + /// Status code + public abstract int Execute(); } \ No newline at end of file diff --git a/LeetCode/Problem.cs b/LeetCode/Problem.cs index ad96f09..1eb5ad8 100644 --- a/LeetCode/Problem.cs +++ b/LeetCode/Problem.cs @@ -1,29 +1,29 @@ -namespace LeetCode; - -internal record Problem( - string Name, - string Description, - Category Category, - Difficulty Difficulty, - Uri? Link, - bool CSharp, - bool FSharp) -{ - public string Language(string join = " ") => - CSharp && FSharp - ? string.Join(join, "C#", "F#") - : CSharp - ? "C#" - : FSharp - ? "F#" - : string.Empty; - - public string LanguageMarkup(string join = " ") => - CSharp && FSharp - ? string.Join(join, "[blue]C#[/]", "[teal]F#[/]") - : CSharp - ? "[blue]C#[/]" - : FSharp - ? "[teal]F#[/]" - : string.Empty; +namespace LeetCode; + +internal record Problem( + string Name, + string Description, + Category Category, + Difficulty Difficulty, + Uri? Link, + bool CSharp, + bool FSharp) +{ + public string Language(string join = " ") => + CSharp && FSharp + ? string.Join(join, "C#", "F#") + : CSharp + ? "C#" + : FSharp + ? "F#" + : string.Empty; + + public string LanguageMarkup(string join = " ") => + CSharp && FSharp + ? string.Join(join, "[blue]C#[/]", "[teal]F#[/]") + : CSharp + ? "[blue]C#[/]" + : FSharp + ? "[teal]F#[/]" + : string.Empty; } \ No newline at end of file diff --git a/LeetCode/Program.cs b/LeetCode/Program.cs index 047b1a3..d42e5d0 100644 --- a/LeetCode/Program.cs +++ b/LeetCode/Program.cs @@ -1,28 +1,28 @@ -using LeetCode; - -var app = new CommandApp(); - -app.Configure(config => -{ - config.SetApplicationName("LeetCode.exe"); - - config.AddCommand(Resources.Command_App) - .WithDescription(Resources.Command_App_Description); - - config.AddCommand(Resources.Command_Benchmark) - .WithDescription(Resources.Command_Benchmark_Description); - - config.AddCommand(Resources.Command_Info) - .WithDescription(Resources.Command_Info_Description); - - config.AddCommand(Resources.Command_List) - .WithDescription(Resources.Command_List_Description); - - config.AddCommand(Resources.Command_Workflow) - .WithDescription(Resources.Command_Workflow_Description); - - config.AddExample(Resources.Command_Benchmark, "LRUCache", "--csharp"); - config.AddExample(Resources.Command_Info, "MergeTwoLists"); -}); - -return await app.RunAsync(args); +using LeetCode; + +var app = new CommandApp(); + +app.Configure(config => +{ + config.SetApplicationName("LeetCode.exe"); + + config.AddCommand(Resources.Command_App) + .WithDescription(Resources.Command_App_Description); + + config.AddCommand(Resources.Command_Benchmark) + .WithDescription(Resources.Command_Benchmark_Description); + + config.AddCommand(Resources.Command_Info) + .WithDescription(Resources.Command_Info_Description); + + config.AddCommand(Resources.Command_List) + .WithDescription(Resources.Command_List_Description); + + config.AddCommand(Resources.Command_Workflow) + .WithDescription(Resources.Command_Workflow_Description); + + config.AddExample(Resources.Command_Benchmark, "LRUCache", "--csharp"); + config.AddExample(Resources.Command_Info, "MergeTwoLists"); +}); + +return await app.RunAsync(args); diff --git a/LeetCode/Reflection.cs b/LeetCode/Reflection.cs index 0a14d2a..b539c01 100644 --- a/LeetCode/Reflection.cs +++ b/LeetCode/Reflection.cs @@ -1,80 +1,80 @@ -namespace LeetCode; - -internal static class Reflection -{ - public static bool TryGetProblem(string name, out Problem problem) - { - var found = typeof(CSharp.Problems.Problem) - .GetMembers() - .Where(m => m.GetCustomAttribute() is not null) - .Select(GetProblem) - .FirstOrDefault(p => - p.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase) || - p.Description.Equals(name, StringComparison.InvariantCultureIgnoreCase)); - - problem = found ?? null!; - - return found is not null; - } - - private static Problem GetProblem(MemberInfo memberInfo) - { - var csharp = GetCSharpProblems().Contains(memberInfo.Name); - var fsharp = GetFSharpProblems().Contains(memberInfo.Name); - var attribute = memberInfo.GetCustomAttribute(); - - if (attribute is null || !csharp && !fsharp) - { - throw new InvalidOperationException($"Invalid member info '{memberInfo.Name}"); - } - - return new Problem( - memberInfo.Name, - attribute.Description, - attribute.Category, - attribute.Difficulty, - attribute.Link, - csharp, - fsharp); - } - - public static IEnumerable> GetProblemsByCategory() => - typeof(CSharp.Problems.Problem) - .GetMembers() - .Where(m => m.GetCustomAttribute() is not null) - .Select(GetProblem) - .OrderBy(p => p.Category) - .ThenBy(p => p.Difficulty) - .ThenBy(p => p.Description) - .GroupBy(p => p.Category, p => p); - - public static IEnumerable GetCSharpBenchmarks() => - GetCSharpBenchmarkTypes().Select(type => - type.Name.EndsWith("Benchmark") ? type.Name[..^9] : type.Name); - - public static IEnumerable GetFSharpBenchmarks() => - GetFSharpBenchmarkTypes().Select(type => - type.Name.EndsWith("Benchmark") ? type.Name[..^9] : type.Name); - - public static IEnumerable GetCSharpBenchmarkTypes() => - typeof(Benchmark).Assembly.GetTypes() - .Where(type => type.Namespace is not null && !type.IsAbstract && - type.Namespace.StartsWith("LeetCode.CSharp.Benchmarks")); - - public static IEnumerable GetFSharpBenchmarkTypes() => - typeof(FSharp.ListNode).Assembly.GetTypes() - .Where(type => type.Namespace is not null && - type.Namespace.StartsWith("LeetCode.FSharp.Benchmarks")); - - private static IEnumerable GetCSharpProblems() => - typeof(CSharp.Problems.Problem) - .GetMembers() - .Where(m => m.GetCustomAttribute() is not null) - .Select(m => m.Name); - - private static IEnumerable GetFSharpProblems() => - typeof(FSharp.ListNode).Assembly.GetTypes() - .Where(type => type.Namespace is not null && - type.Namespace.StartsWith("LeetCode.FSharp.Problems")) - .Select(m => m.Name); -} +namespace LeetCode; + +internal static class Reflection +{ + public static bool TryGetProblem(string name, out Problem problem) + { + var found = typeof(CSharp.Problems.Problem) + .GetMembers() + .Where(m => m.GetCustomAttribute() is not null) + .Select(GetProblem) + .FirstOrDefault(p => + p.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase) || + p.Description.Equals(name, StringComparison.InvariantCultureIgnoreCase)); + + problem = found ?? null!; + + return found is not null; + } + + private static Problem GetProblem(MemberInfo memberInfo) + { + var csharp = GetCSharpProblems().Contains(memberInfo.Name); + var fsharp = GetFSharpProblems().Contains(memberInfo.Name); + var attribute = memberInfo.GetCustomAttribute(); + + if (attribute is null || !csharp && !fsharp) + { + throw new InvalidOperationException($"Invalid member info '{memberInfo.Name}"); + } + + return new Problem( + memberInfo.Name, + attribute.Description, + attribute.Category, + attribute.Difficulty, + attribute.Link, + csharp, + fsharp); + } + + public static IEnumerable> GetProblemsByCategory() => + typeof(CSharp.Problems.Problem) + .GetMembers() + .Where(m => m.GetCustomAttribute() is not null) + .Select(GetProblem) + .OrderBy(p => p.Category) + .ThenBy(p => p.Difficulty) + .ThenBy(p => p.Description) + .GroupBy(p => p.Category, p => p); + + public static IEnumerable GetCSharpBenchmarks() => + GetCSharpBenchmarkTypes().Select(type => + type.Name.EndsWith("Benchmark") ? type.Name[..^9] : type.Name); + + public static IEnumerable GetFSharpBenchmarks() => + GetFSharpBenchmarkTypes().Select(type => + type.Name.EndsWith("Benchmark") ? type.Name[..^9] : type.Name); + + public static IEnumerable GetCSharpBenchmarkTypes() => + typeof(Benchmark).Assembly.GetTypes() + .Where(type => type.Namespace is not null && !type.IsAbstract && + type.Namespace.StartsWith("LeetCode.CSharp.Benchmarks")); + + public static IEnumerable GetFSharpBenchmarkTypes() => + typeof(FSharp.ListNode).Assembly.GetTypes() + .Where(type => type.Namespace is not null && + type.Namespace.StartsWith("LeetCode.FSharp.Benchmarks")); + + private static IEnumerable GetCSharpProblems() => + typeof(CSharp.Problems.Problem) + .GetMembers() + .Where(m => m.GetCustomAttribute() is not null) + .Select(m => m.Name); + + private static IEnumerable GetFSharpProblems() => + typeof(FSharp.ListNode).Assembly.GetTypes() + .Where(type => type.Namespace is not null && + type.Namespace.StartsWith("LeetCode.FSharp.Problems")) + .Select(m => m.Name); +} diff --git a/LeetCode/Resources.Designer.cs b/LeetCode/Resources.Designer.cs index 8cfc16d..09c39bf 100644 --- a/LeetCode/Resources.Designer.cs +++ b/LeetCode/Resources.Designer.cs @@ -1,697 +1,697 @@ -//------------------------------------------------------------------------------ -// -// This code was generated by a tool. -// -// Changes to this file may cause incorrect behavior and will be lost if -// the code is regenerated. -// -//------------------------------------------------------------------------------ - -namespace LeetCode { - using System; - - - /// - /// A strongly-typed resource class, for looking up localized strings, etc. - /// - // This class was auto-generated by the StronglyTypedResourceBuilder - // class via a tool like ResGen or Visual Studio. - // To add or remove a member, edit your .ResX file then rerun ResGen - // with the /str option, or rebuild your VS project. - [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] - [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] - [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] - internal class Resources { - - private static global::System.Resources.ResourceManager resourceMan; - - private static global::System.Globalization.CultureInfo resourceCulture; - - [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] - internal Resources() { - } - - /// - /// Returns the cached ResourceManager instance used by this class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Resources.ResourceManager ResourceManager { - get { - if (object.ReferenceEquals(resourceMan, null)) { - global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LeetCode.Resources", typeof(Resources).Assembly); - resourceMan = temp; - } - return resourceMan; - } - } - - /// - /// Overrides the current thread's CurrentUICulture property for all - /// resource lookups using this strongly typed resource class. - /// - [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] - internal static global::System.Globalization.CultureInfo Culture { - get { - return resourceCulture; - } - set { - resourceCulture = value; - } - } - - /// - /// Looks up a localized string similar to Benchmarked LeetCode problems written in C# and F#. - /// - internal static string About { - get { - return ResourceManager.GetString("About", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Benchmarks. - /// - internal static string Benchmark_Plural { - get { - return ResourceManager.GetString("Benchmark_Plural", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Benchmark. - /// - internal static string Benchmark_Singular { - get { - return ResourceManager.GetString("Benchmark_Singular", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Running C# and F# benchmarks. - /// - internal static string BenchmarkRunner_Running_BothBenchmarks { - get { - return ResourceManager.GetString("BenchmarkRunner_Running_BothBenchmarks", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Running C# benchmarks. - /// - internal static string BenchmarkRunner_Running_CSharpBenchmarks { - get { - return ResourceManager.GetString("BenchmarkRunner_Running_CSharpBenchmarks", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to matching [yellow]{0}[/]. - /// - internal static string BenchmarkRunner_Running_FilterSuffix_Markup { - get { - return ResourceManager.GetString("BenchmarkRunner_Running_FilterSuffix_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Running F# benchmarks. - /// - internal static string BenchmarkRunner_Running_FSharpBenchmarks { - get { - return ResourceManager.GetString("BenchmarkRunner_Running_FSharpBenchmarks", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Running selected benchmarks. - /// - internal static string BenchmarkRunner_Running_SelectedBenchmarks { - get { - return ResourceManager.GetString("BenchmarkRunner_Running_SelectedBenchmarks", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Running {0} {1} for [yellow]{2}[/]. - /// - internal static string BenchmarkRunner_SingleProblem_Markup { - get { - return ResourceManager.GetString("BenchmarkRunner_SingleProblem_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [gray](method: {0})[/]. - /// - internal static string BenchmarkRunner_SingleProblem_Name { - get { - return ResourceManager.GetString("BenchmarkRunner_SingleProblem_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Benchmark not found '{0}'. - /// - internal static string BenchmarkSettings_Error_BenchmarkNotFound { - get { - return ResourceManager.GetString("BenchmarkSettings_Error_BenchmarkNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to --csharp and --fsharp options are mutually exclusive. - /// - internal static string BenchmarkSettings_Error_MutuallyExclusive { - get { - return ResourceManager.GetString("BenchmarkSettings_Error_MutuallyExclusive", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Advanced Graphs. - /// - internal static string Category_AdvancedGraphs { - get { - return ResourceManager.GetString("Category_AdvancedGraphs", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Arrays & Hashing. - /// - internal static string Category_ArraysAndHashing { - get { - return ResourceManager.GetString("Category_ArraysAndHashing", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Back Tracking. - /// - internal static string Category_BackTracking { - get { - return ResourceManager.GetString("Category_BackTracking", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Binary Search. - /// - internal static string Category_BinarySearch { - get { - return ResourceManager.GetString("Category_BinarySearch", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Bit Manipulation. - /// - internal static string Category_BitManipulation { - get { - return ResourceManager.GetString("Category_BitManipulation", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Graphs. - /// - internal static string Category_Graphs { - get { - return ResourceManager.GetString("Category_Graphs", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Greedy. - /// - internal static string Category_Greedy { - get { - return ResourceManager.GetString("Category_Greedy", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Heap / Priority Queue. - /// - internal static string Category_HeapPriorityQueue { - get { - return ResourceManager.GetString("Category_HeapPriorityQueue", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Intervals. - /// - internal static string Category_Intervals { - get { - return ResourceManager.GetString("Category_Intervals", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Linked List. - /// - internal static string Category_LinkedList { - get { - return ResourceManager.GetString("Category_LinkedList", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Maths & Geometry. - /// - internal static string Category_MathAndGeometry { - get { - return ResourceManager.GetString("Category_MathAndGeometry", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Not in NeetCode. - /// - internal static string Category_NotInNeetCode { - get { - return ResourceManager.GetString("Category_NotInNeetCode", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to 1-D Dynamic Programming. - /// - internal static string Category_OneDDynamicProgramming { - get { - return ResourceManager.GetString("Category_OneDDynamicProgramming", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Sliding Window. - /// - internal static string Category_SlidingWindow { - get { - return ResourceManager.GetString("Category_SlidingWindow", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Stack. - /// - internal static string Category_Stack { - get { - return ResourceManager.GetString("Category_Stack", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Trees. - /// - internal static string Category_Trees { - get { - return ResourceManager.GetString("Category_Trees", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Tries. - /// - internal static string Category_Tries { - get { - return ResourceManager.GetString("Category_Tries", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to 2-D Dynamic Programming. - /// - internal static string Category_TwoDDynamicProgramming { - get { - return ResourceManager.GetString("Category_TwoDDynamicProgramming", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Two Pointers. - /// - internal static string Category_TwoPointers { - get { - return ResourceManager.GetString("Category_TwoPointers", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to app. - /// - internal static string Command_App { - get { - return ResourceManager.GetString("Command_App", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Run interactive console application. - /// - internal static string Command_App_Description { - get { - return ResourceManager.GetString("Command_App_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to benchmark. - /// - internal static string Command_Benchmark { - get { - return ResourceManager.GetString("Command_Benchmark", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Run benchmarks against leetcode problems. - /// - internal static string Command_Benchmark_Description { - get { - return ResourceManager.GetString("Command_Benchmark_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to info. - /// - internal static string Command_Info { - get { - return ResourceManager.GetString("Command_Info", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Show information about a problem. - /// - internal static string Command_Info_Description { - get { - return ResourceManager.GetString("Command_Info_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to list. - /// - internal static string Command_List { - get { - return ResourceManager.GetString("Command_List", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to List information about problems. - /// - internal static string Command_List_Description { - get { - return ResourceManager.GetString("Command_List_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to workflow. - /// - internal static string Command_Workflow { - get { - return ResourceManager.GetString("Command_Workflow", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Run benchmarks for a GitHub workflow. - /// - internal static string Command_Workflow_Description { - get { - return ResourceManager.GetString("Command_Workflow_Description", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [gray](Press any key to return to main menu)[/]. - /// - internal static string Console_ReturnToMainMenu_Markup { - get { - return ResourceManager.GetString("Console_ReturnToMainMenu_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [green]Easy[/]. - /// - internal static string Difficulty_Easy_Markup { - get { - return ResourceManager.GetString("Difficulty_Easy_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [red]Hard[/]. - /// - internal static string Difficulty_Hard_Markup { - get { - return ResourceManager.GetString("Difficulty_Hard_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [orange1]Medium[/]. - /// - internal static string Difficulty_Medium_Markup { - get { - return ResourceManager.GetString("Difficulty_Medium_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to __ __ ______ __ - /// / / ___ ___ / /_ / ____/____ ____/ /___ - /// / / / _ \ / _ \ / __// / / __ \ / __ // _ \ - /// / /___/ __// __// /_ / /___ / /_/ // /_/ // __/ - /// /_____/\___/ \___/ \__/ \____/ \____/ \__,_/ \___/ - ///. - /// - internal static string LeetCode_Figlet { - get { - return ResourceManager.GetString("LeetCode_Figlet", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [red]* Missing C# and F# Benchmarks *[/]. - /// - internal static string ListCommand_Missing_BothBenchmarks_Markup { - get { - return ResourceManager.GetString("ListCommand_Missing_BothBenchmarks_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [red]* Missing C# Benchmark *[/]. - /// - internal static string ListCommand_Missing_CSharpBenchmark_Markup { - get { - return ResourceManager.GetString("ListCommand_Missing_CSharpBenchmark_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [red]* Missing F# Benchmark *[/]. - /// - internal static string ListCommand_Missing_FSharpBenchmark_Markup { - get { - return ResourceManager.GetString("ListCommand_Missing_FSharpBenchmark_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [gray]Benchmark[/]. - /// - internal static string Problem_Benchmark_Markup { - get { - return ResourceManager.GetString("Problem_Benchmark_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Category. - /// - internal static string Problem_Category { - get { - return ResourceManager.GetString("Problem_Category", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [gray]Category[/]. - /// - internal static string Problem_Category_Markup { - get { - return ResourceManager.GetString("Problem_Category_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [gray]Description[/]. - /// - internal static string Problem_Description_Markup { - get { - return ResourceManager.GetString("Problem_Description_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Difficulty. - /// - internal static string Problem_Difficulty { - get { - return ResourceManager.GetString("Problem_Difficulty", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [gray]Difficulty[/]. - /// - internal static string Problem_Difficulty_Markup { - get { - return ResourceManager.GetString("Problem_Difficulty_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Language. - /// - internal static string Problem_Language { - get { - return ResourceManager.GetString("Problem_Language", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [gray]Language[/]. - /// - internal static string Problem_Language_Markup { - get { - return ResourceManager.GetString("Problem_Language_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to and. - /// - internal static string Problem_Language_Separator { - get { - return ResourceManager.GetString("Problem_Language_Separator", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [gray]Name[/]. - /// - internal static string Problem_Link_Markup { - get { - return ResourceManager.GetString("Problem_Link_Markup", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Problem. - /// - internal static string Problem_Name { - get { - return ResourceManager.GetString("Problem_Name", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to No problem argument passed. - /// - internal static string ProblemSettings_Error_NoArgumentPassed { - get { - return ResourceManager.GetString("ProblemSettings_Error_NoArgumentPassed", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Problem not found '{0}'. - /// - internal static string ProblemSettings_Error_ProblemNotFound { - get { - return ResourceManager.GetString("ProblemSettings_Error_ProblemNotFound", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to About. - /// - internal static string Selection_About { - get { - return ResourceManager.GetString("Selection_About", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [grey](Press [blue]<space>[/] to toggle, [green]<enter>[/] to run)[/]. - /// - internal static string Selection_Benchmark_InstructionsText { - get { - return ResourceManager.GetString("Selection_Benchmark_InstructionsText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to [gray](Move up and down to reveal more problems)[/]. - /// - internal static string Selection_Benchmark_MoreChoicesText { - get { - return ResourceManager.GetString("Selection_Benchmark_MoreChoicesText", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Select benchmarks to run. - /// - internal static string Selection_Benchmark_Title { - get { - return ResourceManager.GetString("Selection_Benchmark_Title", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Exit. - /// - internal static string Selection_Exit { - get { - return ResourceManager.GetString("Selection_Exit", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to List Problems. - /// - internal static string Selection_ProblemList { - get { - return ResourceManager.GetString("Selection_ProblemList", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Run Benchmark. - /// - internal static string Selection_RunBenchmark { - get { - return ResourceManager.GetString("Selection_RunBenchmark", resourceCulture); - } - } - - /// - /// Looks up a localized string similar to Run Benchmarks. - /// - internal static string Selection_RunBenchmarks { - get { - return ResourceManager.GetString("Selection_RunBenchmarks", resourceCulture); - } - } - } -} +//------------------------------------------------------------------------------ +// +// This code was generated by a tool. +// +// Changes to this file may cause incorrect behavior and will be lost if +// the code is regenerated. +// +//------------------------------------------------------------------------------ + +namespace LeetCode { + using System; + + + /// + /// A strongly-typed resource class, for looking up localized strings, etc. + /// + // This class was auto-generated by the StronglyTypedResourceBuilder + // class via a tool like ResGen or Visual Studio. + // To add or remove a member, edit your .ResX file then rerun ResGen + // with the /str option, or rebuild your VS project. + [global::System.CodeDom.Compiler.GeneratedCodeAttribute("System.Resources.Tools.StronglyTypedResourceBuilder", "17.0.0.0")] + [global::System.Diagnostics.DebuggerNonUserCodeAttribute()] + [global::System.Runtime.CompilerServices.CompilerGeneratedAttribute()] + internal class Resources { + + private static global::System.Resources.ResourceManager resourceMan; + + private static global::System.Globalization.CultureInfo resourceCulture; + + [global::System.Diagnostics.CodeAnalysis.SuppressMessageAttribute("Microsoft.Performance", "CA1811:AvoidUncalledPrivateCode")] + internal Resources() { + } + + /// + /// Returns the cached ResourceManager instance used by this class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Resources.ResourceManager ResourceManager { + get { + if (object.ReferenceEquals(resourceMan, null)) { + global::System.Resources.ResourceManager temp = new global::System.Resources.ResourceManager("LeetCode.Resources", typeof(Resources).Assembly); + resourceMan = temp; + } + return resourceMan; + } + } + + /// + /// Overrides the current thread's CurrentUICulture property for all + /// resource lookups using this strongly typed resource class. + /// + [global::System.ComponentModel.EditorBrowsableAttribute(global::System.ComponentModel.EditorBrowsableState.Advanced)] + internal static global::System.Globalization.CultureInfo Culture { + get { + return resourceCulture; + } + set { + resourceCulture = value; + } + } + + /// + /// Looks up a localized string similar to Benchmarked LeetCode problems written in C# and F#. + /// + internal static string About { + get { + return ResourceManager.GetString("About", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Benchmarks. + /// + internal static string Benchmark_Plural { + get { + return ResourceManager.GetString("Benchmark_Plural", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Benchmark. + /// + internal static string Benchmark_Singular { + get { + return ResourceManager.GetString("Benchmark_Singular", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Running C# and F# benchmarks. + /// + internal static string BenchmarkRunner_Running_BothBenchmarks { + get { + return ResourceManager.GetString("BenchmarkRunner_Running_BothBenchmarks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Running C# benchmarks. + /// + internal static string BenchmarkRunner_Running_CSharpBenchmarks { + get { + return ResourceManager.GetString("BenchmarkRunner_Running_CSharpBenchmarks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to matching [yellow]{0}[/]. + /// + internal static string BenchmarkRunner_Running_FilterSuffix_Markup { + get { + return ResourceManager.GetString("BenchmarkRunner_Running_FilterSuffix_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Running F# benchmarks. + /// + internal static string BenchmarkRunner_Running_FSharpBenchmarks { + get { + return ResourceManager.GetString("BenchmarkRunner_Running_FSharpBenchmarks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Running selected benchmarks. + /// + internal static string BenchmarkRunner_Running_SelectedBenchmarks { + get { + return ResourceManager.GetString("BenchmarkRunner_Running_SelectedBenchmarks", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Running {0} {1} for [yellow]{2}[/]. + /// + internal static string BenchmarkRunner_SingleProblem_Markup { + get { + return ResourceManager.GetString("BenchmarkRunner_SingleProblem_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [gray](method: {0})[/]. + /// + internal static string BenchmarkRunner_SingleProblem_Name { + get { + return ResourceManager.GetString("BenchmarkRunner_SingleProblem_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Benchmark not found '{0}'. + /// + internal static string BenchmarkSettings_Error_BenchmarkNotFound { + get { + return ResourceManager.GetString("BenchmarkSettings_Error_BenchmarkNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to --csharp and --fsharp options are mutually exclusive. + /// + internal static string BenchmarkSettings_Error_MutuallyExclusive { + get { + return ResourceManager.GetString("BenchmarkSettings_Error_MutuallyExclusive", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Advanced Graphs. + /// + internal static string Category_AdvancedGraphs { + get { + return ResourceManager.GetString("Category_AdvancedGraphs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Arrays & Hashing. + /// + internal static string Category_ArraysAndHashing { + get { + return ResourceManager.GetString("Category_ArraysAndHashing", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Back Tracking. + /// + internal static string Category_BackTracking { + get { + return ResourceManager.GetString("Category_BackTracking", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Binary Search. + /// + internal static string Category_BinarySearch { + get { + return ResourceManager.GetString("Category_BinarySearch", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Bit Manipulation. + /// + internal static string Category_BitManipulation { + get { + return ResourceManager.GetString("Category_BitManipulation", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Graphs. + /// + internal static string Category_Graphs { + get { + return ResourceManager.GetString("Category_Graphs", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Greedy. + /// + internal static string Category_Greedy { + get { + return ResourceManager.GetString("Category_Greedy", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Heap / Priority Queue. + /// + internal static string Category_HeapPriorityQueue { + get { + return ResourceManager.GetString("Category_HeapPriorityQueue", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Intervals. + /// + internal static string Category_Intervals { + get { + return ResourceManager.GetString("Category_Intervals", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Linked List. + /// + internal static string Category_LinkedList { + get { + return ResourceManager.GetString("Category_LinkedList", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Maths & Geometry. + /// + internal static string Category_MathAndGeometry { + get { + return ResourceManager.GetString("Category_MathAndGeometry", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Not in NeetCode. + /// + internal static string Category_NotInNeetCode { + get { + return ResourceManager.GetString("Category_NotInNeetCode", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 1-D Dynamic Programming. + /// + internal static string Category_OneDDynamicProgramming { + get { + return ResourceManager.GetString("Category_OneDDynamicProgramming", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Sliding Window. + /// + internal static string Category_SlidingWindow { + get { + return ResourceManager.GetString("Category_SlidingWindow", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Stack. + /// + internal static string Category_Stack { + get { + return ResourceManager.GetString("Category_Stack", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Trees. + /// + internal static string Category_Trees { + get { + return ResourceManager.GetString("Category_Trees", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Tries. + /// + internal static string Category_Tries { + get { + return ResourceManager.GetString("Category_Tries", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to 2-D Dynamic Programming. + /// + internal static string Category_TwoDDynamicProgramming { + get { + return ResourceManager.GetString("Category_TwoDDynamicProgramming", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Two Pointers. + /// + internal static string Category_TwoPointers { + get { + return ResourceManager.GetString("Category_TwoPointers", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to app. + /// + internal static string Command_App { + get { + return ResourceManager.GetString("Command_App", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Run interactive console application. + /// + internal static string Command_App_Description { + get { + return ResourceManager.GetString("Command_App_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to benchmark. + /// + internal static string Command_Benchmark { + get { + return ResourceManager.GetString("Command_Benchmark", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Run benchmarks against leetcode problems. + /// + internal static string Command_Benchmark_Description { + get { + return ResourceManager.GetString("Command_Benchmark_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to info. + /// + internal static string Command_Info { + get { + return ResourceManager.GetString("Command_Info", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Show information about a problem. + /// + internal static string Command_Info_Description { + get { + return ResourceManager.GetString("Command_Info_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to list. + /// + internal static string Command_List { + get { + return ResourceManager.GetString("Command_List", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List information about problems. + /// + internal static string Command_List_Description { + get { + return ResourceManager.GetString("Command_List_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to workflow. + /// + internal static string Command_Workflow { + get { + return ResourceManager.GetString("Command_Workflow", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Run benchmarks for a GitHub workflow. + /// + internal static string Command_Workflow_Description { + get { + return ResourceManager.GetString("Command_Workflow_Description", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [gray](Press any key to return to main menu)[/]. + /// + internal static string Console_ReturnToMainMenu_Markup { + get { + return ResourceManager.GetString("Console_ReturnToMainMenu_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [green]Easy[/]. + /// + internal static string Difficulty_Easy_Markup { + get { + return ResourceManager.GetString("Difficulty_Easy_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [red]Hard[/]. + /// + internal static string Difficulty_Hard_Markup { + get { + return ResourceManager.GetString("Difficulty_Hard_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [orange1]Medium[/]. + /// + internal static string Difficulty_Medium_Markup { + get { + return ResourceManager.GetString("Difficulty_Medium_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to __ __ ______ __ + /// / / ___ ___ / /_ / ____/____ ____/ /___ + /// / / / _ \ / _ \ / __// / / __ \ / __ // _ \ + /// / /___/ __// __// /_ / /___ / /_/ // /_/ // __/ + /// /_____/\___/ \___/ \__/ \____/ \____/ \__,_/ \___/ + ///. + /// + internal static string LeetCode_Figlet { + get { + return ResourceManager.GetString("LeetCode_Figlet", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [red]* Missing C# and F# Benchmarks *[/]. + /// + internal static string ListCommand_Missing_BothBenchmarks_Markup { + get { + return ResourceManager.GetString("ListCommand_Missing_BothBenchmarks_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [red]* Missing C# Benchmark *[/]. + /// + internal static string ListCommand_Missing_CSharpBenchmark_Markup { + get { + return ResourceManager.GetString("ListCommand_Missing_CSharpBenchmark_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [red]* Missing F# Benchmark *[/]. + /// + internal static string ListCommand_Missing_FSharpBenchmark_Markup { + get { + return ResourceManager.GetString("ListCommand_Missing_FSharpBenchmark_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [gray]Benchmark[/]. + /// + internal static string Problem_Benchmark_Markup { + get { + return ResourceManager.GetString("Problem_Benchmark_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Category. + /// + internal static string Problem_Category { + get { + return ResourceManager.GetString("Problem_Category", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [gray]Category[/]. + /// + internal static string Problem_Category_Markup { + get { + return ResourceManager.GetString("Problem_Category_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [gray]Description[/]. + /// + internal static string Problem_Description_Markup { + get { + return ResourceManager.GetString("Problem_Description_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Difficulty. + /// + internal static string Problem_Difficulty { + get { + return ResourceManager.GetString("Problem_Difficulty", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [gray]Difficulty[/]. + /// + internal static string Problem_Difficulty_Markup { + get { + return ResourceManager.GetString("Problem_Difficulty_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Language. + /// + internal static string Problem_Language { + get { + return ResourceManager.GetString("Problem_Language", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [gray]Language[/]. + /// + internal static string Problem_Language_Markup { + get { + return ResourceManager.GetString("Problem_Language_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to and. + /// + internal static string Problem_Language_Separator { + get { + return ResourceManager.GetString("Problem_Language_Separator", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [gray]Name[/]. + /// + internal static string Problem_Link_Markup { + get { + return ResourceManager.GetString("Problem_Link_Markup", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Problem. + /// + internal static string Problem_Name { + get { + return ResourceManager.GetString("Problem_Name", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to No problem argument passed. + /// + internal static string ProblemSettings_Error_NoArgumentPassed { + get { + return ResourceManager.GetString("ProblemSettings_Error_NoArgumentPassed", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Problem not found '{0}'. + /// + internal static string ProblemSettings_Error_ProblemNotFound { + get { + return ResourceManager.GetString("ProblemSettings_Error_ProblemNotFound", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to About. + /// + internal static string Selection_About { + get { + return ResourceManager.GetString("Selection_About", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [grey](Press [blue]<space>[/] to toggle, [green]<enter>[/] to run)[/]. + /// + internal static string Selection_Benchmark_InstructionsText { + get { + return ResourceManager.GetString("Selection_Benchmark_InstructionsText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to [gray](Move up and down to reveal more problems)[/]. + /// + internal static string Selection_Benchmark_MoreChoicesText { + get { + return ResourceManager.GetString("Selection_Benchmark_MoreChoicesText", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Select benchmarks to run. + /// + internal static string Selection_Benchmark_Title { + get { + return ResourceManager.GetString("Selection_Benchmark_Title", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Exit. + /// + internal static string Selection_Exit { + get { + return ResourceManager.GetString("Selection_Exit", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to List Problems. + /// + internal static string Selection_ProblemList { + get { + return ResourceManager.GetString("Selection_ProblemList", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Run Benchmark. + /// + internal static string Selection_RunBenchmark { + get { + return ResourceManager.GetString("Selection_RunBenchmark", resourceCulture); + } + } + + /// + /// Looks up a localized string similar to Run Benchmarks. + /// + internal static string Selection_RunBenchmarks { + get { + return ResourceManager.GetString("Selection_RunBenchmarks", resourceCulture); + } + } + } +} diff --git a/LeetCode/Resources.resx b/LeetCode/Resources.resx index 480b57f..beaec79 100644 --- a/LeetCode/Resources.resx +++ b/LeetCode/Resources.resx @@ -1,316 +1,316 @@ - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - - text/microsoft-resx - - - 1.3 - - - System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 - - - __ __ ______ __ - / / ___ ___ / /_ / ____/____ ____/ /___ - / / / _ \ / _ \ / __// / / __ \ / __ // _ \ - / /___/ __// __// /_ / /___ / /_/ // /_/ // __/ -/_____/\___/ \___/ \__/ \____/ \____/ \__,_/ \___/ - - - - Run interactive console application - - - Show information about a problem - - - List information about problems - - - Run benchmarks for a GitHub workflow - - - Run benchmarks against leetcode problems - - - app - - - benchmark - - - info - - - list - - - workflow - - - --csharp and --fsharp options are mutually exclusive - - - Benchmark not found '{0}' - - - Arrays & Hashing - - - Two Pointers - - - Sliding Window - - - Stack - - - Binary Search - - - Linked List - - - Trees - - - Tries - - - Heap / Priority Queue - - - Back Tracking - - - Graphs - - - Advanced Graphs - - - 1-D Dynamic Programming - - - 2-D Dynamic Programming - - - Greedy - - - Intervals - - - Maths & Geometry - - - Bit Manipulation - - - Not in NeetCode - - - [green]Easy[/] - - - [orange1]Medium[/] - - - [red]Hard[/] - - - [gray]Name[/] - - - [gray]Description[/] - - - [gray]Category[/] - - - [gray]Language[/] - - - [gray]Difficulty[/] - - - [gray]Benchmark[/] - - - [red]* Missing C# Benchmark *[/] - - - [red]* Missing F# Benchmark *[/] - - - [red]* Missing C# and F# Benchmarks *[/] - - - Problem - - - Category - - - Difficulty - - - Language - - - No problem argument passed - - - Problem not found '{0}' - - - Running {0} {1} for [yellow]{2}[/] - - - Benchmark - - - Benchmarks - - - Running C# benchmarks - - - Running F# benchmarks - - - Running C# and F# benchmarks - - - matching [yellow]{0}[/] - - - and - - - [gray](Press any key to return to main menu)[/] - - - [gray](Move up and down to reveal more problems)[/] - - - List Problems - - - Exit - - - Run Benchmark - - - Run Benchmarks - - - About - - - Benchmarked LeetCode problems written in C# and F# - - - [grey](Press [blue]<space>[/] to toggle, [green]<enter>[/] to run)[/] - - - Select benchmarks to run - - - Running selected benchmarks - - - [gray](method: {0})[/] - + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + text/microsoft-resx + + + 1.3 + + + System.Resources.ResXResourceReader, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + System.Resources.ResXResourceWriter, System.Windows.Forms, Version=2.0.3500.0, Culture=neutral, PublicKeyToken=b77a5c561934e089 + + + __ __ ______ __ + / / ___ ___ / /_ / ____/____ ____/ /___ + / / / _ \ / _ \ / __// / / __ \ / __ // _ \ + / /___/ __// __// /_ / /___ / /_/ // /_/ // __/ +/_____/\___/ \___/ \__/ \____/ \____/ \__,_/ \___/ + + + + Run interactive console application + + + Show information about a problem + + + List information about problems + + + Run benchmarks for a GitHub workflow + + + Run benchmarks against leetcode problems + + + app + + + benchmark + + + info + + + list + + + workflow + + + --csharp and --fsharp options are mutually exclusive + + + Benchmark not found '{0}' + + + Arrays & Hashing + + + Two Pointers + + + Sliding Window + + + Stack + + + Binary Search + + + Linked List + + + Trees + + + Tries + + + Heap / Priority Queue + + + Back Tracking + + + Graphs + + + Advanced Graphs + + + 1-D Dynamic Programming + + + 2-D Dynamic Programming + + + Greedy + + + Intervals + + + Maths & Geometry + + + Bit Manipulation + + + Not in NeetCode + + + [green]Easy[/] + + + [orange1]Medium[/] + + + [red]Hard[/] + + + [gray]Name[/] + + + [gray]Description[/] + + + [gray]Category[/] + + + [gray]Language[/] + + + [gray]Difficulty[/] + + + [gray]Benchmark[/] + + + [red]* Missing C# Benchmark *[/] + + + [red]* Missing F# Benchmark *[/] + + + [red]* Missing C# and F# Benchmarks *[/] + + + Problem + + + Category + + + Difficulty + + + Language + + + No problem argument passed + + + Problem not found '{0}' + + + Running {0} {1} for [yellow]{2}[/] + + + Benchmark + + + Benchmarks + + + Running C# benchmarks + + + Running F# benchmarks + + + Running C# and F# benchmarks + + + matching [yellow]{0}[/] + + + and + + + [gray](Press any key to return to main menu)[/] + + + [gray](Move up and down to reveal more problems)[/] + + + List Problems + + + Exit + + + Run Benchmark + + + Run Benchmarks + + + About + + + Benchmarked LeetCode problems written in C# and F# + + + [grey](Press [blue]<space>[/] to toggle, [green]<enter>[/] to run)[/] + + + Select benchmarks to run + + + Running selected benchmarks + + + [gray](method: {0})[/] + \ No newline at end of file diff --git a/LeetCode/SpectreLogger.cs b/LeetCode/SpectreLogger.cs index 4d34422..7b59698 100644 --- a/LeetCode/SpectreLogger.cs +++ b/LeetCode/SpectreLogger.cs @@ -1,53 +1,53 @@ -namespace LeetCode; - -internal sealed class SpectreLogger : ILogger -{ - public static readonly SpectreLogger Logger = new(); - - public void Write(LogKind logKind, string text) => Markup(logKind, text, writeLine: false); - - public void WriteLine() => AnsiConsole.WriteLine(); - - public void WriteLine(LogKind logKind, string text) => Markup(logKind, text, writeLine: true); - - public void Flush() - { - } - - public string Id => nameof(SpectreLogger); - - public int Priority => 0; - - private static void Markup(LogKind logKind, string text, bool writeLine) - { - var prefix = string.Empty; - switch (logKind) - { - case LogKind.Default: - case LogKind.Help: - case LogKind.Header: - case LogKind.Result: - case LogKind.Statistic: - case LogKind.Info: - case LogKind.Hint: - break; - case LogKind.Warning: - prefix = "[orange]Warning[/]: "; - break; - case LogKind.Error: - prefix = "[red]Error[/]: "; - break; - default: - throw new ArgumentOutOfRangeException(nameof(logKind), logKind, null); - } - - if (writeLine) - { - AnsiConsole.MarkupLineInterpolated($"{prefix}{text}"); - } - else - { - AnsiConsole.MarkupInterpolated($"{prefix}{text}"); - } - } -} +namespace LeetCode; + +internal sealed class SpectreLogger : ILogger +{ + public static readonly SpectreLogger Logger = new(); + + public void Write(LogKind logKind, string text) => Markup(logKind, text, writeLine: false); + + public void WriteLine() => AnsiConsole.WriteLine(); + + public void WriteLine(LogKind logKind, string text) => Markup(logKind, text, writeLine: true); + + public void Flush() + { + } + + public string Id => nameof(SpectreLogger); + + public int Priority => 0; + + private static void Markup(LogKind logKind, string text, bool writeLine) + { + var prefix = string.Empty; + switch (logKind) + { + case LogKind.Default: + case LogKind.Help: + case LogKind.Header: + case LogKind.Result: + case LogKind.Statistic: + case LogKind.Info: + case LogKind.Hint: + break; + case LogKind.Warning: + prefix = "[orange]Warning[/]: "; + break; + case LogKind.Error: + prefix = "[red]Error[/]: "; + break; + default: + throw new ArgumentOutOfRangeException(nameof(logKind), logKind, null); + } + + if (writeLine) + { + AnsiConsole.MarkupLineInterpolated($"{prefix}{text}"); + } + else + { + AnsiConsole.MarkupInterpolated($"{prefix}{text}"); + } + } +} diff --git a/LeetCode/SpectreReportBuilder.cs b/LeetCode/SpectreReportBuilder.cs index 88bbe51..94202b2 100644 --- a/LeetCode/SpectreReportBuilder.cs +++ b/LeetCode/SpectreReportBuilder.cs @@ -1,120 +1,120 @@ -namespace LeetCode; - -internal sealed class SpectreReportBuilder(IEnumerable summaries) -{ - private IEnumerable Summaries { get; } = summaries; - - public IRenderable Build() - { - var table = new Table - { - Border = TableBorder.Ascii2, - BorderStyle = new Style(foreground: Color.Grey), - UseSafeBorder = true - }; - - if (!Summaries.Any()) - { - AnsiConsole.MarkupLine("[orange1]Warning:[/] No benchmark summaries found"); - return new Text(string.Empty); - } - - foreach (var infoLine in Summaries.First().HostEnvironmentInfo.ToFormattedString()) - { - SpectreLogger.Logger.WriteLine(infoLine); - } - - AnsiConsole.WriteLine(); - - var headers = BuildHeaders(table).ToArray(); - - foreach (var summary in Summaries) - { - if (summary.Table.FullContent.Length == 0) - { - AnsiConsole.MarkupLine( - $"[orange1]Warning:[/] No benchmark reports found [yellow]'{summary.Title}'[/]"); - continue; - } - - BuildSummary(summary, table, headers); - } - - return table; - } - - private string[] BuildHeaders(Table table) - { - // Default column benchmarks via BenchmarkConfig and summaries in their expected order - var defaultHeaders = new[] - { - "Lang", "Method", "Mean", "Median", "Error", "StdDev", "Op/s", "Gen0", "Gen1", "Gen2", - "Allocated" - }; - - var summaryHeaders = Summaries - .SelectMany(s => s.Table.Columns) - .Where(c => c.NeedToShow) - .DistinctBy(c => c.Header) - .Select(c => c.Header) - .ToList(); - - // This could be a BenchmarkDotNet custom column instead of manual insertion - summaryHeaders.Insert(0, "Lang"); - - // First take the intersection of defaults and summaries, which ensures all columns are - // included in their expected order, then append any remaining columns in summaries - var headers = defaultHeaders - .Intersect(summaryHeaders) - .Union(summaryHeaders) - .Distinct() - .ToArray(); - - foreach (var header in headers) - { - table.AddColumn(header, cfg => cfg.RightAligned()); - } - - // Language - table.Columns[0].Centered(); - // Method - table.Columns[1].LeftAligned(); - - return headers; - } - - private static void BuildSummary(Summary summary, Table table, string[] headers) - { - var csharp = summary.Title.Contains(".CSharp."); - var colour = csharp ? "[blue]" : "[teal]"; - var language = csharp ? $"{colour}C#[/]" : $"{colour}F#[/]"; - - foreach (var line in summary.Table.FullContent) - { - var columns = new string[headers.Length]; - columns[0] = language; - - for (var i = 1; i < headers.Length; i++) - { - columns[i] = string.Empty; - } - - for (var columnIndex = 0; columnIndex < summary.Table.ColumnCount; columnIndex++) - { - var column = summary.Table.Columns[columnIndex]; - if (!column.NeedToShow) - { - continue; - } - - var index = headers.IndexOf(column.Header); - if (index > 0) - { - columns[index] = $"{colour}{line[columnIndex]}[/]"; - } - } - - table.AddRow(columns); - } - } -} +namespace LeetCode; + +internal sealed class SpectreReportBuilder(IEnumerable summaries) +{ + private IEnumerable Summaries { get; } = summaries; + + public IRenderable Build() + { + var table = new Table + { + Border = TableBorder.Ascii2, + BorderStyle = new Style(foreground: Color.Grey), + UseSafeBorder = true + }; + + if (!Summaries.Any()) + { + AnsiConsole.MarkupLine("[orange1]Warning:[/] No benchmark summaries found"); + return new Text(string.Empty); + } + + foreach (var infoLine in Summaries.First().HostEnvironmentInfo.ToFormattedString()) + { + SpectreLogger.Logger.WriteLine(infoLine); + } + + AnsiConsole.WriteLine(); + + var headers = BuildHeaders(table).ToArray(); + + foreach (var summary in Summaries) + { + if (summary.Table.FullContent.Length == 0) + { + AnsiConsole.MarkupLine( + $"[orange1]Warning:[/] No benchmark reports found [yellow]'{summary.Title}'[/]"); + continue; + } + + BuildSummary(summary, table, headers); + } + + return table; + } + + private string[] BuildHeaders(Table table) + { + // Default column benchmarks via BenchmarkConfig and summaries in their expected order + var defaultHeaders = new[] + { + "Lang", "Method", "Mean", "Median", "Error", "StdDev", "Op/s", "Gen0", "Gen1", "Gen2", + "Allocated" + }; + + var summaryHeaders = Summaries + .SelectMany(s => s.Table.Columns) + .Where(c => c.NeedToShow) + .DistinctBy(c => c.Header) + .Select(c => c.Header) + .ToList(); + + // This could be a BenchmarkDotNet custom column instead of manual insertion + summaryHeaders.Insert(0, "Lang"); + + // First take the intersection of defaults and summaries, which ensures all columns are + // included in their expected order, then append any remaining columns in summaries + var headers = defaultHeaders + .Intersect(summaryHeaders) + .Union(summaryHeaders) + .Distinct() + .ToArray(); + + foreach (var header in headers) + { + table.AddColumn(header, cfg => cfg.RightAligned()); + } + + // Language + table.Columns[0].Centered(); + // Method + table.Columns[1].LeftAligned(); + + return headers; + } + + private static void BuildSummary(Summary summary, Table table, string[] headers) + { + var csharp = summary.Title.Contains(".CSharp."); + var colour = csharp ? "[blue]" : "[teal]"; + var language = csharp ? $"{colour}C#[/]" : $"{colour}F#[/]"; + + foreach (var line in summary.Table.FullContent) + { + var columns = new string[headers.Length]; + columns[0] = language; + + for (var i = 1; i < headers.Length; i++) + { + columns[i] = string.Empty; + } + + for (var columnIndex = 0; columnIndex < summary.Table.ColumnCount; columnIndex++) + { + var column = summary.Table.Columns[columnIndex]; + if (!column.NeedToShow) + { + continue; + } + + var index = headers.IndexOf(column.Header); + if (index > 0) + { + columns[index] = $"{colour}{line[columnIndex]}[/]"; + } + } + + table.AddRow(columns); + } + } +} diff --git a/README.md b/README.md index 444b7e0..783c2ff 100644 --- a/README.md +++ b/README.md @@ -1,84 +1,84 @@ -## LeetCode via NeetCode - -[![Build and Benchmark](https://github.com/si618/leetcode/actions/workflows/workflow.yml/badge.svg)](https://github.com/si618/leetcode/actions/workflows/workflow.yml) - -[Benchmarked](https://si618.github.io/leetcode/dev/bench) C# submissions for [LeetCode](https://leetcode.com) problems with naïve F# solutions on my functional programming journey. - -After stumbling across the excellent [NeetCode](https://neetcode.io) website I'm now following the author's guidance and supporting his work by becoming a lifetime member. 🙇‍ - -### Build and test - -``` bash -> dotnet --list-sdks -10.0.103 [/usr/share/dotnet/sdk] - -> git --version -git version 2.53.0 - -> git clone https://github.com/si618/leetcode.git -Cloning into 'leetcode'... - -> cd leetcode -> dotnet build -> dotnet test --no-restore -``` - -### Console application - -An interactive console application can run benchmarks and show problem information. - -``` bash -> cd ./LeetCode -> dotnet run -USAGE: - LeetCode.exe [OPTIONS] - -EXAMPLES: - LeetCode.exe benchmark LRUCache --csharp - LeetCode.exe info MergeTwoLists - -OPTIONS: - -h, --help Prints help information - -v, --version Prints version information - -COMMANDS: - app Run interactive console application - benchmark Run benchmarks against leetcode problems - info Show information about a problem - list List information about problems - workflow Run benchmarks for GitHub workflow - -> dotnet run app - __ __ ______ __ - / / ___ ___ / /_ / ____/____ ____/ /___ - / / / _ \ / _ \ / __// / / __ \ / __ // _ \ - / /___/ __// __// /_ / /___ / /_/ // /_/ // __/ -/_____/\___/ \___/ \__/ \____/ \____/ \__,_/ \___/ - -> List Problems - Run Benchmarks - About - Exit -``` - -### Run application from [podman](https://podman.io/) or [docker](https://docker.com/) - -``` bash -# Build docker or podman image -> podman compose up - -# Run interactive console application -> podman run --rm -it leetcode app - -# List information about problems -> podman run --rm -it leetcode list - -# Show information about a problem -> podman run --rm -it leetcode info 'climbing stairs' - -# Run all F# benchmarks -> podman run --rm -it leetcode benchmark --fsharp - -# Run single C# benchmark -> podman run --rm -it leetcode benchmark LRUCache --csharp -``` +## LeetCode via NeetCode + +[![Build and Benchmark](https://github.com/si618/leetcode/actions/workflows/workflow.yml/badge.svg)](https://github.com/si618/leetcode/actions/workflows/workflow.yml) + +[Benchmarked](https://si618.github.io/leetcode/dev/bench) C# submissions for [LeetCode](https://leetcode.com) problems with naïve F# solutions on my functional programming journey. + +After stumbling across the excellent [NeetCode](https://neetcode.io) website I'm now following the author's guidance and supporting his work by becoming a lifetime member. 🙇‍ + +### Build and test + +``` bash +> dotnet --list-sdks +10.0.103 [/usr/share/dotnet/sdk] + +> git --version +git version 2.53.0 + +> git clone https://github.com/si618/leetcode.git +Cloning into 'leetcode'... + +> cd leetcode +> dotnet build +> dotnet test --no-restore +``` + +### Console application + +An interactive console application can run benchmarks and show problem information. + +``` bash +> cd ./LeetCode +> dotnet run +USAGE: + LeetCode.exe [OPTIONS] + +EXAMPLES: + LeetCode.exe benchmark LRUCache --csharp + LeetCode.exe info MergeTwoLists + +OPTIONS: + -h, --help Prints help information + -v, --version Prints version information + +COMMANDS: + app Run interactive console application + benchmark Run benchmarks against leetcode problems + info Show information about a problem + list List information about problems + workflow Run benchmarks for GitHub workflow + +> dotnet run app + __ __ ______ __ + / / ___ ___ / /_ / ____/____ ____/ /___ + / / / _ \ / _ \ / __// / / __ \ / __ // _ \ + / /___/ __// __// /_ / /___ / /_/ // /_/ // __/ +/_____/\___/ \___/ \__/ \____/ \____/ \__,_/ \___/ + +> List Problems + Run Benchmarks + About + Exit +``` + +### Run application from [podman](https://podman.io/) or [docker](https://docker.com/) + +``` bash +# Build docker or podman image +> podman compose up + +# Run interactive console application +> podman run --rm -it leetcode app + +# List information about problems +> podman run --rm -it leetcode list + +# Show information about a problem +> podman run --rm -it leetcode info 'climbing stairs' + +# Run all F# benchmarks +> podman run --rm -it leetcode benchmark --fsharp + +# Run single C# benchmark +> podman run --rm -it leetcode benchmark LRUCache --csharp +``` diff --git a/Run.ps1 b/Run.ps1 index d25d86f..9dbf493 100644 --- a/Run.ps1 +++ b/Run.ps1 @@ -1 +1 @@ -dotnet run --project LeetCode/LeetCode.csproj -c release $args +dotnet run --project LeetCode/LeetCode.csproj -c release $args diff --git a/docker-compose.yml b/docker-compose.yml index 0f068cc..fce7ef8 100644 --- a/docker-compose.yml +++ b/docker-compose.yml @@ -1,6 +1,6 @@ -services: - leetcode: - image: leetcode - build: - context: . - dockerfile: LeetCode/Dockerfile +services: + leetcode: + image: leetcode + build: + context: . + dockerfile: LeetCode/Dockerfile diff --git a/nuget.config b/nuget.config index 8792c8d..d2976ca 100644 --- a/nuget.config +++ b/nuget.config @@ -1,6 +1,6 @@ - - - - - - + + + + + + diff --git a/version.json b/version.json index 69a6f8b..6a2cb1b 100644 --- a/version.json +++ b/version.json @@ -1,8 +1,8 @@ -{ - "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", - "version": "0.0", - "publicReleaseRefSpec": [ - "^refs/heads/main$" - ], - "versionHeightOffset": -1 +{ + "$schema": "https://raw.githubusercontent.com/dotnet/Nerdbank.GitVersioning/master/src/NerdBank.GitVersioning/version.schema.json", + "version": "0.0", + "publicReleaseRefSpec": [ + "^refs/heads/main$" + ], + "versionHeightOffset": -1 } \ No newline at end of file From a9d5f01caf51a099c339406a07605f0c46a95519 Mon Sep 17 00:00:00 2001 From: Simon McKenna Date: Sun, 18 Oct 2026 12:32:52 +1030 Subject: [PATCH 2/5] Move tests to xunit v3 on Microsoft.Testing.Platform and harden CI - Opt in to the MTP runner in global.json, and roll the SDK forward with latestFeature. - Replace xunit v2, Microsoft.NET.Test.Sdk, coverlet, and xunit.runner.visualstudio with xunit.v3 and Microsoft.Testing.Extensions.CodeCoverage. - Align Directory.Build.props and Directory.Packages.props with the awesome-humans/dotnet templates: artifacts output, latest-recommended analysis, Meziantou.Analyzer, nullable warnings as errors, documentation file, deterministic builds, and transitive pinning. - Pin FSharp.Core to 10.1.402, the version the .NET 10.0.400 SDK ships. - Pin GitHub Actions to commit SHAs, take the SDK from global.json, set least-privilege permissions, and upload TRX and coverage results. - Add a /build/ solution folder for the root build files. --- .github/workflows/workflow.yml | 33 ++++++++++++++++++------- .gitignore | 1 + Directory.Build.props | 34 +++++++++++++++++++++----- Directory.Packages.props | 25 +++++-------------- LeetCode.CSharp/LeetCode.CSharp.csproj | 10 +++++--- LeetCode.FSharp/LeetCode.FSharp.fsproj | 13 +++++----- LeetCode.slnx | 24 +++++++++--------- LeetCode/LeetCode.csproj | 6 +++++ global.json | 8 +++--- 9 files changed, 95 insertions(+), 59 deletions(-) diff --git a/.github/workflows/workflow.yml b/.github/workflows/workflow.yml index 1521b57..e4ef3af 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -6,25 +6,27 @@ on: pull_request: branches: [main] +permissions: + contents: read + env: DOTNET_NOLOGO: true DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true DOTNET_CLI_TELEMETRY_OPTOUT: true - DOTNET_VERSION: 10.0.x jobs: build: runs-on: ubuntu-latest steps: - name: Checkout - uses: actions/checkout@main + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup dotnet - uses: actions/setup-dotnet@v6 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: - dotnet-version: ${{ env.DOTNET_VERSION }} + global-json-file: global.json - name: Run dotnet build id: build @@ -36,22 +38,35 @@ jobs: - name: Run dotnet test id: test - run: dotnet test --configuration Release --no-restore + run: >- + dotnet test --configuration Release --no-build + --report-xunit-trx --results-directory artifacts/test-results + --coverage --coverage-output-format cobertura + + - name: Upload test results + if: ${{ !cancelled() }} + uses: actions/upload-artifact@cf430e030ddbb5b0abf93d22962f4752f3646cd9 # v7.0.2 + with: + name: test-results + path: artifacts/test-results benchmark: needs: [ build ] if: github.event_name == 'push' && github.ref == 'refs/heads/main' runs-on: ubuntu-latest + permissions: + # github-action-benchmark pushes results to the gh-pages branch + contents: write steps: - name: Checkout - uses: actions/checkout@main + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 with: fetch-depth: 0 - name: Setup dotnet - uses: actions/setup-dotnet@v6 + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 with: - dotnet-version: ${{ env.DOTNET_VERSION }} + global-json-file: global.json - name: List problems id: list-problems @@ -71,7 +86,7 @@ jobs: - name: Store benchmark results id: store-benchmarks if: ${{ github.event_name == 'push' }} - uses: benchmark-action/github-action-benchmark@v1.22.1 + uses: benchmark-action/github-action-benchmark@4322e5726e6334590d251fc4f92bec0efafc45dc # v1.22.2 with: name: Benchmarks tool: benchmarkdotnet diff --git a/.gitignore b/.gitignore index 939daf1..25cae2a 100644 --- a/.gitignore +++ b/.gitignore @@ -4,4 +4,5 @@ *.DotSettings.user bin obj +artifacts/ BenchmarkDotNet.Artifacts diff --git a/Directory.Build.props b/Directory.Build.props index 0911ba9..f09e443 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,18 +1,40 @@ - + + true + + + Simon McKenna - true - true - enable + net10.0 latest enable - net10.0 + nullable + enable + + + true + true + true + latest-recommended + true + + + + true + + $(NoWarn);CS1591 + + + + true + true - + + diff --git a/Directory.Packages.props b/Directory.Packages.props index ee75ff3..fb70258 100644 --- a/Directory.Packages.props +++ b/Directory.Packages.props @@ -1,33 +1,20 @@ true + true - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - - + - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + + + - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - + - - - all - runtime; build; native; contentfiles; analyzers; buildtransitive - diff --git a/LeetCode.CSharp/LeetCode.CSharp.csproj b/LeetCode.CSharp/LeetCode.CSharp.csproj index 0aafb17..e23a2e5 100644 --- a/LeetCode.CSharp/LeetCode.CSharp.csproj +++ b/LeetCode.CSharp/LeetCode.CSharp.csproj @@ -2,7 +2,11 @@ false + false LeetCode.CSharp + + Exe + true @@ -19,11 +23,9 @@ - - + - - + diff --git a/LeetCode.FSharp/LeetCode.FSharp.fsproj b/LeetCode.FSharp/LeetCode.FSharp.fsproj index f7947db..ce7b3ac 100644 --- a/LeetCode.FSharp/LeetCode.FSharp.fsproj +++ b/LeetCode.FSharp/LeetCode.FSharp.fsproj @@ -2,10 +2,11 @@ false - false - false + false LeetCode.FSharp - false + + Exe + true @@ -21,10 +22,8 @@ - - - - + + diff --git a/LeetCode.slnx b/LeetCode.slnx index 72f8601..fa10842 100644 --- a/LeetCode.slnx +++ b/LeetCode.slnx @@ -1,20 +1,22 @@ - + + + + - - + + + + + - - - - - - - - \ No newline at end of file + + + + diff --git a/LeetCode/LeetCode.csproj b/LeetCode/LeetCode.csproj index 0c9677e..b81cf06 100644 --- a/LeetCode/LeetCode.csproj +++ b/LeetCode/LeetCode.csproj @@ -3,8 +3,13 @@ LeetCode via NeetCode LeetCode + en Exe + false + false + false + false @@ -21,6 +26,7 @@ + diff --git a/global.json b/global.json index b0bd497..a0703e8 100644 --- a/global.json +++ b/global.json @@ -1,7 +1,9 @@ { "sdk": { - "version": "10.0.103", - "rollForward": "minor", - "allowPrerelease": true + "version": "10.0.400", + "rollForward": "latestFeature" + }, + "test": { + "runner": "Microsoft.Testing.Platform" } } From f706eddba006e7038882bb5ecee89b636aa1e097 Mon Sep 17 00:00:00 2001 From: Simon McKenna Date: Sun, 18 Oct 2026 12:32:52 +1030 Subject: [PATCH 3/5] Adopt the template .editorconfig and fix analyzer diagnostics Keeps this repository's var style, PascalCase static readonly fields, and ReSharper settings. Silences rules that clash with LeetCode's given signatures and the partial Problem class, each with a reason. Fixes the rest in code, mostly with dotnet format. --- .editorconfig | 129 +++++++++++++++++- LeetCode.CSharp/BenchmarkConfig.cs | 2 +- .../Benchmarks/AddTwoNumbersBenchmark.cs | 2 +- .../Benchmarks/BinarySearchBenchmark.cs | 2 +- .../Benchmarks/CanAttendMeetingsBenchmark.cs | 2 +- .../Benchmarks/ContainsDuplicateBenchmark.cs | 2 +- .../Benchmarks/CountBitsBenchmark.cs | 2 +- .../Benchmarks/EncodeDecodeBenchmark.cs | 2 +- .../Benchmarks/GroupAnagramsBenchmark.cs | 2 +- LeetCode.CSharp/Benchmarks/InsertBenchmark.cs | 4 +- .../Benchmarks/IsAnagramBenchmark.cs | 2 +- .../Benchmarks/IsPalindromeBenchmark.cs | 2 +- .../Benchmarks/IsValidSudokuBenchmark.cs | 4 +- .../Benchmarks/KWeakestRowsBenchmark.cs | 2 +- .../Benchmarks/KthLargestBenchmark.cs | 2 +- .../Benchmarks/LRUCacheBenchmark.cs | 2 +- .../Benchmarks/LastStoneWeightBenchmark.cs | 2 +- .../LengthOfLongestSubstringBenchmark.cs | 2 +- .../Benchmarks/MaxProfitBenchmark.cs | 2 +- .../Benchmarks/MaximumWealthBenchmark.cs | 2 +- .../Benchmarks/MiddleNodeBenchmark.cs | 2 +- .../Benchmarks/MissingNumberBenchmark.cs | 2 +- .../Benchmarks/NumberOfStepsBenchmark.cs | 2 +- .../Benchmarks/ProductExceptSelfBenchmark.cs | 2 +- .../Benchmarks/RansomNoteBenchmark.cs | 2 +- .../Benchmarks/ReverseBitsBenchmark.cs | 2 +- .../Benchmarks/RomanToIntBenchmark.cs | 2 +- .../Benchmarks/SubsetsBenchmark.cs | 2 +- .../Benchmarks/TopKFrequentBenchmark.cs | 2 +- LeetCode.CSharp/Benchmarks/TwoSumBenchmark.cs | 2 +- .../Benchmarks/UniquePathsBenchmark.cs | 2 +- .../Benchmarks/ValidParenthesesBenchmark.cs | 2 +- LeetCode.CSharp/Category.cs | 4 +- LeetCode.CSharp/Difficulty.cs | 2 +- LeetCode.CSharp/Interval.cs | 3 + LeetCode.CSharp/LeetCodeAttribute.cs | 26 ++-- LeetCode.CSharp/ListNode.cs | 2 +- LeetCode.CSharp/Problems/BinarySearch.cs | 2 +- LeetCode.CSharp/Problems/CanAttendMeetings.cs | 4 +- LeetCode.CSharp/Problems/EncodeDecode.cs | 4 +- LeetCode.CSharp/Problems/FizzBuzz.cs | 2 +- LeetCode.CSharp/Problems/GroupAnagrams.cs | 6 +- LeetCode.CSharp/Problems/Insert.cs | 18 +-- LeetCode.CSharp/Problems/InvertTree.cs | 2 +- LeetCode.CSharp/Problems/IsAnagram.cs | 2 +- LeetCode.CSharp/Problems/IsPalindrone.cs | 3 - LeetCode.CSharp/Problems/IsSameTree.cs | 9 +- LeetCode.CSharp/Problems/IsSubtree.cs | 2 +- LeetCode.CSharp/Problems/IsValidSudoku.cs | 6 +- LeetCode.CSharp/Problems/KWeakestRows.cs | 4 +- LeetCode.CSharp/Problems/KthLargest.cs | 2 +- LeetCode.CSharp/Problems/LRUCache.cs | 2 +- .../Problems/LowestCommonAncestor.cs | 5 +- LeetCode.CSharp/Problems/MaxDepth.cs | 12 +- LeetCode.CSharp/Problems/MaximumWealth.cs | 6 +- LeetCode.CSharp/Problems/MergeTwoLists.cs | 4 +- LeetCode.CSharp/Problems/MiddleNode.cs | 3 - LeetCode.CSharp/Problems/NumIslands.cs | 16 ++- LeetCode.CSharp/Problems/ProductExceptSelf.cs | 5 +- LeetCode.CSharp/Problems/RansomNote.cs | 18 +-- LeetCode.CSharp/Problems/ReverseBits.cs | 12 +- LeetCode.CSharp/Problems/RomanToInt.cs | 4 +- LeetCode.CSharp/Problems/Subsets.cs | 4 +- LeetCode.CSharp/Problems/TopKFrequent.cs | 13 +- LeetCode.CSharp/Problems/Trie.cs | 5 +- LeetCode.CSharp/Problems/ValidParentheses.cs | 2 +- LeetCode/BenchmarkRunner.cs | 10 +- LeetCode/Commands/BenchmarkSettings.cs | 31 ++--- LeetCode/Commands/ProblemSettings.cs | 23 +--- LeetCode/Commands/WorkflowCommand.cs | 8 +- LeetCode/Extensions.cs | 17 ++- LeetCode/Menus/MainMenu.cs | 4 +- LeetCode/Menus/MenuBase.cs | 2 +- LeetCode/Menus/ProblemMenu.cs | 2 +- LeetCode/Menus/Selections/AboutSelection.cs | 2 +- .../Selections/BenchmarkListSelection.cs | 4 +- .../Menus/Selections/BenchmarkSelection.cs | 7 +- LeetCode/Menus/Selections/ExitSelection.cs | 2 +- .../Menus/Selections/ProblemListSelection.cs | 10 +- LeetCode/Menus/Selections/Selection.cs | 2 +- LeetCode/Problem.cs | 4 +- LeetCode/Program.cs | 2 +- LeetCode/Reflection.cs | 35 +++-- LeetCode/SpectreLogger.cs | 6 +- LeetCode/SpectreReportBuilder.cs | 14 +- 85 files changed, 330 insertions(+), 264 deletions(-) diff --git a/.editorconfig b/.editorconfig index 798c817..72352cd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,25 +1,134 @@ root = true [*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true indent_style = space +indent_size = 4 trim_trailing_whitespace = true -[{*.yml,*.props, *.*proj}] +[*.{json,jsonc,yml,yaml,props,targets,csproj,fsproj,slnx,slnf,xml,config}] indent_size = 2 +[*.md] +trim_trailing_whitespace = false + +[*.{cs,fs}] +dotnet_analyzer_diagnostic.severity = warning + [*.cs] -indent_size = 4 +# --- Language version and style: latest, expression-oriented, explicit intent --- +csharp_style_var_for_built_in_types = true:suggestion +csharp_style_var_when_type_is_apparent = true:suggestion +csharp_style_var_elsewhere = true:suggestion +csharp_style_expression_bodied_methods = when_on_single_line:suggestion +# Constructors too. Left unset, the default (block bodies) is raised to a warning by the bulk +# severity above and fails every one-line constructor (IDE0021). +csharp_style_expression_bodied_constructors = when_on_single_line:suggestion +csharp_style_expression_bodied_properties = true:suggestion +csharp_style_namespace_declarations = file_scoped:warning +csharp_style_prefer_primary_constructors = true:suggestion +csharp_style_prefer_switch_expression = true:warning +csharp_style_pattern_matching_over_as_with_null_check = true:warning +csharp_style_prefer_null_check_over_type_check = true:warning +csharp_prefer_simple_using_statement = true:warning +csharp_style_prefer_top_level_statements = true:suggestion +csharp_style_prefer_method_group_conversion = true:suggestion +csharp_using_directive_placement = outside_namespace:warning + +# Prefer auto-implemented properties over trivial hand-written backing fields. Set the severity +# here, not on dotnet_style_prefer_auto_properties below, which is the same rule: a +# dotnet_diagnostic entry overrides the option's trailing severity, so the second has no effect. +dotnet_diagnostic.IDE0032.severity = warning + +# The bulk severity above raises IDE0058 (unused expression value) to a warning, which requires +# `_ =` on every discarded result, including each Assert.Throws in a test project. Keep it silent. +dotnet_diagnostic.IDE0058.severity = silent + +# The one globalization rule AnalysisLevel=latest-recommended leaves silent: string.Equals +# without a StringComparison. CA1304/1305/1309/1310/1311 already warn (opinions/globalization.md). +dotnet_diagnostic.CA1307.severity = warning + +# The one Meziantou.Analyzer TimeProvider rule that ships disabled: prefer overloads taking a +# TimeProvider. MA0166/MA0188 ship enabled at info severity and are raised to warnings by the +# bulk dotnet_analyzer_diagnostic.severity above (opinions/datetime.md). +dotnet_diagnostic.MA0167.severity = warning + +# --- Nullability and correctness --- +dotnet_style_require_accessibility_modifiers = always:warning +dotnet_style_readonly_field = true:warning +dotnet_style_prefer_auto_properties = true # severity: IDE0032 above +dotnet_style_collection_initializer = true:suggestion +dotnet_style_prefer_collection_expression = true:warning +dotnet_style_object_initializer = true:suggestion +dotnet_style_coalesce_expression = true:warning +dotnet_style_null_propagation = true:warning + +# --- Naming: standard .NET conventions --- +dotnet_naming_rule.interfaces_begin_with_i.severity = warning +dotnet_naming_rule.interfaces_begin_with_i.symbols = interfaces +dotnet_naming_rule.interfaces_begin_with_i.style = prefix_i +dotnet_naming_symbols.interfaces.applicable_kinds = interface +dotnet_naming_style.prefix_i.required_prefix = I +dotnet_naming_style.prefix_i.capitalization = pascal_case -# CA1822: Mark members as static -dotnet_diagnostic.ca1822.severity = silent +# Constants take PascalCase. A rule with required_modifiers is more specific than the private-field +# rule below, so it wins for consts; without it, a private const needs an underscore prefix. +dotnet_naming_rule.constants_pascal_case.severity = warning +dotnet_naming_rule.constants_pascal_case.symbols = constants +dotnet_naming_rule.constants_pascal_case.style = pascal_case +dotnet_naming_symbols.constants.applicable_kinds = field, local +dotnet_naming_symbols.constants.applicable_accessibilities = * +dotnet_naming_symbols.constants.required_modifiers = const +dotnet_naming_style.pascal_case.capitalization = pascal_case +# Static readonly fields take PascalCase, as this repository has always used. Like the const rule, +# required_modifiers makes it more specific than the private-field rule below. +dotnet_naming_rule.static_readonly_pascal_case.severity = warning +dotnet_naming_rule.static_readonly_pascal_case.symbols = static_readonly_fields +dotnet_naming_rule.static_readonly_pascal_case.style = pascal_case +dotnet_naming_symbols.static_readonly_fields.applicable_kinds = field +dotnet_naming_symbols.static_readonly_fields.applicable_accessibilities = * +dotnet_naming_symbols.static_readonly_fields.required_modifiers = static, readonly + +dotnet_naming_rule.private_fields_camel_underscore.severity = warning +dotnet_naming_rule.private_fields_camel_underscore.symbols = private_fields +dotnet_naming_rule.private_fields_camel_underscore.style = underscore_camel +dotnet_naming_symbols.private_fields.applicable_kinds = field +dotnet_naming_symbols.private_fields.applicable_accessibilities = private +dotnet_naming_style.underscore_camel.required_prefix = _ +dotnet_naming_style.underscore_camel.capitalization = camel_case + +[*.fs] +fsharp_multiline_bracket_style = stroustrup + +[*.cs] +# --- Repository choices for LeetCode solutions --- +# The var style rules above use var everywhere, which this repository has always done +# Methods are expression-bodied wherever they fit, not only on a single line csharp_style_expression_bodied_methods = true:suggestion -csharp_style_namespace_declarations = file_scoped -# Microsoft .NET properties +# Test and benchmark methods are instance members, so xUnit and BenchmarkDotNet can discover them. +# MA0038 is Meziantou's deprecated duplicate of CA1822. +dotnet_diagnostic.CA1822.severity = none +dotnet_diagnostic.MA0038.severity = none + +# Each problem lives in its own file as part of the partial Problem class +dotnet_diagnostic.MA0048.severity = none + +# Signatures follow the ones LeetCode gives, which use List and similar concrete types +dotnet_diagnostic.MA0016.severity = none +dotnet_diagnostic.CA1002.severity = none + +# Node types expose public fields (ListNode.val, TreeNode.left), as LeetCode defines them +dotnet_diagnostic.CA1051.severity = none + +# TODO comments are deliberate notes on solutions worth revisiting +dotnet_diagnostic.MA0026.severity = none + csharp_new_line_before_members_in_object_initializers = false csharp_preferred_modifier_order = public, private, protected, internal, new, sealed, abstract, virtual, static, readonly, override, extern, unsafe, volatile, async:suggestion -csharp_using_directive_placement = inside_namespace:silent dotnet_sort_system_directives_first = false # ReSharper properties @@ -41,3 +150,9 @@ resharper_place_expr_method_on_single_line = true resharper_remove_blank_lines_near_braces_in_declarations = false resharper_wrap_array_initializer_style = chop_if_long resharper_wrap_object_and_collection_initializer_style = wrap_if_long + +[LeetCode/**.cs] +# Console messages format each resource string once per command, so caching a CompositeFormat gains nothing +dotnet_diagnostic.CA1863.severity = none +# The app uses the static AnsiConsole by design, and Spectre.Console.Analyzer 1.0.0 crashes on this rule (AD0001) +dotnet_diagnostic.Spectre1010.severity = none diff --git a/LeetCode.CSharp/BenchmarkConfig.cs b/LeetCode.CSharp/BenchmarkConfig.cs index 11c902d..f3f2254 100644 --- a/LeetCode.CSharp/BenchmarkConfig.cs +++ b/LeetCode.CSharp/BenchmarkConfig.cs @@ -5,7 +5,7 @@ public sealed class BenchmarkConfig : ManualConfig public BenchmarkConfig() { // FsUnit.xUnit has DEBUG reference - WithOption(ConfigOptions.DisableOptimizationsValidator, true); + WithOption(ConfigOptions.DisableOptimizationsValidator, value: true); AddDiagnoser(MemoryDiagnoser.Default); diff --git a/LeetCode.CSharp/Benchmarks/AddTwoNumbersBenchmark.cs b/LeetCode.CSharp/Benchmarks/AddTwoNumbersBenchmark.cs index 9431a06..ff8ce3c 100644 --- a/LeetCode.CSharp/Benchmarks/AddTwoNumbersBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/AddTwoNumbersBenchmark.cs @@ -24,4 +24,4 @@ public void AddTwoNumbersCleanup() ListNode1 = new ListNode(IntArray1); ListNode2 = new ListNode(IntArray2); } -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/BinarySearchBenchmark.cs b/LeetCode.CSharp/Benchmarks/BinarySearchBenchmark.cs index 28fd8c5..8162edc 100644 --- a/LeetCode.CSharp/Benchmarks/BinarySearchBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/BinarySearchBenchmark.cs @@ -10,4 +10,4 @@ public class BinarySearchBenchmark : Benchmark [GlobalCleanup(Target = nameof(BinarySearch))] public void BinarySearchCleanup() => IntArray1 = []; -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/CanAttendMeetingsBenchmark.cs b/LeetCode.CSharp/Benchmarks/CanAttendMeetingsBenchmark.cs index 1260f03..dd0d31f 100644 --- a/LeetCode.CSharp/Benchmarks/CanAttendMeetingsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/CanAttendMeetingsBenchmark.cs @@ -27,4 +27,4 @@ public void CanAttendMeetingsCleanup() Int2 = 0; Intervals1.Clear(); } -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/ContainsDuplicateBenchmark.cs b/LeetCode.CSharp/Benchmarks/ContainsDuplicateBenchmark.cs index d8357a5..6144bdb 100644 --- a/LeetCode.CSharp/Benchmarks/ContainsDuplicateBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/ContainsDuplicateBenchmark.cs @@ -10,4 +10,4 @@ public class ContainsDuplicateBenchmark : Benchmark [GlobalCleanup(Target = nameof(ContainsDuplicate))] public void ContainsDuplicateCleanup() => IntArray1 = []; -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/CountBitsBenchmark.cs b/LeetCode.CSharp/Benchmarks/CountBitsBenchmark.cs index a50f756..47cbdde 100644 --- a/LeetCode.CSharp/Benchmarks/CountBitsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/CountBitsBenchmark.cs @@ -4,4 +4,4 @@ public class CountBitsBenchmark : Benchmark { [Benchmark] public int[] CountBits() => Problem.CountBits(10_000); -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/EncodeDecodeBenchmark.cs b/LeetCode.CSharp/Benchmarks/EncodeDecodeBenchmark.cs index 6b21b24..8ae7da0 100644 --- a/LeetCode.CSharp/Benchmarks/EncodeDecodeBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/EncodeDecodeBenchmark.cs @@ -44,4 +44,4 @@ public void DecodeCleanup() String1 = string.Empty; StringArray1 = []; } -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/GroupAnagramsBenchmark.cs b/LeetCode.CSharp/Benchmarks/GroupAnagramsBenchmark.cs index d6e983c..b2d6f03 100644 --- a/LeetCode.CSharp/Benchmarks/GroupAnagramsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/GroupAnagramsBenchmark.cs @@ -18,4 +18,4 @@ public void GroupAnagramsSetup() [GlobalCleanup(Target = nameof(GroupAnagrams))] public void GroupAnagramsCleanup() => StringArray1 = []; -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/InsertBenchmark.cs b/LeetCode.CSharp/Benchmarks/InsertBenchmark.cs index 6643d95..d9524c3 100644 --- a/LeetCode.CSharp/Benchmarks/InsertBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/InsertBenchmark.cs @@ -19,7 +19,7 @@ public void InsertSetup() IntArray2 = [ IntArrayMulti1[9_999][0] + 1, - IntArrayMulti1[9_999][0] + 10 + IntArrayMulti1[9_999][0] + 10, ]; } @@ -34,4 +34,4 @@ public void InsertCleanup() IntArrayMulti1 = []; IntArray2 = []; } -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/IsAnagramBenchmark.cs b/LeetCode.CSharp/Benchmarks/IsAnagramBenchmark.cs index 8db8fad..e4b8c86 100644 --- a/LeetCode.CSharp/Benchmarks/IsAnagramBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/IsAnagramBenchmark.cs @@ -18,4 +18,4 @@ public void IsAnagramCleanup() String1 = string.Empty; String2 = string.Empty; } -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/IsPalindromeBenchmark.cs b/LeetCode.CSharp/Benchmarks/IsPalindromeBenchmark.cs index a60269b..e817e96 100644 --- a/LeetCode.CSharp/Benchmarks/IsPalindromeBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/IsPalindromeBenchmark.cs @@ -20,4 +20,4 @@ public void IsPalindromeCleanup() IntArray2 = []; ListNode1 = new ListNode(); } -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/IsValidSudokuBenchmark.cs b/LeetCode.CSharp/Benchmarks/IsValidSudokuBenchmark.cs index 25864a2..56cb6ff 100644 --- a/LeetCode.CSharp/Benchmarks/IsValidSudokuBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/IsValidSudokuBenchmark.cs @@ -13,7 +13,7 @@ public void IsValidSudokuSetup() => CharArrayMulti = ['7', '.', '.', '.', '2', '.', '.', '.', '6'], ['.', '6', '.', '.', '.', '.', '2', '8', '.'], ['.', '.', '.', '4', '1', '9', '.', '.', '5'], - ['.', '.', '.', '.', '8', '.', '.', '7', '9'] + ['.', '.', '.', '.', '8', '.', '.', '7', '9'], ]; [Benchmark] @@ -21,4 +21,4 @@ public void IsValidSudokuSetup() => CharArrayMulti = [GlobalCleanup(Target = nameof(IsValidSudoku))] public void IsValidSudokuCleanup() => CharArrayMulti = [[char.MinValue]]; -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/KWeakestRowsBenchmark.cs b/LeetCode.CSharp/Benchmarks/KWeakestRowsBenchmark.cs index 69e5315..9d48c8f 100644 --- a/LeetCode.CSharp/Benchmarks/KWeakestRowsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/KWeakestRowsBenchmark.cs @@ -22,4 +22,4 @@ public void KWeakestRowsCleanup() IntArray1 = []; IntArrayMulti1 = []; } -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/KthLargestBenchmark.cs b/LeetCode.CSharp/Benchmarks/KthLargestBenchmark.cs index 5f97dbf..4646711 100644 --- a/LeetCode.CSharp/Benchmarks/KthLargestBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/KthLargestBenchmark.cs @@ -20,4 +20,4 @@ public void KthLargestCleanup() IntArray1 = []; _kthLargest = null!; } -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/LRUCacheBenchmark.cs b/LeetCode.CSharp/Benchmarks/LRUCacheBenchmark.cs index 0fe260d..680f91a 100644 --- a/LeetCode.CSharp/Benchmarks/LRUCacheBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/LRUCacheBenchmark.cs @@ -23,4 +23,4 @@ public void LRUCacheSetup() [GlobalCleanup(Target = nameof(LRUCache))] [SuppressMessage("ReSharper", "InconsistentNaming")] public void LRUCacheCleanup() => _lruCache = null!; -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/LastStoneWeightBenchmark.cs b/LeetCode.CSharp/Benchmarks/LastStoneWeightBenchmark.cs index d741467..644e25c 100644 --- a/LeetCode.CSharp/Benchmarks/LastStoneWeightBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/LastStoneWeightBenchmark.cs @@ -10,4 +10,4 @@ public class LastStoneWeightBenchmark : Benchmark [GlobalCleanup(Target = nameof(LastStoneWeight))] public void LastStoneWeightCleanup() => IntArray1 = []; -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/LengthOfLongestSubstringBenchmark.cs b/LeetCode.CSharp/Benchmarks/LengthOfLongestSubstringBenchmark.cs index 6a2cce3..65dcb4d 100644 --- a/LeetCode.CSharp/Benchmarks/LengthOfLongestSubstringBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/LengthOfLongestSubstringBenchmark.cs @@ -10,4 +10,4 @@ public class LengthOfLongestSubstringBenchmark : Benchmark [GlobalCleanup(Target = nameof(LengthOfLongestSubstring))] public void LengthOfLongestSubstringCleanup() => String1 = string.Empty; -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/MaxProfitBenchmark.cs b/LeetCode.CSharp/Benchmarks/MaxProfitBenchmark.cs index 0301912..49e7aaa 100644 --- a/LeetCode.CSharp/Benchmarks/MaxProfitBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/MaxProfitBenchmark.cs @@ -10,4 +10,4 @@ public class MaxProfitBenchmark : Benchmark [GlobalCleanup(Target = nameof(MaxProfit))] public void MaxProfitCleanup() => IntArray1 = []; -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/MaximumWealthBenchmark.cs b/LeetCode.CSharp/Benchmarks/MaximumWealthBenchmark.cs index fce1c93..bff9048 100644 --- a/LeetCode.CSharp/Benchmarks/MaximumWealthBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/MaximumWealthBenchmark.cs @@ -22,4 +22,4 @@ public void MaximumWealthCleanup() IntArray1 = []; IntArrayMulti1 = []; } -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/MiddleNodeBenchmark.cs b/LeetCode.CSharp/Benchmarks/MiddleNodeBenchmark.cs index ab15158..d719e6f 100644 --- a/LeetCode.CSharp/Benchmarks/MiddleNodeBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/MiddleNodeBenchmark.cs @@ -11,4 +11,4 @@ public void MiddleNodeSetup() => [GlobalCleanup(Target = nameof(MiddleNode))] public void MiddleNodeCleanup() => ListNode1 = new ListNode(); -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/MissingNumberBenchmark.cs b/LeetCode.CSharp/Benchmarks/MissingNumberBenchmark.cs index 4d5dfe2..09c5561 100644 --- a/LeetCode.CSharp/Benchmarks/MissingNumberBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/MissingNumberBenchmark.cs @@ -11,4 +11,4 @@ public void MissingNumberSetup() => [GlobalCleanup(Target = nameof(MissingNumber))] public void MissingNumberCleanup() => IntArray1 = []; -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/NumberOfStepsBenchmark.cs b/LeetCode.CSharp/Benchmarks/NumberOfStepsBenchmark.cs index ffda485..5d2ef7f 100644 --- a/LeetCode.CSharp/Benchmarks/NumberOfStepsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/NumberOfStepsBenchmark.cs @@ -4,4 +4,4 @@ public class NumberOfStepsBenchmark : Benchmark { [Benchmark] public int NumberOfSteps() => Problem.NumberOfSteps(1_000_000_000); -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/ProductExceptSelfBenchmark.cs b/LeetCode.CSharp/Benchmarks/ProductExceptSelfBenchmark.cs index d26499d..97ea153 100644 --- a/LeetCode.CSharp/Benchmarks/ProductExceptSelfBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/ProductExceptSelfBenchmark.cs @@ -10,4 +10,4 @@ public class ProductExceptSelfBenchmark : Benchmark [GlobalCleanup(Target = nameof(ProductExceptSelf))] public void ProductExceptSelfCleanup() => StringArray1 = []; -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/RansomNoteBenchmark.cs b/LeetCode.CSharp/Benchmarks/RansomNoteBenchmark.cs index 28a3a0d..15b7200 100644 --- a/LeetCode.CSharp/Benchmarks/RansomNoteBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/RansomNoteBenchmark.cs @@ -18,4 +18,4 @@ public void RansomNoteCleanup() String1 = string.Empty; String2 = string.Empty; } -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/ReverseBitsBenchmark.cs b/LeetCode.CSharp/Benchmarks/ReverseBitsBenchmark.cs index 083ebf6..9c2fcb2 100644 --- a/LeetCode.CSharp/Benchmarks/ReverseBitsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/ReverseBitsBenchmark.cs @@ -4,4 +4,4 @@ public class ReverseBitsBenchmark : Benchmark { [Benchmark] public uint ReverseBits() => Problem.ReverseBits(0b00100010100101000001111010011100); -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/RomanToIntBenchmark.cs b/LeetCode.CSharp/Benchmarks/RomanToIntBenchmark.cs index 80d0c88..1e7f5b5 100644 --- a/LeetCode.CSharp/Benchmarks/RomanToIntBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/RomanToIntBenchmark.cs @@ -5,4 +5,4 @@ public class RomanToIntBenchmark : Benchmark [Benchmark] [SuppressMessage("ReSharper", "StringLiteralTypo")] public int RomanToInt() => Problem.RomanToInt("MMMCMXCIXCMXCIX"); -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/SubsetsBenchmark.cs b/LeetCode.CSharp/Benchmarks/SubsetsBenchmark.cs index 9e7243f..0be9d83 100644 --- a/LeetCode.CSharp/Benchmarks/SubsetsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/SubsetsBenchmark.cs @@ -18,4 +18,4 @@ public void SubsetsSetup() [GlobalCleanup(Target = nameof(Subsets))] public void SubsetsCleanup() => IntArray1 = []; -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/TopKFrequentBenchmark.cs b/LeetCode.CSharp/Benchmarks/TopKFrequentBenchmark.cs index f0a8ff2..9575200 100644 --- a/LeetCode.CSharp/Benchmarks/TopKFrequentBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/TopKFrequentBenchmark.cs @@ -10,4 +10,4 @@ public class TopKFrequentBenchmark : Benchmark [GlobalCleanup(Target = nameof(TopKFrequent))] public void TopKFrequentCleanup() => IntArray1 = []; -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/TwoSumBenchmark.cs b/LeetCode.CSharp/Benchmarks/TwoSumBenchmark.cs index 8ab8b83..a284153 100644 --- a/LeetCode.CSharp/Benchmarks/TwoSumBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/TwoSumBenchmark.cs @@ -19,4 +19,4 @@ public void TwoSumCleanup() IntArray1 = []; Int1 = 0; } -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/UniquePathsBenchmark.cs b/LeetCode.CSharp/Benchmarks/UniquePathsBenchmark.cs index 7480c1b..10fc069 100644 --- a/LeetCode.CSharp/Benchmarks/UniquePathsBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/UniquePathsBenchmark.cs @@ -4,4 +4,4 @@ public class UniquePathsBenchmark : Benchmark { [Benchmark] public int UniquePaths() => Problem.UniquePaths(10_000, 100); -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Benchmarks/ValidParenthesesBenchmark.cs b/LeetCode.CSharp/Benchmarks/ValidParenthesesBenchmark.cs index b126cd6..9d505d2 100644 --- a/LeetCode.CSharp/Benchmarks/ValidParenthesesBenchmark.cs +++ b/LeetCode.CSharp/Benchmarks/ValidParenthesesBenchmark.cs @@ -25,4 +25,4 @@ public void ValidParenthesesCleanup() Int1 = 0; String1 = string.Empty; } -} \ No newline at end of file +} diff --git a/LeetCode.CSharp/Category.cs b/LeetCode.CSharp/Category.cs index 4eb424a..ef16553 100644 --- a/LeetCode.CSharp/Category.cs +++ b/LeetCode.CSharp/Category.cs @@ -3,7 +3,7 @@ namespace LeetCode.CSharp; /// NeetCode category public enum Category { - /// Arrays & Hashing + /// Arrays & Hashing ArraysAndHashing, /// Two Pointers TwoPointers, @@ -40,5 +40,5 @@ public enum Category /// Bit Manipulation BitManipulation, /// Not in NeetCode - NotInNeetCode + NotInNeetCode, } diff --git a/LeetCode.CSharp/Difficulty.cs b/LeetCode.CSharp/Difficulty.cs index 8d884d8..841d2b6 100644 --- a/LeetCode.CSharp/Difficulty.cs +++ b/LeetCode.CSharp/Difficulty.cs @@ -9,5 +9,5 @@ public enum Difficulty /// Medium Medium, /// Hard - Hard + Hard, } diff --git a/LeetCode.CSharp/Interval.cs b/LeetCode.CSharp/Interval.cs index 5ace68c..0d9e963 100644 --- a/LeetCode.CSharp/Interval.cs +++ b/LeetCode.CSharp/Interval.cs @@ -1,4 +1,7 @@ +using System.Runtime.InteropServices; + namespace LeetCode.CSharp; // ReSharper disable InconsistentNaming +[StructLayout(LayoutKind.Auto)] public readonly record struct Interval(int start, int end); diff --git a/LeetCode.CSharp/LeetCodeAttribute.cs b/LeetCode.CSharp/LeetCodeAttribute.cs index d11b1db..b9adb9c 100644 --- a/LeetCode.CSharp/LeetCodeAttribute.cs +++ b/LeetCode.CSharp/LeetCodeAttribute.cs @@ -1,29 +1,21 @@ namespace LeetCode.CSharp; [AttributeUsage(AttributeTargets.Method | AttributeTargets.Class)] -public sealed class LeetCodeAttribute : Attribute +public sealed class LeetCodeAttribute( + string description, + Difficulty difficulty, + Category category, + string uri = "") : Attribute { /// Challenge description - public string Description { get; } + public string Description { get; } = description; /// LeetCode difficulty - public Difficulty Difficulty { get; } + public Difficulty Difficulty { get; } = difficulty; /// NeetCode category - public Category Category { get; } + public Category Category { get; } = category; /// Link to NeetCode video - public Uri? Link { get; } - - public LeetCodeAttribute( - string description, - Difficulty difficulty, - Category category, - string uri = "") - { - Description = description; - Difficulty = difficulty; - Category = category; - Link = string.IsNullOrEmpty(uri) ? null : new Uri($"{uri}", UriKind.Absolute); - } + public Uri? Link { get; } = string.IsNullOrEmpty(uri) ? null : new Uri($"{uri}", UriKind.Absolute); } diff --git a/LeetCode.CSharp/ListNode.cs b/LeetCode.CSharp/ListNode.cs index a49fcc1..dfd4347 100644 --- a/LeetCode.CSharp/ListNode.cs +++ b/LeetCode.CSharp/ListNode.cs @@ -32,7 +32,7 @@ public ListNode(IReadOnlyList list) { var node = new ListNode(list[i]) { - next = lastNode + next = lastNode, }; lastNode = node; } diff --git a/LeetCode.CSharp/Problems/BinarySearch.cs b/LeetCode.CSharp/Problems/BinarySearch.cs index 1c068fa..53e6b44 100644 --- a/LeetCode.CSharp/Problems/BinarySearch.cs +++ b/LeetCode.CSharp/Problems/BinarySearch.cs @@ -14,7 +14,7 @@ public static int BinarySearch(int[] nums, int target) while (leftPtr <= rightPtr) { // Find mid-point without risk of overflowing - var midPtr = leftPtr + (rightPtr - leftPtr) / 2; + var midPtr = leftPtr + ((rightPtr - leftPtr) / 2); var midVal = nums[midPtr]; if (midVal > target) diff --git a/LeetCode.CSharp/Problems/CanAttendMeetings.cs b/LeetCode.CSharp/Problems/CanAttendMeetings.cs index 00c1687..e268a57 100644 --- a/LeetCode.CSharp/Problems/CanAttendMeetings.cs +++ b/LeetCode.CSharp/Problems/CanAttendMeetings.cs @@ -32,12 +32,12 @@ public void CanAttendMeetingsTest() { new(0, 30), new(5, 10), - new(15, 20) + new(15, 20), }; var ex2 = new List { new(5, 8), - new(9, 15) + new(9, 15), }; CanAttendMeetings(ex1).ShouldBeFalse(); diff --git a/LeetCode.CSharp/Problems/EncodeDecode.cs b/LeetCode.CSharp/Problems/EncodeDecode.cs index d0c3c9e..539a423 100644 --- a/LeetCode.CSharp/Problems/EncodeDecode.cs +++ b/LeetCode.CSharp/Problems/EncodeDecode.cs @@ -1,3 +1,5 @@ +using System.Globalization; + namespace LeetCode.CSharp.Problems; public sealed partial class Problem @@ -31,7 +33,7 @@ public static IEnumerable Decode(string str) } // Assumes string is correctly encoded - var length = int.Parse(str.AsSpan(i, j - i)); + var length = int.Parse(str.AsSpan(i, j - i), CultureInfo.InvariantCulture); // Move past delimiter j++; diff --git a/LeetCode.CSharp/Problems/FizzBuzz.cs b/LeetCode.CSharp/Problems/FizzBuzz.cs index 8893e34..52f1053 100644 --- a/LeetCode.CSharp/Problems/FizzBuzz.cs +++ b/LeetCode.CSharp/Problems/FizzBuzz.cs @@ -23,7 +23,7 @@ public static IList FizzBuzz(int n) if (string.IsNullOrEmpty(value)) { - value = i.ToString(); + value = i.ToString(System.Globalization.CultureInfo.InvariantCulture); } result.Add(value); diff --git a/LeetCode.CSharp/Problems/GroupAnagrams.cs b/LeetCode.CSharp/Problems/GroupAnagrams.cs index c50acec..d34dcbb 100644 --- a/LeetCode.CSharp/Problems/GroupAnagrams.cs +++ b/LeetCode.CSharp/Problems/GroupAnagrams.cs @@ -10,7 +10,7 @@ public sealed partial class Problem [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] public static IList> GroupAnagrams(string[] strs) { - var dictionary = new Dictionary>(); + var dictionary = new Dictionary>(StringComparer.Ordinal); foreach (var str in strs) { @@ -44,7 +44,7 @@ public void GroupAnagramsTest() { new() { "eat", "tea", "ate" }, new() { "tan", "nat" }, - new() { "bat" } + new() { "bat" }, }; var ex2 = new[] { "" }; var ex2Expected = new List> { new() { "" } }; @@ -62,7 +62,7 @@ public void GroupAnagramsTest() new() { "buy" }, new() { "bar" }, new() { "max" }, - new() { "doc" } + new() { "doc" }, }; // ReSharper disable once CollectionNeverQueried.Local diff --git a/LeetCode.CSharp/Problems/Insert.cs b/LeetCode.CSharp/Problems/Insert.cs index 5c0358c..36f484b 100644 --- a/LeetCode.CSharp/Problems/Insert.cs +++ b/LeetCode.CSharp/Problems/Insert.cs @@ -38,7 +38,7 @@ public static int[][] Insert(int[][] intervals, int[] newInterval) newInterval = [ Math.Min(intervalStart, newIntervalStart), - Math.Max(intervalEnd, newIntervalEnd) + Math.Max(intervalEnd, newIntervalEnd), ]; } } @@ -55,29 +55,29 @@ public void InsertTest() var ex1Intervals = new[] { new[] { 1, 3 }, - new[] { 6, 9 } + [6, 9], }; var ex1NewInterval = new[] { 2, 5 }; var ex1Expected = new[] { new[] { 1, 5 }, - new[] { 6, 9 } + [6, 9], }; var ex2Intervals = new[] { new[] { 1, 2 }, - new[] { 3, 5 }, - new[] { 6, 7 }, - new[] { 8, 10 }, - new[] { 12, 16 } + [3, 5], + [6, 7], + [8, 10], + [12, 16], }; var ex2NewInterval = new[] { 4, 8 }; var ex2Expected = new[] { new[] { 1, 2 }, - new[] { 3, 10 }, - new[] { 12, 16 } + [3, 10], + [12, 16], }; Insert(ex1Intervals, ex1NewInterval).ShouldBe(ex1Expected); diff --git a/LeetCode.CSharp/Problems/InvertTree.cs b/LeetCode.CSharp/Problems/InvertTree.cs index d4d6045..d4fb24a 100644 --- a/LeetCode.CSharp/Problems/InvertTree.cs +++ b/LeetCode.CSharp/Problems/InvertTree.cs @@ -42,6 +42,6 @@ public void InvertTreeTest() InvertTree(root1).ShouldBeEquivalentTo(exp1); InvertTree(root2).ShouldBeEquivalentTo(exp2); InvertTree(new TreeNode()).ShouldBeEquivalentTo(new TreeNode()); - InvertTree(null).ShouldBeNull(); + InvertTree(root: null).ShouldBeNull(); } } diff --git a/LeetCode.CSharp/Problems/IsAnagram.cs b/LeetCode.CSharp/Problems/IsAnagram.cs index 42e74e7..9d2bf6f 100644 --- a/LeetCode.CSharp/Problems/IsAnagram.cs +++ b/LeetCode.CSharp/Problems/IsAnagram.cs @@ -7,7 +7,7 @@ public sealed partial class Problem Category.ArraysAndHashing, "https://www.youtube.com/watch?v=9UtInBqnCgA")] public static bool IsAnagram(string s, string t) => - s.Length == t.Length && s.OrderBy(c => c).SequenceEqual(t.OrderBy(c => c)); + s.Length == t.Length && s.Order().SequenceEqual(t.Order()); [Fact] [SuppressMessage("ReSharper", "StringLiteralTypo")] diff --git a/LeetCode.CSharp/Problems/IsPalindrone.cs b/LeetCode.CSharp/Problems/IsPalindrone.cs index c567904..63d14b2 100644 --- a/LeetCode.CSharp/Problems/IsPalindrone.cs +++ b/LeetCode.CSharp/Problems/IsPalindrone.cs @@ -1,8 +1,5 @@ namespace LeetCode.CSharp.Problems; -using System.Collections.Generic; -using System.Linq; - public sealed partial class Problem { [LeetCode("Palindrome Linked List", diff --git a/LeetCode.CSharp/Problems/IsSameTree.cs b/LeetCode.CSharp/Problems/IsSameTree.cs index 81a8c6d..9b44ca5 100644 --- a/LeetCode.CSharp/Problems/IsSameTree.cs +++ b/LeetCode.CSharp/Problems/IsSameTree.cs @@ -21,12 +21,7 @@ public static bool IsSameTree(TreeNode? p, TreeNode? q) } // Both must now be non-null - if (p.val != q.val) - { - return false; - } - - return IsSameTree(p.left, q.left) && IsSameTree(p.right, q.right); + return p.val == q.val && IsSameTree(p.left, q.left) && IsSameTree(p.right, q.right); } [Fact] @@ -42,6 +37,6 @@ public void IsSameTreeTest() IsSameTree(p1, q1).ShouldBeTrue(); IsSameTree(p2, q2).ShouldBeFalse(); IsSameTree(p3, q3).ShouldBeFalse(); - IsSameTree(null, null).ShouldBeTrue(); + IsSameTree(p: null, q: null).ShouldBeTrue(); } } diff --git a/LeetCode.CSharp/Problems/IsSubtree.cs b/LeetCode.CSharp/Problems/IsSubtree.cs index fa4d69c..3a7d2a7 100644 --- a/LeetCode.CSharp/Problems/IsSubtree.cs +++ b/LeetCode.CSharp/Problems/IsSubtree.cs @@ -40,6 +40,6 @@ public void IsSubtreeTest() IsSubtree(root1, subRoot1).ShouldBeTrue(); IsSubtree(root2, subRoot2).ShouldBeFalse(); - IsSubtree(null, null).ShouldBeTrue(); + IsSubtree(root: null, subRoot: null).ShouldBeTrue(); } } diff --git a/LeetCode.CSharp/Problems/IsValidSudoku.cs b/LeetCode.CSharp/Problems/IsValidSudoku.cs index 475190c..5f05c0d 100644 --- a/LeetCode.CSharp/Problems/IsValidSudoku.cs +++ b/LeetCode.CSharp/Problems/IsValidSudoku.cs @@ -74,7 +74,7 @@ public void IsValidSudokuTest() ['7', '.', '.', '.', '2', '.', '.', '.', '6'], ['.', '6', '.', '.', '.', '.', '2', '8', '.'], ['.', '.', '.', '4', '1', '9', '.', '.', '5'], - ['.', '.', '.', '.', '8', '.', '.', '7', '9'] + ['.', '.', '.', '.', '8', '.', '.', '7', '9'], }; var ex2 = new char[][] { @@ -86,7 +86,7 @@ public void IsValidSudokuTest() ['7', '.', '.', '.', '2', '.', '.', '.', '6'], ['.', '6', '.', '.', '.', '.', '2', '8', '.'], ['.', '.', '.', '4', '1', '9', '.', '.', '5'], - ['.', '.', '.', '.', '8', '.', '.', '7', '9'] + ['.', '.', '.', '.', '8', '.', '.', '7', '9'], }; var ex3 = new char[][] { @@ -98,7 +98,7 @@ public void IsValidSudokuTest() ['.', '.', '.', '7', '.', '.', '.', '.', '.'], ['.', '.', '.', '5', '.', '.', '.', '.', '.'], ['.', '.', '.', '.', '.', '.', '.', '.', '.'], - ['.', '.', '.', '.', '.', '.', '.', '.', '.'] + ['.', '.', '.', '.', '.', '.', '.', '.', '.'], }; IsValidSudoku(ex1).ShouldBeTrue(); diff --git a/LeetCode.CSharp/Problems/KWeakestRows.cs b/LeetCode.CSharp/Problems/KWeakestRows.cs index 047df3d..b756570 100644 --- a/LeetCode.CSharp/Problems/KWeakestRows.cs +++ b/LeetCode.CSharp/Problems/KWeakestRows.cs @@ -19,14 +19,14 @@ public void KWeakestRowsTest() [1, 1, 1, 1, 0], [1, 0, 0, 0, 0], [1, 1, 0, 0, 0], - [1, 1, 1, 1, 1] + [1, 1, 1, 1, 1], }; var ex2 = new int[][] { [1, 0, 0, 0], [1, 1, 1, 1], [1, 0, 0, 0], - [1, 0, 0, 0] + [1, 0, 0, 0], }; KWeakestRows(ex1, 3).ShouldBe([2, 0, 3]); diff --git a/LeetCode.CSharp/Problems/KthLargest.cs b/LeetCode.CSharp/Problems/KthLargest.cs index 218434e..8fa8ec2 100644 --- a/LeetCode.CSharp/Problems/KthLargest.cs +++ b/LeetCode.CSharp/Problems/KthLargest.cs @@ -16,7 +16,7 @@ public KthLargest(int k, int[] nums) { _k = k; nums - .OrderBy(n => n) + .Order() .TakeLast(k) .ToList() .ForEach(n => _queue.Enqueue(n, n)); diff --git a/LeetCode.CSharp/Problems/LRUCache.cs b/LeetCode.CSharp/Problems/LRUCache.cs index e5d256c..75c3a78 100644 --- a/LeetCode.CSharp/Problems/LRUCache.cs +++ b/LeetCode.CSharp/Problems/LRUCache.cs @@ -9,7 +9,7 @@ public sealed partial class Problem [SuppressMessage("ReSharper", "InconsistentNaming")] public class LRUCache { - private record Node(int Key = 0, int Value = 0) + private sealed record Node(int Key = 0, int Value = 0) { public Node? Previous { get; set; } diff --git a/LeetCode.CSharp/Problems/LowestCommonAncestor.cs b/LeetCode.CSharp/Problems/LowestCommonAncestor.cs index ca328ab..ccc5d2d 100644 --- a/LeetCode.CSharp/Problems/LowestCommonAncestor.cs +++ b/LeetCode.CSharp/Problems/LowestCommonAncestor.cs @@ -12,7 +12,10 @@ public static TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode while (true) { - ArgumentNullException.ThrowIfNull(current); + if (current is null) + { + throw new ArgumentException("Both nodes must be in the tree", nameof(root)); + } if (p.val < current.val && q.val < current.val) { diff --git a/LeetCode.CSharp/Problems/MaxDepth.cs b/LeetCode.CSharp/Problems/MaxDepth.cs index b027db0..edda9fe 100644 --- a/LeetCode.CSharp/Problems/MaxDepth.cs +++ b/LeetCode.CSharp/Problems/MaxDepth.cs @@ -6,15 +6,7 @@ public sealed partial class Problem Difficulty.Easy, Category.Trees, "https://www.youtube.com/watch?v=hTM3phVI6YQ")] - public static int MaxDepth(TreeNode? root) - { - if (root is null) - { - return 0; - } - - return Math.Max(MaxDepth(root.left), MaxDepth(root.right)) + 1; - } + public static int MaxDepth(TreeNode? root) => root is null ? 0 : Math.Max(MaxDepth(root.left), MaxDepth(root.right)) + 1; [Fact] public void MaxDepthTest() @@ -24,7 +16,7 @@ public void MaxDepthTest() right: new TreeNode(20, left: new TreeNode(15), right: new TreeNode(7))); var root2 = new TreeNode(1, left: null, right: new TreeNode(2)); - MaxDepth(null).ShouldBe(0); + MaxDepth(root: null).ShouldBe(0); MaxDepth(root1).ShouldBe(3); MaxDepth(root2).ShouldBe(2); } diff --git a/LeetCode.CSharp/Problems/MaximumWealth.cs b/LeetCode.CSharp/Problems/MaximumWealth.cs index e0e5bdc..14fb769 100644 --- a/LeetCode.CSharp/Problems/MaximumWealth.cs +++ b/LeetCode.CSharp/Problems/MaximumWealth.cs @@ -5,7 +5,7 @@ public sealed partial class Problem [LeetCode("Richest Customer Wealth", Difficulty.Easy, Category.NotInNeetCode)] [SuppressMessage("ReSharper", "ParameterTypeCanBeEnumerable.Global")] public static int MaximumWealth(int[][] accounts) => - accounts.Select(account => account.Sum()).Max(); + accounts.Max(account => account.Sum()); [Fact] public void MaximumWealthTest() @@ -13,13 +13,13 @@ public void MaximumWealthTest() var ex1 = new int[][] { [1, 2, 3], - [3, 2, 1] + [3, 2, 1], }; var ex2 = new int[][] { [1, 5], [7, 3], - [3, 5] + [3, 5], }; MaximumWealth(ex1).ShouldBe(6); diff --git a/LeetCode.CSharp/Problems/MergeTwoLists.cs b/LeetCode.CSharp/Problems/MergeTwoLists.cs index 4b9f102..bfdc47c 100644 --- a/LeetCode.CSharp/Problems/MergeTwoLists.cs +++ b/LeetCode.CSharp/Problems/MergeTwoLists.cs @@ -47,7 +47,7 @@ public void MergeTwoListsTest() var ex3 = new ListNode(); MergeTwoLists(ex11, ex12).ShouldBeEquivalentTo(ep1); - MergeTwoLists(null, null).ShouldBeNull(); - MergeTwoLists(null, ex3).ShouldBeEquivalentTo(ex3); + MergeTwoLists(list1: null, list2: null).ShouldBeNull(); + MergeTwoLists(list1: null, ex3).ShouldBeEquivalentTo(ex3); } } diff --git a/LeetCode.CSharp/Problems/MiddleNode.cs b/LeetCode.CSharp/Problems/MiddleNode.cs index 7b07020..2da48b0 100644 --- a/LeetCode.CSharp/Problems/MiddleNode.cs +++ b/LeetCode.CSharp/Problems/MiddleNode.cs @@ -1,8 +1,5 @@ namespace LeetCode.CSharp.Problems; -using System.Collections.Generic; -using System.Linq; - public sealed partial class Problem { [LeetCode("Middle of the Linked List", Difficulty.Easy, Category.NotInNeetCode)] diff --git a/LeetCode.CSharp/Problems/NumIslands.cs b/LeetCode.CSharp/Problems/NumIslands.cs index 9c27676..5344961 100644 --- a/LeetCode.CSharp/Problems/NumIslands.cs +++ b/LeetCode.CSharp/Problems/NumIslands.cs @@ -6,6 +6,8 @@ public sealed partial class Problem Difficulty.Medium, Category.Graphs, "https://www.youtube.com/watch?v=pV2kpPD66nE")] + [SuppressMessage("Design", "MA0051:Method is too long", + Justification = "The local functions share the search state and count towards the length")] public static int NumIslands(char[][]? grid) { if (grid is null || grid.Length == 0) @@ -13,7 +15,7 @@ public static int NumIslands(char[][]? grid) return 0; } - const char sea = '0'; + const char Sea = '0'; var rows = grid.Length; var columns = grid[0].Length; var visited = new HashSet<(int, int)>(); @@ -23,7 +25,7 @@ public static int NumIslands(char[][]? grid) Up = (1, 0), Left = (-1, 0), Right = (0, 1), - Down = (0, -1) + Down = (0, -1), }; var islands = 0; @@ -32,7 +34,7 @@ public static int NumIslands(char[][]? grid) { for (var column = 0; column < columns; column++) { - if (grid[row][column] == sea) + if (grid[row][column] == Sea) { continue; } @@ -61,7 +63,7 @@ void TestDirection((int row, int column) position, (int row, int column) directi return; } - if (grid[row][column] == sea) + if (grid[row][column] == Sea) { return; } @@ -103,17 +105,17 @@ public void NumIslandsTest() ['1', '1', '1', '1', '0'], ['1', '1', '0', '1', '0'], ['1', '1', '0', '0', '0'], - ['0', '0', '0', '0', '0'] + ['0', '0', '0', '0', '0'], }; var ex2 = new char[][] { ['1', '1', '0', '0', '0'], ['1', '1', '0', '0', '0'], ['0', '0', '1', '0', '0'], - ['0', '0', '0', '1', '1'] + ['0', '0', '0', '1', '1'], }; - NumIslands(null).ShouldBe(0); + NumIslands(grid: null).ShouldBe(0); NumIslands([]).ShouldBe(0); NumIslands(ex1).ShouldBe(1); NumIslands(ex2).ShouldBe(3); diff --git a/LeetCode.CSharp/Problems/ProductExceptSelf.cs b/LeetCode.CSharp/Problems/ProductExceptSelf.cs index 4bd75b1..4b14e72 100644 --- a/LeetCode.CSharp/Problems/ProductExceptSelf.cs +++ b/LeetCode.CSharp/Problems/ProductExceptSelf.cs @@ -9,7 +9,10 @@ public sealed partial class Problem public static int[] ProductExceptSelf(int[] nums) { var length = nums.Length; - if (length == 0) return nums; + if (length == 0) + { + return nums; + } var prefix = 1; var productArray = new int[length]; diff --git a/LeetCode.CSharp/Problems/RansomNote.cs b/LeetCode.CSharp/Problems/RansomNote.cs index 1bceeb7..5ace2ed 100644 --- a/LeetCode.CSharp/Problems/RansomNote.cs +++ b/LeetCode.CSharp/Problems/RansomNote.cs @@ -36,15 +36,15 @@ public static bool RansomNote(string ransomNote, string magazine) [SuppressMessage("ReSharper", "StringLiteralTypo")] public void RansomNoteTest() { - const string m1 = "a"; - const string r1 = "b"; - const string m2 = "aa"; - const string r2 = "ab"; - const string r3 = "bg"; - const string m3 = "aabefjbdfbdgfjhhaiigfhbaejahgfbbgbjagbddfgdiaigdadhcfcj"; + const string M1 = "a"; + const string R1 = "b"; + const string M2 = "aa"; + const string R2 = "ab"; + const string R3 = "bg"; + const string M3 = "aabefjbdfbdgfjhhaiigfhbaejahgfbbgbjagbddfgdiaigdadhcfcj"; - RansomNote(r1, m1).ShouldBeFalse(); - RansomNote(r2, m2).ShouldBeFalse(); - RansomNote(r3, m3).ShouldBeTrue(); + RansomNote(R1, M1).ShouldBeFalse(); + RansomNote(R2, M2).ShouldBeFalse(); + RansomNote(R3, M3).ShouldBeTrue(); } } diff --git a/LeetCode.CSharp/Problems/ReverseBits.cs b/LeetCode.CSharp/Problems/ReverseBits.cs index 77a880c..72a6b37 100644 --- a/LeetCode.CSharp/Problems/ReverseBits.cs +++ b/LeetCode.CSharp/Problems/ReverseBits.cs @@ -12,8 +12,8 @@ public static uint ReverseBits(uint n) for (var i = 0; i < 32; i++) { - var bit = n >> i & 1; - result |= bit << 31 - i; + var bit = (n >> i) & 1; + result |= bit << (31 - i); } return result; @@ -22,10 +22,10 @@ public static uint ReverseBits(uint n) [Fact] public void ReverseBitsTest() { - const uint ex1 = 0b00000010100101000001111010011100; - const uint ex2 = 0b11111111111111111111111111111101; + const uint Ex1 = 0b00000010100101000001111010011100; + const uint Ex2 = 0b11111111111111111111111111111101; - ReverseBits(ex1).ShouldBe(0b00111001011110000010100101000000U); - ReverseBits(ex2).ShouldBe(0b10111111111111111111111111111111U); + ReverseBits(Ex1).ShouldBe(0b00111001011110000010100101000000U); + ReverseBits(Ex2).ShouldBe(0b10111111111111111111111111111111U); } } diff --git a/LeetCode.CSharp/Problems/RomanToInt.cs b/LeetCode.CSharp/Problems/RomanToInt.cs index 4c74c7d..88a582a 100644 --- a/LeetCode.CSharp/Problems/RomanToInt.cs +++ b/LeetCode.CSharp/Problems/RomanToInt.cs @@ -1,7 +1,5 @@ namespace LeetCode.CSharp.Problems; -using System.Collections.Generic; - public sealed partial class Problem { [LeetCode("Roman to Integer", Difficulty.Easy, Category.NotInNeetCode)] @@ -15,7 +13,7 @@ public static int RomanToInt(string s) { 'L', 50 }, { 'C', 100 }, { 'D', 500 }, - { 'M', 1_000 } + { 'M', 1_000 }, }; var result = 0; var length = s.Length - 1; diff --git a/LeetCode.CSharp/Problems/Subsets.cs b/LeetCode.CSharp/Problems/Subsets.cs index ab270c0..b08c0a0 100644 --- a/LeetCode.CSharp/Problems/Subsets.cs +++ b/LeetCode.CSharp/Problems/Subsets.cs @@ -51,13 +51,13 @@ public void SubsetsTest() new List { 2, 3 }, new List { 2 }, new List { 3 }, - new List() + new List(), }; var ex2 = new[] { 0 }; var ep2 = new List> { new List{ 0 }, - new List() + new List(), }; Subsets(ex1).ShouldBe(ep1); diff --git a/LeetCode.CSharp/Problems/TopKFrequent.cs b/LeetCode.CSharp/Problems/TopKFrequent.cs index a4ca2cd..f46ed87 100644 --- a/LeetCode.CSharp/Problems/TopKFrequent.cs +++ b/LeetCode.CSharp/Problems/TopKFrequent.cs @@ -1,3 +1,5 @@ +using System.Runtime.InteropServices; + namespace LeetCode.CSharp.Problems; public sealed partial class Problem @@ -15,15 +17,8 @@ public static int[] TopKFrequent(int[] nums, int k) foreach (var num in nums) { - // ContainsKey will warn on CA1854 and benchmarking showed virtually no difference - if (frequency.TryGetValue(num, out _)) - { - frequency[num]++; - } - else - { - frequency.Add(num, 1); - } + // One lookup per number, instead of a lookup and then an add or update + CollectionsMarshal.GetValueRefOrAddDefault(frequency, num, out _)++; } // Benchmarking showed linq solution around twice as slow but slightly more memory efficient diff --git a/LeetCode.CSharp/Problems/Trie.cs b/LeetCode.CSharp/Problems/Trie.cs index 790900e..f8b594a 100644 --- a/LeetCode.CSharp/Problems/Trie.cs +++ b/LeetCode.CSharp/Problems/Trie.cs @@ -8,10 +8,7 @@ public sealed partial class Problem "https://www.youtube.com/watch?v=oobqoCJlHA0")] public class Trie { - public Trie() - { - Root = new TrieChild(); - } + public Trie() => Root = new TrieChild(); private TrieChild Root { get; } diff --git a/LeetCode.CSharp/Problems/ValidParentheses.cs b/LeetCode.CSharp/Problems/ValidParentheses.cs index 73b5f89..11f79dc 100644 --- a/LeetCode.CSharp/Problems/ValidParentheses.cs +++ b/LeetCode.CSharp/Problems/ValidParentheses.cs @@ -17,7 +17,7 @@ public static bool ValidParentheses(string s) { { ')', '(' }, { ']', '[' }, - { '}', '{' } + { '}', '{' }, }; var stack = new Stack(); diff --git a/LeetCode/BenchmarkRunner.cs b/LeetCode/BenchmarkRunner.cs index df8db71..2f95223 100644 --- a/LeetCode/BenchmarkRunner.cs +++ b/LeetCode/BenchmarkRunner.cs @@ -77,12 +77,12 @@ private static string WaitingMessage(BenchmarkSettings settings, string[] args) { var language = problem.Language($" {Resources.Problem_Language_Separator} "); var benchmark = problem.CSharp & problem.FSharp - ? Resources.Benchmark_Plural.ToLower() : Resources.Benchmark_Singular.ToLower(); - message.AppendFormat(Resources.BenchmarkRunner_SingleProblem_Markup, + ? Resources.Benchmark_Plural.ToLowerInvariant() : Resources.Benchmark_Singular.ToLowerInvariant(); + message.AppendFormat(CultureInfo.CurrentCulture, Resources.BenchmarkRunner_SingleProblem_Markup, language, benchmark, problem.Description); if (!problem.HasSimilarNameAndDescription()) { - message.AppendFormat(Resources.BenchmarkRunner_SingleProblem_Name, problem.Name); + message.AppendFormat(CultureInfo.CurrentCulture, Resources.BenchmarkRunner_SingleProblem_Name, problem.Name); } } else @@ -95,8 +95,8 @@ private static string WaitingMessage(BenchmarkSettings settings, string[] args) if (settings.Filter?.Length > 0) { - message.AppendFormat( - Resources.BenchmarkRunner_Running_FilterSuffix_Markup, settings.Filter!); + message.AppendFormat(CultureInfo.CurrentCulture, + Resources.BenchmarkRunner_Running_FilterSuffix_Markup, settings.Filter); } } diff --git a/LeetCode/Commands/BenchmarkSettings.cs b/LeetCode/Commands/BenchmarkSettings.cs index 1bec58a..eb2fbee 100644 --- a/LeetCode/Commands/BenchmarkSettings.cs +++ b/LeetCode/Commands/BenchmarkSettings.cs @@ -22,21 +22,12 @@ internal sealed class BenchmarkSettings : CommandSettings [CommandOption("--exporters")] public string? Exporters { get; init; } - public override ValidationResult Validate() - { - if (CSharp && FSharp) - { - return ValidationResult.Error(Resources.BenchmarkSettings_Error_MutuallyExclusive); - } - - if (!string.IsNullOrEmpty(Filter) && !BenchmarkFound()) - { - return ValidationResult.Error( - string.Format(Resources.BenchmarkSettings_Error_BenchmarkNotFound, Filter)); - } - - return ValidationResult.Success(); - } + public override ValidationResult Validate() => CSharp && FSharp + ? ValidationResult.Error(Resources.BenchmarkSettings_Error_MutuallyExclusive) + : !string.IsNullOrEmpty(Filter) && !BenchmarkFound() + ? ValidationResult.Error( + string.Format(CultureInfo.CurrentCulture, Resources.BenchmarkSettings_Error_BenchmarkNotFound, Filter)) + : ValidationResult.Success(); public Type[] BenchmarkTypes() { @@ -54,8 +45,8 @@ public Type[] BenchmarkTypes() } return [.. types - .OrderBy(t => t.Name) - .ThenBy(t => t.Namespace)]; + .OrderBy(t => t.Name, StringComparer.Ordinal) + .ThenBy(t => t.Namespace, StringComparer.Ordinal)]; } public string[] BuildArgs() @@ -84,12 +75,12 @@ public string[] BuildArgs() foreach (var benchmark in benchmarks) { - if (benchmark.Contains('*')) + if (benchmark.Contains('*', StringComparison.Ordinal)) { // User added wildcard so use whatever was passed args.Add(benchmark); } - else if (benchmark.Contains('.')) + else if (benchmark.Contains('.', StringComparison.Ordinal)) { // User added namespace but no wildcard so add suffix args.Add($"{benchmark}*"); @@ -116,6 +107,6 @@ public string[] BuildArgs() private bool BenchmarkFound() => Reflection .GetCSharpBenchmarks() - .Union(Reflection.GetFSharpBenchmarks()) + .Union(Reflection.GetFSharpBenchmarks(), StringComparer.Ordinal) .Contains(Filter, StringComparer.InvariantCultureIgnoreCase); } diff --git a/LeetCode/Commands/ProblemSettings.cs b/LeetCode/Commands/ProblemSettings.cs index fbe9b74..1ff313e 100644 --- a/LeetCode/Commands/ProblemSettings.cs +++ b/LeetCode/Commands/ProblemSettings.cs @@ -6,19 +6,10 @@ internal sealed class ProblemSettings : CommandSettings [CommandArgument(0, "[name]")] public string Name { get; init; } = string.Empty; - public override ValidationResult Validate() - { - if (string.IsNullOrWhiteSpace(Name)) - { - return ValidationResult.Error(Resources.ProblemSettings_Error_NoArgumentPassed); - } - - if (!Reflection.TryGetProblem(Name, out _)) - { - return ValidationResult.Error( - string.Format(Resources.ProblemSettings_Error_ProblemNotFound, Name)); - } - - return ValidationResult.Success(); - } -} \ No newline at end of file + public override ValidationResult Validate() => string.IsNullOrWhiteSpace(Name) + ? ValidationResult.Error(Resources.ProblemSettings_Error_NoArgumentPassed) + : !Reflection.TryGetProblem(Name, out _) + ? ValidationResult.Error( + string.Format(CultureInfo.CurrentCulture, Resources.ProblemSettings_Error_ProblemNotFound, Name)) + : ValidationResult.Success(); +} diff --git a/LeetCode/Commands/WorkflowCommand.cs b/LeetCode/Commands/WorkflowCommand.cs index b8520ba..a851b76 100644 --- a/LeetCode/Commands/WorkflowCommand.cs +++ b/LeetCode/Commands/WorkflowCommand.cs @@ -46,17 +46,17 @@ private static void CombineBenchmarkResults( File.Delete(resultsPath); } - const string ns = "LeetCode.XSharp.Benchmarks."; + const string BenchmarkNamespace = "LeetCode.XSharp.Benchmarks."; var reports = Directory .GetFiles(resultsDir, searchPattern, SearchOption.TopDirectoryOnly) - .OrderBy(report => report[ns.Length..]) + .OrderBy(report => report[BenchmarkNamespace.Length..], StringComparer.Ordinal) .ToArray(); if (reports.Length == 0) { throw new FileNotFoundException($"Reports not found '{searchPattern}'"); } - var firstReport = reports.First(); + var firstReport = reports[0]; var combinedReport = JsonNode.Parse(File.ReadAllText(firstReport))!; var title = combinedReport["Title"]!; var benchmarks = combinedReport["Benchmarks"]!.AsArray(); @@ -83,7 +83,7 @@ private static void CombineBenchmarkResults( private static void SetBenchmarkName(string report, JsonNode benchmark) { // Make pretty as only one method per benchmark - or tweak index.html? - var language = report.Contains("CSharp") ? "C#" : "F#"; + var language = report.Contains("CSharp", StringComparison.Ordinal) ? "C#" : "F#"; benchmark["FullName"] = $"{benchmark["Method"]} in {language}"; } } diff --git a/LeetCode/Extensions.cs b/LeetCode/Extensions.cs index 51cced6..6ed5d4d 100644 --- a/LeetCode/Extensions.cs +++ b/LeetCode/Extensions.cs @@ -1,5 +1,7 @@ namespace LeetCode; +[SuppressMessage("Naming", "CA1708:Identifiers should differ by more than case", + Justification = "False positive on the compiler-generated names of C# 14 extension blocks")] public static partial class Extensions { extension(Category category) @@ -16,15 +18,14 @@ public string Markup() => extension(Problem problem) { - internal bool HasSimilarNameAndDescription() => - problem.Description.ReplaceWhitespace(string.Empty) == problem.Name; + internal bool HasSimilarNameAndDescription() => string.Equals(problem.Description.ReplaceWhitespace(string.Empty), problem.Name, StringComparison.Ordinal); internal Table Markup() { var table = new Table { Border = TableBorder.None, - ShowHeaders = false + ShowHeaders = false, }; table.AddColumn(new TableColumn("-").PadRight(3)); @@ -32,7 +33,7 @@ internal Table Markup() table.AddRow(Resources.Problem_Benchmark_Markup, problem.Name); - if (problem.Name != problem.Description) + if (!string.Equals(problem.Name, problem.Description, StringComparison.Ordinal)) { table.AddRow(Resources.Problem_Description_Markup, problem.Description); } @@ -56,12 +57,10 @@ private string ReplaceWhitespace(string replacement) => MatchWhitespace.Replace(input, replacement); private string GetResource() => - Resources.ResourceManager.GetString(input) ?? + Resources.ResourceManager.GetString(input, CultureInfo.InvariantCulture) ?? throw new InvalidOperationException($"Missing resource '{input}'"); } - private static readonly Regex MatchWhitespace = MatchWhitespaceRegex(); - - [GeneratedRegex(@"\s+")] - private static partial Regex MatchWhitespaceRegex(); + [GeneratedRegex(@"\s+", RegexOptions.None, matchTimeoutMilliseconds: 1000)] + private static partial Regex MatchWhitespace { get; } } diff --git a/LeetCode/Menus/MainMenu.cs b/LeetCode/Menus/MainMenu.cs index 82ffda1..2d6d8ed 100644 --- a/LeetCode/Menus/MainMenu.cs +++ b/LeetCode/Menus/MainMenu.cs @@ -9,7 +9,7 @@ public MainMenu() new ProblemListSelection(1), new BenchmarkListSelection(2), new AboutSelection(3), - new ExitSelection(4) + new ExitSelection(4), ]; } public int Render() @@ -20,7 +20,7 @@ public int Render() .UseConverter(m => m.Name); var exitCode = 0; - while (selected.Name != Resources.Selection_Exit) + while (!string.Equals(selected.Name, Resources.Selection_Exit, StringComparison.Ordinal)) { ConsoleWriter.WriteHeader(clearConsole: true); diff --git a/LeetCode/Menus/MenuBase.cs b/LeetCode/Menus/MenuBase.cs index f3235b8..cf554e9 100644 --- a/LeetCode/Menus/MenuBase.cs +++ b/LeetCode/Menus/MenuBase.cs @@ -5,4 +5,4 @@ internal abstract class MenuBase protected IEnumerable Choices { get; init; } = []; protected IEnumerable GetChoices() => Choices.OrderBy(m => m.Order); -} \ No newline at end of file +} diff --git a/LeetCode/Menus/ProblemMenu.cs b/LeetCode/Menus/ProblemMenu.cs index 4cdaf34..67b4325 100644 --- a/LeetCode/Menus/ProblemMenu.cs +++ b/LeetCode/Menus/ProblemMenu.cs @@ -10,7 +10,7 @@ public ProblemMenu(Problem problem) Choices = [ new BenchmarkSelection(Problem, 1), - new ExitSelection(2) + new ExitSelection(2), ]; } diff --git a/LeetCode/Menus/Selections/AboutSelection.cs b/LeetCode/Menus/Selections/AboutSelection.cs index d8af98f..b0bd59e 100644 --- a/LeetCode/Menus/Selections/AboutSelection.cs +++ b/LeetCode/Menus/Selections/AboutSelection.cs @@ -16,4 +16,4 @@ public override int Execute() return 0; } -} \ No newline at end of file +} diff --git a/LeetCode/Menus/Selections/BenchmarkListSelection.cs b/LeetCode/Menus/Selections/BenchmarkListSelection.cs index 8ae6339..2eadc8b 100644 --- a/LeetCode/Menus/Selections/BenchmarkListSelection.cs +++ b/LeetCode/Menus/Selections/BenchmarkListSelection.cs @@ -35,7 +35,7 @@ public override int Execute() .Where(problem => selectedProblems.Contains(problem.Description)) .Select(problem => problem.Name); - var settings = new BenchmarkSettings { Filter = string.Join(" ", names) }; + var settings = new BenchmarkSettings { Filter = string.Join(' ', names) }; var summaries = BenchmarkRunner.BuildSummaries(settings); var builder = new SpectreReportBuilder(summaries); var report = builder.Build(); @@ -46,4 +46,4 @@ public override int Execute() return 0; } -} \ No newline at end of file +} diff --git a/LeetCode/Menus/Selections/BenchmarkSelection.cs b/LeetCode/Menus/Selections/BenchmarkSelection.cs index f096b9d..1d8aab2 100644 --- a/LeetCode/Menus/Selections/BenchmarkSelection.cs +++ b/LeetCode/Menus/Selections/BenchmarkSelection.cs @@ -10,10 +10,7 @@ internal BenchmarkSelection(Problem problem, int order) } private BenchmarkSelection(Problem problem, string name, int order) - : base(name, order) - { - Problem = problem; - } + : base(name, order) => Problem = problem; public override int Execute() { @@ -35,4 +32,4 @@ public override int Execute() return 0; } -} \ No newline at end of file +} diff --git a/LeetCode/Menus/Selections/ExitSelection.cs b/LeetCode/Menus/Selections/ExitSelection.cs index 3e58e72..37fc670 100644 --- a/LeetCode/Menus/Selections/ExitSelection.cs +++ b/LeetCode/Menus/Selections/ExitSelection.cs @@ -12,4 +12,4 @@ public override int Execute() return 0; } -} \ No newline at end of file +} diff --git a/LeetCode/Menus/Selections/ProblemListSelection.cs b/LeetCode/Menus/Selections/ProblemListSelection.cs index 3cf0699..b5aa16e 100644 --- a/LeetCode/Menus/Selections/ProblemListSelection.cs +++ b/LeetCode/Menus/Selections/ProblemListSelection.cs @@ -28,7 +28,7 @@ public override int Execute() var table = new Table { Border = TableBorder.Simple, - UseSafeBorder = true + UseSafeBorder = true, }; table.AddColumns(Resources.Problem_Name, Resources.Problem_Category, Resources.Problem_Difficulty); table.Columns[0].Width = padding.DescriptionPad; @@ -50,8 +50,8 @@ private sealed record ProblemPadding(int DescriptionPad, int CategoryPad); private static string ConvertProblem(Problem problem, ProblemPadding padding) => new StringBuilder() - .Append($"{problem.Description.PadRight(padding.DescriptionPad + 3)}") - .Append($"{problem.Category.Description().PadRight(padding.CategoryPad + 3)}") - .Append($"{problem.Difficulty.Markup()}") + .Append(problem.Description.PadRight(padding.DescriptionPad + 3)) + .Append(problem.Category.Description().PadRight(padding.CategoryPad + 3)) + .Append(problem.Difficulty.Markup()) .ToString(); -} \ No newline at end of file +} diff --git a/LeetCode/Menus/Selections/Selection.cs b/LeetCode/Menus/Selections/Selection.cs index 88a5031..c3b9a5a 100644 --- a/LeetCode/Menus/Selections/Selection.cs +++ b/LeetCode/Menus/Selections/Selection.cs @@ -7,4 +7,4 @@ internal abstract record Selection(string Name, int Order) /// /// Status code public abstract int Execute(); -} \ No newline at end of file +} diff --git a/LeetCode/Problem.cs b/LeetCode/Problem.cs index 1eb5ad8..747b87e 100644 --- a/LeetCode/Problem.cs +++ b/LeetCode/Problem.cs @@ -1,6 +1,6 @@ namespace LeetCode; -internal record Problem( +internal sealed record Problem( string Name, string Description, Category Category, @@ -26,4 +26,4 @@ public string LanguageMarkup(string join = " ") => : FSharp ? "[teal]F#[/]" : string.Empty; -} \ No newline at end of file +} diff --git a/LeetCode/Program.cs b/LeetCode/Program.cs index d42e5d0..6a2ca05 100644 --- a/LeetCode/Program.cs +++ b/LeetCode/Program.cs @@ -25,4 +25,4 @@ config.AddExample(Resources.Command_Info, "MergeTwoLists"); }); -return await app.RunAsync(args); +return await app.RunAsync(args, Xunit.TestContext.Current.CancellationToken).ConfigureAwait(false); diff --git a/LeetCode/Reflection.cs b/LeetCode/Reflection.cs index b539c01..ebd0e6f 100644 --- a/LeetCode/Reflection.cs +++ b/LeetCode/Reflection.cs @@ -6,11 +6,11 @@ public static bool TryGetProblem(string name, out Problem problem) { var found = typeof(CSharp.Problems.Problem) .GetMembers() - .Where(m => m.GetCustomAttribute() is not null) + .Where(m => Attribute.IsDefined(m, typeof(LeetCodeAttribute))) .Select(GetProblem) .FirstOrDefault(p => - p.Name.Equals(name, StringComparison.InvariantCultureIgnoreCase) || - p.Description.Equals(name, StringComparison.InvariantCultureIgnoreCase)); + p.Name.Equals(name, StringComparison.OrdinalIgnoreCase) || + p.Description.Equals(name, StringComparison.OrdinalIgnoreCase)); problem = found ?? null!; @@ -19,16 +19,13 @@ public static bool TryGetProblem(string name, out Problem problem) private static Problem GetProblem(MemberInfo memberInfo) { - var csharp = GetCSharpProblems().Contains(memberInfo.Name); - var fsharp = GetFSharpProblems().Contains(memberInfo.Name); + var csharp = GetCSharpProblems().Contains(memberInfo.Name, StringComparer.Ordinal); + var fsharp = GetFSharpProblems().Contains(memberInfo.Name, StringComparer.Ordinal); var attribute = memberInfo.GetCustomAttribute(); - if (attribute is null || !csharp && !fsharp) - { - throw new InvalidOperationException($"Invalid member info '{memberInfo.Name}"); - } - - return new Problem( + return attribute is null || (!csharp && !fsharp) + ? throw new InvalidOperationException($"Invalid member info '{memberInfo.Name}") + : new Problem( memberInfo.Name, attribute.Description, attribute.Category, @@ -41,40 +38,40 @@ private static Problem GetProblem(MemberInfo memberInfo) public static IEnumerable> GetProblemsByCategory() => typeof(CSharp.Problems.Problem) .GetMembers() - .Where(m => m.GetCustomAttribute() is not null) + .Where(m => Attribute.IsDefined(m, typeof(LeetCodeAttribute))) .Select(GetProblem) .OrderBy(p => p.Category) .ThenBy(p => p.Difficulty) - .ThenBy(p => p.Description) + .ThenBy(p => p.Description, StringComparer.Ordinal) .GroupBy(p => p.Category, p => p); public static IEnumerable GetCSharpBenchmarks() => GetCSharpBenchmarkTypes().Select(type => - type.Name.EndsWith("Benchmark") ? type.Name[..^9] : type.Name); + type.Name.EndsWith("Benchmark", StringComparison.Ordinal) ? type.Name[..^9] : type.Name); public static IEnumerable GetFSharpBenchmarks() => GetFSharpBenchmarkTypes().Select(type => - type.Name.EndsWith("Benchmark") ? type.Name[..^9] : type.Name); + type.Name.EndsWith("Benchmark", StringComparison.Ordinal) ? type.Name[..^9] : type.Name); public static IEnumerable GetCSharpBenchmarkTypes() => typeof(Benchmark).Assembly.GetTypes() .Where(type => type.Namespace is not null && !type.IsAbstract && - type.Namespace.StartsWith("LeetCode.CSharp.Benchmarks")); + type.Namespace.StartsWith("LeetCode.CSharp.Benchmarks", StringComparison.Ordinal)); public static IEnumerable GetFSharpBenchmarkTypes() => typeof(FSharp.ListNode).Assembly.GetTypes() .Where(type => type.Namespace is not null && - type.Namespace.StartsWith("LeetCode.FSharp.Benchmarks")); + type.Namespace.StartsWith("LeetCode.FSharp.Benchmarks", StringComparison.Ordinal)); private static IEnumerable GetCSharpProblems() => typeof(CSharp.Problems.Problem) .GetMembers() - .Where(m => m.GetCustomAttribute() is not null) + .Where(m => Attribute.IsDefined(m, typeof(LeetCodeAttribute))) .Select(m => m.Name); private static IEnumerable GetFSharpProblems() => typeof(FSharp.ListNode).Assembly.GetTypes() .Where(type => type.Namespace is not null && - type.Namespace.StartsWith("LeetCode.FSharp.Problems")) + type.Namespace.StartsWith("LeetCode.FSharp.Problems", StringComparison.Ordinal)) .Select(m => m.Name); } diff --git a/LeetCode/SpectreLogger.cs b/LeetCode/SpectreLogger.cs index 7b59698..f89463c 100644 --- a/LeetCode/SpectreLogger.cs +++ b/LeetCode/SpectreLogger.cs @@ -38,16 +38,16 @@ private static void Markup(LogKind logKind, string text, bool writeLine) prefix = "[red]Error[/]: "; break; default: - throw new ArgumentOutOfRangeException(nameof(logKind), logKind, null); + throw new ArgumentOutOfRangeException(nameof(logKind), logKind, message: null); } if (writeLine) { - AnsiConsole.MarkupLineInterpolated($"{prefix}{text}"); + AnsiConsole.MarkupLineInterpolated(CultureInfo.CurrentCulture, $"{prefix}{text}"); } else { - AnsiConsole.MarkupInterpolated($"{prefix}{text}"); + AnsiConsole.MarkupInterpolated(CultureInfo.CurrentCulture, $"{prefix}{text}"); } } } diff --git a/LeetCode/SpectreReportBuilder.cs b/LeetCode/SpectreReportBuilder.cs index 94202b2..af78ec8 100644 --- a/LeetCode/SpectreReportBuilder.cs +++ b/LeetCode/SpectreReportBuilder.cs @@ -10,7 +10,7 @@ public IRenderable Build() { Border = TableBorder.Ascii2, BorderStyle = new Style(foreground: Color.Grey), - UseSafeBorder = true + UseSafeBorder = true, }; if (!Summaries.Any()) @@ -49,13 +49,13 @@ private string[] BuildHeaders(Table table) var defaultHeaders = new[] { "Lang", "Method", "Mean", "Median", "Error", "StdDev", "Op/s", "Gen0", "Gen1", "Gen2", - "Allocated" + "Allocated", }; var summaryHeaders = Summaries .SelectMany(s => s.Table.Columns) .Where(c => c.NeedToShow) - .DistinctBy(c => c.Header) + .DistinctBy(c => c.Header, StringComparer.Ordinal) .Select(c => c.Header) .ToList(); @@ -65,9 +65,9 @@ private string[] BuildHeaders(Table table) // First take the intersection of defaults and summaries, which ensures all columns are // included in their expected order, then append any remaining columns in summaries var headers = defaultHeaders - .Intersect(summaryHeaders) - .Union(summaryHeaders) - .Distinct() + .Intersect(summaryHeaders, StringComparer.Ordinal) + .Union(summaryHeaders, StringComparer.Ordinal) + .Distinct(StringComparer.Ordinal) .ToArray(); foreach (var header in headers) @@ -85,7 +85,7 @@ private string[] BuildHeaders(Table table) private static void BuildSummary(Summary summary, Table table, string[] headers) { - var csharp = summary.Title.Contains(".CSharp."); + var csharp = summary.Title.Contains(".CSharp.", StringComparison.Ordinal); var colour = csharp ? "[blue]" : "[teal]"; var language = csharp ? $"{colour}C#[/]" : $"{colour}F#[/]"; From 38b09cb58a17c95a973f18f41c6b55a457ef1f85 Mon Sep 17 00:00:00 2001 From: Simon McKenna Date: Sun, 18 Oct 2026 12:32:52 +1030 Subject: [PATCH 4/5] Add writing style and agent attribution rules to AGENTS.md Drops CLAUDE.md, which only imported AGENTS.md, and updates the single-test command for MTP. --- AGENTS.md | 45 ++++++++++++++++++++++++++++++++++++++++++--- CLAUDE.md | 3 --- 2 files changed, 42 insertions(+), 6 deletions(-) delete mode 100644 CLAUDE.md diff --git a/AGENTS.md b/AGENTS.md index 01cd0a5..68b46b5 100644 --- a/AGENTS.md +++ b/AGENTS.md @@ -31,7 +31,7 @@ dotnet test --no-restore ### Run a single test ```bash -dotnet test --filter "FullyQualifiedName~TwoSumTest" +dotnet test --project LeetCode.CSharp --filter-method "*TwoSumTest" ``` ### Run console application @@ -74,8 +74,47 @@ for running benchmarks and viewing problem information. **Testing**: -Uses xUnit with Shouldly for test assertions. Tests are co-located with problem implementations for easy access. +Uses xUnit v3 on Microsoft.Testing.Platform, with Shouldly for C# assertions and FsUnit for F#. Tests are co-located with problem implementations for easy access. **Package Management**: -Uses Directory.Packages.props for centralized NuGet package version management across all projects. \ No newline at end of file +Uses Directory.Packages.props for centralized NuGet package version management across all projects. + +## Writing style + +These rules cover all prose in this repository: documentation, code comments, commit messages, pull request titles and +descriptions, and comments an agent posts on issues and pull requests. + +Follow the [Google developer documentation style guide](https://developers.google.com/style), starting with its +[highlights](https://developers.google.com/style/highlights). When a question comes up, use this order of precedence: + +1. The rules in this section. +2. The Google developer documentation style guide. +3. For a technical term that neither settles, the + [Microsoft Writing Style Guide](https://learn.microsoft.com/style-guide/welcome/). + +For more detail, see [awesome-humans/dotnet: AGENTS.md](https://github.com/awesome-humans/dotnet/blob/main/AGENTS.md), +which these rules adapt. + +- **Write for a working .NET developer.** Address the reader as "you", use the imperative for instructions, and use + active voice and present tense. +- **Lead with what matters.** Put the action or the recommendation first, and the reason after it. +- **Be specific.** Name the exact type, member, diagnostic ID, and version instead of describing it. A measured number + beats an adjective. +- **Keep it short and plain.** Aim for about 20 words a sentence. Write _use_, not _utilize_, and drop filler such as + _please_, _simply_, and _just_. +- **Use British spelling, except where .NET names the word.** Write _behaviour_ and _colour_, but keep _globalization_ + and every API name as .NET spells it. +- **Write dates as ISO 8601,** such as `2026-10-18`. + +## Agent attribution + +Pull request titles and descriptions become squash commits, so keep agent attribution out of history: + +- **No agent attribution in history.** Pull request titles, descriptions, and commit messages don't carry + `Co-Authored-By` trailers or "Generated with" lines. This rule overrides any default that an agent harness applies. +- **The rule covers every commit on the branch.** A squash merge appends a `Co-authored-by` line for each co-author + trailer and each commit author other than the merger. Commit under the author's git identity, and leave the trailer + out of branch commits too. +- **Attribute in conversation instead.** End each comment an agent writes on an issue or pull request with an italic + line, such as `_Written by an agent: , ._` diff --git a/CLAUDE.md b/CLAUDE.md deleted file mode 100644 index f5d7667..0000000 --- a/CLAUDE.md +++ /dev/null @@ -1,3 +0,0 @@ -# CLAUDE.md - -@AGENTS.md \ No newline at end of file From 20ed9793ecf2156f813d19abac11b48dc0bed870 Mon Sep 17 00:00:00 2001 From: Simon McKenna Date: Sun, 18 Oct 2026 12:45:19 +1030 Subject: [PATCH 5/5] Skip cursor moves when console output is redirected Spectre.Console falls back to Console.SetCursorPosition without a terminal, and moving up from the first row threw ArgumentOutOfRangeException in list and benchmark. --- LeetCode/BenchmarkRunner.cs | 4 ++-- LeetCode/Commands/ListCommand.cs | 2 +- LeetCode/ConsoleWriter.cs | 14 ++++++++++++++ LeetCode/Menus/Selections/ProblemListSelection.cs | 2 +- 4 files changed, 18 insertions(+), 4 deletions(-) diff --git a/LeetCode/BenchmarkRunner.cs b/LeetCode/BenchmarkRunner.cs index 2f95223..895cb3d 100644 --- a/LeetCode/BenchmarkRunner.cs +++ b/LeetCode/BenchmarkRunner.cs @@ -11,7 +11,7 @@ public static IEnumerable BuildSummaries(BenchmarkSettings settings) throw new ArgumentOutOfRangeException(nameof(settings), "Invalid arguments"); } - AnsiConsole.Cursor.Move(CursorDirection.Up, 1); + ConsoleWriter.MoveCursor(CursorDirection.Up); Console.SetOut(TextWriter.Null); @@ -23,7 +23,7 @@ public static IEnumerable BuildSummaries(BenchmarkSettings settings) Console.SetOut(Console.Out); - AnsiConsole.Cursor.Move(CursorDirection.Down, 1); + ConsoleWriter.MoveCursor(CursorDirection.Down); return summaries; } diff --git a/LeetCode/Commands/ListCommand.cs b/LeetCode/Commands/ListCommand.cs index eb8c6c9..4535023 100644 --- a/LeetCode/Commands/ListCommand.cs +++ b/LeetCode/Commands/ListCommand.cs @@ -9,7 +9,7 @@ public override int Execute([NotNull] CommandContext context, CancellationToken { ConsoleWriter.WriteHeader(); - AnsiConsole.Cursor.Move(CursorDirection.Up, 1); + ConsoleWriter.MoveCursor(CursorDirection.Up); WriteProblemList(); diff --git a/LeetCode/ConsoleWriter.cs b/LeetCode/ConsoleWriter.cs index db5bedd..59463dc 100644 --- a/LeetCode/ConsoleWriter.cs +++ b/LeetCode/ConsoleWriter.cs @@ -28,6 +28,20 @@ public static void AnimateHeader() AnsiConsole.WriteLine(); } + /// + /// Moves the cursor, unless output is redirected. Spectre.Console then falls back to + /// Console.SetCursorPosition, which throws when the cursor would leave the buffer. + /// + public static void MoveCursor(CursorDirection direction, int steps = 1) + { + if (Console.IsOutputRedirected) + { + return; + } + + AnsiConsole.Cursor.Move(direction, steps); + } + public static void WaitForKeyPress() { AnsiConsole.WriteLine(); diff --git a/LeetCode/Menus/Selections/ProblemListSelection.cs b/LeetCode/Menus/Selections/ProblemListSelection.cs index b5aa16e..fbc3d7f 100644 --- a/LeetCode/Menus/Selections/ProblemListSelection.cs +++ b/LeetCode/Menus/Selections/ProblemListSelection.cs @@ -34,7 +34,7 @@ public override int Execute() table.Columns[0].Width = padding.DescriptionPad; table.Columns[1].Width = padding.CategoryPad; - AnsiConsole.Cursor.MoveUp(); + ConsoleWriter.MoveCursor(CursorDirection.Up); AnsiConsole.Write(table); // TODO Capture X (or whatever) to return to main menu instead of forcing selection