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..72352cd 100644 --- a/.editorconfig +++ b/.editorconfig @@ -1,43 +1,158 @@ -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 + +[*] +charset = utf-8 +end_of_line = lf +insert_final_newline = true +indent_style = space +indent_size = 4 +trim_trailing_whitespace = true + +[*.{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] +# --- 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 + +# 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 + +# 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 +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 + +[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/.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..e4ef3af 100644 --- a/.github/workflows/workflow.yml +++ b/.github/workflows/workflow.yml @@ -1,80 +1,95 @@ -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] + +permissions: + contents: read + +env: + DOTNET_NOLOGO: true + DOTNET_SKIP_FIRST_TIME_EXPERIENCE: true + DOTNET_CLI_TELEMETRY_OPTOUT: true + +jobs: + build: + runs-on: ubuntu-latest + steps: + - name: Checkout + uses: actions/checkout@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + + - name: Setup dotnet + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 + with: + global-json-file: global.json + + - 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-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@3d3c42e5aac5ba805825da76410c181273ba90b1 # v7.0.1 + with: + fetch-depth: 0 + + - name: Setup dotnet + uses: actions/setup-dotnet@a98b56852c35b8e3190ac28c8c2271da59106c68 # v6.0.0 + with: + global-json-file: global.json + + - 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@4322e5726e6334590d251fc4f92bec0efafc45dc # v1.22.2 + 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..25cae2a 100644 --- a/.gitignore +++ b/.gitignore @@ -1,7 +1,8 @@ -.idea +.idea .plan .vs *.DotSettings.user bin obj +artifacts/ BenchmarkDotNet.Artifacts 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 diff --git a/Directory.Build.props b/Directory.Build.props index 86c7227..f09e443 100644 --- a/Directory.Build.props +++ b/Directory.Build.props @@ -1,18 +1,40 @@ - - - - - Simon McKenna - true - true - enable - latest - enable - net10.0 - true - - - - - - + + + + + true + + + + Simon McKenna + net10.0 + latest + enable + 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/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..f3f2254 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, value: true); + + AddDiagnoser(MemoryDiagnoser.Default); + + AddColumn(StatisticColumn.OperationsPerSecond); + } +} diff --git a/LeetCode.CSharp/Benchmarks/AddTwoNumbersBenchmark.cs b/LeetCode.CSharp/Benchmarks/AddTwoNumbersBenchmark.cs index afba9a5..ff8ce3c 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); - } -} \ No newline at end of file +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); + } +} diff --git a/LeetCode.CSharp/Benchmarks/BinarySearchBenchmark.cs b/LeetCode.CSharp/Benchmarks/BinarySearchBenchmark.cs index 25e2363..8162edc 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 = []; -} \ No newline at end of file +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 = []; +} diff --git a/LeetCode.CSharp/Benchmarks/CanAttendMeetingsBenchmark.cs b/LeetCode.CSharp/Benchmarks/CanAttendMeetingsBenchmark.cs index 3bcccbc..dd0d31f 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(); - } -} \ No newline at end of file +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(); + } +} 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..6144bdb 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 = []; -} \ No newline at end of file +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 = []; +} diff --git a/LeetCode.CSharp/Benchmarks/CountBitsBenchmark.cs b/LeetCode.CSharp/Benchmarks/CountBitsBenchmark.cs index 00489f7..47cbdde 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); -} \ No newline at end of file +namespace LeetCode.CSharp.Benchmarks; + +public class CountBitsBenchmark : Benchmark +{ + [Benchmark] + public int[] CountBits() => Problem.CountBits(10_000); +} 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..8ae7da0 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 = []; - } -} \ No newline at end of file +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 = []; + } +} 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..b2d6f03 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 = []; -} \ No newline at end of file +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 = []; +} 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..d9524c3 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 = []; - } -} \ No newline at end of file +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 = []; + } +} 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..e4b8c86 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; - } -} \ No newline at end of file +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; + } +} 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..e817e96 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(); - } -} \ No newline at end of file +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(); + } +} 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..56cb6ff 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]]; -} \ No newline at end of file +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]]; +} diff --git a/LeetCode.CSharp/Benchmarks/KWeakestRowsBenchmark.cs b/LeetCode.CSharp/Benchmarks/KWeakestRowsBenchmark.cs index c72f9e9..9d48c8f 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 = []; - } -} \ No newline at end of file +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 = []; + } +} diff --git a/LeetCode.CSharp/Benchmarks/KthLargestBenchmark.cs b/LeetCode.CSharp/Benchmarks/KthLargestBenchmark.cs index 620e2e1..4646711 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!; - } -} \ No newline at end of file +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!; + } +} diff --git a/LeetCode.CSharp/Benchmarks/LRUCacheBenchmark.cs b/LeetCode.CSharp/Benchmarks/LRUCacheBenchmark.cs index c8fec7e..680f91a 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!; -} \ No newline at end of file +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!; +} diff --git a/LeetCode.CSharp/Benchmarks/LastStoneWeightBenchmark.cs b/LeetCode.CSharp/Benchmarks/LastStoneWeightBenchmark.cs index a27da4e..644e25c 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 = []; -} \ No newline at end of file +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 = []; +} diff --git a/LeetCode.CSharp/Benchmarks/LengthOfLongestSubstringBenchmark.cs b/LeetCode.CSharp/Benchmarks/LengthOfLongestSubstringBenchmark.cs index 4cf9896..65dcb4d 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; -} \ No newline at end of file +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; +} 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..49e7aaa 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 = []; -} \ No newline at end of file +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 = []; +} 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..bff9048 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 = []; - } -} \ No newline at end of file +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 = []; + } +} 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..d719e6f 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(); -} \ No newline at end of file +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(); +} 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..09c5561 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 = []; -} \ No newline at end of file +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 = []; +} 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..5d2ef7f 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); -} \ No newline at end of file +namespace LeetCode.CSharp.Benchmarks; + +public class NumberOfStepsBenchmark : Benchmark +{ + [Benchmark] + public int NumberOfSteps() => Problem.NumberOfSteps(1_000_000_000); +} 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..97ea153 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 = []; -} \ No newline at end of file +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 = []; +} diff --git a/LeetCode.CSharp/Benchmarks/RansomNoteBenchmark.cs b/LeetCode.CSharp/Benchmarks/RansomNoteBenchmark.cs index 9a7bf5b..15b7200 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; - } -} \ No newline at end of file +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; + } +} diff --git a/LeetCode.CSharp/Benchmarks/ReverseBitsBenchmark.cs b/LeetCode.CSharp/Benchmarks/ReverseBitsBenchmark.cs index 6b42669..9c2fcb2 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); -} \ No newline at end of file +namespace LeetCode.CSharp.Benchmarks; + +public class ReverseBitsBenchmark : Benchmark +{ + [Benchmark] + public uint ReverseBits() => Problem.ReverseBits(0b00100010100101000001111010011100); +} 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..1e7f5b5 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"); -} \ No newline at end of file +namespace LeetCode.CSharp.Benchmarks; + +public class RomanToIntBenchmark : Benchmark +{ + [Benchmark] + [SuppressMessage("ReSharper", "StringLiteralTypo")] + public int RomanToInt() => Problem.RomanToInt("MMMCMXCIXCMXCIX"); +} 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..0be9d83 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 = []; -} \ No newline at end of file +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 = []; +} diff --git a/LeetCode.CSharp/Benchmarks/TopKFrequentBenchmark.cs b/LeetCode.CSharp/Benchmarks/TopKFrequentBenchmark.cs index 1f2a7d0..9575200 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 = []; -} \ No newline at end of file +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 = []; +} 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..a284153 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; - } -} \ No newline at end of file +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; + } +} diff --git a/LeetCode.CSharp/Benchmarks/UniquePathsBenchmark.cs b/LeetCode.CSharp/Benchmarks/UniquePathsBenchmark.cs index a4549c3..10fc069 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); -} \ No newline at end of file +namespace LeetCode.CSharp.Benchmarks; + +public class UniquePathsBenchmark : Benchmark +{ + [Benchmark] + public int UniquePaths() => Problem.UniquePaths(10_000, 100); +} diff --git a/LeetCode.CSharp/Benchmarks/ValidParenthesesBenchmark.cs b/LeetCode.CSharp/Benchmarks/ValidParenthesesBenchmark.cs index 9f6a160..9d505d2 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; - } -} \ No newline at end of file +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; + } +} diff --git a/LeetCode.CSharp/Category.cs b/LeetCode.CSharp/Category.cs index 92bc658..ef16553 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..841d2b6 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..0d9e963 100644 --- a/LeetCode.CSharp/Interval.cs +++ b/LeetCode.CSharp/Interval.cs @@ -1,4 +1,7 @@ -namespace LeetCode.CSharp; - -// ReSharper disable InconsistentNaming -public readonly record struct Interval(int start, int end); +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/LeetCode.CSharp.csproj b/LeetCode.CSharp/LeetCode.CSharp.csproj index 9bb829d..e23a2e5 100644 --- a/LeetCode.CSharp/LeetCode.CSharp.csproj +++ b/LeetCode.CSharp/LeetCode.CSharp.csproj @@ -1,29 +1,31 @@ - - - - false - LeetCode.CSharp - - - - - - - - - - - - - - - - - - - - - - - - + + + + false + false + LeetCode.CSharp + + Exe + true + + + + + + + + + + + + + + + + + + + + + + diff --git a/LeetCode.CSharp/LeetCodeAttribute.cs b/LeetCode.CSharp/LeetCodeAttribute.cs index 91b5898..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 -{ - /// 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( + string description, + Difficulty difficulty, + Category category, + string uri = "") : Attribute +{ + /// Challenge description + public string Description { get; } = description; + + /// LeetCode difficulty + public Difficulty Difficulty { get; } = difficulty; + + /// NeetCode category + public Category Category { get; } = category; + + /// Link to NeetCode video + 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 e5b8910..dfd4347 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..53e6b44 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..e268a57 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..539a423 100644 --- a/LeetCode.CSharp/Problems/EncodeDecode.cs +++ b/LeetCode.CSharp/Problems/EncodeDecode.cs @@ -1,62 +1,64 @@ -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); -} +using System.Globalization; + +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), CultureInfo.InvariantCulture); + + // 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..52f1053 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(System.Globalization.CultureInfo.InvariantCulture); + } + + 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..d34dcbb 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>(StringComparer.Ordinal); + + 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..36f484b 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 }, + [6, 9], + }; + var ex1NewInterval = new[] { 2, 5 }; + var ex1Expected = new[] + { + new[] { 1, 5 }, + [6, 9], + }; + + var ex2Intervals = new[] + { + new[] { 1, 2 }, + [3, 5], + [6, 7], + [8, 10], + [12, 16], + }; + var ex2NewInterval = new[] { 4, 8 }; + var ex2Expected = new[] + { + new[] { 1, 2 }, + [3, 10], + [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..d4fb24a 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(root: null).ShouldBeNull(); + } +} diff --git a/LeetCode.CSharp/Problems/IsAnagram.cs b/LeetCode.CSharp/Problems/IsAnagram.cs index d957103..9d2bf6f 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.Order().SequenceEqual(t.Order()); + + [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..63d14b2 100644 --- a/LeetCode.CSharp/Problems/IsPalindrone.cs +++ b/LeetCode.CSharp/Problems/IsPalindrone.cs @@ -1,51 +1,48 @@ -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; + +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..9b44ca5 100644 --- a/LeetCode.CSharp/Problems/IsSameTree.cs +++ b/LeetCode.CSharp/Problems/IsSameTree.cs @@ -1,47 +1,42 @@ -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 + return p.val == q.val && 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(p: null, q: null).ShouldBeTrue(); + } +} diff --git a/LeetCode.CSharp/Problems/IsSubtree.cs b/LeetCode.CSharp/Problems/IsSubtree.cs index 7cd98a0..3a7d2a7 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(root: null, subRoot: null).ShouldBeTrue(); + } +} diff --git a/LeetCode.CSharp/Problems/IsValidSudoku.cs b/LeetCode.CSharp/Problems/IsValidSudoku.cs index b5836fd..5f05c0d 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..b756570 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..8fa8ec2 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 + .Order() + .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..75c3a78 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 sealed 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..ccc5d2d 100644 --- a/LeetCode.CSharp/Problems/LowestCommonAncestor.cs +++ b/LeetCode.CSharp/Problems/LowestCommonAncestor.cs @@ -1,49 +1,52 @@ -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) + { + 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) + { + // 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..edda9fe 100644 --- a/LeetCode.CSharp/Problems/MaxDepth.cs +++ b/LeetCode.CSharp/Problems/MaxDepth.cs @@ -1,31 +1,23 @@ -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) => root is null ? 0 : 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(root: 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..14fb769 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.Max(account => account.Sum()); + + [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..bfdc47c 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(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 21d9baa..2da48b0 100644 --- a/LeetCode.CSharp/Problems/MiddleNode.cs +++ b/LeetCode.CSharp/Problems/MiddleNode.cs @@ -1,32 +1,29 @@ -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; + +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..5344961 100644 --- a/LeetCode.CSharp/Problems/NumIslands.cs +++ b/LeetCode.CSharp/Problems/NumIslands.cs @@ -1,121 +1,123 @@ -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")] + [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) + { + 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(grid: 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..4b14e72 100644 --- a/LeetCode.CSharp/Problems/ProductExceptSelf.cs +++ b/LeetCode.CSharp/Problems/ProductExceptSelf.cs @@ -1,47 +1,50 @@ -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..5ace2ed 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..72a6b37 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..88a582a 100644 --- a/LeetCode.CSharp/Problems/RomanToInt.cs +++ b/LeetCode.CSharp/Problems/RomanToInt.cs @@ -1,51 +1,49 @@ -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; + +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..b08c0a0 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..f46ed87 100644 --- a/LeetCode.CSharp/Problems/TopKFrequent.cs +++ b/LeetCode.CSharp/Problems/TopKFrequent.cs @@ -1,72 +1,67 @@ -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); - } -} +using System.Runtime.InteropServices; + +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) + { + // 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 + // 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..f8b594a 100644 --- a/LeetCode.CSharp/Problems/Trie.cs +++ b/LeetCode.CSharp/Problems/Trie.cs @@ -1,83 +1,80 @@ -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..11f79dc 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..ce7b3ac 100644 --- a/LeetCode.FSharp/LeetCode.FSharp.fsproj +++ b/LeetCode.FSharp/LeetCode.FSharp.fsproj @@ -1,35 +1,34 @@ - - - - false - false - false - LeetCode.FSharp - false - - - - - - - - - - - - - - - - - - - - - - - - - - - + + + + false + false + LeetCode.FSharp + + Exe + true + + + + + + + + + + + + + + + + + + + + + + + + + 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..fa10842 100644 --- a/LeetCode.slnx +++ b/LeetCode.slnx @@ -1,20 +1,22 @@ - - + + + + + - - + + + + + - - - - - - - - \ No newline at end of file + + + + diff --git a/LeetCode/BenchmarkRunner.cs b/LeetCode/BenchmarkRunner.cs index 3f22ade..895cb3d 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"); + } + + ConsoleWriter.MoveCursor(CursorDirection.Up); + + 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); + + ConsoleWriter.MoveCursor(CursorDirection.Down); + + 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.ToLowerInvariant() : Resources.Benchmark_Singular.ToLowerInvariant(); + message.AppendFormat(CultureInfo.CurrentCulture, Resources.BenchmarkRunner_SingleProblem_Markup, + language, benchmark, problem.Description); + if (!problem.HasSimilarNameAndDescription()) + { + message.AppendFormat(CultureInfo.CurrentCulture, 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(CultureInfo.CurrentCulture, + 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..eb2fbee 100644 --- a/LeetCode/Commands/BenchmarkSettings.cs +++ b/LeetCode/Commands/BenchmarkSettings.cs @@ -1,121 +1,112 @@ -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() => 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() + { + 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, StringComparer.Ordinal) + .ThenBy(t => t.Namespace, StringComparer.Ordinal)]; + } + + 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('*', StringComparison.Ordinal)) + { + // User added wildcard so use whatever was passed + args.Add(benchmark); + } + else if (benchmark.Contains('.', StringComparison.Ordinal)) + { + // 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(), StringComparer.Ordinal) + .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..4535023 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(); + + ConsoleWriter.MoveCursor(CursorDirection.Up); + + 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..1ff313e 100644 --- a/LeetCode/Commands/ProblemSettings.cs +++ b/LeetCode/Commands/ProblemSettings.cs @@ -1,24 +1,15 @@ -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 +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() => 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 f18b098..a851b76 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 BenchmarkNamespace = "LeetCode.XSharp.Benchmarks."; + var reports = Directory + .GetFiles(resultsDir, searchPattern, SearchOption.TopDirectoryOnly) + .OrderBy(report => report[BenchmarkNamespace.Length..], StringComparer.Ordinal) + .ToArray(); + if (reports.Length == 0) + { + throw new FileNotFoundException($"Reports not found '{searchPattern}'"); + } + + var firstReport = reports[0]; + 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", StringComparison.Ordinal) ? "C#" : "F#"; + benchmark["FullName"] = $"{benchmark["Method"]} in {language}"; + } +} diff --git a/LeetCode/ConsoleWriter.cs b/LeetCode/ConsoleWriter.cs index 3c1abaf..59463dc 100644 --- a/LeetCode/ConsoleWriter.cs +++ b/LeetCode/ConsoleWriter.cs @@ -1,41 +1,55 @@ -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(); + } + + /// + /// 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(); + + 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..6ed5d4d 100644 --- a/LeetCode/Extensions.cs +++ b/LeetCode/Extensions.cs @@ -1,67 +1,66 @@ -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; + +[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) + { + public string Description() => + $"Category_{category}".GetResource(); + } + + extension(Difficulty difficulty) + { + public string Markup() => + $"Difficulty_{difficulty}_Markup".GetResource(); + } + + extension(Problem problem) + { + 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, + }; + + table.AddColumn(new TableColumn("-").PadRight(3)); + table.AddColumn("-"); + + table.AddRow(Resources.Problem_Benchmark_Markup, problem.Name); + + if (!string.Equals(problem.Name, problem.Description, StringComparison.Ordinal)) + { + 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, CultureInfo.InvariantCulture) ?? + throw new InvalidOperationException($"Missing resource '{input}'"); + } + + [GeneratedRegex(@"\s+", RegexOptions.None, matchTimeoutMilliseconds: 1000)] + private static partial Regex MatchWhitespace { get; } +} diff --git a/LeetCode/LeetCode.csproj b/LeetCode/LeetCode.csproj index ee5e54b..b81cf06 100644 --- a/LeetCode/LeetCode.csproj +++ b/LeetCode/LeetCode.csproj @@ -1,71 +1,77 @@ - - - - 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 + en + Exe + + false + false + false + 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..2d6d8ed 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 (!string.Equals(selected.Name, Resources.Selection_Exit, StringComparison.Ordinal)) + { + 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..cf554e9 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); -} \ No newline at end of file +namespace LeetCode.Menus; + +internal abstract class MenuBase +{ + protected IEnumerable Choices { get; init; } = []; + + protected IEnumerable GetChoices() => Choices.OrderBy(m => m.Order); +} diff --git a/LeetCode/Menus/ProblemMenu.cs b/LeetCode/Menus/ProblemMenu.cs index b170bae..67b4325 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..b0bd59e 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; - } -} \ No newline at end of file +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; + } +} diff --git a/LeetCode/Menus/Selections/BenchmarkListSelection.cs b/LeetCode/Menus/Selections/BenchmarkListSelection.cs index 2129377..2eadc8b 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; - } -} \ No newline at end of file +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; + } +} diff --git a/LeetCode/Menus/Selections/BenchmarkSelection.cs b/LeetCode/Menus/Selections/BenchmarkSelection.cs index d529df1..1d8aab2 100644 --- a/LeetCode/Menus/Selections/BenchmarkSelection.cs +++ b/LeetCode/Menus/Selections/BenchmarkSelection.cs @@ -1,38 +1,35 @@ -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 +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; + } +} diff --git a/LeetCode/Menus/Selections/ExitSelection.cs b/LeetCode/Menus/Selections/ExitSelection.cs index ba74909..37fc670 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; - } -} \ No newline at end of file +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; + } +} diff --git a/LeetCode/Menus/Selections/ProblemListSelection.cs b/LeetCode/Menus/Selections/ProblemListSelection.cs index c3e21da..fbc3d7f 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(); -} \ No newline at end of file +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; + + ConsoleWriter.MoveCursor(CursorDirection.Up); + 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(); +} diff --git a/LeetCode/Menus/Selections/Selection.cs b/LeetCode/Menus/Selections/Selection.cs index d197cb4..c3b9a5a 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(); -} \ No newline at end of file +namespace LeetCode.Menus.Selections; + +internal abstract record Selection(string Name, int Order) +{ + /// + /// Execute a menu item when selected + /// + /// Status code + public abstract int Execute(); +} diff --git a/LeetCode/Problem.cs b/LeetCode/Problem.cs index ad96f09..747b87e 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; -} \ No newline at end of file +namespace LeetCode; + +internal sealed 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; +} diff --git a/LeetCode/Program.cs b/LeetCode/Program.cs index 047b1a3..6a2ca05 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, Xunit.TestContext.Current.CancellationToken).ConfigureAwait(false); diff --git a/LeetCode/Reflection.cs b/LeetCode/Reflection.cs index 0a14d2a..ebd0e6f 100644 --- a/LeetCode/Reflection.cs +++ b/LeetCode/Reflection.cs @@ -1,80 +1,77 @@ -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 => Attribute.IsDefined(m, typeof(LeetCodeAttribute))) + .Select(GetProblem) + .FirstOrDefault(p => + p.Name.Equals(name, StringComparison.OrdinalIgnoreCase) || + p.Description.Equals(name, StringComparison.OrdinalIgnoreCase)); + + problem = found ?? null!; + + return found is not null; + } + + private static Problem GetProblem(MemberInfo memberInfo) + { + var csharp = GetCSharpProblems().Contains(memberInfo.Name, StringComparer.Ordinal); + var fsharp = GetFSharpProblems().Contains(memberInfo.Name, StringComparer.Ordinal); + var attribute = memberInfo.GetCustomAttribute(); + + return attribute is null || (!csharp && !fsharp) + ? throw new InvalidOperationException($"Invalid member info '{memberInfo.Name}") + : 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 => Attribute.IsDefined(m, typeof(LeetCodeAttribute))) + .Select(GetProblem) + .OrderBy(p => p.Category) + .ThenBy(p => p.Difficulty) + .ThenBy(p => p.Description, StringComparer.Ordinal) + .GroupBy(p => p.Category, p => p); + + public static IEnumerable GetCSharpBenchmarks() => + GetCSharpBenchmarkTypes().Select(type => + type.Name.EndsWith("Benchmark", StringComparison.Ordinal) ? type.Name[..^9] : type.Name); + + public static IEnumerable GetFSharpBenchmarks() => + GetFSharpBenchmarkTypes().Select(type => + 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", StringComparison.Ordinal)); + + public static IEnumerable GetFSharpBenchmarkTypes() => + typeof(FSharp.ListNode).Assembly.GetTypes() + .Where(type => type.Namespace is not null && + type.Namespace.StartsWith("LeetCode.FSharp.Benchmarks", StringComparison.Ordinal)); + + private static IEnumerable GetCSharpProblems() => + typeof(CSharp.Problems.Problem) + .GetMembers() + .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", StringComparison.Ordinal)) + .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..f89463c 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, message: null); + } + + if (writeLine) + { + AnsiConsole.MarkupLineInterpolated(CultureInfo.CurrentCulture, $"{prefix}{text}"); + } + else + { + AnsiConsole.MarkupInterpolated(CultureInfo.CurrentCulture, $"{prefix}{text}"); + } + } +} diff --git a/LeetCode/SpectreReportBuilder.cs b/LeetCode/SpectreReportBuilder.cs index 88bbe51..af78ec8 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, StringComparer.Ordinal) + .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, StringComparer.Ordinal) + .Union(summaryHeaders, StringComparer.Ordinal) + .Distinct(StringComparer.Ordinal) + .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.", StringComparison.Ordinal); + 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/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" } } 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