diff --git a/.github/pull_request_template.md b/.github/pull_request_template.md index 86a64e158..fac8e2e97 100644 --- a/.github/pull_request_template.md +++ b/.github/pull_request_template.md @@ -1,15 +1,15 @@ -[//]: # "Pull Request Template" -[//]: # "Replace the placeholder values in the template below" +[//]: # 'Pull Request Template' +[//]: # 'Replace the placeholder values in the template below' - **File(s) Modified**: _0001-two-sum.py, 0002-add-two-numbers.py, etc..._ - **Language(s) Used**: _python, javascript, etc..._ - **Submission URL**: _https://leetcode.com/problems/[problem-name]/submissions/xxxxxxxxx/_ -[//]: # "Getting the Submission URL" -[//]: # "Go to the leetcode [`Submissions tab`](https://user-images.githubusercontent.com/71089234/180188604-b1ecaf90-bf27-4fd6-a559-5567aebf8930.png)" -[//]: # "and [click on the `Accepted` status of your submission.](https://user-images.githubusercontent.com/71089234/180189321-1a48c33f-aa65-4b29-8aaa-685f4f5f8c9e.png)]" -[//]: # "Finally copy the URL from the nav bar, it should look like https://leetcode.com/problems/[problem-name]/submissions/xxxxxxxxx/" - +[//]: # 'Getting the Submission URL' +[//]: # 'Go to the leetcode [`Submissions tab`](https://user-images.githubusercontent.com/71089234/180188604-b1ecaf90-bf27-4fd6-a559-5567aebf8930.png)' +[//]: # 'and [click on the `Accepted` status of your submission.](https://user-images.githubusercontent.com/71089234/180189321-1a48c33f-aa65-4b29-8aaa-685f4f5f8c9e.png)]' +[//]: # 'Finally copy the URL from the nav bar, it should look like https://leetcode.com/problems/[problem-name]/submissions/xxxxxxxxx/' ### Important + Please make sure the file name is lowercase and a duplicate file does not already exist before merging. diff --git a/.github/workflows/build-readme.yml b/.github/workflows/build-readme.yml index fcd5b875e..60ac82c25 100644 --- a/.github/workflows/build-readme.yml +++ b/.github/workflows/build-readme.yml @@ -1,40 +1,42 @@ name: Build readme file on: - #push: - workflow_dispatch: - schedule: - - cron: '0 * * * *' + workflow_dispatch: + schedule: + - cron: '0 * * * *' # Every hour jobs: - Build: - runs-on: ubuntu-latest - - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.head_ref }} - fetch-depth: 1 - - - name: Use Node.js (dependency) - uses: actions/setup-node@v3 - with: - node-version: 16 - - - name: Completion Table - run: node updateCompletionTable.js; - - - name: Check for modified files - id: git-check - run: echo modified=$(if git diff-index --quiet HEAD --; then echo "false"; else echo "true"; fi) >> $GITHUB_OUTPUT - - - name: Push - if: steps.git-check.outputs.modified == 'true' - run: | - git config --global user.email "71089234+Ahmad-A0@users.noreply.github.com" - git config --global user.name "Bot-A0" - git add . - git commit -am "📜 Update README table (🛠️ from Github Actions)" || true - git push || git pull --rebase && git push - - + Build: + runs-on: ubuntu-latest + + strategy: + matrix: + node-version: [20.x] + + steps: + - name: Checkout Repository + uses: actions/checkout@v4 + with: + ref: ${{ github.head_ref }} + fetch-depth: 1 + + - name: Use Node.js (dependency) + uses: actions/setup-node@v4 + with: + node-version: ${{ matrix.node-version }} + + - name: Completion Table + run: node updateCompletionTable.js; + + - name: Check for modified files + id: git-check + run: echo modified=$(if git diff-index --quiet HEAD --; then echo "false"; else echo "true"; fi) >> $GITHUB_OUTPUT + + - name: Push + if: steps.git-check.outputs.modified == 'true' + run: | + git config --global user.email "71089234+Ahmad-A0@users.noreply.github.com" + git config --global user.name "Bot-A0" + git add . + git commit -am "📜 Update README table (🛠️ from Github Actions)" || true + git push || git pull --rebase && git push \ No newline at end of file diff --git a/.github/workflows/format.yml b/.github/workflows/format.yml deleted file mode 100644 index f2847ab45..000000000 --- a/.github/workflows/format.yml +++ /dev/null @@ -1,65 +0,0 @@ -name: Format Files - -# cpp -# csharp - https://github.com/dotnet/format ? -# java - prettier-plugin-java -# javascript - prettier -# python - black -# ruby - rufo -# swift - https://github.com/apple/swift-format ? -# typescript - prettier - -on: - # pull_request_target: - # types: [opened, synchronize] - workflow_dispatch: - -jobs: - Format: - runs-on: ubuntu-latest - - strategy: - matrix: - node-version: [16.x] - - steps: - - uses: actions/checkout@v3 - with: - ref: ${{ github.head_ref }} - fetch-depth: 1 - - - name: Use Node.js (dependency) - uses: actions/setup-node@v1 - with: - node-version: ${{ matrix.node-version }} - - - name: Install Rufo (dependency) - run: | - sudo apt update - sudo gem install rufo - - - name: Install Prettier - run: | - npm install -g prettier - npm install -g prettier-plugin-java - - - name: Install Black - uses: BSFishy/pip-action@v1 - with: - packages: black - - - name: Format - run: | - prettier --config "$GITHUB_WORKSPACE/.prettierrc" --write "$GITHUB_WORKSPACE/javascript/*.js" 2>&1 || true - prettier --config "$GITHUB_WORKSPACE/.prettierrc" --write "$GITHUB_WORKSPACE/typescript/*.ts" 2>&1 || true - prettier --config "$GITHUB_WORKSPACE/.prettierrc" --write "$GITHUB_WORKSPACE/java/*.java" 2>&1 || true - rufo "$GITHUB_WORKSPACE/ruby" 2>&1 || true - python -m black "$GITHUB_WORKSPACE/" 2>&1 || true - - - name: Push - run: | - git config --global user.email "71089234+Ahmad-A0@users.noreply.github.com" - git config --global user.name "Bot-A0" - git add . - git commit -m "🎨 Format files (🛠️ from Github Actions)" || true - git push || true diff --git a/.gitignore b/.gitignore index 146f8c207..f4b05d997 100644 --- a/.gitignore +++ b/.gitignore @@ -1,3 +1,5 @@ .DS_Store .metals -.vscode \ No newline at end of file +.vscode +.idea +node_modules \ No newline at end of file diff --git a/.problemSiteData.json b/.problemSiteData.json index 5699c6b13..402862497 100644 --- a/.problemSiteData.json +++ b/.problemSiteData.json @@ -1,6779 +1,6779 @@ [ - { - "neetcode150":true, - "blind75":true, - "problem":"Contains Duplicate", - "pattern":"Arrays & Hashing", - "link":"contains-duplicate/", - "video":"3OamzN90kPg", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0217-contains-duplicate", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "scala":true, - "dart":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Valid Anagram", - "pattern":"Arrays & Hashing", - "link":"valid-anagram/", - "video":"9UtInBqnCgA", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0242-valid-anagram", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "scala":true, - "dart":true - }, - { - "problem":"Concatenation of Array", - "pattern":"Arrays & Hashing", - "link":"concatenation-of-array/", - "video":"68isPRHgcFQ", - "difficulty":"Easy", - "code":"1929-concatenation-of-array", - "python":true, - "cpp":true, - "java":true, - "javascript":true, - "kotlin":true, - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "rust":true, - "scala":true, - "dart":true - }, - { - "problem":"Replace Elements With Greatest Element On Right Side", - "pattern":"Arrays & Hashing", - "link":"replace-elements-with-greatest-element-on-right-side/", - "video":"ZHjKhUjcsaU", - "difficulty":"Easy", - "code":"1299-replace-elements-with-greatest-element-on-right-side", - "c":true, - "cpp":true, - "csharp":true, - "java":true, - "python":true, - "javascript":true, - "typescript":true, - "go":true, - "rust":true, - "dart":true, - "kotlin":true, - "swift":true - }, - { - "problem":"Is Subsequence", - "pattern":"Arrays & Hashing", - "link":"is-subsequence/", - "video":"99RVfqklbCE", - "difficulty":"Easy", - "code":"0392-is-subsequence", - "c":true, - "cpp":true, - "csharp":true, - "java":true, - "python":true, - "javascript":true, - "typescript":true, - "go":true, - "rust":true, - "dart":true, - "kotlin":true, - "swift":true - }, - { - "problem":"Length of Last Word", - "pattern":"Arrays & Hashing", - "link":"length-of-last-word/", - "video":"KT9rltZTybQ", - "difficulty":"Easy", - "code":"0058-length-of-last-word", - "c":true, - "cpp":true, - "csharp":true, - "java":true, - "python":true, - "javascript":true, - "typescript":true, - "rust":true, - "go":true, - "swift":true, - "dart":true, - "ruby":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Two Sum", - "pattern":"Arrays & Hashing", - "link":"two-sum/", - "video":"KLlXCFG5TnA", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0001-two-sum", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "scala":true, - "dart":true - }, - { - "problem":"Longest Common Prefix", - "pattern":"Arrays & Hashing", - "link":"longest-common-prefix/", - "video":"0sWShKIJoo4", - "difficulty":"Easy", - "code":"0014-longest-common-prefix", - "cpp":true, - "python":true, - "javascript":true, - "c":true, - "csharp":true, - "java":true, - "typescript":true, - "go":true, - "rust":true, - "dart":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Group Anagrams", - "pattern":"Arrays & Hashing", - "link":"group-anagrams/", - "video":"vzdNOK2oB2E", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0049-group-anagrams", - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "dart":true, - "c":true, - "scala":true - }, - { - "problem":"Pascals Triangle", - "pattern":"Arrays & Hashing", - "link":"pascals-triangle/", - "video":"nPVEaB3AjUM", - "difficulty":"Easy", - "code":"0118-pascals-triangle", - "c":true, - "cpp":true, - "java":true, - "python":true, - "javascript":true, - "typescript":true, - "rust":true, - "csharp":true, - "go":true, - "dart":true, - "kotlin":true - }, - { - "problem":"Remove Element", - "pattern":"Arrays & Hashing", - "link":"remove-element/", - "video":"Pcd1ii9P9ZI", - "difficulty":"Easy", - "code":"0027-remove-element", - "c":true, - "java":true, - "python":true, - "javascript":true, - "typescript":true, - "go":true, - "cpp":true, - "csharp":true, - "swift":true, - "rust":true, - "dart":true, - "kotlin":true - }, - { - "problem":"Unique Email Addresses", - "pattern":"Arrays & Hashing", - "link":"unique-email-addresses/", - "video":"TC_xLIWl7qY", - "difficulty":"Easy", - "code":"0929-unique-email-addresses", - "java":true, - "python":true, - "javascript":true, - "typescript":true, - "swift":true, - "cpp":true, - "csharp":true, - "go":true, - "rust":true, - "c":true, - "kotlin":true - }, - { - "problem":"Isomorphic Strings", - "pattern":"Arrays & Hashing", - "link":"isomorphic-strings/", - "video":"7yF-U1hLEqQ", - "difficulty":"Easy", - "code":"0205-isomorphic-strings", - "c":true, - "java":true, - "python":true, - "javascript":true, - "typescript":true, - "swift":true, - "cpp":true, - "csharp":true, - "go":true, - "rust":true, - "kotlin":true - }, - { - "problem":"Can Place Flowers", - "pattern":"Arrays & Hashing", - "link":"can-place-flowers/", - "video":"ZGxqqjljpUI", - "difficulty":"Easy", - "code":"0605-can-place-flowers", - "c":true, - "cpp":true, - "python":true, - "javascript":true, - "typescript":true, - "csharp":true, - "go":true, - "rust":true, - "java":true, - "kotlin":true, - "swift":true - }, - { - "problem":"Majority Element", - "pattern":"Arrays & Hashing", - "link":"majority-element/", - "video":"7pnhv842keE", - "difficulty":"Easy", - "code":"0169-majority-element", - "c":true, - "cpp":true, - "python":true, - "javascript":true, - "typescript":true, - "swift":true, - "csharp":true, - "java":true, - "go":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Next Greater Element I", - "pattern":"Arrays & Hashing", - "link":"next-greater-element-i/", - "video":"68a1Dc_qVq4", - "difficulty":"Easy", - "code":"0496-next-greater-element-i", - "java":true, - "python":true, - "typescript":true, - "c":true, - "cpp":true, - "csharp":true, - "javascript":true, - "go":true, - "rust":true, - "kotlin":true - }, - { - "problem":"Find Pivot Index", - "pattern":"Arrays & Hashing", - "link":"find-pivot-index/", - "video":"u89i60lYx8U", - "difficulty":"Easy", - "code":"0724-find-pivot-index", - "c":true, - "cpp":true, - "java":true, - "python":true, - "javascript":true, - "typescript":true, - "go":true, - "rust":true, - "csharp":true, - "kotlin":true, - "swift":true - }, - { - "problem":"Range Sum Query - Immutable", - "pattern":"Arrays & Hashing", - "link":"range-sum-query-immutable/", - "video":"2pndAmo_sMA", - "difficulty":"Easy", - "code":"0303-range-sum-query-immutable", - "python":true, - "c":true, - "cpp":true, - "java":true, - "kotlin":true, - "csharp":true, - "javascript":true, - "rust":true - }, - { - "problem":"Find All Numbers Disappeared in An Array", - "pattern":"Arrays & Hashing", - "link":"find-all-numbers-disappeared-in-an-array/", - "video":"8i-f24YFWC4", - "difficulty":"Easy", - "code":"0448-find-all-numbers-disappeared-in-an-array", - "cpp":true, - "java":true, - "python":true, - "javascript":true, - "c":true, - "typescript":true, - "go":true, - "rust":true, - "csharp":true, - "kotlin":true - }, - { - "problem":"Maximum Number of Balloons", - "pattern":"Arrays & Hashing", - "link":"maximum-number-of-balloons/", - "video":"G9xeB2-7PqY", - "difficulty":"Easy", - "code":"1189-maximum-number-of-balloons", - "c":true, - "java":true, - "python":true, - "javascript":true, - "cpp":true, - "typescript":true, - "go":true, - "rust":true, - "csharp":true, - "kotlin":true - }, - { - "problem":"Word Pattern", - "pattern":"Arrays & Hashing", - "link":"word-pattern/", - "video":"W_akoecmCbM", - "difficulty":"Easy", - "code":"0290-word-pattern", - "java":true, - "python":true, - "javascript":true, - "typescript":true, - "c":true, - "cpp":true, - "go":true, - "rust":true, - "csharp":true, - "kotlin":true - }, - { - "problem":"Design HashSet", - "pattern":"Arrays & Hashing", - "link":"design-hashset/", - "video":"VymjPQUXjL8", - "difficulty":"Easy", - "code":"0705-design-hashset", - "kotlin":true, - "c":true, - "cpp":true, - "java":true, - "python":true, - "javascript":true, - "rust":true - }, - { - "problem":"Design HashMap", - "pattern":"Arrays & Hashing", - "link":"design-hashmap/", - "video":"cNWsgbKwwoU", - "difficulty":"Easy", - "code":"0706-design-hashmap", - "python":true, - "c":true, - "cpp":true, - "java":true, - "javascript":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Sort an Array", - "pattern":"Arrays & Hashing", - "link":"sort-an-array/", - "video":"MsYZSinhuFo", - "difficulty":"Medium", - "code":"0912-sort-an-array", - "python":true, - "java":true, - "kotlin":true, - "cpp":true, - "csharp":true, - "javascript":true, - "go":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Top K Frequent Elements", - "pattern":"Arrays & Hashing", - "link":"top-k-frequent-elements/", - "video":"YPTqKIgVk-k", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0347-top-k-frequent-elements", - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "c":true, - "scala":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Product of Array Except Self", - "pattern":"Arrays & Hashing", - "link":"product-of-array-except-self/", - "video":"bNvIQI2wAjk", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0238-product-of-array-except-self", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Valid Sudoku", - "pattern":"Arrays & Hashing", - "link":"valid-sudoku/", - "video":"TjFXEUCMqI8", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0036-valid-sudoku", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "kotlin":true, - "rust":true, - "dart":true, - "scala":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Encode and Decode Strings", - "premium":true, - "freeLink":"https://www.lintcode.com/problem/659/", - "pattern":"Arrays & Hashing", - "link":"encode-and-decode-strings/", - "video":"B1k_sxOSgv8", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0271-encode-and-decode-strings", - "csharp":true, - "go":true, - "ruby":true, - "swift":true, - "rust":true, - "typescript":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Longest Consecutive Sequence", - "pattern":"Arrays & Hashing", - "link":"longest-consecutive-sequence/", - "video":"P6RZZMu_maU", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0128-longest-consecutive-sequence", - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "c":true - }, - { - "problem":"Sort Colors", - "pattern":"Arrays & Hashing", - "link":"sort-colors/", - "video":"4xbWSRZHqac", - "difficulty":"Medium", - "code":"0075-sort-colors", - "c":true, - "java":true, - "javascript":true, - "go":true, - "kotlin":true, - "cpp":true, - "python":true, - "typescript":true, - "csharp":true, - "rust":true, - "swift":true - }, - { - "problem":"Encode and Decode TinyURL", - "pattern":"Arrays & Hashing", - "link":"encode-and-decode-tinyurl/", - "video":"VyBOaboQLGc", - "difficulty":"Medium", - "code":"0535-encode-and-decode-tinyurl", - "javascript":true, - "cpp":true, - "python":true, - "typescript":true, - "go":true, - "rust":true, - "swift":true, - "kotlin":true, - "c":true, - "java":true - }, - { - "problem":"Brick Wall", - "pattern":"Arrays & Hashing", - "link":"brick-wall/", - "video":"Kkmv2h48ekw", - "difficulty":"Medium", - "code":"0554-brick-wall", - "javascript":true, - "typescript":true, - "c":true, - "cpp":true, - "java":true, - "python":true, - "rust":true, - "kotlin":true - }, - { - "problem":"Best Time to Buy And Sell Stock II", - "pattern":"Arrays & Hashing", - "link":"best-time-to-buy-and-sell-stock-ii/", - "video":"3SJ3pUkPQMc", - "difficulty":"Medium", - "code":"0122-best-time-to-buy-and-sell-stock-ii", - "c":true, - "javascript":true, - "go":true, - "cpp":true, - "java":true, - "python":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Subarray Sum Equals K", - "pattern":"Arrays & Hashing", - "link":"subarray-sum-equals-k/", - "video":"fFVZt-6sgyo", - "difficulty":"Medium", - "code":"0560-subarray-sum-equals-k", - "java":true, - "cpp":true, - "go":true, - "c":true, - "python":true, - "javascript":true, - "typescript":true, - "kotlin":true, - "rust":true, - "csharp":true - }, - { - "problem":"Unique Length 3 Palindromic Subsequences", - "pattern":"Arrays & Hashing", - "link":"unique-length-3-palindromic-subsequences/", - "video":"3THUt0vAFLU", - "difficulty":"Medium", - "code":"1930-unique-length-3-palindromic-subsequences", - "cpp":true, - "java":true, - "kotlin":true, - "c":true, - "python":true, - "javascript":true, - "typescript":true, - "rust":true - }, - { - "problem":"Minimum Number of Swaps to Make The String Balanced", - "pattern":"Arrays & Hashing", - "link":"minimum-number-of-swaps-to-make-the-string-balanced/", - "video":"3YDBT9ZrfaU", - "difficulty":"Medium", - "code":"1963-minimum-number-of-swaps-to-make-the-string-balanced", - "javascript":true, - "cpp":true, - "c":true, - "python":true, - "kotlin":true, - "java":true, - "rust":true - }, - { - "problem":"Number of Pairs of Interchangeable Rectangles", - "pattern":"Arrays & Hashing", - "link":"number-of-pairs-of-interchangeable-rectangles/", - "video":"lEQ8ZlLOuyQ", - "difficulty":"Medium", - "code":"2001-number-of-pairs-of-interchangeable-rectangles", - "javascript":true, - "cpp":true, - "python":true, - "c":true, - "java":true, - "rust":true, - "kotlin":true - }, - { - "problem":"Maximum Product of The Length of Two Palindromic Subsequences", - "pattern":"Arrays & Hashing", - "link":"maximum-product-of-the-length-of-two-palindromic-subsequences/", - "video":"aoHbYlO8vDg", - "difficulty":"Medium", - "code":"2002-maximum-product-of-the-length-of-two-palindromic-subsequences", - "cpp":true, - "c":true, - "csharp":true, - "java":true, - "python":true, - "javascript":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Grid Game", - "pattern":"Arrays & Hashing", - "link":"grid-game/", - "video":"N4wDSOw65hI", - "difficulty":"Medium", - "code":"2017-grid-game", - "python":true, - "cpp":true, - "kotlin":true, - "java":true, - "javascript":true, - "rust":true - }, - { - "problem":"Find All Anagrams in a String", - "pattern":"Arrays & Hashing", - "link":"find-all-anagrams-in-a-string/", - "video":"G8xtZy0fDKg", - "difficulty":"Medium", - "code":"0438-find-all-anagrams-in-a-string", - "cpp":true, - "csharp":true, - "python":true, - "java":true, - "javascript":true, - "go":true, - "kotlin":true, - "c":true - }, - { - "problem":"Find The Index of The First Occurrence in a String", - "pattern":"Arrays & Hashing", - "link":"find-the-index-of-the-first-occurrence-in-a-string/", - "video":"JoF0Z7nVSrA", - "difficulty":"Easy", - "code":"0028-find-the-index-of-the-first-occurrence-in-a-string", - "python":true, - "cpp":true, - "go":true, - "c":true, - "java":true, - "kotlin":true, - "csharp":true, - "javascript":true - }, - { - "problem":"Wiggle Sort", - "pattern":"Arrays & Hashing", - "premium":true, - "freeLink":"https://www.lintcode.com/problem/508/", - "link":"wiggle-sort/", - "video":"vGsyTE4s34w", - "difficulty":"Medium", - "code":"0280-wiggle-sort", - "cpp":true, - "python":true, - "kotlin":true - }, - { - "problem":"Largest Number", - "pattern":"Arrays & Hashing", - "link":"largest-number/", - "video":"WDx6Y4i4xJ8", - "difficulty":"Medium", - "code":"0179-largest-number", - "typescript":true, - "cpp":true, - "java":true, - "kotlin":true, - "c":true, - "csharp":true, - "python":true, - "javascript":true, - "go":true, - "ruby":true, - "swift":true, - "rust":true, - "scala":true - }, - { - "problem":"Continuous Subarray Sum", - "pattern":"Arrays & Hashing", - "link":"continuous-subarray-sum/", - "video":"OKcrLfR-8mE", - "difficulty":"Medium", - "code":"0523-continuous-subarray-sum", - "java":true, - "python":true, - "cpp":true, - "kotlin":true, - "c":true, - "javascript":true, - "rust":true - }, - { - "problem":"Push Dominoes", - "pattern":"Arrays & Hashing", - "link":"push-dominoes/", - "video":"evUFsOb_iLY", - "difficulty":"Medium", - "code":"0838-push-dominoes", - "typescript":true, - "cpp":true, - "python":true, - "kotlin":true, - "java":true - }, - { - "problem":"Repeated DNA Sequences", - "pattern":"Arrays & Hashing", - "link":"repeated-dna-sequences/", - "video":"FzTYfsmtOso", - "difficulty":"Medium", - "code":"0187-repeated-dna-sequences", - "java":true, - "typescript":true, - "cpp":true, - "kotlin":true, - "python":true, - "javascript":true - }, - { - "problem":"Insert Delete Get Random O(1)", - "pattern":"Arrays & Hashing", - "link":"insert-delete-getrandom-o1/", - "video":"j4KwhBziOpg", - "difficulty":"Medium", - "code":"0380-insert-delete-getrandom-o1", - "java":true, - "typescript":true, - "javascript":true, - "go":true, - "cpp":true, - "swift":true, - "kotlin":true, - "python":true - }, - { - "problem":"Check if a String Contains all Binary Codes of Size K", - "pattern":"Arrays & Hashing", - "link":"check-if-a-string-contains-all-binary-codes-of-size-k/", - "video":"qU32rTy_kOM", - "difficulty":"Medium", - "code":"1461-check-if-a-string-contains-all-binary-codes-of-size-k", - "cpp":true, - "kotlin":true, - "python":true, - "javascript":true - }, - { - "problem":"Range Sum Query 2D Immutable", - "pattern":"Arrays & Hashing", - "link":"range-sum-query-2d-immutable/", - "video":"KE8MQuwE2yA", - "difficulty":"Medium", - "code":"0304-range-sum-query-2d-immutable", - "cpp":true, - "python":true, - "kotlin":true, - "javascript":true - }, - { - "problem":"Non Decreasing Array", - "pattern":"Arrays & Hashing", - "link":"non-decreasing-array/", - "video":"RegQckCegDk", - "difficulty":"Medium", - "code":"0665-non-decreasing-array", - "cpp":true, - "java":true, - "javascript":true, - "typescript":true, - "go":true, - "scala":true, - "kotlin":true, - "python":true, - "csharp":true - }, - { - "problem":"First Missing Positive", - "pattern":"Arrays & Hashing", - "link":"first-missing-positive/", - "video":"8g78yfzMlao", - "difficulty":"Hard", - "code":"0041-first-missing-positive", - "python":true, - "typescript":true, - "cpp":true, - "java":true, - "go":true, - "kotlin":true, - "c":true, - "javascript":true - }, - { - "problem":"Sign of An Array", - "pattern":"Arrays & Hashing", - "link":"sign-of-the-product-of-an-array/", - "video":"ILDLM86jNow", - "difficulty":"Easy", - "code":"1822-sign-of-the-product-of-an-array", - "cpp":true, - "java":true, - "python":true, - "javascript":true, - "typescript":true, - "go":true, - "kotlin":true - }, - { - "problem":"Find the Difference of Two Arrays", - "pattern":"Arrays & Hashing", - "link":"find-the-difference-of-two-arrays/", - "video":"a4wqKR-znBE", - "difficulty":"Easy", - "code":"2215-find-the-difference-of-two-arrays", - "kotlin":true, - "cpp":true, - "csharp":true, - "java":true, - "python":true, - "javascript":true, - "typescript":true - }, - { - "problem":"Design Parking System", - "pattern":"Arrays & Hashing", - "link":"design-parking-system/", - "video":"d5zCHesOrSk", - "difficulty":"Easy", - "code":"1603-design-parking-system", - "kotlin":true, - "java":true, - "python":true, - "javascript":true - }, - { - "problem":"Number of Zero-Filled Subarrays", - "pattern":"Arrays & Hashing", - "link":"number-of-zero-filled-subarrays/", - "video":"G-EWVGCcL_w", - "difficulty":"Medium", - "code":"2348-number-of-zero-filled-subarrays", - "kotlin":true, - "cpp":true, - "java":true, - "python":true - }, - { - "problem":"Optimal Partition of String", - "pattern":"Arrays & Hashing", - "link":"optimal-partition-of-string/", - "video":"CKZPdiXiQf0", - "difficulty":"Medium", - "code":"2405-optimal-partition-of-string", - "kotlin":true, - "java":true - }, - { - "problem":"Design Underground System", - "pattern":"Arrays & Hashing", - "link":"design-underground-system/", - "video":"W5QOLqXskZM", - "difficulty":"Medium", - "code":"1396-design-underground-system", - "kotlin":true, - "java":true, - "javascript":true - }, - { - "problem":"Minimum Penalty for a Shop", - "pattern":"Arrays & Hashing", - "link":"minimum-penalty-for-a-shop/", - "video":"0d7ShRoOFVE", - "difficulty":"Medium", - "code":"2483-minimum-penalty-for-a-shop", - "cpp":true, - "java":true, - "kotlin":true - }, - { - "problem":"Text Justification", - "pattern":"Arrays & Hashing", - "link":"text-justification/", - "video":"TzMl4Z7pVh8", - "difficulty":"Hard", - "code":"0068-naming-a-company", - "python":true, - "kotlin":true - }, - { - "problem":"Naming a Company", - "pattern":"Arrays & Hashing", - "link":"naming-a-company/", - "video":"NrHpgTScOcY", - "difficulty":"Hard", - "code":"2306-naming-a-company", - "kotlin":true, - "java":true, - "javascript":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Valid Palindrome", - "pattern":"Two Pointers", - "link":"valid-palindrome/", - "video":"jJXJ16kPFWg", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0125-valid-palindrome", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "dart":true, - "scala":true - }, - { - "problem":"Valid Palindrome II", - "pattern":"Two Pointers", - "link":"valid-palindrome-ii/", - "video":"JrxRYBwG6EI", - "difficulty":"Easy", - "code":"0680-valid-palindrome-ii", - "python":true, - "cpp":true, - "csharp":true, - "java":true, - "javascript":true, - "typescript":true, - "go":true, - "rust":true, - "c":true, - "kotlin":true - }, - { - "problem":"Minimum Difference Between Highest And Lowest of K Scores", - "pattern":"Two Pointers", - "link":"minimum-difference-between-highest-and-lowest-of-k-scores/", - "video":"JU5XdBZZtlk", - "difficulty":"Easy", - "code":"1984-minimum-difference-between-highest-and-lowest-of-k-scores", - "javascript":true, - "cpp":true, - "python":true, - "typescript":true, - "go":true, - "rust":true, - "java":true, - "kotlin":true - }, - { - "problem":"Merge Strings Alternately", - "pattern":"Two Pointers", - "link":"merge-strings-alternately/", - "video":"LECWOvTo-Sc", - "difficulty":"Easy", - "code":"1768-merge-strings-alternately", - "kotlin":true, - "cpp":true, - "java":true, - "python":true, - "javascript":true, - "typescript":true - }, - { - "problem":"Reverse String", - "pattern":"Two Pointers", - "link":"reverse-string/", - "video":"_d0T_2Lk2qA", - "difficulty":"Easy", - "code":"0344-reverse-string", - "c":true, - "python":true, - "javascript":true, - "typescript":true, - "swift":true, - "cpp":true, - "java":true, - "go":true, - "rust":true, - "kotlin":true, - "dart":true - }, - { - "problem":"Merge Sorted Array", - "pattern":"Two Pointers", - "link":"merge-sorted-array/", - "video":"P1Ic85RarKY", - "difficulty":"Easy", - "code":"0088-merge-sorted-array", - "c":true, - "java":true, - "javascript":true, - "cpp":true, - "python":true, - "typescript":true, - "go":true, - "rust":true, - "kotlin":true - }, - { - "problem":"Move Zeroes", - "pattern":"Two Pointers", - "link":"move-zeroes/", - "video":"aayNRwUN3Do", - "difficulty":"Easy", - "code":"0283-move-zeroes", - "c":true, - "cpp":true, - "javascript":true, - "csharp":true, - "python":true, - "typescript":true, - "go":true, - "swift":true, - "rust":true, - "java":true, - "kotlin":true - }, - { - "problem":"Remove Duplicates From Sorted Array", - "pattern":"Two Pointers", - "link":"remove-duplicates-from-sorted-array/", - "video":"DEJAZBq0FDA", - "difficulty":"Easy", - "code":"0026-remove-duplicates-from-sorted-array", - "python":true, - "javascript":true, - "go":true, - "cpp":true, - "typescript":true, - "swift":true, - "rust":true, - "java":true, - "kotlin":true, - "c":true - }, - { - "problem":"Remove Duplicates From Sorted Array II", - "pattern":"Two Pointers", - "link":"remove-duplicates-from-sorted-array-ii/", - "video":"ycAq8iqh0TI", - "difficulty":"Medium", - "code":"0080-remove-duplicates-from-sorted-array-ii", - "python":true, - "kotlin":true, - "cpp":true, - "csharp":true, - "javascript":true, - "swift":true - }, - { - "neetcode150":true, - "problem":"Two Sum II Input Array Is Sorted", - "pattern":"Two Pointers", - "link":"two-sum-ii-input-array-is-sorted/", - "video":"cQ1Oz4ckceM", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0167-two-sum-ii-input-array-is-sorted", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "scala":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"3Sum", - "pattern":"Two Pointers", - "link":"3sum/", - "video":"jzZsG8n2R9A", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0015-3sum", - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "scala":true, - "c":true - }, - { - "problem":"4Sum", - "pattern":"Two Pointers", - "link":"4sum/", - "video":"EYeR-_1NRlQ", - "difficulty":"Medium", - "code":"0018-4sum", - "python":true, - "javascript":true, - "typescript":true, - "go":true, - "cpp":true, - "kotlin":true, - "java":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Container With Most Water", - "pattern":"Two Pointers", - "link":"container-with-most-water/", - "video":"UuiTKBwPgAo", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0011-container-with-most-water", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "scala":true, - "dart":true - }, - { - "problem":"Number of Subsequences That Satisfy The Given Sum Condition", - "pattern":"Two Pointers", - "link":"number-of-subsequences-that-satisfy-the-given-sum-condition/", - "video":"xCsIkPLS4Ls", - "difficulty":"Medium", - "code":"1498-number-of-subsequences-that-satisfy-the-given-sum-condition", - "cpp":true, - "python":true, - "kotlin":true - }, - { - "problem":"Rotate Array", - "pattern":"Two Pointers", - "link":"rotate-array/", - "video":"BHr381Guz3Y", - "difficulty":"Medium", - "code":"0189-rotate-array", - "cpp":true, - "java":true, - "python":true, - "typescript":true, - "go":true, - "kotlin":true, - "javascript":true - }, - { - "problem":"Array With Elements Not Equal to Average of Neighbors", - "pattern":"Two Pointers", - "link":"array-with-elements-not-equal-to-average-of-neighbors/", - "video":"Wmb3YdVYfqM", - "difficulty":"Medium", - "code":"1968-array-with-elements-not-equal-to-average-of-neighbors", - "c":true, - "cpp":true, - "kotlin":true, - "python":true, - "javascript":true - }, - { - "problem":"Boats to Save People", - "pattern":"Two Pointers", - "link":"boats-to-save-people/", - "video":"XbaxWuHIWUs", - "difficulty":"Medium", - "code":"0881-boats-to-save-people", - "c":true, - "cpp":true, - "typescript":true, - "javascript":true, - "python":true, - "kotlin":true, - "java":true, - "swift":true - }, - { - "neetcode150":true, - "problem":"Trapping Rain Water", - "pattern":"Two Pointers", - "link":"trapping-rain-water/", - "video":"ZI2z5pq0TqA", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0042-trapping-rain-water", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Best Time to Buy And Sell Stock", - "pattern":"Sliding Window", - "link":"best-time-to-buy-and-sell-stock/", - "video":"1pkOgXD63yU", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0121-best-time-to-buy-and-sell-stock", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "scala":true - }, - { - "problem":"Contains Duplicate II", - "pattern":"Sliding Window", - "link":"contains-duplicate-ii/", - "video":"ypn0aZ0nrL4", - "difficulty":"Easy", - "python":true, - "code":"0219-contains-duplicate-ii", - "cpp":true, - "java":true, - "javascript":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Number of Sub Arrays of Size K and Avg Greater than or Equal to Threshold", - "pattern":"Sliding Window", - "link":"number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold/", - "video":"D8B4tKxMTnY", - "difficulty":"Medium", - "python":true, - "code":"1343-number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold", - "cpp":true, - "javascript":true, - "kotlin":true, - "java":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Longest Substring Without Repeating Characters", - "pattern":"Sliding Window", - "link":"longest-substring-without-repeating-characters/", - "video":"wiGpQwVHdE0", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0003-longest-substring-without-repeating-characters", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "scala":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Longest Repeating Character Replacement", - "pattern":"Sliding Window", - "link":"longest-repeating-character-replacement/", - "video":"gqXU1UyA8pk", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0424-longest-repeating-character-replacement", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "kotlin":true, - "rust":true, - "swift":true - }, - { - "neetcode150":true, - "problem":"Permutation In String", - "pattern":"Sliding Window", - "link":"permutation-in-string/", - "video":"UbyhOgBN834", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0567-permutation-in-string", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Frequency of The Most Frequent Element", - "pattern":"Sliding Window", - "link":"frequency-of-the-most-frequent-element/", - "video":"vgBrQ0NM5vE", - "difficulty":"Medium", - "code":"1838-frequency-of-the-most-frequent-element", - "csharp":true, - "javascript":true, - "typescript":true, - "go":true, - "rust":true, - "c":true, - "cpp":true, - "kotlin":true, - "java":true, - "python":true - }, - { - "problem":"Fruits into Basket", - "pattern":"Sliding Window", - "link":"fruit-into-baskets/", - "video":"yYtaV0G3mWQ", - "difficulty":"Medium", - "code":"0904-fruit-into-baskets", - "javascript":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true, - "python":true - }, - { - "problem":"Maximum Number of Vowels in a Substring of Given Length", - "pattern":"Sliding Window", - "link":"maximum-number-of-vowels-in-a-substring-of-given-length/", - "video":"kEfPSzgL-Ss", - "difficulty":"Medium", - "code":"1456-maximum-number-of-vowels-in-a-substring-of-given-length", - "kotlin":true, - "cpp":true, - "java":true, - "python":true - }, - { - "problem":"Minimum Number of Flips to Make The Binary String Alternating", - "pattern":"Sliding Window", - "link":"minimum-number-of-flips-to-make-the-binary-string-alternating/", - "video":"MOeuK6gaC2A", - "difficulty":"Medium", - "code":"1888-minimum-number-of-flips-to-make-the-binary-string-alternating", - "javascript":true, - "typescript":true, - "kotlin":true, - "python":true - }, - { - "problem":"Minimum Size Subarray Sum", - "pattern":"Sliding Window", - "link":"minimum-size-subarray-sum/", - "video":"aYqYMIqZx5s", - "difficulty":"Medium", - "code":"0209-minimum-size-subarray-sum", - "c":true, - "cpp":true, - "javascript":true, - "go":true, - "java":true, - "kotlin":true, - "python":true - }, - { - "problem":"Find K Closest Elements", - "pattern":"Sliding Window", - "link":"find-k-closest-elements/", - "video":"o-YDQzHoaKM", - "difficulty":"Medium", - "code":"0658-find-k-closest-elements", - "python":true, - "typescript":true, - "javascript":true, - "kotlin":true - }, - { - "problem":"Minimum Operations to Reduce X to Zero", - "pattern":"Sliding Window", - "link":"minimum-operations-to-reduce-x-to-zero/", - "video":"xumn16n7njs", - "difficulty":"Medium", - "code":"1658-minimum-operations-to-reduce-x-to-zero", - "java":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Minimum Window Substring", - "pattern":"Sliding Window", - "link":"minimum-window-substring/", - "video":"jSto0O4AJbM", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0076-minimum-window-substring", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true, - "ruby":true, - "swift":true - }, - { - "neetcode150":true, - "problem":"Sliding Window Maximum", - "pattern":"Sliding Window", - "link":"sliding-window-maximum/", - "video":"DfljaUwZsOk", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0239-sliding-window-maximum", - "csharp":true, - "go":true, - "kotlin":true, - "typescript":true, - "ruby":true, - "c":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Valid Parentheses", - "pattern":"Stack", - "link":"valid-parentheses/", - "video":"WTzjTskDFMg", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0020-valid-parentheses", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "dart":true - }, - { - "problem":"Baseball Game", - "pattern":"Stack", - "link":"baseball-game/", - "video":"Id_tqGdsZQI", - "difficulty":"Easy", - "code":"0682-baseball-game", - "c":true, - "cpp":true, - "python":true, - "java":true, - "typescript":true, - "go":true, - "rust":true, - "kotlin":true, - "csharp":true, - "javascript":true, - "swift":true - }, - { - "problem":"Implement Stack Using Queues", - "pattern":"Stack", - "link":"implement-stack-using-queues/", - "video":"rW4vm0-DLYc", - "difficulty":"Easy", - "code":"0225-implement-stack-using-queues", - "cpp":true, - "go":true, - "c":true, - "java":true, - "python":true, - "javascript":true, - "typescript":true, - "rust":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Min Stack", - "pattern":"Stack", - "link":"min-stack/", - "video":"qkLl7nAwDPo", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0155-min-stack", - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "kotlin":true, - "c":true, - "rust":true, - "swift":true - }, - { - "neetcode150":true, - "problem":"Evaluate Reverse Polish Notation", - "pattern":"Stack", - "link":"evaluate-reverse-polish-notation/", - "video":"iu0082c4HDE", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0150-evaluate-reverse-polish-notation", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Removing Stars From a String", - "pattern":"Stack", - "link":"removing-stars-from-a-string/", - "video":"pRyFZIaKegA", - "difficulty":"Medium", - "code":"2390-removing-stars-from-a-string", - "kotlin":true, - "java":true, - "python":true, - "javascript":true - }, - { - "problem":"Validate Stack Sequences", - "pattern":"Stack", - "link":"validate-stack-sequences/", - "video":"mzua0r94kb8", - "difficulty":"Medium", - "code":"0946-validate-stack-sequences", - "kotlin":true, - "python":true - }, - { - "neetcode150":true, - "problem":"Generate Parentheses", - "pattern":"Stack", - "link":"generate-parentheses/", - "video":"s9fokUqJ76A", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0022-generate-parentheses", - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "kotlin":true, - "c":true, - "rust":true, - "swift":true - }, - { - "problem":"Asteroid Collision", - "pattern":"Stack", - "link":"asteroid-collision/", - "video":"LN7KjRszjk4", - "difficulty":"Medium", - "code":"0735-asteroid-collision", - "java":true, - "javascript":true, - "typescript":true, - "rust":true, - "python":true, - "cpp":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Daily Temperatures", - "pattern":"Stack", - "link":"daily-temperatures/", - "video":"cTBiBSnjO3c", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0739-daily-temperatures", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Online Stock Span", - "pattern":"Stack", - "link":"online-stock-span/", - "video":"slYh0ZNEqSw", - "difficulty":"Medium", - "code":"0901-online-stock-span", - "python":true, - "typescript":true, - "rust":true, - "cpp":true, - "java":true, - "javascript":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Car Fleet", - "pattern":"Stack", - "link":"car-fleet/", - "video":"Pr6T-3yB9RM", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0853-car-fleet", - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "kotlin":true, - "rust":true, - "c":true - }, - { - "problem":"Simplify Path", - "pattern":"Stack", - "link":"simplify-path/", - "video":"qYlHrAKJfyA", - "difficulty":"Medium", - "code":"0071-simplify-path", - "python":true, - "typescript":true, - "rust":true, - "java":true, - "kotlin":true, - "javascript":true - }, - { - "problem":"Decode String", - "pattern":"Stack", - "link":"decode-string/", - "video":"qB0zZpBJlh8", - "difficulty":"Medium", - "code":"0394-decode-string", - "python":true, - "typescript":true, - "rust":true, - "scala":true, - "java":true, - "kotlin":true - }, - { - "problem":"Remove K Digits", - "pattern":"Stack", - "link":"remove-k-digits/", - "video":"cFabMOnJaq0", - "difficulty":"Medium", - "code":"0402-remove-k-digits", - "cpp":true, - "javascript":true, - "typescript":true, - "rust":true, - "kotlin":true, - "java":true, - "python":true - }, - { - "problem":"Remove All Adjacent Duplicates In String II", - "pattern":"Stack", - "link":"remove-all-adjacent-duplicates-in-string-ii/", - "video":"w6LcypDgC4w", - "difficulty":"Medium", - "code":"1209-remove-all-adjacent-duplicates-in-string-ii", - "cpp":true, - "python":true, - "javascript":true, - "typescript":true, - "rust":true, - "kotlin":true - }, - { - "problem":"132 Pattern", - "pattern":"Stack", - "link":"132-pattern/", - "video":"q5ANAl8Z458", - "difficulty":"Medium", - "code":"0456-132-pattern", - "python":true, - "cpp":true, - "java":true, - "javascript":true, - "typescript":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Maximum Frequency Stack", - "pattern":"Stack", - "link":"maximum-frequency-stack/", - "video":"Z6idIicFDOE", - "difficulty":"Hard", - "code":"0895-maximum-frequency-stack", - "javascript":true, - "typescript":true, - "rust":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Largest Rectangle In Histogram", - "pattern":"Stack", - "link":"largest-rectangle-in-histogram/", - "video":"zx5Sw9130L0", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0084-largest-rectangle-in-histogram", - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true, - "c":true - }, - { - "neetcode150":true, - "problem":"Binary Search", - "pattern":"Binary Search", - "link":"binary-search/", - "video":"s4DPM8ct1pI", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0704-binary-search", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "dart":true - }, - { - "problem":"Search Insert Position", - "pattern":"Binary Search", - "link":"search-insert-position/", - "video":"K-RYzDZkzCI", - "difficulty":"Easy", - "code":"0035-search-insert-position", - "c":true, - "cpp":true, - "python":true, - "javascript":true, - "swift":true, - "csharp":true, - "java":true, - "go":true, - "kotlin":true, - "typescript":true, - "rust":true - }, - { - "problem":"Guess Number Higher Or Lower", - "pattern":"Binary Search", - "link":"guess-number-higher-or-lower/", - "video":"xW4QsTtaCa4", - "difficulty":"Easy", - "code":"0374-guess-number-higher-or-lower", - "c":true, - "python":true, - "cpp":true, - "java":true, - "javascript":true, - "go":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Arranging Coins", - "pattern":"Binary Search", - "link":"arranging-coins/", - "video":"5rHz_6s2Buw", - "difficulty":"Easy", - "code":"0441-arranging-coins", - "python":true, - "cpp":true, - "kotlin":true, - "java":true, - "javascript":true - }, - { - "problem":"Squares of a Sorted Array", - "pattern":"Binary Search", - "link":"squares-of-a-sorted-array/", - "video":"FPCZsG_AkUg", - "difficulty":"Easy", - "code":"0977-squares-of-a-sorted-array", - "cpp":true, - "python":true, - "javascript":true, - "typescript":true, - "go":true, - "kotlin":true, - "java":true, - "rust":true - }, - { - "problem":"Valid Perfect Square", - "pattern":"Binary Search", - "link":"valid-perfect-square/", - "video":"Cg_wWPHJ2Sk", - "difficulty":"Easy", - "code":"0367-valid-perfect-square", - "python":true, - "javascript":true, - "cpp":true, - "swift":true, - "java":true, - "kotlin":true - }, - { - "problem":"Sqrt(x) ", - "pattern":"Binary Search", - "link":"sqrtx/", - "video":"zdMhGxRWutQ", - "difficulty":"Easy", - "code":"0069-sqrtx", - "kotlin":true, - "c":true, - "cpp":true, - "java":true, - "python":true, - "javascript":true - }, - { - "problem":"Single Element in a Sorted Array", - "pattern":"Binary Search", - "link":"single-element-in-a-sorted-array/", - "video":"HGtqdzyUJ3k", - "difficulty":"Medium", - "code":"0540-single-element-in-a-sorted-array", - "kotlin":true, - "cpp":true, - "java":true, - "python":true, - "javascript":true, - "typescript":true - }, - { - "problem":"Capacity to Ship Packages", - "pattern":"Binary Search", - "link":"capacity-to-ship-packages-within-d-days/", - "video":"ER_oLmdc-nw", - "difficulty":"Medium", - "code":"1011-capacity-to-ship-packages-within-d-days", - "kotlin":true, - "java":true, - "python":true - }, - { - "problem":"Find Peak Element", - "pattern":"Binary Search", - "link":"find-peak-element/", - "video":"kMzJy9es7Hc", - "difficulty":"Medium", - "code":"0162-find-peak-element", - "kotlin":true, - "cpp":true, - "java":true, - "python":true, - "javascript":true - }, - { - "problem":"Successful Pairs of Spells and Potions", - "pattern":"Binary Search", - "link":"successful-pairs-of-spells-and-potions/", - "video":"OKnm5oyAhWg", - "difficulty":"Medium", - "code":"2300-successful-pairs-of-spells-and-potions", - "kotlin":true, - "cpp":true, - "python":true - }, - { - "neetcode150":true, - "problem":"Search a 2D Matrix", - "pattern":"Binary Search", - "link":"search-a-2d-matrix/", - "video":"Ber2pi2C0j0", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0074-search-a-2d-matrix", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Koko Eating Bananas", - "pattern":"Binary Search", - "link":"koko-eating-bananas/", - "video":"U2SozAs9RzA", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0875-koko-eating-bananas", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Minimize the Maximum Difference of Pairs", - "pattern":"Binary Search", - "link":"minimize-the-maximum-difference-of-pairs/", - "video":"lf1Pxg7IrzQ", - "difficulty":"Medium", - "code":"2616-minimize-the-maximum-difference-of-pairs", - "java":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Find Minimum In Rotated Sorted Array", - "pattern":"Binary Search", - "link":"find-minimum-in-rotated-sorted-array/", - "video":"nIVW4P8b1VA", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0153-find-minimum-in-rotated-sorted-array", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "rust":true, - "scala":true, - "ruby":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Search In Rotated Sorted Array", - "pattern":"Binary Search", - "link":"search-in-rotated-sorted-array/", - "video":"U8XENwh8Oy8", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0033-search-in-rotated-sorted-array", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "rust":true, - "scala":true - }, - { - "problem":"Search In Rotated Sorted Array II", - "pattern":"Binary Search", - "link":"search-in-rotated-sorted-array-ii/", - "video":"oUnF7o88_Xc", - "difficulty":"Medium", - "code":"0081-search-in-rotated-sorted-array-ii", - "java":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Time Based Key Value Store", - "pattern":"Binary Search", - "link":"time-based-key-value-store/", - "video":"fu2cD_6E8Hw", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0981-time-based-key-value-store", - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "ruby":true, - "rust":true, - "c":true - }, - { - "problem":"Find First And Last Position of Element In Sorted Array", - "pattern":"Binary Search", - "link":"find-first-and-last-position-of-element-in-sorted-array/", - "video":"4sQL7R5ySUU", - "difficulty":"Medium", - "code":"0034-find-first-and-last-position-of-element-in-sorted-array", - "csharp":true, - "python":true, - "kotlin":true, - "cpp":true, - "java":true, - "swift":true, - "javascript":true - }, - { - "problem":"Maximum Number of Removable Characters", - "pattern":"Binary Search", - "link":"maximum-number-of-removable-characters/", - "video":"NMP3nRPyX5g", - "difficulty":"Medium", - "code":"1898-maximum-number-of-removable-characters", - "javascript":true, - "kotlin":true - }, - { - "problem":"Populating Next Right Pointers In Each Node", - "pattern":"Binary Search", - "link":"populating-next-right-pointers-in-each-node/", - "video":"U4hFQCa1Cq0", - "difficulty":"Medium", - "code":"0116-populating-next-right-pointers-in-each-node", - "go":true, - "cpp":true, - "javascript":true, - "kotlin":true - }, - { - "problem":"Search Suggestions System", - "pattern":"Binary Search", - "link":"search-suggestions-system/", - "video":"D4T2N0yAr20", - "difficulty":"Medium", - "code":"1268-search-suggestions-system", - "java":true, - "javascript":true, - "kotlin":true - }, - { - "problem":"Split Array Largest Sum", - "pattern":"Binary Search", - "link":"split-array-largest-sum/", - "video":"YUF3_eBdzsk", - "difficulty":"Hard", - "code":"0410-split-array-largest-sum", - "python":true, - "javascript":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Median of Two Sorted Arrays", - "pattern":"Binary Search", - "link":"median-of-two-sorted-arrays/", - "video":"q6IEA26hvXc", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0004-median-of-two-sorted-arrays", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Reverse Linked List", - "pattern":"Linked List", - "link":"reverse-linked-list/", - "video":"G0_I-ZF0S38", - "difficulty":"Easy", - "python":true, - "cpp":true, - "javascript":true, - "java":true, - "code":"0206-reverse-linked-list", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "scala":true, - "rust":true, - "dart":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Merge Two Sorted Lists", - "pattern":"Linked List", - "link":"merge-two-sorted-lists/", - "video":"XIdigk956u0", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0021-merge-two-sorted-lists", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "scala":true, - "dart":true, - "rust":true - }, - { - "problem":"Palindrome Linked List", - "pattern":"Linked List", - "link":"palindrome-linked-list/", - "video":"yOzXms1J6Nk", - "difficulty":"Easy", - "code":"0234-palindrome-linked-list", - "cpp":true, - "javascript":true, - "python":true, - "go":true, - "java":true, - "kotlin":true, - "c":true - }, - { - "problem":"Remove Linked List Elements", - "pattern":"Linked List", - "link":"remove-linked-list-elements/", - "video":"JI71sxtHTng", - "difficulty":"Easy", - "code":"0203-remove-linked-list-elements", - "javascript":true, - "typescript":true, - "go":true, - "cpp":true, - "java":true, - "python":true, - "kotlin":true - }, - { - "problem":"Remove Duplicates From Sorted List", - "pattern":"Linked List", - "link":"remove-duplicates-from-sorted-list/", - "video":"p10f-VpO4nE", - "difficulty":"Easy", - "code":"0083-remove-duplicates-from-sorted-list", - "cpp":true, - "python":true, - "javascript":true, - "go":true, - "java":true, - "kotlin":true, - "c":true - }, - { - "problem":"Middle of the Linked List", - "pattern":"Linked List", - "link":"middle-of-the-linked-list/", - "video":"A2_ldqM4QcY", - "difficulty":"Easy", - "python":true, - "code":"0876-middle-of-the-linked-list", - "c":true, - "cpp":true, - "csharp":true, - "java":true, - "javascript":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true, - "swift":true - }, - { - "problem":"Intersection of Two Linked Lists", - "pattern":"Linked List", - "link":"intersection-of-two-linked-lists/", - "video":"D0X0BONOQhI", - "difficulty":"Easy", - "code":"0160-intersection-of-two-linked-lists", - "python":true, - "javascript":true, - "java":true, - "go":true, - "kotlin":true, - "c":true, - "cpp":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Reorder List", - "pattern":"Linked List", - "link":"reorder-list/", - "video":"S5bfdUTrKLM", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0143-reorder-list", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true - }, - { - "problem":"Maximum Twin Sum Of A Linked List", - "pattern":"Linked List", - "link":"maximum-twin-sum-of-a-linked-list/", - "video":"doj95MelfSA", - "difficulty":"Medium", - "code":"2130-maximum-twin-sum-of-a-linked-list", - "python":true, - "java":true, - "kotlin":true, - "cpp":true, - "javascript":true, - "go":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Remove Nth Node From End of List", - "pattern":"Linked List", - "link":"remove-nth-node-from-end-of-list/", - "video":"XVuQxVej6y8", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0019-remove-nth-node-from-end-of-list", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Swapping Nodes in a Linked List", - "pattern":"Linked List", - "link":"swapping-nodes-in-a-linked-list/", - "video":"4LsrgMyQIjQ", - "difficulty":"Medium", - "code":"1721-swapping-nodes-in-a-linked-list", - "kotlin":true, - "cpp":true, - "java":true, - "python":true, - "go":true - }, - { - "problem":"LFU Cache", - "pattern":"Linked List", - "link":"lfu-cache/", - "video":"bLEIHn-DgoA", - "difficulty":"Hard", - "code":"0460-lfu-cache", - "javascript":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Copy List With Random Pointer", - "pattern":"Linked List", - "link":"copy-list-with-random-pointer/", - "video":"5Y2EiZST97Y", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0138-copy-list-with-random-pointer", - "c":true, - "csharp":true, - "typescript":true, - "ruby":true, - "swift":true, - "kotlin":true, - "go":true - }, - { - "problem":"Design Linked List", - "pattern":"Linked List", - "link":"design-linked-list/", - "video":"Wf4QhpdVFQo", - "difficulty":"Medium", - "python":true, - "code":"0707-design-linked-list", - "go":true, - "kotlin":true, - "c":true, - "java":true - }, - { - "problem":"Design Browser History", - "pattern":"Linked List", - "link":"design-browser-history/", - "video":"i1G-kKnBu8k", - "difficulty":"Medium", - "python":true, - "code":"1472-design-browser-history", - "javascript":true, - "typescript":true, - "go":true, - "rust":true, - "java":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Add Two Numbers", - "pattern":"Linked List", - "link":"add-two-numbers/", - "video":"wgFPrzTjm7s", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0002-add-two-numbers", - "c":true, - "csharp":true, - "typescript":true, - "ruby":true, - "swift":true, - "kotlin":true, - "scala":true, - "go":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Linked List Cycle", - "pattern":"Linked List", - "link":"linked-list-cycle/", - "video":"gBTe7lFR3vc", - "difficulty":"Easy", - "python":true, - "cpp":true, - "javascript":true, - "java":true, - "code":"0141-linked-list-cycle", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "scala":true - }, - { - "neetcode150":true, - "problem":"Find The Duplicate Number", - "pattern":"Linked List", - "link":"find-the-duplicate-number/", - "video":"wjYnzkAhcNk", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0287-find-the-duplicate-number", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Swap Nodes In Pairs", - "pattern":"Linked List", - "link":"swap-nodes-in-pairs/", - "video":"o811TZLAWOo", - "difficulty":"Medium", - "code":"0024-swap-nodes-in-pairs", - "python":true, - "go":true, - "java":true, - "kotlin":true, - "c":true, - "cpp":true - }, - { - "problem":"Sort List", - "pattern":"Linked List", - "link":"sort-list/", - "video":"TGveA1oFhrc", - "difficulty":"Medium", - "code":"0148-sort-list", - "java":true, - "python":true, - "c":true, - "cpp":true, - "kotlin":true - }, - { - "problem":"Partition List", - "pattern":"Linked List", - "link":"partition-list/", - "video":"KT1iUciJr4g", - "difficulty":"Medium", - "code":"0086-partition-list", - "python":true, - "java":true, - "kotlin":true - }, - { - "problem":"Rotate List", - "pattern":"Linked List", - "link":"rotate-list/", - "video":"UcGtPs2LE_c", - "difficulty":"Medium", - "code":"0061-rotate-list", - "python":true, - "cpp":true, - "java":true, - "kotlin":true - }, - { - "problem":"Reverse Linked List II", - "pattern":"Linked List", - "link":"reverse-linked-list-ii/", - "video":"RF_M9tX4Eag", - "difficulty":"Medium", - "code":"0092-reverse-linked-list-ii", - "python":true, - "javascript":true, - "cpp":true, - "java":true, - "kotlin":true - }, - { - "problem":"Design Circular Queue", - "pattern":"Linked List", - "link":"design-circular-queue/", - "video":"aBbsfn863oA", - "difficulty":"Medium", - "code":"0622-design-circular-queue", - "python":true, - "go":true, - "kotlin":true, - "java":true - }, - { - "problem":"Insertion Sort List", - "pattern":"Linked List", - "link":"insertion-sort-list/", - "video":"Kk6mXAzqX3Y", - "difficulty":"Medium", - "code":"0147-insertion-sort-list", - "python":true, - "cpp":true, - "kotlin":true - }, - { - "problem":"Split Linked List in Parts", - "pattern":"Linked List", - "link":"split-linked-list-in-parts/", - "video":"-OTlqdrxrVI", - "difficulty":"Medium", - "code":"0725-split-linked-list-in-parts", - "java":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"LRU Cache", - "pattern":"Linked List", - "link":"lru-cache/", - "video":"7ABFKPK2hD4", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0146-lru-cache", - "c":true, - "csharp":true, - "ruby":true, - "kotlin":true, - "go":true, - "typescript":true, - "swift":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Merge K Sorted Lists", - "pattern":"Linked List", - "link":"merge-k-sorted-lists/", - "video":"q5a5OiGbT6Q", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0023-merge-k-sorted-lists", - "c":true, - "csharp":true, - "typescript":true, - "kotlin":true, - "go":true, - "swift":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Reverse Nodes In K Group", - "pattern":"Linked List", - "link":"reverse-nodes-in-k-group/", - "video":"1UOPsfP85V4", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0025-reverse-nodes-in-k-group", - "c":true, - "csharp":true, - "typescript":true, - "kotlin":true, - "go":true, - "swift":true, - "rust":true - }, - { - "problem":"Binary Tree Inorder Traversal", - "pattern":"Trees", - "link":"binary-tree-inorder-traversal/", - "video":"g_S5WuasWUE", - "difficulty":"Easy", - "code":"0094-binary-tree-inorder-traversal", - "c":true, - "python":true, - "javascript":true, - "typescript":true, - "ruby":true, - "csharp":true, - "java":true, - "go":true, - "swift":true, - "kotlin":true, - "rust":true, - "cpp":true - }, - { - "problem":"Binary Tree Preorder Traversal", - "pattern":"Trees", - "link":"binary-tree-preorder-traversal/", - "video":"afTpieEZXck", - "difficulty":"Easy", - "code":"0144-binary-tree-preorder-traversal", - "python":true, - "cpp":true, - "typescript":true, - "kotlin":true - }, - { - "problem":"Binary Tree Postorder Traversal", - "pattern":"Trees", - "link":"binary-tree-postorder-traversal/", - "video":"QhszUQhGGlA", - "difficulty":"Easy", - "code":"0145-binary-tree-postorder-traversal", - "python":true, - "java":true, - "cpp":true, - "typescript":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Invert Binary Tree", - "pattern":"Trees", - "link":"invert-binary-tree/", - "video":"OnSn2XEQ4MY", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0226-invert-binary-tree", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Maximum Depth of Binary Tree", - "pattern":"Trees", - "link":"maximum-depth-of-binary-tree/", - "video":"hTM3phVI6YQ", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0104-maximum-depth-of-binary-tree", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Diameter of Binary Tree", - "pattern":"Trees", - "link":"diameter-of-binary-tree/", - "video":"bkxqA8Rfv04", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0543-diameter-of-binary-tree", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Balanced Binary Tree", - "pattern":"Trees", - "link":"balanced-binary-tree/", - "video":"QfJsau0ItOY", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0110-balanced-binary-tree", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Same Tree", - "pattern":"Trees", - "link":"same-tree/", - "video":"vRbbcKXCxOw", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0100-same-tree", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Subtree of Another Tree", - "pattern":"Trees", - "link":"subtree-of-another-tree/", - "video":"E36O5SWp-LE", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0572-subtree-of-another-tree", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "scala":true, - "rust":true - }, - { - "problem":"Convert Sorted Array to Binary Search Tree", - "pattern":"Trees", - "link":"convert-sorted-array-to-binary-search-tree/", - "video":"0K0uCMYq5ng", - "difficulty":"Easy", - "code":"0108-convert-sorted-array-to-binary-search-tree", - "c":true, - "javascript":true, - "go":true, - "kotlin":true, - "java":true, - "python":true - }, - { - "problem":"Merge Two Binary Trees", - "pattern":"Trees", - "link":"merge-two-binary-trees/", - "video":"QHH6rIK3dDQ", - "difficulty":"Easy", - "code":"0617-merge-two-binary-trees", - "c":true, - "java":true, - "python":true, - "javascript":true, - "go":true, - "dart":true, - "kotlin":true, - "cpp":true - }, - { - "problem":"Path Sum", - "pattern":"Trees", - "link":"path-sum/", - "video":"LSKQyOz_P8I", - "difficulty":"Easy", - "code":"0112-path-sum", - "go":true, - "c":true, - "csharp":true, - "javascript":true, - "swift":true, - "java":true, - "python":true, - "kotlin":true - }, - { - "problem":"Construct String From Binary Tree", - "pattern":"Trees", - "link":"construct-string-from-binary-tree/", - "video":"b1WpYxnuebQ", - "difficulty":"Easy", - "code":"0606-construct-string-from-binary-tree", - "java":true, - "python":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Lowest Common Ancestor of a Binary Search Tree", - "pattern":"Trees", - "link":"lowest-common-ancestor-of-a-binary-search-tree/", - "video":"gs2LMfuOR9k", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0235-lowest-common-ancestor-of-a-binary-search-tree", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "scala":true, - "rust":true - }, - { - "problem":"Insert into a Binary Search Tree", - "pattern":"Trees", - "link":"insert-into-a-binary-search-tree/", - "video":"Cpg8f79luEA", - "difficulty":"Medium", - "python":true, - "code":"0701-insert-into-a-binary-search-tree", - "kotlin":true, - "cpp":true, - "csharp":true, - "java":true, - "typescript":true - }, - { - "problem":"Delete Node in a BST", - "pattern":"Trees", - "link":"delete-node-in-a-bst/", - "video":"LFzAoJJt92M", - "difficulty":"Medium", - "python":true, - "code":"0450-delete-node-in-a-bst", - "kotlin":true, - "cpp":true, - "java":true, - "typescript":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Binary Tree Level Order Traversal", - "pattern":"Trees", - "link":"binary-tree-level-order-traversal/", - "video":"6ZnyEApgFYg", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0102-binary-tree-level-order-traversal", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Binary Tree Right Side View", - "pattern":"Trees", - "link":"binary-tree-right-side-view/", - "video":"d4zLyf32e3I", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0199-binary-tree-right-side-view", - "c":true, - "csharp":true, - "typescript":true, - "swift":true, - "kotlin":true, - "go":true, - "rust":true - }, - { - "problem":"Minimum Distance between BST Nodes", - "pattern":"Trees", - "link":"minimum-distance-between-bst-nodes/", - "video":"joxx4hTYwcw", - "difficulty":"Easy", - "code":"0783-minimum-distance-between-bst-nodes", - "kotlin":true, - "python":true - }, - { - "problem":"Symmetric Tree ", - "pattern":"Trees", - "link":"symmetric-tree/", - "video":"Mao9uzxwvmc", - "difficulty":"Easy", - "code":"0101-symmetric-tree", - "kotlin":true, - "python":true - }, - { - "problem":"Minimum Time to Collect All Apples in a Tree", - "pattern":"Trees", - "link":"minimum-time-to-collect-all-apples-in-a-tree/", - "video":"Xdt5Z583auM", - "difficulty":"Medium", - "code":"1443-minimum-time-to-collect-all-apples-in-a-tree", - "rust":true, - "kotlin":true - }, - { - "problem":"Binary Tree Zigzag Level Order Traversal", - "pattern":"Trees", - "link":"binary-tree-zigzag-level-order-traversal/", - "video":"igbboQbiwqw", - "difficulty":"Medium", - "code":"0103-binary-tree-zigzag-level-order-traversal", - "kotlin":true, - "cpp":true, - "python":true - }, - { - "problem":"Construct Quad Tree", - "pattern":"Trees", - "link":"construct-quad-tree/", - "video":"UQ-1sBMV0v4", - "difficulty":"Medium", - "code":"0427-construct-quad-tree", - "kotlin":true - }, - { - "problem":"Find Duplicate Subtrees", - "pattern":"Trees", - "link":"find-duplicate-subtrees/", - "video":"kn0Z5_qPPzY", - "difficulty":"Medium", - "code":"0652-find-duplicate-subtrees", - "kotlin":true - }, - { - "problem":"Check Completeness of a Binary Tree", - "pattern":"Trees", - "link":"check-completeness-of-a-binary-tree/", - "video":"olbiZ-EOSig", - "difficulty":"Medium", - "code":"0958-check-completeness-of-a-binary-tree", - "kotlin":true, - "cpp":true - }, - { - "problem":"Construct Binary Tree from Inorder and Postorder Traversal", - "pattern":"Trees", - "link":"construct-binary-tree-from-inorder-and-postorder-traversal/", - "video":"vm63HuIU7kw", - "difficulty":"Medium", - "code":"0106-construct-binary-tree-from-inorder-and-postorder-traversal", - "java":true, - "kotlin":true - }, - { - "problem":"Maximum Width of Binary Tree ", - "pattern":"Trees", - "link":"maximum-width-of-binary-tree/", - "video":"FPzLE2L7uHs", - "difficulty":"Medium", - "code":"0662-maximum-width-of-binary-tree", - "java":true, - "kotlin":true - }, - { - "problem":"Time Needed to Inform All Employees ", - "pattern":"Trees", - "link":"time-needed-to-inform-all-employees/", - "video":"zdBYi0p4L5Q", - "difficulty":"Medium", - "code":"1376-time-needed-to-inform-all-employees", - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Count Good Nodes In Binary Tree", - "pattern":"Trees", - "link":"count-good-nodes-in-binary-tree/", - "video":"7cp5imvDzl4", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"1448-count-good-nodes-in-binary-tree", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Validate Binary Search Tree", - "pattern":"Trees", - "link":"validate-binary-search-tree/", - "video":"s6ATEkipzow", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0098-validate-binary-search-tree", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Kth Smallest Element In a Bst", - "pattern":"Trees", - "link":"kth-smallest-element-in-a-bst/", - "video":"5LUXSvjmGCw", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0230-kth-smallest-element-in-a-bst", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "scala":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Construct Binary Tree From Preorder And Inorder Traversal", - "pattern":"Trees", - "link":"construct-binary-tree-from-preorder-and-inorder-traversal/", - "video":"ihj4IQGZ2zc", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0105-construct-binary-tree-from-preorder-and-inorder-traversal", - "c":true, - "csharp":true, - "typescript":true, - "kotlin":true, - "go":true - }, - { - "problem":"Unique Binary Search Trees", - "pattern":"Trees", - "link":"unique-binary-search-trees/", - "video":"Ox0TenN3Zpg", - "difficulty":"Medium", - "code":"0096-unique-binary-search-trees", - "c":true, - "java":true, - "kotlin":true - }, - { - "problem":"Unique Binary Search Trees II", - "pattern":"Trees", - "link":"unique-binary-search-trees-ii/", - "video":"m907FlQa2Yc", - "difficulty":"Medium", - "code":"0095-unique-binary-search-trees-ii", - "kotlin":true - }, - { - "problem":"Sum Root to Leaf Numbers", - "pattern":"Trees", - "link":"sum-root-to-leaf-numbers/", - "video":"Jk16lZGFWxE", - "difficulty":"Medium", - "code":"0129-sum-root-to-leaf-numbers", - "c":true, - "java":true, - "cpp":true, - "kotlin":true - }, - { - "problem":"House Robber III", - "pattern":"Trees", - "link":"house-robber-iii/", - "video":"nHR8ytpzz7c", - "difficulty":"Medium", - "code":"0337-house-robber-iii", - "java":true, - "kotlin":true - }, - { - "problem":"Flip Equivalent Binary Trees", - "pattern":"Trees", - "link":"flip-equivalent-binary-trees/", - "video":"izRDc1il9Pk", - "difficulty":"Medium", - "code":"0951-flip-equivalent-binary-trees", - "java":true, - "kotlin":true - }, - { - "problem":"Operations On Tree", - "pattern":"Trees", - "link":"operations-on-tree/", - "video":"qK4PtjrVD0U", - "difficulty":"Medium", - "code":"1993-operations-on-tree", - "kotlin":true - }, - { - "problem":"All Possible Full Binary Trees", - "pattern":"Trees", - "link":"all-possible-full-binary-trees/", - "video":"nZtrZPTTCAo", - "difficulty":"Medium", - "code":"0894-all-possible-full-binary-trees", - "python":true, - "java":true, - "kotlin":true - }, - { - "problem":"Find Bottom Left Tree Value", - "pattern":"Trees", - "link":"find-bottom-left-tree-value/", - "video":"u_by_cTsNJA", - "difficulty":"Medium", - "code":"0513-find-bottom-left-tree-value", - "java":true, - "kotlin":true - }, - { - "problem":"Trim a Binary Search Tree", - "pattern":"Trees", - "link":"trim-a-binary-search-tree/", - "video":"jwt5mTjEXGc", - "difficulty":"Medium", - "code":"0669-trim-a-binary-search-tree", - "python":true, - "javascript":true, - "typescript":true, - "go":true, - "java":true, - "kotlin":true - }, - { - "problem":"Binary Search Tree Iterator", - "pattern":"Trees", - "link":"binary-search-tree-iterator/", - "video":"RXy5RzGF5wo", - "difficulty":"Medium", - "code":"0173-binary-search-tree-iterator", - "java":true, - "javascript":true, - "kotlin":true - }, - { - "problem":"Convert Bst to Greater Tree", - "pattern":"Trees", - "link":"convert-bst-to-greater-tree/", - "video":"7vVEJwVvAlI", - "difficulty":"Medium", - "code":"0538-convert-bst-to-greater-tree", - "cpp":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Binary Tree Maximum Path Sum", - "pattern":"Trees", - "link":"binary-tree-maximum-path-sum/", - "video":"Hr5cWUld4vU", - "difficulty":"Hard", - "code":"0124-binary-tree-maximum-path-sum", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Serialize And Deserialize Binary Tree", - "pattern":"Trees", - "link":"serialize-and-deserialize-binary-tree/", - "video":"u4JAi2JJhI8", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0297-serialize-and-deserialize-binary-tree", - "c":true, - "csharp":true, - "kotlin":true, - "go":true, - "typescript":true, - "swift":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Implement Trie Prefix Tree", - "pattern":"Tries", - "link":"implement-trie-prefix-tree/", - "video":"oobqoCJlHA0", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0208-implement-trie-prefix-tree", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "scala":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Design Add And Search Words Data Structure", - "pattern":"Tries", - "link":"design-add-and-search-words-data-structure/", - "video":"BTf05gs_8iU", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0211-design-add-and-search-words-data-structure", - "csharp":true, - "typescript":true, - "ruby":true, - "kotlin":true, - "rust":true, - "go":true, - "c":true, - "scala":true - }, - { - "problem":"Extra Characters in a String", - "pattern":"Tries", - "link":"extra-characters-in-a-string/", - "video":"ONstwO1cD7c", - "difficulty":"Medium", - "code":"2707-extra-characters-in-a-string", - "cpp":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Word Search II", - "pattern":"Tries", - "link":"word-search-ii/", - "video":"asbcE9mZz_U", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0212-word-search-ii", - "csharp":true, - "swift":true, - "kotlin":true, - "rust":true, - "go":true, - "c":true - }, - { - "neetcode150":true, - "problem":"Kth Largest Element In a Stream", - "pattern":"Heap / Priority Queue", - "link":"kth-largest-element-in-a-stream/", - "video":"hOjcdrqMoQ8", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0703-kth-largest-element-in-a-stream", - "c":true, - "csharp":true, - "ruby":true, - "swift":true, - "go":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Last Stone Weight", - "pattern":"Heap / Priority Queue", - "link":"last-stone-weight/", - "video":"B-QCq79-Vfw", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"1046-last-stone-weight", - "csharp":true, - "typescript":true, - "ruby":true, - "kotlin":true, - "go":true, - "rust":true, - "c":true - }, - { - "neetcode150":true, - "problem":"K Closest Points to Origin", - "pattern":"Heap / Priority Queue", - "link":"k-closest-points-to-origin/", - "video":"rI2EBUEMfTk", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0973-k-closest-points-to-origin", - "csharp":true, - "kotlin":true, - "go":true, - "rust":true, - "c":true - }, - { - "neetcode150":true, - "problem":"Kth Largest Element In An Array", - "pattern":"Heap / Priority Queue", - "link":"kth-largest-element-in-an-array/", - "video":"XEmy13g1Qxc", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0215-kth-largest-element-in-an-array", - "csharp":true, - "typescript":true, - "kotlin":true, - "go":true, - "scala":true, - "c":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Task Scheduler", - "pattern":"Heap / Priority Queue", - "link":"task-scheduler/", - "video":"s8p8ukTyA2I", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0621-task-scheduler", - "csharp":true, - "typescript":true, - "kotlin":true, - "rust":true, - "c":true - }, - { - "neetcode150":true, - "problem":"Design Twitter", - "pattern":"Heap / Priority Queue", - "link":"design-twitter/", - "video":"pNichitDD2E", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0355-design-twitter", - "csharp":true, - "go":true, - "kotlin":true - }, - { - "problem":"Minimize Deviation in Array", - "pattern":"Heap / Priority Queue", - "link":"minimize-deviation-in-array/", - "video":"boHNFptxo2A", - "difficulty":"Hard", - "code":"1675-minimize-deviation-in-array", - "kotlin":true, - "cpp":true - }, - { - "problem":"Maximum Subsequence Score", - "pattern":"Heap / Priority Queue", - "link":"maximum-subsequence-score/", - "video":"ax1DKi5lJwk", - "difficulty":"Medium", - "code":"2542-maximum-subsequence-score", - "kotlin":true, - "cpp":true - }, - { - "problem":"Single Threaded Cpu", - "pattern":"Heap / Priority Queue", - "link":"single-threaded-cpu/", - "video":"RR1n-d4oYqE", - "difficulty":"Medium", - "code":"1834-single-threaded-cpu", - "java":true, - "python":true, - "javascript":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Seat Reservation Manager", - "pattern":"Heap / Priority Queue", - "link":"seat-reservation-manager/", - "video":"ahobllKXEEY", - "difficulty":"Medium", - "code":"1845-seat-reservation-manager", - "python":true, - "cpp":true, - "kotlin":true - }, - { - "problem":"Process Tasks Using Servers", - "pattern":"Heap / Priority Queue", - "link":"process-tasks-using-servers/", - "video":"XKA22PecuMQ", - "difficulty":"Medium", - "code":"1882-process-tasks-using-servers", - "kotlin":true - }, - { - "problem":"Find The Kth Largest Integer In The Array", - "pattern":"Heap / Priority Queue", - "link":"find-the-kth-largest-integer-in-the-array/", - "video":"lRCaNiqO3xI", - "difficulty":"Medium", - "code":"1985-find-the-kth-largest-integer-in-the-array", - "java":true, - "python":true, - "swift":true, - "cpp":true, - "go":true, - "kotlin":true - }, - { - "problem":"Reorganize String", - "pattern":"Heap / Priority Queue", - "link":"reorganize-string/", - "video":"2g_b1aYTHeg", - "difficulty":"Medium", - "code":"0767-reorganize-string", - "java":true, - "python":true, - "cpp":true, - "kotlin":true - }, - { - "problem":"Longest Happy String", - "pattern":"Heap / Priority Queue", - "link":"longest-happy-string/", - "video":"8u-H6O_XQKE", - "difficulty":"Medium", - "code":"1405-longest-happy-string", - "kotlin":true - }, - { - "problem":"Car Pooling", - "pattern":"Heap / Priority Queue", - "link":"car-pooling/", - "video":"08sn_w4LWEE", - "difficulty":"Medium", - "code":"1094-car-pooling", - "csharp":true, - "cpp":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Find Median From Data Stream", - "pattern":"Heap / Priority Queue", - "link":"find-median-from-data-stream/", - "video":"itmhHWaHupI", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0295-find-median-from-data-stream", - "csharp":true, - "kotlin":true, - "go":true, - "typescript":true - }, - { - "problem":"Maximum Performance of a Team", - "pattern":"Heap / Priority Queue", - "link":"maximum-performance-of-a-team/", - "video":"Y7UTvogADH0", - "difficulty":"Hard", - "code":"1383-maximum-performance-of-a-team", - "csharp":true, - "python":true, - "kotlin":true - }, - { - "problem":"IPO", - "pattern":"Heap / Priority Queue", - "link":"ipo/", - "video":"1IUzNJ6TPEM", - "difficulty":"Hard", - "code":"0502-ipo", - "python":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Subsets", - "pattern":"Backtracking", - "link":"subsets/", - "video":"REOH22Xwdkk", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0078-subsets", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Combination Sum", - "pattern":"Backtracking", - "link":"combination-sum/", - "video":"GBKI9VSKdGg", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0039-combination-sum", - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "ruby":true, - "rust":true, - "c":true, - "swift":true - }, - { - "problem":"Combinations", - "pattern":"Backtracking", - "link":"combinations/", - "video":"q0s6m7AiM7o", - "difficulty":"Medium", - "code":"0077-combinations", - "python":true, - "go":true, - "kotlin":true, - "java":true - }, - { - "neetcode150":true, - "problem":"Permutations", - "pattern":"Backtracking", - "link":"permutations/", - "video":"s7AvT7cGdSo", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0046-permutations", - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "ruby":true, - "rust":true, - "c":true - }, - { - "neetcode150":true, - "problem":"Subsets II", - "pattern":"Backtracking", - "link":"subsets-ii/", - "video":"Vn2v6ajA7U0", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0090-subsets-ii", - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "ruby":true, - "rust":true, - "c":true - }, - { - "neetcode150":true, - "problem":"Combination Sum II", - "pattern":"Backtracking", - "link":"combination-sum-ii/", - "video":"rSA3t6BDDwg", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0040-combination-sum-ii", - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "ruby":true, - "c":true - }, - { - "problem":"Permutations II", - "pattern":"Backtracking", - "link":"permutations-ii/", - "video":"qhBVWf0YafA", - "difficulty":"Medium", - "code":"0047-permutations-ii", - "python":true, - "go":true, - "kotlin":true, - "java":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Word Search", - "pattern":"Backtracking", - "link":"word-search/", - "video":"pfiQ_PS1g8E", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0079-word-search", - "c":true, - "csharp":true, - "go":true, - "swift":true, - "kotlin":true, - "rust":true, - "ruby":true - }, - { - "neetcode150":true, - "problem":"Palindrome Partitioning", - "pattern":"Backtracking", - "link":"palindrome-partitioning/", - "video":"3jvWodd7ht0", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0131-palindrome-partitioning", - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "rust":true, - "swift":true, - "kotlin":true - }, - { - "problem":"Restore IP Addresses", - "pattern":"Backtracking", - "link":"restore-ip-addresses/", - "video":"61tN4YEdiTM", - "difficulty":"Medium", - "code":"0093-restore-ip-addresses", - "javascript":true, - "typescript":true, - "go":true, - "rust":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Letter Combinations of a Phone Number", - "pattern":"Backtracking", - "link":"letter-combinations-of-a-phone-number/", - "video":"0snEunUacZY", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0017-letter-combinations-of-a-phone-number", - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "rust":true, - "kotlin":true, - "swift":true - }, - { - "problem":"Matchsticks to Square", - "pattern":"Backtracking", - "link":"matchsticks-to-square/", - "video":"hUe0cUKV-YY", - "difficulty":"Medium", - "code":"0473-matchsticks-to-square", - "cpp":true, - "python":true, - "javascript":true, - "java":true, - "kotlin":true - }, - { - "problem":"Splitting a String Into Descending Consecutive Values", - "pattern":"Backtracking", - "link":"splitting-a-string-into-descending-consecutive-values/", - "video":"eDtMmysldaw", - "difficulty":"Medium", - "code":"1849-splitting-a-string-into-descending-consecutive-values", - "python":true, - "cpp":true, - "kotlin":true - }, - { - "problem":"Find Unique Binary String", - "pattern":"Backtracking", - "link":"find-unique-binary-string/", - "video":"aHqn4Dynd1k", - "difficulty":"Medium", - "code":"1980-find-unique-binary-string", - "python":true, - "kotlin":true, - "java":true - }, - { - "problem":"Maximum Length of a Concatenated String With Unique Characters", - "pattern":"Backtracking", - "link":"maximum-length-of-a-concatenated-string-with-unique-characters/", - "video":"d4SPuvkaeoo", - "difficulty":"Medium", - "code":"1239-maximum-length-of-a-concatenated-string-with-unique-characters", - "python":true, - "kotlin":true - }, - { - "problem":"Partition to K Equal Sum Subsets", - "pattern":"Backtracking", - "link":"partition-to-k-equal-sum-subsets/", - "video":"mBk4I0X46oI", - "difficulty":"Medium", - "code":"0698-partition-to-k-equal-sum-subsets", - "kotlin":true, - "python":true, - "java":true - }, - { - "neetcode150":true, - "problem":"N Queens", - "pattern":"Backtracking", - "link":"n-queens/", - "video":"Ph95IHmRp5M", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0051-n-queens", - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "c":true, - "rust":true - }, - { - "problem":"N Queens II", - "pattern":"Backtracking", - "link":"n-queens-ii/", - "video":"nalYyLZgvCY", - "difficulty":"Hard", - "code":"0052-n-queens-ii", - "c":true, - "cpp":true, - "javascript":true, - "python":true, - "kotlin":true - }, - { - "problem":"Island Perimeter", - "pattern":"Graphs", - "link":"island-perimeter/", - "video":"fISIuAFRM2s", - "difficulty":"Easy", - "code":"0463-island-perimeter", - "c":true, - "cpp":true, - "csharp":true, - "python":true, - "java":true, - "javascript":true, - "go":true, - "kotlin":true - }, - { - "problem":"Verifying An Alien Dictionary", - "pattern":"Graphs", - "link":"verifying-an-alien-dictionary/", - "video":"OVgPAJIyX6o", - "difficulty":"Easy", - "code":"0953-verifying-an-alien-dictionary", - "c":true, - "cpp":true, - "java":true, - "python":true, - "javascript":true, - "go":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Number of Islands", - "pattern":"Graphs", - "link":"number-of-islands/", - "video":"pV2kpPD66nE", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0200-number-of-islands", - "c":true, - "csharp":true, - "typescript":true, - "ruby":true, - "swift":true, - "kotlin":true, - "go":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Clone Graph", - "pattern":"Graphs", - "link":"clone-graph/", - "video":"mQeF6bN8hMk", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0133-clone-graph", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Max Area of Island", - "pattern":"Graphs", - "link":"max-area-of-island/", - "video":"iJGr1OtmH0c", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0695-max-area-of-island", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Count Sub Islands", - "pattern":"Graphs", - "link":"count-sub-islands/", - "video":"mLpW3qfbNJ8", - "difficulty":"Medium", - "code":"1905-count-sub-islands", - "c":true, - "csharp":true, - "python":true, - "cpp":true, - "java":true, - "javascript":true, - "go":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Pacific Atlantic Water Flow", - "pattern":"Graphs", - "link":"pacific-atlantic-water-flow/", - "video":"s-VkcjHqkGI", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0417-pacific-atlantic-water-flow", - "c":true, - "csharp":true, - "kotlin":true, - "typescript":true, - "go":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Surrounded Regions", - "pattern":"Graphs", - "link":"surrounded-regions/", - "video":"9z2BunfoZ5Y", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0130-surrounded-regions", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true - }, - { - "problem":"Reorder Routes to Make All Paths Lead to The City Zero", - "pattern":"Graphs", - "link":"reorder-routes-to-make-all-paths-lead-to-the-city-zero/", - "video":"m17yOR5_PpI", - "difficulty":"Medium", - "code":"1466-reorder-routes-to-make-all-paths-lead-to-the-city-zero", - "csharp":true, - "cpp":true, - "kotlin":true, - "java":true - }, - { - "neetcode150":true, - "problem":"Rotting Oranges", - "pattern":"Graphs", - "link":"rotting-oranges/", - "video":"y704fEOx0s0", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0994-rotting-oranges", - "c":true, - "csharp":true, - "typescript":true, - "kotlin":true, - "go":true - }, - { - "neetcode150":true, - "problem":"Walls And Gates", - "premium":true, - "freeLink":"https://www.lintcode.com/problem/663/", - "pattern":"Graphs", - "link":"walls-and-gates/", - "video":"e69C6xhiSQE", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0286-walls-and-gates", - "csharp":true - }, - { - "problem":"Snakes And Ladders", - "pattern":"Graphs", - "link":"snakes-and-ladders/", - "video":"6lH4nO3JfLk", - "difficulty":"Medium", - "code":"0909-snakes-and-ladders", - "csharp":true, - "python":true, - "java":true, - "kotlin":true - }, - { - "problem":"Open The Lock", - "pattern":"Graphs", - "link":"open-the-lock/", - "video":"Pzg3bCDY87w", - "difficulty":"Medium", - "code":"0752-open-the-lock", - "csharp":true, - "java":true, - "python":true, - "kotlin":true - }, - { - "problem":"Find Eventual Safe States", - "pattern":"Graphs", - "link":"find-eventual-safe-states/", - "video":"Re_v0j0CRsg", - "difficulty":"Medium", - "code":"0802-find-eventual-safe-states", - "kotlin":true, - "java":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Course Schedule", - "pattern":"Graphs", - "link":"course-schedule/", - "video":"EgI5nU9etnU", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0207-course-schedule", - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "c":true - }, - { - "neetcode150":true, - "problem":"Course Schedule II", - "pattern":"Graphs", - "link":"course-schedule-ii/", - "video":"Akt3glAwyfY", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0210-course-schedule-ii", - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true - }, - { - "problem":"Course Schedule IV", - "pattern":"Graphs", - "link":"course-schedule-iv/", - "video":"cEW05ofxhn0", - "difficulty":"Medium", - "python":true, - "code":"1462-course-schedule-iv", - "kotlin":true - }, - { - "problem":"Check if Move Is Legal", - "pattern":"Graphs", - "link":"check-if-move-is-legal/", - "video":"KxK33AcQZpQ", - "difficulty":"Medium", - "code":"1958-check-if-move-is-legal", - "cpp":true, - "java":true, - "python":true, - "javascript":true, - "go":true, - "kotlin":true - }, - { - "problem":"Shortest Bridge", - "pattern":"Graphs", - "link":"shortest-bridge/", - "video":"gkINMhbbIbU", - "difficulty":"Medium", - "code":"0934-shortest-bridge", - "kotlin":true, - "javascript":true - }, - { - "problem":"Shortest Path in Binary Matrix", - "pattern":"Graphs", - "video":"YnxUdAO7TAo", - "link":"shortest-path-in-binary-matrix/", - "difficulty":"Medium", - "code":"1091-shortest-path-in-binary-matrix", - "python":true, - "java":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Redundant Connection", - "pattern":"Graphs", - "link":"redundant-connection/", - "video":"FXWRE67PLL0", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0684-redundant-connection", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Number of Connected Components In An Undirected Graph", - "premium":true, - "freeLink":"https://www.lintcode.com/problem/3651/", - "pattern":"Graphs", - "link":"number-of-connected-components-in-an-undirected-graph/", - "video":"8f1XPm4WOUc", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0323-number-of-connected-components-in-an-undirected-graph", - "csharp":true, - "go":true, - "swift":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Graph Valid Tree", - "premium":true, - "freeLink":"https://www.lintcode.com/problem/178/", - "pattern":"Graphs", - "link":"graph-valid-tree/", - "video":"bXsUuownnoQ", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0261-graph-valid-tree", - "csharp":true, - "typescript":true, - "swift":true - }, - { - "problem":"Accounts Merge", - "pattern":"Graphs", - "link":"accounts-merge/", - "video":"6st4IxEF-90", - "difficulty":"Medium", - "code":"0721-accounts-merge", - "python":true, - "kotlin":true, - "java":true - }, - { - "problem":"Find Closest Node to Given Two Nodes", - "pattern":"Graphs", - "link":"find-closest-node-to-given-two-nodes/", - "video":"AZA8orksO4w", - "difficulty":"Medium", - "code":"2359-find-closest-node-to-given-two-nodes", - "kotlin":true - }, - { - "problem":"As Far from Land as Possible", - "pattern":"Graphs", - "link":"as-far-from-land-as-possible/", - "video":"fjxb1hQfrZk", - "difficulty":"Medium", - "code":"1162-as-far-from-land-as-possible", - "kotlin":true - }, - { - "problem":"Shortest Path with Alternating Colors", - "pattern":"Graphs", - "link":"shortest-path-with-alternating-colors/", - "video":"69rcy6lb-HQ", - "difficulty":"Medium", - "code":"1129-shortest-path-with-alternating-colors", - "kotlin":true - }, - { - "problem":"Minimum Fuel Cost to Report to the Capital", - "pattern":"Graphs", - "link":"minimum-fuel-cost-to-report-to-the-capital/", - "video":"I3lnDUIzIG4", - "difficulty":"Medium", - "code":"2477-minimum-fuel-cost-to-report-to-the-capital", - "kotlin":true, - "java":true - }, - { - "problem":"Minimum Score of a Path Between Two Cities", - "pattern":"Graphs", - "link":"minimum-score-of-a-path-between-two-cities/", - "video":"K7-mXA0irhY", - "difficulty":"Medium", - "code":"2492-minimum-score-of-a-path-between-two-cities", - "kotlin":true - }, - { - "problem":"Number of Closed Islands", - "pattern":"Graphs", - "link":"number-of-closed-islands/", - "video":"X8k48xek8g8", - "difficulty":"Medium", - "code":"1254-number-of-closed-islands", - "kotlin":true - }, - { - "problem":"Number of Enclaves", - "pattern":"Graphs", - "link":"number-of-enclaves/", - "video":"gf0zsh1FIgE", - "difficulty":"Medium", - "code":"1020-number-of-enclaves", - "kotlin":true, - "java":true - }, - { - "problem":"Minimum Number of Vertices to Reach all Nodes", - "pattern":"Graphs", - "link":"minimum-number-of-vertices-to-reach-all-nodes/", - "video":"TLzcum7vrTc", - "difficulty":"Medium", - "code":"1557-minimum-number-of-vertices-to-reach-all-nodes", - "java":true, - "kotlin":true - }, - { - "problem":"Is Graph Bipartite?", - "pattern":"Graphs", - "link":"is-graph-bipartite/", - "video":"mev55LTubBY", - "difficulty":"Medium", - "code":"0785-is-graph-bipartite", - "kotlin":true, - "java":true - }, - { - "problem":"Evaluate Division", - "pattern":"Graphs", - "link":"evaluate-division/", - "video":"Uei1fwDoyKk", - "difficulty":"Medium", - "code":"0399-evaluate-division", - "kotlin":true, - "cpp":true - }, - { - "problem":"Detonate the Maximum Bombs", - "pattern":"Graphs", - "link":"detonate-the-maximum-bombs/", - "video":"8NPbAvVXKR4", - "difficulty":"Medium", - "code":"2101-detonate-the-maximum-bombs", - "kotlin":true - }, - { - "problem":"Largest Color Value in a Directed Graph", - "pattern":"Graphs", - "link":"largest-color-value-in-a-directed-graph/", - "video":"xLoDjKczUSk", - "difficulty":"Hard", - "code":"1857-largest-color-value-in-a-directed-graph", - "kotlin":true - }, - { - "problem":"Minimum Number of Days to Eat N Oranges", - "pattern":"Graphs", - "link":"minimum-number-of-days-to-eat-n-oranges/", - "video":"LziQ6Qx9sks", - "difficulty":"Hard", - "code":"1553-minimum-number-of-days-to-eat-n-oranges", - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Word Ladder", - "pattern":"Graphs", - "link":"word-ladder/", - "video":"h9iTnkgv05E", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0127-word-ladder", - "csharp":true, - "typescript":true, - "kotlin":true, - "go":true, - "rust":true - }, - { - "problem":"Path with Minimum Effort", - "pattern":"Advanced Graphs", - "link":"path-with-minimum-effort/", - "video":"XQlxCCx2vI4", - "difficulty":"Medium", - "code":"1631-path-with-minimum-effort", - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Reconstruct Itinerary", - "pattern":"Advanced Graphs", - "link":"reconstruct-itinerary/", - "video":"ZyB_gQ8vqGA", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0332-reconstruct-itinerary", - "csharp":true, - "kotlin":true, - "go":true, - "c":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Min Cost to Connect All Points", - "pattern":"Advanced Graphs", - "link":"min-cost-to-connect-all-points/", - "video":"f7JOBJIC-NA", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"1584-min-cost-to-connect-all-points", - "csharp":true, - "ruby":true, - "swift":true, - "go":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Network Delay Time", - "pattern":"Advanced Graphs", - "link":"network-delay-time/", - "video":"EaphyqKU4PQ", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0743-network-delay-time", - "csharp":true, - "go":true, - "kotlin":true - }, - { - "problem":"Path with Maximum Probability", - "pattern":"Advanced Graphs", - "link":"path-with-maximum-probability/", - "video":"kPsDTGcrzGM", - "difficulty":"Medium", - "python":true, - "code":"1514-path-with-maximum-probability", - "java":true, - "javascript":true, - "kotlin":true, - "cpp":true - }, - { - "neetcode150":true, - "problem":"Swim In Rising Water", - "pattern":"Advanced Graphs", - "link":"swim-in-rising-water/", - "video":"amvrKlMLuGY", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0778-swim-in-rising-water", - "csharp":true, - "go":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Alien Dictionary", - "premium":true, - "freeLink":"https://www.lintcode.com/problem/892/", - "pattern":"Advanced Graphs", - "link":"alien-dictionary/", - "video":"6kTZYvNNyps", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0269-alien-dictionary", - "csharp":true - }, - { - "neetcode150":true, - "problem":"Cheapest Flights Within K Stops", - "pattern":"Advanced Graphs", - "link":"cheapest-flights-within-k-stops/", - "video":"5eIK3zUdYmE", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0787-cheapest-flights-within-k-stops", - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true - }, - { - "problem":"Number of Good Paths", - "pattern":"Advanced Graphs", - "link":"number-of-good-paths/", - "video":"rv2GBYQm7xM", - "difficulty":"Hard", - "code":"2421-number-of-good-paths", - "javascript":true, - "typescript":true, - "go":true, - "rust":true, - "kotlin":true - }, - { - "problem":"Remove Max Number of Edges to Keep Graph Fully Traversable", - "pattern":"Advanced Graphs", - "link":"remove-max-number-of-edges-to-keep-graph-fully-traversable/", - "video":"booGwg5wYm4", - "difficulty":"Hard", - "code":"1579-remove-max-number-of-edges-to-keep-graph-fully-traversable", - "kotlin":true - }, - { - "problem":"Find Critical and Pseudo Critical Edges in Minimum Spanning Tree", - "pattern":"Advanced Graphs", - "link":"find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree/", - "video":"83JnUxrLKJU", - "difficulty":"Hard", - "code":"1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree", - "python":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Climbing Stairs", - "pattern":"1-D Dynamic Programming", - "link":"climbing-stairs/", - "video":"Y0lT9Fck7qI", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0070-climbing-stairs", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "dart":true - }, - { - "neetcode150":true, - "problem":"Min Cost Climbing Stairs", - "pattern":"1-D Dynamic Programming", - "link":"min-cost-climbing-stairs/", - "code":"0746-min-cost-climbing-stairs", - "video":"ktmzAZWkEZ0", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "scala":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"House Robber", - "pattern":"1-D Dynamic Programming", - "link":"house-robber/", - "video":"73r3KWiEvyk", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0198-house-robber", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "scala":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"House Robber II", - "pattern":"1-D Dynamic Programming", - "link":"house-robber-ii/", - "video":"rWAJCfYYOvM", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0213-house-robber-ii", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "scala":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Longest Palindromic Substring", - "pattern":"1-D Dynamic Programming", - "link":"longest-palindromic-substring/", - "video":"XYQecbcd6_c", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0005-longest-palindromic-substring", - "c":true, - "csharp":true, - "typescript":true, - "rust":true, - "go":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Palindromic Substrings", - "pattern":"1-D Dynamic Programming", - "link":"palindromic-substrings/", - "video":"4RACzI5-du8", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0647-palindromic-substrings", - "c":true, - "csharp":true, - "typescript":true, - "rust":true, - "go":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Decode Ways", - "pattern":"1-D Dynamic Programming", - "link":"decode-ways/", - "video":"6aEyTjOwlJU", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0091-decode-ways", - "c":true, - "csharp":true, - "typescript":true, - "kotlin":true, - "scala":true, - "go":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Coin Change", - "pattern":"1-D Dynamic Programming", - "link":"coin-change/", - "video":"H9bfqozjoqs", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0322-coin-change", - "c":true, - "csharp":true, - "typescript":true, - "kotlin":true, - "rust":true, - "go":true, - "scala":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Maximum Product Subarray", - "pattern":"1-D Dynamic Programming", - "link":"maximum-product-subarray/", - "video":"lXVy6YWFcRM", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0152-maximum-product-subarray", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Word Break", - "pattern":"1-D Dynamic Programming", - "link":"word-break/", - "video":"Sx9NNgInc3A", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0139-word-break", - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Longest Increasing Subsequence", - "pattern":"1-D Dynamic Programming", - "link":"longest-increasing-subsequence/", - "video":"cjWnW0hdF1Y", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0300-longest-increasing-subsequence", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Partition Equal Subset Sum", - "pattern":"1-D Dynamic Programming", - "link":"partition-equal-subset-sum/", - "video":"IsvocB5BJhw", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0416-partition-equal-subset-sum", - "csharp":true, - "go":true, - "kotlin":true, - "c":true - }, - { - "problem":"Triangle", - "pattern":"1-D Dynamic Programming", - "link":"triangle/", - "video":"OM1MTokvxs4", - "difficulty":"Medium", - "code":"0120-triangle", - "cpp":true, - "java":true, - "python":true, - "kotlin":true, - "c":true - }, - { - "problem":"Delete And Earn", - "pattern":"1-D Dynamic Programming", - "link":"delete-and-earn/", - "video":"7FCemBxvGw0", - "difficulty":"Medium", - "code":"0740-delete-and-earn", - "python":true, - "go":true, - "kotlin":true, - "c":true, - "cpp":true - }, - { - "problem":"Paint House", - "pattern":"1-D Dynamic Programming", - "link":"paint-house/", - "video":"-w67-4tnH5U", - "difficulty":"Medium", - "code":"0256-paint-house", - "csharp":true - }, - { - "problem":"Combination Sum IV", - "pattern":"1-D Dynamic Programming", - "link":"combination-sum-iv/", - "video":"dw2nMCxG0ik", - "difficulty":"Medium", - "code":"0377-combination-sum-iv", - "python":true, - "cpp":true, - "kotlin":true, - "c":true, - "java":true - }, - { - "problem":"Perfect Squares", - "pattern":"1-D Dynamic Programming", - "link":"perfect-squares/", - "video":"HLZLwjzIVGo", - "difficulty":"Medium", - "code":"0279-perfect-squares", - "java":true, - "go":true, - "cpp":true, - "kotlin":true, - "c":true - }, - { - "problem":"Check if There is a Valid Partition For The Array", - "pattern":"1-D Dynamic Programming", - "link":"check-if-there-is-a-valid-partition-for-the-array/", - "video":"OxXPiwWFdTI", - "difficulty":"Medium", - "code":"2369-check-if-there-is-a-valid-partition-for-the-array", - "kotlin":true - }, - { - "problem":"Maximum Subarray Min Product", - "pattern":"1-D Dynamic Programming", - "link":"maximum-subarray-min-product/", - "video":"YLesLbNkyjA", - "difficulty":"Medium", - "code":"1856-maximum-subarray-min-product", - "kotlin":true, - "c":true, - "java":true - }, - { - "problem":"Minimum Cost For Tickets", - "pattern":"1-D Dynamic Programming", - "link":"minimum-cost-for-tickets/", - "video":"4pY1bsBpIY4", - "difficulty":"Medium", - "code":"0983-minimum-cost-for-tickets", - "cpp":true, - "kotlin":true, - "c":true - }, - { - "problem":"Integer Break", - "pattern":"1-D Dynamic Programming", - "link":"integer-break/", - "video":"in6QbUPMJ3I", - "difficulty":"Medium", - "code":"0343-integer-break", - "cpp":true, - "kotlin":true, - "c":true, - "java":true - }, - { - "problem":"Number of Longest Increasing Subsequence", - "pattern":"1-D Dynamic Programming", - "link":"number-of-longest-increasing-subsequence/", - "video":"Tuc-rjJbsXU", - "difficulty":"Medium", - "code":"0673-number-of-longest-increasing-subsequence", - "python":true, - "kotlin":true, - "c":true - }, - { - "problem":"Stickers to Spell Word", - "pattern":"1-D Dynamic Programming", - "link":"stickers-to-spell-word/", - "video":"hsomLb6mUdI", - "difficulty":"Hard", - "code":"0691-stickers-to-spell-word", - "c":true, - "kotlin":true - }, - { - "problem":"N-th Tribonacci Number", - "pattern":"1-D Dynamic Programming", - "link":"n-th-tribonacci-number/", - "video":"3lpNp5Ojvrw", - "difficulty":"Easy", - "code":"1137-n-th-tribonacci-number", - "python":true, - "javascript":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true, - "c":true, - "cpp":true - }, - { - "problem":"Uncrossed Lines", - "pattern":"1-D Dynamic Programming", - "link":"uncrossed-lines/", - "video":"mnJF4vJ7GyE", - "difficulty":"Medium", - "code":"1035-uncrossed-lines", - "kotlin":true, - "c":true - }, - { - "problem":"Solving Questions With Brainpower", - "pattern":"1-D Dynamic Programming", - "link":"solving-questions-with-brainpower/", - "video":"D7TD_ArkfkA", - "difficulty":"Medium", - "code":"2140-solving-questions-with-brainpower", - "kotlin":true, - "c":true, - "cpp":true - }, - { - "problem":"Count Ways to Build Good Strings", - "pattern":"1-D Dynamic Programming", - "link":"count-ways-to-build-good-strings/", - "video":"JKpVHG2mhbk", - "difficulty":"Medium", - "code":"2466-count-ways-to-build-good-strings", - "kotlin":true, - "c":true - }, - { - "problem":"New 21 Game", - "pattern":"1-D Dynamic Programming", - "link":"new-21-game/", - "video":"zKi4LzjK27k", - "difficulty":"Medium", - "code":"0837-new-21-game", - "kotlin":true, - "c":true, - "javascript":true - }, - { - "problem":"Best Team with no Conflicts", - "pattern":"1-D Dynamic Programming", - "link":"best-team-with-no-conflicts/", - "video":"7kURH3btcV4", - "difficulty":"Medium", - "code":"1626-best-team-with-no-conflicts", - "c":true, - "kotlin":true - }, - { - "problem":"Stone Game III", - "pattern":"1-D Dynamic Programming", - "link":"stone-game-iii/", - "video":"HsLG5QW9CFQ", - "difficulty":"Hard", - "code":"1406-stone-game-iii", - "kotlin":true, - "c":true - }, - { - "problem":"Concatenated Words", - "pattern":"1-D Dynamic Programming", - "link":"concatenated-words/", - "video":"iHp7fjw1R28", - "difficulty":"Hard", - "code":"0472-concatenated-words", - "javascript":true, - "typescript":true, - "go":true, - "rust":true, - "kotlin":true - }, - { - "problem":"Maximize Score after N Operations", - "pattern":"1-D Dynamic Programming", - "link":"maximize-score-after-n-operations/", - "video":"RRQVDqp5RSE", - "difficulty":"Hard", - "code":"1799-maximize-score-after-n-operations", - "kotlin":true, - "c":true - }, - { - "problem":"Find the Longest Valid Obstacle Course at Each Position", - "pattern":"1-D Dynamic Programming", - "link":"find-the-longest-valid-obstacle-course-at-each-position/", - "video":"Xq9VT7p0lic", - "difficulty":"Hard", - "code":"1964-find-the-longest-valid-obstacle-course-at-each-position", - "kotlin":true, - "c":true - }, - { - "problem":"Count all Valid Pickup and Delivery Options", - "pattern":"1-D Dynamic Programming", - "link":"count-all-valid-pickup-and-delivery-options/", - "video":"OpgslsirW8s", - "difficulty":"Hard", - "code":"1359-count-all-valid-pickup-and-delivery-options", - "java":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Unique Paths", - "pattern":"2-D Dynamic Programming", - "link":"unique-paths/", - "video":"IlEsdxuD4lY", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0062-unique-paths", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Unique Paths II", - "pattern":"2-D Dynamic Programming", - "link":"unique-paths-ii/", - "video":"d3UOz7zdE4I", - "difficulty":"Medium", - "python":true, - "code":"0063-unique-paths-ii", - "cpp":true, - "java":true, - "go":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Longest Common Subsequence", - "pattern":"2-D Dynamic Programming", - "link":"longest-common-subsequence/", - "video":"Ua0GhsJSlWM", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"1143-longest-common-subsequence", - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "rust":true, - "c":true - }, - { - "problem":"Longest Palindromic Subsequence", - "pattern":"2-D Dynamic Programming", - "link":"longest-palindromic-subsequence/", - "video":"bUr8cNWI09Q", - "difficulty":"Medium", - "python":true, - "code":"0516-longest-palindromic-subsequence", - "kotlin":true - }, - { - "problem":"Last Stone Weight II", - "pattern":"2-D Dynamic Programming", - "link":"last-stone-weight-ii/", - "video":"gdXkkmzvR3c", - "difficulty":"Medium", - "python":true, - "code":"1049-last-stone-weight-ii", - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Best Time to Buy And Sell Stock With Cooldown", - "pattern":"2-D Dynamic Programming", - "link":"best-time-to-buy-and-sell-stock-with-cooldown/", - "video":"I7j0F7AHpb8", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0309-best-time-to-buy-and-sell-stock-with-cooldown", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Coin Change II", - "pattern":"2-D Dynamic Programming", - "link":"coin-change-ii/", - "video":"Mjy4hd2xgrs", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0518-coin-change-ii", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Target Sum", - "pattern":"2-D Dynamic Programming", - "link":"target-sum/", - "video":"g0npyaQtAQM", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0494-target-sum", - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "c":true - }, - { - "neetcode150":true, - "problem":"Interleaving String", - "pattern":"2-D Dynamic Programming", - "link":"interleaving-string/", - "video":"3Rw3p9LrgvE", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0097-interleaving-string", - "csharp":true, - "typescript":true, - "go":true, - "scala":true, - "kotlin":true, - "c":true - }, - { - "problem":"Stone Game", - "pattern":"2-D Dynamic Programming", - "link":"stone-game/", - "video":"uhgdXOlGYqE", - "difficulty":"Medium", - "code":"0877-stone-game", - "kotlin":true, - "cpp":true - }, - { - "problem":"Minimum Path Sum", - "pattern":"2-D Dynamic Programming", - "link":"minimum-path-sum/", - "video":"pGMsrvt0fpk", - "difficulty":"Medium", - "code":"0064-minimum-path-sum", - "cpp":true, - "java":true, - "python":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Longest Increasing Path In a Matrix", - "pattern":"2-D Dynamic Programming", - "link":"longest-increasing-path-in-a-matrix/", - "video":"wCc_nd-GiEc", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0329-longest-increasing-path-in-a-matrix", - "c":true, - "csharp":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Maximal Square", - "pattern":"2-D Dynamic Programming", - "link":"maximal-square/", - "video":"6X7Ha2PrDmM", - "difficulty":"Medium", - "code":"0221-maximal-square", - "python":true, - "java":true, - "kotlin":true, - "cpp":true - }, - { - "problem":"Ones and Zeroes", - "pattern":"2-D Dynamic Programming", - "link":"ones-and-zeroes/", - "video":"miZ3qV04b1g", - "difficulty":"Medium", - "python":true, - "code":"0474-ones-and-zeroes", - "kotlin":true, - "cpp":true - }, - { - "problem":"Maximum Alternating Subsequence Sum", - "pattern":"2-D Dynamic Programming", - "link":"maximum-alternating-subsequence-sum/", - "video":"4v42XOuU1XA", - "difficulty":"Medium", - "code":"5782-maximum-alternating-subsequence-sum" - }, - { - "neetcode150":true, - "problem":"Distinct Subsequences", - "pattern":"2-D Dynamic Programming", - "link":"distinct-subsequences/", - "video":"-RDzMJ33nx8", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0115-distinct-subsequences", - "csharp":true, - "typescript":true, - "kotlin":true, - "c":true - }, - { - "neetcode150":true, - "problem":"Edit Distance", - "pattern":"2-D Dynamic Programming", - "link":"edit-distance/", - "video":"XYi2-LPrwm4", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0072-edit-distance", - "csharp":true, - "swift":true, - "scala":true, - "kotlin":true, - "c":true - }, - { - "problem":"Count Vowels Permutation", - "pattern":"2-D Dynamic Programming", - "link":"count-vowels-permutation/", - "video":"VUVpTZVa7Ls", - "difficulty":"Hard", - "code":"1220-count-vowels-permutation", - "python":true, - "java":true, - "go":true, - "cpp":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Burst Balloons", - "pattern":"2-D Dynamic Programming", - "link":"burst-balloons/", - "video":"VFskby7lUbw", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0312-burst-balloons", - "csharp":true, - "typescript":true, - "kotlin":true, - "c":true - }, - { - "problem":"Number of Ways to Rearrange Sticks With K Sticks Visible", - "pattern":"2-D Dynamic Programming", - "link":"number-of-ways-to-rearrange-sticks-with-k-sticks-visible/", - "video":"O761YBjGxGA", - "difficulty":"Hard", - "code":"1866-number-of-ways-to-rearrange-sticks-with-k-sticks-visible", - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Regular Expression Matching", - "pattern":"2-D Dynamic Programming", - "link":"regular-expression-matching/", - "video":"HAA8mgxlov8", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0010-regular-expression-matching", - "csharp":true, - "typescript":true, - "go":true, - "c":true, - "kotlin":true - }, - { - "problem":"Stone Game II", - "pattern":"2-D Dynamic Programming", - "link":"stone-game-ii/", - "video":"I-z-u0zfQtg", - "difficulty":"Medium", - "code":"1140-stone-game-ii", - "kotlin":true - }, - { - "problem":"Flip String to Monotone Increasing", - "pattern":"2-D Dynamic Programming", - "link":"flip-string-to-monotone-increasing/", - "video":"tMq9z5k3umQ", - "difficulty":"Medium", - "code":"0926-flip-string-to-monotone-increasing", - "javascript":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Maximum Value of K Coins from Piles", - "pattern":"2-D Dynamic Programming", - "link":"maximum-value-of-k-coins-from-piles/", - "video":"ZRdEd_eun8g", - "difficulty":"Hard", - "code":"2218-maximum-value-of-k-coins-from-piles", - "kotlin":true - }, - { - "problem":"Number of Music Playlists", - "pattern":"2-D Dynamic Programming", - "link":"number-of-music-playlists/", - "video":"gk4qzZSmyrs", - "difficulty":"Hard", - "code":"0920-number-of-music-playlists", - "java":true, - "kotlin":true - }, - { - "problem":"Number of Ways to Form a Target String Given a Dictionary", - "pattern":"2-D Dynamic Programming", - "link":"number-of-ways-to-form-a-target-string-given-a-dictionary/", - "video":"_GF-0T-YjW8", - "difficulty":"Hard", - "code":"1639-number-of-ways-to-form-a-target-string-given-a-dictionary", - "kotlin":true - }, - { - "problem":"Profitable Schemes", - "pattern":"2-D Dynamic Programming", - "link":"profitable-schemes/", - "video":"CcLKQLKvOl8", - "difficulty":"Hard", - "code":"0879-profitable-schemes", - "kotlin":true - }, - { - "problem":"Minimum Cost to Cut a Stick", - "pattern":"2-D Dynamic Programming", - "link":"minimum-cost-to-cut-a-stick/", - "video":"EVxTO5I0d7w", - "difficulty":"Hard", - "code":"1547-minimum-cost-to-cut-a-stick", - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Maximum Subarray", - "pattern":"Greedy", - "link":"maximum-subarray/", - "video":"5WZl3MMT0Eg", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0053-maximum-subarray", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "rust":true, - "ruby":true - }, - { - "problem":"Maximum Sum Circular Subarray", - "pattern":"Greedy", - "link":"maximum-sum-circular-subarray/", - "video":"fxT9KjakYPM", - "difficulty":"Medium", - "code":"0918-maximum-sum-circular-subarray", - "python":true, - "javascript":true, - "typescript":true, - "go":true, - "rust":true, - "kotlin":true, - "java":true - }, - { - "problem":"Longest Turbulent Array", - "pattern":"Greedy", - "link":"longest-turbulent-subarray/", - "video":"V_iHUhR8Dek", - "difficulty":"Medium", - "code":"0978-longest-turbulent-subarray", - "python":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Jump Game", - "pattern":"Greedy", - "link":"jump-game/", - "video":"Yan0cv2cLy8", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0055-jump-game", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Jump Game II", - "pattern":"Greedy", - "link":"jump-game-ii/", - "video":"dJ7sWiOoK7g", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0045-jump-game-ii", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "ruby":true - }, - { - "problem":"Jump Game VII", - "pattern":"Greedy", - "link":"jump-game-vii/", - "video":"v1HpZUnQ4Yo", - "difficulty":"Medium", - "code":"1871-jump-game-vii", - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Gas Station", - "pattern":"Greedy", - "link":"gas-station/", - "video":"lJwbPZGo05A", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0134-gas-station", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "ruby":true - }, - { - "neetcode150":true, - "problem":"Hand of Straights", - "pattern":"Greedy", - "link":"hand-of-straights/", - "video":"amnrMCVd2YI", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0846-hand-of-straights", - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "kotlin":true, - "c":true - }, - { - "problem":"Minimize Maximum of Array", - "pattern":"Greedy", - "link":"minimize-maximum-of-array/", - "video":"AeHMvcKuR0Y", - "difficulty":"Medium", - "code":"2439-minimize-maximum-of-array", - "kotlin":true - }, - { - "problem":"Dota2 Senate", - "pattern":"Greedy", - "link":"dota2-senate/", - "video":"zZA5KskfMuQ", - "difficulty":"Medium", - "code":"0649-dota2-senate", - "kotlin":true - }, - { - "problem":"Maximum Points You Can Obtain From Cards", - "pattern":"Greedy", - "link":"maximum-points-you-can-obtain-from-cards/", - "video":"TsA4vbtfCvo", - "difficulty":"Medium", - "code":"1423-maximum-points-you-can-obtain-from-cards", - "csharp":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Merge Triplets to Form Target Triplet", - "pattern":"Greedy", - "link":"merge-triplets-to-form-target-triplet/", - "video":"kShkQLQZ9K4", - "difficulty":"Medium", - "code":"1899-merge-triplets-to-form-target-triplet", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "csharp":true, - "typescript":true, - "ruby":true, - "swift":true, - "kotlin":true, - "c":true - }, - { - "neetcode150":true, - "problem":"Partition Labels", - "pattern":"Greedy", - "link":"partition-labels/", - "video":"B7m8UmZE-vw", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0763-partition-labels", - "csharp":true, - "go":true, - "ruby":true, - "kotlin":true, - "c":true - }, - { - "neetcode150":true, - "problem":"Valid Parenthesis String", - "pattern":"Greedy", - "link":"valid-parenthesis-string/", - "video":"QhPdNS143Qg", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0678-valid-parenthesis-string", - "c":true, - "csharp":true, - "typescript":true, - "kotlin":true - }, - { - "problem":"Eliminate Maximum Number of Monsters", - "pattern":"Greedy", - "link":"eliminate-maximum-number-of-monsters/", - "video":"6QQRayzOTD4", - "difficulty":"Medium", - "code":"1921-eliminate-maximum-number-of-monsters", - "cpp":true, - "java":true, - "kotlin":true - }, - { - "problem":"Two City Scheduling", - "pattern":"Greedy", - "link":"two-city-scheduling/", - "video":"d-B_gk_gJtQ", - "difficulty":"Medium", - "code":"1029-two-city-scheduling", - "java":true, - "python":true, - "javascript":true, - "typescript":true, - "go":true, - "rust":true, - "kotlin":true - }, - { - "problem":"Maximum Length of Pair Chain", - "pattern":"Greedy", - "link":"maximum-length-of-pair-chain/", - "video":"LcNNorqMVTw", - "difficulty":"Medium", - "code":"0646-maximum-length-of-pair-chain", - "kotlin":true - }, - { - "problem":"Minimum Deletions to Make Character Frequencies Unique", - "pattern":"Greedy", - "link":"minimum-deletions-to-make-character-frequencies-unique/", - "video":"h8AZEN49gTc", - "difficulty":"Medium", - "code":"1647-minimum-deletions-to-make-character-frequencies-unique", - "java":true, - "kotlin":true - }, - { - "problem":"Candy", - "pattern":"Greedy", - "link":"candy/", - "video":"1IzCRCcK17A", - "difficulty":"Hard", - "code":"135-candy" - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Insert Interval", - "pattern":"Intervals", - "link":"insert-interval/", - "video":"A8NUOmlwOlM", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0057-insert-interval", - "csharp":true, - "typescript":true, - "swift":true, - "rust":true, - "go":true, - "kotlin":true, - "c":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Merge Intervals", - "pattern":"Intervals", - "link":"merge-intervals/", - "video":"44H3cEC2fFM", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0056-merge-intervals", - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "scala":true, - "c":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Non Overlapping Intervals", - "pattern":"Intervals", - "link":"non-overlapping-intervals/", - "video":"nONCGxWoUfM", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0435-non-overlapping-intervals", - "csharp":true, - "typescript":true, - "go":true, - "scala":true, - "c":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Meeting Rooms", - "premium":true, - "freeLink":"https://www.lintcode.com/problem/920/", - "pattern":"Intervals", - "link":"meeting-rooms/", - "video":"PaJxqZVPhbg", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0252-meeting-rooms", - "csharp":true, - "rust":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Meeting Rooms II", - "premium":true, - "freeLink":"https://www.lintcode.com/problem/919/", - "pattern":"Intervals", - "link":"meeting-rooms-ii/", - "video":"FdzJmTCVyJU", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0253-meeting-rooms-ii", - "csharp":true, - "rust":true, - "kotlin":true - }, - { - "problem":"Remove Covered Intervals", - "pattern":"Intervals", - "link":"remove-covered-intervals/", - "video":"nhAsMabiVkM", - "difficulty":"Medium", - "code":"1288-remove-covered-intervals", - "c":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Minimum Interval to Include Each Query", - "pattern":"Intervals", - "link":"minimum-interval-to-include-each-query/", - "video":"5hQ5WWW5awQ", - "difficulty":"Hard", - "python":true, - "java":true, - "cpp":true, - "code":"1851-minimum-interval-to-include-each-query", - "csharp":true, - "javascript":true, - "kotlin":true - }, - { - "problem":"Data Stream as Disjoint Intervals", - "pattern":"Intervals", - "link":"data-stream-as-disjoint-intervals/", - "video":"FavoZjPIWpo", - "difficulty":"Hard", - "code":"0352-data-stream-as-disjoint-intervals", - "javascript":true, - "typescript":true, - "go":true, - "rust":true, - "kotlin":true - }, - { - "problem":"Excel Sheet Column Title", - "pattern":"Math & Geometry", - "link":"excel-sheet-column-title/", - "video":"X_vJDpCCuoA", - "difficulty":"Easy", - "code":"0168-excel-sheet-column-title", - "java":true, - "python":true, - "kotlin":true - }, - { - "problem":"Greatest Common Divisor of Strings", - "pattern":"Math & Geometry", - "link":"greatest-common-divisor-of-strings/", - "video":"i5I_wrbUdzM", - "difficulty":"Easy", - "code":"1071-greatest-common-divisor-of-strings", - "javascript":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true, - "cpp":true - }, - { - "problem":"Count Odd Numbers in an Interval Range", - "pattern":"Math & Geometry", - "link":"count-odd-numbers-in-an-interval-range/", - "video":"wrIWye928JQ", - "difficulty":"Easy", - "code":"1523-count-odd-numbers-in-an-interval-range", - "kotlin":true - }, - { - "problem":"Matrix Diagonal Sum", - "pattern":"Math & Geometry", - "link":"matrix-diagonal-sum/", - "video":"WliTu6gIK7o", - "difficulty":"Easy", - "code":"1572-matrix-diagonal-sum", - "kotlin":true, - "javascript":true - }, - { - "problem":"Maximum Points on a Line", - "pattern":"Math & Geometry", - "link":"max-points-on-a-line/", - "video":"Bb9lOXUOnFw", - "difficulty":"Hard", - "code":"0149-max-points-on-a-line", - "python":true, - "javascript":true, - "typescript":true, - "rust":true, - "cpp":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Rotate Image", - "pattern":"Math & Geometry", - "link":"rotate-image/", - "video":"fMSJSS7eO1w", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0048-rotate-image", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "ruby":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Spiral Matrix", - "pattern":"Math & Geometry", - "link":"spiral-matrix/", - "video":"BJnMZNwUk1M", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0054-spiral-matrix", - "csharp":true, - "typescript":true, - "kotlin":true, - "go":true, - "ruby":true, - "c":true - }, - { - "problem":"Spiral Matrix II ", - "pattern":"Math & Geometry", - "link":"spiral-matrix-ii/", - "video":"RvLrWFBJ9fM", - "difficulty":"Medium", - "code":"0059-spiral-matrix-ii", - "javascript":true, - "kotlin":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Set Matrix Zeroes", - "pattern":"Math & Geometry", - "link":"set-matrix-zeroes/", - "video":"T41rL0L3Pnw", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0073-set-matrix-zeroes", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "kotlin":true, - "ruby":true - }, - { - "neetcode150":true, - "problem":"Happy Number", - "pattern":"Math & Geometry", - "link":"happy-number/", - "video":"ljz85bxOYJ0", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0202-happy-number", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "ruby":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Plus One", - "pattern":"Math & Geometry", - "link":"plus-one/", - "video":"jIaA8boiG1s", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0066-plus-one", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "swift":true, - "kotlin":true, - "ruby":true, - "rust":true - }, - { - "problem":"Palindrome Number", - "pattern":"Math & Geometry", - "link":"palindrome-number/", - "video":"yubRKwixN-U", - "difficulty":"Easy", - "code":"0009-palindrome-number", - "javascript":true, - "typescript":true, - "cpp":true, - "java":true, - "python":true, - "go":true, - "rust":true, - "swift":true, - "c":true, - "kotlin":true - }, - { - "problem":"Ugly Number", - "pattern":"Math & Geometry", - "link":"ugly-number/", - "video":"M0Zay1Qr9ws", - "difficulty":"Easy", - "code":"0263-ugly-number", - "c":true, - "cpp":true, - "java":true, - "python":true, - "javascript":true, - "typescript":true, - "go":true, - "rust":true, - "swift":true, - "kotlin":true - }, - { - "problem":"Shift 2D Grid", - "pattern":"Math & Geometry", - "link":"shift-2d-grid/", - "video":"nJYFh4Dl-as", - "difficulty":"Easy", - "code":"1260-shift-2d-grid", - "cpp":true, - "java":true, - "python":true, - "javascript":true, - "kotlin":true - }, - { - "problem":"Roman to Integer", - "pattern":"Math & Geometry", - "link":"roman-to-integer/", - "video":"3jdxYj3DD98", - "difficulty":"Easy", - "code":"0013-roman-to-integer", - "python":true, - "javascript":true, - "go":true, - "typescript":true, - "rust":true, - "java":true, - "cpp":true, - "kotlin":true - }, - { - "problem":"Integer to Roman", - "pattern":"Math & Geometry", - "link":"integer-to-roman/", - "video":"ohBNdSJyLh8", - "difficulty":"Medium", - "code":"0012-integer-to-roman", - "python":true, - "typescript":true, - "go":true, - "rust":true, - "javascript":true, - "cpp":true, - "java":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Pow(x, n)", - "pattern":"Math & Geometry", - "link":"powx-n/", - "video":"g9YQyYi4IQQ", - "difficulty":"Medium", - "python":true, - "java":true, - "javascript":true, - "cpp":true, - "code":"0050-powx-n", - "c":true, - "csharp":true, - "typescript":true, - "swift":true, - "ruby":true, - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Multiply Strings", - "pattern":"Math & Geometry", - "link":"multiply-strings/", - "video":"1vZswirL8Y8", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0043-multiply-strings", - "csharp":true, - "typescript":true, - "swift":true, - "ruby":true, - "kotlin":true, - "c":true - }, - { - "neetcode150":true, - "problem":"Detect Squares", - "pattern":"Math & Geometry", - "link":"detect-squares/", - "video":"bahebearrDc", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"2013-detect-squares", - "csharp":true, - "kotlin":true, - "ruby":true, - "rust":true - }, - { - "problem":"Robot Bounded In Circle", - "pattern":"Math & Geometry", - "link":"robot-bounded-in-circle/", - "video":"nKv2LnC_g6E", - "difficulty":"Medium", - "code":"1041-robot-bounded-in-circle", - "kotlin":true - }, - { - "problem":"Zigzag Conversion", - "pattern":"Math & Geometry", - "link":"zigzag-conversion/", - "video":"Q2Tw6gcVEwc", - "difficulty":"Medium", - "code":"0006-zigzag-conversion", - "java":true, - "cpp":true, - "go":true, - "kotlin":true - }, - { - "problem":"Find Missing Observations", - "pattern":"Math & Geometry", - "link":"find-missing-observations/", - "video":"86yKkaNi3sU", - "difficulty":"Medium", - "code":"2028-find-missing-observations", - "kotlin":true - }, - { - "neetcode150":true, - "problem":"Single Number", - "pattern":"Bit Manipulation", - "link":"single-number/", - "video":"qMPX1AOa83k", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0136-single-number", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true, - "dart":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Number of 1 Bits", - "pattern":"Bit Manipulation", - "link":"number-of-1-bits/", - "video":"5Km3utixwZs", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0191-number-of-1-bits", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Counting Bits", - "pattern":"Bit Manipulation", - "link":"counting-bits/", - "video":"RyBM56RIWrM", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0338-counting-bits", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Reverse Bits", - "pattern":"Bit Manipulation", - "link":"reverse-bits/", - "video":"UcoN6UjAI64", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0190-reverse-bits", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Missing Number", - "pattern":"Bit Manipulation", - "link":"missing-number/", - "video":"WnPLSRLSANE", - "difficulty":"Easy", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0268-missing-number", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "problem":"Shuffle the Array", - "pattern":"Bit Manipulation", - "link":"shuffle-the-array/", - "video":"IvIKD_EU8BY", - "difficulty":"Easy", - "code":"1470-shuffle-the-array", - "javascript":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true, - "c":true - }, - { - "problem":"Add to Array-Form of Integer", - "pattern":"Bit Manipulation", - "link":"add-to-array-form-of-integer/", - "video":"eBTZQt1TWfk", - "difficulty":"Easy", - "code":"0989-add-to-array-form-of-integer", - "javascript":true, - "typescript":true, - "go":true, - "kotlin":true, - "rust":true, - "c":true - }, - { - "neetcode150":true, - "blind75":true, - "problem":"Sum of Two Integers", - "pattern":"Bit Manipulation", - "link":"sum-of-two-integers/", - "video":"gVUrDV4tZfY", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0371-sum-of-two-integers", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "rust":true - }, - { - "neetcode150":true, - "problem":"Reverse Integer", - "pattern":"Bit Manipulation", - "link":"reverse-integer/", - "video":"HAgLH58IgJQ", - "difficulty":"Medium", - "python":true, - "java":true, - "cpp":true, - "javascript":true, - "code":"0007-reverse-integer", - "c":true, - "csharp":true, - "typescript":true, - "go":true, - "ruby":true, - "swift":true, - "kotlin":true, - "scala":true, - "rust":true - }, - { - "problem":"Add Binary", - "pattern":"Bit Manipulation", - "link":"add-binary/", - "video":"keuWJ47xG8g", - "difficulty":"Easy", - "code":"0067-add-binary", - "cpp":true, - "java":true, - "python":true, - "kotlin":true, - "rust":true, - "c":true - }, - { - "problem":"Create Hello World Function", - "pattern":"JavaScript", - "link":"create-hello-world-function/", - "video":"P9Ldx1eTlRc", - "difficulty":"Easy", - "code":"2667-create-hello-world-function", - "javascript":true, - "typescript":true - }, - { - "problem":"Counter", - "pattern":"JavaScript", - "link":"counter/", - "video":"yEGQQAG5V68", - "difficulty":"Easy", - "code":"2620-counter", - "javascript":true, - "typescript":true - }, - { - "problem":"Counter II", - "pattern":"JavaScript", - "link":"counter-ii/", - "video":"UXNXKGFZD08", - "difficulty":"Easy", - "code":"2665-counter-ii", - "javascript":true - }, - { - "problem":"Apply Transform over each Element in Array", - "pattern":"JavaScript", - "link":"apply-transform-over-each-element-in-array/", - "video":"7FhJHA5jlYk", - "difficulty":"Easy", - "code":"2635-apply-transform-over-each-element-in-array" - }, - { - "problem":"Filter Elements from Array", - "pattern":"JavaScript", - "link":"filter-elements-from-array/", - "video":"w1o81gbEEJU", - "difficulty":"Easy", - "code":"2634-filter-elements-from-array" - }, - { - "problem":"Array Reduce Transformation", - "pattern":"JavaScript", - "link":"array-reduce-transformation/", - "video":"KmTbYfpGxdM", - "difficulty":"Easy", - "code":"2626-array-reduce-transformation" - }, - { - "problem":"Function Composition", - "pattern":"JavaScript", - "link":"function-composition/", - "video":"mIFw1H7Ljco", - "difficulty":"Easy", - "code":"2629-function-composition" - }, - { - "problem":"Allow One Function Call", - "pattern":"JavaScript", - "link":"allow-one-function-call/", - "video":"m_SWhM9iX3s", - "difficulty":"Easy", - "code":"2666-allow-one-function-call" - }, - { - "problem":"Memoize", - "pattern":"JavaScript", - "link":"memoize/", - "video":"oFXyzJt9VeU", - "difficulty":"Medium", - "code":"2623-memoize" - }, - { - "problem":"Curry", - "pattern":"JavaScript", - "link":"curry/", - "video":"pi4kqMWQXxA", - "difficulty":"Medium", - "code":"2632-curry" - }, - { - "problem":"Sleep", - "pattern":"JavaScript", - "link":"sleep/", - "video":"P0D9Z6H7O00", - "difficulty":"Easy", - "code":"2621-sleep" - }, - { - "problem":"Promise Time Limit", - "pattern":"JavaScript", - "link":"promise-time-limit/", - "video":"hfH57rdZhOk", - "difficulty":"Easy", - "code":"2637-promise-time-limit" - }, - { - "problem":"Promise Pool", - "pattern":"JavaScript", - "link":"promise-pool/", - "video":"DB8pAAg-9xw", - "difficulty":"Medium", - "code":"2636-promise-pool" - }, - { - "problem":"Cache With Time Limit", - "pattern":"JavaScript", - "link":"cache-with-time-limit/", - "video":"w772gtNK0Gw", - "difficulty":"Medium", - "code":"2622-cache-with-time-limit" - }, - { - "problem":"Debounce", - "pattern":"JavaScript", - "link":"debounce/", - "video":"1sxSpnxNx5w", - "difficulty":"Medium", - "code":"2627-debounce" - }, - { - "problem":"Throttle", - "pattern":"JavaScript", - "link":"throttle/", - "video":"zyGZV_fIQWk", - "difficulty":"Medium", - "code":"2676-throttle" - }, - { - "problem":"JSON Deep Equal", - "pattern":"JavaScript", - "link":"json-deep-equal/", - "video":"4JVZ-mVqJPg", - "difficulty":"Medium", - "code":"2628-json-deep-equal", - "javascript":true - }, - { - "problem":"Convert Object to JSON String", - "pattern":"JavaScript", - "link":"convert-object-to-json-string/", - "video":"f94fUbHU-FY", - "difficulty":"Medium", - "code":"2633-convert-object-to-json-string" - }, - { - "problem":"Array of Objects to Matrix", - "pattern":"JavaScript", - "link":"array-of-objects-to-matrix/", - "video":"LJwgAMHGcI0", - "difficulty":"Medium", - "code":"2675-array-of-objects-to-matrix" - }, - { - "problem":"Difference Between Two Objects", - "pattern":"JavaScript", - "link":"differences-between-two-objects/", - "video":"gH7oZs1WZfg", - "difficulty":"Medium", - "code":"2700-differences-between-two-objects" - }, - { - "problem":"Chunk Array", - "pattern":"JavaScript", - "link":"chunk-array/", - "video":"VUN-O3B9ceY", - "difficulty":"Easy", - "code":"2677-chunk-array" - }, - { - "problem":"Flatten Deeply Nested Array", - "pattern":"JavaScript", - "link":"flatten-deeply-nested-array/", - "video":"_DetLPKtFNk", - "difficulty":"Medium", - "code":"2625-flatten-deeply-nested-array" - }, - { - "problem":"Array Prototype Last", - "pattern":"JavaScript", - "link":"array-prototype-last/", - "video":"3JdtfMBrUqc", - "difficulty":"Easy", - "code":"2619-array-prototype-last" - }, - { - "problem":"Group By", - "pattern":"JavaScript", - "link":"group-by/", - "video":"zs9axOyYHRE", - "difficulty":"Medium", - "code":"2631-group-by" - }, - { - "problem":"Check if Object Instance of Class", - "pattern":"JavaScript", - "link":"check-if-object-instance-of-class/", - "video":"meIo-Q07Ba8", - "difficulty":"Medium", - "code":"2618-check-if-object-instance-of-class" - }, - { - "problem":"Call Function with Custom Context", - "pattern":"JavaScript", - "link":"call-function-with-custom-context/", - "video":"du_GH-Ooa8E", - "difficulty":"Medium", - "code":"2693-call-function-with-custom-context" - }, - { - "problem":"Event Emitter", - "pattern":"JavaScript", - "link":"event-emitter/", - "video":"M69bjWFarU0", - "difficulty":"Medium", - "code":"2694-event-emitter" - }, - { - "problem":"Array Wrapper", - "pattern":"JavaScript", - "link":"array-wrapper/", - "video":"XoGjPdPTAVA", - "difficulty":"Easy", - "code":"2695-array-wrapper" - }, - { - "problem":"Generate Fibonacci Sequence", - "pattern":"JavaScript", - "link":"generate-fibonacci-sequence/", - "video":"T643rQ70Jlk", - "difficulty":"Easy", - "code":"2648-generate-fibonacci-sequence" - }, - { - "problem":"Nested Array Generator", - "pattern":"JavaScript", - "link":"nested-array-generator/", - "video":"yo-J1jQaZYU", - "difficulty":"Medium", - "code":"2649-nested-array-generator" - } -] \ No newline at end of file + { + "neetcode150": true, + "blind75": true, + "problem": "Contains Duplicate", + "pattern": "Arrays & Hashing", + "link": "contains-duplicate/", + "video": "3OamzN90kPg", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0217-contains-duplicate", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "scala": true, + "dart": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Valid Anagram", + "pattern": "Arrays & Hashing", + "link": "valid-anagram/", + "video": "9UtInBqnCgA", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0242-valid-anagram", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "scala": true, + "dart": true + }, + { + "problem": "Concatenation of Array", + "pattern": "Arrays & Hashing", + "link": "concatenation-of-array/", + "video": "68isPRHgcFQ", + "difficulty": "Easy", + "code": "1929-concatenation-of-array", + "python": true, + "cpp": true, + "java": true, + "javascript": true, + "kotlin": true, + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "rust": true, + "scala": true, + "dart": true + }, + { + "problem": "Replace Elements With Greatest Element On Right Side", + "pattern": "Arrays & Hashing", + "link": "replace-elements-with-greatest-element-on-right-side/", + "video": "ZHjKhUjcsaU", + "difficulty": "Easy", + "code": "1299-replace-elements-with-greatest-element-on-right-side", + "c": true, + "cpp": true, + "csharp": true, + "java": true, + "python": true, + "javascript": true, + "typescript": true, + "go": true, + "rust": true, + "dart": true, + "kotlin": true, + "swift": true + }, + { + "problem": "Is Subsequence", + "pattern": "Arrays & Hashing", + "link": "is-subsequence/", + "video": "99RVfqklbCE", + "difficulty": "Easy", + "code": "0392-is-subsequence", + "c": true, + "cpp": true, + "csharp": true, + "java": true, + "python": true, + "javascript": true, + "typescript": true, + "go": true, + "rust": true, + "dart": true, + "kotlin": true, + "swift": true + }, + { + "problem": "Length of Last Word", + "pattern": "Arrays & Hashing", + "link": "length-of-last-word/", + "video": "KT9rltZTybQ", + "difficulty": "Easy", + "code": "0058-length-of-last-word", + "c": true, + "cpp": true, + "csharp": true, + "java": true, + "python": true, + "javascript": true, + "typescript": true, + "rust": true, + "go": true, + "swift": true, + "dart": true, + "ruby": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Two Sum", + "pattern": "Arrays & Hashing", + "link": "two-sum/", + "video": "KLlXCFG5TnA", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0001-two-sum", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "scala": true, + "dart": true + }, + { + "problem": "Longest Common Prefix", + "pattern": "Arrays & Hashing", + "link": "longest-common-prefix/", + "video": "0sWShKIJoo4", + "difficulty": "Easy", + "code": "0014-longest-common-prefix", + "cpp": true, + "python": true, + "javascript": true, + "c": true, + "csharp": true, + "java": true, + "typescript": true, + "go": true, + "rust": true, + "dart": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Group Anagrams", + "pattern": "Arrays & Hashing", + "link": "group-anagrams/", + "video": "vzdNOK2oB2E", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0049-group-anagrams", + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "dart": true, + "c": true, + "scala": true + }, + { + "problem": "Pascals Triangle", + "pattern": "Arrays & Hashing", + "link": "pascals-triangle/", + "video": "nPVEaB3AjUM", + "difficulty": "Easy", + "code": "0118-pascals-triangle", + "c": true, + "cpp": true, + "java": true, + "python": true, + "javascript": true, + "typescript": true, + "rust": true, + "csharp": true, + "go": true, + "dart": true, + "kotlin": true + }, + { + "problem": "Remove Element", + "pattern": "Arrays & Hashing", + "link": "remove-element/", + "video": "Pcd1ii9P9ZI", + "difficulty": "Easy", + "code": "0027-remove-element", + "c": true, + "java": true, + "python": true, + "javascript": true, + "typescript": true, + "go": true, + "cpp": true, + "csharp": true, + "swift": true, + "rust": true, + "dart": true, + "kotlin": true + }, + { + "problem": "Unique Email Addresses", + "pattern": "Arrays & Hashing", + "link": "unique-email-addresses/", + "video": "TC_xLIWl7qY", + "difficulty": "Easy", + "code": "0929-unique-email-addresses", + "java": true, + "python": true, + "javascript": true, + "typescript": true, + "swift": true, + "cpp": true, + "csharp": true, + "go": true, + "rust": true, + "c": true, + "kotlin": true + }, + { + "problem": "Isomorphic Strings", + "pattern": "Arrays & Hashing", + "link": "isomorphic-strings/", + "video": "7yF-U1hLEqQ", + "difficulty": "Easy", + "code": "0205-isomorphic-strings", + "c": true, + "java": true, + "python": true, + "javascript": true, + "typescript": true, + "swift": true, + "cpp": true, + "csharp": true, + "go": true, + "rust": true, + "kotlin": true + }, + { + "problem": "Can Place Flowers", + "pattern": "Arrays & Hashing", + "link": "can-place-flowers/", + "video": "ZGxqqjljpUI", + "difficulty": "Easy", + "code": "0605-can-place-flowers", + "c": true, + "cpp": true, + "python": true, + "javascript": true, + "typescript": true, + "csharp": true, + "go": true, + "rust": true, + "java": true, + "kotlin": true, + "swift": true + }, + { + "problem": "Majority Element", + "pattern": "Arrays & Hashing", + "link": "majority-element/", + "video": "7pnhv842keE", + "difficulty": "Easy", + "code": "0169-majority-element", + "c": true, + "cpp": true, + "python": true, + "javascript": true, + "typescript": true, + "swift": true, + "csharp": true, + "java": true, + "go": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Next Greater Element I", + "pattern": "Arrays & Hashing", + "link": "next-greater-element-i/", + "video": "68a1Dc_qVq4", + "difficulty": "Easy", + "code": "0496-next-greater-element-i", + "java": true, + "python": true, + "typescript": true, + "c": true, + "cpp": true, + "csharp": true, + "javascript": true, + "go": true, + "rust": true, + "kotlin": true + }, + { + "problem": "Find Pivot Index", + "pattern": "Arrays & Hashing", + "link": "find-pivot-index/", + "video": "u89i60lYx8U", + "difficulty": "Easy", + "code": "0724-find-pivot-index", + "c": true, + "cpp": true, + "java": true, + "python": true, + "javascript": true, + "typescript": true, + "go": true, + "rust": true, + "csharp": true, + "kotlin": true, + "swift": true + }, + { + "problem": "Range Sum Query - Immutable", + "pattern": "Arrays & Hashing", + "link": "range-sum-query-immutable/", + "video": "2pndAmo_sMA", + "difficulty": "Easy", + "code": "0303-range-sum-query-immutable", + "python": true, + "c": true, + "cpp": true, + "java": true, + "kotlin": true, + "csharp": true, + "javascript": true, + "rust": true + }, + { + "problem": "Find All Numbers Disappeared in An Array", + "pattern": "Arrays & Hashing", + "link": "find-all-numbers-disappeared-in-an-array/", + "video": "8i-f24YFWC4", + "difficulty": "Easy", + "code": "0448-find-all-numbers-disappeared-in-an-array", + "cpp": true, + "java": true, + "python": true, + "javascript": true, + "c": true, + "typescript": true, + "go": true, + "rust": true, + "csharp": true, + "kotlin": true + }, + { + "problem": "Maximum Number of Balloons", + "pattern": "Arrays & Hashing", + "link": "maximum-number-of-balloons/", + "video": "G9xeB2-7PqY", + "difficulty": "Easy", + "code": "1189-maximum-number-of-balloons", + "c": true, + "java": true, + "python": true, + "javascript": true, + "cpp": true, + "typescript": true, + "go": true, + "rust": true, + "csharp": true, + "kotlin": true + }, + { + "problem": "Word Pattern", + "pattern": "Arrays & Hashing", + "link": "word-pattern/", + "video": "W_akoecmCbM", + "difficulty": "Easy", + "code": "0290-word-pattern", + "java": true, + "python": true, + "javascript": true, + "typescript": true, + "c": true, + "cpp": true, + "go": true, + "rust": true, + "csharp": true, + "kotlin": true + }, + { + "problem": "Design HashSet", + "pattern": "Arrays & Hashing", + "link": "design-hashset/", + "video": "VymjPQUXjL8", + "difficulty": "Easy", + "code": "0705-design-hashset", + "kotlin": true, + "c": true, + "cpp": true, + "java": true, + "python": true, + "javascript": true, + "rust": true + }, + { + "problem": "Design HashMap", + "pattern": "Arrays & Hashing", + "link": "design-hashmap/", + "video": "cNWsgbKwwoU", + "difficulty": "Easy", + "code": "0706-design-hashmap", + "python": true, + "c": true, + "cpp": true, + "java": true, + "javascript": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Sort an Array", + "pattern": "Arrays & Hashing", + "link": "sort-an-array/", + "video": "MsYZSinhuFo", + "difficulty": "Medium", + "code": "0912-sort-an-array", + "python": true, + "java": true, + "kotlin": true, + "cpp": true, + "csharp": true, + "javascript": true, + "go": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Top K Frequent Elements", + "pattern": "Arrays & Hashing", + "link": "top-k-frequent-elements/", + "video": "YPTqKIgVk-k", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0347-top-k-frequent-elements", + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "c": true, + "scala": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Product of Array Except Self", + "pattern": "Arrays & Hashing", + "link": "product-of-array-except-self/", + "video": "bNvIQI2wAjk", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0238-product-of-array-except-self", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Valid Sudoku", + "pattern": "Arrays & Hashing", + "link": "valid-sudoku/", + "video": "TjFXEUCMqI8", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0036-valid-sudoku", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "kotlin": true, + "rust": true, + "dart": true, + "scala": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Encode and Decode Strings", + "premium": true, + "freeLink": "https://www.lintcode.com/problem/659/", + "pattern": "Arrays & Hashing", + "link": "encode-and-decode-strings/", + "video": "B1k_sxOSgv8", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0271-encode-and-decode-strings", + "csharp": true, + "go": true, + "ruby": true, + "swift": true, + "rust": true, + "typescript": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Longest Consecutive Sequence", + "pattern": "Arrays & Hashing", + "link": "longest-consecutive-sequence/", + "video": "P6RZZMu_maU", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0128-longest-consecutive-sequence", + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "c": true + }, + { + "problem": "Sort Colors", + "pattern": "Arrays & Hashing", + "link": "sort-colors/", + "video": "4xbWSRZHqac", + "difficulty": "Medium", + "code": "0075-sort-colors", + "c": true, + "java": true, + "javascript": true, + "go": true, + "kotlin": true, + "cpp": true, + "python": true, + "typescript": true, + "csharp": true, + "rust": true, + "swift": true + }, + { + "problem": "Encode and Decode TinyURL", + "pattern": "Arrays & Hashing", + "link": "encode-and-decode-tinyurl/", + "video": "VyBOaboQLGc", + "difficulty": "Medium", + "code": "0535-encode-and-decode-tinyurl", + "javascript": true, + "cpp": true, + "python": true, + "typescript": true, + "go": true, + "rust": true, + "swift": true, + "kotlin": true, + "c": true, + "java": true + }, + { + "problem": "Brick Wall", + "pattern": "Arrays & Hashing", + "link": "brick-wall/", + "video": "Kkmv2h48ekw", + "difficulty": "Medium", + "code": "0554-brick-wall", + "javascript": true, + "typescript": true, + "c": true, + "cpp": true, + "java": true, + "python": true, + "rust": true, + "kotlin": true + }, + { + "problem": "Best Time to Buy And Sell Stock II", + "pattern": "Arrays & Hashing", + "link": "best-time-to-buy-and-sell-stock-ii/", + "video": "3SJ3pUkPQMc", + "difficulty": "Medium", + "code": "0122-best-time-to-buy-and-sell-stock-ii", + "c": true, + "javascript": true, + "go": true, + "cpp": true, + "java": true, + "python": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Subarray Sum Equals K", + "pattern": "Arrays & Hashing", + "link": "subarray-sum-equals-k/", + "video": "fFVZt-6sgyo", + "difficulty": "Medium", + "code": "0560-subarray-sum-equals-k", + "java": true, + "cpp": true, + "go": true, + "c": true, + "python": true, + "javascript": true, + "typescript": true, + "kotlin": true, + "rust": true, + "csharp": true + }, + { + "problem": "Unique Length 3 Palindromic Subsequences", + "pattern": "Arrays & Hashing", + "link": "unique-length-3-palindromic-subsequences/", + "video": "3THUt0vAFLU", + "difficulty": "Medium", + "code": "1930-unique-length-3-palindromic-subsequences", + "cpp": true, + "java": true, + "kotlin": true, + "c": true, + "python": true, + "javascript": true, + "typescript": true, + "rust": true + }, + { + "problem": "Minimum Number of Swaps to Make The String Balanced", + "pattern": "Arrays & Hashing", + "link": "minimum-number-of-swaps-to-make-the-string-balanced/", + "video": "3YDBT9ZrfaU", + "difficulty": "Medium", + "code": "1963-minimum-number-of-swaps-to-make-the-string-balanced", + "javascript": true, + "cpp": true, + "c": true, + "python": true, + "kotlin": true, + "java": true, + "rust": true + }, + { + "problem": "Number of Pairs of Interchangeable Rectangles", + "pattern": "Arrays & Hashing", + "link": "number-of-pairs-of-interchangeable-rectangles/", + "video": "lEQ8ZlLOuyQ", + "difficulty": "Medium", + "code": "2001-number-of-pairs-of-interchangeable-rectangles", + "javascript": true, + "cpp": true, + "python": true, + "c": true, + "java": true, + "rust": true, + "kotlin": true + }, + { + "problem": "Maximum Product of The Length of Two Palindromic Subsequences", + "pattern": "Arrays & Hashing", + "link": "maximum-product-of-the-length-of-two-palindromic-subsequences/", + "video": "aoHbYlO8vDg", + "difficulty": "Medium", + "code": "2002-maximum-product-of-the-length-of-two-palindromic-subsequences", + "cpp": true, + "c": true, + "csharp": true, + "java": true, + "python": true, + "javascript": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Grid Game", + "pattern": "Arrays & Hashing", + "link": "grid-game/", + "video": "N4wDSOw65hI", + "difficulty": "Medium", + "code": "2017-grid-game", + "python": true, + "cpp": true, + "kotlin": true, + "java": true, + "javascript": true, + "rust": true + }, + { + "problem": "Find All Anagrams in a String", + "pattern": "Arrays & Hashing", + "link": "find-all-anagrams-in-a-string/", + "video": "G8xtZy0fDKg", + "difficulty": "Medium", + "code": "0438-find-all-anagrams-in-a-string", + "cpp": true, + "csharp": true, + "python": true, + "java": true, + "javascript": true, + "go": true, + "kotlin": true, + "c": true + }, + { + "problem": "Find The Index of The First Occurrence in a String", + "pattern": "Arrays & Hashing", + "link": "find-the-index-of-the-first-occurrence-in-a-string/", + "video": "JoF0Z7nVSrA", + "difficulty": "Easy", + "code": "0028-find-the-index-of-the-first-occurrence-in-a-string", + "python": true, + "cpp": true, + "go": true, + "c": true, + "java": true, + "kotlin": true, + "csharp": true, + "javascript": true + }, + { + "problem": "Wiggle Sort", + "pattern": "Arrays & Hashing", + "premium": true, + "freeLink": "https://www.lintcode.com/problem/508/", + "link": "wiggle-sort/", + "video": "vGsyTE4s34w", + "difficulty": "Medium", + "code": "0280-wiggle-sort", + "cpp": true, + "python": true, + "kotlin": true + }, + { + "problem": "Largest Number", + "pattern": "Arrays & Hashing", + "link": "largest-number/", + "video": "WDx6Y4i4xJ8", + "difficulty": "Medium", + "code": "0179-largest-number", + "typescript": true, + "cpp": true, + "java": true, + "kotlin": true, + "c": true, + "csharp": true, + "python": true, + "javascript": true, + "go": true, + "ruby": true, + "swift": true, + "rust": true, + "scala": true + }, + { + "problem": "Continuous Subarray Sum", + "pattern": "Arrays & Hashing", + "link": "continuous-subarray-sum/", + "video": "OKcrLfR-8mE", + "difficulty": "Medium", + "code": "0523-continuous-subarray-sum", + "java": true, + "python": true, + "cpp": true, + "kotlin": true, + "c": true, + "javascript": true, + "rust": true + }, + { + "problem": "Push Dominoes", + "pattern": "Arrays & Hashing", + "link": "push-dominoes/", + "video": "evUFsOb_iLY", + "difficulty": "Medium", + "code": "0838-push-dominoes", + "typescript": true, + "cpp": true, + "python": true, + "kotlin": true, + "java": true + }, + { + "problem": "Repeated DNA Sequences", + "pattern": "Arrays & Hashing", + "link": "repeated-dna-sequences/", + "video": "FzTYfsmtOso", + "difficulty": "Medium", + "code": "0187-repeated-dna-sequences", + "java": true, + "typescript": true, + "cpp": true, + "kotlin": true, + "python": true, + "javascript": true + }, + { + "problem": "Insert Delete Get Random O(1)", + "pattern": "Arrays & Hashing", + "link": "insert-delete-getrandom-o1/", + "video": "j4KwhBziOpg", + "difficulty": "Medium", + "code": "0380-insert-delete-getrandom-o1", + "java": true, + "typescript": true, + "javascript": true, + "go": true, + "cpp": true, + "swift": true, + "kotlin": true, + "python": true + }, + { + "problem": "Check if a String Contains all Binary Codes of Size K", + "pattern": "Arrays & Hashing", + "link": "check-if-a-string-contains-all-binary-codes-of-size-k/", + "video": "qU32rTy_kOM", + "difficulty": "Medium", + "code": "1461-check-if-a-string-contains-all-binary-codes-of-size-k", + "cpp": true, + "kotlin": true, + "python": true, + "javascript": true + }, + { + "problem": "Range Sum Query 2D Immutable", + "pattern": "Arrays & Hashing", + "link": "range-sum-query-2d-immutable/", + "video": "KE8MQuwE2yA", + "difficulty": "Medium", + "code": "0304-range-sum-query-2d-immutable", + "cpp": true, + "python": true, + "kotlin": true, + "javascript": true + }, + { + "problem": "Non Decreasing Array", + "pattern": "Arrays & Hashing", + "link": "non-decreasing-array/", + "video": "RegQckCegDk", + "difficulty": "Medium", + "code": "0665-non-decreasing-array", + "cpp": true, + "java": true, + "javascript": true, + "typescript": true, + "go": true, + "scala": true, + "kotlin": true, + "python": true, + "csharp": true + }, + { + "problem": "First Missing Positive", + "pattern": "Arrays & Hashing", + "link": "first-missing-positive/", + "video": "8g78yfzMlao", + "difficulty": "Hard", + "code": "0041-first-missing-positive", + "python": true, + "typescript": true, + "cpp": true, + "java": true, + "go": true, + "kotlin": true, + "c": true, + "javascript": true + }, + { + "problem": "Sign of An Array", + "pattern": "Arrays & Hashing", + "link": "sign-of-the-product-of-an-array/", + "video": "ILDLM86jNow", + "difficulty": "Easy", + "code": "1822-sign-of-the-product-of-an-array", + "cpp": true, + "java": true, + "python": true, + "javascript": true, + "typescript": true, + "go": true, + "kotlin": true + }, + { + "problem": "Find the Difference of Two Arrays", + "pattern": "Arrays & Hashing", + "link": "find-the-difference-of-two-arrays/", + "video": "a4wqKR-znBE", + "difficulty": "Easy", + "code": "2215-find-the-difference-of-two-arrays", + "kotlin": true, + "cpp": true, + "csharp": true, + "java": true, + "python": true, + "javascript": true, + "typescript": true + }, + { + "problem": "Design Parking System", + "pattern": "Arrays & Hashing", + "link": "design-parking-system/", + "video": "d5zCHesOrSk", + "difficulty": "Easy", + "code": "1603-design-parking-system", + "kotlin": true, + "java": true, + "python": true, + "javascript": true + }, + { + "problem": "Number of Zero-Filled Subarrays", + "pattern": "Arrays & Hashing", + "link": "number-of-zero-filled-subarrays/", + "video": "G-EWVGCcL_w", + "difficulty": "Medium", + "code": "2348-number-of-zero-filled-subarrays", + "kotlin": true, + "cpp": true, + "java": true, + "python": true + }, + { + "problem": "Optimal Partition of String", + "pattern": "Arrays & Hashing", + "link": "optimal-partition-of-string/", + "video": "CKZPdiXiQf0", + "difficulty": "Medium", + "code": "2405-optimal-partition-of-string", + "kotlin": true, + "java": true + }, + { + "problem": "Design Underground System", + "pattern": "Arrays & Hashing", + "link": "design-underground-system/", + "video": "W5QOLqXskZM", + "difficulty": "Medium", + "code": "1396-design-underground-system", + "kotlin": true, + "java": true, + "javascript": true + }, + { + "problem": "Minimum Penalty for a Shop", + "pattern": "Arrays & Hashing", + "link": "minimum-penalty-for-a-shop/", + "video": "0d7ShRoOFVE", + "difficulty": "Medium", + "code": "2483-minimum-penalty-for-a-shop", + "cpp": true, + "java": true, + "kotlin": true + }, + { + "problem": "Text Justification", + "pattern": "Arrays & Hashing", + "link": "text-justification/", + "video": "TzMl4Z7pVh8", + "difficulty": "Hard", + "code": "0068-naming-a-company", + "python": true, + "kotlin": true + }, + { + "problem": "Naming a Company", + "pattern": "Arrays & Hashing", + "link": "naming-a-company/", + "video": "NrHpgTScOcY", + "difficulty": "Hard", + "code": "2306-naming-a-company", + "kotlin": true, + "java": true, + "javascript": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Valid Palindrome", + "pattern": "Two Pointers", + "link": "valid-palindrome/", + "video": "jJXJ16kPFWg", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0125-valid-palindrome", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "dart": true, + "scala": true + }, + { + "problem": "Valid Palindrome II", + "pattern": "Two Pointers", + "link": "valid-palindrome-ii/", + "video": "JrxRYBwG6EI", + "difficulty": "Easy", + "code": "0680-valid-palindrome-ii", + "python": true, + "cpp": true, + "csharp": true, + "java": true, + "javascript": true, + "typescript": true, + "go": true, + "rust": true, + "c": true, + "kotlin": true + }, + { + "problem": "Minimum Difference Between Highest And Lowest of K Scores", + "pattern": "Two Pointers", + "link": "minimum-difference-between-highest-and-lowest-of-k-scores/", + "video": "JU5XdBZZtlk", + "difficulty": "Easy", + "code": "1984-minimum-difference-between-highest-and-lowest-of-k-scores", + "javascript": true, + "cpp": true, + "python": true, + "typescript": true, + "go": true, + "rust": true, + "java": true, + "kotlin": true + }, + { + "problem": "Merge Strings Alternately", + "pattern": "Two Pointers", + "link": "merge-strings-alternately/", + "video": "LECWOvTo-Sc", + "difficulty": "Easy", + "code": "1768-merge-strings-alternately", + "kotlin": true, + "cpp": true, + "java": true, + "python": true, + "javascript": true, + "typescript": true + }, + { + "problem": "Reverse String", + "pattern": "Two Pointers", + "link": "reverse-string/", + "video": "_d0T_2Lk2qA", + "difficulty": "Easy", + "code": "0344-reverse-string", + "c": true, + "python": true, + "javascript": true, + "typescript": true, + "swift": true, + "cpp": true, + "java": true, + "go": true, + "rust": true, + "kotlin": true, + "dart": true + }, + { + "problem": "Merge Sorted Array", + "pattern": "Two Pointers", + "link": "merge-sorted-array/", + "video": "P1Ic85RarKY", + "difficulty": "Easy", + "code": "0088-merge-sorted-array", + "c": true, + "java": true, + "javascript": true, + "cpp": true, + "python": true, + "typescript": true, + "go": true, + "rust": true, + "kotlin": true + }, + { + "problem": "Move Zeroes", + "pattern": "Two Pointers", + "link": "move-zeroes/", + "video": "aayNRwUN3Do", + "difficulty": "Easy", + "code": "0283-move-zeroes", + "c": true, + "cpp": true, + "javascript": true, + "csharp": true, + "python": true, + "typescript": true, + "go": true, + "swift": true, + "rust": true, + "java": true, + "kotlin": true + }, + { + "problem": "Remove Duplicates From Sorted Array", + "pattern": "Two Pointers", + "link": "remove-duplicates-from-sorted-array/", + "video": "DEJAZBq0FDA", + "difficulty": "Easy", + "code": "0026-remove-duplicates-from-sorted-array", + "python": true, + "javascript": true, + "go": true, + "cpp": true, + "typescript": true, + "swift": true, + "rust": true, + "java": true, + "kotlin": true, + "c": true + }, + { + "problem": "Remove Duplicates From Sorted Array II", + "pattern": "Two Pointers", + "link": "remove-duplicates-from-sorted-array-ii/", + "video": "ycAq8iqh0TI", + "difficulty": "Medium", + "code": "0080-remove-duplicates-from-sorted-array-ii", + "python": true, + "kotlin": true, + "cpp": true, + "csharp": true, + "javascript": true, + "swift": true + }, + { + "neetcode150": true, + "problem": "Two Sum II Input Array Is Sorted", + "pattern": "Two Pointers", + "link": "two-sum-ii-input-array-is-sorted/", + "video": "cQ1Oz4ckceM", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0167-two-sum-ii-input-array-is-sorted", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "scala": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "3Sum", + "pattern": "Two Pointers", + "link": "3sum/", + "video": "jzZsG8n2R9A", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0015-3sum", + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "scala": true, + "c": true + }, + { + "problem": "4Sum", + "pattern": "Two Pointers", + "link": "4sum/", + "video": "EYeR-_1NRlQ", + "difficulty": "Medium", + "code": "0018-4sum", + "python": true, + "javascript": true, + "typescript": true, + "go": true, + "cpp": true, + "kotlin": true, + "java": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Container With Most Water", + "pattern": "Two Pointers", + "link": "container-with-most-water/", + "video": "UuiTKBwPgAo", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0011-container-with-most-water", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "scala": true, + "dart": true + }, + { + "problem": "Number of Subsequences That Satisfy The Given Sum Condition", + "pattern": "Two Pointers", + "link": "number-of-subsequences-that-satisfy-the-given-sum-condition/", + "video": "xCsIkPLS4Ls", + "difficulty": "Medium", + "code": "1498-number-of-subsequences-that-satisfy-the-given-sum-condition", + "cpp": true, + "python": true, + "kotlin": true + }, + { + "problem": "Rotate Array", + "pattern": "Two Pointers", + "link": "rotate-array/", + "video": "BHr381Guz3Y", + "difficulty": "Medium", + "code": "0189-rotate-array", + "cpp": true, + "java": true, + "python": true, + "typescript": true, + "go": true, + "kotlin": true, + "javascript": true + }, + { + "problem": "Array With Elements Not Equal to Average of Neighbors", + "pattern": "Two Pointers", + "link": "array-with-elements-not-equal-to-average-of-neighbors/", + "video": "Wmb3YdVYfqM", + "difficulty": "Medium", + "code": "1968-array-with-elements-not-equal-to-average-of-neighbors", + "c": true, + "cpp": true, + "kotlin": true, + "python": true, + "javascript": true + }, + { + "problem": "Boats to Save People", + "pattern": "Two Pointers", + "link": "boats-to-save-people/", + "video": "XbaxWuHIWUs", + "difficulty": "Medium", + "code": "0881-boats-to-save-people", + "c": true, + "cpp": true, + "typescript": true, + "javascript": true, + "python": true, + "kotlin": true, + "java": true, + "swift": true + }, + { + "neetcode150": true, + "problem": "Trapping Rain Water", + "pattern": "Two Pointers", + "link": "trapping-rain-water/", + "video": "ZI2z5pq0TqA", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0042-trapping-rain-water", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Best Time to Buy And Sell Stock", + "pattern": "Sliding Window", + "link": "best-time-to-buy-and-sell-stock/", + "video": "1pkOgXD63yU", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0121-best-time-to-buy-and-sell-stock", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "scala": true + }, + { + "problem": "Contains Duplicate II", + "pattern": "Sliding Window", + "link": "contains-duplicate-ii/", + "video": "ypn0aZ0nrL4", + "difficulty": "Easy", + "python": true, + "code": "0219-contains-duplicate-ii", + "cpp": true, + "java": true, + "javascript": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Number of Sub Arrays of Size K and Avg Greater than or Equal to Threshold", + "pattern": "Sliding Window", + "link": "number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold/", + "video": "D8B4tKxMTnY", + "difficulty": "Medium", + "python": true, + "code": "1343-number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold", + "cpp": true, + "javascript": true, + "kotlin": true, + "java": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Longest Substring Without Repeating Characters", + "pattern": "Sliding Window", + "link": "longest-substring-without-repeating-characters/", + "video": "wiGpQwVHdE0", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0003-longest-substring-without-repeating-characters", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "scala": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Longest Repeating Character Replacement", + "pattern": "Sliding Window", + "link": "longest-repeating-character-replacement/", + "video": "gqXU1UyA8pk", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0424-longest-repeating-character-replacement", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "kotlin": true, + "rust": true, + "swift": true + }, + { + "neetcode150": true, + "problem": "Permutation In String", + "pattern": "Sliding Window", + "link": "permutation-in-string/", + "video": "UbyhOgBN834", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0567-permutation-in-string", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Frequency of The Most Frequent Element", + "pattern": "Sliding Window", + "link": "frequency-of-the-most-frequent-element/", + "video": "vgBrQ0NM5vE", + "difficulty": "Medium", + "code": "1838-frequency-of-the-most-frequent-element", + "csharp": true, + "javascript": true, + "typescript": true, + "go": true, + "rust": true, + "c": true, + "cpp": true, + "kotlin": true, + "java": true, + "python": true + }, + { + "problem": "Fruits into Basket", + "pattern": "Sliding Window", + "link": "fruit-into-baskets/", + "video": "yYtaV0G3mWQ", + "difficulty": "Medium", + "code": "0904-fruit-into-baskets", + "javascript": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true, + "python": true + }, + { + "problem": "Maximum Number of Vowels in a Substring of Given Length", + "pattern": "Sliding Window", + "link": "maximum-number-of-vowels-in-a-substring-of-given-length/", + "video": "kEfPSzgL-Ss", + "difficulty": "Medium", + "code": "1456-maximum-number-of-vowels-in-a-substring-of-given-length", + "kotlin": true, + "cpp": true, + "java": true, + "python": true + }, + { + "problem": "Minimum Number of Flips to Make The Binary String Alternating", + "pattern": "Sliding Window", + "link": "minimum-number-of-flips-to-make-the-binary-string-alternating/", + "video": "MOeuK6gaC2A", + "difficulty": "Medium", + "code": "1888-minimum-number-of-flips-to-make-the-binary-string-alternating", + "javascript": true, + "typescript": true, + "kotlin": true, + "python": true + }, + { + "problem": "Minimum Size Subarray Sum", + "pattern": "Sliding Window", + "link": "minimum-size-subarray-sum/", + "video": "aYqYMIqZx5s", + "difficulty": "Medium", + "code": "0209-minimum-size-subarray-sum", + "c": true, + "cpp": true, + "javascript": true, + "go": true, + "java": true, + "kotlin": true, + "python": true + }, + { + "problem": "Find K Closest Elements", + "pattern": "Sliding Window", + "link": "find-k-closest-elements/", + "video": "o-YDQzHoaKM", + "difficulty": "Medium", + "code": "0658-find-k-closest-elements", + "python": true, + "typescript": true, + "javascript": true, + "kotlin": true + }, + { + "problem": "Minimum Operations to Reduce X to Zero", + "pattern": "Sliding Window", + "link": "minimum-operations-to-reduce-x-to-zero/", + "video": "xumn16n7njs", + "difficulty": "Medium", + "code": "1658-minimum-operations-to-reduce-x-to-zero", + "java": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Minimum Window Substring", + "pattern": "Sliding Window", + "link": "minimum-window-substring/", + "video": "jSto0O4AJbM", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0076-minimum-window-substring", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true, + "ruby": true, + "swift": true + }, + { + "neetcode150": true, + "problem": "Sliding Window Maximum", + "pattern": "Sliding Window", + "link": "sliding-window-maximum/", + "video": "DfljaUwZsOk", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0239-sliding-window-maximum", + "csharp": true, + "go": true, + "kotlin": true, + "typescript": true, + "ruby": true, + "c": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Valid Parentheses", + "pattern": "Stack", + "link": "valid-parentheses/", + "video": "WTzjTskDFMg", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0020-valid-parentheses", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "dart": true + }, + { + "problem": "Baseball Game", + "pattern": "Stack", + "link": "baseball-game/", + "video": "Id_tqGdsZQI", + "difficulty": "Easy", + "code": "0682-baseball-game", + "c": true, + "cpp": true, + "python": true, + "java": true, + "typescript": true, + "go": true, + "rust": true, + "kotlin": true, + "csharp": true, + "javascript": true, + "swift": true + }, + { + "problem": "Implement Stack Using Queues", + "pattern": "Stack", + "link": "implement-stack-using-queues/", + "video": "rW4vm0-DLYc", + "difficulty": "Easy", + "code": "0225-implement-stack-using-queues", + "cpp": true, + "go": true, + "c": true, + "java": true, + "python": true, + "javascript": true, + "typescript": true, + "rust": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Min Stack", + "pattern": "Stack", + "link": "min-stack/", + "video": "qkLl7nAwDPo", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0155-min-stack", + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "kotlin": true, + "c": true, + "rust": true, + "swift": true + }, + { + "neetcode150": true, + "problem": "Evaluate Reverse Polish Notation", + "pattern": "Stack", + "link": "evaluate-reverse-polish-notation/", + "video": "iu0082c4HDE", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0150-evaluate-reverse-polish-notation", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Removing Stars From a String", + "pattern": "Stack", + "link": "removing-stars-from-a-string/", + "video": "pRyFZIaKegA", + "difficulty": "Medium", + "code": "2390-removing-stars-from-a-string", + "kotlin": true, + "java": true, + "python": true, + "javascript": true + }, + { + "problem": "Validate Stack Sequences", + "pattern": "Stack", + "link": "validate-stack-sequences/", + "video": "mzua0r94kb8", + "difficulty": "Medium", + "code": "0946-validate-stack-sequences", + "kotlin": true, + "python": true + }, + { + "neetcode150": true, + "problem": "Generate Parentheses", + "pattern": "Stack", + "link": "generate-parentheses/", + "video": "s9fokUqJ76A", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0022-generate-parentheses", + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "kotlin": true, + "c": true, + "rust": true, + "swift": true + }, + { + "problem": "Asteroid Collision", + "pattern": "Stack", + "link": "asteroid-collision/", + "video": "LN7KjRszjk4", + "difficulty": "Medium", + "code": "0735-asteroid-collision", + "java": true, + "javascript": true, + "typescript": true, + "rust": true, + "python": true, + "cpp": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Daily Temperatures", + "pattern": "Stack", + "link": "daily-temperatures/", + "video": "cTBiBSnjO3c", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0739-daily-temperatures", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Online Stock Span", + "pattern": "Stack", + "link": "online-stock-span/", + "video": "slYh0ZNEqSw", + "difficulty": "Medium", + "code": "0901-online-stock-span", + "python": true, + "typescript": true, + "rust": true, + "cpp": true, + "java": true, + "javascript": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Car Fleet", + "pattern": "Stack", + "link": "car-fleet/", + "video": "Pr6T-3yB9RM", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0853-car-fleet", + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "kotlin": true, + "rust": true, + "c": true + }, + { + "problem": "Simplify Path", + "pattern": "Stack", + "link": "simplify-path/", + "video": "qYlHrAKJfyA", + "difficulty": "Medium", + "code": "0071-simplify-path", + "python": true, + "typescript": true, + "rust": true, + "java": true, + "kotlin": true, + "javascript": true + }, + { + "problem": "Decode String", + "pattern": "Stack", + "link": "decode-string/", + "video": "qB0zZpBJlh8", + "difficulty": "Medium", + "code": "0394-decode-string", + "python": true, + "typescript": true, + "rust": true, + "scala": true, + "java": true, + "kotlin": true + }, + { + "problem": "Remove K Digits", + "pattern": "Stack", + "link": "remove-k-digits/", + "video": "cFabMOnJaq0", + "difficulty": "Medium", + "code": "0402-remove-k-digits", + "cpp": true, + "javascript": true, + "typescript": true, + "rust": true, + "kotlin": true, + "java": true, + "python": true + }, + { + "problem": "Remove All Adjacent Duplicates In String II", + "pattern": "Stack", + "link": "remove-all-adjacent-duplicates-in-string-ii/", + "video": "w6LcypDgC4w", + "difficulty": "Medium", + "code": "1209-remove-all-adjacent-duplicates-in-string-ii", + "cpp": true, + "python": true, + "javascript": true, + "typescript": true, + "rust": true, + "kotlin": true + }, + { + "problem": "132 Pattern", + "pattern": "Stack", + "link": "132-pattern/", + "video": "q5ANAl8Z458", + "difficulty": "Medium", + "code": "0456-132-pattern", + "python": true, + "cpp": true, + "java": true, + "javascript": true, + "typescript": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Maximum Frequency Stack", + "pattern": "Stack", + "link": "maximum-frequency-stack/", + "video": "Z6idIicFDOE", + "difficulty": "Hard", + "code": "0895-maximum-frequency-stack", + "javascript": true, + "typescript": true, + "rust": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Largest Rectangle In Histogram", + "pattern": "Stack", + "link": "largest-rectangle-in-histogram/", + "video": "zx5Sw9130L0", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0084-largest-rectangle-in-histogram", + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true, + "c": true + }, + { + "neetcode150": true, + "problem": "Binary Search", + "pattern": "Binary Search", + "link": "binary-search/", + "video": "s4DPM8ct1pI", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0704-binary-search", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "dart": true + }, + { + "problem": "Search Insert Position", + "pattern": "Binary Search", + "link": "search-insert-position/", + "video": "K-RYzDZkzCI", + "difficulty": "Easy", + "code": "0035-search-insert-position", + "c": true, + "cpp": true, + "python": true, + "javascript": true, + "swift": true, + "csharp": true, + "java": true, + "go": true, + "kotlin": true, + "typescript": true, + "rust": true + }, + { + "problem": "Guess Number Higher Or Lower", + "pattern": "Binary Search", + "link": "guess-number-higher-or-lower/", + "video": "xW4QsTtaCa4", + "difficulty": "Easy", + "code": "0374-guess-number-higher-or-lower", + "c": true, + "python": true, + "cpp": true, + "java": true, + "javascript": true, + "go": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Arranging Coins", + "pattern": "Binary Search", + "link": "arranging-coins/", + "video": "5rHz_6s2Buw", + "difficulty": "Easy", + "code": "0441-arranging-coins", + "python": true, + "cpp": true, + "kotlin": true, + "java": true, + "javascript": true + }, + { + "problem": "Squares of a Sorted Array", + "pattern": "Binary Search", + "link": "squares-of-a-sorted-array/", + "video": "FPCZsG_AkUg", + "difficulty": "Easy", + "code": "0977-squares-of-a-sorted-array", + "cpp": true, + "python": true, + "javascript": true, + "typescript": true, + "go": true, + "kotlin": true, + "java": true, + "rust": true + }, + { + "problem": "Valid Perfect Square", + "pattern": "Binary Search", + "link": "valid-perfect-square/", + "video": "Cg_wWPHJ2Sk", + "difficulty": "Easy", + "code": "0367-valid-perfect-square", + "python": true, + "javascript": true, + "cpp": true, + "swift": true, + "java": true, + "kotlin": true + }, + { + "problem": "Sqrt(x) ", + "pattern": "Binary Search", + "link": "sqrtx/", + "video": "zdMhGxRWutQ", + "difficulty": "Easy", + "code": "0069-sqrtx", + "kotlin": true, + "c": true, + "cpp": true, + "java": true, + "python": true, + "javascript": true + }, + { + "problem": "Single Element in a Sorted Array", + "pattern": "Binary Search", + "link": "single-element-in-a-sorted-array/", + "video": "HGtqdzyUJ3k", + "difficulty": "Medium", + "code": "0540-single-element-in-a-sorted-array", + "kotlin": true, + "cpp": true, + "java": true, + "python": true, + "javascript": true, + "typescript": true + }, + { + "problem": "Capacity to Ship Packages", + "pattern": "Binary Search", + "link": "capacity-to-ship-packages-within-d-days/", + "video": "ER_oLmdc-nw", + "difficulty": "Medium", + "code": "1011-capacity-to-ship-packages-within-d-days", + "kotlin": true, + "java": true, + "python": true + }, + { + "problem": "Find Peak Element", + "pattern": "Binary Search", + "link": "find-peak-element/", + "video": "kMzJy9es7Hc", + "difficulty": "Medium", + "code": "0162-find-peak-element", + "kotlin": true, + "cpp": true, + "java": true, + "python": true, + "javascript": true + }, + { + "problem": "Successful Pairs of Spells and Potions", + "pattern": "Binary Search", + "link": "successful-pairs-of-spells-and-potions/", + "video": "OKnm5oyAhWg", + "difficulty": "Medium", + "code": "2300-successful-pairs-of-spells-and-potions", + "kotlin": true, + "cpp": true, + "python": true + }, + { + "neetcode150": true, + "problem": "Search a 2D Matrix", + "pattern": "Binary Search", + "link": "search-a-2d-matrix/", + "video": "Ber2pi2C0j0", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0074-search-a-2d-matrix", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Koko Eating Bananas", + "pattern": "Binary Search", + "link": "koko-eating-bananas/", + "video": "U2SozAs9RzA", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0875-koko-eating-bananas", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Minimize the Maximum Difference of Pairs", + "pattern": "Binary Search", + "link": "minimize-the-maximum-difference-of-pairs/", + "video": "lf1Pxg7IrzQ", + "difficulty": "Medium", + "code": "2616-minimize-the-maximum-difference-of-pairs", + "java": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Find Minimum In Rotated Sorted Array", + "pattern": "Binary Search", + "link": "find-minimum-in-rotated-sorted-array/", + "video": "nIVW4P8b1VA", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0153-find-minimum-in-rotated-sorted-array", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "rust": true, + "scala": true, + "ruby": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Search In Rotated Sorted Array", + "pattern": "Binary Search", + "link": "search-in-rotated-sorted-array/", + "video": "U8XENwh8Oy8", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0033-search-in-rotated-sorted-array", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "rust": true, + "scala": true + }, + { + "problem": "Search In Rotated Sorted Array II", + "pattern": "Binary Search", + "link": "search-in-rotated-sorted-array-ii/", + "video": "oUnF7o88_Xc", + "difficulty": "Medium", + "code": "0081-search-in-rotated-sorted-array-ii", + "java": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Time Based Key Value Store", + "pattern": "Binary Search", + "link": "time-based-key-value-store/", + "video": "fu2cD_6E8Hw", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0981-time-based-key-value-store", + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "ruby": true, + "rust": true, + "c": true + }, + { + "problem": "Find First And Last Position of Element In Sorted Array", + "pattern": "Binary Search", + "link": "find-first-and-last-position-of-element-in-sorted-array/", + "video": "4sQL7R5ySUU", + "difficulty": "Medium", + "code": "0034-find-first-and-last-position-of-element-in-sorted-array", + "csharp": true, + "python": true, + "kotlin": true, + "cpp": true, + "java": true, + "swift": true, + "javascript": true + }, + { + "problem": "Maximum Number of Removable Characters", + "pattern": "Binary Search", + "link": "maximum-number-of-removable-characters/", + "video": "NMP3nRPyX5g", + "difficulty": "Medium", + "code": "1898-maximum-number-of-removable-characters", + "javascript": true, + "kotlin": true + }, + { + "problem": "Populating Next Right Pointers In Each Node", + "pattern": "Binary Search", + "link": "populating-next-right-pointers-in-each-node/", + "video": "U4hFQCa1Cq0", + "difficulty": "Medium", + "code": "0116-populating-next-right-pointers-in-each-node", + "go": true, + "cpp": true, + "javascript": true, + "kotlin": true + }, + { + "problem": "Search Suggestions System", + "pattern": "Binary Search", + "link": "search-suggestions-system/", + "video": "D4T2N0yAr20", + "difficulty": "Medium", + "code": "1268-search-suggestions-system", + "java": true, + "javascript": true, + "kotlin": true + }, + { + "problem": "Split Array Largest Sum", + "pattern": "Binary Search", + "link": "split-array-largest-sum/", + "video": "YUF3_eBdzsk", + "difficulty": "Hard", + "code": "0410-split-array-largest-sum", + "python": true, + "javascript": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Median of Two Sorted Arrays", + "pattern": "Binary Search", + "link": "median-of-two-sorted-arrays/", + "video": "q6IEA26hvXc", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0004-median-of-two-sorted-arrays", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Reverse Linked List", + "pattern": "Linked List", + "link": "reverse-linked-list/", + "video": "G0_I-ZF0S38", + "difficulty": "Easy", + "python": true, + "cpp": true, + "javascript": true, + "java": true, + "code": "0206-reverse-linked-list", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "scala": true, + "rust": true, + "dart": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Merge Two Sorted Lists", + "pattern": "Linked List", + "link": "merge-two-sorted-lists/", + "video": "XIdigk956u0", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0021-merge-two-sorted-lists", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "scala": true, + "dart": true, + "rust": true + }, + { + "problem": "Palindrome Linked List", + "pattern": "Linked List", + "link": "palindrome-linked-list/", + "video": "yOzXms1J6Nk", + "difficulty": "Easy", + "code": "0234-palindrome-linked-list", + "cpp": true, + "javascript": true, + "python": true, + "go": true, + "java": true, + "kotlin": true, + "c": true + }, + { + "problem": "Remove Linked List Elements", + "pattern": "Linked List", + "link": "remove-linked-list-elements/", + "video": "JI71sxtHTng", + "difficulty": "Easy", + "code": "0203-remove-linked-list-elements", + "javascript": true, + "typescript": true, + "go": true, + "cpp": true, + "java": true, + "python": true, + "kotlin": true + }, + { + "problem": "Remove Duplicates From Sorted List", + "pattern": "Linked List", + "link": "remove-duplicates-from-sorted-list/", + "video": "p10f-VpO4nE", + "difficulty": "Easy", + "code": "0083-remove-duplicates-from-sorted-list", + "cpp": true, + "python": true, + "javascript": true, + "go": true, + "java": true, + "kotlin": true, + "c": true + }, + { + "problem": "Middle of the Linked List", + "pattern": "Linked List", + "link": "middle-of-the-linked-list/", + "video": "A2_ldqM4QcY", + "difficulty": "Easy", + "python": true, + "code": "0876-middle-of-the-linked-list", + "c": true, + "cpp": true, + "csharp": true, + "java": true, + "javascript": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true, + "swift": true + }, + { + "problem": "Intersection of Two Linked Lists", + "pattern": "Linked List", + "link": "intersection-of-two-linked-lists/", + "video": "D0X0BONOQhI", + "difficulty": "Easy", + "code": "0160-intersection-of-two-linked-lists", + "python": true, + "javascript": true, + "java": true, + "go": true, + "kotlin": true, + "c": true, + "cpp": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Reorder List", + "pattern": "Linked List", + "link": "reorder-list/", + "video": "S5bfdUTrKLM", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0143-reorder-list", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true + }, + { + "problem": "Maximum Twin Sum Of A Linked List", + "pattern": "Linked List", + "link": "maximum-twin-sum-of-a-linked-list/", + "video": "doj95MelfSA", + "difficulty": "Medium", + "code": "2130-maximum-twin-sum-of-a-linked-list", + "python": true, + "java": true, + "kotlin": true, + "cpp": true, + "javascript": true, + "go": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Remove Nth Node From End of List", + "pattern": "Linked List", + "link": "remove-nth-node-from-end-of-list/", + "video": "XVuQxVej6y8", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0019-remove-nth-node-from-end-of-list", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Swapping Nodes in a Linked List", + "pattern": "Linked List", + "link": "swapping-nodes-in-a-linked-list/", + "video": "4LsrgMyQIjQ", + "difficulty": "Medium", + "code": "1721-swapping-nodes-in-a-linked-list", + "kotlin": true, + "cpp": true, + "java": true, + "python": true, + "go": true + }, + { + "problem": "LFU Cache", + "pattern": "Linked List", + "link": "lfu-cache/", + "video": "bLEIHn-DgoA", + "difficulty": "Hard", + "code": "0460-lfu-cache", + "javascript": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Copy List With Random Pointer", + "pattern": "Linked List", + "link": "copy-list-with-random-pointer/", + "video": "5Y2EiZST97Y", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0138-copy-list-with-random-pointer", + "c": true, + "csharp": true, + "typescript": true, + "ruby": true, + "swift": true, + "kotlin": true, + "go": true + }, + { + "problem": "Design Linked List", + "pattern": "Linked List", + "link": "design-linked-list/", + "video": "Wf4QhpdVFQo", + "difficulty": "Medium", + "python": true, + "code": "0707-design-linked-list", + "go": true, + "kotlin": true, + "c": true, + "java": true + }, + { + "problem": "Design Browser History", + "pattern": "Linked List", + "link": "design-browser-history/", + "video": "i1G-kKnBu8k", + "difficulty": "Medium", + "python": true, + "code": "1472-design-browser-history", + "javascript": true, + "typescript": true, + "go": true, + "rust": true, + "java": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Add Two Numbers", + "pattern": "Linked List", + "link": "add-two-numbers/", + "video": "wgFPrzTjm7s", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0002-add-two-numbers", + "c": true, + "csharp": true, + "typescript": true, + "ruby": true, + "swift": true, + "kotlin": true, + "scala": true, + "go": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Linked List Cycle", + "pattern": "Linked List", + "link": "linked-list-cycle/", + "video": "gBTe7lFR3vc", + "difficulty": "Easy", + "python": true, + "cpp": true, + "javascript": true, + "java": true, + "code": "0141-linked-list-cycle", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "scala": true + }, + { + "neetcode150": true, + "problem": "Find The Duplicate Number", + "pattern": "Linked List", + "link": "find-the-duplicate-number/", + "video": "wjYnzkAhcNk", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0287-find-the-duplicate-number", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Swap Nodes In Pairs", + "pattern": "Linked List", + "link": "swap-nodes-in-pairs/", + "video": "o811TZLAWOo", + "difficulty": "Medium", + "code": "0024-swap-nodes-in-pairs", + "python": true, + "go": true, + "java": true, + "kotlin": true, + "c": true, + "cpp": true + }, + { + "problem": "Sort List", + "pattern": "Linked List", + "link": "sort-list/", + "video": "TGveA1oFhrc", + "difficulty": "Medium", + "code": "0148-sort-list", + "java": true, + "python": true, + "c": true, + "cpp": true, + "kotlin": true + }, + { + "problem": "Partition List", + "pattern": "Linked List", + "link": "partition-list/", + "video": "KT1iUciJr4g", + "difficulty": "Medium", + "code": "0086-partition-list", + "python": true, + "java": true, + "kotlin": true + }, + { + "problem": "Rotate List", + "pattern": "Linked List", + "link": "rotate-list/", + "video": "UcGtPs2LE_c", + "difficulty": "Medium", + "code": "0061-rotate-list", + "python": true, + "cpp": true, + "java": true, + "kotlin": true + }, + { + "problem": "Reverse Linked List II", + "pattern": "Linked List", + "link": "reverse-linked-list-ii/", + "video": "RF_M9tX4Eag", + "difficulty": "Medium", + "code": "0092-reverse-linked-list-ii", + "python": true, + "javascript": true, + "cpp": true, + "java": true, + "kotlin": true + }, + { + "problem": "Design Circular Queue", + "pattern": "Linked List", + "link": "design-circular-queue/", + "video": "aBbsfn863oA", + "difficulty": "Medium", + "code": "0622-design-circular-queue", + "python": true, + "go": true, + "kotlin": true, + "java": true + }, + { + "problem": "Insertion Sort List", + "pattern": "Linked List", + "link": "insertion-sort-list/", + "video": "Kk6mXAzqX3Y", + "difficulty": "Medium", + "code": "0147-insertion-sort-list", + "python": true, + "cpp": true, + "kotlin": true + }, + { + "problem": "Split Linked List in Parts", + "pattern": "Linked List", + "link": "split-linked-list-in-parts/", + "video": "-OTlqdrxrVI", + "difficulty": "Medium", + "code": "0725-split-linked-list-in-parts", + "java": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "LRU Cache", + "pattern": "Linked List", + "link": "lru-cache/", + "video": "7ABFKPK2hD4", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0146-lru-cache", + "c": true, + "csharp": true, + "ruby": true, + "kotlin": true, + "go": true, + "typescript": true, + "swift": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Merge K Sorted Lists", + "pattern": "Linked List", + "link": "merge-k-sorted-lists/", + "video": "q5a5OiGbT6Q", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0023-merge-k-sorted-lists", + "c": true, + "csharp": true, + "typescript": true, + "kotlin": true, + "go": true, + "swift": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Reverse Nodes In K Group", + "pattern": "Linked List", + "link": "reverse-nodes-in-k-group/", + "video": "1UOPsfP85V4", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0025-reverse-nodes-in-k-group", + "c": true, + "csharp": true, + "typescript": true, + "kotlin": true, + "go": true, + "swift": true, + "rust": true + }, + { + "problem": "Binary Tree Inorder Traversal", + "pattern": "Trees", + "link": "binary-tree-inorder-traversal/", + "video": "g_S5WuasWUE", + "difficulty": "Easy", + "code": "0094-binary-tree-inorder-traversal", + "c": true, + "python": true, + "javascript": true, + "typescript": true, + "ruby": true, + "csharp": true, + "java": true, + "go": true, + "swift": true, + "kotlin": true, + "rust": true, + "cpp": true + }, + { + "problem": "Binary Tree Preorder Traversal", + "pattern": "Trees", + "link": "binary-tree-preorder-traversal/", + "video": "afTpieEZXck", + "difficulty": "Easy", + "code": "0144-binary-tree-preorder-traversal", + "python": true, + "cpp": true, + "typescript": true, + "kotlin": true + }, + { + "problem": "Binary Tree Postorder Traversal", + "pattern": "Trees", + "link": "binary-tree-postorder-traversal/", + "video": "QhszUQhGGlA", + "difficulty": "Easy", + "code": "0145-binary-tree-postorder-traversal", + "python": true, + "java": true, + "cpp": true, + "typescript": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Invert Binary Tree", + "pattern": "Trees", + "link": "invert-binary-tree/", + "video": "OnSn2XEQ4MY", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0226-invert-binary-tree", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Maximum Depth of Binary Tree", + "pattern": "Trees", + "link": "maximum-depth-of-binary-tree/", + "video": "hTM3phVI6YQ", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0104-maximum-depth-of-binary-tree", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Diameter of Binary Tree", + "pattern": "Trees", + "link": "diameter-of-binary-tree/", + "video": "bkxqA8Rfv04", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0543-diameter-of-binary-tree", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Balanced Binary Tree", + "pattern": "Trees", + "link": "balanced-binary-tree/", + "video": "QfJsau0ItOY", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0110-balanced-binary-tree", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Same Tree", + "pattern": "Trees", + "link": "same-tree/", + "video": "vRbbcKXCxOw", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0100-same-tree", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Subtree of Another Tree", + "pattern": "Trees", + "link": "subtree-of-another-tree/", + "video": "E36O5SWp-LE", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0572-subtree-of-another-tree", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "scala": true, + "rust": true + }, + { + "problem": "Convert Sorted Array to Binary Search Tree", + "pattern": "Trees", + "link": "convert-sorted-array-to-binary-search-tree/", + "video": "0K0uCMYq5ng", + "difficulty": "Easy", + "code": "0108-convert-sorted-array-to-binary-search-tree", + "c": true, + "javascript": true, + "go": true, + "kotlin": true, + "java": true, + "python": true + }, + { + "problem": "Merge Two Binary Trees", + "pattern": "Trees", + "link": "merge-two-binary-trees/", + "video": "QHH6rIK3dDQ", + "difficulty": "Easy", + "code": "0617-merge-two-binary-trees", + "c": true, + "java": true, + "python": true, + "javascript": true, + "go": true, + "dart": true, + "kotlin": true, + "cpp": true + }, + { + "problem": "Path Sum", + "pattern": "Trees", + "link": "path-sum/", + "video": "LSKQyOz_P8I", + "difficulty": "Easy", + "code": "0112-path-sum", + "go": true, + "c": true, + "csharp": true, + "javascript": true, + "swift": true, + "java": true, + "python": true, + "kotlin": true + }, + { + "problem": "Construct String From Binary Tree", + "pattern": "Trees", + "link": "construct-string-from-binary-tree/", + "video": "b1WpYxnuebQ", + "difficulty": "Easy", + "code": "0606-construct-string-from-binary-tree", + "java": true, + "python": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Lowest Common Ancestor of a Binary Search Tree", + "pattern": "Trees", + "link": "lowest-common-ancestor-of-a-binary-search-tree/", + "video": "gs2LMfuOR9k", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0235-lowest-common-ancestor-of-a-binary-search-tree", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "scala": true, + "rust": true + }, + { + "problem": "Insert into a Binary Search Tree", + "pattern": "Trees", + "link": "insert-into-a-binary-search-tree/", + "video": "Cpg8f79luEA", + "difficulty": "Medium", + "python": true, + "code": "0701-insert-into-a-binary-search-tree", + "kotlin": true, + "cpp": true, + "csharp": true, + "java": true, + "typescript": true + }, + { + "problem": "Delete Node in a BST", + "pattern": "Trees", + "link": "delete-node-in-a-bst/", + "video": "LFzAoJJt92M", + "difficulty": "Medium", + "python": true, + "code": "0450-delete-node-in-a-bst", + "kotlin": true, + "cpp": true, + "java": true, + "typescript": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Binary Tree Level Order Traversal", + "pattern": "Trees", + "link": "binary-tree-level-order-traversal/", + "video": "6ZnyEApgFYg", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0102-binary-tree-level-order-traversal", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Binary Tree Right Side View", + "pattern": "Trees", + "link": "binary-tree-right-side-view/", + "video": "d4zLyf32e3I", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0199-binary-tree-right-side-view", + "c": true, + "csharp": true, + "typescript": true, + "swift": true, + "kotlin": true, + "go": true, + "rust": true + }, + { + "problem": "Minimum Distance between BST Nodes", + "pattern": "Trees", + "link": "minimum-distance-between-bst-nodes/", + "video": "joxx4hTYwcw", + "difficulty": "Easy", + "code": "0783-minimum-distance-between-bst-nodes", + "kotlin": true, + "python": true + }, + { + "problem": "Symmetric Tree ", + "pattern": "Trees", + "link": "symmetric-tree/", + "video": "Mao9uzxwvmc", + "difficulty": "Easy", + "code": "0101-symmetric-tree", + "kotlin": true, + "python": true + }, + { + "problem": "Minimum Time to Collect All Apples in a Tree", + "pattern": "Trees", + "link": "minimum-time-to-collect-all-apples-in-a-tree/", + "video": "Xdt5Z583auM", + "difficulty": "Medium", + "code": "1443-minimum-time-to-collect-all-apples-in-a-tree", + "rust": true, + "kotlin": true + }, + { + "problem": "Binary Tree Zigzag Level Order Traversal", + "pattern": "Trees", + "link": "binary-tree-zigzag-level-order-traversal/", + "video": "igbboQbiwqw", + "difficulty": "Medium", + "code": "0103-binary-tree-zigzag-level-order-traversal", + "kotlin": true, + "cpp": true, + "python": true + }, + { + "problem": "Construct Quad Tree", + "pattern": "Trees", + "link": "construct-quad-tree/", + "video": "UQ-1sBMV0v4", + "difficulty": "Medium", + "code": "0427-construct-quad-tree", + "kotlin": true + }, + { + "problem": "Find Duplicate Subtrees", + "pattern": "Trees", + "link": "find-duplicate-subtrees/", + "video": "kn0Z5_qPPzY", + "difficulty": "Medium", + "code": "0652-find-duplicate-subtrees", + "kotlin": true + }, + { + "problem": "Check Completeness of a Binary Tree", + "pattern": "Trees", + "link": "check-completeness-of-a-binary-tree/", + "video": "olbiZ-EOSig", + "difficulty": "Medium", + "code": "0958-check-completeness-of-a-binary-tree", + "kotlin": true, + "cpp": true + }, + { + "problem": "Construct Binary Tree from Inorder and Postorder Traversal", + "pattern": "Trees", + "link": "construct-binary-tree-from-inorder-and-postorder-traversal/", + "video": "vm63HuIU7kw", + "difficulty": "Medium", + "code": "0106-construct-binary-tree-from-inorder-and-postorder-traversal", + "java": true, + "kotlin": true + }, + { + "problem": "Maximum Width of Binary Tree ", + "pattern": "Trees", + "link": "maximum-width-of-binary-tree/", + "video": "FPzLE2L7uHs", + "difficulty": "Medium", + "code": "0662-maximum-width-of-binary-tree", + "java": true, + "kotlin": true + }, + { + "problem": "Time Needed to Inform All Employees ", + "pattern": "Trees", + "link": "time-needed-to-inform-all-employees/", + "video": "zdBYi0p4L5Q", + "difficulty": "Medium", + "code": "1376-time-needed-to-inform-all-employees", + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Count Good Nodes In Binary Tree", + "pattern": "Trees", + "link": "count-good-nodes-in-binary-tree/", + "video": "7cp5imvDzl4", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "1448-count-good-nodes-in-binary-tree", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Validate Binary Search Tree", + "pattern": "Trees", + "link": "validate-binary-search-tree/", + "video": "s6ATEkipzow", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0098-validate-binary-search-tree", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Kth Smallest Element In a Bst", + "pattern": "Trees", + "link": "kth-smallest-element-in-a-bst/", + "video": "5LUXSvjmGCw", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0230-kth-smallest-element-in-a-bst", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "scala": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Construct Binary Tree From Preorder And Inorder Traversal", + "pattern": "Trees", + "link": "construct-binary-tree-from-preorder-and-inorder-traversal/", + "video": "ihj4IQGZ2zc", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0105-construct-binary-tree-from-preorder-and-inorder-traversal", + "c": true, + "csharp": true, + "typescript": true, + "kotlin": true, + "go": true + }, + { + "problem": "Unique Binary Search Trees", + "pattern": "Trees", + "link": "unique-binary-search-trees/", + "video": "Ox0TenN3Zpg", + "difficulty": "Medium", + "code": "0096-unique-binary-search-trees", + "c": true, + "java": true, + "kotlin": true + }, + { + "problem": "Unique Binary Search Trees II", + "pattern": "Trees", + "link": "unique-binary-search-trees-ii/", + "video": "m907FlQa2Yc", + "difficulty": "Medium", + "code": "0095-unique-binary-search-trees-ii", + "kotlin": true + }, + { + "problem": "Sum Root to Leaf Numbers", + "pattern": "Trees", + "link": "sum-root-to-leaf-numbers/", + "video": "Jk16lZGFWxE", + "difficulty": "Medium", + "code": "0129-sum-root-to-leaf-numbers", + "c": true, + "java": true, + "cpp": true, + "kotlin": true + }, + { + "problem": "House Robber III", + "pattern": "Trees", + "link": "house-robber-iii/", + "video": "nHR8ytpzz7c", + "difficulty": "Medium", + "code": "0337-house-robber-iii", + "java": true, + "kotlin": true + }, + { + "problem": "Flip Equivalent Binary Trees", + "pattern": "Trees", + "link": "flip-equivalent-binary-trees/", + "video": "izRDc1il9Pk", + "difficulty": "Medium", + "code": "0951-flip-equivalent-binary-trees", + "java": true, + "kotlin": true + }, + { + "problem": "Operations On Tree", + "pattern": "Trees", + "link": "operations-on-tree/", + "video": "qK4PtjrVD0U", + "difficulty": "Medium", + "code": "1993-operations-on-tree", + "kotlin": true + }, + { + "problem": "All Possible Full Binary Trees", + "pattern": "Trees", + "link": "all-possible-full-binary-trees/", + "video": "nZtrZPTTCAo", + "difficulty": "Medium", + "code": "0894-all-possible-full-binary-trees", + "python": true, + "java": true, + "kotlin": true + }, + { + "problem": "Find Bottom Left Tree Value", + "pattern": "Trees", + "link": "find-bottom-left-tree-value/", + "video": "u_by_cTsNJA", + "difficulty": "Medium", + "code": "0513-find-bottom-left-tree-value", + "java": true, + "kotlin": true + }, + { + "problem": "Trim a Binary Search Tree", + "pattern": "Trees", + "link": "trim-a-binary-search-tree/", + "video": "jwt5mTjEXGc", + "difficulty": "Medium", + "code": "0669-trim-a-binary-search-tree", + "python": true, + "javascript": true, + "typescript": true, + "go": true, + "java": true, + "kotlin": true + }, + { + "problem": "Binary Search Tree Iterator", + "pattern": "Trees", + "link": "binary-search-tree-iterator/", + "video": "RXy5RzGF5wo", + "difficulty": "Medium", + "code": "0173-binary-search-tree-iterator", + "java": true, + "javascript": true, + "kotlin": true + }, + { + "problem": "Convert Bst to Greater Tree", + "pattern": "Trees", + "link": "convert-bst-to-greater-tree/", + "video": "7vVEJwVvAlI", + "difficulty": "Medium", + "code": "0538-convert-bst-to-greater-tree", + "cpp": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Binary Tree Maximum Path Sum", + "pattern": "Trees", + "link": "binary-tree-maximum-path-sum/", + "video": "Hr5cWUld4vU", + "difficulty": "Hard", + "code": "0124-binary-tree-maximum-path-sum", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Serialize And Deserialize Binary Tree", + "pattern": "Trees", + "link": "serialize-and-deserialize-binary-tree/", + "video": "u4JAi2JJhI8", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0297-serialize-and-deserialize-binary-tree", + "c": true, + "csharp": true, + "kotlin": true, + "go": true, + "typescript": true, + "swift": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Implement Trie Prefix Tree", + "pattern": "Tries", + "link": "implement-trie-prefix-tree/", + "video": "oobqoCJlHA0", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0208-implement-trie-prefix-tree", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "scala": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Design Add And Search Words Data Structure", + "pattern": "Tries", + "link": "design-add-and-search-words-data-structure/", + "video": "BTf05gs_8iU", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0211-design-add-and-search-words-data-structure", + "csharp": true, + "typescript": true, + "ruby": true, + "kotlin": true, + "rust": true, + "go": true, + "c": true, + "scala": true + }, + { + "problem": "Extra Characters in a String", + "pattern": "Tries", + "link": "extra-characters-in-a-string/", + "video": "ONstwO1cD7c", + "difficulty": "Medium", + "code": "2707-extra-characters-in-a-string", + "cpp": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Word Search II", + "pattern": "Tries", + "link": "word-search-ii/", + "video": "asbcE9mZz_U", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0212-word-search-ii", + "csharp": true, + "swift": true, + "kotlin": true, + "rust": true, + "go": true, + "c": true + }, + { + "neetcode150": true, + "problem": "Kth Largest Element In a Stream", + "pattern": "Heap / Priority Queue", + "link": "kth-largest-element-in-a-stream/", + "video": "hOjcdrqMoQ8", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0703-kth-largest-element-in-a-stream", + "c": true, + "csharp": true, + "ruby": true, + "swift": true, + "go": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Last Stone Weight", + "pattern": "Heap / Priority Queue", + "link": "last-stone-weight/", + "video": "B-QCq79-Vfw", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "1046-last-stone-weight", + "csharp": true, + "typescript": true, + "ruby": true, + "kotlin": true, + "go": true, + "rust": true, + "c": true + }, + { + "neetcode150": true, + "problem": "K Closest Points to Origin", + "pattern": "Heap / Priority Queue", + "link": "k-closest-points-to-origin/", + "video": "rI2EBUEMfTk", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0973-k-closest-points-to-origin", + "csharp": true, + "kotlin": true, + "go": true, + "rust": true, + "c": true + }, + { + "neetcode150": true, + "problem": "Kth Largest Element In An Array", + "pattern": "Heap / Priority Queue", + "link": "kth-largest-element-in-an-array/", + "video": "XEmy13g1Qxc", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0215-kth-largest-element-in-an-array", + "csharp": true, + "typescript": true, + "kotlin": true, + "go": true, + "scala": true, + "c": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Task Scheduler", + "pattern": "Heap / Priority Queue", + "link": "task-scheduler/", + "video": "s8p8ukTyA2I", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0621-task-scheduler", + "csharp": true, + "typescript": true, + "kotlin": true, + "rust": true, + "c": true + }, + { + "neetcode150": true, + "problem": "Design Twitter", + "pattern": "Heap / Priority Queue", + "link": "design-twitter/", + "video": "pNichitDD2E", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0355-design-twitter", + "csharp": true, + "go": true, + "kotlin": true + }, + { + "problem": "Minimize Deviation in Array", + "pattern": "Heap / Priority Queue", + "link": "minimize-deviation-in-array/", + "video": "boHNFptxo2A", + "difficulty": "Hard", + "code": "1675-minimize-deviation-in-array", + "kotlin": true, + "cpp": true + }, + { + "problem": "Maximum Subsequence Score", + "pattern": "Heap / Priority Queue", + "link": "maximum-subsequence-score/", + "video": "ax1DKi5lJwk", + "difficulty": "Medium", + "code": "2542-maximum-subsequence-score", + "kotlin": true, + "cpp": true + }, + { + "problem": "Single Threaded Cpu", + "pattern": "Heap / Priority Queue", + "link": "single-threaded-cpu/", + "video": "RR1n-d4oYqE", + "difficulty": "Medium", + "code": "1834-single-threaded-cpu", + "java": true, + "python": true, + "javascript": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Seat Reservation Manager", + "pattern": "Heap / Priority Queue", + "link": "seat-reservation-manager/", + "video": "ahobllKXEEY", + "difficulty": "Medium", + "code": "1845-seat-reservation-manager", + "python": true, + "cpp": true, + "kotlin": true + }, + { + "problem": "Process Tasks Using Servers", + "pattern": "Heap / Priority Queue", + "link": "process-tasks-using-servers/", + "video": "XKA22PecuMQ", + "difficulty": "Medium", + "code": "1882-process-tasks-using-servers", + "kotlin": true + }, + { + "problem": "Find The Kth Largest Integer In The Array", + "pattern": "Heap / Priority Queue", + "link": "find-the-kth-largest-integer-in-the-array/", + "video": "lRCaNiqO3xI", + "difficulty": "Medium", + "code": "1985-find-the-kth-largest-integer-in-the-array", + "java": true, + "python": true, + "swift": true, + "cpp": true, + "go": true, + "kotlin": true + }, + { + "problem": "Reorganize String", + "pattern": "Heap / Priority Queue", + "link": "reorganize-string/", + "video": "2g_b1aYTHeg", + "difficulty": "Medium", + "code": "0767-reorganize-string", + "java": true, + "python": true, + "cpp": true, + "kotlin": true + }, + { + "problem": "Longest Happy String", + "pattern": "Heap / Priority Queue", + "link": "longest-happy-string/", + "video": "8u-H6O_XQKE", + "difficulty": "Medium", + "code": "1405-longest-happy-string", + "kotlin": true + }, + { + "problem": "Car Pooling", + "pattern": "Heap / Priority Queue", + "link": "car-pooling/", + "video": "08sn_w4LWEE", + "difficulty": "Medium", + "code": "1094-car-pooling", + "csharp": true, + "cpp": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Find Median From Data Stream", + "pattern": "Heap / Priority Queue", + "link": "find-median-from-data-stream/", + "video": "itmhHWaHupI", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0295-find-median-from-data-stream", + "csharp": true, + "kotlin": true, + "go": true, + "typescript": true + }, + { + "problem": "Maximum Performance of a Team", + "pattern": "Heap / Priority Queue", + "link": "maximum-performance-of-a-team/", + "video": "Y7UTvogADH0", + "difficulty": "Hard", + "code": "1383-maximum-performance-of-a-team", + "csharp": true, + "python": true, + "kotlin": true + }, + { + "problem": "IPO", + "pattern": "Heap / Priority Queue", + "link": "ipo/", + "video": "1IUzNJ6TPEM", + "difficulty": "Hard", + "code": "0502-ipo", + "python": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Subsets", + "pattern": "Backtracking", + "link": "subsets/", + "video": "REOH22Xwdkk", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0078-subsets", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Combination Sum", + "pattern": "Backtracking", + "link": "combination-sum/", + "video": "GBKI9VSKdGg", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0039-combination-sum", + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "ruby": true, + "rust": true, + "c": true, + "swift": true + }, + { + "problem": "Combinations", + "pattern": "Backtracking", + "link": "combinations/", + "video": "q0s6m7AiM7o", + "difficulty": "Medium", + "code": "0077-combinations", + "python": true, + "go": true, + "kotlin": true, + "java": true + }, + { + "neetcode150": true, + "problem": "Permutations", + "pattern": "Backtracking", + "link": "permutations/", + "video": "s7AvT7cGdSo", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0046-permutations", + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "ruby": true, + "rust": true, + "c": true + }, + { + "neetcode150": true, + "problem": "Subsets II", + "pattern": "Backtracking", + "link": "subsets-ii/", + "video": "Vn2v6ajA7U0", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0090-subsets-ii", + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "ruby": true, + "rust": true, + "c": true + }, + { + "neetcode150": true, + "problem": "Combination Sum II", + "pattern": "Backtracking", + "link": "combination-sum-ii/", + "video": "rSA3t6BDDwg", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0040-combination-sum-ii", + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "ruby": true, + "c": true + }, + { + "problem": "Permutations II", + "pattern": "Backtracking", + "link": "permutations-ii/", + "video": "qhBVWf0YafA", + "difficulty": "Medium", + "code": "0047-permutations-ii", + "python": true, + "go": true, + "kotlin": true, + "java": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Word Search", + "pattern": "Backtracking", + "link": "word-search/", + "video": "pfiQ_PS1g8E", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0079-word-search", + "c": true, + "csharp": true, + "go": true, + "swift": true, + "kotlin": true, + "rust": true, + "ruby": true + }, + { + "neetcode150": true, + "problem": "Palindrome Partitioning", + "pattern": "Backtracking", + "link": "palindrome-partitioning/", + "video": "3jvWodd7ht0", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0131-palindrome-partitioning", + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "rust": true, + "swift": true, + "kotlin": true + }, + { + "problem": "Restore IP Addresses", + "pattern": "Backtracking", + "link": "restore-ip-addresses/", + "video": "61tN4YEdiTM", + "difficulty": "Medium", + "code": "0093-restore-ip-addresses", + "javascript": true, + "typescript": true, + "go": true, + "rust": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Letter Combinations of a Phone Number", + "pattern": "Backtracking", + "link": "letter-combinations-of-a-phone-number/", + "video": "0snEunUacZY", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0017-letter-combinations-of-a-phone-number", + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "rust": true, + "kotlin": true, + "swift": true + }, + { + "problem": "Matchsticks to Square", + "pattern": "Backtracking", + "link": "matchsticks-to-square/", + "video": "hUe0cUKV-YY", + "difficulty": "Medium", + "code": "0473-matchsticks-to-square", + "cpp": true, + "python": true, + "javascript": true, + "java": true, + "kotlin": true + }, + { + "problem": "Splitting a String Into Descending Consecutive Values", + "pattern": "Backtracking", + "link": "splitting-a-string-into-descending-consecutive-values/", + "video": "eDtMmysldaw", + "difficulty": "Medium", + "code": "1849-splitting-a-string-into-descending-consecutive-values", + "python": true, + "cpp": true, + "kotlin": true + }, + { + "problem": "Find Unique Binary String", + "pattern": "Backtracking", + "link": "find-unique-binary-string/", + "video": "aHqn4Dynd1k", + "difficulty": "Medium", + "code": "1980-find-unique-binary-string", + "python": true, + "kotlin": true, + "java": true + }, + { + "problem": "Maximum Length of a Concatenated String With Unique Characters", + "pattern": "Backtracking", + "link": "maximum-length-of-a-concatenated-string-with-unique-characters/", + "video": "d4SPuvkaeoo", + "difficulty": "Medium", + "code": "1239-maximum-length-of-a-concatenated-string-with-unique-characters", + "python": true, + "kotlin": true + }, + { + "problem": "Partition to K Equal Sum Subsets", + "pattern": "Backtracking", + "link": "partition-to-k-equal-sum-subsets/", + "video": "mBk4I0X46oI", + "difficulty": "Medium", + "code": "0698-partition-to-k-equal-sum-subsets", + "kotlin": true, + "python": true, + "java": true + }, + { + "neetcode150": true, + "problem": "N Queens", + "pattern": "Backtracking", + "link": "n-queens/", + "video": "Ph95IHmRp5M", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0051-n-queens", + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "c": true, + "rust": true + }, + { + "problem": "N Queens II", + "pattern": "Backtracking", + "link": "n-queens-ii/", + "video": "nalYyLZgvCY", + "difficulty": "Hard", + "code": "0052-n-queens-ii", + "c": true, + "cpp": true, + "javascript": true, + "python": true, + "kotlin": true + }, + { + "problem": "Island Perimeter", + "pattern": "Graphs", + "link": "island-perimeter/", + "video": "fISIuAFRM2s", + "difficulty": "Easy", + "code": "0463-island-perimeter", + "c": true, + "cpp": true, + "csharp": true, + "python": true, + "java": true, + "javascript": true, + "go": true, + "kotlin": true + }, + { + "problem": "Verifying An Alien Dictionary", + "pattern": "Graphs", + "link": "verifying-an-alien-dictionary/", + "video": "OVgPAJIyX6o", + "difficulty": "Easy", + "code": "0953-verifying-an-alien-dictionary", + "c": true, + "cpp": true, + "java": true, + "python": true, + "javascript": true, + "go": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Number of Islands", + "pattern": "Graphs", + "link": "number-of-islands/", + "video": "pV2kpPD66nE", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0200-number-of-islands", + "c": true, + "csharp": true, + "typescript": true, + "ruby": true, + "swift": true, + "kotlin": true, + "go": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Clone Graph", + "pattern": "Graphs", + "link": "clone-graph/", + "video": "mQeF6bN8hMk", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0133-clone-graph", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Max Area of Island", + "pattern": "Graphs", + "link": "max-area-of-island/", + "video": "iJGr1OtmH0c", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0695-max-area-of-island", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Count Sub Islands", + "pattern": "Graphs", + "link": "count-sub-islands/", + "video": "mLpW3qfbNJ8", + "difficulty": "Medium", + "code": "1905-count-sub-islands", + "c": true, + "csharp": true, + "python": true, + "cpp": true, + "java": true, + "javascript": true, + "go": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Pacific Atlantic Water Flow", + "pattern": "Graphs", + "link": "pacific-atlantic-water-flow/", + "video": "s-VkcjHqkGI", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0417-pacific-atlantic-water-flow", + "c": true, + "csharp": true, + "kotlin": true, + "typescript": true, + "go": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Surrounded Regions", + "pattern": "Graphs", + "link": "surrounded-regions/", + "video": "9z2BunfoZ5Y", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0130-surrounded-regions", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true + }, + { + "problem": "Reorder Routes to Make All Paths Lead to The City Zero", + "pattern": "Graphs", + "link": "reorder-routes-to-make-all-paths-lead-to-the-city-zero/", + "video": "m17yOR5_PpI", + "difficulty": "Medium", + "code": "1466-reorder-routes-to-make-all-paths-lead-to-the-city-zero", + "csharp": true, + "cpp": true, + "kotlin": true, + "java": true + }, + { + "neetcode150": true, + "problem": "Rotting Oranges", + "pattern": "Graphs", + "link": "rotting-oranges/", + "video": "y704fEOx0s0", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0994-rotting-oranges", + "c": true, + "csharp": true, + "typescript": true, + "kotlin": true, + "go": true + }, + { + "neetcode150": true, + "problem": "Walls And Gates", + "premium": true, + "freeLink": "https://www.lintcode.com/problem/663/", + "pattern": "Graphs", + "link": "walls-and-gates/", + "video": "e69C6xhiSQE", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0286-walls-and-gates", + "csharp": true + }, + { + "problem": "Snakes And Ladders", + "pattern": "Graphs", + "link": "snakes-and-ladders/", + "video": "6lH4nO3JfLk", + "difficulty": "Medium", + "code": "0909-snakes-and-ladders", + "csharp": true, + "python": true, + "java": true, + "kotlin": true + }, + { + "problem": "Open The Lock", + "pattern": "Graphs", + "link": "open-the-lock/", + "video": "Pzg3bCDY87w", + "difficulty": "Medium", + "code": "0752-open-the-lock", + "csharp": true, + "java": true, + "python": true, + "kotlin": true + }, + { + "problem": "Find Eventual Safe States", + "pattern": "Graphs", + "link": "find-eventual-safe-states/", + "video": "Re_v0j0CRsg", + "difficulty": "Medium", + "code": "0802-find-eventual-safe-states", + "kotlin": true, + "java": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Course Schedule", + "pattern": "Graphs", + "link": "course-schedule/", + "video": "EgI5nU9etnU", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0207-course-schedule", + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "c": true + }, + { + "neetcode150": true, + "problem": "Course Schedule II", + "pattern": "Graphs", + "link": "course-schedule-ii/", + "video": "Akt3glAwyfY", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0210-course-schedule-ii", + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true + }, + { + "problem": "Course Schedule IV", + "pattern": "Graphs", + "link": "course-schedule-iv/", + "video": "cEW05ofxhn0", + "difficulty": "Medium", + "python": true, + "code": "1462-course-schedule-iv", + "kotlin": true + }, + { + "problem": "Check if Move Is Legal", + "pattern": "Graphs", + "link": "check-if-move-is-legal/", + "video": "KxK33AcQZpQ", + "difficulty": "Medium", + "code": "1958-check-if-move-is-legal", + "cpp": true, + "java": true, + "python": true, + "javascript": true, + "go": true, + "kotlin": true + }, + { + "problem": "Shortest Bridge", + "pattern": "Graphs", + "link": "shortest-bridge/", + "video": "gkINMhbbIbU", + "difficulty": "Medium", + "code": "0934-shortest-bridge", + "kotlin": true, + "javascript": true + }, + { + "problem": "Shortest Path in Binary Matrix", + "pattern": "Graphs", + "video": "YnxUdAO7TAo", + "link": "shortest-path-in-binary-matrix/", + "difficulty": "Medium", + "code": "1091-shortest-path-in-binary-matrix", + "python": true, + "java": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Redundant Connection", + "pattern": "Graphs", + "link": "redundant-connection/", + "video": "FXWRE67PLL0", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0684-redundant-connection", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Number of Connected Components In An Undirected Graph", + "premium": true, + "freeLink": "https://www.lintcode.com/problem/3651/", + "pattern": "Graphs", + "link": "number-of-connected-components-in-an-undirected-graph/", + "video": "8f1XPm4WOUc", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0323-number-of-connected-components-in-an-undirected-graph", + "csharp": true, + "go": true, + "swift": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Graph Valid Tree", + "premium": true, + "freeLink": "https://www.lintcode.com/problem/178/", + "pattern": "Graphs", + "link": "graph-valid-tree/", + "video": "bXsUuownnoQ", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0261-graph-valid-tree", + "csharp": true, + "typescript": true, + "swift": true + }, + { + "problem": "Accounts Merge", + "pattern": "Graphs", + "link": "accounts-merge/", + "video": "6st4IxEF-90", + "difficulty": "Medium", + "code": "0721-accounts-merge", + "python": true, + "kotlin": true, + "java": true + }, + { + "problem": "Find Closest Node to Given Two Nodes", + "pattern": "Graphs", + "link": "find-closest-node-to-given-two-nodes/", + "video": "AZA8orksO4w", + "difficulty": "Medium", + "code": "2359-find-closest-node-to-given-two-nodes", + "kotlin": true + }, + { + "problem": "As Far from Land as Possible", + "pattern": "Graphs", + "link": "as-far-from-land-as-possible/", + "video": "fjxb1hQfrZk", + "difficulty": "Medium", + "code": "1162-as-far-from-land-as-possible", + "kotlin": true + }, + { + "problem": "Shortest Path with Alternating Colors", + "pattern": "Graphs", + "link": "shortest-path-with-alternating-colors/", + "video": "69rcy6lb-HQ", + "difficulty": "Medium", + "code": "1129-shortest-path-with-alternating-colors", + "kotlin": true + }, + { + "problem": "Minimum Fuel Cost to Report to the Capital", + "pattern": "Graphs", + "link": "minimum-fuel-cost-to-report-to-the-capital/", + "video": "I3lnDUIzIG4", + "difficulty": "Medium", + "code": "2477-minimum-fuel-cost-to-report-to-the-capital", + "kotlin": true, + "java": true + }, + { + "problem": "Minimum Score of a Path Between Two Cities", + "pattern": "Graphs", + "link": "minimum-score-of-a-path-between-two-cities/", + "video": "K7-mXA0irhY", + "difficulty": "Medium", + "code": "2492-minimum-score-of-a-path-between-two-cities", + "kotlin": true + }, + { + "problem": "Number of Closed Islands", + "pattern": "Graphs", + "link": "number-of-closed-islands/", + "video": "X8k48xek8g8", + "difficulty": "Medium", + "code": "1254-number-of-closed-islands", + "kotlin": true + }, + { + "problem": "Number of Enclaves", + "pattern": "Graphs", + "link": "number-of-enclaves/", + "video": "gf0zsh1FIgE", + "difficulty": "Medium", + "code": "1020-number-of-enclaves", + "kotlin": true, + "java": true + }, + { + "problem": "Minimum Number of Vertices to Reach all Nodes", + "pattern": "Graphs", + "link": "minimum-number-of-vertices-to-reach-all-nodes/", + "video": "TLzcum7vrTc", + "difficulty": "Medium", + "code": "1557-minimum-number-of-vertices-to-reach-all-nodes", + "java": true, + "kotlin": true + }, + { + "problem": "Is Graph Bipartite?", + "pattern": "Graphs", + "link": "is-graph-bipartite/", + "video": "mev55LTubBY", + "difficulty": "Medium", + "code": "0785-is-graph-bipartite", + "kotlin": true, + "java": true + }, + { + "problem": "Evaluate Division", + "pattern": "Graphs", + "link": "evaluate-division/", + "video": "Uei1fwDoyKk", + "difficulty": "Medium", + "code": "0399-evaluate-division", + "kotlin": true, + "cpp": true + }, + { + "problem": "Detonate the Maximum Bombs", + "pattern": "Graphs", + "link": "detonate-the-maximum-bombs/", + "video": "8NPbAvVXKR4", + "difficulty": "Medium", + "code": "2101-detonate-the-maximum-bombs", + "kotlin": true + }, + { + "problem": "Largest Color Value in a Directed Graph", + "pattern": "Graphs", + "link": "largest-color-value-in-a-directed-graph/", + "video": "xLoDjKczUSk", + "difficulty": "Hard", + "code": "1857-largest-color-value-in-a-directed-graph", + "kotlin": true + }, + { + "problem": "Minimum Number of Days to Eat N Oranges", + "pattern": "Graphs", + "link": "minimum-number-of-days-to-eat-n-oranges/", + "video": "LziQ6Qx9sks", + "difficulty": "Hard", + "code": "1553-minimum-number-of-days-to-eat-n-oranges", + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Word Ladder", + "pattern": "Graphs", + "link": "word-ladder/", + "video": "h9iTnkgv05E", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0127-word-ladder", + "csharp": true, + "typescript": true, + "kotlin": true, + "go": true, + "rust": true + }, + { + "problem": "Path with Minimum Effort", + "pattern": "Advanced Graphs", + "link": "path-with-minimum-effort/", + "video": "XQlxCCx2vI4", + "difficulty": "Medium", + "code": "1631-path-with-minimum-effort", + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Reconstruct Itinerary", + "pattern": "Advanced Graphs", + "link": "reconstruct-itinerary/", + "video": "ZyB_gQ8vqGA", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0332-reconstruct-itinerary", + "csharp": true, + "kotlin": true, + "go": true, + "c": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Min Cost to Connect All Points", + "pattern": "Advanced Graphs", + "link": "min-cost-to-connect-all-points/", + "video": "f7JOBJIC-NA", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "1584-min-cost-to-connect-all-points", + "csharp": true, + "ruby": true, + "swift": true, + "go": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Network Delay Time", + "pattern": "Advanced Graphs", + "link": "network-delay-time/", + "video": "EaphyqKU4PQ", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0743-network-delay-time", + "csharp": true, + "go": true, + "kotlin": true + }, + { + "problem": "Path with Maximum Probability", + "pattern": "Advanced Graphs", + "link": "path-with-maximum-probability/", + "video": "kPsDTGcrzGM", + "difficulty": "Medium", + "python": true, + "code": "1514-path-with-maximum-probability", + "java": true, + "javascript": true, + "kotlin": true, + "cpp": true + }, + { + "neetcode150": true, + "problem": "Swim In Rising Water", + "pattern": "Advanced Graphs", + "link": "swim-in-rising-water/", + "video": "amvrKlMLuGY", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0778-swim-in-rising-water", + "csharp": true, + "go": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Alien Dictionary", + "premium": true, + "freeLink": "https://www.lintcode.com/problem/892/", + "pattern": "Advanced Graphs", + "link": "alien-dictionary/", + "video": "6kTZYvNNyps", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0269-alien-dictionary", + "csharp": true + }, + { + "neetcode150": true, + "problem": "Cheapest Flights Within K Stops", + "pattern": "Advanced Graphs", + "link": "cheapest-flights-within-k-stops/", + "video": "5eIK3zUdYmE", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0787-cheapest-flights-within-k-stops", + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true + }, + { + "problem": "Number of Good Paths", + "pattern": "Advanced Graphs", + "link": "number-of-good-paths/", + "video": "rv2GBYQm7xM", + "difficulty": "Hard", + "code": "2421-number-of-good-paths", + "javascript": true, + "typescript": true, + "go": true, + "rust": true, + "kotlin": true + }, + { + "problem": "Remove Max Number of Edges to Keep Graph Fully Traversable", + "pattern": "Advanced Graphs", + "link": "remove-max-number-of-edges-to-keep-graph-fully-traversable/", + "video": "booGwg5wYm4", + "difficulty": "Hard", + "code": "1579-remove-max-number-of-edges-to-keep-graph-fully-traversable", + "kotlin": true + }, + { + "problem": "Find Critical and Pseudo Critical Edges in Minimum Spanning Tree", + "pattern": "Advanced Graphs", + "link": "find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree/", + "video": "83JnUxrLKJU", + "difficulty": "Hard", + "code": "1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree", + "python": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Climbing Stairs", + "pattern": "1-D Dynamic Programming", + "link": "climbing-stairs/", + "video": "Y0lT9Fck7qI", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0070-climbing-stairs", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "dart": true + }, + { + "neetcode150": true, + "problem": "Min Cost Climbing Stairs", + "pattern": "1-D Dynamic Programming", + "link": "min-cost-climbing-stairs/", + "code": "0746-min-cost-climbing-stairs", + "video": "ktmzAZWkEZ0", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "scala": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "House Robber", + "pattern": "1-D Dynamic Programming", + "link": "house-robber/", + "video": "73r3KWiEvyk", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0198-house-robber", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "scala": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "House Robber II", + "pattern": "1-D Dynamic Programming", + "link": "house-robber-ii/", + "video": "rWAJCfYYOvM", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0213-house-robber-ii", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "scala": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Longest Palindromic Substring", + "pattern": "1-D Dynamic Programming", + "link": "longest-palindromic-substring/", + "video": "XYQecbcd6_c", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0005-longest-palindromic-substring", + "c": true, + "csharp": true, + "typescript": true, + "rust": true, + "go": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Palindromic Substrings", + "pattern": "1-D Dynamic Programming", + "link": "palindromic-substrings/", + "video": "4RACzI5-du8", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0647-palindromic-substrings", + "c": true, + "csharp": true, + "typescript": true, + "rust": true, + "go": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Decode Ways", + "pattern": "1-D Dynamic Programming", + "link": "decode-ways/", + "video": "6aEyTjOwlJU", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0091-decode-ways", + "c": true, + "csharp": true, + "typescript": true, + "kotlin": true, + "scala": true, + "go": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Coin Change", + "pattern": "1-D Dynamic Programming", + "link": "coin-change/", + "video": "H9bfqozjoqs", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0322-coin-change", + "c": true, + "csharp": true, + "typescript": true, + "kotlin": true, + "rust": true, + "go": true, + "scala": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Maximum Product Subarray", + "pattern": "1-D Dynamic Programming", + "link": "maximum-product-subarray/", + "video": "lXVy6YWFcRM", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0152-maximum-product-subarray", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Word Break", + "pattern": "1-D Dynamic Programming", + "link": "word-break/", + "video": "Sx9NNgInc3A", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0139-word-break", + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Longest Increasing Subsequence", + "pattern": "1-D Dynamic Programming", + "link": "longest-increasing-subsequence/", + "video": "cjWnW0hdF1Y", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0300-longest-increasing-subsequence", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Partition Equal Subset Sum", + "pattern": "1-D Dynamic Programming", + "link": "partition-equal-subset-sum/", + "video": "IsvocB5BJhw", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0416-partition-equal-subset-sum", + "csharp": true, + "go": true, + "kotlin": true, + "c": true + }, + { + "problem": "Triangle", + "pattern": "1-D Dynamic Programming", + "link": "triangle/", + "video": "OM1MTokvxs4", + "difficulty": "Medium", + "code": "0120-triangle", + "cpp": true, + "java": true, + "python": true, + "kotlin": true, + "c": true + }, + { + "problem": "Delete And Earn", + "pattern": "1-D Dynamic Programming", + "link": "delete-and-earn/", + "video": "7FCemBxvGw0", + "difficulty": "Medium", + "code": "0740-delete-and-earn", + "python": true, + "go": true, + "kotlin": true, + "c": true, + "cpp": true + }, + { + "problem": "Paint House", + "pattern": "1-D Dynamic Programming", + "link": "paint-house/", + "video": "-w67-4tnH5U", + "difficulty": "Medium", + "code": "0256-paint-house", + "csharp": true + }, + { + "problem": "Combination Sum IV", + "pattern": "1-D Dynamic Programming", + "link": "combination-sum-iv/", + "video": "dw2nMCxG0ik", + "difficulty": "Medium", + "code": "0377-combination-sum-iv", + "python": true, + "cpp": true, + "kotlin": true, + "c": true, + "java": true + }, + { + "problem": "Perfect Squares", + "pattern": "1-D Dynamic Programming", + "link": "perfect-squares/", + "video": "HLZLwjzIVGo", + "difficulty": "Medium", + "code": "0279-perfect-squares", + "java": true, + "go": true, + "cpp": true, + "kotlin": true, + "c": true + }, + { + "problem": "Check if There is a Valid Partition For The Array", + "pattern": "1-D Dynamic Programming", + "link": "check-if-there-is-a-valid-partition-for-the-array/", + "video": "OxXPiwWFdTI", + "difficulty": "Medium", + "code": "2369-check-if-there-is-a-valid-partition-for-the-array", + "kotlin": true + }, + { + "problem": "Maximum Subarray Min Product", + "pattern": "1-D Dynamic Programming", + "link": "maximum-subarray-min-product/", + "video": "YLesLbNkyjA", + "difficulty": "Medium", + "code": "1856-maximum-subarray-min-product", + "kotlin": true, + "c": true, + "java": true + }, + { + "problem": "Minimum Cost For Tickets", + "pattern": "1-D Dynamic Programming", + "link": "minimum-cost-for-tickets/", + "video": "4pY1bsBpIY4", + "difficulty": "Medium", + "code": "0983-minimum-cost-for-tickets", + "cpp": true, + "kotlin": true, + "c": true + }, + { + "problem": "Integer Break", + "pattern": "1-D Dynamic Programming", + "link": "integer-break/", + "video": "in6QbUPMJ3I", + "difficulty": "Medium", + "code": "0343-integer-break", + "cpp": true, + "kotlin": true, + "c": true, + "java": true + }, + { + "problem": "Number of Longest Increasing Subsequence", + "pattern": "1-D Dynamic Programming", + "link": "number-of-longest-increasing-subsequence/", + "video": "Tuc-rjJbsXU", + "difficulty": "Medium", + "code": "0673-number-of-longest-increasing-subsequence", + "python": true, + "kotlin": true, + "c": true + }, + { + "problem": "Stickers to Spell Word", + "pattern": "1-D Dynamic Programming", + "link": "stickers-to-spell-word/", + "video": "hsomLb6mUdI", + "difficulty": "Hard", + "code": "0691-stickers-to-spell-word", + "c": true, + "kotlin": true + }, + { + "problem": "N-th Tribonacci Number", + "pattern": "1-D Dynamic Programming", + "link": "n-th-tribonacci-number/", + "video": "3lpNp5Ojvrw", + "difficulty": "Easy", + "code": "1137-n-th-tribonacci-number", + "python": true, + "javascript": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true, + "c": true, + "cpp": true + }, + { + "problem": "Uncrossed Lines", + "pattern": "1-D Dynamic Programming", + "link": "uncrossed-lines/", + "video": "mnJF4vJ7GyE", + "difficulty": "Medium", + "code": "1035-uncrossed-lines", + "kotlin": true, + "c": true + }, + { + "problem": "Solving Questions With Brainpower", + "pattern": "1-D Dynamic Programming", + "link": "solving-questions-with-brainpower/", + "video": "D7TD_ArkfkA", + "difficulty": "Medium", + "code": "2140-solving-questions-with-brainpower", + "kotlin": true, + "c": true, + "cpp": true + }, + { + "problem": "Count Ways to Build Good Strings", + "pattern": "1-D Dynamic Programming", + "link": "count-ways-to-build-good-strings/", + "video": "JKpVHG2mhbk", + "difficulty": "Medium", + "code": "2466-count-ways-to-build-good-strings", + "kotlin": true, + "c": true + }, + { + "problem": "New 21 Game", + "pattern": "1-D Dynamic Programming", + "link": "new-21-game/", + "video": "zKi4LzjK27k", + "difficulty": "Medium", + "code": "0837-new-21-game", + "kotlin": true, + "c": true, + "javascript": true + }, + { + "problem": "Best Team with no Conflicts", + "pattern": "1-D Dynamic Programming", + "link": "best-team-with-no-conflicts/", + "video": "7kURH3btcV4", + "difficulty": "Medium", + "code": "1626-best-team-with-no-conflicts", + "c": true, + "kotlin": true + }, + { + "problem": "Stone Game III", + "pattern": "1-D Dynamic Programming", + "link": "stone-game-iii/", + "video": "HsLG5QW9CFQ", + "difficulty": "Hard", + "code": "1406-stone-game-iii", + "kotlin": true, + "c": true + }, + { + "problem": "Concatenated Words", + "pattern": "1-D Dynamic Programming", + "link": "concatenated-words/", + "video": "iHp7fjw1R28", + "difficulty": "Hard", + "code": "0472-concatenated-words", + "javascript": true, + "typescript": true, + "go": true, + "rust": true, + "kotlin": true + }, + { + "problem": "Maximize Score after N Operations", + "pattern": "1-D Dynamic Programming", + "link": "maximize-score-after-n-operations/", + "video": "RRQVDqp5RSE", + "difficulty": "Hard", + "code": "1799-maximize-score-after-n-operations", + "kotlin": true, + "c": true + }, + { + "problem": "Find the Longest Valid Obstacle Course at Each Position", + "pattern": "1-D Dynamic Programming", + "link": "find-the-longest-valid-obstacle-course-at-each-position/", + "video": "Xq9VT7p0lic", + "difficulty": "Hard", + "code": "1964-find-the-longest-valid-obstacle-course-at-each-position", + "kotlin": true, + "c": true + }, + { + "problem": "Count all Valid Pickup and Delivery Options", + "pattern": "1-D Dynamic Programming", + "link": "count-all-valid-pickup-and-delivery-options/", + "video": "OpgslsirW8s", + "difficulty": "Hard", + "code": "1359-count-all-valid-pickup-and-delivery-options", + "java": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Unique Paths", + "pattern": "2-D Dynamic Programming", + "link": "unique-paths/", + "video": "IlEsdxuD4lY", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0062-unique-paths", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Unique Paths II", + "pattern": "2-D Dynamic Programming", + "link": "unique-paths-ii/", + "video": "d3UOz7zdE4I", + "difficulty": "Medium", + "python": true, + "code": "0063-unique-paths-ii", + "cpp": true, + "java": true, + "go": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Longest Common Subsequence", + "pattern": "2-D Dynamic Programming", + "link": "longest-common-subsequence/", + "video": "Ua0GhsJSlWM", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "1143-longest-common-subsequence", + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "rust": true, + "c": true + }, + { + "problem": "Longest Palindromic Subsequence", + "pattern": "2-D Dynamic Programming", + "link": "longest-palindromic-subsequence/", + "video": "bUr8cNWI09Q", + "difficulty": "Medium", + "python": true, + "code": "0516-longest-palindromic-subsequence", + "kotlin": true + }, + { + "problem": "Last Stone Weight II", + "pattern": "2-D Dynamic Programming", + "link": "last-stone-weight-ii/", + "video": "gdXkkmzvR3c", + "difficulty": "Medium", + "python": true, + "code": "1049-last-stone-weight-ii", + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Best Time to Buy And Sell Stock With Cooldown", + "pattern": "2-D Dynamic Programming", + "link": "best-time-to-buy-and-sell-stock-with-cooldown/", + "video": "I7j0F7AHpb8", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0309-best-time-to-buy-and-sell-stock-with-cooldown", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Coin Change II", + "pattern": "2-D Dynamic Programming", + "link": "coin-change-ii/", + "video": "Mjy4hd2xgrs", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0518-coin-change-ii", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Target Sum", + "pattern": "2-D Dynamic Programming", + "link": "target-sum/", + "video": "g0npyaQtAQM", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0494-target-sum", + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "c": true + }, + { + "neetcode150": true, + "problem": "Interleaving String", + "pattern": "2-D Dynamic Programming", + "link": "interleaving-string/", + "video": "3Rw3p9LrgvE", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0097-interleaving-string", + "csharp": true, + "typescript": true, + "go": true, + "scala": true, + "kotlin": true, + "c": true + }, + { + "problem": "Stone Game", + "pattern": "2-D Dynamic Programming", + "link": "stone-game/", + "video": "uhgdXOlGYqE", + "difficulty": "Medium", + "code": "0877-stone-game", + "kotlin": true, + "cpp": true + }, + { + "problem": "Minimum Path Sum", + "pattern": "2-D Dynamic Programming", + "link": "minimum-path-sum/", + "video": "pGMsrvt0fpk", + "difficulty": "Medium", + "code": "0064-minimum-path-sum", + "cpp": true, + "java": true, + "python": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Longest Increasing Path In a Matrix", + "pattern": "2-D Dynamic Programming", + "link": "longest-increasing-path-in-a-matrix/", + "video": "wCc_nd-GiEc", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0329-longest-increasing-path-in-a-matrix", + "c": true, + "csharp": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Maximal Square", + "pattern": "2-D Dynamic Programming", + "link": "maximal-square/", + "video": "6X7Ha2PrDmM", + "difficulty": "Medium", + "code": "0221-maximal-square", + "python": true, + "java": true, + "kotlin": true, + "cpp": true + }, + { + "problem": "Ones and Zeroes", + "pattern": "2-D Dynamic Programming", + "link": "ones-and-zeroes/", + "video": "miZ3qV04b1g", + "difficulty": "Medium", + "python": true, + "code": "0474-ones-and-zeroes", + "kotlin": true, + "cpp": true + }, + { + "problem": "Maximum Alternating Subsequence Sum", + "pattern": "2-D Dynamic Programming", + "link": "maximum-alternating-subsequence-sum/", + "video": "4v42XOuU1XA", + "difficulty": "Medium", + "code": "5782-maximum-alternating-subsequence-sum" + }, + { + "neetcode150": true, + "problem": "Distinct Subsequences", + "pattern": "2-D Dynamic Programming", + "link": "distinct-subsequences/", + "video": "-RDzMJ33nx8", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0115-distinct-subsequences", + "csharp": true, + "typescript": true, + "kotlin": true, + "c": true + }, + { + "neetcode150": true, + "problem": "Edit Distance", + "pattern": "2-D Dynamic Programming", + "link": "edit-distance/", + "video": "XYi2-LPrwm4", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0072-edit-distance", + "csharp": true, + "swift": true, + "scala": true, + "kotlin": true, + "c": true + }, + { + "problem": "Count Vowels Permutation", + "pattern": "2-D Dynamic Programming", + "link": "count-vowels-permutation/", + "video": "VUVpTZVa7Ls", + "difficulty": "Hard", + "code": "1220-count-vowels-permutation", + "python": true, + "java": true, + "go": true, + "cpp": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Burst Balloons", + "pattern": "2-D Dynamic Programming", + "link": "burst-balloons/", + "video": "VFskby7lUbw", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0312-burst-balloons", + "csharp": true, + "typescript": true, + "kotlin": true, + "c": true + }, + { + "problem": "Number of Ways to Rearrange Sticks With K Sticks Visible", + "pattern": "2-D Dynamic Programming", + "link": "number-of-ways-to-rearrange-sticks-with-k-sticks-visible/", + "video": "O761YBjGxGA", + "difficulty": "Hard", + "code": "1866-number-of-ways-to-rearrange-sticks-with-k-sticks-visible", + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Regular Expression Matching", + "pattern": "2-D Dynamic Programming", + "link": "regular-expression-matching/", + "video": "HAA8mgxlov8", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0010-regular-expression-matching", + "csharp": true, + "typescript": true, + "go": true, + "c": true, + "kotlin": true + }, + { + "problem": "Stone Game II", + "pattern": "2-D Dynamic Programming", + "link": "stone-game-ii/", + "video": "I-z-u0zfQtg", + "difficulty": "Medium", + "code": "1140-stone-game-ii", + "kotlin": true + }, + { + "problem": "Flip String to Monotone Increasing", + "pattern": "2-D Dynamic Programming", + "link": "flip-string-to-monotone-increasing/", + "video": "tMq9z5k3umQ", + "difficulty": "Medium", + "code": "0926-flip-string-to-monotone-increasing", + "javascript": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Maximum Value of K Coins from Piles", + "pattern": "2-D Dynamic Programming", + "link": "maximum-value-of-k-coins-from-piles/", + "video": "ZRdEd_eun8g", + "difficulty": "Hard", + "code": "2218-maximum-value-of-k-coins-from-piles", + "kotlin": true + }, + { + "problem": "Number of Music Playlists", + "pattern": "2-D Dynamic Programming", + "link": "number-of-music-playlists/", + "video": "gk4qzZSmyrs", + "difficulty": "Hard", + "code": "0920-number-of-music-playlists", + "java": true, + "kotlin": true + }, + { + "problem": "Number of Ways to Form a Target String Given a Dictionary", + "pattern": "2-D Dynamic Programming", + "link": "number-of-ways-to-form-a-target-string-given-a-dictionary/", + "video": "_GF-0T-YjW8", + "difficulty": "Hard", + "code": "1639-number-of-ways-to-form-a-target-string-given-a-dictionary", + "kotlin": true + }, + { + "problem": "Profitable Schemes", + "pattern": "2-D Dynamic Programming", + "link": "profitable-schemes/", + "video": "CcLKQLKvOl8", + "difficulty": "Hard", + "code": "0879-profitable-schemes", + "kotlin": true + }, + { + "problem": "Minimum Cost to Cut a Stick", + "pattern": "2-D Dynamic Programming", + "link": "minimum-cost-to-cut-a-stick/", + "video": "EVxTO5I0d7w", + "difficulty": "Hard", + "code": "1547-minimum-cost-to-cut-a-stick", + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Maximum Subarray", + "pattern": "Greedy", + "link": "maximum-subarray/", + "video": "5WZl3MMT0Eg", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0053-maximum-subarray", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "rust": true, + "ruby": true + }, + { + "problem": "Maximum Sum Circular Subarray", + "pattern": "Greedy", + "link": "maximum-sum-circular-subarray/", + "video": "fxT9KjakYPM", + "difficulty": "Medium", + "code": "0918-maximum-sum-circular-subarray", + "python": true, + "javascript": true, + "typescript": true, + "go": true, + "rust": true, + "kotlin": true, + "java": true + }, + { + "problem": "Longest Turbulent Array", + "pattern": "Greedy", + "link": "longest-turbulent-subarray/", + "video": "V_iHUhR8Dek", + "difficulty": "Medium", + "code": "0978-longest-turbulent-subarray", + "python": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Jump Game", + "pattern": "Greedy", + "link": "jump-game/", + "video": "Yan0cv2cLy8", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0055-jump-game", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Jump Game II", + "pattern": "Greedy", + "link": "jump-game-ii/", + "video": "dJ7sWiOoK7g", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0045-jump-game-ii", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "ruby": true + }, + { + "problem": "Jump Game VII", + "pattern": "Greedy", + "link": "jump-game-vii/", + "video": "v1HpZUnQ4Yo", + "difficulty": "Medium", + "code": "1871-jump-game-vii", + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Gas Station", + "pattern": "Greedy", + "link": "gas-station/", + "video": "lJwbPZGo05A", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0134-gas-station", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "ruby": true + }, + { + "neetcode150": true, + "problem": "Hand of Straights", + "pattern": "Greedy", + "link": "hand-of-straights/", + "video": "amnrMCVd2YI", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0846-hand-of-straights", + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "kotlin": true, + "c": true + }, + { + "problem": "Minimize Maximum of Array", + "pattern": "Greedy", + "link": "minimize-maximum-of-array/", + "video": "AeHMvcKuR0Y", + "difficulty": "Medium", + "code": "2439-minimize-maximum-of-array", + "kotlin": true + }, + { + "problem": "Dota2 Senate", + "pattern": "Greedy", + "link": "dota2-senate/", + "video": "zZA5KskfMuQ", + "difficulty": "Medium", + "code": "0649-dota2-senate", + "kotlin": true + }, + { + "problem": "Maximum Points You Can Obtain From Cards", + "pattern": "Greedy", + "link": "maximum-points-you-can-obtain-from-cards/", + "video": "TsA4vbtfCvo", + "difficulty": "Medium", + "code": "1423-maximum-points-you-can-obtain-from-cards", + "csharp": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Merge Triplets to Form Target Triplet", + "pattern": "Greedy", + "link": "merge-triplets-to-form-target-triplet/", + "video": "kShkQLQZ9K4", + "difficulty": "Medium", + "code": "1899-merge-triplets-to-form-target-triplet", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "csharp": true, + "typescript": true, + "ruby": true, + "swift": true, + "kotlin": true, + "c": true + }, + { + "neetcode150": true, + "problem": "Partition Labels", + "pattern": "Greedy", + "link": "partition-labels/", + "video": "B7m8UmZE-vw", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0763-partition-labels", + "csharp": true, + "go": true, + "ruby": true, + "kotlin": true, + "c": true + }, + { + "neetcode150": true, + "problem": "Valid Parenthesis String", + "pattern": "Greedy", + "link": "valid-parenthesis-string/", + "video": "QhPdNS143Qg", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0678-valid-parenthesis-string", + "c": true, + "csharp": true, + "typescript": true, + "kotlin": true + }, + { + "problem": "Eliminate Maximum Number of Monsters", + "pattern": "Greedy", + "link": "eliminate-maximum-number-of-monsters/", + "video": "6QQRayzOTD4", + "difficulty": "Medium", + "code": "1921-eliminate-maximum-number-of-monsters", + "cpp": true, + "java": true, + "kotlin": true + }, + { + "problem": "Two City Scheduling", + "pattern": "Greedy", + "link": "two-city-scheduling/", + "video": "d-B_gk_gJtQ", + "difficulty": "Medium", + "code": "1029-two-city-scheduling", + "java": true, + "python": true, + "javascript": true, + "typescript": true, + "go": true, + "rust": true, + "kotlin": true + }, + { + "problem": "Maximum Length of Pair Chain", + "pattern": "Greedy", + "link": "maximum-length-of-pair-chain/", + "video": "LcNNorqMVTw", + "difficulty": "Medium", + "code": "0646-maximum-length-of-pair-chain", + "kotlin": true + }, + { + "problem": "Minimum Deletions to Make Character Frequencies Unique", + "pattern": "Greedy", + "link": "minimum-deletions-to-make-character-frequencies-unique/", + "video": "h8AZEN49gTc", + "difficulty": "Medium", + "code": "1647-minimum-deletions-to-make-character-frequencies-unique", + "java": true, + "kotlin": true + }, + { + "problem": "Candy", + "pattern": "Greedy", + "link": "candy/", + "video": "1IzCRCcK17A", + "difficulty": "Hard", + "code": "135-candy" + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Insert Interval", + "pattern": "Intervals", + "link": "insert-interval/", + "video": "A8NUOmlwOlM", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0057-insert-interval", + "csharp": true, + "typescript": true, + "swift": true, + "rust": true, + "go": true, + "kotlin": true, + "c": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Merge Intervals", + "pattern": "Intervals", + "link": "merge-intervals/", + "video": "44H3cEC2fFM", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0056-merge-intervals", + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "scala": true, + "c": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Non Overlapping Intervals", + "pattern": "Intervals", + "link": "non-overlapping-intervals/", + "video": "nONCGxWoUfM", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0435-non-overlapping-intervals", + "csharp": true, + "typescript": true, + "go": true, + "scala": true, + "c": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Meeting Rooms", + "premium": true, + "freeLink": "https://www.lintcode.com/problem/920/", + "pattern": "Intervals", + "link": "meeting-rooms/", + "video": "PaJxqZVPhbg", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0252-meeting-rooms", + "csharp": true, + "rust": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Meeting Rooms II", + "premium": true, + "freeLink": "https://www.lintcode.com/problem/919/", + "pattern": "Intervals", + "link": "meeting-rooms-ii/", + "video": "FdzJmTCVyJU", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0253-meeting-rooms-ii", + "csharp": true, + "rust": true, + "kotlin": true + }, + { + "problem": "Remove Covered Intervals", + "pattern": "Intervals", + "link": "remove-covered-intervals/", + "video": "nhAsMabiVkM", + "difficulty": "Medium", + "code": "1288-remove-covered-intervals", + "c": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Minimum Interval to Include Each Query", + "pattern": "Intervals", + "link": "minimum-interval-to-include-each-query/", + "video": "5hQ5WWW5awQ", + "difficulty": "Hard", + "python": true, + "java": true, + "cpp": true, + "code": "1851-minimum-interval-to-include-each-query", + "csharp": true, + "javascript": true, + "kotlin": true + }, + { + "problem": "Data Stream as Disjoint Intervals", + "pattern": "Intervals", + "link": "data-stream-as-disjoint-intervals/", + "video": "FavoZjPIWpo", + "difficulty": "Hard", + "code": "0352-data-stream-as-disjoint-intervals", + "javascript": true, + "typescript": true, + "go": true, + "rust": true, + "kotlin": true + }, + { + "problem": "Excel Sheet Column Title", + "pattern": "Math & Geometry", + "link": "excel-sheet-column-title/", + "video": "X_vJDpCCuoA", + "difficulty": "Easy", + "code": "0168-excel-sheet-column-title", + "java": true, + "python": true, + "kotlin": true + }, + { + "problem": "Greatest Common Divisor of Strings", + "pattern": "Math & Geometry", + "link": "greatest-common-divisor-of-strings/", + "video": "i5I_wrbUdzM", + "difficulty": "Easy", + "code": "1071-greatest-common-divisor-of-strings", + "javascript": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true, + "cpp": true + }, + { + "problem": "Count Odd Numbers in an Interval Range", + "pattern": "Math & Geometry", + "link": "count-odd-numbers-in-an-interval-range/", + "video": "wrIWye928JQ", + "difficulty": "Easy", + "code": "1523-count-odd-numbers-in-an-interval-range", + "kotlin": true + }, + { + "problem": "Matrix Diagonal Sum", + "pattern": "Math & Geometry", + "link": "matrix-diagonal-sum/", + "video": "WliTu6gIK7o", + "difficulty": "Easy", + "code": "1572-matrix-diagonal-sum", + "kotlin": true, + "javascript": true + }, + { + "problem": "Maximum Points on a Line", + "pattern": "Math & Geometry", + "link": "max-points-on-a-line/", + "video": "Bb9lOXUOnFw", + "difficulty": "Hard", + "code": "0149-max-points-on-a-line", + "python": true, + "javascript": true, + "typescript": true, + "rust": true, + "cpp": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Rotate Image", + "pattern": "Math & Geometry", + "link": "rotate-image/", + "video": "fMSJSS7eO1w", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0048-rotate-image", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "ruby": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Spiral Matrix", + "pattern": "Math & Geometry", + "link": "spiral-matrix/", + "video": "BJnMZNwUk1M", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0054-spiral-matrix", + "csharp": true, + "typescript": true, + "kotlin": true, + "go": true, + "ruby": true, + "c": true + }, + { + "problem": "Spiral Matrix II ", + "pattern": "Math & Geometry", + "link": "spiral-matrix-ii/", + "video": "RvLrWFBJ9fM", + "difficulty": "Medium", + "code": "0059-spiral-matrix-ii", + "javascript": true, + "kotlin": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Set Matrix Zeroes", + "pattern": "Math & Geometry", + "link": "set-matrix-zeroes/", + "video": "T41rL0L3Pnw", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0073-set-matrix-zeroes", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "kotlin": true, + "ruby": true + }, + { + "neetcode150": true, + "problem": "Happy Number", + "pattern": "Math & Geometry", + "link": "happy-number/", + "video": "ljz85bxOYJ0", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0202-happy-number", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "ruby": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Plus One", + "pattern": "Math & Geometry", + "link": "plus-one/", + "video": "jIaA8boiG1s", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0066-plus-one", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "swift": true, + "kotlin": true, + "ruby": true, + "rust": true + }, + { + "problem": "Palindrome Number", + "pattern": "Math & Geometry", + "link": "palindrome-number/", + "video": "yubRKwixN-U", + "difficulty": "Easy", + "code": "0009-palindrome-number", + "javascript": true, + "typescript": true, + "cpp": true, + "java": true, + "python": true, + "go": true, + "rust": true, + "swift": true, + "c": true, + "kotlin": true + }, + { + "problem": "Ugly Number", + "pattern": "Math & Geometry", + "link": "ugly-number/", + "video": "M0Zay1Qr9ws", + "difficulty": "Easy", + "code": "0263-ugly-number", + "c": true, + "cpp": true, + "java": true, + "python": true, + "javascript": true, + "typescript": true, + "go": true, + "rust": true, + "swift": true, + "kotlin": true + }, + { + "problem": "Shift 2D Grid", + "pattern": "Math & Geometry", + "link": "shift-2d-grid/", + "video": "nJYFh4Dl-as", + "difficulty": "Easy", + "code": "1260-shift-2d-grid", + "cpp": true, + "java": true, + "python": true, + "javascript": true, + "kotlin": true + }, + { + "problem": "Roman to Integer", + "pattern": "Math & Geometry", + "link": "roman-to-integer/", + "video": "3jdxYj3DD98", + "difficulty": "Easy", + "code": "0013-roman-to-integer", + "python": true, + "javascript": true, + "go": true, + "typescript": true, + "rust": true, + "java": true, + "cpp": true, + "kotlin": true + }, + { + "problem": "Integer to Roman", + "pattern": "Math & Geometry", + "link": "integer-to-roman/", + "video": "ohBNdSJyLh8", + "difficulty": "Medium", + "code": "0012-integer-to-roman", + "python": true, + "typescript": true, + "go": true, + "rust": true, + "javascript": true, + "cpp": true, + "java": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Pow(x, n)", + "pattern": "Math & Geometry", + "link": "powx-n/", + "video": "g9YQyYi4IQQ", + "difficulty": "Medium", + "python": true, + "java": true, + "javascript": true, + "cpp": true, + "code": "0050-powx-n", + "c": true, + "csharp": true, + "typescript": true, + "swift": true, + "ruby": true, + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Multiply Strings", + "pattern": "Math & Geometry", + "link": "multiply-strings/", + "video": "1vZswirL8Y8", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0043-multiply-strings", + "csharp": true, + "typescript": true, + "swift": true, + "ruby": true, + "kotlin": true, + "c": true + }, + { + "neetcode150": true, + "problem": "Detect Squares", + "pattern": "Math & Geometry", + "link": "detect-squares/", + "video": "bahebearrDc", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "2013-detect-squares", + "csharp": true, + "kotlin": true, + "ruby": true, + "rust": true + }, + { + "problem": "Robot Bounded In Circle", + "pattern": "Math & Geometry", + "link": "robot-bounded-in-circle/", + "video": "nKv2LnC_g6E", + "difficulty": "Medium", + "code": "1041-robot-bounded-in-circle", + "kotlin": true + }, + { + "problem": "Zigzag Conversion", + "pattern": "Math & Geometry", + "link": "zigzag-conversion/", + "video": "Q2Tw6gcVEwc", + "difficulty": "Medium", + "code": "0006-zigzag-conversion", + "java": true, + "cpp": true, + "go": true, + "kotlin": true + }, + { + "problem": "Find Missing Observations", + "pattern": "Math & Geometry", + "link": "find-missing-observations/", + "video": "86yKkaNi3sU", + "difficulty": "Medium", + "code": "2028-find-missing-observations", + "kotlin": true + }, + { + "neetcode150": true, + "problem": "Single Number", + "pattern": "Bit Manipulation", + "link": "single-number/", + "video": "qMPX1AOa83k", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0136-single-number", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true, + "dart": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Number of 1 Bits", + "pattern": "Bit Manipulation", + "link": "number-of-1-bits/", + "video": "5Km3utixwZs", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0191-number-of-1-bits", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Counting Bits", + "pattern": "Bit Manipulation", + "link": "counting-bits/", + "video": "RyBM56RIWrM", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0338-counting-bits", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Reverse Bits", + "pattern": "Bit Manipulation", + "link": "reverse-bits/", + "video": "UcoN6UjAI64", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0190-reverse-bits", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Missing Number", + "pattern": "Bit Manipulation", + "link": "missing-number/", + "video": "WnPLSRLSANE", + "difficulty": "Easy", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0268-missing-number", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "problem": "Shuffle the Array", + "pattern": "Bit Manipulation", + "link": "shuffle-the-array/", + "video": "IvIKD_EU8BY", + "difficulty": "Easy", + "code": "1470-shuffle-the-array", + "javascript": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true, + "c": true + }, + { + "problem": "Add to Array-Form of Integer", + "pattern": "Bit Manipulation", + "link": "add-to-array-form-of-integer/", + "video": "eBTZQt1TWfk", + "difficulty": "Easy", + "code": "0989-add-to-array-form-of-integer", + "javascript": true, + "typescript": true, + "go": true, + "kotlin": true, + "rust": true, + "c": true + }, + { + "neetcode150": true, + "blind75": true, + "problem": "Sum of Two Integers", + "pattern": "Bit Manipulation", + "link": "sum-of-two-integers/", + "video": "gVUrDV4tZfY", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0371-sum-of-two-integers", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "rust": true + }, + { + "neetcode150": true, + "problem": "Reverse Integer", + "pattern": "Bit Manipulation", + "link": "reverse-integer/", + "video": "HAgLH58IgJQ", + "difficulty": "Medium", + "python": true, + "java": true, + "cpp": true, + "javascript": true, + "code": "0007-reverse-integer", + "c": true, + "csharp": true, + "typescript": true, + "go": true, + "ruby": true, + "swift": true, + "kotlin": true, + "scala": true, + "rust": true + }, + { + "problem": "Add Binary", + "pattern": "Bit Manipulation", + "link": "add-binary/", + "video": "keuWJ47xG8g", + "difficulty": "Easy", + "code": "0067-add-binary", + "cpp": true, + "java": true, + "python": true, + "kotlin": true, + "rust": true, + "c": true + }, + { + "problem": "Create Hello World Function", + "pattern": "JavaScript", + "link": "create-hello-world-function/", + "video": "P9Ldx1eTlRc", + "difficulty": "Easy", + "code": "2667-create-hello-world-function", + "javascript": true, + "typescript": true + }, + { + "problem": "Counter", + "pattern": "JavaScript", + "link": "counter/", + "video": "yEGQQAG5V68", + "difficulty": "Easy", + "code": "2620-counter", + "javascript": true, + "typescript": true + }, + { + "problem": "Counter II", + "pattern": "JavaScript", + "link": "counter-ii/", + "video": "UXNXKGFZD08", + "difficulty": "Easy", + "code": "2665-counter-ii", + "javascript": true + }, + { + "problem": "Apply Transform over each Element in Array", + "pattern": "JavaScript", + "link": "apply-transform-over-each-element-in-array/", + "video": "7FhJHA5jlYk", + "difficulty": "Easy", + "code": "2635-apply-transform-over-each-element-in-array" + }, + { + "problem": "Filter Elements from Array", + "pattern": "JavaScript", + "link": "filter-elements-from-array/", + "video": "w1o81gbEEJU", + "difficulty": "Easy", + "code": "2634-filter-elements-from-array" + }, + { + "problem": "Array Reduce Transformation", + "pattern": "JavaScript", + "link": "array-reduce-transformation/", + "video": "KmTbYfpGxdM", + "difficulty": "Easy", + "code": "2626-array-reduce-transformation" + }, + { + "problem": "Function Composition", + "pattern": "JavaScript", + "link": "function-composition/", + "video": "mIFw1H7Ljco", + "difficulty": "Easy", + "code": "2629-function-composition" + }, + { + "problem": "Allow One Function Call", + "pattern": "JavaScript", + "link": "allow-one-function-call/", + "video": "m_SWhM9iX3s", + "difficulty": "Easy", + "code": "2666-allow-one-function-call" + }, + { + "problem": "Memoize", + "pattern": "JavaScript", + "link": "memoize/", + "video": "oFXyzJt9VeU", + "difficulty": "Medium", + "code": "2623-memoize" + }, + { + "problem": "Curry", + "pattern": "JavaScript", + "link": "curry/", + "video": "pi4kqMWQXxA", + "difficulty": "Medium", + "code": "2632-curry" + }, + { + "problem": "Sleep", + "pattern": "JavaScript", + "link": "sleep/", + "video": "P0D9Z6H7O00", + "difficulty": "Easy", + "code": "2621-sleep" + }, + { + "problem": "Promise Time Limit", + "pattern": "JavaScript", + "link": "promise-time-limit/", + "video": "hfH57rdZhOk", + "difficulty": "Easy", + "code": "2637-promise-time-limit" + }, + { + "problem": "Promise Pool", + "pattern": "JavaScript", + "link": "promise-pool/", + "video": "DB8pAAg-9xw", + "difficulty": "Medium", + "code": "2636-promise-pool" + }, + { + "problem": "Cache With Time Limit", + "pattern": "JavaScript", + "link": "cache-with-time-limit/", + "video": "w772gtNK0Gw", + "difficulty": "Medium", + "code": "2622-cache-with-time-limit" + }, + { + "problem": "Debounce", + "pattern": "JavaScript", + "link": "debounce/", + "video": "1sxSpnxNx5w", + "difficulty": "Medium", + "code": "2627-debounce" + }, + { + "problem": "Throttle", + "pattern": "JavaScript", + "link": "throttle/", + "video": "zyGZV_fIQWk", + "difficulty": "Medium", + "code": "2676-throttle" + }, + { + "problem": "JSON Deep Equal", + "pattern": "JavaScript", + "link": "json-deep-equal/", + "video": "4JVZ-mVqJPg", + "difficulty": "Medium", + "code": "2628-json-deep-equal", + "javascript": true + }, + { + "problem": "Convert Object to JSON String", + "pattern": "JavaScript", + "link": "convert-object-to-json-string/", + "video": "f94fUbHU-FY", + "difficulty": "Medium", + "code": "2633-convert-object-to-json-string" + }, + { + "problem": "Array of Objects to Matrix", + "pattern": "JavaScript", + "link": "array-of-objects-to-matrix/", + "video": "LJwgAMHGcI0", + "difficulty": "Medium", + "code": "2675-array-of-objects-to-matrix" + }, + { + "problem": "Difference Between Two Objects", + "pattern": "JavaScript", + "link": "differences-between-two-objects/", + "video": "gH7oZs1WZfg", + "difficulty": "Medium", + "code": "2700-differences-between-two-objects" + }, + { + "problem": "Chunk Array", + "pattern": "JavaScript", + "link": "chunk-array/", + "video": "VUN-O3B9ceY", + "difficulty": "Easy", + "code": "2677-chunk-array" + }, + { + "problem": "Flatten Deeply Nested Array", + "pattern": "JavaScript", + "link": "flatten-deeply-nested-array/", + "video": "_DetLPKtFNk", + "difficulty": "Medium", + "code": "2625-flatten-deeply-nested-array" + }, + { + "problem": "Array Prototype Last", + "pattern": "JavaScript", + "link": "array-prototype-last/", + "video": "3JdtfMBrUqc", + "difficulty": "Easy", + "code": "2619-array-prototype-last" + }, + { + "problem": "Group By", + "pattern": "JavaScript", + "link": "group-by/", + "video": "zs9axOyYHRE", + "difficulty": "Medium", + "code": "2631-group-by" + }, + { + "problem": "Check if Object Instance of Class", + "pattern": "JavaScript", + "link": "check-if-object-instance-of-class/", + "video": "meIo-Q07Ba8", + "difficulty": "Medium", + "code": "2618-check-if-object-instance-of-class" + }, + { + "problem": "Call Function with Custom Context", + "pattern": "JavaScript", + "link": "call-function-with-custom-context/", + "video": "du_GH-Ooa8E", + "difficulty": "Medium", + "code": "2693-call-function-with-custom-context" + }, + { + "problem": "Event Emitter", + "pattern": "JavaScript", + "link": "event-emitter/", + "video": "M69bjWFarU0", + "difficulty": "Medium", + "code": "2694-event-emitter" + }, + { + "problem": "Array Wrapper", + "pattern": "JavaScript", + "link": "array-wrapper/", + "video": "XoGjPdPTAVA", + "difficulty": "Easy", + "code": "2695-array-wrapper" + }, + { + "problem": "Generate Fibonacci Sequence", + "pattern": "JavaScript", + "link": "generate-fibonacci-sequence/", + "video": "T643rQ70Jlk", + "difficulty": "Easy", + "code": "2648-generate-fibonacci-sequence" + }, + { + "problem": "Nested Array Generator", + "pattern": "JavaScript", + "link": "nested-array-generator/", + "video": "yo-J1jQaZYU", + "difficulty": "Medium", + "code": "2649-nested-array-generator" + } +] diff --git a/CONTRIBUTING.md b/CONTRIBUTING.md index 83d524dd0..3fdb8d878 100644 --- a/CONTRIBUTING.md +++ b/CONTRIBUTING.md @@ -1,25 +1,26 @@ # Contributing + **Please read the [guidelines below](#contributing-guidelines) before opening a PR** Solutions from these languages will be linked from [NeetCode.io](https://neetcode.io): -* Python -* C++ -* Java -* Javascript +- Python +- C++ +- Java +- Javascript -Solutions are also welcome for any other *supported* language on leetcode.com! +Solutions are also welcome for any other _supported_ language on leetcode.com! To contribute, please fork this repo and open a PR adding a [missing solution](./README.md#missing-solutions) from the supported languages. -If you would like to have collaborator permissions on the repo to merge your own PRs or review others' PRs please let me know. +If you would like to have collaborator permissions on the repo to merge your own PRs or review others' PRs please let me know. ## Contributing Guidelines - **Match the casing of files and directories** - - For files, it's **`/-name-of-problem.`** (e.g. `java/0001-two-sum.java`) - - Make sure the `problem-number` is formatted as four digits adding leading zeroes if necessary - - You can find the `name-of-problem` in the leetcode URL, e.g https://leetcode.com/problems/ _**two-sum**_ / + - For files, it's **`/-name-of-problem.`** (e.g. `java/0001-two-sum.java`) + - Make sure the `problem-number` is formatted as four digits adding leading zeroes if necessary + - You can find the `name-of-problem` in the leetcode URL, e.g https://leetcode.com/problems/ _**two-sum**_ / - **Give your PR a succinct and accurate title** (e.g. _"Create: 0001-two-sum.py"_) - Prefer **one solution/change per PR** (not a hard and fast rule, but will typically make the review cycle shorter) - **Follow the** [PR template](./.github/pull_request_template.md) and add additional information when needed @@ -32,21 +33,25 @@ If you would like to have collaborator permissions on the repo to merge your own **Q:** What should my solution include? **A:** You can keep your solution exactly the same as the one you submit to leetcode, you don't need to write tests or your own implementation of leetcode's built-ins. + ## **Q:** What if there are multiple ways to solve the problem? **A:** Multiple solutions to the same problem are accepted (as long as they differ in approach or time/memory complexity), although the first solution should always follow the same algorithm shown on [the channel](https://www.youtube.com/c/neetcode). Please make sure distinct solutions are grouped together in the same file, with appropriately differentiating names (e.g. `isValidBstIterative` and `isValidBstRecursive`) + ## **Q:** What if my solution has a lower runtime but the same time/memory complexity? **A:** Leetcode's runtime measurement can be severely inaccurate varying based on server load, time of day and many other factors. In general, readability and clarity of the code (in the context of interviews) are features more important than performance gains, however changes that transparently improve performance will be accepted. + ## **Q:** What if the problem I want to add isn't in the Neetcode 150 list or Missing Solutions table? **A:** Questions outside of the Neetcode 150 list can be added but please prioritise adding the listed solutions first. + ## Thanks for contributing 🚀 diff --git a/README.md b/README.md index 621435471..120f0d73c 100644 --- a/README.md +++ b/README.md @@ -1,20 +1,22 @@ # Leetcode solutions for 🚀 [NeetCode.io](https://neetcode.io) + > This repo hosts the solutions found on [NeetCode.io](https://neetcode.io) including the solutions shown on the [NeetCode YouTube channel](https://www.youtube.com/c/neetcode). The site will periodically be updated with new solutions from this repo!
Solutions from these languages will be linked from [NeetCode.io](https://neetcode.io): + > Python, Java, JavaScript, C++, Go, Swift, C#, TypeScript, Rust, Kotlin, Ruby, C, Scala and Dart -Solutions are also welcome for any other *supported* language on leetcode.com! +Solutions are also welcome for any other _supported_ language on leetcode.com! ## Contributing -**Please read the [contributing guidlines](./CONTRIBUTING.md) before opening a PR** +**Please read the [contributing guidlines](./CONTRIBUTING.md) before opening a PR** To contribute, please fork this repo and open a PR adding a [missing solution](#missing-solutions) from the supported languages. -If you would like to have collaborator permissions on the repo to merge your own PRs or review others' PRs please let me know. +If you would like to have collaborator permissions on the repo to merge your own PRs or review others' PRs please let me know. ## Credits diff --git a/README_template.md b/README_template.md index 177477379..53e56cae0 100644 --- a/README_template.md +++ b/README_template.md @@ -1,20 +1,22 @@ # Leetcode solutions for 🚀 [NeetCode.io](https://neetcode.io) + > This repo hosts the solutions found on [NeetCode.io](https://neetcode.io) including the solutions shown on the [NeetCode YouTube channel](https://www.youtube.com/c/neetcode). The site will periodically be updated with new solutions from this repo!
Solutions from these languages will be linked from [NeetCode.io](https://neetcode.io): + > Python, Java, JavaScript, C++, Go, Swift, C#, TypeScript, Rust, Kotlin, Ruby, C, Scala and Dart -Solutions are also welcome for any other *supported* language on leetcode.com! +Solutions are also welcome for any other _supported_ language on leetcode.com! ## Contributing -**Please read the [contributing guidlines](./CONTRIBUTING.md) before opening a PR** +**Please read the [contributing guidlines](./CONTRIBUTING.md) before opening a PR** To contribute, please fork this repo and open a PR adding a [missing solution](#missing-solutions) from the supported languages. -If you would like to have collaborator permissions on the repo to merge your own PRs or review others' PRs please let me know. +If you would like to have collaborator permissions on the repo to merge your own PRs or review others' PRs please let me know. ## Credits diff --git a/articles/132-pattern.md b/articles/132-pattern.md new file mode 100644 index 000000000..5bdc63728 --- /dev/null +++ b/articles/132-pattern.md @@ -0,0 +1,420 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def find132pattern(self, nums: List[int]) -> bool: + n = len(nums) + + for k in range(2, n): + for j in range(k - 1, 0, -1): + if nums[j] <= nums[k]: + continue + + for i in range(j - 1, -1, -1): + if nums[i] < nums[k]: + return True + + return False +``` + +```java +public class Solution { + public boolean find132pattern(int[] nums) { + int n = nums.length; + + for (int k = 2; k < n; k++) { + for (int j = k - 1; j > 0; j--) { + if (nums[j] <= nums[k]) { + continue; + } + + for (int i = j - 1; i >= 0; i--) { + if (nums[i] < nums[k]) { + return true; + } + } + } + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool find132pattern(vector& nums) { + int n = nums.size(); + + for (int k = 2; k < n; k++) { + for (int j = k - 1; j > 0; j--) { + if (nums[j] <= nums[k]) { + continue; + } + + for (int i = j - 1; i >= 0; i--) { + if (nums[i] < nums[k]) { + return true; + } + } + } + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + find132pattern(nums) { + let n = nums.length; + + for (let k = 2; k < n; k++) { + for (let j = k - 1; j > 0; j--) { + if (nums[j] <= nums[k]) { + continue; + } + + for (let i = j - 1; i >= 0; i--) { + if (nums[i] < nums[k]) { + return true; + } + } + } + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Stack + +::tabs-start + +```python +class Solution: + def find132pattern(self, nums: List[int]) -> bool: + stack = [] # pair [num, minLeft], mono decreasing + curMin = nums[0] + + for i in range(1, len(nums)): + while stack and nums[i] >= stack[-1][0]: + stack.pop() + if stack and nums[i] > stack[-1][1]: + return True + + stack.append([nums[i], curMin]) + curMin = min(curMin, nums[i]) + + return False +``` + +```java +public class Solution { + public boolean find132pattern(int[] nums) { + Stack stack = new Stack<>(); // pair [num, minLeft] + int curMin = nums[0]; + + for (int i = 1; i < nums.length; i++) { + while (!stack.isEmpty() && nums[i] >= stack.peek()[0]) { + stack.pop(); + } + if (!stack.isEmpty() && nums[i] > stack.peek()[1]) { + return true; + } + + stack.push(new int[]{nums[i], curMin}); + curMin = Math.min(curMin, nums[i]); + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool find132pattern(vector& nums) { + stack> stack; // pair + int curMin = nums[0]; + + for (int i = 1; i < nums.size(); i++) { + while (!stack.empty() && nums[i] >= stack.top().first) { + stack.pop(); + } + if (!stack.empty() && nums[i] > stack.top().second) { + return true; + } + + stack.push({nums[i], curMin}); + curMin = min(curMin, nums[i]); + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + find132pattern(nums) { + const stack = []; // pair [num, minLeft] + let curMin = nums[0]; + + for (let i = 1; i < nums.length; i++) { + while (stack.length > 0 && nums[i] >= stack[stack.length - 1][0]) { + stack.pop(); + } + if (stack.length > 0 && nums[i] > stack[stack.length - 1][1]) { + return true; + } + + stack.push([nums[i], curMin]); + curMin = Math.min(curMin, nums[i]); + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Stack (Optimal) + +::tabs-start + +```python +class Solution: + def find132pattern(self, nums: List[int]) -> bool: + stack, k = [], float('-inf') + + for i in range(len(nums) - 1, -1, -1): + if nums[i] < k: + return True + + while stack and stack[-1] < nums[i]: + k = stack.pop() + stack.append(nums[i]) + + return False +``` + +```java +public class Solution { + public boolean find132pattern(int[] nums) { + Stack stack = new Stack<>(); + int k = Integer.MIN_VALUE; + + for (int i = nums.length - 1; i >= 0; i--) { + if (nums[i] < k) { + return true; + } + + while (!stack.isEmpty() && stack.peek() < nums[i]) { + k = stack.pop(); + } + stack.push(nums[i]); + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool find132pattern(vector& nums) { + stack stack; + int k = INT_MIN; + + for (int i = nums.size() - 1; i >= 0; i--) { + if (nums[i] < k) { + return true; + } + + while (!stack.empty() && stack.top() < nums[i]) { + k = stack.top(); + stack.pop(); + } + stack.push(nums[i]); + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + find132pattern(nums) { + const stack = []; + let k = -Infinity; + + for (let i = nums.length - 1; i >= 0; i--) { + if (nums[i] < k) { + return true; + } + + while (stack.length > 0 && stack[stack.length - 1] < nums[i]) { + k = stack.pop(); + } + stack.push(nums[i]); + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Two Pointers + +::tabs-start + +```python +class Solution: + def find132pattern(self, nums: List[int]) -> bool: + n = len(nums) + stkTop, k = n, float('-inf') + + for i in range(n - 1, -1, -1): + if nums[i] < k: + return True + + while stkTop < n and nums[i] > nums[stkTop]: + k = nums[stkTop] + stkTop += 1 + + stkTop -= 1 + nums[stkTop] = nums[i] + + return False +``` + +```java +public class Solution { + public boolean find132pattern(int[] nums) { + int n = nums.length; + int stkTop = n; + int k = Integer.MIN_VALUE; + + for (int i = n - 1; i >= 0; i--) { + if (nums[i] < k) { + return true; + } + + while (stkTop < n && nums[i] > nums[stkTop]) { + k = nums[stkTop++]; + } + + nums[--stkTop] = nums[i]; + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool find132pattern(vector& nums) { + int n = nums.size(); + int stkTop = n; + int k = INT_MIN; + + for (int i = n - 1; i >= 0; i--) { + if (nums[i] < k) { + return true; + } + + while (stkTop < n && nums[i] > nums[stkTop]) { + k = nums[stkTop++]; + } + + nums[--stkTop] = nums[i]; + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + find132pattern(nums) { + const n = nums.length; + let stkTop = n; + let k = -Infinity; + + for (let i = n - 1; i >= 0; i--) { + if (nums[i] < k) { + return true; + } + + while (stkTop < n && nums[i] > nums[stkTop]) { + k = nums[stkTop++]; + } + + nums[--stkTop] = nums[i]; + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/4sum.md b/articles/4sum.md index f99c11ddd..c1675c054 100644 --- a/articles/4sum.md +++ b/articles/4sum.md @@ -84,7 +84,14 @@ class Solution { for (let c = b + 1; c < n; c++) { for (let d = c + 1; d < n; d++) { if (nums[a] + nums[b] + nums[c] + nums[d] === target) { - res.add(JSON.stringify([nums[a], nums[b], nums[c], nums[d]])); + res.add( + JSON.stringify([ + nums[a], + nums[b], + nums[c], + nums[d], + ]), + ); } } } @@ -96,12 +103,41 @@ class Solution { } ``` +```csharp +public class Solution { + public List> FourSum(int[] nums, int target) { + int n = nums.Length; + Array.Sort(nums); + HashSet<(int, int, int, int)> res = new HashSet<(int, int, int, int)>(); + + for (int a = 0; a < n; a++) { + for (int b = a + 1; b < n; b++) { + for (int c = b + 1; c < n; c++) { + for (int d = c + 1; d < n; d++) { + long sum = (long)nums[a] + nums[b] + nums[c] + nums[d]; + if (sum == target) { + res.Add((nums[a], nums[b], nums[c], nums[d])); + } + } + } + } + } + + var result = new List>(); + foreach (var quad in res) { + result.Add(new List { quad.Item1, quad.Item2, quad.Item3, quad.Item4 }); + } + return result; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 4)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n ^ 4)$ +- Space complexity: $O(m)$ > Where $n$ is the size of the array $nums$ and $m$ is the number of quadruplets. @@ -287,14 +323,66 @@ class Solution { } ``` +```csharp +public class Solution { + public List> FourSum(int[] nums, int target) { + Array.Sort(nums); + Dictionary count = new Dictionary(); + + foreach (int num in nums) { + if (!count.ContainsKey(num)) { + count[num] = 0; + } + count[num]++; + } + + List> res = new List>(); + + for (int i = 0; i < nums.Length; i++) { + count[nums[i]]--; + if (i > 0 && nums[i] == nums[i - 1]) continue; + + for (int j = i + 1; j < nums.Length; j++) { + count[nums[j]]--; + if (j > i + 1 && nums[j] == nums[j - 1]) continue; + + for (int k = j + 1; k < nums.Length; k++) { + count[nums[k]]--; + if (k > j + 1 && nums[k] == nums[k - 1]) continue; + + long fourth = (long)target - (long)nums[i] - (long)nums[j] - (long)nums[k]; + if (fourth > int.MaxValue || fourth < int.MinValue) { + continue; + } + + if (count.ContainsKey((int)fourth) && count[(int)fourth] > 0) { + res.Add(new List { nums[i], nums[j], nums[k], (int)fourth }); + } + } + + for (int k = j + 1; k < nums.Length; k++) { + count[nums[k]]++; + } + } + + for (int j = i + 1; j < nums.Length; j++) { + count[nums[j]]++; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: - * $O(n)$ space for the hash map. - * $O(m)$ space for the output array. +- Time complexity: $O(n ^ 3)$ +- Space complexity: + - $O(n)$ space for the hash map. + - $O(m)$ space for the output array. > Where $n$ is the size of the array $nums$ and $m$ is the number of quadruplets. @@ -425,15 +513,54 @@ class Solution { for (let j = i + 1; j < n; j++) { if (j > i + 1 && nums[j] === nums[j - 1]) continue; - let left = j + 1, right = n - 1; + let left = j + 1, + right = n - 1; while (left < right) { const sum = nums[i] + nums[j] + nums[left] + nums[right]; if (sum === target) { res.push([nums[i], nums[j], nums[left], nums[right]]); left++; right--; - while (left < right && nums[left] === nums[left - 1]) left++; - while (left < right && nums[right] === nums[right + 1]) right--; + while (left < right && nums[left] === nums[left - 1]) + left++; + while (left < right && nums[right] === nums[right + 1]) + right--; + } else if (sum < target) { + left++; + } else { + right--; + } + } + } + } + + return res; + } +} +``` + +```csharp +public class Solution { + public List> FourSum(int[] nums, int target) { + Array.Sort(nums); + List> res = new List>(); + int n = nums.Length; + + for (int i = 0; i < n; i++) { + if (i > 0 && nums[i] == nums[i - 1]) continue; + + for (int j = i + 1; j < n; j++) { + if (j > i + 1 && nums[j] == nums[j - 1]) continue; + + int left = j + 1, right = n - 1; + while (left < right) { + long sum = (long)nums[i] + nums[j] + nums[left] + nums[right]; + if (sum == target) { + res.Add(new List { nums[i], nums[j], nums[left], nums[right] }); + left++; + right--; + while (left < right && nums[left] == nums[left - 1]) left++; + while (left < right && nums[right] == nums[right + 1]) right--; } else if (sum < target) { left++; } else { @@ -452,10 +579,10 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: - * $O(1)$ or $O(n)$ space depending on the sorting algorithm. - * $O(m)$ space for the output array. +- Time complexity: $O(n ^ 3)$ +- Space complexity: + - $O(1)$ or $O(n)$ space depending on the sorting algorithm. + - $O(m)$ space for the output array. --- @@ -605,7 +732,8 @@ class Solution { const kSum = (k, start, target) => { if (k === 2) { - let l = start, r = nums.length - 1; + let l = start, + r = nums.length - 1; while (l < r) { const sum = nums[l] + nums[r]; if (sum < target) { @@ -637,11 +765,57 @@ class Solution { } ``` +```csharp +public class Solution { + private List> res; + private List quad; + + public List> FourSum(int[] nums, int target) { + Array.Sort(nums); + res = new List>(); + quad = new List(); + KSum(nums, 4, 0, target); + return res; + } + + private void KSum(int[] nums, int k, int start, long target) { + if (k == 2) { + int l = start, r = nums.Length - 1; + while (l < r) { + long sum = (long)nums[l] + nums[r]; + if (sum < target) { + l++; + } else if (sum > target) { + r--; + } else { + List newQuad = new List(quad); + newQuad.Add(nums[l]); + newQuad.Add(nums[r]); + res.Add(newQuad); + l++; + r--; + while (l < r && nums[l] == nums[l - 1]) l++; + while (l < r && nums[r] == nums[r + 1]) r--; + } + } + return; + } + + for (int i = start; i < nums.Length - k + 1; i++) { + if (i > start && nums[i] == nums[i - 1]) continue; + quad.Add(nums[i]); + KSum(nums, k - 1, i + 1, target - nums[i]); + quad.RemoveAt(quad.Count - 1); + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: - * $O(1)$ or $O(n)$ space depending on the sorting algorithm. - * $O(m)$ space for the output array. \ No newline at end of file +- Time complexity: $O(n ^ 3)$ +- Space complexity: + - $O(1)$ or $O(n)$ space depending on the sorting algorithm. + - $O(m)$ space for the output array. diff --git a/articles/accounts-merge.md b/articles/accounts-merge.md index 665334798..849adad95 100644 --- a/articles/accounts-merge.md +++ b/articles/accounts-merge.md @@ -20,7 +20,7 @@ class Solution: emailIdx[email] = m emailToAcc[m] = accId m += 1 - + adj = [[] for _ in range(m)] for a in accounts: for i in range(2, len(a)): @@ -28,7 +28,7 @@ class Solution: id2 = emailIdx[a[i - 1]] adj[id1].append(id2) adj[id2].append(id1) - + emailGroup = defaultdict(list) # index of acc -> list of emails visited = [False] * m def dfs(node, accId): @@ -37,16 +37,16 @@ class Solution: for nei in adj[node]: if not visited[nei]: dfs(nei, accId) - + for i in range(m): if not visited[i]: dfs(i, emailToAcc[i]) - + res = [] for accId in emailGroup: name = accounts[accId][0] res.append([name] + sorted(emailGroup[accId])) - + return res ``` @@ -284,12 +284,85 @@ class Solution { } ``` +```csharp +public class Solution { + private Dictionary emailIdx = new Dictionary(); + private List emails = new List(); + private List> adj; + private bool[] visited; + private Dictionary> components = new Dictionary>(); + private Dictionary componentName = new Dictionary(); + + public List> AccountsMerge(List> accounts) { + int m = 0; + + for (int accId = 0; accId < accounts.Count; accId++) { + var account = accounts[accId]; + for (int i = 1; i < account.Count; i++) { + string email = account[i]; + if (!emailIdx.ContainsKey(email)) { + emailIdx[email] = m++; + emails.Add(email); + } + } + } + + adj = new List>(); + for (int i = 0; i < m; i++) adj.Add(new List()); + + foreach (var account in accounts) { + for (int i = 2; i < account.Count; i++) { + int u = emailIdx[account[i - 1]]; + int v = emailIdx[account[i]]; + adj[u].Add(v); + adj[v].Add(u); + } + } + + visited = new bool[m]; + + foreach (var account in accounts) { + string name = account[0]; + foreach (var email in account.Skip(1)) { + int idx = emailIdx[email]; + if (!visited[idx]) { + components[idx] = new List(); + componentName[idx] = name; + Dfs(idx, idx); + } + } + } + + var res = new List>(); + foreach (var kvp in components) { + var group = kvp.Value; + group.Sort(StringComparer.Ordinal); + var merged = new List { componentName[kvp.Key] }; + merged.AddRange(group); + res.Add(merged); + } + + return res; + } + + private void Dfs(int node, int root) { + visited[node] = true; + components[root].Add(emails[node]); + foreach (int nei in adj[node]) { + if (!visited[nei]) { + Dfs(nei, root); + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O((n * m)\log (n * m))$ -* Space complexity: $O(n * m)$ +- Time complexity: $O((n * m)\log (n * m))$ +- Space complexity: $O(n * m)$ > Where $n$ is the number of accounts and $m$ is the number of emails. @@ -317,7 +390,7 @@ class Solution: emailIdx[email] = m emailToAcc[m] = accId m += 1 - + adj = [[] for _ in range(m)] for a in accounts: for i in range(2, len(a)): @@ -325,7 +398,7 @@ class Solution: id2 = emailIdx[a[i - 1]] adj[id1].append(id2) adj[id2].append(id1) - + emailGroup = defaultdict(list) # index of acc -> list of emails visited = [False] * m @@ -339,16 +412,16 @@ class Solution: if not visited[nei]: visited[nei] = True queue.append(nei) - + for i in range(m): if not visited[i]: bfs(i, emailToAcc[i]) - + res = [] for accId in emailGroup: name = accounts[accId][0] res.append([name] + sorted(emailGroup[accId])) - + return res ``` @@ -607,12 +680,91 @@ class Solution { } ``` +```csharp +public class Solution { + public List> AccountsMerge(List> accounts) { + int n = accounts.Count; + Dictionary emailIdx = new Dictionary(); + List emails = new List(); + Dictionary emailToAcc = new Dictionary(); + + int m = 0; + for (int accId = 0; accId < n; accId++) { + var account = accounts[accId]; + for (int i = 1; i < account.Count; i++) { + string email = account[i]; + if (!emailIdx.ContainsKey(email)) { + emailIdx[email] = m; + emails.Add(email); + emailToAcc[m] = accId; + m++; + } + } + } + + List> adj = new List>(); + for (int i = 0; i < m; i++) adj.Add(new List()); + + foreach (var account in accounts) { + for (int i = 2; i < account.Count; i++) { + int id1 = emailIdx[account[i]]; + int id2 = emailIdx[account[i - 1]]; + adj[id1].Add(id2); + adj[id2].Add(id1); + } + } + + Dictionary> emailGroup = new Dictionary>(); + bool[] visited = new bool[m]; + + void Bfs(int start, int accId) { + Queue queue = new Queue(); + queue.Enqueue(start); + visited[start] = true; + + if (!emailGroup.ContainsKey(accId)) + emailGroup[accId] = new List(); + + while (queue.Count > 0) { + int node = queue.Dequeue(); + emailGroup[accId].Add(emails[node]); + + foreach (int nei in adj[node]) { + if (!visited[nei]) { + visited[nei] = true; + queue.Enqueue(nei); + } + } + } + } + + for (int i = 0; i < m; i++) { + if (!visited[i]) { + Bfs(i, emailToAcc[i]); + } + } + + List> res = new List>(); + foreach (var kvp in emailGroup) { + int accId = kvp.Key; + string name = accounts[accId][0]; + List merged = new List { name }; + kvp.Value.Sort(StringComparer.Ordinal); + merged.AddRange(kvp.Value); + res.Add(merged); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O((n * m)\log (n * m))$ -* Space complexity: $O(n * m)$ +- Time complexity: $O((n * m)\log (n * m))$ +- Space complexity: $O(n * m)$ > Where $n$ is the number of accounts and $m$ is the number of emails. @@ -922,11 +1074,92 @@ class Solution { } ``` +```csharp +public class UnionFind { + private int[] parent; + private int[] rank; + + public UnionFind(int n) { + parent = new int[n]; + rank = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + rank[i] = 1; + } + } + + public int Find(int x) { + if (x != parent[x]) { + parent[x] = Find(parent[x]); + } + return parent[x]; + } + + public bool Union(int x, int y) { + int rootX = Find(x); + int rootY = Find(y); + + if (rootX == rootY) return false; + + if (rank[rootX] > rank[rootY]) { + parent[rootY] = rootX; + rank[rootX] += rank[rootY]; + } else { + parent[rootX] = rootY; + rank[rootY] += rank[rootX]; + } + + return true; + } +} + +public class Solution { + public List> AccountsMerge(List> accounts) { + int n = accounts.Count; + UnionFind uf = new UnionFind(n); + Dictionary emailToAcc = new Dictionary(); + + for (int i = 0; i < n; i++) { + for (int j = 1; j < accounts[i].Count; j++) { + string email = accounts[i][j]; + if (emailToAcc.ContainsKey(email)) { + uf.Union(i, emailToAcc[email]); + } else { + emailToAcc[email] = i; + } + } + } + + Dictionary> emailGroup = new Dictionary>(); + foreach (var kvp in emailToAcc) { + string email = kvp.Key; + int leader = uf.Find(kvp.Value); + if (!emailGroup.ContainsKey(leader)) { + emailGroup[leader] = new List(); + } + emailGroup[leader].Add(email); + } + + List> res = new List>(); + foreach (var kvp in emailGroup) { + int accId = kvp.Key; + List emails = kvp.Value; + emails.Sort(StringComparer.Ordinal); + List merged = new List { accounts[accId][0] }; + merged.AddRange(emails); + res.Add(merged); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O((n * m)\log (n * m))$ -* Space complexity: $O(n * m)$ +- Time complexity: $O((n * m)\log (n * m))$ +- Space complexity: $O(n * m)$ -> Where $n$ is the number of accounts and $m$ is the number of emails. \ No newline at end of file +> Where $n$ is the number of accounts and $m$ is the number of emails. diff --git a/articles/add-binary.md b/articles/add-binary.md index 424adb990..650317c2e 100644 --- a/articles/add-binary.md +++ b/articles/add-binary.md @@ -29,24 +29,24 @@ public class Solution { public String addBinary(String a, String b) { StringBuilder res = new StringBuilder(); int carry = 0; - + StringBuilder sa = new StringBuilder(a).reverse(); StringBuilder sb = new StringBuilder(b).reverse(); - + for (int i = 0; i < Math.max(sa.length(), sb.length()); i++) { int digitA = i < sa.length() ? sa.charAt(i) - '0' : 0; int digitB = i < sb.length() ? sb.charAt(i) - '0' : 0; - + int total = digitA + digitB + carry; char c = (char)((total % 2) + '0'); res.append(c); carry = total / 2; } - + if (carry > 0) { res.append('1'); } - + return res.reverse().toString(); } } @@ -58,20 +58,20 @@ public: string addBinary(string a, string b) { string res = ""; int carry = 0; - + reverse(a.begin(), a.end()); reverse(b.begin(), b.end()); - + for (int i = 0; i < max(a.length(), b.length()); i++) { int digitA = i < a.length() ? a[i] - '0' : 0; int digitB = i < b.length() ? b[i] - '0' : 0; - + int total = digitA + digitB + carry; char c = (total % 2) + '0'; res += c; carry = total / 2; } - + if (carry) { res += '1'; } @@ -91,35 +91,68 @@ class Solution { addBinary(a, b) { let res = []; let carry = 0; - - a = a.split("").reverse().join(""); - b = b.split("").reverse().join(""); - + + a = a.split('').reverse().join(''); + b = b.split('').reverse().join(''); + for (let i = 0; i < Math.max(a.length, b.length); i++) { const digitA = i < a.length ? a[i] - '0' : 0; const digitB = i < b.length ? b[i] - '0' : 0; - + const total = digitA + digitB + carry; const char = (total % 2).toString(); - res.push(char) + res.push(char); carry = Math.floor(total / 2); } - + if (carry) { res.push('1'); } - res.reverse() + res.reverse(); return res.join(''); } } ``` +```csharp +public class Solution { + public string AddBinary(string a, string b) { + StringBuilder res = new StringBuilder(); + int carry = 0; + + char[] sa = a.ToCharArray(); + char[] sb = b.ToCharArray(); + Array.Reverse(sa); + Array.Reverse(sb); + + int n = Math.Max(sa.Length, sb.Length); + + for (int i = 0; i < n; i++) { + int digitA = i < sa.Length ? sa[i] - '0' : 0; + int digitB = i < sb.Length ? sb[i] - '0' : 0; + + int total = digitA + digitB + carry; + res.Append((char)((total % 2) + '0')); + carry = total / 2; + } + + if (carry > 0) { + res.Append('1'); + } + + char[] resultArray = res.ToString().ToCharArray(); + Array.Reverse(resultArray); + return new string(resultArray); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(max(m, n))$ -* Space complexity: $O(m + n)$ +- Time complexity: $O(max(m, n))$ +- Space complexity: $O(m + n)$ > Where $m$ and $n$ are the lengths of the strings $a$ and $b$ respectively. @@ -212,10 +245,11 @@ class Solution { let res = []; let carry = 0; - let i = a.length - 1, j = b.length - 1; + let i = a.length - 1, + j = b.length - 1; while (i >= 0 || j >= 0 || carry > 0) { - const digitA = i >= 0 ? a[i] - "0" : 0; - const digitB = j >= 0 ? b[j] - "0" : 0; + const digitA = i >= 0 ? a[i] - '0' : 0; + const digitB = j >= 0 ? b[j] - '0' : 0; const total = digitA + digitB + carry; res.push(total % 2); @@ -224,17 +258,43 @@ class Solution { i--; j--; } - res.reverse() + res.reverse(); return res.join(''); } } ``` +```csharp +public class Solution { + public string AddBinary(string a, string b) { + StringBuilder res = new StringBuilder(); + int carry = 0; + + int i = a.Length - 1, j = b.Length - 1; + while (i >= 0 || j >= 0 || carry > 0) { + int digitA = i >= 0 ? a[i] - '0' : 0; + int digitB = j >= 0 ? b[j] - '0' : 0; + + int total = digitA + digitB + carry; + res.Append(total % 2); + carry = total / 2; + + i--; + j--; + } + + char[] resultArray = res.ToString().ToCharArray(); + Array.Reverse(resultArray); + return new string(resultArray); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(max(m, n))$ -* Space complexity: $O(max(m, n))$ +- Time complexity: $O(max(m, n))$ +- Space complexity: $O(max(m, n))$ -> Where $m$ and $n$ are the lengths of the strings $a$ and $b$ respectively. \ No newline at end of file +> Where $m$ and $n$ are the lengths of the strings $a$ and $b$ respectively. diff --git a/articles/add-to-array-form-of-integer.md b/articles/add-to-array-form-of-integer.md index ecab6ca84..7cb704555 100644 --- a/articles/add-to-array-form-of-integer.md +++ b/articles/add-to-array-form-of-integer.md @@ -98,8 +98,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(max(n, m))$ -* Space complexity: $O(n)$. +- Time complexity: $O(max(n, m))$ +- Space complexity: $O(n)$. > Where $n$ is the size of the array $num$ and $m$ is the number of digits in $k$. @@ -184,7 +184,8 @@ class Solution { */ addToArrayForm(num, k) { let res = new Deque(); - let carry = 0, i = num.length - 1; + let carry = 0, + i = num.length - 1; while (i >= 0 || k > 0 || carry > 0) { const digit = k % 10; @@ -211,7 +212,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(max(n, m))$ -* Space complexity: $O(n)$ +- Time complexity: $O(max(n, m))$ +- Space complexity: $O(n)$ -> Where $n$ is the size of the array $num$ and $m$ is the number of digits in $k$. \ No newline at end of file +> Where $n$ is the size of the array $num$ and $m$ is the number of digits in $k$. diff --git a/articles/add-two-numbers-ii.md b/articles/add-two-numbers-ii.md new file mode 100644 index 000000000..6ccb8b95b --- /dev/null +++ b/articles/add-two-numbers-ii.md @@ -0,0 +1,468 @@ +## 1. Reverse List + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]: + def reverseList(head): + prev, curr = None, head + while curr: + temp = curr.next + curr.next = prev + prev = curr + curr = temp + return prev + + l1 = reverseList(l1) + l2 = reverseList(l2) + head = None + carry = 0 + + while l1 or l2 or carry: + v1 = l1.val if l1 else 0 + v2 = l2.val if l2 else 0 + total = v1 + v2 + carry + carry = total // 10 + node = ListNode(total % 10) + node.next = head + head = node + l1 = l1.next if l1 else None + l2 = l2.next if l2 else None + + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + private ListNode reverseList(ListNode head) { + ListNode prev = null, curr = head; + while (curr != null) { + ListNode temp = curr.next; + curr.next = prev; + prev = curr; + curr = temp; + } + return prev; + } + + public ListNode addTwoNumbers(ListNode l1, ListNode l2) { + l1 = reverseList(l1); + l2 = reverseList(l2); + ListNode head = null; + int carry = 0; + + while (l1 != null || l2 != null || carry > 0) { + int v1 = l1 != null ? l1.val : 0; + int v2 = l2 != null ? l2.val : 0; + int total = v1 + v2 + carry; + carry = total / 10; + ListNode node = new ListNode(total % 10); + node.next = head; + head = node; + l1 = l1 != null ? l1.next : null; + l2 = l2 != null ? l2.next : null; + } + + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { + ListNode* reverseList(ListNode* head) { + ListNode* prev = nullptr; + ListNode* curr = head; + while (curr) { + ListNode* temp = curr->next; + curr->next = prev; + prev = curr; + curr = temp; + } + return prev; + } + +public: + ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { + l1 = reverseList(l1); + l2 = reverseList(l2); + ListNode* head = nullptr; + int carry = 0; + + while (l1 || l2 || carry) { + int v1 = l1 ? l1->val : 0; + int v2 = l2 ? l2->val : 0; + int total = v1 + v2 + carry; + carry = total / 10; + ListNode* node = new ListNode(total % 10); + node->next = head; + head = node; + l1 = l1 ? l1->next : nullptr; + l2 = l2 ? l2->next : nullptr; + } + + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ + +class Solution { + /** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ + addTwoNumbers(l1, l2) { + const reverseList = (head) => { + let prev = null, curr = head; + while (curr) { + let temp = curr.next; + curr.next = prev; + prev = curr; + curr = temp; + } + return prev; + } + + l1 = reverseList(l1); + l2 = reverseList(l2); + let head = null; + let carry = 0; + + while (l1 || l2 || carry) { + let v1 = l1 ? l1.val : 0; + let v2 = l2 ? l2.val : 0; + let total = v1 + v2 + carry; + carry = Math.floor(total / 10); + let node = new ListNode(total % 10); + node.next = head; + head = node; + l1 = l1 ? l1.next : null; + l2 = l2 ? l2.next : null; + } + return head; + } +} +``` + +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val=0, ListNode next=null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + private ListNode ReverseList(ListNode head) { + ListNode prev = null, curr = head; + while (curr != null) { + ListNode temp = curr.next; + curr.next = prev; + prev = curr; + curr = temp; + } + return prev; + } + + public ListNode AddTwoNumbers(ListNode l1, ListNode l2) { + l1 = ReverseList(l1); + l2 = ReverseList(l2); + ListNode head = null; + int carry = 0; + + while (l1 != null || l2 != null || carry != 0) { + int v1 = l1 != null ? l1.val : 0; + int v2 = l2 != null ? l2.val : 0; + int total = v1 + v2 + carry; + carry = total / 10; + ListNode node = new ListNode(total % 10); + node.next = head; + head = node; + l1 = l1 != null ? l1.next : null; + l2 = l2 != null ? l2.next : null; + } + + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m + n)$ +* Space complexity: $O(max(m, n))$ for the output list. + +> Where $m$ is the length of $l1$ and $n$ is the length of $l2$. + +--- + +## 2. Stack + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def addTwoNumbers(self, l1: Optional[ListNode], l2: Optional[ListNode]) -> Optional[ListNode]: + s1, s2 = [], [] + + while l1: + s1.append(l1.val) + l1 = l1.next + + while l2: + s2.append(l2.val) + l2 = l2.next + + carry = 0 + head = None + + while s1 or s2 or carry: + v1 = s1.pop() if s1 else 0 + v2 = s2.pop() if s2 else 0 + total = v1 + v2 + carry + carry = total // 10 + node = ListNode(total % 10) + node.next = head + head = node + + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode addTwoNumbers(ListNode l1, ListNode l2) { + Stack s1 = new Stack<>(); + Stack s2 = new Stack<>(); + + while (l1 != null) { + s1.push(l1.val); + l1 = l1.next; + } + + while (l2 != null) { + s2.push(l2.val); + l2 = l2.next; + } + + int carry = 0; + ListNode head = null; + + while (!s1.isEmpty() || !s2.isEmpty() || carry > 0) { + int v1 = s1.isEmpty() ? 0 : s1.pop(); + int v2 = s2.isEmpty() ? 0 : s2.pop(); + int total = v1 + v2 + carry; + carry = total / 10; + ListNode node = new ListNode(total % 10); + node.next = head; + head = node; + } + + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* addTwoNumbers(ListNode* l1, ListNode* l2) { + stack s1, s2; + + while (l1) { + s1.push(l1->val); + l1 = l1->next; + } + + while (l2) { + s2.push(l2->val); + l2 = l2->next; + } + + int carry = 0; + ListNode* head = nullptr; + + while (!s1.empty() || !s2.empty() || carry) { + int v1 = s1.empty() ? 0 : s1.top(); if (!s1.empty()) s1.pop(); + int v2 = s2.empty() ? 0 : s2.top(); if (!s2.empty()) s2.pop(); + int total = v1 + v2 + carry; + carry = total / 10; + ListNode* node = new ListNode(total % 10); + node->next = head; + head = node; + } + + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ + +class Solution { + /** + * @param {ListNode} l1 + * @param {ListNode} l2 + * @return {ListNode} + */ + addTwoNumbers(l1, l2) { + const s1 = [], s2 = []; + + while (l1) { + s1.push(l1.val); + l1 = l1.next; + } + + while (l2) { + s2.push(l2.val); + l2 = l2.next; + } + + let carry = 0; + let head = null; + + while (s1.length || s2.length || carry) { + const v1 = s1.length ? s1.pop() : 0; + const v2 = s2.length ? s2.pop() : 0; + const total = v1 + v2 + carry; + carry = Math.floor(total / 10); + const node = new ListNode(total % 10); + node.next = head; + head = node; + } + + return head; + } +} +``` + +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val=0, ListNode next=null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + public ListNode AddTwoNumbers(ListNode l1, ListNode l2) { + Stack s1 = new Stack(); + Stack s2 = new Stack(); + + while (l1 != null) { + s1.Push(l1.val); + l1 = l1.next; + } + + while (l2 != null) { + s2.Push(l2.val); + l2 = l2.next; + } + + int carry = 0; + ListNode head = null; + + while (s1.Count > 0 || s2.Count > 0 || carry > 0) { + int v1 = s1.Count > 0 ? s1.Pop() : 0; + int v2 = s2.Count > 0 ? s2.Pop() : 0; + int total = v1 + v2 + carry; + carry = total / 10; + ListNode node = new ListNode(total % 10); + node.next = head; + head = node; + } + + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m + n)$ +* Space complexity: $O(m + n)$ + +> Where $m$ is the length of $l1$ and $n$ is the length of $l2$. \ No newline at end of file diff --git a/articles/add-two-numbers.md b/articles/add-two-numbers.md index 6225ac227..87ffdefc1 100644 --- a/articles/add-two-numbers.md +++ b/articles/add-two-numbers.md @@ -13,15 +13,15 @@ class Solution: def add(self, l1: Optional[ListNode], l2: Optional[ListNode], carry: int) -> Optional[ListNode]: if not l1 and not l2 and carry == 0: return None - + v1 = l1.val if l1 else 0 v2 = l2.val if l2 else 0 - + carry, val = divmod(v1 + v2 + carry, 10) - + next_node = self.add( - l1.next if l1 else None, - l2.next if l2 else None, + l1.next if l1 else None, + l2.next if l2 else None, carry ) return ListNode(val, next_node) @@ -47,7 +47,7 @@ public class Solution { if (l1 == null && l2 == null && carry == 0) { return null; } - + int v1 = 0; int v2 = 0; if (l1 != null) { @@ -56,17 +56,17 @@ public class Solution { if (l2 != null) { v2 = l2.val; } - + int sum = v1 + v2 + carry; int newCarry = sum / 10; int nodeValue = sum % 10; - + ListNode nextNode = add( - (l1 != null) ? l1.next : null, - (l2 != null) ? l2.next : null, + (l1 != null) ? l1.next : null, + (l2 != null) ? l2.next : null, newCarry ); - + return new ListNode(nodeValue, nextNode); } @@ -94,7 +94,7 @@ public: if (!l1 && !l2 && carry == 0) { return nullptr; } - + int v1 = 0; int v2 = 0; if (l1) { @@ -103,14 +103,14 @@ public: if (l2) { v2 = l2->val; } - + int sum = v1 + v2 + carry; int newCarry = sum / 10; int nodeValue = sum % 10; ListNode* nextNode = add( - (l1 ? l1->next : nullptr), - (l2 ? l2->next : nullptr), + (l1 ? l1->next : nullptr), + (l2 ? l2->next : nullptr), newCarry ); @@ -145,7 +145,7 @@ class Solution { if (!l1 && !l2 && carry === 0) { return null; } - + let v1 = 0; let v2 = 0; if (l1) { @@ -154,15 +154,15 @@ class Solution { if (l2) { v2 = l2.val; } - + let sum = v1 + v2 + carry; let newCarry = Math.floor(sum / 10); let nodeValue = sum % 10; let nextNode = this.add( - (l1 ? l1.next : null), - (l2 ? l2.next : null), - newCarry + l1 ? l1.next : null, + l2 ? l2.next : null, + newCarry, ); return new ListNode(nodeValue, nextNode); @@ -197,7 +197,7 @@ public class Solution { if (l1 == null && l2 == null && carry == 0) { return null; } - + int v1 = 0; int v2 = 0; if (l1 != null) { @@ -212,8 +212,8 @@ public class Solution { int nodeValue = sum % 10; ListNode nextNode = Add( - (l1 != null ? l1.next : null), - (l2 != null ? l2.next : null), + (l1 != null ? l1.next : null), + (l2 != null ? l2.next : null), newCarry ); @@ -238,7 +238,7 @@ func add(l1 *ListNode, l2 *ListNode, carry int) *ListNode { if l1 == nil && l2 == nil && carry == 0 { return nil } - + v1, v2 := 0, 0 if l1 != nil { v1 = l1.Val @@ -246,10 +246,10 @@ func add(l1 *ListNode, l2 *ListNode, carry int) *ListNode { if l2 != nil { v2 = l2.Val } - + sum := v1 + v2 + carry carry, val := sum/10, sum%10 - + var nextNode *ListNode nextL1 := l1 nextL2 := l2 @@ -303,12 +303,46 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + private func add(_ l1: ListNode?, _ l2: ListNode?, _ carry: Int) -> ListNode? { + if l1 == nil && l2 == nil && carry == 0 { + return nil + } + + let v1 = l1?.val ?? 0 + let v2 = l2?.val ?? 0 + + let sum = v1 + v2 + carry + let newCarry = sum / 10 + let val = sum % 10 + + let nextNode = add(l1?.next, l2?.next, newCarry) + return ListNode(val, nextNode) + } + + func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { + return add(l1, l2, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n)$ -* Space complexity: $O(m + n)$ +- Time complexity: $O(m + n)$ +- Space complexity: $O(m + n)$ > Where $m$ is the length of $l1$ and $n$ is the length of $l2$. @@ -523,7 +557,7 @@ func addTwoNumbers(l1 *ListNode, l2 *ListNode) *ListNode { v1 = l1.Val l1 = l1.Next } - + v2 := 0 if l2 != nil { v2 = l2.Val @@ -577,11 +611,49 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func addTwoNumbers(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { + let dummy = ListNode(0) + var cur = dummy + var l1 = l1, l2 = l2 + var carry = 0 + + while l1 != nil || l2 != nil || carry != 0 { + let v1 = l1?.val ?? 0 + let v2 = l2?.val ?? 0 + + let sum = v1 + v2 + carry + carry = sum / 10 + let val = sum % 10 + cur.next = ListNode(val) + + cur = cur.next! + l1 = l1?.next + l2 = l2?.next + } + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(m + n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(max(m, n))$ for the output list. -> Where $m$ is the length of $l1$ and $n$ is the length of $l2$. \ No newline at end of file +> Where $m$ is the length of $l1$ and $n$ is the length of $l2$. diff --git a/articles/all-possible-full-binary-trees.md b/articles/all-possible-full-binary-trees.md new file mode 100644 index 000000000..58ce3a748 --- /dev/null +++ b/articles/all-possible-full-binary-trees.md @@ -0,0 +1,693 @@ +## 1. Recursion + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]: + def backtrack(n): + if n == 0: + return [] + if n == 1: + return [TreeNode(0)] + + res = [] + for l in range(n): + r = n - 1 - l + leftTrees, rightTrees = backtrack(l), backtrack(r) + + for t1 in leftTrees: + for t2 in rightTrees: + res.append(TreeNode(0, t1, t2)) + return res + + return backtrack(n) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List allPossibleFBT(int n) { + return backtrack(n); + } + + private List backtrack(int n) { + if (n == 0) { + return new ArrayList<>(); + } + if (n == 1) { + return Arrays.asList(new TreeNode(0)); + } + + List res = new ArrayList<>(); + for (int l = 0; l < n; l++) { + int r = n - 1 - l; + List leftTrees = backtrack(l); + List rightTrees = backtrack(r); + + for (TreeNode t1 : leftTrees) { + for (TreeNode t2 : rightTrees) { + res.add(new TreeNode(0, t1, t2)); + } + } + } + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector allPossibleFBT(int n) { + return backtrack(n); + } + +private: + vector backtrack(int n) { + if (n == 0) { + return {}; + } + if (n == 1) { + return {new TreeNode(0)}; + } + + vector res; + for (int l = 0; l < n; l++) { + int r = n - 1 - l; + vector leftTrees = backtrack(l); + vector rightTrees = backtrack(r); + + for (auto& t1 : leftTrees) { + for (auto& t2 : rightTrees) { + res.push_back(new TreeNode(0, t1, t2)); + } + } + } + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number} n + * @return {TreeNode[]} + */ + allPossibleFBT(n) { + const backtrack = (n) => { + if (n === 0) { + return []; + } + if (n === 1) { + return [new TreeNode(0)]; + } + + let res = []; + for (let l = 0; l < n; l++) { + let r = n - 1 - l; + let leftTrees = backtrack(l); + let rightTrees = backtrack(r); + + for (let t1 of leftTrees) { + for (let t2 of rightTrees) { + res.push(new TreeNode(0, t1, t2)); + } + } + } + return res; + }; + + return backtrack(n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n * 2 ^ n)$ + +--- + +## 2. Recursion (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]: + if n % 2 == 0: + return [] + if n == 1: + return [TreeNode(0)] + + res = [] + for left in range(1, n, 2): + leftSubTree = self.allPossibleFBT(left) + rightSubTree = self.allPossibleFBT(n - 1 - left) + for l in leftSubTree: + for r in rightSubTree: + root = TreeNode(0, l, r) + res.append(root) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List allPossibleFBT(int n) { + if (n % 2 == 0) { + return new ArrayList<>(); + } + if (n == 1) { + return Arrays.asList(new TreeNode(0)); + } + + List res = new ArrayList<>(); + for (int left = 1; left < n; left += 2) { + List leftSubTree = allPossibleFBT(left); + List rightSubTree = allPossibleFBT(n - 1 - left); + for (TreeNode l : leftSubTree) { + for (TreeNode r : rightSubTree) { + TreeNode root = new TreeNode(0, l, r); + res.add(root); + } + } + } + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector allPossibleFBT(int n) { + if (n % 2 == 0) { + return {}; + } + if (n == 1) { + return {new TreeNode(0)}; + } + + vector res; + for (int left = 1; left < n; left += 2) { + vector leftSubTree = allPossibleFBT(left); + vector rightSubTree = allPossibleFBT(n - 1 - left); + for (auto& l : leftSubTree) { + for (auto& r : rightSubTree) { + TreeNode* root = new TreeNode(0, l, r); + res.push_back(root); + } + } + } + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number} n + * @return {TreeNode[]} + */ + allPossibleFBT(n) { + if (n % 2 === 0) { + return []; + } + if (n === 1) { + return [new TreeNode(0)]; + } + + let res = []; + for (let left = 1; left < n; left += 2) { + let leftSubTree = this.allPossibleFBT(left); + let rightSubTree = this.allPossibleFBT(n - 1 - left); + for (let l of leftSubTree) { + for (let r of rightSubTree) { + let root = new TreeNode(0, l, r); + res.push(root); + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n * 2 ^ n)$ + +--- + +## 3. Dynamic Programming (Top-Down) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]: + dp = {} + + def dfs(n): + if n % 2 == 0: + return [] + if n == 1: + return [TreeNode(0)] + if n in dp: + return dp[n] + + res = [] + for left in range(1, n, 2): + leftSubTree = dfs(left) + rightSubTree = dfs(n - 1 - left) + for l in leftSubTree: + for r in rightSubTree: + res.append(TreeNode(0, l, r)) + + dp[n] = res + return res + + return dfs(n) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private List[] dp; + + public List allPossibleFBT(int n) { + dp = new ArrayList[n + 1]; + return dfs(n); + } + + private List dfs(int n) { + if (n % 2 == 0) { + return new ArrayList<>(); + } + if (n == 1) { + return Arrays.asList(new TreeNode(0)); + } + if (dp[n] != null) { + return dp[n]; + } + + List res = new ArrayList<>(); + for (int left = 1; left < n; left += 2) { + List leftSubTree = dfs(left); + List rightSubTree = dfs(n - 1 - left); + for (TreeNode l : leftSubTree) { + for (TreeNode r : rightSubTree) { + res.add(new TreeNode(0, l, r)); + } + } + } + + return dp[n] = res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +private: + vector> dp; + +public: + vector allPossibleFBT(int n) { + dp.resize(n + 1); + return dfs(n); + } + + vector dfs(int n) { + if (n % 2 == 0) { + return {}; + } + if (n == 1) { + return {new TreeNode(0)}; + } + if (!dp[n].empty()) { + return dp[n]; + } + + vector res; + for (int left = 1; left < n; left += 2) { + vector leftSubTree = dfs(left); + vector rightSubTree = dfs(n - 1 - left); + for (auto& l : leftSubTree) { + for (auto& r : rightSubTree) { + res.push_back(new TreeNode(0, l, r)); + } + } + } + + return dp[n] = res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number} n + * @return {TreeNode[]} + */ + allPossibleFBT(n) { + let dp = new Array(n + 1); + + const dfs = (n) => { + if (n % 2 === 0) { + return []; + } + if (n === 1) { + return [new TreeNode(0)]; + } + if (dp[n]) { + return dp[n]; + } + + let res = []; + for (let left = 1; left < n; left += 2) { + let leftSubTree = dfs(left); + let rightSubTree = dfs(n - 1 - left); + for (let t1 of leftSubTree) { + for (let t2 of rightSubTree) { + res.push(new TreeNode(0, t1, t2)); + } + } + } + + return (dp[n] = res); + }; + + return dfs(n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n * 2 ^ n)$ + +--- + +## 4. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def allPossibleFBT(self, n: int) -> List[Optional[TreeNode]]: + if n % 2 == 0: + return [] + + dp = [[] for _ in range(n + 1)] + dp[1] = [TreeNode(0)] + + for nodes in range(3, n + 1, 2): + res = [] + for left in range(1, nodes, 2): + right = nodes - 1 - left + for t1 in dp[left]: + for t2 in dp[right]: + res.append(TreeNode(0, t1, t2)) + dp[nodes] = res + + return dp[n] +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List allPossibleFBT(int n) { + if (n % 2 == 0) { + return new ArrayList<>(); + } + + List[] dp = new ArrayList[n + 1]; + for (int i = 0; i <= n; i++) { + dp[i] = new ArrayList<>(); + } + dp[1].add(new TreeNode(0)); + + for (int nodes = 3; nodes <= n; nodes += 2) { + List res = new ArrayList<>(); + for (int left = 1; left < nodes; left += 2) { + int right = nodes - 1 - left; + for (TreeNode t1 : dp[left]) { + for (TreeNode t2 : dp[right]) { + res.add(new TreeNode(0, t1, t2)); + } + } + } + dp[nodes] = res; + } + + return dp[n]; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector allPossibleFBT(int n) { + if (n % 2 == 0) { + return {}; + } + + vector> dp(n + 1); + dp[1].push_back(new TreeNode(0)); + + for (int nodes = 3; nodes <= n; nodes += 2) { + vector res; + for (int left = 1; left < nodes; left += 2) { + int right = nodes - 1 - left; + for (auto& t1 : dp[left]) { + for (auto& t2 : dp[right]) { + res.push_back(new TreeNode(0, t1, t2)); + } + } + } + dp[nodes] = res; + } + + return dp[n]; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number} n + * @return {TreeNode[]} + */ + allPossibleFBT(n) { + if (n % 2 === 0) { + return []; + } + + let dp = Array.from({ length: n + 1 }, () => []); + dp[1] = [new TreeNode(0)]; + + for (let nodes = 3; nodes <= n; nodes += 2) { + let res = []; + for (let left = 1; left < nodes; left += 2) { + let right = nodes - 1 - left; + for (let t1 of dp[left]) { + for (let t2 of dp[right]) { + res.push(new TreeNode(0, t1, t2)); + } + } + } + dp[nodes] = res; + } + + return dp[n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n * 2 ^ n)$ diff --git a/articles/anagram-groups.md b/articles/anagram-groups.md index a0aae3216..0969c406c 100644 --- a/articles/anagram-groups.md +++ b/articles/anagram-groups.md @@ -80,7 +80,7 @@ public class Solution { } res[sortedS].Add(s); } - return res.Values.ToList>(); + return res.Values.ToList>(); } } ``` @@ -125,12 +125,27 @@ class Solution { } ``` +```swift +class Solution { + func groupAnagrams(_ strs: [String]) -> [[String]] { + var res = [String: [String]]() + + for s in strs { + let sortedS = String(s.sorted()) + res[sortedS, default: []].append(s) + } + + return Array(res.values) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n \log n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n \log n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of strings and $n$ is the length of the longest string. @@ -234,7 +249,7 @@ public class Solution { } res[key].Add(s); } - return res.Values.ToList>(); + return res.Values.ToList>(); } } ``` @@ -277,11 +292,31 @@ class Solution { } ``` +```swift +class Solution { + func groupAnagrams(_ strs: [String]) -> [[String]] { + var res = [Array: [String]]() + + for s in strs { + var count = [Int](repeating: 0, count: 26) + for c in s { + count[Int(c.asciiValue!) - 97] += 1 + } + res[count, default: []].append(s) + } + + return Array(res.values) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m)$ +- Time complexity: $O(m * n)$ +- Space complexity: + - $O(m)$ extra space. + - $O(m * n)$ space for the output list. > Where $m$ is the number of strings and $n$ is the length of the longest string. diff --git a/articles/analyze-user-website-visit-pattern.md b/articles/analyze-user-website-visit-pattern.md new file mode 100644 index 000000000..849afb47e --- /dev/null +++ b/articles/analyze-user-website-visit-pattern.md @@ -0,0 +1,226 @@ +## 1. Hash Map + +::tabs-start + +```python +class Solution: + def mostVisitedPattern(self, username: List[str], timestamp: List[int], website: List[str]) -> List[str]: + arr = list(zip(timestamp, username, website)) + arr.sort() + + mp = defaultdict(list) + for time, user, site in arr: + mp[user].append(site) + + count = defaultdict(int) + for user in mp: + patterns = set() + cur = mp[user] + for i in range(len(cur)): + for j in range(i + 1, len(cur)): + for k in range(j + 1, len(cur)): + patterns.add((cur[i], cur[j], cur[k])) + for p in patterns: + count[p] += 1 + + max_count = 0 + res = tuple() + for pattern in count: + if count[pattern] > max_count or (count[pattern] == max_count and pattern < res): + max_count = count[pattern] + res = pattern + + return list(res) +``` + +```java +public class Solution { + public List mostVisitedPattern(String[] username, int[] timestamp, String[] website) { + int n = timestamp.length; + List arr = new ArrayList<>(); + for (int i = 0; i < n; i++) arr.add(new int[]{timestamp[i], i}); + arr.sort((a, b) -> Integer.compare(a[0], b[0])); + + Map> mp = new HashMap<>(); + for (int[] p : arr) { + int idx = p[1]; + mp.computeIfAbsent(username[idx], k -> new ArrayList<>()).add(website[idx]); + } + + Map count = new HashMap<>(); + for (String user : mp.keySet()) { + List cur = mp.get(user); + Set patterns = new HashSet<>(); + for (int i = 0; i < cur.size(); i++) + for (int j = i + 1; j < cur.size(); j++) + for (int k = j + 1; k < cur.size(); k++) + patterns.add(cur.get(i) + "#" + cur.get(j) + "#" + cur.get(k)); + for (String p : patterns) + count.put(p, count.getOrDefault(p, 0) + 1); + } + + String res = ""; + int max_count = 0; + for (String p : count.keySet()) { + int c = count.get(p); + if (c > max_count || (c == max_count && p.compareTo(res) < 0)) { + max_count = c; + res = p; + } + } + return Arrays.asList(res.split("#")); + } +} +``` + +```cpp +class Solution { +public: + vector mostVisitedPattern(vector& username, vector& timestamp, vector& website) { + int n = timestamp.size(); + vector> arr; + for (int i = 0; i < n; ++i) arr.push_back({timestamp[i], i}); + sort(arr.begin(), arr.end(), + [](auto& a, auto& b){ return a.first < b.first; }); + + unordered_map> mp; + for (auto& p : arr) mp[username[p.second]].push_back(website[p.second]); + + unordered_map count; + for (auto& kv : mp) { + auto& cur = kv.second; + unordered_set patterns; + for (int i = 0; i < (int)cur.size(); ++i) + for (int j = i + 1; j < (int)cur.size(); ++j) + for (int k = j + 1; k < (int)cur.size(); ++k) + patterns.insert(cur[i] + "#" + cur[j] + "#" + cur[k]); + for (auto& p : patterns) ++count[p]; + } + + int maxCnt = 0; + string res; + for (auto& kv : count) + if (kv.second > maxCnt || + (kv.second == maxCnt && (res.empty() || kv.first < res))) { + maxCnt = kv.second; + res = kv.first; + } + + vector ans; + string tmp; + for (char ch : res) { + if (ch == '#') { + ans.push_back(tmp); + tmp.clear(); + } else { + tmp += ch; + } + } + ans.push_back(tmp); + return ans; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} username + * @param {number[]} timestamp + * @param {string[]} website + * @return {string[]} + */ + mostVisitedPattern(username, timestamp, website) { + const n = timestamp.length; + const arr = []; + for (let i = 0; i < n; i++) arr.push([timestamp[i], i]); + arr.sort((a, b) => a[0] - b[0]); + + const mp = new Map(); + for (const [, idx] of arr) { + const user = username[idx], + site = website[idx]; + if (!mp.has(user)) mp.set(user, []); + mp.get(user).push(site); + } + + const count = new Map(); + for (const user of mp.keys()) { + const cur = mp.get(user); + const patterns = new Set(); + for (let i = 0; i < cur.length; i++) { + for (let j = i + 1; j < cur.length; j++) { + for (let k = j + 1; k < cur.length; k++) { + patterns.add(`${cur[i]}#${cur[j]}#${cur[k]}`); + } + } + } + for (const p of patterns) { + count.set(p, (count.get(p) || 0) + 1); + } + } + + let maxCnt = 0, + res = ''; + for (const [pat, c] of count.entries()) { + if (c > maxCnt || (c === maxCnt && (res === '' || pat < res))) { + maxCnt = c; + res = pat; + } + } + return res.split('#'); + } +} +``` + +```csharp +public class Solution { + public List MostVisitedPattern(string[] username, int[] timestamp, string[] website) { + int n = timestamp.Length; + var arr = new List<(int t, int i)>(); + for (int i = 0; i < n; i++) arr.Add((timestamp[i], i)); + arr.Sort((a, b) => a.t.CompareTo(b.t)); + + var mp = new Dictionary>(); + foreach (var (t, idx) in arr) { + string user = username[idx], site = website[idx]; + if (!mp.ContainsKey(user)) mp[user] = new List(); + mp[user].Add(site); + } + + var count = new Dictionary(); + foreach (var kv in mp) { + var cur = kv.Value; + var patterns = new HashSet(); + for (int i = 0; i < cur.Count; i++) + for (int j = i + 1; j < cur.Count; j++) + for (int k = j + 1; k < cur.Count; k++) + patterns.Add($"{cur[i]}#{cur[j]}#{cur[k]}"); + foreach (var p in patterns) { + count[p] = count.ContainsKey(p) ? count[p] + 1 : 1; + } + } + + int maxCnt = 0; + string res = ""; + foreach (var kv in count) { + if (kv.Value > maxCnt || + (kv.Value == maxCnt && + (res == "" || string.Compare(kv.Key, res, StringComparison.Ordinal) < 0))) { + maxCnt = kv.Value; + res = kv.Key; + } + } + return new List(res.Split('#')); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n + n * u + n ^ 3 * w)$ +- Space complexity: $O(n * u + n ^ 3 * w)$ + +> Where $n$ is the size of the array $timestamp$, $u$ is the maximum length of any string in the array $username$, and $w$ is the maximum length of any string in the array $website$. diff --git a/articles/append-characters-to-string-to-make-subsequence.md b/articles/append-characters-to-string-to-make-subsequence.md new file mode 100644 index 000000000..66c5b6eb5 --- /dev/null +++ b/articles/append-characters-to-string-to-make-subsequence.md @@ -0,0 +1,213 @@ +## 1. Two Pointers + +::tabs-start + +```python +class Solution: + def appendCharacters(self, s: str, t: str) -> int: + i, j = 0, 0 + + while i < len(s) and j < len(t): + if s[i] == t[j]: + i += 1 + j += 1 + else: + i += 1 + return len(t) - j +``` + +```java +public class Solution { + public int appendCharacters(String s, String t) { + int i = 0, j = 0; + + while (i < s.length() && j < t.length()) { + if (s.charAt(i) == t.charAt(j)) { + i++; + j++; + } else { + i++; + } + } + return t.length() - j; + } +} +``` + +```cpp +class Solution { +public: + int appendCharacters(string s, string t) { + int i = 0, j = 0; + + while (i < s.length() && j < t.length()) { + if (s[i] == t[j]) { + i++; + j++; + } else { + i++; + } + } + return t.length() - j; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} t + * @return {number} + */ + appendCharacters(s, t) { + let i = 0, + j = 0; + + while (i < s.length && j < t.length) { + if (s[i] === t[j]) { + i++; + j++; + } else { + i++; + } + } + return t.length - j; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m)$ +- Space complexity: $O(1)$ + +> Where $n$ and $m$ are the lengths of the strings $s$ and $t$, respectively. + +--- + +## 2. Index Jumping + +::tabs-start + +```python +class Solution: + def appendCharacters(self, s: str, t: str) -> int: + n, m = len(s), len(t) + store = [[n + 1] * 26 for _ in range(n)] + store[n - 1][ord(s[n - 1]) - ord('a')] = n - 1 + + for i in range(n - 2, -1, -1): + store[i] = store[i + 1][:] + store[i][ord(s[i]) - ord('a')] = i + + i, j = 0, 0 + while i < n and j < m: + if store[i][ord(t[j]) - ord('a')] == n + 1: + break + + i = store[i][ord(t[j]) - ord('a')] + 1 + j += 1 + + return m - j +``` + +```java +public class Solution { + public int appendCharacters(String s, String t) { + int n = s.length(), m = t.length(); + int[][] store = new int[n][26]; + for (int[] row : store) { + Arrays.fill(row, n + 1); + } + store[n - 1][s.charAt(n - 1) - 'a'] = n - 1; + + for (int i = n - 2; i >= 0; i--) { + store[i] = store[i + 1].clone(); + store[i][s.charAt(i) - 'a'] = i; + } + + int i = 0, j = 0; + while (i < n && j < m) { + if (store[i][t.charAt(j) - 'a'] == n + 1) { + break; + } + i = store[i][t.charAt(j) - 'a'] + 1; + j++; + } + + return m - j; + } +} +``` + +```cpp +class Solution { +public: + int appendCharacters(string s, string t) { + int n = s.length(), m = t.length(); + vector> store(n, vector(26, n + 1)); + store[n - 1][s[n - 1] - 'a'] = n - 1; + + for (int i = n - 2; i >= 0; i--) { + store[i] = store[i + 1]; + store[i][s[i] - 'a'] = i; + } + + int i = 0, j = 0; + while (i < n && j < m) { + if (store[i][t[j] - 'a'] == n + 1) { + break; + } + i = store[i][t[j] - 'a'] + 1; + j++; + } + + return m - j; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} t + * @return {number} + */ + appendCharacters(s, t) { + const n = s.length, + m = t.length; + const store = Array.from({ length: n }, () => Array(26).fill(n + 1)); + store[n - 1][s.charCodeAt(n - 1) - 97] = n - 1; + + for (let i = n - 2; i >= 0; i--) { + store[i] = store[i + 1].slice(); + store[i][s.charCodeAt(i) - 97] = i; + } + + let i = 0, + j = 0; + while (i < n && j < m) { + if (store[i][t.charCodeAt(j) - 97] === n + 1) { + break; + } + i = store[i][t.charCodeAt(j) - 97] + 1; + j++; + } + + return m - j; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m)$ +- Space complexity: $O(n)$ + +> Where $n$ and $m$ are the lengths of the strings $s$ and $t$, respectively. diff --git a/articles/arithmetic-slices-ii-subsequence.md b/articles/arithmetic-slices-ii-subsequence.md index 427b1557c..ec1718c72 100644 --- a/articles/arithmetic-slices-ii-subsequence.md +++ b/articles/arithmetic-slices-ii-subsequence.md @@ -155,8 +155,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: $O(n ^ 3)$ +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n ^ 3)$ --- @@ -185,7 +185,7 @@ public class Solution { int n = nums.length; int res = 0; Map[] dp = new HashMap[n]; - + for (int i = 0; i < n; i++) { dp[i] = new HashMap<>(); for (int j = 0; j < i; j++) { @@ -207,7 +207,7 @@ public: int n = nums.size(); int res = 0; vector> dp(n); - + for (int i = 0; i < n; i++) { for (int j = 0; j < i; j++) { long long diff = (long long) nums[i] - nums[j]; @@ -249,8 +249,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -331,7 +331,8 @@ class Solution { * @return {number} */ numberOfArithmeticSlices(nums) { - let res = 0, n = nums.length; + let res = 0, + n = nums.length; const s = new Set(nums); const dp = Array.from({ length: n }, () => new Map()); @@ -354,8 +355,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -495,5 +496,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ \ No newline at end of file +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ diff --git a/articles/arranging-coins.md b/articles/arranging-coins.md index cb8920a4a..97219c171 100644 --- a/articles/arranging-coins.md +++ b/articles/arranging-coins.md @@ -56,12 +56,25 @@ class Solution { } ``` +```csharp +public class Solution { + public int ArrangeCoins(int n) { + int row = 0; + while (n - row > 0) { + row++; + n -= row; + } + return row; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\sqrt {n})$ -* Space complexity: $O(1)$ +- Time complexity: $O(\sqrt {n})$ +- Space complexity: $O(1)$ --- @@ -83,7 +96,7 @@ class Solution: else: l = mid + 1 res = max(res, mid) - + return res ``` @@ -102,7 +115,7 @@ public class Solution { res = Math.max(res, mid); } } - + return res; } } @@ -124,7 +137,7 @@ public: res = max(res, mid); } } - + return res; } }; @@ -137,7 +150,9 @@ class Solution { * @return {number} */ arrangeCoins(n) { - let l = 1, r = n, res = 0; + let l = 1, + r = n, + res = 0; while (l <= r) { let mid = Math.floor((l + r) / 2); @@ -155,12 +170,35 @@ class Solution { } ``` +```csharp +public class Solution { + public int ArrangeCoins(int n) { + int l = 1, r = n; + int res = 0; + + while (l <= r) { + int mid = l + (r - l) / 2; + long coins = (long)mid * (mid + 1) / 2; + + if (coins > n) { + r = mid - 1; + } else { + res = Math.Max(res, mid); + l = mid + 1; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ --- @@ -181,7 +219,7 @@ class Solution: l = mid + 1 else: r = mid - + return l - 1 ``` @@ -226,7 +264,7 @@ public: r = mid; } } - + return l - 1; } }; @@ -243,7 +281,8 @@ class Solution { return n == 1 ? 1 : n - 1; } - let l = 1, r = (n / 2) + 1; + let l = 1, + r = n / 2 + 1; while (l < r) { let mid = Math.floor((l + r) / 2); let coins = (mid * (mid + 1)) / 2; @@ -259,12 +298,36 @@ class Solution { } ``` +```csharp +public class Solution { + public int ArrangeCoins(int n) { + if (n <= 3) { + return n == 1 ? 1 : n - 1; + } + + int l = 1, r = (n / 2) + 1; + while (l < r) { + int mid = (l + r) / 2; + long coins = (long)mid * (mid + 1) / 2; + + if (coins <= n) { + l = mid + 1; + } else { + r = mid; + } + } + + return l - 1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ --- @@ -345,12 +408,32 @@ class Solution { } ``` +```csharp +public class Solution { + public int ArrangeCoins(int n) { + int mask = 1 << 15; + int rows = 0; + + while (mask > 0) { + rows |= mask; + long coins = (long)rows * (rows + 1) / 2; + if (coins > n) { + rows ^= mask; + } + mask >>= 1; + } + + return rows; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ since we iterate $15$ times. -* Space complexity: $O(1)$ +- Time complexity: $O(1)$ since we iterate $15$ times. +- Space complexity: $O(1)$ --- @@ -393,9 +476,17 @@ class Solution { } ``` +```csharp +public class Solution { + public int ArrangeCoins(int n) { + return (int)(Math.Sqrt(2L * n + 0.25) - 0.5); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ or $O(\sqrt {n})$ depending on the language. -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(1)$ or $O(\sqrt {n})$ depending on the language. +- Space complexity: $O(1)$ diff --git a/articles/array-with-elements-not-equal-to-average-of-neighbors.md b/articles/array-with-elements-not-equal-to-average-of-neighbors.md new file mode 100644 index 000000000..ae5064818 --- /dev/null +++ b/articles/array-with-elements-not-equal-to-average-of-neighbors.md @@ -0,0 +1,341 @@ +## 1. Greedy + +::tabs-start + +```python +class Solution: + def rearrangeArray(self, nums: List[int]) -> List[int]: + nums.sort() + res = [] + l, r = 0, len(nums) - 1 + while len(res) != len(nums): + res.append(nums[l]) + l += 1 + if l <= r: + res.append(nums[r]) + r -= 1 + return res +``` + +```java +public class Solution { + public int[] rearrangeArray(int[] nums) { + Arrays.sort(nums); + int[] res = new int[nums.length]; + int l = 0, r = nums.length - 1; + int idx = 0; + + while (idx != nums.length) { + res[idx++] = nums[l++]; + if (l <= r) { + res[idx++] = nums[r--]; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector rearrangeArray(vector& nums) { + sort(nums.begin(), nums.end()); + vector res; + int l = 0, r = nums.size() - 1; + + while (res.size() != nums.size()) { + res.push_back(nums[l++]); + if (l <= r) { + res.push_back(nums[r--]); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + rearrangeArray(nums) { + nums.sort((a, b) => a - b); + const res = []; + let l = 0, + r = nums.length - 1; + + while (res.length !== nums.length) { + res.push(nums[l++]); + if (l <= r) { + res.push(nums[r--]); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n\log n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Greedy (Space Optimized) + +::tabs-start + +```python +class Solution: + def rearrangeArray(self, nums: List[int]) -> List[int]: + nums.sort() + for i in range(1, len(nums), 2): + nums[i], nums[i - 1] = nums[i - 1], nums[i] + return nums +``` + +```java +public class Solution { + public int[] rearrangeArray(int[] nums) { + Arrays.sort(nums); + for (int i = 1; i < nums.length; i += 2) { + int temp = nums[i]; + nums[i] = nums[i - 1]; + nums[i - 1] = temp; + } + return nums; + } +} +``` + +```cpp +class Solution { +public: + vector rearrangeArray(vector& nums) { + sort(nums.begin(), nums.end()); + for (int i = 1; i < nums.size(); i += 2) { + swap(nums[i], nums[i - 1]); + } + return nums; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + rearrangeArray(nums) { + nums.sort((a, b) => a - b); + for (let i = 1; i < nums.length; i += 2) { + [nums[i], nums[i - 1]] = [nums[i - 1], nums[i]]; + } + return nums; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 3. Greedy (Optimal) - I + +::tabs-start + +```python +class Solution: + def rearrangeArray(self, nums: List[int]) -> List[int]: + n = len(nums) + + for i in range(1, n - 1): + if 2 * nums[i] == (nums[i - 1] + nums[i + 1]): + nums[i], nums[i + 1] = nums[i + 1], nums[i] + + for i in range(n - 2, 0, -1): + if 2 * nums[i] == (nums[i - 1] + nums[i + 1]): + nums[i], nums[i - 1] = nums[i - 1], nums[i] + + return nums +``` + +```java +public class Solution { + public int[] rearrangeArray(int[] nums) { + int n = nums.length; + + for (int i = 1; i < n - 1; i++) { + if (2 * nums[i] == (nums[i - 1] + nums[i + 1])) { + int temp = nums[i]; + nums[i] = nums[i + 1]; + nums[i + 1] = temp; + } + } + + for (int i = n - 2; i > 0; i--) { + if (2 * nums[i] == (nums[i - 1] + nums[i + 1])) { + int temp = nums[i]; + nums[i] = nums[i - 1]; + nums[i - 1] = temp; + } + } + + return nums; + } +} +``` + +```cpp +class Solution { +public: + vector rearrangeArray(vector& nums) { + int n = nums.size(); + + for (int i = 1; i < n - 1; i++) { + if (2 * nums[i] == (nums[i - 1] + nums[i + 1])) { + swap(nums[i], nums[i + 1]); + } + } + + for (int i = n - 2; i > 0; i--) { + if (2 * nums[i] == (nums[i - 1] + nums[i + 1])) { + swap(nums[i], nums[i - 1]); + } + } + + return nums; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + rearrangeArray(nums) { + const n = nums.length; + + for (let i = 1; i < n - 1; i++) { + if (2 * nums[i] === nums[i - 1] + nums[i + 1]) { + [nums[i], nums[i + 1]] = [nums[i + 1], nums[i]]; + } + } + + for (let i = n - 2; i > 0; i--) { + if (2 * nums[i] === nums[i - 1] + nums[i + 1]) { + [nums[i], nums[i - 1]] = [nums[i - 1], nums[i]]; + } + } + + return nums; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 4. Greedy Optimal - II + +::tabs-start + +```python +class Solution: + def rearrangeArray(self, nums: List[int]) -> List[int]: + increase = nums[0] < nums[1] + for i in range(1, len(nums) - 1): + if ((increase and nums[i] < nums[i + 1]) or + (not increase and nums[i] > nums[i + 1]) + ): + nums[i], nums[i + 1] = nums[i + 1], nums[i] + increase = not increase + return nums +``` + +```java +public class Solution { + public int[] rearrangeArray(int[] nums) { + boolean increase = nums[0] < nums[1]; + for (int i = 1; i < nums.length - 1; i++) { + if ((increase && nums[i] < nums[i + 1]) || + (!increase && nums[i] > nums[i + 1])) { + int temp = nums[i]; + nums[i] = nums[i + 1]; + nums[i + 1] = temp; + } + increase = !increase; + } + return nums; + } +} +``` + +```cpp +class Solution { +public: + vector rearrangeArray(vector& nums) { + bool increase = nums[0] < nums[1]; + for (int i = 1; i < nums.size() - 1; i++) { + if ((increase && nums[i] < nums[i + 1]) || + (!increase && nums[i] > nums[i + 1])) { + swap(nums[i], nums[i + 1]); + } + increase = !increase; + } + return nums; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + rearrangeArray(nums) { + let increase = nums[0] < nums[1]; + for (let i = 1; i < nums.length - 1; i++) { + if ( + (increase && nums[i] < nums[i + 1]) || + (!increase && nums[i] > nums[i + 1]) + ) { + [nums[i], nums[i + 1]] = [nums[i + 1], nums[i]]; + } + increase = !increase; + } + return nums; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/as-far-from-land-as-possible.md b/articles/as-far-from-land-as-possible.md new file mode 100644 index 000000000..dd17d099c --- /dev/null +++ b/articles/as-far-from-land-as-possible.md @@ -0,0 +1,795 @@ +## 1. Brute Force (BFS) + +::tabs-start + +```python +class Solution: + def maxDistance(self, grid: list[list[int]]) -> int: + N = len(grid) + direct = [[0, 1], [0, -1], [1, 0], [-1, 0]] + + def bfs(row, col): + q = deque([(row, col)]) + visit = [[False] * N for _ in range(N)] + dist, visit[row][col] = 0, True + + while q: + dist += 1 + for _ in range(len(q)): + r, c = q.popleft() + for dx, dy in direct: + newR, newC = r + dx, c + dy + if min(newR, newC) < 0 or max(newR, newC) >= N or visit[newR][newC]: + continue + if grid[newR][newC] == 1: + return dist + visit[newR][newC] = True + q.append((newR, newC)) + return -1 + + res = -1 + for r in range(N): + for c in range(N): + if grid[r][c] == 0: + res = max(res, bfs(r, c)) + if res == -1: + return res + + return res +``` + +```java +public class Solution { + private static final int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + public int maxDistance(int[][] grid) { + int N = grid.length; + int res = -1; + + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 0) { + res = Math.max(res, bfs(grid, r, c, N)); + if (res == -1) return res; + } + } + } + return res; + } + + private int bfs(int[][] grid, int row, int col, int N) { + Queue q = new LinkedList<>(); + boolean[][] visit = new boolean[N][N]; + q.offer(new int[]{row, col}); + visit[row][col] = true; + int dist = 0; + + while (!q.isEmpty()) { + dist++; + for (int i = q.size(); i > 0; i--) { + int[] cell = q.poll(); + int r = cell[0], c = cell[1]; + + for (int[] d : direct) { + int newR = r + d[0], newC = c + d[1]; + if (newR < 0 || newC < 0 || newR >= N || newC >= N || visit[newR][newC]) + continue; + if (grid[newR][newC] == 1) + return dist; + + visit[newR][newC] = true; + q.offer(new int[]{newR, newC}); + } + } + } + return -1; + } +} +``` + +```cpp +class Solution { +public: + int maxDistance(vector>& grid) { + int N = grid.size(); + int res = -1; + + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 0) { + res = max(res, bfs(grid, r, c, N)); + if (res == -1) return res; + } + } + } + return res; + } + +private: + const int direct[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + int bfs(vector>& grid, int row, int col, int N) { + queue> q; + vector> visit(N, vector(N, false)); + q.push({row, col}); + visit[row][col] = true; + int dist = 0; + + while (!q.empty()) { + dist++; + for (int i = q.size(); i > 0; i--) { + auto [r, c] = q.front();q.pop(); + + for (auto& d : direct) { + int newR = r + d[0], newC = c + d[1]; + if (newR < 0 || newC < 0 || newR >= N || newC >= N || visit[newR][newC]) + continue; + if (grid[newR][newC] == 1) + return dist; + + visit[newR][newC] = true; + q.push({newR, newC}); + } + } + } + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + maxDistance(grid) { + const N = grid.length; + const direct = [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ]; + + const bfs = (row, col) => { + const q = new Queue([[row, col]]); + const visit = Array.from({ length: N }, () => Array(N).fill(false)); + visit[row][col] = true; + let dist = 0; + + while (!q.isEmpty()) { + dist++; + for (let i = q.size(); i > 0; i--) { + const [r, c] = q.pop(); + for (let d = 0; d < 4; d++) { + let newR = r + direct[d][0], + newC = c + direct[d][1]; + if ( + newR < 0 || + newC < 0 || + newR >= N || + newC >= N || + visit[newR][newC] + ) + continue; + if (grid[newR][newC] === 1) return dist; + + visit[newR][newC] = true; + q.push([newR, newC]); + } + } + } + return -1; + }; + + let res = -1; + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 0) { + res = Math.max(res, bfs(r, c)); + if (res === -1) return res; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 4)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 2. Multi Source BFS (Overwriting Input) + +::tabs-start + +```python +class Solution: + def maxDistance(self, grid: List[List[int]]) -> int: + N = len(grid) + q = deque() + + for r in range(N): + for c in range(N): + if grid[r][c]: + q.append([r, c]) + + res = -1 + direct = [[0, 1], [1, 0], [0, -1], [-1, 0]] + + while q: + r, c = q.popleft() + res = grid[r][c] + + for dr, dc in direct: + newR, newC = r + dr, c + dc + if min(newR, newC) >= 0 and max(newR, newC) < N and grid[newR][newC] == 0: + q.append([newR, newC]) + grid[newR][newC] = grid[r][c] + 1 + + return res - 1 if res > 1 else -1 +``` + +```java +public class Solution { + private static final int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + public int maxDistance(int[][] grid) { + int N = grid.length; + Queue q = new LinkedList<>(); + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + q.offer(new int[]{r, c}); + } + } + } + + int res = -1; + while (!q.isEmpty()) { + int[] cell = q.poll(); + int r = cell[0], c = cell[1]; + res = grid[r][c]; + for (int d = 0; d < 4; d++) { + int newR = r + direct[d][0], newC = c + direct[d][1]; + if (newR >= 0 && newC >= 0 && newR < N && newC < N && grid[newR][newC] == 0) { + q.offer(new int[]{newR, newC}); + grid[newR][newC] = grid[r][c] + 1; + } + } + } + return res > 1 ? res - 1 : -1; + } +} +``` + +```cpp +class Solution { + const int direct[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + +public: + int maxDistance(vector>& grid) { + int N = grid.size(); + queue> q; + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + q.push({r, c}); + } + } + } + + int res = -1; + while (!q.empty()) { + auto [r, c] = q.front();q.pop(); + res = grid[r][c]; + for (int d = 0; d < 4; d++) { + int newR = r + direct[d][0], newC = c + direct[d][1]; + if (newR >= 0 && newC >= 0 && newR < N && newC < N && grid[newR][newC] == 0) { + q.push({newR, newC}); + grid[newR][newC] = grid[r][c] + 1; + } + } + } + return res > 1 ? res - 1 : -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + maxDistance(grid) { + const N = grid.length; + const q = new Queue(); + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + q.push([r, c]); + } + } + } + + let res = -1; + const direct = [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ]; + while (!q.isEmpty()) { + const [r, c] = q.pop(); + res = grid[r][c]; + for (let d = 0; d < 4; d++) { + let newR = r + direct[d][0], + newC = c + direct[d][1]; + if ( + newR >= 0 && + newC >= 0 && + newR < N && + newC < N && + grid[newR][newC] === 0 + ) { + q.push([newR, newC]); + grid[newR][newC] = grid[r][c] + 1; + } + } + } + return res > 1 ? res - 1 : -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 3. Multi Source BFS + +::tabs-start + +```python +class Solution: + def maxDistance(self, grid: List[List[int]]) -> int: + N = len(grid) + direct = [0, 1, 0, -1, 0] + visit = [[False] * N for _ in range(N)] + q = deque() + + for r in range(N): + for c in range(N): + if grid[r][c] == 1: + visit[r][c] = True + q.append((r, c)) + + res = 0 + while q: + res += 1 + for _ in range(len(q)): + r, c = q.popleft() + for d in range(4): + newR, newC = r + direct[d], c + direct[d + 1] + if 0 <= newR < N and 0 <= newC < N and not visit[newR][newC]: + q.append((newR, newC)) + visit[newR][newC] = True + + return res - 1 if res > 1 else -1 +``` + +```java +public class Solution { + public int maxDistance(int[][] grid) { + int N = grid.length; + int[] direct = {0, 1, 0, -1, 0}; + boolean[][] visit = new boolean[N][N]; + Queue q = new LinkedList<>(); + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + visit[r][c] = true; + q.offer(new int[]{r, c}); + } + } + } + + int res = 0; + while (!q.isEmpty()) { + res++; + for (int i = q.size(); i > 0; i--) { + int[] cur = q.poll(); + int r = cur[0], c = cur[1]; + for (int d = 0; d < 4; d++) { + int newR = r + direct[d], newC = c + direct[d + 1]; + if (newR >= 0 && newC >= 0 && newR < N && newC < N && !visit[newR][newC]) { + q.offer(new int[]{newR, newC}); + visit[newR][newC] = true; + } + } + } + } + return res > 1 ? res - 1 : -1; + } +} +``` + +```cpp +class Solution { +public: + int maxDistance(vector>& grid) { + int N = grid.size(); + vector direct = {0, 1, 0, -1, 0}; + vector> visit(N, vector(N, false)); + queue> q; + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + visit[r][c] = true; + q.push({r, c}); + } + } + } + + int res = 0; + while (!q.empty()) { + res++; + for (int i = q.size(); i > 0; i--) { + auto [r, c] = q.front();q.pop(); + for (int d = 0; d < 4; d++) { + int newR = r + direct[d], newC = c + direct[d + 1]; + if (newR >= 0 && newC >= 0 && newR < N && newC < N && !visit[newR][newC]) { + q.push({newR, newC}); + visit[newR][newC] = true; + } + } + } + } + return res > 1 ? res - 1 : -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + maxDistance(grid) { + const N = grid.length; + const direct = [0, 1, 0, -1, 0]; + const visit = Array.from({ length: N }, () => Array(N).fill(false)); + const q = new Queue(); + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + visit[r][c] = true; + q.push([r, c]); + } + } + } + + let res = 0; + while (!q.isEmpty()) { + res++; + for (let i = q.size(); i > 0; i--) { + const [r, c] = q.pop(); + for (let d = 0; d < 4; d++) { + let newR = r + direct[d], + newC = c + direct[d + 1]; + if ( + newR >= 0 && + newC >= 0 && + newR < N && + newC < N && + !visit[newR][newC] + ) { + q.push([newR, newC]); + visit[newR][newC] = true; + } + } + } + } + return res > 1 ? res - 1 : -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 4. Dynamic Programming (Overwrting the Input) + +::tabs-start + +```python +class Solution: + def maxDistance(self, grid: List[List[int]]) -> int: + N, INF = len(grid), 10**6 + + for r in range(N): + for c in range(N): + if grid[r][c] == 1: + continue + grid[r][c] = INF + if r > 0: + grid[r][c] = min(grid[r][c], grid[r - 1][c] + 1) + if c > 0: + grid[r][c] = min(grid[r][c], grid[r][c - 1] + 1) + + res = 0 + for r in range(N - 1, -1, -1): + for c in range(N - 1, -1, -1): + if grid[r][c] == 1: + continue + if r < N - 1: + grid[r][c] = min(grid[r][c], grid[r + 1][c] + 1) + if c < N - 1: + grid[r][c] = min(grid[r][c], grid[r][c + 1] + 1) + res = max(res, grid[r][c]) + + return res - 1 if res < INF else -1 +``` + +```java +public class Solution { + public int maxDistance(int[][] grid) { + int N = grid.length, INF = 1000000; + + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) continue; + grid[r][c] = INF; + if (r > 0) grid[r][c] = Math.min(grid[r][c], grid[r - 1][c] + 1); + if (c > 0) grid[r][c] = Math.min(grid[r][c], grid[r][c - 1] + 1); + } + } + + int res = 0; + for (int r = N - 1; r >= 0; r--) { + for (int c = N - 1; c >= 0; c--) { + if (grid[r][c] == 1) continue; + if (r < N - 1) grid[r][c] = Math.min(grid[r][c], grid[r + 1][c] + 1); + if (c < N - 1) grid[r][c] = Math.min(grid[r][c], grid[r][c + 1] + 1); + res = Math.max(res, grid[r][c]); + } + } + + return res < INF ? res - 1 : -1; + } +} +``` + +```cpp +class Solution { +public: + int maxDistance(vector>& grid) { + int N = grid.size(), INF = 1000000; + + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) continue; + grid[r][c] = INF; + if (r > 0) grid[r][c] = min(grid[r][c], grid[r - 1][c] + 1); + if (c > 0) grid[r][c] = min(grid[r][c], grid[r][c - 1] + 1); + } + } + + int res = 0; + for (int r = N - 1; r >= 0; r--) { + for (int c = N - 1; c >= 0; c--) { + if (grid[r][c] == 1) continue; + if (r < N - 1) grid[r][c] = min(grid[r][c], grid[r + 1][c] + 1); + if (c < N - 1) grid[r][c] = min(grid[r][c], grid[r][c + 1] + 1); + res = max(res, grid[r][c]); + } + } + + return res < INF ? res - 1 : -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + maxDistance(grid) { + const N = grid.length, + INF = 1000000; + + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) continue; + grid[r][c] = INF; + if (r > 0) + grid[r][c] = Math.min(grid[r][c], grid[r - 1][c] + 1); + if (c > 0) + grid[r][c] = Math.min(grid[r][c], grid[r][c - 1] + 1); + } + } + + let res = 0; + for (let r = N - 1; r >= 0; r--) { + for (let c = N - 1; c >= 0; c--) { + if (grid[r][c] === 1) continue; + if (r < N - 1) + grid[r][c] = Math.min(grid[r][c], grid[r + 1][c] + 1); + if (c < N - 1) + grid[r][c] = Math.min(grid[r][c], grid[r][c + 1] + 1); + res = Math.max(res, grid[r][c]); + } + } + + return res < INF ? res - 1 : -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 5. Dynamic Programming + +::tabs-start + +```python +class Solution: + def maxDistance(self, grid: List[List[int]]) -> int: + N = len(grid) + res, INF = -1, 10**6 + dp = [[INF] * (N + 2) for _ in range(N + 2)] + + for r in range(1, N + 1): + for c in range(1, N + 1): + if grid[r - 1][c - 1] == 1: + dp[r][c] = 0 + else: + dp[r][c] = min(dp[r - 1][c], dp[r][c - 1]) + 1 + + for r in range(N, 0, -1): + for c in range(N, 0, -1): + if grid[r - 1][c - 1] == 0: + dp[r][c] = min(dp[r][c], min(dp[r + 1][c], dp[r][c + 1]) + 1) + res = max(res, dp[r][c]) + + return res if res < INF else -1 +``` + +```java +public class Solution { + public int maxDistance(int[][] grid) { + int N = grid.length; + int INF = 1000000; + int[][] dp = new int[N + 2][N + 2]; + for (int[] row : dp) { + Arrays.fill(row, INF); + } + + for (int r = 1; r <= N; r++) { + for (int c = 1; c <= N; c++) { + if (grid[r - 1][c - 1] == 1) { + dp[r][c] = 0; + } else { + dp[r][c] = Math.min(dp[r - 1][c], dp[r][c - 1]) + 1; + } + } + } + + int res = -1; + for (int r = N; r > 0; r--) { + for (int c = N; c > 0; c--) { + if (grid[r - 1][c - 1] == 0) { + dp[r][c] = Math.min(dp[r][c], Math.min(dp[r + 1][c], dp[r][c + 1]) + 1); + res = Math.max(res, dp[r][c]); + } + } + } + return res < INF ? res : -1; + } +} +``` + +```cpp +class Solution { +public: + int maxDistance(vector>& grid) { + int N = grid.size(); + int INF = 1000000, res = -1; + vector> dp(N + 2, vector(N + 2, INF)); + + for (int r = 1; r <= N; r++) { + for (int c = 1; c <= N; c++) { + if (grid[r - 1][c - 1] == 1) { + dp[r][c] = 0; + } else { + dp[r][c] = min(dp[r - 1][c], dp[r][c - 1]) + 1; + } + } + } + + for (int r = N; r > 0; r--) { + for (int c = N; c > 0; c--) { + if (grid[r - 1][c - 1] == 0) { + dp[r][c] = min(dp[r][c], min(dp[r + 1][c], dp[r][c + 1]) + 1); + res = max(res, dp[r][c]); + } + } + } + return res < INF ? res : -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + maxDistance(grid) { + const N = grid.length; + const INF = 1000000; + let res = -1; + let dp = Array.from({ length: N + 2 }, () => Array(N + 2).fill(INF)); + + for (let r = 1; r <= N; r++) { + for (let c = 1; c <= N; c++) { + if (grid[r - 1][c - 1] === 1) { + dp[r][c] = 0; + } else { + dp[r][c] = Math.min(dp[r - 1][c], dp[r][c - 1]) + 1; + } + } + } + + for (let r = N; r > 0; r--) { + for (let c = N; c > 0; c--) { + if (grid[r - 1][c - 1] === 0) { + dp[r][c] = Math.min( + dp[r][c], + Math.min(dp[r + 1][c], dp[r][c + 1]) + 1, + ); + res = Math.max(res, dp[r][c]); + } + } + } + return res < INF ? res : -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ diff --git a/articles/assign-cookies.md b/articles/assign-cookies.md index b591a8ef9..8c471f4f4 100644 --- a/articles/assign-cookies.md +++ b/articles/assign-cookies.md @@ -13,14 +13,14 @@ class Solution: for j in range(len(s)): if s[j] < i: continue - + if minIdx == -1 or s[minIdx] > s[j]: minIdx = j - + if minIdx != -1: s[minIdx] = -1 res += 1 - + return res ``` @@ -115,8 +115,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m + m \log m)$ -* Space complexity: $O(1)$ or $O(m)$ depending on the sorting algorithm. +- Time complexity: $O(n * m + m \log m)$ +- Space complexity: $O(1)$ or $O(m)$ depending on the sorting algorithm. > Where $n$ is the size of the array $g$ and $m$ is the size of the array $s$. @@ -131,7 +131,7 @@ class Solution: def findContentChildren(self, g: List[int], s: List[int]) -> int: g.sort() s.sort() - + i = j = 0 while i < len(g): while j < len(s) and g[i] > s[j]: @@ -195,7 +195,8 @@ class Solution { g.sort((a, b) => a - b); s.sort((a, b) => a - b); - let i = 0, j = 0; + let i = 0, + j = 0; while (i < g.length) { while (j < s.length && g[i] > s[j]) { j++; @@ -213,8 +214,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n + m \log m)$ -* Space complexity: $O(1)$ or $O(n + m)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n + m \log m)$ +- Space complexity: $O(1)$ or $O(n + m)$ depending on the sorting algorithm. > Where $n$ is the size of the array $g$ and $m$ is the size of the array $s$. @@ -229,13 +230,13 @@ class Solution: def findContentChildren(self, g: List[int], s: List[int]) -> int: g.sort() s.sort() - + i = j = 0 while i < len(g) and j < len(s): if g[i] <= s[j]: i += 1 j += 1 - + return i ``` @@ -294,7 +295,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n + m \log m)$ -* Space complexity: $O(1)$ or $O(n + m)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n + m \log m)$ +- Space complexity: $O(1)$ or $O(n + m)$ depending on the sorting algorithm. -> Where $n$ is the size of the array $g$ and $m$ is the size of the array $s$. \ No newline at end of file +> Where $n$ is the size of the array $g$ and $m$ is the size of the array $s$. diff --git a/articles/asteroid-collision.md b/articles/asteroid-collision.md index e9634e9e8..d8926e704 100644 --- a/articles/asteroid-collision.md +++ b/articles/asteroid-collision.md @@ -101,12 +101,41 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] AsteroidCollision(int[] asteroids) { + Stack stack = new Stack(); + + foreach (int a in asteroids) { + int current = a; + while (stack.Count > 0 && current < 0 && stack.Peek() > 0) { + int diff = current + stack.Peek(); + if (diff < 0) { + stack.Pop(); + } else if (diff > 0) { + current = 0; + } else { + current = 0; + stack.Pop(); + } + } + if (current != 0) { + stack.Push(current); + } + } + + int[] result = stack.Reverse().ToArray(); + return result; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -231,9 +260,43 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] AsteroidCollision(int[] asteroids) { + int n = asteroids.Length; + int j = -1; + + foreach (int a in asteroids) { + int current = a; + + while (j >= 0 && asteroids[j] > 0 && current < 0) { + if (asteroids[j] > Math.Abs(current)) { + current = 0; + break; + } else if (asteroids[j] == Math.Abs(current)) { + j--; + current = 0; + break; + } else { + j--; + } + } + + if (current != 0) { + asteroids[++j] = current; + } + } + + int[] result = new int[j + 1]; + Array.Copy(asteroids, 0, result, 0, j + 1); + return result; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for the output array. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for the output array. diff --git a/articles/average-waiting-time.md b/articles/average-waiting-time.md new file mode 100644 index 000000000..3aac9a698 --- /dev/null +++ b/articles/average-waiting-time.md @@ -0,0 +1,171 @@ +## 1. Simulation - I + +::tabs-start + +```python +class Solution: + def averageWaitingTime(self, customers: List[List[int]]) -> float: + t = 0 + total = 0 + + for arrival, order in customers: + if t > arrival: + total += t - arrival + else: + t = arrival + total += order + t += order + + return total / len(customers) +``` + +```java +public class Solution { + public double averageWaitingTime(int[][] customers) { + long t = 0, total = 0; + + for (int[] c : customers) { + int arrival = c[0], order = c[1]; + if (t > arrival) { + total += t - arrival; + } else { + t = arrival; + } + total += order; + t += order; + } + + return (double) total / customers.length; + } +} +``` + +```cpp +class Solution { +public: + double averageWaitingTime(vector>& customers) { + long long t = 0, total = 0; + + for (auto& c : customers) { + int arrival = c[0], order = c[1]; + if (t > arrival) { + total += t - arrival; + } else { + t = arrival; + } + total += order; + t += order; + } + + return (double) total / customers.size(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} customers + * @return {number} + */ + averageWaitingTime(customers) { + let t = 0, + total = 0; + + for (let [arrival, order] of customers) { + if (t > arrival) { + total += t - arrival; + } else { + t = arrival; + } + total += order; + t += order; + } + + return total / customers.length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 2. Simulation - II + +::tabs-start + +```python +class Solution: + def averageWaitingTime(self, customers: List[List[int]]) -> float: + t = total = 0 + for arrival, order in customers: + t = max(t, arrival) + order + total += t - arrival + return total / len(customers) +``` + +```java +public class Solution { + public double averageWaitingTime(int[][] customers) { + long t = 0, total = 0; + + for (int[] c : customers) { + int arrival = c[0], order = c[1]; + t = Math.max(t, arrival) + order; + total += t - arrival; + } + + return (double) total / customers.length; + } +} +``` + +```cpp +class Solution { +public: + double averageWaitingTime(vector>& customers) { + long long t = 0, total = 0; + + for (auto& c : customers) { + int arrival = c[0], order = c[1]; + t = max(t, (long long)arrival) + order; + total += t - arrival; + } + + return (double) total / customers.size(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} customers + * @return {number} + */ + averageWaitingTime(customers) { + let t = 0, + total = 0; + + for (let [arrival, order] of customers) { + t = Math.max(t, arrival) + order; + total += t - arrival; + } + + return total / customers.length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/backspace-string-compare.md b/articles/backspace-string-compare.md index 6064e5bd6..b95f0c691 100644 --- a/articles/backspace-string-compare.md +++ b/articles/backspace-string-compare.md @@ -94,8 +94,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ > Where $n$ is the length of the string $s$ and $m$ is the length of the string $t$. @@ -180,7 +180,7 @@ class Solution { */ backspaceCompare(s, t) { const convert = (s) => { - const res = []; + const res = []; let backspace = 0; for (let i = s.length - 1; i >= 0; i--) { if (s[i] === '#') { @@ -202,8 +202,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ > Where $n$ is the length of the string $s$ and $m$ is the length of the string $t$. @@ -353,7 +353,8 @@ class Solution { return index; }; - let indexS = s.length - 1, indexT = t.length - 1; + let indexS = s.length - 1, + indexT = t.length - 1; while (indexS >= 0 || indexT >= 0) { indexS = nextValidChar(s, indexS); @@ -377,8 +378,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(1)$ > Where $n$ is the length of the string $s$ and $m$ is the length of the string $t$. @@ -393,7 +394,7 @@ class Solution: def backspaceCompare(self, s: str, t: str) -> bool: index_s, index_t = len(s) - 1, len(t) - 1 backspace_s = backspace_t = 0 - + while True: while index_s >= 0 and (backspace_s or s[index_s] == '#'): backspace_s += 1 if s[index_s] == '#' else -1 @@ -419,7 +420,7 @@ public class Solution { backspaceS += s.charAt(indexS) == '#' ? 1 : -1; indexS--; } - + while (indexT >= 0 && (backspaceT > 0 || t.charAt(indexT) == '#')) { backspaceT += t.charAt(indexT) == '#' ? 1 : -1; indexT--; @@ -443,7 +444,7 @@ public: int backspaceS = 0, backspaceT = 0; while (true) { - + while (indexS >= 0 && (backspaceS > 0 || s[indexS] == '#')) { backspaceS += (s[indexS] == '#') ? 1 : -1; indexS--; @@ -472,8 +473,10 @@ class Solution { * @return {boolean} */ backspaceCompare(s, t) { - let indexS = s.length - 1, indexT = t.length - 1; - let backspaceS = 0, backspaceT = 0; + let indexS = s.length - 1, + indexT = t.length - 1; + let backspaceS = 0, + backspaceT = 0; while (true) { while (indexS >= 0 && (backspaceS > 0 || s[indexS] === '#')) { @@ -486,7 +489,13 @@ class Solution { indexT--; } - if (!(indexS >= 0 && indexT >= 0 && s.charAt(indexS) === t.charAt(indexT))) { + if ( + !( + indexS >= 0 && + indexT >= 0 && + s.charAt(indexS) === t.charAt(indexT) + ) + ) { return indexS === -1 && indexT === -1; } indexS--; @@ -500,7 +509,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(1)$ -> Where $n$ is the length of the string $s$ and $m$ is the length of the string $t$. \ No newline at end of file +> Where $n$ is the length of the string $s$ and $m$ is the length of the string $t$. diff --git a/articles/bag-of-tokens.md b/articles/bag-of-tokens.md new file mode 100644 index 000000000..a0faabc0f --- /dev/null +++ b/articles/bag-of-tokens.md @@ -0,0 +1,112 @@ +## 1. Greedy + Two Pointers + +::tabs-start + +```python +class Solution: + def bagOfTokensScore(self, tokens: List[int], power: int) -> int: + res = score = 0 + tokens.sort() + l, r = 0, len(tokens) - 1 + while l <= r: + if power >= tokens[l]: + power -= tokens[l] + l += 1 + score += 1 + res = max(res, score) + elif score > 0: + power += tokens[r] + r -= 1 + score -= 1 + else: + break + return res +``` + +```java +public class Solution { + public int bagOfTokensScore(int[] tokens, int power) { + Arrays.sort(tokens); + int res = 0, score = 0, l = 0, r = tokens.length - 1; + + while (l <= r) { + if (power >= tokens[l]) { + power -= tokens[l++]; + score++; + res = Math.max(res, score); + } else if (score > 0) { + power += tokens[r--]; + score--; + } else { + break; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int bagOfTokensScore(vector& tokens, int power) { + sort(tokens.begin(), tokens.end()); + int res = 0, score = 0, l = 0, r = tokens.size() - 1; + + while (l <= r) { + if (power >= tokens[l]) { + power -= tokens[l++]; + score++; + res = max(res, score); + } else if (score > 0) { + power += tokens[r--]; + score--; + } else { + break; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} tokens + * @param {number} power + * @return {number} + */ + bagOfTokensScore(tokens, power) { + tokens.sort((a, b) => a - b); + let res = 0, + score = 0, + l = 0, + r = tokens.length - 1; + + while (l <= r) { + if (power >= tokens[l]) { + power -= tokens[l++]; + score++; + res = Math.max(res, score); + } else if (score > 0) { + power += tokens[r--]; + score--; + } else { + break; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. diff --git a/articles/balanced-binary-tree.md b/articles/balanced-binary-tree.md index c9c407ed0..a2e4a230c 100644 --- a/articles/balanced-binary-tree.md +++ b/articles/balanced-binary-tree.md @@ -14,7 +14,7 @@ class Solution: def isBalanced(self, root: Optional[TreeNode]) -> bool: if not root: return True - + left = self.height(root.left) right = self.height(root.right) if abs(left - right) > 1: @@ -83,10 +83,10 @@ public: bool isBalanced(TreeNode* root) { if (!root) return true; - int left = height(root->left); + int left = height(root->left); int right = height(root->right); if (abs(left - right) > 1) return false; - return isBalanced(root->left) && isBalanced(root->right); + return isBalanced(root->left) && isBalanced(root->right); } int height(TreeNode* root) { @@ -134,9 +134,7 @@ class Solution { return 0; } - return ( - 1 + Math.max(this.height(root.left), this.height(root.right)) - ); + return 1 + Math.max(this.height(root.left), this.height(root.right)); } } ``` @@ -189,7 +187,7 @@ func isBalanced(root *TreeNode) bool { if root == nil { return true } - + left := height(root.Left) right := height(root.Right) if abs(left-right) > 1 { @@ -236,7 +234,7 @@ class Solution { if (root == null) { return true } - + val left = height(root.left) val right = height(root.right) if (Math.abs(left - right) > 1) { @@ -244,7 +242,7 @@ class Solution { } return isBalanced(root.left) && isBalanced(root.right) } - + private fun height(root: TreeNode?): Int { if (root == null) { return 0 @@ -254,12 +252,49 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isBalanced(_ root: TreeNode?) -> Bool { + guard let root = root else { return true } + + let left = height(root.left) + let right = height(root.right) + + if abs(left - right) > 1 { + return false + } + + return isBalanced(root.left) && isBalanced(root.right) + } + + private func height(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + return 1 + max(height(root.left), height(root.right)) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -306,7 +341,7 @@ class Solution: */ class Solution { - + public boolean isBalanced(TreeNode root) { return dfs(root)[0] == 1; } @@ -319,7 +354,7 @@ class Solution { int[] left = dfs(root.left); int[] right = dfs(root.right); - boolean balanced = (left[0] == 1 && right[0] == 1) && + boolean balanced = (left[0] == 1 && right[0] == 1) && (Math.abs(left[1] - right[1]) <= 1); int height = 1 + Math.max(left[1], right[1]); @@ -356,7 +391,7 @@ private: vector left = dfs(root->left); vector right = dfs(root->right); - bool balanced = (left[0] == 1 && right[0] == 1) && + bool balanced = (left[0] == 1 && right[0] == 1) && (abs(left[1] - right[1]) <= 1); int height = 1 + max(left[1], right[1]); @@ -425,7 +460,7 @@ class Solution { */ public class Solution { - + public bool IsBalanced(TreeNode root) { return Dfs(root)[0] == 1; } @@ -469,10 +504,10 @@ func dfs(root *TreeNode) Result { if root == nil { return Result{true, 0} } - + left := dfs(root.Left) right := dfs(root.Right) - + balanced := left.balanced && right.balanced && abs(left.height - right.height) <= 1 return Result{balanced, 1 + max(left.height, right.height)} } @@ -507,12 +542,12 @@ class Solution { fun isBalanced(root: TreeNode?): Boolean { return dfs(root).first } - + private fun dfs(root: TreeNode?): Pair { if (root == null) { return Pair(true, 0) } - + val left = dfs(root.left) val right = dfs(root.right) val balanced = left.first && right.first && Math.abs(left.second - right.second) <= 1 @@ -521,20 +556,53 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isBalanced(_ root: TreeNode?) -> Bool { + return dfs(root).0 + } + + private func dfs(_ root: TreeNode?) -> (Bool, Int) { + guard let root = root else { return (true, 0) } + + let left = dfs(root.left) + let right = dfs(root.right) + + let balanced = left.0 && right.0 && abs(left.1 - right.1) <= 1 + return (balanced, 1 + max(left.1, right.1)) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(h)$ - * Best Case ([balanced tree](https://www.geeksforgeeks.org/balanced-binary-tree/)): $O(log(n))$ - * Worst Case ([degenerate tree](https://www.geeksforgeeks.org/introduction-to-degenerate-binary-tree/)): $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(h)$ + - Best Case ([balanced tree](https://www.geeksforgeeks.org/balanced-binary-tree/)): $O(log(n))$ + - Worst Case ([degenerate tree](https://www.geeksforgeeks.org/introduction-to-degenerate-binary-tree/)): $O(n)$ > Where $n$ is the number of nodes in the tree and $h$ is the height of the tree. --- -## 3. Depth First Search (Stack) +## 3. Iterative DFS ::tabs-start @@ -598,7 +666,7 @@ public class Solution { Stack stack = new Stack<>(); TreeNode node = root, last = null; Map depths = new HashMap<>(); - + while (!stack.isEmpty() || node != null) { if (node != null) { stack.push(node); @@ -687,7 +755,8 @@ class Solution { */ isBalanced(root) { let stack = []; - let node = root, last = null; + let node = root, + last = null; let depths = new Map(); while (stack.length > 0 || node !== null) { @@ -743,10 +812,10 @@ public class Solution { node = stack.Peek(); if (node.right == null || last == node.right) { stack.Pop(); - - int left = (node.left != null && depths.ContainsKey(node.left)) + + int left = (node.left != null && depths.ContainsKey(node.left)) ? depths[node.left] : 0; - int right = (node.right != null && depths.ContainsKey(node.right)) + int right = (node.right != null && depths.ContainsKey(node.right)) ? depths[node.right] : 0; if (Math.Abs(left - right) > 1) return false; @@ -866,9 +935,61 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isBalanced(_ root: TreeNode?) -> Bool { + var stack = [TreeNode]() + var node = root + var last: TreeNode? = nil + var depths = [ObjectIdentifier: Int]() + + while !stack.isEmpty || node != nil { + if let current = node { + stack.append(current) + node = current.left + } else { + guard let current = stack.last else { break } + if current.right == nil || last === current.right { + stack.removeLast() + + let leftDepth = current.left != nil ? depths[ObjectIdentifier(current.left!)] ?? 0 : 0 + let rightDepth = current.right != nil ? depths[ObjectIdentifier(current.right!)] ?? 0 : 0 + if abs(leftDepth - rightDepth) > 1 { + return false + } + + depths[ObjectIdentifier(current)] = 1 + max(leftDepth, rightDepth) + last = current + node = nil + } else { + node = current.right + } + } + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/baseball-game.md b/articles/baseball-game.md index 2d04f4311..f62506f65 100644 --- a/articles/baseball-game.md +++ b/articles/baseball-game.md @@ -1,4 +1,4 @@ -## 1. Stack +## 1. Stack - I ::tabs-start @@ -78,14 +78,14 @@ class Solution { calPoints(operations) { const stack = []; for (const op of operations) { - if (op === "+") { + if (op === '+') { const top = stack.pop(); const newTop = top + stack[stack.length - 1]; stack.push(top); stack.push(newTop); - } else if (op === "D") { + } else if (op === 'D') { stack.push(2 * stack[stack.length - 1]); - } else if (op === "C") { + } else if (op === 'C') { stack.pop(); } else { stack.push(parseInt(op)); @@ -96,12 +96,42 @@ class Solution { } ``` +```csharp +public class Solution { + public int CalPoints(string[] operations) { + Stack stack = new Stack(); + + foreach (var op in operations) { + if (op == "+") { + int top = stack.Pop(); + int newTop = top + stack.Peek(); + stack.Push(top); + stack.Push(newTop); + } else if (op == "D") { + stack.Push(2 * stack.Peek()); + } else if (op == "C") { + stack.Pop(); + } else { + stack.Push(int.Parse(op)); + } + } + + int total = 0; + foreach (var val in stack) { + total += val; + } + + return total; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -194,16 +224,16 @@ class Solution { const stack = []; let res = 0; for (const op of operations) { - if (op === "+") { + if (op === '+') { const top = stack.pop(); const newTop = top + stack[stack.length - 1]; stack.push(top); stack.push(newTop); res += newTop; - } else if (op === "D") { + } else if (op === 'D') { stack.push(2 * stack[stack.length - 1]); res += stack[stack.length - 1]; - } else if (op === "C") { + } else if (op === 'C') { res -= stack.pop(); } else { stack.push(parseInt(op)); @@ -215,9 +245,41 @@ class Solution { } ``` +```csharp +public class Solution { + public int CalPoints(string[] operations) { + Stack stack = new Stack(); + int res = 0; + + foreach (var op in operations) { + if (op == "+") { + int top = stack.Pop(); + int second = stack.Peek(); + int sum = top + second; + stack.Push(top); + stack.Push(sum); + res += sum; + } else if (op == "D") { + int doubleVal = 2 * stack.Peek(); + stack.Push(doubleVal); + res += doubleVal; + } else if (op == "C") { + res -= stack.Pop(); + } else { + int num = int.Parse(op); + stack.Push(num); + res += num; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/basic-calculator-ii.md b/articles/basic-calculator-ii.md new file mode 100644 index 000000000..a38710b58 --- /dev/null +++ b/articles/basic-calculator-ii.md @@ -0,0 +1,404 @@ +## 1. Stack + +::tabs-start + +```python +class Solution: + def calculate(self, s: str) -> int: + stack = [] + num = 0 + op = '+' + s = s.replace(' ', '') + + for i, ch in enumerate(s): + if ch.isdigit(): + num = num * 10 + int(ch) + if (not ch.isdigit()) or i == len(s) - 1: + if op == '+': + stack.append(num) + elif op == '-': + stack.append(-num) + elif op == '*': + stack.append(stack.pop() * num) + else: + prev = stack.pop() + stack.append(int(prev / num)) + op = ch + num = 0 + + return sum(stack) +``` + +```java +public class Solution { + public int calculate(String s) { + s = s.replace(" ", ""); + Stack stack = new Stack<>(); + int num = 0; + char op = '+'; + + for (int i = 0; i < s.length(); i++) { + char ch = s.charAt(i); + if (Character.isDigit(ch)) { + num = num * 10 + (ch - '0'); + } + if (!Character.isDigit(ch) || i == s.length() - 1) { + if (op == '+') { + stack.push(num); + } else if (op == '-') { + stack.push(-num); + } else if (op == '*') { + stack.push(stack.pop() * num); + } else { // op == '/' + int prev = stack.pop(); + stack.push(prev / num); + } + op = ch; + num = 0; + } + } + + int res = 0; + while (!stack.isEmpty()) { + res += stack.pop(); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int calculate(string s) { + s.erase(remove(s.begin(), s.end(), ' '), s.end()); + vector stack; + int num = 0; + char op = '+'; + for (int i = 0; i < s.size(); i++) { + char ch = s[i]; + if (isdigit(ch)) { + num = num * 10 + (ch - '0'); + } + if (!isdigit(ch) || i == s.size() - 1) { + if (op == '+') { + stack.push_back(num); + } else if (op == '-') { + stack.push_back(-num); + } else if (op == '*') { + int prev = stack.back(); stack.pop_back(); + stack.push_back(prev * num); + } else { + int prev = stack.back(); stack.pop_back(); + stack.push_back(prev / num); + } + op = ch; + num = 0; + } + } + int res = 0; + for (int x : stack) res += x; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + calculate(s) { + s = s.replace(/\s+/g, ''); + const stack = []; + let num = 0; + let op = '+'; + for (let i = 0; i < s.length; i++) { + const ch = s[i]; + if (/\d/.test(ch)) { + num = num * 10 + (ch - '0'); + } + if (!/\d/.test(ch) || i === s.length - 1) { + if (op === '+') { + stack.push(num); + } else if (op === '-') { + stack.push(-num); + } else if (op === '*') { + stack.push(stack.pop() * num); + } else { + const prev = stack.pop(); + stack.push(Math.trunc(prev / num)); + } + op = ch; + num = 0; + } + } + return stack.reduce((a, b) => a + b, 0); + } +} +``` + +```csharp +public class Solution { + public int Calculate(string s) { + s = s.Replace(" ", ""); + var stack = new Stack(); + int num = 0; + char op = '+'; + + for (int i = 0; i < s.Length; i++) { + char ch = s[i]; + if (char.IsDigit(ch)) { + num = num * 10 + (ch - '0'); + } + if (!char.IsDigit(ch) || i == s.Length - 1) { + if (op == '+') { + stack.Push(num); + } else if (op == '-') { + stack.Push(-num); + } else if (op == '*') { + int prev = stack.Pop(); + stack.Push(prev * num); + } else { + int prev = stack.Pop(); + stack.Push(prev / num); + } + op = ch; + num = 0; + } + } + + int res = 0; + while (stack.Count > 0) { + res += stack.Pop(); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Without Stack + +::tabs-start + +```python +class Solution: + def calculate(self, s: str) -> int: + total = prev = num = 0 + op = '+' + n = len(s) + i = 0 + + while i <= n: + ch = s[i] if i < n else '+' + if ch == ' ': + i += 1 + continue + + if '0' <= ch <= '9': + num = num * 10 + (ord(ch) - ord('0')) + else: + if op == '+': + total += prev + prev = num + elif op == '-': + total += prev + prev = -num + elif op == '*': + prev = prev * num + else: + if prev < 0: + prev = -(-prev // num) + else: + prev = prev // num + + op = ch + num = 0 + + i += 1 + + total += prev + return total +``` + +```java +public class Solution { + public int calculate(String s) { + int total = 0, prev = 0, num = 0; + char op = '+'; + int n = s.length(), i = 0; + while (i <= n) { + char ch = i < n ? s.charAt(i) : '+'; + if (ch == ' ') { + i++; + continue; + } + if (Character.isDigit(ch)) { + num = num * 10 + (ch - '0'); + } else { + switch (op) { + case '+': + total += prev; + prev = num; + break; + case '-': + total += prev; + prev = -num; + break; + case '*': + prev = prev * num; + break; + default: + prev = prev / num; + } + op = ch; + num = 0; + } + i++; + } + total += prev; + return total; + } +} +``` + +```cpp +class Solution { +public: + int calculate(string s) { + int total = 0, prev = 0, num = 0; + char op = '+'; + int n = s.size(), i = 0; + while (i <= n) { + char ch = i < n ? s[i] : '+'; + if (ch == ' ') { + i++; + continue; + } + if (isdigit(ch)) { + num = num * 10 + (ch - '0'); + } else { + if (op == '+') { + total += prev; + prev = num; + } else if (op == '-') { + total += prev; + prev = -num; + } else if (op == '*') { + prev = prev * num; + } else { + prev = prev / num; + } + op = ch; + num = 0; + } + i++; + } + total += prev; + return total; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + calculate(s) { + let total = 0, + prev = 0, + num = 0; + let op = '+'; + const n = s.length; + let i = 0; + while (i <= n) { + const ch = i < n ? s[i] : '+'; + if (ch === ' ') { + i++; + continue; + } + if (ch >= '0' && ch <= '9') { + num = num * 10 + (ch.charCodeAt(0) - 48); + } else { + if (op === '+') { + total += prev; + prev = num; + } else if (op === '-') { + total += prev; + prev = -num; + } else if (op === '*') { + prev = prev * num; + } else { + prev = (prev / num) | 0; + } + op = ch; + num = 0; + } + i++; + } + total += prev; + return total; + } +} +``` + +```csharp +public class Solution { + public int Calculate(string s) { + int total = 0, prev = 0, num = 0; + char op = '+'; + int n = s.Length, i = 0; + while (i <= n) { + char ch = i < n ? s[i] : '+'; + if (ch == ' ') { + i++; + continue; + } + if (char.IsDigit(ch)) { + num = num * 10 + (ch - '0'); + } else { + switch (op) { + case '+': + total += prev; + prev = num; + break; + case '-': + total += prev; + prev = -num; + break; + case '*': + prev = prev * num; + break; + default: + prev = prev / num; + break; + } + op = ch; + num = 0; + } + i++; + } + total += prev; + return total; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/best-team-with-no-conflicts.md b/articles/best-team-with-no-conflicts.md index a4e77a374..778922672 100644 --- a/articles/best-team-with-no-conflicts.md +++ b/articles/best-team-with-no-conflicts.md @@ -159,8 +159,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -171,7 +171,7 @@ class Solution { ```python class Solution: def bestTeamScore(self, scores: List[int], ages: List[int]) -> int: - pairs = [[scores[i], ages[i]] for i in range(len(scores))] + pairs = [[scores[i], ages[i]] for i in range(len(scores))] pairs.sort() dp = [pairs[i][0] for i in range(len(pairs))] @@ -290,8 +290,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -542,7 +542,7 @@ public: class SegmentTree { /** * @constructor - * @param {number} N + * @param {number} N */ constructor(N) { this.n = N; @@ -569,7 +569,10 @@ class SegmentTree { this.tree[pos] = Math.max(this.tree[pos], val); pos >>= 1; while (pos >= 1) { - this.tree[pos] = Math.max(this.tree[pos << 1], this.tree[pos << 1 | 1]); + this.tree[pos] = Math.max( + this.tree[pos << 1], + this.tree[(pos << 1) | 1], + ); pos >>= 1; } } @@ -619,7 +622,9 @@ class Solution { dp[i] = pairs[i][0]; } - const uniqueAges = [...new Set(pairs.map((p) => p[1]))].sort((a, b) => a - b); + const uniqueAges = [...new Set(pairs.map((p) => p[1]))].sort( + (a, b) => a - b, + ); const ageId = new Map(); uniqueAges.forEach((val, idx) => ageId.set(val, idx)); @@ -645,5 +650,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/best-time-to-buy-and-sell-stock-ii.md b/articles/best-time-to-buy-and-sell-stock-ii.md index e6abb861a..cc1d82833 100644 --- a/articles/best-time-to-buy-and-sell-stock-ii.md +++ b/articles/best-time-to-buy-and-sell-stock-ii.md @@ -85,12 +85,36 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxProfit(int[] prices) { + return Rec(prices, 0, false); + } + + private int Rec(int[] prices, int i, bool bought) { + if (i == prices.Length) { + return 0; + } + + int res = Rec(prices, i + 1, bought); + + if (bought) { + res = Math.Max(res, prices[i] + Rec(prices, i + 1, false)); + } else { + res = Math.Max(res, -prices[i] + Rec(prices, i + 1, true)); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -211,12 +235,49 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxProfit(int[] prices) { + int n = prices.Length; + int[,] dp = new int[n, 2]; + + for (int i = 0; i < n; i++) { + dp[i, 0] = -1; + dp[i, 1] = -1; + } + + return Rec(prices, 0, 0, dp); + } + + private int Rec(int[] prices, int i, int bought, int[,] dp) { + if (i == prices.Length) { + return 0; + } + + if (dp[i, bought] != -1) { + return dp[i, bought]; + } + + int res = Rec(prices, i + 1, bought, dp); + + if (bought == 1) { + res = Math.Max(res, prices[i] + Rec(prices, i + 1, 0, dp)); + } else { + res = Math.Max(res, -prices[i] + Rec(prices, i + 1, 1, dp)); + } + + dp[i, bought] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -229,11 +290,11 @@ class Solution: def maxProfit(self, prices: List[int]) -> int: n = len(prices) dp = [[0] * 2 for _ in range(n + 1)] - + for i in range(n - 1, -1, -1): dp[i][0] = max(dp[i + 1][0], -prices[i] + dp[i + 1][1]) dp[i][1] = max(dp[i + 1][1], prices[i] + dp[i + 1][0]) - + return dp[0][0] ``` @@ -242,12 +303,12 @@ public class Solution { public int maxProfit(int[] prices) { int n = prices.length; int[][] dp = new int[n + 1][2]; - + for (int i = n - 1; i >= 0; i--) { dp[i][0] = Math.max(dp[i + 1][0], -prices[i] + dp[i + 1][1]); dp[i][1] = Math.max(dp[i + 1][1], prices[i] + dp[i + 1][0]); } - + return dp[0][0]; } } @@ -259,12 +320,12 @@ public: int maxProfit(vector& prices) { int n = prices.size(); vector> dp(n + 1, vector(2, 0)); - + for (int i = n - 1; i >= 0; i--) { dp[i][0] = max(dp[i + 1][0], -prices[i] + dp[i + 1][1]); dp[i][1] = max(dp[i + 1][1], prices[i] + dp[i + 1][0]); } - + return dp[0][0]; } }; @@ -279,23 +340,39 @@ class Solution { maxProfit(prices) { const n = prices.length; const dp = Array.from({ length: n + 1 }, () => Array(2).fill(0)); - + for (let i = n - 1; i >= 0; i--) { dp[i][0] = Math.max(dp[i + 1][0], -prices[i] + dp[i + 1][1]); dp[i][1] = Math.max(dp[i + 1][1], prices[i] + dp[i + 1][0]); } - + return dp[0][0]; } } ``` +```csharp +public class Solution { + public int MaxProfit(int[] prices) { + int n = prices.Length; + int[,] dp = new int[n + 1, 2]; + + for (int i = n - 1; i >= 0; i--) { + dp[i, 0] = Math.Max(dp[i + 1, 0], -prices[i] + dp[i + 1, 1]); + dp[i, 1] = Math.Max(dp[i + 1, 1], prices[i] + dp[i + 1, 0]); + } + + return dp[0, 0]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -309,13 +386,13 @@ class Solution: n = len(prices) next_buy = next_sell = 0 cur_buy = cur_sell = 0 - + for i in range(n - 1, -1, -1): cur_buy = max(next_buy, -prices[i] + next_sell) cur_sell = max(next_sell, prices[i] + next_buy) next_buy = cur_buy next_sell = cur_sell - + return cur_buy ``` @@ -363,8 +440,10 @@ class Solution { * @return {number} */ maxProfit(prices) { - let nextBuy = 0, nextSell = 0; - let curBuy = 0, curSell = 0; + let nextBuy = 0, + nextSell = 0; + let curBuy = 0, + curSell = 0; for (let i = prices.length - 1; i >= 0; i--) { curBuy = Math.max(nextBuy, -prices[i] + nextSell); @@ -378,12 +457,30 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxProfit(int[] prices) { + int nextBuy = 0, nextSell = 0; + int curBuy = 0, curSell = 0; + + for (int i = prices.Length - 1; i >= 0; i--) { + curBuy = Math.Max(nextBuy, -prices[i] + nextSell); + curSell = Math.Max(nextSell, prices[i] + nextBuy); + nextBuy = curBuy; + nextSell = curSell; + } + + return curBuy; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -399,7 +496,7 @@ class Solution: for i in range(1, len(prices)): if prices[i] > prices[i - 1]: profit += (prices[i] - prices[i - 1]) - + return profit ``` @@ -442,7 +539,21 @@ class Solution { let profit = 0; for (let i = 1; i < prices.length; i++) { if (prices[i] > prices[i - 1]) { - profit += (prices[i] - prices[i - 1]); + profit += prices[i] - prices[i - 1]; + } + } + return profit; + } +} +``` + +```csharp +public class Solution { + public int MaxProfit(int[] prices) { + int profit = 0; + for (int i = 1; i < prices.Length; i++) { + if (prices[i] > prices[i - 1]) { + profit += prices[i] - prices[i - 1]; } } return profit; @@ -454,5 +565,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/binary-search-tree-iterator.md b/articles/binary-search-tree-iterator.md new file mode 100644 index 000000000..4eccdb1ef --- /dev/null +++ b/articles/binary-search-tree-iterator.md @@ -0,0 +1,699 @@ +## 1. Flattening the BST (DFS) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class BSTIterator: + + def __init__(self, root: Optional[TreeNode]): + self.arr = [] + self.itr = 0 + + def dfs(node): + if not node: + return + dfs(node.left) + self.arr.append(node.val) + dfs(node.right) + + dfs(root) + + def next(self) -> int: + val = self.arr[self.itr] + self.itr += 1 + return val + + def hasNext(self) -> bool: + return self.itr < len(self.arr) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class BSTIterator { + private List arr; + private int itr; + + public BSTIterator(TreeNode root) { + arr = new ArrayList<>(); + itr = 0; + dfs(root); + } + + private void dfs(TreeNode node) { + if (node == null) { + return; + } + dfs(node.left); + arr.add(node.val); + dfs(node.right); + } + + public int next() { + return arr.get(itr++); + } + + public boolean hasNext() { + return itr < arr.size(); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class BSTIterator { +private: + vector arr; + int itr; + + void dfs(TreeNode* node) { + if (!node) { + return; + } + dfs(node->left); + arr.push_back(node->val); + dfs(node->right); + } + +public: + BSTIterator(TreeNode* root) { + itr = 0; + dfs(root); + } + + int next() { + return arr[itr++]; + } + + bool hasNext() { + return itr < arr.size(); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class BSTIterator { + /** + * @constructor + * @param {TreeNode} root + */ + constructor(root) { + this.arr = []; + this.itr = 0; + + const dfs = (node) => { + if (!node) { + return; + } + dfs(node.left); + this.arr.push(node.val); + dfs(node.right); + }; + + dfs(root); + } + + /** + * @return {number} + */ + next() { + return this.arr[this.itr++]; + } + + /** + * @return {boolean} + */ + hasNext() { + return this.itr < this.arr.length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(n)$ time for initialization. + - $O(n)$ time for each $next()$ and $hasNext()$ function calls. +- Space complexity: $O(n)$ + +--- + +## 2. Flatten the BST (Iterative DFS) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class BSTIterator: + + def __init__(self, root: Optional[TreeNode]): + self.arr = [] + self.itr = 0 + + stack = [] + while root or stack: + while root: + stack.append(root) + root = root.left + root = stack.pop() + self.arr.append(root.val) + root = root.right + + def next(self) -> int: + val = self.arr[self.itr] + self.itr += 1 + return val + + def hasNext(self) -> bool: + return self.itr < len(self.arr) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class BSTIterator { + private List arr; + private int itr; + + public BSTIterator(TreeNode root) { + arr = new ArrayList<>(); + itr = 0; + Stack stack = new Stack<>(); + while (root != null || !stack.isEmpty()) { + while (root != null) { + stack.push(root); + root = root.left; + } + root = stack.pop(); + arr.add(root.val); + root = root.right; + } + } + + public int next() { + return arr.get(itr++); + } + + public boolean hasNext() { + return itr < arr.size(); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class BSTIterator { +private: + vector arr; + int itr; + +public: + BSTIterator(TreeNode* root) { + itr = 0; + stack stack; + while (root || !stack.empty()) { + while (root) { + stack.push(root); + root = root->left; + } + root = stack.top(); + stack.pop(); + arr.push_back(root->val); + root = root->right; + } + } + + int next() { + return arr[itr++]; + } + + bool hasNext() { + return itr < arr.size(); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class BSTIterator { + /** + * @constructor + * @param {TreeNode} root + */ + constructor(root) { + this.arr = []; + this.itr = 0; + + let stack = []; + while (root || stack.length) { + while (root) { + stack.push(root); + root = root.left; + } + root = stack.pop(); + this.arr.push(root.val); + root = root.right; + } + } + + /** + * @return {number} + */ + next() { + return this.arr[this.itr++]; + } + + /** + * @return {boolean} + */ + hasNext() { + return this.itr < this.arr.length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(n)$ time for initialization. + - $O(n)$ time for each $next()$ and $hasNext()$ function calls. +- Space complexity: $O(n)$ + +--- + +## 3. Iterative DFS - I + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class BSTIterator: + + def __init__(self, root: Optional[TreeNode]): + self.stack = [] + while root: + self.stack.append(root) + root = root.left + + def next(self) -> int: + res = self.stack.pop() + cur = res.right + while cur: + self.stack.append(cur) + cur = cur.left + return res.val + + def hasNext(self) -> bool: + return bool(self.stack) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class BSTIterator { + private Stack stack; + + public BSTIterator(TreeNode root) { + stack = new Stack<>(); + while (root != null) { + stack.push(root); + root = root.left; + } + } + + public int next() { + TreeNode res = stack.pop(); + TreeNode cur = res.right; + while (cur != null) { + stack.push(cur); + cur = cur.left; + } + return res.val; + } + + public boolean hasNext() { + return !stack.isEmpty(); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class BSTIterator { +private: + stack stack; + +public: + BSTIterator(TreeNode* root) { + while (root) { + stack.push(root); + root = root->left; + } + } + + int next() { + TreeNode* res = stack.top(); + stack.pop(); + TreeNode* cur = res->right; + while (cur) { + stack.push(cur); + cur = cur->left; + } + return res->val; + } + + bool hasNext() { + return !stack.empty(); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class BSTIterator { + /** + * @constructor + * @param {TreeNode} root + */ + constructor(root) { + this.stack = []; + while (root) { + this.stack.push(root); + root = root.left; + } + } + + /** + * @return {number} + */ + next() { + let res = this.stack.pop(); + let cur = res.right; + while (cur) { + this.stack.push(cur); + cur = cur.left; + } + return res.val; + } + + /** + * @return {boolean} + */ + hasNext() { + return this.stack.length > 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ in average for each function call. +- Space complexity: $O(h)$ + +> Where $n$ is the number of nodes and $h$ is the height of the given tree. + +--- + +## 4. Iterative DFS - II + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class BSTIterator: + + def __init__(self, root: Optional[TreeNode]): + self.cur = root + self.stack = [] + + def next(self) -> int: + while self.cur: + self.stack.append(self.cur) + self.cur = self.cur.left + + node = self.stack.pop() + self.cur = node.right + return node.val + + def hasNext(self) -> bool: + return bool(self.cur) or bool(self.stack) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class BSTIterator { + private TreeNode cur; + private Stack stack; + + public BSTIterator(TreeNode root) { + cur = root; + stack = new Stack<>(); + } + + public int next() { + while (cur != null) { + stack.push(cur); + cur = cur.left; + } + + TreeNode node = stack.pop(); + cur = node.right; + return node.val; + } + + public boolean hasNext() { + return cur != null || !stack.isEmpty(); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class BSTIterator { +private: + TreeNode* cur; + stack stack; + +public: + BSTIterator(TreeNode* root) { + cur = root; + } + + int next() { + while (cur) { + stack.push(cur); + cur = cur->left; + } + + TreeNode* node = stack.top(); + stack.pop(); + cur = node->right; + return node->val; + } + + bool hasNext() { + return cur || !stack.empty(); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class BSTIterator { + /** + * @constructor + * @param {TreeNode} root + */ + constructor(root) { + this.cur = root; + this.stack = []; + } + + /** + * @return {number} + */ + next() { + while (this.cur) { + this.stack.push(this.cur); + this.cur = this.cur.left; + } + + let node = this.stack.pop(); + this.cur = node.right; + return node.val; + } + + /** + * @return {boolean} + */ + hasNext() { + return this.cur !== null || this.stack.length > 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ in average for each function call. +- Space complexity: $O(h)$ + +> Where $n$ is the number of nodes and $h$ is the height of the given tree. diff --git a/articles/binary-search.md b/articles/binary-search.md index 5e88782ce..83a4584ab 100644 --- a/articles/binary-search.md +++ b/articles/binary-search.md @@ -8,7 +8,7 @@ class Solution: if l > r: return -1 m = l + (r - l) // 2 - + if nums[m] == target: return m if nums[m] < target: @@ -24,10 +24,10 @@ public class Solution { public int binary_search(int l, int r, int[] nums, int target) { if (l > r) return -1; int m = l + (r - l) / 2; - + if (nums[m] == target) return m; - return (nums[m] < target) ? - binary_search(m + 1, r, nums, target) : + return (nums[m] < target) ? + binary_search(m + 1, r, nums, target) : binary_search(l, m - 1, nums, target); } @@ -43,10 +43,10 @@ public: int binary_search(int l, int r, vector& nums, int target){ if (l > r) return -1; int m = l + (r - l) / 2; - + if (nums[m] == target) return m; - return ((nums[m] < target) ? - binary_search(m + 1, r, nums, target) : + return ((nums[m] < target) ? + binary_search(m + 1, r, nums, target) : binary_search(l, m - 1, nums, target)); } @@ -66,11 +66,11 @@ class Solution { binary_search(l, r, nums, target) { if (l > r) return -1; let m = l + Math.floor((r - l) / 2); - + if (nums[m] === target) return m; - return (nums[m] < target) ? - this.binary_search(m + 1, r, nums, target) : - this.binary_search(l, m - 1, nums, target); + return nums[m] < target + ? this.binary_search(m + 1, r, nums, target) + : this.binary_search(l, m - 1, nums, target); } search(nums, target) { @@ -84,10 +84,10 @@ public class Solution { public int BinarySearch(int l, int r, int[] nums, int target) { if (l > r) return -1; int m = l + (r - l) / 2; - + if (nums[m] == target) return m; - return (nums[m] < target) ? - BinarySearch(m + 1, r, nums, target) : + return (nums[m] < target) ? + BinarySearch(m + 1, r, nums, target) : BinarySearch(l, m - 1, nums, target); } @@ -139,12 +139,35 @@ class Solution { } ``` +```swift +class Solution { + func binarySearch(_ l: Int, _ r: Int, _ nums: [Int], _ target: Int) -> Int { + if l > r { + return -1 + } + let m = l + (r - l) / 2 + + if nums[m] == target { + return m + } + if nums[m] < target { + return binarySearch(m + 1, r, nums, target) + } + return binarySearch(l, m - 1, nums, target) + } + + func search(_ nums: [Int], _ target: Int) -> Int { + return binarySearch(0, nums.count - 1, nums, target) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(\log n)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(\log n)$ --- @@ -159,7 +182,7 @@ class Solution: while l <= r: # (l + r) // 2 can lead to overflow - m = l + ((r - l) // 2) + m = l + ((r - l) // 2) if nums[m] > target: r = m - 1 @@ -296,12 +319,34 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + var l = 0, r = nums.count - 1 + + while l <= r { + // (l + r) // 2 can lead to overflow + let m = l + (r - l) / 2 + + if nums[m] > target { + r = m - 1 + } else if nums[m] < target { + l = m + 1 + } else { + return m + } + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ --- @@ -315,12 +360,12 @@ class Solution: l, r = 0, len(nums) while l < r: - m = l + ((r - l) // 2) + m = l + ((r - l) // 2) if nums[m] > target: r = m elif nums[m] <= target: l = m + 1 - return l - 1 if (l and nums[l - 1] == target) else -1 + return l - 1 if (l and nums[l - 1] == target) else -1 ``` ```java @@ -368,7 +413,8 @@ class Solution { * @return {number} */ search(nums, target) { - let l = 0, r = nums.length; + let l = 0, + r = nums.length; while (l < r) { let m = l + Math.floor((r - l) / 2); @@ -378,7 +424,7 @@ class Solution { l = m + 1; } } - return (l > 0 && nums[l - 1] === target) ? l - 1 : -1; + return l > 0 && nums[l - 1] === target ? l - 1 : -1; } } ``` @@ -439,12 +485,30 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + var l = 0, r = nums.count + + while l < r { + let m = l + (r - l) / 2 + if nums[m] > target { + r = m + } else { + l = m + 1 + } + } + return (l > 0 && nums[l - 1] == target) ? l - 1 : -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ --- @@ -458,12 +522,12 @@ class Solution: l, r = 0, len(nums) while l < r: - m = l + ((r - l) // 2) + m = l + ((r - l) // 2) if nums[m] >= target: r = m elif nums[m] < target: l = m + 1 - return l if (l < len(nums) and nums[l] == target) else -1 + return l if (l < len(nums) and nums[l] == target) else -1 ``` ```java @@ -511,7 +575,8 @@ class Solution { * @return {number} */ search(nums, target) { - let l = 0, r = nums.length; + let l = 0, + r = nums.length; while (l < r) { let m = l + Math.floor((r - l) / 2); @@ -521,7 +586,7 @@ class Solution { l = m + 1; } } - return (l < nums.length && nums[l] === target) ? l : -1; + return l < nums.length && nums[l] === target ? l : -1; } } ``` @@ -582,12 +647,30 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + var l = 0, r = nums.count + + while l < r { + let m = l + (r - l) / 2 + if nums[m] >= target { + r = m + } else { + l = m + 1 + } + } + return (l < nums.count && nums[l] == target) ? l : -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ --- @@ -664,9 +747,18 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + let index = nums.partitioningIndex { $0 >= target } + return (index < nums.count && nums[index] == target) ? index : -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/binary-subarrays-with-sum.md b/articles/binary-subarrays-with-sum.md new file mode 100644 index 000000000..e6b42256d --- /dev/null +++ b/articles/binary-subarrays-with-sum.md @@ -0,0 +1,385 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def numSubarraysWithSum(self, nums: List[int], goal: int) -> int: + n, res = len(nums), 0 + + for i in range(n): + curSum = 0 + for j in range(i, n): + curSum += nums[j] + if curSum == goal: + res += 1 + + return res +``` + +```java +public class Solution { + public int numSubarraysWithSum(int[] nums, int goal) { + int n = nums.length, res = 0; + + for (int i = 0; i < n; i++) { + int curSum = 0; + for (int j = i; j < n; j++) { + curSum += nums[j]; + if (curSum == goal) { + res++; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubarraysWithSum(vector& nums, int goal) { + int n = nums.size(), res = 0; + + for (int i = 0; i < n; i++) { + int curSum = 0; + for (int j = i; j < n; j++) { + curSum += nums[j]; + if (curSum == goal) { + res++; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} goal + * @return {number} + */ + numSubarraysWithSum(nums, goal) { + const n = nums.length; + let res = 0; + + for (let i = 0; i < n; i++) { + let curSum = 0; + for (let j = i; j < n; j++) { + curSum += nums[j]; + if (curSum === goal) { + res++; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Prefix Sum + Hash Map + +::tabs-start + +```python +class Solution: + def numSubarraysWithSum(self, nums: List[int], goal: int) -> int: + prefixSum = 0 + count = { 0 : 1 } # prefixSum -> count + res = 0 + + for num in nums: + prefixSum += num + res += count.get(prefixSum - goal, 0) + count[prefixSum] = count.get(prefixSum, 0) + 1 + + return res +``` + +```java +public class Solution { + public int numSubarraysWithSum(int[] nums, int goal) { + int prefixSum = 0, res = 0; + HashMap count = new HashMap<>(); + count.put(0, 1); + + for (int num : nums) { + prefixSum += num; + res += count.getOrDefault(prefixSum - goal, 0); + count.put(prefixSum, count.getOrDefault(prefixSum, 0) + 1); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubarraysWithSum(vector& nums, int goal) { + int prefixSum = 0, res = 0; + unordered_map count; + count[0] = 1; + + for (int& num : nums) { + prefixSum += num; + res += count[prefixSum - goal]; + count[prefixSum]++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} goal + * @return {number} + */ + numSubarraysWithSum(nums, goal) { + let prefixSum = 0, + res = 0; + const count = new Map(); + count.set(0, 1); + + for (const num of nums) { + prefixSum += num; + res += count.get(prefixSum - goal) || 0; + count.set(prefixSum, (count.get(prefixSum) || 0) + 1); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Prefix Sum + Array + +::tabs-start + +```python +class Solution: + def numSubarraysWithSum(self, nums: List[int], goal: int) -> int: + n = len(nums) + count = [0] * (n + 1) + count[0] = 1 + prefixSum, res = 0, 0 + + for num in nums: + prefixSum += num + if prefixSum >= goal: + res += count[prefixSum - goal] + count[prefixSum] += 1 + + return res +``` + +```java +public class Solution { + public int numSubarraysWithSum(int[] nums, int goal) { + int n = nums.length, prefixSum = 0, res = 0; + int[] count = new int[n + 1]; + count[0] = 1; + + for (int num : nums) { + prefixSum += num; + if (prefixSum >= goal) { + res += count[prefixSum - goal]; + } + count[prefixSum]++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubarraysWithSum(vector& nums, int goal) { + int n = nums.size(), prefixSum = 0, res = 0; + vector count(n + 1, 0); + count[0] = 1; + + for (int num : nums) { + prefixSum += num; + if (prefixSum >= goal) { + res += count[prefixSum - goal]; + } + count[prefixSum]++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} goal + * @return {number} + */ + numSubarraysWithSum(nums, goal) { + const n = nums.length; + const count = Array(n + 1).fill(0); + count[0] = 1; + let prefixSum = 0, + res = 0; + + for (const num of nums) { + prefixSum += num; + if (prefixSum >= goal) { + res += count[prefixSum - goal]; + } + count[prefixSum]++; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Sliding Window + +::tabs-start + +```python +class Solution: + def numSubarraysWithSum(self, nums: List[int], goal: int) -> int: + def helper(x): + if x < 0: + return 0 + res = l = cur = 0 + for r in range(len(nums)): + cur += nums[r] + while cur > x: + cur -= nums[l] + l += 1 + res += (r - l + 1) + return res + + return helper(goal) - helper(goal - 1) +``` + +```java +public class Solution { + public int numSubarraysWithSum(int[] nums, int goal) { + return helper(nums, goal) - helper(nums, goal - 1); + } + + private int helper(int[] nums, int x) { + if (x < 0) return 0; + int res = 0, l = 0, cur = 0; + for (int r = 0; r < nums.length; r++) { + cur += nums[r]; + while (cur > x) { + cur -= nums[l]; + l++; + } + res += (r - l + 1); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubarraysWithSum(vector& nums, int goal) { + return helper(nums, goal) - helper(nums, goal - 1); + } + +private: + int helper(vector& nums, int x) { + if (x < 0) return 0; + int res = 0, l = 0, cur = 0; + for (int r = 0; r < nums.size(); r++) { + cur += nums[r]; + while (cur > x) { + cur -= nums[l]; + l++; + } + res += (r - l + 1); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} goal + * @return {number} + */ + numSubarraysWithSum(nums, goal) { + const helper = (x) => { + if (x < 0) return 0; + let res = 0, + l = 0, + cur = 0; + for (let r = 0; r < nums.length; r++) { + cur += nums[r]; + while (cur > x) { + cur -= nums[l]; + l++; + } + res += r - l + 1; + } + return res; + }; + + return helper(goal) - helper(goal - 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/binary-tree-diameter.md b/articles/binary-tree-diameter.md index 3c73fbe92..de04dd9e6 100644 --- a/articles/binary-tree-diameter.md +++ b/articles/binary-tree-diameter.md @@ -14,10 +14,10 @@ class Solution: def diameterOfBinaryTree(self, root: Optional[TreeNode]) -> int: if not root: return 0 - + leftHeight = self.maxHeight(root.left) rightHeight = self.maxHeight(root.right) - diameter = leftHeight + rightHeight + diameter = leftHeight + rightHeight sub = max(self.diameterOfBinaryTree(root.left), self.diameterOfBinaryTree(root.right)) return max(diameter, sub) @@ -52,7 +52,7 @@ public class Solution { if (root == null) { return 0; } - + int leftHeight = maxHeight(root.left); int rightHeight = maxHeight(root.right); int diameter = leftHeight + rightHeight; @@ -87,7 +87,7 @@ class Solution { public: int diameterOfBinaryTree(TreeNode* root) { if (!root) return 0; - + int leftHeight = maxHeight(root->left); int rightHeight = maxHeight(root->right); int diameter = leftHeight + rightHeight; @@ -122,12 +122,14 @@ class Solution { */ diameterOfBinaryTree(root) { if (!root) return 0; - + let leftHeight = this.maxHeight(root.left); let rightHeight = this.maxHeight(root.right); let diameter = leftHeight + rightHeight; - let sub = Math.max(this.diameterOfBinaryTree(root.left), - this.diameterOfBinaryTree(root.right)); + let sub = Math.max( + this.diameterOfBinaryTree(root.left), + this.diameterOfBinaryTree(root.right), + ); return Math.max(diameter, sub); } @@ -137,7 +139,9 @@ class Solution { */ maxHeight(root) { if (!root) return 0; - return 1 + Math.max(this.maxHeight(root.left), this.maxHeight(root.right)); + return ( + 1 + Math.max(this.maxHeight(root.left), this.maxHeight(root.right)) + ); } } ``` @@ -166,7 +170,7 @@ public class Solution { int leftHeight = MaxHeight(root.left); int rightHeight = MaxHeight(root.right); int diameter = leftHeight + rightHeight; - int sub = Math.Max(DiameterOfBinaryTree(root.left), + int sub = Math.Max(DiameterOfBinaryTree(root.left), DiameterOfBinaryTree(root.right)); return Math.Max(diameter, sub); } @@ -193,14 +197,14 @@ func diameterOfBinaryTree(root *TreeNode) int { if root == nil { return 0 } - + leftHeight := maxHeight(root.Left) rightHeight := maxHeight(root.Right) diameter := leftHeight + rightHeight - - sub := max(diameterOfBinaryTree(root.Left), + + sub := max(diameterOfBinaryTree(root.Left), diameterOfBinaryTree(root.Right)) - + return max(diameter, sub) } @@ -208,7 +212,7 @@ func maxHeight(root *TreeNode) int { if root == nil { return 0 } - + return 1 + max(maxHeight(root.Left), maxHeight(root.Right)) } @@ -236,35 +240,70 @@ class Solution { if (root == null) { return 0 } - + val leftHeight = maxHeight(root.left) val rightHeight = maxHeight(root.right) val diameter = leftHeight + rightHeight - + val sub = maxOf( diameterOfBinaryTree(root.left), diameterOfBinaryTree(root.right) ) - + return maxOf(diameter, sub) } - + private fun maxHeight(root: TreeNode?): Int { if (root == null) { return 0 } - + return 1 + maxOf(maxHeight(root.left), maxHeight(root.right)) } } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func diameterOfBinaryTree(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + + let leftHeight = maxHeight(root.left) + let rightHeight = maxHeight(root.right) + let diameter = leftHeight + rightHeight + let sub = max(diameterOfBinaryTree(root.left), diameterOfBinaryTree(root.right)) + + return max(diameter, sub) + } + + private func maxHeight(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + return 1 + max(maxHeight(root.left), maxHeight(root.right)) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -317,7 +356,7 @@ class Solution: */ class Solution { - + public int diameterOfBinaryTree(TreeNode root) { int[] res = new int[1]; dfs(root, res); @@ -426,7 +465,7 @@ class Solution { */ public class Solution { - + public int DiameterOfBinaryTree(TreeNode root) { int res = 0; DFS(root, ref res); @@ -456,20 +495,20 @@ public class Solution { */ func diameterOfBinaryTree(root *TreeNode) int { res := 0 - + var dfs func(*TreeNode) int dfs = func(root *TreeNode) int { if root == nil { return 0 } - + left := dfs(root.Left) right := dfs(root.Right) res = max(res, left + right) - + return 1 + max(left, right) } - + dfs(root) return res } @@ -495,34 +534,68 @@ func max(a, b int) int { */ class Solution { private var res = 0 - + fun diameterOfBinaryTree(root: TreeNode?): Int { dfs(root) return res } - + private fun dfs(root: TreeNode?): Int { if (root == null) { return 0 } - + val left = dfs(root.left) val right = dfs(root.right) res = maxOf(res, left + right) - + return 1 + maxOf(left, right) } } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func diameterOfBinaryTree(_ root: TreeNode?) -> Int { + var res = 0 + + func dfs(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + let left = dfs(root.left) + let right = dfs(root.right) + res = max(res, left + right) + return 1 + max(left, right) + } + + dfs(root) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(h)$ - * Best Case ([balanced tree](https://www.geeksforgeeks.org/balanced-binary-tree/)): $O(log(n))$ - * Worst Case ([degenerate tree](https://www.geeksforgeeks.org/introduction-to-degenerate-binary-tree/)): $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(h)$ + - Best Case ([balanced tree](https://www.geeksforgeeks.org/balanced-binary-tree/)): $O(log(n))$ + - Worst Case ([degenerate tree](https://www.geeksforgeeks.org/introduction-to-degenerate-binary-tree/)): $O(n)$ > Where $n$ is the number of nodes in the tree and $h$ is the height of the tree. @@ -605,7 +678,7 @@ public class Solution { int rightHeight = rightData[0], rightDiameter = rightData[1]; int height = 1 + Math.max(leftHeight, rightHeight); - int diameter = Math.max(leftHeight + rightHeight, + int diameter = Math.max(leftHeight + rightHeight, Math.max(leftDiameter, rightDiameter)); mp.put(node, new int[]{height, diameter}); @@ -652,7 +725,7 @@ public: auto[rightHeight, rightDiameter] = mp[node->right]; int height = 1 + std::max(leftHeight, rightHeight); - int diameter = max(leftHeight + rightHeight, + int diameter = max(leftHeight + rightHeight, max(leftDiameter, rightDiameter)); mp[node] = {height, diameter}; @@ -699,8 +772,10 @@ class Solution { let [rightHeight, rightDiameter] = mp.get(node.right); let height = 1 + Math.max(leftHeight, rightHeight); - let diameter = Math.max(leftHeight + rightHeight, - Math.max(leftDiameter, rightDiameter)); + let diameter = Math.max( + leftHeight + rightHeight, + Math.max(leftDiameter, rightDiameter), + ); mp.set(node, [height, diameter]); } @@ -756,7 +831,7 @@ public class Solution { } int height = 1 + Math.Max(leftHeight, rightHeight); - int diameter = Math.Max(leftHeight + rightHeight, + int diameter = Math.Max(leftHeight + rightHeight, Math.Max(leftDiameter, rightDiameter)); mp[node] = (height, diameter); @@ -781,36 +856,36 @@ func diameterOfBinaryTree(root *TreeNode) int { if root == nil { return 0 } - + stack := linkedliststack.New() stack.Push(root) mp := make(map[*TreeNode][]int) mp[nil] = []int{0, 0} - + for !stack.Empty() { val, _ := stack.Peek() node := val.(*TreeNode) - + if node.Left != nil && len(mp[node.Left]) == 0 { stack.Push(node.Left) } else if node.Right != nil && len(mp[node.Right]) == 0 { stack.Push(node.Right) } else { stack.Pop() - + leftHeight := mp[node.Left][0] leftDiameter := mp[node.Left][1] rightHeight := mp[node.Right][0] rightDiameter := mp[node.Right][1] - + height := 1 + max(leftHeight, rightHeight) - diameter := max(leftHeight+rightHeight, + diameter := max(leftHeight+rightHeight, max(leftDiameter, rightDiameter)) - + mp[node] = []int{height, diameter} } } - + return mp[root][1] } @@ -838,16 +913,16 @@ class Solution { if (root == null) { return 0 } - + val stack = ArrayDeque() stack.addLast(root) - + val mp = HashMap>() mp[null] = Pair(0, 0) - + while (stack.isNotEmpty()) { val node = stack.last() - + when { node.left != null && !mp.containsKey(node.left) -> { stack.addLast(node.left) @@ -857,28 +932,71 @@ class Solution { } else -> { stack.removeLast() - + val (leftHeight, leftDiameter) = mp[node.left] ?: Pair(0, 0) val (rightHeight, rightDiameter) = mp[node.right] ?: Pair(0, 0) - + val height = 1 + maxOf(leftHeight, rightHeight) - val diameter = maxOf(leftHeight + rightHeight, - leftDiameter, + val diameter = maxOf(leftHeight + rightHeight, + leftDiameter, rightDiameter) - + mp[node] = Pair(height, diameter) } } } - + return mp[root]?.second ?: 0 } } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func diameterOfBinaryTree(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + var stack: [TreeNode] = [root] + var mp = [ObjectIdentifier: (Int, Int)]() + + while !stack.isEmpty { + let node = stack.last! + if let left = node.left, mp[ObjectIdentifier(left)] == nil { + stack.append(left) + } else if let right = node.right, mp[ObjectIdentifier(right)] == nil { + stack.append(right) + } else { + let node = stack.removeLast() + let leftTuple = node.left != nil ? mp[ObjectIdentifier(node.left!)]! : (0, 0) + let rightTuple = node.right != nil ? mp[ObjectIdentifier(node.right!)]! : (0, 0) + let height = 1 + max(leftTuple.0, rightTuple.0) + let diameter = max(leftTuple.0 + rightTuple.0, leftTuple.1, rightTuple.1) + mp[ObjectIdentifier(node)] = (height, diameter) + } + } + + return mp[ObjectIdentifier(root)]!.1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/binary-tree-from-preorder-and-inorder-traversal.md b/articles/binary-tree-from-preorder-and-inorder-traversal.md index 0e2049976..04b56213c 100644 --- a/articles/binary-tree-from-preorder-and-inorder-traversal.md +++ b/articles/binary-tree-from-preorder-and-inorder-traversal.md @@ -181,9 +181,9 @@ func buildTree(preorder []int, inorder []int) *TreeNode { if len(preorder) == 0 || len(inorder) == 0 { return nil } - + root := &TreeNode{Val: preorder[0]} - + mid := 0 for i, val := range inorder { if val == preorder[0] { @@ -191,10 +191,10 @@ func buildTree(preorder []int, inorder []int) *TreeNode { break } } - + root.Left = buildTree(preorder[1:mid+1], inorder[:mid]) root.Right = buildTree(preorder[mid+1:], inorder[mid+1:]) - + return root } ``` @@ -215,21 +215,64 @@ class Solution { if (preorder.isEmpty() || inorder.isEmpty()) { return null } - + val root = TreeNode(preorder[0]) - + val mid = inorder.indexOf(preorder[0]) - + root.left = buildTree( preorder.slice(1..mid).toIntArray(), inorder.slice(0 until mid).toIntArray() ) - + root.right = buildTree( preorder.slice(mid + 1 until preorder.size).toIntArray(), inorder.slice(mid + 1 until inorder.size).toIntArray() ) - + + return root + } +} +``` + +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func buildTree(_ preorder: [Int], _ inorder: [Int]) -> TreeNode? { + if preorder.isEmpty || inorder.isEmpty { + return nil + } + + let rootValue = preorder[0] + let root = TreeNode(rootValue) + guard let mid = inorder.firstIndex(of: rootValue) else { + return root + } + + root.left = buildTree( + Array(preorder[1..<(mid + 1)]), + Array(inorder[0.. Optional[TreeNode]: indices = {val: idx for idx, val in enumerate(inorder)} - + self.pre_idx = 0 def dfs(l, r): if l > r: @@ -332,7 +375,7 @@ public class Solution { class Solution { int pre_idx = 0; unordered_map indices; - + TreeNode* dfs(vector& preorder, int l, int r) { if (l > r) return nullptr; int root_val = preorder[pre_idx++]; @@ -342,7 +385,7 @@ class Solution { root->right = dfs(preorder, mid + 1, r); return root; } - + public: TreeNode* buildTree(vector& preorder, vector& inorder) { for (int i = 0; i < inorder.size(); ++i) { @@ -374,9 +417,9 @@ class Solution { buildTree(preorder, inorder) { let pre_idx = 0; let indices = new Map(); - + inorder.forEach((val, i) => indices.set(val, i)); - + function dfs(l, r) { if (l > r) return null; let root_val = preorder[pre_idx++]; @@ -386,7 +429,7 @@ class Solution { root.right = dfs(mid + 1, r); return root; } - + return dfs(0, inorder.length - 1); } } @@ -444,27 +487,27 @@ func buildTree(preorder []int, inorder []int) *TreeNode { for i, val := range inorder { indices[val] = i } - + preIdx := 0 - + var dfs func(int, int) *TreeNode dfs = func(left, right int) *TreeNode { if left > right { return nil } - + rootVal := preorder[preIdx] preIdx++ - + root := &TreeNode{Val: rootVal} mid := indices[rootVal] - + root.Left = dfs(left, mid - 1) root.Right = dfs(mid + 1, right) - + return root } - + return dfs(0, len(inorder) - 1) } ``` @@ -482,37 +525,82 @@ func buildTree(preorder []int, inorder []int) *TreeNode { */ class Solution { private var preIdx = 0 - + fun buildTree(preorder: IntArray, inorder: IntArray): TreeNode? { val indices = inorder.withIndex() .associate { (index, value) -> value to index } - + fun dfs(left: Int, right: Int): TreeNode? { if (left > right) { return null } - + val rootVal = preorder[preIdx++] val root = TreeNode(rootVal) val mid = indices[rootVal]!! - + root.left = dfs(left, mid - 1) root.right = dfs(mid + 1, right) - + return root } - + return dfs(0, inorder.lastIndex) } } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + var preIndex = 0 + var indexMap = [Int: Int]() + + func buildTree(_ preorder: [Int], _ inorder: [Int]) -> TreeNode? { + for (index, value) in inorder.enumerated() { + indexMap[value] = index + } + return dfs(preorder, 0, inorder.count - 1) + } + + private func dfs(_ preorder: [Int], _ left: Int, _ right: Int) -> TreeNode? { + if left > right { + return nil + } + + let rootVal = preorder[preIndex] + preIndex += 1 + let root = TreeNode(rootVal) + let mid = indexMap[rootVal]! + + root.left = dfs(preorder, left, mid - 1) + root.right = dfs(preorder, mid + 1, right) + + return root + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -538,7 +626,7 @@ class Solution: if inorder[inIdx] == limit: inIdx += 1 return None - + root = TreeNode(preorder[preIdx]) preIdx += 1 root.left = dfs(root.val) @@ -643,21 +731,22 @@ class Solution { * @return {TreeNode} */ buildTree(preorder, inorder) { - let preIdx = 0, inIdx = 0; - + let preIdx = 0, + inIdx = 0; + function dfs(limit) { if (preIdx >= preorder.length) return null; if (inorder[inIdx] === limit) { inIdx++; return null; } - + let root = new TreeNode(preorder[preIdx++]); root.left = dfs(root.val); root.right = dfs(limit); return root; } - + return dfs(Infinity); } } @@ -712,7 +801,7 @@ public class Solution { */ func buildTree(preorder []int, inorder []int) *TreeNode { preIdx, inIdx := 0, 0 - + var dfs func(int) *TreeNode dfs = func(limit int) *TreeNode { if preIdx >= len(preorder) { @@ -722,16 +811,16 @@ func buildTree(preorder []int, inorder []int) *TreeNode { inIdx++ return nil } - + root := &TreeNode{Val: preorder[preIdx]} preIdx++ - + root.Left = dfs(root.Val) root.Right = dfs(limit) - + return root } - + return dfs(math.MaxInt) } ``` @@ -750,7 +839,7 @@ func buildTree(preorder []int, inorder []int) *TreeNode { class Solution { private var preIdx = 0 private var inIdx = 0 - + fun buildTree(preorder: IntArray, inorder: IntArray): TreeNode? { fun dfs(limit: Int): TreeNode? { if (preIdx >= preorder.size) { @@ -760,24 +849,66 @@ class Solution { inIdx++ return null } - + val root = TreeNode(preorder[preIdx]) preIdx++ - + root.left = dfs(root.`val`) root.right = dfs(limit) - + return root } - + return dfs(Int.MAX_VALUE) } } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + var preIdx = 0 + var inIdx = 0 + + func buildTree(_ preorder: [Int], _ inorder: [Int]) -> TreeNode? { + return dfs(preorder, inorder, Int.max) + } + + private func dfs(_ preorder: [Int], _ inorder: [Int], _ limit: Int) -> TreeNode? { + if preIdx >= preorder.count { + return nil + } + if inorder[inIdx] == limit { + inIdx += 1 + return nil + } + + let root = TreeNode(preorder[preIdx]) + preIdx += 1 + root.left = dfs(preorder, inorder, root.val) + root.right = dfs(preorder, inorder, limit) + return root + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. diff --git a/articles/binary-tree-inorder-traversal.md b/articles/binary-tree-inorder-traversal.md index 4735f8400..79a7a36f9 100644 --- a/articles/binary-tree-inorder-traversal.md +++ b/articles/binary-tree-inorder-traversal.md @@ -16,11 +16,11 @@ class Solution: def inorder(node): if not node: return - + inorder(node.left) res.append(node.val) inorder(node.right) - + inorder(root) return res ``` @@ -126,14 +126,43 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public List InorderTraversal(TreeNode root) { + List res = new List(); + void Inorder(TreeNode node) { + if (node == null) return; + Inorder(node.left); + res.Add(node.val); + Inorder(node.right); + } + Inorder(root); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(n)$ space for the recursion stack. - * $O(n)$ space for the output array. +- Time complexity: $O(n)$ +- Space complexity: + - $O(n)$ space for the recursion stack. + - $O(n)$ space for the output array. --- @@ -161,7 +190,7 @@ class Solution: cur = stack.pop() res.append(cur.val) cur = cur.right - + return res ``` @@ -273,14 +302,49 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public IList InorderTraversal(TreeNode root) { + List res = new List(); + Stack stack = new Stack(); + TreeNode cur = root; + + while (cur != null || stack.Count > 0) { + while (cur != null) { + stack.Push(cur); + cur = cur.left; + } + cur = stack.Pop(); + res.Add(cur.val); + cur = cur.right; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(n)$ space for the stack. - * $O(n)$ space for the output array. +- Time complexity: $O(n)$ +- Space complexity: + - $O(n)$ space for the stack. + - $O(n)$ space for the output array. --- @@ -457,11 +521,56 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public List InorderTraversal(TreeNode root) { + List res = new List(); + TreeNode cur = root; + + while (cur != null) { + if (cur.left == null) { + res.Add(cur.val); + cur = cur.right; + } else { + TreeNode prev = cur.left; + while (prev.right != null && prev.right != cur) { + prev = prev.right; + } + + if (prev.right == null) { + prev.right = cur; + cur = cur.left; + } else { + prev.right = null; + res.Add(cur.val); + cur = cur.right; + } + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(1)$ extra space. - * $O(n)$ space for the output array. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output array. diff --git a/articles/binary-tree-maximum-path-sum.md b/articles/binary-tree-maximum-path-sum.md index af442201a..a783160d0 100644 --- a/articles/binary-tree-maximum-path-sum.md +++ b/articles/binary-tree-maximum-path-sum.md @@ -16,7 +16,7 @@ class Solution: def dfs(root): nonlocal res if not root: - return + return left = self.getMax(root.left) right = self.getMax(root.right) res =max(res, root.val + left + right) @@ -24,11 +24,11 @@ class Solution: dfs(root.right) dfs(root) return res - + def getMax(self, root: Optional[TreeNode]) -> int: if not root: return 0 - + left = self.getMax(root.left) right = self.getMax(root.right) path = root.val + max(left, right) @@ -215,7 +215,7 @@ public class Solution { * } */ func maxPathSum(root *TreeNode) int { - res := -1 << 31 + res := -1 << 31 dfs(root, &res) return res } @@ -290,12 +290,55 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + var res = Int.min + + func maxPathSum(_ root: TreeNode?) -> Int { + dfs(root) + return res + } + + private func dfs(_ root: TreeNode?) { + guard let node = root else { return } + let left = getMax(node.left) + let right = getMax(node.right) + res = max(res, node.val + left + right) + dfs(node.left) + dfs(node.right) + } + + private func getMax(_ root: TreeNode?) -> Int { + guard let node = root else { return 0 } + let left = getMax(node.left) + let right = getMax(node.right) + let path = node.val + max(left, right) + return max(0, path) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -496,24 +539,24 @@ public class Solution { */ func maxPathSum(root *TreeNode) int { res := []int{root.Val} - + var dfs func(node *TreeNode) int dfs = func(node *TreeNode) int { if node == nil { return 0 } - + leftMax := dfs(node.Left) rightMax := dfs(node.Right) - + leftMax = max(leftMax, 0) rightMax = max(rightMax, 0) - + res[0] = max(res[0], node.Val+leftMax+rightMax) - + return node.Val + max(leftMax, rightMax) } - + dfs(root) return res[0] } @@ -539,30 +582,66 @@ func max(a, b int) int { */ class Solution { private var res = Int.MIN_VALUE - + fun maxPathSum(root: TreeNode?): Int { dfs(root) return res } - + private fun dfs(node: TreeNode?): Int { if (node == null) { return 0 } - + val leftMax = maxOf(dfs(node.left), 0) val rightMax = maxOf(dfs(node.right), 0) - + res = maxOf(res, node.`val` + leftMax + rightMax) - + return node.`val` + maxOf(leftMax, rightMax) } } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func maxPathSum(_ root: TreeNode?) -> Int { + var res = root!.val + + func dfs(_ root: TreeNode?) -> Int { + guard let node = root else { return 0 } + + let leftMax = max(dfs(node.left), 0) + let rightMax = max(dfs(node.right), 0) + + res = max(res, node.val + leftMax + rightMax) + return node.val + max(leftMax, rightMax) + } + + dfs(root) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/binary-tree-postorder-traversal.md b/articles/binary-tree-postorder-traversal.md index 554c3006a..4b1ea9958 100644 --- a/articles/binary-tree-postorder-traversal.md +++ b/articles/binary-tree-postorder-traversal.md @@ -16,11 +16,11 @@ class Solution: def postorder(node): if not node: return - + postorder(node.left) postorder(node.right) res.append(node.val) - + postorder(root) return res ``` @@ -126,14 +126,45 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public List PostorderTraversal(TreeNode root) { + List res = new List(); + + void Postorder(TreeNode node) { + if (node == null) return; + Postorder(node.left); + Postorder(node.right); + res.Add(node.val); + } + + Postorder(root); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(n)$ space for the recursion stack. - * $O(n)$ space for the output array. +- Time complexity: $O(n)$ +- Space complexity: + - $O(n)$ space for the recursion stack. + - $O(n)$ space for the output array. --- @@ -309,14 +340,60 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public List PostorderTraversal(TreeNode root) { + var stack = new Stack(); + var visit = new Stack(); + var res = new List(); + + stack.Push(root); + visit.Push(false); + + while (stack.Count > 0) { + var cur = stack.Pop(); + var v = visit.Pop(); + + if (cur != null) { + if (v) { + res.Add(cur.val); + } else { + stack.Push(cur); + visit.Push(true); + stack.Push(cur.right); + visit.Push(false); + stack.Push(cur.left); + visit.Push(false); + } + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(n)$ space for the stacks. - * $O(n)$ space for the output array. +- Time complexity: $O(n)$ +- Space complexity: + - $O(n)$ space for the stacks. + - $O(n)$ space for the output array. --- @@ -464,14 +541,51 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public List PostorderTraversal(TreeNode root) { + List res = new List(); + Stack stack = new Stack(); + TreeNode cur = root; + + while (cur != null || stack.Count > 0) { + if (cur != null) { + res.Add(cur.val); + stack.Push(cur); + cur = cur.right; + } else { + cur = stack.Pop(); + cur = cur.left; + } + } + + res.Reverse(); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(n)$ space for the stack. - * $O(n)$ space for the output array. +- Time complexity: $O(n)$ +- Space complexity: + - $O(n)$ space for the stack. + - $O(n)$ space for the output array. --- @@ -507,7 +621,7 @@ class Solution: else: prev.left = None cur = cur.left - + res.reverse() return res ``` @@ -652,11 +766,57 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public List PostorderTraversal(TreeNode root) { + List res = new List(); + TreeNode cur = root; + + while (cur != null) { + if (cur.right == null) { + res.Add(cur.val); + cur = cur.left; + } else { + TreeNode prev = cur.right; + while (prev.left != null && prev.left != cur) { + prev = prev.left; + } + + if (prev.left == null) { + res.Add(cur.val); + prev.left = cur; + cur = cur.right; + } else { + prev.left = null; + cur = cur.left; + } + } + } + + res.Reverse(); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(1)$ extra space. - * $O(n)$ space for the output array. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output array. diff --git a/articles/binary-tree-preorder-traversal.md b/articles/binary-tree-preorder-traversal.md index fbcc8b4d6..fe9cecef4 100644 --- a/articles/binary-tree-preorder-traversal.md +++ b/articles/binary-tree-preorder-traversal.md @@ -16,11 +16,11 @@ class Solution: def preorder(node): if not node: return - + res.append(node.val) preorder(node.left) preorder(node.right) - + preorder(root) return res ``` @@ -126,14 +126,45 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public List PreorderTraversal(TreeNode root) { + List res = new List(); + Preorder(root, res); + return res; + } + + private void Preorder(TreeNode node, List res) { + if (node == null) return; + + res.Add(node.val); + Preorder(node.left, res); + Preorder(node.right, res); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(n)$ space for the recursion stack. - * $O(n)$ space for the output array. +- Time complexity: $O(n)$ +- Space complexity: + - $O(n)$ space for the recursion stack. + - $O(n)$ space for the output array. --- @@ -161,7 +192,7 @@ class Solution: cur = cur.left else: cur = stack.pop() - + return res ``` @@ -265,7 +296,41 @@ class Solution { cur = cur.left; } else { cur = stack.pop(); + } + } + + return res; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public List PreorderTraversal(TreeNode root) { + List res = new List(); + Stack stack = new Stack(); + TreeNode cur = root; + while (cur != null || stack.Count > 0) { + if (cur != null) { + res.Add(cur.val); + stack.Push(cur.right); + cur = cur.left; + } else { + cur = stack.Pop(); } } @@ -278,10 +343,10 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(n)$ space for the stack. - * $O(n)$ space for the output array. +- Time complexity: $O(n)$ +- Space complexity: + - $O(n)$ space for the stack. + - $O(n)$ space for the output array. --- @@ -458,11 +523,56 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public List PreorderTraversal(TreeNode root) { + List res = new List(); + TreeNode cur = root; + + while (cur != null) { + if (cur.left == null) { + res.Add(cur.val); + cur = cur.right; + } else { + TreeNode prev = cur.left; + while (prev.right != null && prev.right != cur) { + prev = prev.right; + } + + if (prev.right == null) { + res.Add(cur.val); + prev.right = cur; + cur = cur.left; + } else { + prev.right = null; + cur = cur.right; + } + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(1)$ extra space. - * $O(n)$ space for the output array. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output array. diff --git a/articles/binary-tree-right-side-view.md b/articles/binary-tree-right-side-view.md index e17b22299..4d64bb984 100644 --- a/articles/binary-tree-right-side-view.md +++ b/articles/binary-tree-right-side-view.md @@ -19,10 +19,10 @@ class Solution: return None if depth == len(res): res.append(node.val) - + dfs(node.right, depth + 1) dfs(node.left, depth + 1) - + dfs(root, 0) return res ``` @@ -46,21 +46,21 @@ class Solution: public class Solution { List res = new ArrayList<>(); - + public List rightSideView(TreeNode root) { dfs(root, 0); return res; } - + private void dfs(TreeNode node, int depth) { if (node == null) { return; } - + if (res.size() == depth) { res.add(node.val); } - + dfs(node.right, depth + 1); dfs(node.left, depth + 1); } @@ -83,19 +83,19 @@ public class Solution { class Solution { public: vector res; - + vector rightSideView(TreeNode* root) { dfs(root, 0); return res; } - + void dfs(TreeNode* node, int depth) { if (!node) return; - + if (res.size() == depth) { res.push_back(node->val); } - + dfs(node->right, depth + 1); dfs(node->left, depth + 1); } @@ -156,21 +156,21 @@ class Solution { public class Solution { List res = new List(); - + public List RightSideView(TreeNode root) { dfs(root, 0); return res; } - + private void dfs(TreeNode node, int depth) { if (node == null) { return; } - + if (res.Count == depth) { res.Add(node.val); } - + dfs(node.right, depth + 1); dfs(node.left, depth + 1); } @@ -200,7 +200,7 @@ func rightSideView(root *TreeNode) []int { dfs(node.Right, depth+1) dfs(node.Left, depth+1) } - + dfs(root, 0) return res } @@ -236,12 +236,48 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func rightSideView(_ root: TreeNode?) -> [Int] { + var res = [Int]() + + func dfs(_ node: TreeNode?, _ depth: Int) { + guard let node = node else { return } + if depth == res.count { + res.append(node.val) + } + + dfs(node.right, depth + 1) + dfs(node.left, depth + 1) + } + + dfs(root, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -462,7 +498,7 @@ func rightSideView(root *TreeNode) []int { if root == nil { return []int{} } - + res := []int{} q := []*TreeNode{root} @@ -473,7 +509,7 @@ func rightSideView(root *TreeNode) []int { for i := 0; i < qLen; i++ { node := q[0] q = q[1:] - + if node != nil { rightSide = node.Val if node.Left != nil { @@ -486,7 +522,7 @@ func rightSideView(root *TreeNode) []int { } res = append(res, rightSide) } - + return res } ``` @@ -524,7 +560,49 @@ class Solution { } rightSide?.let { res.add(it.`val`) } } - + + return res + } +} +``` + +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func rightSideView(_ root: TreeNode?) -> [Int] { + var res = [Int]() + var q = Deque() + q.append(root) + + while !q.isEmpty { + var rightSide: TreeNode? + let qLen = q.count + + for _ in 0.. List[List[int]]: + cols = defaultdict(list) + que = deque([(root, 0)]) + + while que: + node, pos = que.popleft() + if node: + cols[pos].append(node.val) + que.append((node.left, pos - 1)) + que.append((node.right, pos + 1)) + + return [cols[x] for x in sorted(cols)] +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List> verticalOrder(TreeNode root) { + if (root == null) return new ArrayList<>(); + + Map> cols = new TreeMap<>(); + Queue> queue = new LinkedList<>(); + queue.offer(new Pair<>(root, 0)); + + while (!queue.isEmpty()) { + Pair p = queue.poll(); + TreeNode node = p.getKey(); + int pos = p.getValue(); + + cols.computeIfAbsent(pos, k -> new ArrayList<>()).add(node.val); + + if (node.left != null) queue.offer(new Pair<>(node.left, pos - 1)); + if (node.right != null) queue.offer(new Pair<>(node.right, pos + 1)); + } + + return new ArrayList<>(cols.values()); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector> verticalOrder(TreeNode* root) { + if (!root) return {}; + map> cols; + queue> q; + q.push({root, 0}); + + while (!q.empty()) { + auto [node, pos] = q.front(); q.pop(); + cols[pos].push_back(node->val); + if (node->left) q.push({node->left, pos - 1}); + if (node->right) q.push({node->right, pos + 1}); + } + + vector> res; + for (auto& [_, vec] : cols) + res.push_back(vec); + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[][]} + */ + verticalOrder(root) { + if (!root) return []; + + const cols = new Map(); + const queue = new Queue([[root, 0]]); + + while (!queue.isEmpty()) { + const [node, pos] = queue.pop(); + if (!cols.has(pos)) cols.set(pos, []); + cols.get(pos).push(node.val); + + if (node.left) queue.push([node.left, pos - 1]); + if (node.right) queue.push([node.right, pos + 1]); + } + + const sortedKeys = Array.from(cols.keys()).sort((a, b) => a - b); + return sortedKeys.map((k) => cols.get(k)); + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public List> VerticalOrder(TreeNode root) { + if (root == null) return new List>(); + + var cols = new SortedDictionary>(); + var queue = new Queue<(TreeNode node, int pos)>(); + queue.Enqueue((root, 0)); + + while (queue.Count > 0) { + var (node, pos) = queue.Dequeue(); + + if (!cols.ContainsKey(pos)) + cols[pos] = new List(); + cols[pos].Add(node.val); + + if (node.left != null) queue.Enqueue((node.left, pos - 1)); + if (node.right != null) queue.Enqueue((node.right, pos + 1)); + } + + return cols.Values.ToList>(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Depth First Search + Sorting + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def verticalOrder(self, root: Optional[TreeNode]) -> List[List[int]]: + cols = defaultdict(list) + + def dfs(node, row, col): + if not node: + return + cols[col].append((row, node.val)) + dfs(node.left, row + 1, col - 1) + dfs(node.right, row + 1, col + 1) + + dfs(root, 0, 0) + + res = [] + for col in sorted(cols): + col_vals = sorted(cols[col], key=lambda x: x[0]) + res.append([val for _, val in col_vals]) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private Map> cols = new TreeMap<>(); + + public List> verticalOrder(TreeNode root) { + dfs(root, 0, 0); + List> res = new ArrayList<>(); + + for (List list : cols.values()) { + list.sort(Comparator.comparingInt(a -> a[0])); + List colVals = new ArrayList<>(); + for (int[] p : list) colVals.add(p[1]); + res.add(colVals); + } + + return res; + } + + private void dfs(TreeNode node, int row, int col) { + if (node == null) return; + cols.computeIfAbsent(col, k -> new ArrayList<>()).add(new int[]{row, node.val}); + dfs(node.left, row + 1, col - 1); + dfs(node.right, row + 1, col + 1); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { + map>> cols; + + void dfs(TreeNode* node, int row, int col) { + if (!node) return; + cols[col].push_back({row, node->val}); + dfs(node->left, row + 1, col - 1); + dfs(node->right, row + 1, col + 1); + } + +public: + vector> verticalOrder(TreeNode* root) { + dfs(root, 0, 0); + vector> res; + + for (auto& [col, vec] : cols) { + stable_sort(vec.begin(), vec.end(), + [](const pair& a, const pair& b) { + return a.first < b.first; // sort ONLY by row + }); + + vector colVals; + for (auto& [_, val] : vec) + colVals.push_back(val); + res.push_back(colVals); + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[][]} + */ + verticalOrder(root) { + const cols = new Map(); + + const dfs = (node, row, col) => { + if (!node) return; + if (!cols.has(col)) cols.set(col, []); + cols.get(col).push([row, node.val]); + dfs(node.left, row + 1, col - 1); + dfs(node.right, row + 1, col + 1); + }; + + dfs(root, 0, 0); + + const sortedCols = Array.from(cols.entries()).sort( + (a, b) => a[0] - b[0], + ); + return sortedCols.map(([_, vec]) => + vec.sort((a, b) => a[0] - b[0]).map(([_, val]) => val), + ); + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + private SortedDictionary> cols = new(); + + public List> VerticalOrder(TreeNode root) { + DFS(root, 0, 0); + + List> res = new(); + foreach (var entry in cols) { + var list = entry.Value.OrderBy(x => x.Item1).Select(x => x.Item2).ToList(); + res.Add(list); + } + + return res; + } + + private void DFS(TreeNode node, int row, int col) { + if (node == null) return; + if (!cols.ContainsKey(col)) cols[col] = new List<(int, int)>(); + cols[col].Add((row, node.val)); + DFS(node.left, row + 1, col - 1); + DFS(node.right, row + 1, col + 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n \log n)$ + +--- + +## 3. Breadth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def verticalOrder(self, root: Optional[TreeNode]) -> List[List[int]]: + if not root: + return [] + + cols = defaultdict(list) + queue = deque([(root, 0)]) + minCol = maxCol = 0 + + while queue: + node, col = queue.popleft() + cols[col].append(node.val) + minCol = min(minCol, col) + maxCol = max(maxCol, col) + + if node.left: + queue.append((node.left, col - 1)) + if node.right: + queue.append((node.right, col + 1)) + + return [cols[c] for c in range(minCol, maxCol + 1)] +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List> verticalOrder(TreeNode root) { + if (root == null) return new ArrayList<>(); + + Map> cols = new HashMap<>(); + Queue> queue = new LinkedList<>(); + queue.offer(new Pair<>(root, 0)); + int minCol = 0, maxCol = 0; + + while (!queue.isEmpty()) { + Pair p = queue.poll(); + TreeNode node = p.getKey(); + int col = p.getValue(); + + cols.computeIfAbsent(col, x -> new ArrayList<>()).add(node.val); + minCol = Math.min(minCol, col); + maxCol = Math.max(maxCol, col); + + if (node.left != null) queue.offer(new Pair<>(node.left, col - 1)); + if (node.right != null) queue.offer(new Pair<>(node.right, col + 1)); + } + + List> res = new ArrayList<>(); + for (int c = minCol; c <= maxCol; c++) { + res.add(cols.get(c)); + } + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector> verticalOrder(TreeNode* root) { + if (!root) return {}; + + unordered_map> cols; + queue> q; + q.push({root, 0}); + int minCol = 0, maxCol = 0; + + while (!q.empty()) { + auto [node, col] = q.front(); q.pop(); + cols[col].push_back(node->val); + minCol = min(minCol, col); + maxCol = max(maxCol, col); + + if (node->left) q.push({node->left, col - 1}); + if (node->right) q.push({node->right, col + 1}); + } + + vector> res; + for (int c = minCol; c <= maxCol; ++c) + res.push_back(cols[c]); + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[][]} + */ + verticalOrder(root) { + if (!root) return []; + + const cols = new Map(); + const queue = new Queue([[root, 0]]); + let minCol = 0, + maxCol = 0; + + while (!queue.isEmpty()) { + const [node, col] = queue.pop(); + if (!cols.has(col)) cols.set(col, []); + cols.get(col).push(node.val); + minCol = Math.min(minCol, col); + maxCol = Math.max(maxCol, col); + + if (node.left) queue.push([node.left, col - 1]); + if (node.right) queue.push([node.right, col + 1]); + } + + const res = []; + for (let c = minCol; c <= maxCol; c++) { + res.push(cols.get(c)); + } + return res; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public List> VerticalOrder(TreeNode root) { + if (root == null) return new List>(); + + Dictionary> cols = new(); + Queue<(TreeNode node, int col)> queue = new(); + queue.Enqueue((root, 0)); + int minCol = 0, maxCol = 0; + + while (queue.Count > 0) { + var (node, col) = queue.Dequeue(); + if (!cols.ContainsKey(col)) + cols[col] = new List(); + cols[col].Add(node.val); + minCol = Math.Min(minCol, col); + maxCol = Math.Max(maxCol, col); + + if (node.left != null) queue.Enqueue((node.left, col - 1)); + if (node.right != null) queue.Enqueue((node.right, col + 1)); + } + + var res = new List>(); + for (int c = minCol; c <= maxCol; c++) { + res.Add(cols[c]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Depth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def verticalOrder(self, root: Optional[TreeNode]) -> List[List[int]]: + if not root: + return [] + + cols = defaultdict(list) + minCol = maxCol = 0 + + def dfs(node, row, col): + nonlocal minCol, maxCol + if not node: + return + cols[col].append((row, node.val)) + minCol = min(minCol, col) + maxCol = max(maxCol, col) + dfs(node.left, row + 1, col - 1) + dfs(node.right, row + 1, col + 1) + + dfs(root, 0, 0) + + res = [] + for c in range(minCol, maxCol + 1): + # sort by row only + col_vals = sorted(cols[c], key=lambda x: x[0]) + res.append([val for _, val in col_vals]) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private Map> cols = new HashMap<>(); + private int minCol = 0, maxCol = 0; + + public List> verticalOrder(TreeNode root) { + if (root == null) return new ArrayList<>(); + dfs(root, 0, 0); + + List> res = new ArrayList<>(); + for (int c = minCol; c <= maxCol; c++) { + List list = cols.getOrDefault(c, new ArrayList<>()); + list.sort(Comparator.comparingInt(a -> a[0])); // sort by row + List colVals = new ArrayList<>(); + for (int[] p : list) colVals.add(p[1]); + res.add(colVals); + } + return res; + } + + private void dfs(TreeNode node, int row, int col) { + if (node == null) return; + cols.computeIfAbsent(col, k -> new ArrayList<>()).add(new int[]{row, node.val}); + minCol = Math.min(minCol, col); + maxCol = Math.max(maxCol, col); + dfs(node.left, row + 1, col - 1); + dfs(node.right, row + 1, col + 1); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { + unordered_map>> cols; + int minCol = 0, maxCol = 0; + + void dfs(TreeNode* node, int row, int col) { + if (!node) return; + cols[col].emplace_back(row, node->val); + minCol = min(minCol, col); + maxCol = max(maxCol, col); + dfs(node->left, row + 1, col - 1); + dfs(node->right, row + 1, col + 1); + } + +public: + vector> verticalOrder(TreeNode* root) { + if (!root) return {}; + dfs(root, 0, 0); + vector> res; + + for (int c = minCol; c <= maxCol; ++c) { + auto& vec = cols[c]; + stable_sort(vec.begin(), vec.end(), + [](const pair& a, const pair& b) { + return a.first < b.first; // sort by row only + }); + vector colVals; + for (auto& [_, val] : vec) + colVals.push_back(val); + res.push_back(colVals); + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[][]} + */ + verticalOrder(root) { + if (!root) return []; + + const cols = new Map(); + let minCol = 0, + maxCol = 0; + + const dfs = (node, row, col) => { + if (!node) return; + if (!cols.has(col)) cols.set(col, []); + cols.get(col).push([row, node.val]); + minCol = Math.min(minCol, col); + maxCol = Math.max(maxCol, col); + dfs(node.left, row + 1, col - 1); + dfs(node.right, row + 1, col + 1); + }; + + dfs(root, 0, 0); + + const res = []; + for (let c = minCol; c <= maxCol; c++) { + let entries = cols.get(c) || []; + entries.sort((a, b) => a[0] - b[0]); // sort by row only + res.push(entries.map(([_, val]) => val)); + } + + return res; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + private Dictionary> cols = new(); + private int minCol = 0, maxCol = 0; + + public List> VerticalOrder(TreeNode root) { + if (root == null) return new List>(); + DFS(root, 0, 0); + var res = new List>(); + + for (int c = minCol; c <= maxCol; c++) { + var list = cols.ContainsKey(c) ? cols[c] : new List<(int, int)>(); + list.Sort((a, b) => a.Item1.CompareTo(b.Item1)); // sort by row + res.Add(list.Select(p => p.Item2).ToList()); + } + + return res; + } + + private void DFS(TreeNode node, int row, int col) { + if (node == null) return; + if (!cols.ContainsKey(col)) cols[col] = new List<(int, int)>(); + cols[col].Add((row, node.val)); + minCol = Math.Min(minCol, col); + maxCol = Math.Max(maxCol, col); + DFS(node.left, row + 1, col - 1); + DFS(node.right, row + 1, col + 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(w * h \log h)$ +- Space complexity: $O(n)$ + +> Where $n$ is the number of nodes, $h$ is the height of the tree (i.e. maximum number of nodes in any vertical line of the tree), and $w$ is the width of the tree (i.e. maximum number of nodes in any of the levels of the tree). diff --git a/articles/binary-tree-zigzag-level-order-traversal.md b/articles/binary-tree-zigzag-level-order-traversal.md new file mode 100644 index 000000000..449ee2151 --- /dev/null +++ b/articles/binary-tree-zigzag-level-order-traversal.md @@ -0,0 +1,647 @@ +## 1. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def zigzagLevelOrder(self, root: Optional[TreeNode]) -> List[List[int]]: + res = [] + q = deque([root] if root else []) + while q: + level = [] + for i in range(len(q)): + node = q.popleft() + level.append(node.val) + if node.left: + q.append(node.left) + if node.right: + q.append(node.right) + if len(res) % 2: + level.reverse() + res.append(level) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List> zigzagLevelOrder(TreeNode root) { + List> res = new ArrayList<>(); + if (root == null) return res; + + Queue q = new LinkedList<>(); + q.offer(root); + + while (!q.isEmpty()) { + List level = new ArrayList<>(); + for (int i = q.size(); i > 0; i--) { + TreeNode node = q.poll(); + level.add(node.val); + if (node.left != null) q.offer(node.left); + if (node.right != null) q.offer(node.right); + } + if (res.size() % 2 != 0) Collections.reverse(level); + res.add(level); + } + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector> zigzagLevelOrder(TreeNode* root) { + vector> res; + if (!root) return res; + + queue q; + q.push(root); + + while (!q.empty()) { + vector level; + for (int i = q.size(); i > 0; i--) { + TreeNode* node = q.front(); + q.pop(); + level.push_back(node->val); + if (node->left) q.push(node->left); + if (node->right) q.push(node->right); + } + if (res.size() % 2) reverse(level.begin(), level.end()); + res.push_back(level); + } + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[][]} + */ + zigzagLevelOrder(root) { + const res = []; + if (!root) return res; + + const queue = new Queue([root]); + + while (!queue.isEmpty()) { + const level = []; + for (let i = queue.size(); i > 0; i--) { + const node = queue.pop(); + level.push(node.val); + if (node.left) queue.push(node.left); + if (node.right) queue.push(node.right); + } + if (res.length % 2 !== 0) level.reverse(); + res.push(level); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Breadth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def zigzagLevelOrder(self, root: Optional[TreeNode]) -> List[List[int]]: + res = [] + q = deque([root] if root else []) + while q: + size = len(q) + level = [0] * size + for i in range(size): + node = q.popleft() + idx = size - i - 1 if len(res) % 2 else i + level[idx] = node.val + if node.left: + q.append(node.left) + if node.right: + q.append(node.right) + res.append(level) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List> zigzagLevelOrder(TreeNode root) { + List> res = new ArrayList<>(); + if (root == null) return res; + + Queue q = new LinkedList<>(); + q.offer(root); + + while (!q.isEmpty()) { + int size = q.size(); + Integer[] level = new Integer[size]; + for (int i = 0; i < size; i++) { + TreeNode node = q.poll(); + int idx = (res.size() % 2 == 0) ? i : size - i - 1; + level[idx] = node.val; + if (node.left != null) q.offer(node.left); + if (node.right != null) q.offer(node.right); + } + res.add(Arrays.asList(level)); + } + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector> zigzagLevelOrder(TreeNode* root) { + vector> res; + if (!root) return res; + + queue q; + q.push(root); + + while (!q.empty()) { + int size = q.size(); + vector level(size); + for (int i = 0; i < size; ++i) { + TreeNode* node = q.front(); + q.pop(); + int idx = (res.size() % 2 == 0) ? i : size - i - 1; + level[idx] = node->val; + if (node->left) q.push(node->left); + if (node->right) q.push(node->right); + } + res.push_back(level); + } + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[][]} + */ + zigzagLevelOrder(root) { + const res = []; + if (!root) return res; + + const q = new Queue([root]); + + while (!q.isEmpty()) { + const size = q.size(); + const level = Array(size).fill(0); + + for (let i = 0; i < size; i++) { + const node = q.pop(); + const idx = res.length % 2 === 0 ? i : size - i - 1; + level[idx] = node.val; + if (node.left) q.push(node.left); + if (node.right) q.push(node.right); + } + res.push(level); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def zigzagLevelOrder(self, root: Optional[TreeNode]) -> List[List[int]]: + res = [] + + def dfs(node, depth): + if not node: + return + if depth == len(res): + res.append([]) + res[depth].append(node.val) + dfs(node.left, depth + 1) + dfs(node.right, depth + 1) + + dfs(root, 0) + for i, level in enumerate(res): + if i & 1: + level.reverse() + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List> zigzagLevelOrder(TreeNode root) { + List> res = new ArrayList<>(); + dfs(root, 0, res); + for (int i = 0; i < res.size(); i++) { + if ((i & 1) == 1) { + Collections.reverse(res.get(i)); + } + } + return res; + } + + private void dfs(TreeNode node, int depth, List> res) { + if (node == null) return; + if (depth == res.size()) { + res.add(new ArrayList<>()); + } + res.get(depth).add(node.val); + dfs(node.left, depth + 1, res); + dfs(node.right, depth + 1, res); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector> zigzagLevelOrder(TreeNode* root) { + vector> res; + dfs(root, 0, res); + for (int i = 0; i < res.size(); ++i) { + if (i & 1) { + reverse(res[i].begin(), res[i].end()); + } + } + return res; + } + +private: + void dfs(TreeNode* node, int depth, vector>& res) { + if (!node) return; + if (depth == res.size()) { + res.push_back({}); + } + res[depth].push_back(node->val); + dfs(node->left, depth + 1, res); + dfs(node->right, depth + 1, res); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[][]} + */ + zigzagLevelOrder(root) { + const res = []; + const dfs = (node, depth) => { + if (!node) return; + if (depth === res.length) res.push([]); + res[depth].push(node.val); + dfs(node.left, depth + 1); + dfs(node.right, depth + 1); + }; + + dfs(root, 0); + for (let i = 0; i < res.length; i++) { + if (i % 2 === 1) res[i].reverse(); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def zigzagLevelOrder(self, root: Optional[TreeNode]) -> List[List[int]]: + if not root: + return [] + + res = [] + stack = [(root, 0)] + + while stack: + node, depth = stack.pop() + if depth == len(res): + res.append([]) + + res[depth].append(node.val) + + if node.right: + stack.append((node.right, depth + 1)) + if node.left: + stack.append((node.left, depth + 1)) + + for i in range(len(res)): + if i % 2 == 1: + res[i].reverse() + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List> zigzagLevelOrder(TreeNode root) { + if (root == null) return new ArrayList<>(); + + List> res = new ArrayList<>(); + Stack stack = new Stack<>(); + stack.push(new Pair(root, 0)); + + while (!stack.isEmpty()) { + Pair current = stack.pop(); + TreeNode node = current.getKey(); + int depth = current.getValue(); + + if (depth == res.size()) { + res.add(new ArrayList<>()); + } + res.get(depth).add(node.val); + + if (node.right != null) stack.push(new Pair<>(node.right, depth + 1)); + if (node.left != null) stack.push(new Pair<>(node.left, depth + 1)); + } + + for (int i = 0; i < res.size(); i++) { + if (i % 2 == 1) { + Collections.reverse(res.get(i)); + } + } + + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector> zigzagLevelOrder(TreeNode* root) { + if (!root) return {}; + + vector> res; + stack> s; + s.push({root, 0}); + + while (!s.empty()) { + auto [node, depth] = s.top(); + s.pop(); + + if (depth == res.size()) { + res.push_back({}); + } + res[depth].push_back(node->val); + + if (node->right) s.push({node->right, depth + 1}); + if (node->left) s.push({node->left, depth + 1}); + } + + for (int i = 0; i < res.size(); i++) { + if (i % 2 == 1) { + reverse(res[i].begin(), res[i].end()); + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[][]} + */ + zigzagLevelOrder(root) { + if (!root) return []; + + const res = []; + const stack = [[root, 0]]; + + while (stack.length) { + const [node, depth] = stack.pop(); + + if (depth === res.length) res.push([]); + res[depth].push(node.val); + + if (node.right) stack.push([node.right, depth + 1]); + if (node.left) stack.push([node.left, depth + 1]); + } + + for (let i = 0; i < res.length; i++) { + if (i % 2 === 1) res[i].reverse(); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/bitwise-and-of-numbers-range.md b/articles/bitwise-and-of-numbers-range.md index 6c5ab4521..95b3e306d 100644 --- a/articles/bitwise-and-of-numbers-range.md +++ b/articles/bitwise-and-of-numbers-range.md @@ -53,12 +53,24 @@ class Solution { } ``` +```csharp +public class Solution { + public int RangeBitwiseAnd(int left, int right) { + int res = left; + for (int i = left + 1; i <= right; i++) { + res &= i; + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -143,6 +155,25 @@ class Solution { const next = Math.pow(2, i + 1); const remain = left % next; const diff = next - remain; + if (right - left < diff) { + res |= 1 << i; + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public int RangeBitwiseAnd(int left, int right) { + int res = 0; + for (int i = 0; i < 32; i++) { + int bit = (left >> i) & 1; + if (bit == 0) continue; + + int remain = left % (1 << (i + 1)); + int diff = (1 << (i + 1)) - remain; if (right - left < diff) { res |= (1 << i); } @@ -156,8 +187,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(1)$ since we iterate $32$ times. -* Space complexity: $O(1)$ +- Time complexity: $O(1)$ since we iterate $32$ times. +- Space complexity: $O(1)$ --- @@ -224,12 +255,26 @@ class Solution { } ``` +```csharp +public class Solution { + public int RangeBitwiseAnd(int left, int right) { + int i = 0; + while (left != right) { + left >>= 1; + right >>= 1; + i++; + } + return left << i; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ --- @@ -276,6 +321,17 @@ class Solution { * @return {number} */ rangeBitwiseAnd(left, right) { + while (left < right) { + right &= right - 1; + } + return right; + } +} +``` + +```csharp +public class Solution { + public int RangeBitwiseAnd(int left, int right) { while (left < right) { right &= (right - 1); } @@ -288,5 +344,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ diff --git a/articles/boats-to-save-people.md b/articles/boats-to-save-people.md index 8abd6a9a7..0ec01c654 100644 --- a/articles/boats-to-save-people.md +++ b/articles/boats-to-save-people.md @@ -60,7 +60,9 @@ class Solution { */ numRescueBoats(people, limit) { people.sort((a, b) => a - b); - let res = 0, l = 0, r = people.length - 1; + let res = 0, + l = 0, + r = people.length - 1; while (l <= r) { let remain = limit - people[r--]; res++; @@ -73,12 +75,33 @@ class Solution { } ``` +```csharp +public class Solution { + public int NumRescueBoats(int[] people, int limit) { + Array.Sort(people); + int res = 0, l = 0, r = people.Length - 1; + + while (l <= r) { + int remain = limit - people[r]; + r--; + res++; + + if (l <= r && remain >= people[l]) { + l++; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -93,7 +116,7 @@ class Solution: count = [0] * (m + 1) for p in people: count[p] += 1 - + idx, i = 0, 1 while idx < len(people): while count[i] == 0: @@ -120,7 +143,7 @@ public class Solution { for (int p : people) { count[p]++; } - + int idx = 0, i = 1; while (idx < people.length) { while (count[i] == 0) { @@ -129,7 +152,7 @@ public class Solution { people[idx++] = i; count[i]--; } - + int res = 0, l = 0, r = people.length - 1; while (l <= r) { int remain = limit - people[r--]; @@ -152,7 +175,7 @@ public: for (int p : people) { count[p]++; } - + int idx = 0, i = 1; while (idx < people.size()) { while (count[i] == 0) { @@ -161,7 +184,7 @@ public: people[idx++] = i; count[i]--; } - + int res = 0, l = 0, r = people.size() - 1; while (l <= r) { int remain = limit - people[r--]; @@ -188,8 +211,9 @@ class Solution { for (const p of people) { count[p]++; } - - let idx = 0, i = 1; + + let idx = 0, + i = 1; while (idx < people.length) { while (count[i] === 0) { i++; @@ -197,8 +221,10 @@ class Solution { people[idx++] = i; count[i]--; } - - let res = 0, l = 0, r = people.length - 1; + + let res = 0, + l = 0, + r = people.length - 1; while (l <= r) { const remain = limit - people[r--]; res++; @@ -211,11 +237,49 @@ class Solution { } ``` +```csharp +public class Solution { + public int NumRescueBoats(int[] people, int limit) { + int m = 0; + foreach (int p in people) { + m = Math.Max(m, p); + } + + int[] count = new int[m + 1]; + foreach (int p in people) { + count[p]++; + } + + int idx = 0, iVal = 1; + while (idx < people.Length) { + while (count[iVal] == 0) { + iVal++; + } + people[idx] = iVal; + count[iVal]--; + idx++; + } + + int res = 0, l = 0, r = people.Length - 1; + while (l <= r) { + int remain = limit - people[r]; + r--; + res++; + if (l <= r && remain >= people[l]) { + l++; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n)$ +- Space complexity: $O(m)$ -> Where $n$ is the size of the input array and $m$ is the maximum value in the array. \ No newline at end of file +> Where $n$ is the size of the input array and $m$ is the maximum value in the array. diff --git a/articles/brick-wall.md b/articles/brick-wall.md index 991f98ce3..c0c470210 100644 --- a/articles/brick-wall.md +++ b/articles/brick-wall.md @@ -16,14 +16,14 @@ class Solution: for brick in wall[i]: gap += brick gaps[i].append(gap) - + res = n for line in range(1, m): cuts = 0 for i in range(n): if line not in gaps[i]: cuts += 1 - + res = min(res, cuts) return res ``` @@ -140,8 +140,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n * g)$ -* Space complexity: $O(n * g)$ +- Time complexity: $O(m * n * g)$ +- Space complexity: $O(n * g)$ > Where $m$ is the sum of widths of the bricks in the first row, $n$ is the number of rows and $g$ is the average number of gaps in each row. @@ -239,7 +239,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(N)$ -* Space complexity: $O(g)$ +- Time complexity: $O(N)$ +- Space complexity: $O(g)$ -> Where $N$ is the total number of bricks in the wall and $g$ is the total number of gaps in all the rows. \ No newline at end of file +> Where $N$ is the total number of bricks in the wall and $g$ is the total number of gaps in all the rows. diff --git a/articles/build-a-matrix-with-conditions.md b/articles/build-a-matrix-with-conditions.md index 8a4d3f610..319bca3c3 100644 --- a/articles/build-a-matrix-with-conditions.md +++ b/articles/build-a-matrix-with-conditions.md @@ -23,7 +23,7 @@ class Solution: adj = defaultdict(list) for src, dst in edges: adj[src].append(dst) - + visit, path = set(), set() order = [] for src in range(1, k + 1): @@ -34,17 +34,17 @@ class Solution: row_order = topo_sort(rowConditions) if not row_order: return [] - + col_order = topo_sort(colConditions) if not col_order: return [] - + val_to_row = {num: i for i, num in enumerate(row_order)} val_to_col = {num: i for i, num in enumerate(col_order)} res = [[0] * k for _ in range(k)] for num in range(1, k + 1): r, c = val_to_row[num], val_to_col[num] res[r][c] = num - + return res ``` @@ -270,14 +270,95 @@ class Solution { } ``` +```csharp +public class Solution { + private HashSet visit; + private HashSet path; + private List order; + + public int[][] BuildMatrix(int k, int[][] rowConditions, int[][] colConditions) { + int[] rowOrder = TopoSort(k, rowConditions); + if (rowOrder == null) return new int[0][]; + + int[] colOrder = TopoSort(k, colConditions); + if (colOrder == null) return new int[0][]; + + Dictionary valToRow = new Dictionary(); + for (int i = 0; i < rowOrder.Length; i++) { + valToRow[rowOrder[i]] = i; + } + + Dictionary valToCol = new Dictionary(); + for (int i = 0; i < colOrder.Length; i++) { + valToCol[colOrder[i]] = i; + } + + int[][] res = new int[k][]; + for (int i = 0; i < k; i++) { + res[i] = new int[k]; + } + + for (int num = 1; num <= k; num++) { + int r = valToRow[num]; + int c = valToCol[num]; + res[r][c] = num; + } + + return res; + } + + private int[] TopoSort(int k, int[][] edges) { + Dictionary> adj = new Dictionary>(); + for (int i = 1; i <= k; i++) { + adj[i] = new List(); + } + + foreach (var edge in edges) { + adj[edge[0]].Add(edge[1]); + } + + visit = new HashSet(); + path = new HashSet(); + order = new List(); + + for (int i = 1; i <= k; i++) { + if (!visit.Contains(i)) { + if (!DFS(i, adj)) { + return null; + } + } + } + + order.Reverse(); + return order.ToArray(); + } + + private bool DFS(int src, Dictionary> adj) { + if (path.Contains(src)) return false; + if (visit.Contains(src)) return true; + + visit.Add(src); + path.Add(src); + foreach (int nei in adj[src]) { + if (!DFS(nei, adj)) { + return false; + } + } + path.Remove(src); + order.Add(src); + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(k ^ 2 + n + m)$ -* Space complexity: - * $O(k + n + m)$ extra space. - * $O(k ^ 2)$ space for the output matrix. +- Time complexity: $O(k ^ 2 + n + m)$ +- Space complexity: + - $O(k + n + m)$ extra space. + - $O(k ^ 2)$ space for the output matrix. > Where $n$ is the size of the array $rowConditions$, $m$ is the size of the array $colConditions$, and $k$ is the size of the output matrix. @@ -296,13 +377,13 @@ class Solution: for u, v in edges: adj[u].append(v) indegree[v] += 1 - + order = [] q = deque() for i in range(1, k + 1): if not indegree[i]: q.append(i) - + while q: node = q.popleft() order.append(node) @@ -310,20 +391,20 @@ class Solution: indegree[nei] -= 1 if not indegree[nei]: q.append(nei) - + return order row_order = topo_sort(rowConditions) if len(row_order) != k: return [] - + col_order = topo_sort(colConditions) if len(col_order) != k: return [] - + res = [[0] * k for _ in range(k)] colIndex = [0] * (k + 1) for i in range(k): colIndex[col_order[i]] = i - + for i in range(k): res[i][colIndex[row_order[i]]] = row_order[i] return res @@ -382,7 +463,7 @@ public class Solution { } } } - + if (idx != k) return new int[0]; return order; } @@ -489,7 +570,7 @@ class Solution { indegree[v]++; } - const queue = []; + const queue = new Queue(); const order = []; for (let i = 1; i <= k; i++) { @@ -498,8 +579,8 @@ class Solution { } } - while (queue.length) { - const node = queue.shift(); + while (!queue.isEmpty()) { + const node = queue.pop(); order.push(node); for (const nei of adj[node]) { indegree[nei]--; @@ -514,13 +595,75 @@ class Solution { } ``` +```csharp +public class Solution { + public int[][] BuildMatrix(int k, int[][] rowConditions, int[][] colConditions) { + int[] rowOrder = TopoSort(k, rowConditions); + if (rowOrder.Length != k) return new int[0][]; + + int[] colOrder = TopoSort(k, colConditions); + if (colOrder.Length != k) return new int[0][]; + + int[][] res = new int[k][]; + for (int i = 0; i < k; i++) res[i] = new int[k]; + + int[] colIndex = new int[k + 1]; + for (int i = 0; i < k; i++) { + colIndex[colOrder[i]] = i; + } + + for (int i = 0; i < k; i++) { + res[i][colIndex[rowOrder[i]]] = rowOrder[i]; + } + + return res; + } + + private int[] TopoSort(int k, int[][] edges) { + int[] indegree = new int[k + 1]; + List> adj = new List>(); + for (int i = 0; i <= k; i++) { + adj.Add(new List()); + } + + foreach (var edge in edges) { + adj[edge[0]].Add(edge[1]); + indegree[edge[1]]++; + } + + Queue queue = new Queue(); + int[] order = new int[k]; + int idx = 0; + for (int i = 1; i <= k; i++) { + if (indegree[i] == 0) { + queue.Enqueue(i); + } + } + + while (queue.Count > 0) { + int node = queue.Dequeue(); + order[idx++] = node; + foreach (var nei in adj[node]) { + indegree[nei]--; + if (indegree[nei] == 0) { + queue.Enqueue(nei); + } + } + } + + if (idx != k) return new int[0]; + return order; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(k ^ 2 + n + m)$ -* Space complexity: - * $O(k + n + m)$ extra space. - * $O(k ^ 2)$ space for the output matrix. +- Time complexity: $O(k ^ 2 + n + m)$ +- Space complexity: + - $O(k + n + m)$ extra space. + - $O(k ^ 2)$ space for the output matrix. -> Where $n$ is the size of the array $rowConditions$, $m$ is the size of the array $colConditions$, and $k$ is the size of the output matrix. \ No newline at end of file +> Where $n$ is the size of the array $rowConditions$, $m$ is the size of the array $colConditions$, and $k$ is the size of the output matrix. diff --git a/articles/buildings-with-an-ocean-view.md b/articles/buildings-with-an-ocean-view.md new file mode 100644 index 000000000..91e816ec0 --- /dev/null +++ b/articles/buildings-with-an-ocean-view.md @@ -0,0 +1,342 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def findBuildings(self, heights: List[int]) -> List[int]: + n = len(heights) + res = [] + + for i in range(n): + flag = True + for j in range(i + 1, n): + if heights[i] <= heights[j]: + flag = False + break + if flag: + res.append(i) + + return res +``` + +```java +public class Solution { + public int[] findBuildings(int[] heights) { + int n = heights.length; + List temp = new ArrayList<>(); + + for (int i = 0; i < n; i++) { + boolean flag = true; + for (int j = i + 1; j < n; j++) { + if (heights[i] <= heights[j]) { + flag = false; + break; + } + } + if (flag) temp.add(i); + } + + int[] res = new int[temp.size()]; + for (int i = 0; i < temp.size(); i++) { + res[i] = temp.get(i); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findBuildings(vector& heights) { + int n = heights.size(); + vector res; + + for (int i = 0; i < n; i++) { + bool flag = true; + for (int j = i + 1; j < n; j++) { + if (heights[i] <= heights[j]) { + flag = false; + break; + } + } + if (flag) res.push_back(i); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @return {number[]} + */ + findBuildings(heights) { + const n = heights.length; + const res = []; + + for (let i = 0; i < n; i++) { + let flag = true; + for (let j = i + 1; j < n; j++) { + if (heights[i] <= heights[j]) { + flag = false; + break; + } + } + if (flag) res.push(i); + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int[] FindBuildings(int[] heights) { + int n = heights.Length; + List temp = new List(); + + for (int i = 0; i < n; i++) { + bool flag = true; + for (int j = i + 1; j < n; j++) { + if (heights[i] <= heights[j]) { + flag = false; + break; + } + } + if (flag) temp.Add(i); + } + + return temp.ToArray(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ for the output array. + +--- + +## 2. Monotonic Stack + +::tabs-start + +```python +class Solution: + def findBuildings(self, heights: List[int]) -> List[int]: + stack = [] + + for i, h in enumerate(heights): + while stack and heights[stack[-1]] <= h: + stack.pop() + stack.append(i) + + return stack +``` + +```java +public class Solution { + public int[] findBuildings(int[] heights) { + int n = heights.length; + Stack stack = new Stack<>(); + + for (int i = 0; i < n; i++) { + while (!stack.isEmpty() && heights[stack.peek()] <= heights[i]) { + stack.pop(); + } + stack.push(i); + } + + int[] res = new int[stack.size()]; + for (int i = stack.size() - 1; i >= 0; i--) { + res[i] = stack.get(i); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findBuildings(vector& heights) { + vector stack; + + for (int i = 0; i < heights.size(); i++) { + while (!stack.empty() && heights[stack.back()] <= heights[i]) { + stack.pop_back(); + } + stack.push_back(i); + } + + return stack; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @return {number[]} + */ + findBuildings(heights) { + const stack = []; + + for (let i = 0; i < heights.length; i++) { + while ( + stack.length && + heights[stack[stack.length - 1]] <= heights[i] + ) { + stack.pop(); + } + stack.push(i); + } + + return stack; + } +} +``` + +```csharp +public class Solution { + public int[] FindBuildings(int[] heights) { + List stack = new List(); + + for (int i = 0; i < heights.Length; i++) { + while (stack.Count > 0 && heights[stack[stack.Count - 1]] <= heights[i]) { + stack.RemoveAt(stack.Count - 1); + } + stack.Add(i); + } + + return stack.ToArray(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Greedy + +::tabs-start + +```python +class Solution: + def findBuildings(self, heights: List[int]) -> List[int]: + res = [len(heights) - 1] + for i in range(len(heights) - 2, -1, -1): + if heights[i] > heights[res[-1]]: + res.append(i) + res.reverse() + return res +``` + +```java +public class Solution { + public int[] findBuildings(int[] heights) { + List res = new ArrayList<>(); + int n = heights.length; + res.add(n - 1); + + for (int i = n - 2; i >= 0; i--) { + if (heights[i] > heights[res.get(res.size() - 1)]) { + res.add(i); + } + } + + Collections.reverse(res); + int[] ans = new int[res.size()]; + for (int i = 0; i < res.size(); i++) { + ans[i] = res.get(i); + } + + return ans; + } +} +``` + +```cpp +class Solution { +public: + vector findBuildings(vector& heights) { + vector res; + int n = heights.size(); + res.push_back(n - 1); + + for (int i = n - 2; i >= 0; i--) { + if (heights[i] > heights[res.back()]) { + res.push_back(i); + } + } + + reverse(res.begin(), res.end()); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @return {number[]} + */ + findBuildings(heights) { + const n = heights.length; + const res = [n - 1]; + + for (let i = n - 2; i >= 0; i--) { + if (heights[i] > heights[res[res.length - 1]]) { + res.push(i); + } + } + + return res.reverse(); + } +} +``` + +```csharp +public class Solution { + public int[] FindBuildings(int[] heights) { + int n = heights.Length; + List res = new List { n - 1 }; + + for (int i = n - 2; i >= 0; i--) { + if (heights[i] > heights[res[res.Count - 1]]) { + res.Add(i); + } + } + + res.Reverse(); + return res.ToArray(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ for the output array. diff --git a/articles/burst-balloons.md b/articles/burst-balloons.md index 3febbdd81..3c74cbfab 100644 --- a/articles/burst-balloons.md +++ b/articles/burst-balloons.md @@ -177,7 +177,7 @@ class Solution { var maxCoins = 0 for (i in 1 until nums.size - 1) { val coins = nums[i - 1] * nums[i] * nums[i + 1] - val nextCoins = dfs(nums.take(i).toIntArray() + + val nextCoins = dfs(nums.take(i).toIntArray() + nums.drop(i + 1).toIntArray()) maxCoins = maxOf(maxCoins, coins + nextCoins) } @@ -189,12 +189,36 @@ class Solution { } ``` +```swift +class Solution { + func maxCoins(_ nums: [Int]) -> Int { + var nums = [1] + nums + [1] + + func dfs(_ nums: [Int]) -> Int { + if nums.count == 2 { + return 0 + } + + var maxCoins = 0 + for i in 1..<(nums.count - 1) { + let coins = nums[i - 1] * nums[i] * nums[i + 1] + + dfs(Array(nums[.. Int { + var nums = [1] + nums + [1] + let n = nums.count + var dp = Array(repeating: Array(repeating: -1, count: n), count: n) + + func dfs(_ l: Int, _ r: Int) -> Int { + if l > r { + return 0 + } + if dp[l][r] != -1 { + return dp[l][r] + } + + dp[l][r] = 0 + for i in l...r { + let coins = nums[l - 1] * nums[i] * nums[r + 1] + dfs(l, i - 1) + dfs(i + 1, r) + dp[l][r] = max(dp[l][r], coins) + } + return dp[l][r] + } + + return dfs(1, n - 2) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n ^ 2)$ --- @@ -621,9 +674,32 @@ class Solution { } ``` +```swift +class Solution { + func maxCoins(_ nums: [Int]) -> Int { + let n = nums.count + var newNums = [1] + nums + [1] + + var dp = Array(repeating: Array(repeating: 0, count: n + 2), count: n + 2) + + for l in stride(from: n, through: 1, by: -1) { + for r in l...n { + for i in l...r { + let coins = (newNums[l - 1] * newNums[i] * newNums[r + 1]) + + dp[l][i - 1] + dp[i + 1][r] + dp[l][r] = max(dp[l][r], coins) + } + } + } + + return dp[1][n] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n^3)$ -* Space complexity: $O(n^2)$ \ No newline at end of file +- Time complexity: $O(n^3)$ +- Space complexity: $O(n^2)$ diff --git a/articles/buy-and-sell-crypto-with-cooldown.md b/articles/buy-and-sell-crypto-with-cooldown.md index 366028454..6dcebbcd8 100644 --- a/articles/buy-and-sell-crypto-with-cooldown.md +++ b/articles/buy-and-sell-crypto-with-cooldown.md @@ -5,11 +5,11 @@ ```python class Solution: def maxProfit(self, prices: List[int]) -> int: - + def dfs(i, buying): if i >= len(prices): return 0 - + cooldown = dfs(i + 1, buying) if buying: buy = dfs(i + 1, not buying) - prices[i] @@ -17,17 +17,17 @@ class Solution: else: sell = dfs(i + 2, not buying) + prices[i] return max(sell, cooldown) - + return dfs(0, True) ``` ```java public class Solution { public int maxProfit(int[] prices) { - + return dfs(0, true, prices); } - + private int dfs(int i, boolean buying, int[] prices) { if (i >= prices.length) { return 0; @@ -51,7 +51,7 @@ public: int maxProfit(vector& prices) { return dfs(0, true, prices); } - + private: int dfs(int i, bool buying, vector& prices) { if (i >= prices.size()) { @@ -77,7 +77,6 @@ class Solution { * @return {number} */ maxProfit(prices) { - const dfs = (i, buying) => { if (i >= prices.length) { return 0; @@ -91,8 +90,8 @@ class Solution { let sell = dfs(i + 2, true) + prices[i]; return Math.max(sell, cooldown); } - } - + }; + return dfs(0, true); } } @@ -128,7 +127,7 @@ func maxProfit(prices []int) int { if i >= len(prices) { return 0 } - + cooldown := dfs(i + 1, buying) if buying { buy := dfs(i + 1, false) - prices[i] @@ -155,7 +154,7 @@ class Solution { fun maxProfit(prices: IntArray): Int { fun dfs(i: Int, buying: Boolean): Int { if (i >= prices.size) return 0 - + val cooldown = dfs(i + 1, buying) return if (buying) { val buy = dfs(i + 1, false) - prices[i] @@ -165,7 +164,32 @@ class Solution { maxOf(sell, cooldown) } } - + + return dfs(0, true) + } +} +``` + +```swift +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + let n = prices.count + + func dfs(_ i: Int, _ buying: Bool) -> Int { + if i >= n { + return 0 + } + + let cooldown = dfs(i + 1, buying) + if buying { + let buy = dfs(i + 1, false) - prices[i] + return max(buy, cooldown) + } else { + let sell = dfs(i + 2, true) + prices[i] + return max(sell, cooldown) + } + } + return dfs(0, true) } } @@ -175,8 +199,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -210,16 +234,16 @@ class Solution: ```java public class Solution { private Map dp = new HashMap<>(); - + public int maxProfit(int[] prices) { return dfs(0, true, prices); } - + private int dfs(int i, boolean buying, int[] prices) { if (i >= prices.length) { return 0; } - + String key = i + "-" + buying; if (dp.containsKey(key)) { return dp.get(key); @@ -243,7 +267,7 @@ public class Solution { class Solution { public: unordered_map dp; - + int maxProfit(vector& prices) { return dfs(0, true, prices); } @@ -299,8 +323,8 @@ class Solution { dp[key] = Math.max(sell, cooldown); } return dp[key]; - } - + }; + return dfs(0, true); } } @@ -308,7 +332,7 @@ class Solution { ```csharp public class Solution { - private Dictionary<(int, bool), int> dp = + private Dictionary<(int, bool), int> dp = new Dictionary<(int, bool), int>(); public int MaxProfit(int[] prices) { @@ -412,12 +436,42 @@ class Solution { } ``` +```swift +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + let n = prices.count + var dp = [[Int?]](repeating: [Int?](repeating: nil, count: 2), count: n) + + func dfs(_ i: Int, _ buying: Int) -> Int { + if i >= n { + return 0 + } + if let cached = dp[i][buying] { + return cached + } + + let cooldown = dfs(i + 1, buying) + if buying == 1 { + let buy = dfs(i + 1, 0) - prices[i] + dp[i][buying] = max(buy, cooldown) + } else { + let sell = dfs(i + 2, 1) + prices[i] + dp[i][buying] = max(sell, cooldown) + } + return dp[i][buying]! + } + + return dfs(0, 1) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -429,7 +483,7 @@ class Solution { class Solution: def maxProfit(self, prices: List[int]) -> int: n = len(prices) - dp = [[0] * 2 for _ in range(n + 1)] + dp = [[0] * 2 for _ in range(n + 1)] for i in range(n - 1, -1, -1): for buying in [True, False]: @@ -449,7 +503,7 @@ class Solution: public class Solution { public int maxProfit(int[] prices) { int n = prices.length; - int[][] dp = new int[n + 1][2]; + int[][] dp = new int[n + 1][2]; for (int i = n - 1; i >= 0; i--) { for (int buying = 1; buying >= 0; buying--) { @@ -475,7 +529,7 @@ class Solution { public: int maxProfit(vector& prices) { int n = prices.size(); - vector> dp(n + 1, vector(2, 0)); + vector> dp(n + 1, vector(2, 0)); for (int i = n - 1; i >= 0; --i) { for (int buying = 1; buying >= 0; --buying) { @@ -504,7 +558,7 @@ class Solution { */ maxProfit(prices) { const n = prices.length; - const dp = Array.from({ length: n + 1 }, () => [0, 0]); + const dp = Array.from({ length: n + 1 }, () => [0, 0]); for (let i = n - 1; i >= 0; i--) { for (let buying = 1; buying >= 0; buying--) { @@ -513,7 +567,7 @@ class Solution { let cooldown = dp[i + 1][1]; dp[i][1] = Math.max(buy, cooldown); } else { - let sell = (i + 2 < n) ? dp[i + 2][1] + prices[i] : prices[i]; + let sell = i + 2 < n ? dp[i + 2][1] + prices[i] : prices[i]; let cooldown = dp[i + 1][0]; dp[i][0] = Math.max(sell, cooldown); } @@ -529,7 +583,7 @@ class Solution { public class Solution { public int MaxProfit(int[] prices) { int n = prices.Length; - int[,] dp = new int[n + 1, 2]; + int[,] dp = new int[n + 1, 2]; for (int i = n - 1; i >= 0; i--) { for (int buying = 1; buying >= 0; buying--) { @@ -611,12 +665,37 @@ class Solution { } ``` +```swift +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + let n = prices.count + var dp = Array(repeating: [0, 0], count: n + 1) + + for i in stride(from: n - 1, through: 0, by: -1) { + for buying in 0...1 { + if buying == 1 { + let buy = (i + 1 < n ? dp[i + 1][0] - prices[i] : -prices[i]) + let cooldown = (i + 1 < n ? dp[i + 1][1] : 0) + dp[i][1] = max(buy, cooldown) + } else { + let sell = (i + 2 < n ? dp[i + 2][1] + prices[i] : prices[i]) + let cooldown = (i + 1 < n ? dp[i + 1][0] : 0) + dp[i][0] = max(sell, cooldown) + } + } + } + + return dp[0][1] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -628,7 +707,7 @@ class Solution { class Solution: def maxProfit(self, prices: List[int]) -> int: n = len(prices) - dp1_buy, dp1_sell = 0, 0 + dp1_buy, dp1_sell = 0, 0 dp2_buy = 0 for i in range(n - 1, -1, -1): @@ -689,7 +768,8 @@ class Solution { */ maxProfit(prices) { const n = prices.length; - let dp1_buy = 0, dp1_sell = 0; + let dp1_buy = 0, + dp1_sell = 0; let dp2_buy = 0; for (let i = n - 1; i >= 0; i--) { @@ -769,9 +849,29 @@ class Solution { } ``` +```swift +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + let n = prices.count + var dp1Buy = 0, dp1Sell = 0 + var dp2Buy = 0 + + for i in stride(from: n - 1, through: 0, by: -1) { + let dpBuy = max(dp1Sell - prices[i], dp1Buy) + let dpSell = max(dp2Buy + prices[i], dp1Sell) + dp2Buy = dp1Buy + dp1Buy = dpBuy + dp1Sell = dpSell + } + + return dp1Buy + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/buy-and-sell-crypto.md b/articles/buy-and-sell-crypto.md index 0e618efd5..40e943308 100644 --- a/articles/buy-and-sell-crypto.md +++ b/articles/buy-and-sell-crypto.md @@ -120,12 +120,28 @@ class Solution { } ``` +```swift +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + var res = 0 + for i in 0.. Int { + var l = 0, r = 1 + var maxP = 0 + + while r < prices.count { + if prices[l] < prices[r] { + let profit = prices[r] - prices[l] + maxP = max(maxP, profit) + } else { + l = r + } + r += 1 + } + return maxP + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -397,9 +434,24 @@ class Solution { } ``` +```swift +class Solution { + func maxProfit(_ prices: [Int]) -> Int { + var maxP = 0 + var minBuy = prices[0] + + for sell in prices { + maxP = max(maxP, sell - minBuy) + minBuy = min(minBuy, sell) + } + return maxP + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/buy-two-chocolates.md b/articles/buy-two-chocolates.md index 0b6edc79d..35c721092 100644 --- a/articles/buy-two-chocolates.md +++ b/articles/buy-two-chocolates.md @@ -48,6 +48,11 @@ public: ```javascript class Solution { + /** + * @param {number[]} prices + * @param {number} money + * @return {number} + */ buyChoco(prices, money) { let res = -1; for (let i = 0; i < prices.length; i++) { @@ -62,12 +67,28 @@ class Solution { } ``` +```csharp +public class Solution { + public int BuyChoco(int[] prices, int money) { + int res = -1; + for (int i = 0; i < prices.Length; i++) { + for (int j = i + 1; j < prices.Length; j++) { + if (prices[i] + prices[j] <= money) { + res = Math.Max(res, money - prices[i] - prices[j]); + } + } + } + return res == -1 ? money : res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. --- @@ -106,6 +127,11 @@ public: ```javascript class Solution { + /** + * @param {number[]} prices + * @param {number} money + * @return {number} + */ buyChoco(prices, money) { prices.sort((a, b) => a - b); let buy = prices[0] + prices[1]; @@ -114,12 +140,22 @@ class Solution { } ``` +```csharp +public class Solution { + public int BuyChoco(int[] prices, int money) { + Array.Sort(prices); + int buy = prices[0] + prices[1]; + return buy > money ? money : money - buy; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -137,7 +173,7 @@ class Solution: min1, min2 = p, min1 elif p < min2: min2 = p - + leftover = money - min1 - min2 return leftover if leftover >= 0 else money ``` @@ -185,8 +221,14 @@ public: ```javascript class Solution { + /** + * @param {number[]} prices + * @param {number} money + * @return {number} + */ buyChoco(prices, money) { - let min1 = Infinity, min2 = Infinity; + let min1 = Infinity, + min2 = Infinity; for (const p of prices) { if (p < min1) { @@ -203,9 +245,29 @@ class Solution { } ``` +```csharp +public class Solution { + public int BuyChoco(int[] prices, int money) { + int min1 = int.MaxValue, min2 = int.MaxValue; + + foreach (int p in prices) { + if (p < min1) { + min2 = min1; + min1 = p; + } else if (p < min2) { + min2 = p; + } + } + + int leftover = money - min1 - min2; + return leftover >= 0 ? leftover : money; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/calculate-money-in-leetcode-bank.md b/articles/calculate-money-in-leetcode-bank.md new file mode 100644 index 000000000..2e9b10133 --- /dev/null +++ b/articles/calculate-money-in-leetcode-bank.md @@ -0,0 +1,250 @@ +## 1. Simulation + +::tabs-start + +```python +class Solution: + def totalMoney(self, n: int) -> int: + day, deposit = 0, 1 + res = 0 + + while day < n: + res += deposit + deposit += 1 + day += 1 + + if day % 7 == 0: + deposit = 1 + day // 7 + + return res +``` + +```java +public class Solution { + public int totalMoney(int n) { + int day = 0, deposit = 1, res = 0; + + while (day < n) { + res += deposit; + deposit++; + day++; + + if (day % 7 == 0) { + deposit = 1 + day / 7; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int totalMoney(int n) { + int day = 0, deposit = 1, res = 0; + + while (day < n) { + res += deposit; + deposit++; + day++; + + if (day % 7 == 0) { + deposit = 1 + day / 7; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + totalMoney(n) { + let day = 0, + deposit = 1, + res = 0; + + while (day < n) { + res += deposit; + deposit++; + day++; + + if (day % 7 === 0) { + deposit = 1 + Math.floor(day / 7); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 2. Math + +::tabs-start + +```python +class Solution: + def totalMoney(self, n: int) -> int: + weeks = n // 7 + low = 28 + high = 28 + 7 * (weeks - 1) + res = weeks * (low + high) // 2 + + monday = weeks + 1 + for i in range(n % 7): + res += i + monday + + return res +``` + +```java +public class Solution { + public int totalMoney(int n) { + int weeks = n / 7; + int low = 28; + int high = 28 + 7 * (weeks - 1); + int res = weeks * (low + high) / 2; + + int monday = weeks + 1; + for (int i = 0; i < n % 7; i++) { + res += i + monday; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int totalMoney(int n) { + int weeks = n / 7; + int low = 28; + int high = 28 + 7 * (weeks - 1); + int res = weeks * (low + high) / 2; + + int monday = weeks + 1; + for (int i = 0; i < n % 7; i++) { + res += i + monday; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + totalMoney(n) { + const weeks = Math.floor(n / 7); + const low = 28; + const high = 28 + 7 * (weeks - 1); + let res = (weeks * (low + high)) / 2; + + const monday = weeks + 1; + for (let i = 0; i < n % 7; i++) { + res += i + monday; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +--- + +## 3. Math (Optimal) + +::tabs-start + +```python +class Solution: + def totalMoney(self, n: int) -> int: + SUM = lambda x: (x * (x + 1)) >> 1 + weeks = n // 7 + res = SUM(weeks - 1) * 7 + weeks * SUM(7) + res += SUM(n % 7) + weeks * (n % 7) + return res +``` + +```java +public class Solution { + public int totalMoney(int n) { + int weeks = n / 7; + int res = SUM(weeks - 1) * 7 + weeks * SUM(7); + res += SUM(n % 7) + weeks * (n % 7); + return res; + } + + private int SUM(int n) { + return (n * (n + 1)) / 2; + } +} +``` + +```cpp +class Solution { +public: + int totalMoney(int n) { + auto SUM = [](int x) { return (x * (x + 1)) / 2; }; + + int weeks = n / 7; + int res = SUM(weeks - 1) * 7 + weeks * SUM(7); + res += SUM(n % 7) + weeks * (n % 7); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + totalMoney(n) { + const SUM = (x) => (x * (x + 1)) / 2; + + const weeks = Math.floor(n / 7); + let res = SUM(weeks - 1) * 7 + weeks * SUM(7); + res += SUM(n % 7) + weeks * (n % 7); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ diff --git a/articles/can-place-flowers.md b/articles/can-place-flowers.md index 7ccaeba96..80aa4a5b7 100644 --- a/articles/can-place-flowers.md +++ b/articles/can-place-flowers.md @@ -6,23 +6,23 @@ class Solution: def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool: f = [0] + flowerbed + [0] - + for i in range(1, len(f) - 1): if f[i - 1] == 0 and f[i] == 0 and f[i + 1] == 0: f[i] = 1 n -= 1 - + return n <= 0 ``` ```java public class Solution { public boolean canPlaceFlowers(int[] flowerbed, int n) { - int[] f = new int[flowerbed.length + 2]; + int[] f = new int[flowerbed.length + 2]; for (int i = 0; i < flowerbed.length; i++) { f[i + 1] = flowerbed[i]; } - + for (int i = 1; i < f.length - 1; i++) { if (f[i - 1] == 0 && f[i] == 0 && f[i + 1] == 0) { f[i] = 1; @@ -42,7 +42,7 @@ public: for (int i = 0; i < flowerbed.size(); i++) { f[i + 1] = flowerbed[i]; } - + for (int i = 1; i < f.size() - 1; i++) { if (f[i - 1] == 0 && f[i] == 0 && f[i + 1] == 0) { f[i] = 1; @@ -63,7 +63,7 @@ class Solution { */ canPlaceFlowers(flowerbed, n) { const f = [0, ...flowerbed, 0]; - + for (let i = 1; i < f.length - 1; i++) { if (f[i - 1] === 0 && f[i] === 0 && f[i + 1] === 0) { f[i] = 1; @@ -79,8 +79,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -92,14 +92,14 @@ class Solution { class Solution: def canPlaceFlowers(self, flowerbed: List[int], n: int) -> bool: empty = 0 if flowerbed[0] else 1 - + for f in flowerbed: if f: n -= int((empty - 1) / 2) empty = 0 else: empty += 1 - + n -= empty // 2 return n <= 0 ``` @@ -108,7 +108,7 @@ class Solution: public class Solution { public boolean canPlaceFlowers(int[] flowerbed, int n) { int empty = flowerbed[0] == 0 ? 1 : 0; - + for (int f : flowerbed) { if (f == 1) { n -= (empty - 1) / 2; @@ -117,7 +117,7 @@ public class Solution { empty++; } } - + n -= empty / 2; return n <= 0; } @@ -129,7 +129,7 @@ class Solution { public: bool canPlaceFlowers(vector& flowerbed, int n) { int empty = flowerbed[0] == 0 ? 1 : 0; - + for (int f : flowerbed) { if (f == 1) { n -= (empty - 1) / 2; @@ -138,7 +138,7 @@ public: empty++; } } - + n -= empty / 2; return n <= 0; } @@ -154,7 +154,7 @@ class Solution { */ canPlaceFlowers(flowerbed, n) { let empty = flowerbed[0] === 0 ? 1 : 0; - + for (let f of flowerbed) { if (f === 1) { n -= Math.floor(Math.max(0, empty - 1) / 2); @@ -163,7 +163,7 @@ class Solution { empty++; } } - + n -= Math.floor(empty / 2); return n <= 0; } @@ -174,5 +174,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/candy.md b/articles/candy.md index adeba0a66..e7675e571 100644 --- a/articles/candy.md +++ b/articles/candy.md @@ -130,12 +130,48 @@ class Solution { } ``` +```csharp +public class Solution { + public int Candy(int[] ratings) { + int n = ratings.Length; + int[] arr = new int[n]; + Array.Fill(arr, 1); + + for (int i = 0; i < n - 1; i++) { + if (ratings[i] == ratings[i + 1]) { + continue; + } + if (ratings[i + 1] > ratings[i]) { + arr[i + 1] = arr[i] + 1; + } else if (arr[i] == arr[i + 1]) { + arr[i + 1] = arr[i]; + arr[i]++; + for (int j = i - 1; j >= 0; j--) { + if (ratings[j] > ratings[j + 1]) { + if (arr[j + 1] < arr[j]) break; + arr[j]++; + } else { + break; + } + } + } + } + + int total = 0; + foreach (int a in arr) { + total += a; + } + return total; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -152,11 +188,11 @@ class Solution: for i in range(1, n): if ratings[i - 1] < ratings[i]: arr[i] = arr[i - 1] + 1 - + for i in range(n - 2, -1, -1): if ratings[i] > ratings[i + 1]: arr[i] = max(arr[i], arr[i + 1] + 1) - + return sum(arr) ``` @@ -239,12 +275,40 @@ class Solution { } ``` +```csharp +public class Solution { + public int Candy(int[] ratings) { + int n = ratings.Length; + int[] arr = new int[n]; + Array.Fill(arr, 1); + + for (int i = 1; i < n; i++) { + if (ratings[i - 1] < ratings[i]) { + arr[i] = arr[i - 1] + 1; + } + } + + for (int i = n - 2; i >= 0; i--) { + if (ratings[i] > ratings[i + 1]) { + arr[i] = Math.Max(arr[i], arr[i + 1] + 1); + } + } + + int total = 0; + foreach (int a in arr) { + total += a; + } + return total; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -263,7 +327,7 @@ class Solution: if ratings[i] == ratings[i - 1]: i += 1 continue - + inc = 0 while i < n and ratings[i] > ratings[i - 1]: inc += 1 @@ -275,9 +339,9 @@ class Solution: dec += 1 res += dec i += 1 - + res -= min(inc, dec) - + return res ``` @@ -391,9 +455,44 @@ class Solution { } ``` +```csharp +public class Solution { + public int Candy(int[] ratings) { + int n = ratings.Length; + int res = n; + int i = 1; + + while (i < n) { + if (ratings[i] == ratings[i - 1]) { + i++; + continue; + } + + int inc = 0; + while (i < n && ratings[i] > ratings[i - 1]) { + inc++; + res += inc; + i++; + } + + int dec = 0; + while (i < n && ratings[i] < ratings[i - 1]) { + dec++; + res += dec; + i++; + } + + res -= Math.Min(inc, dec); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/capacity-to-ship-packages-within-d-days.md b/articles/capacity-to-ship-packages-within-d-days.md index 9a5d4e777..caf60abe3 100644 --- a/articles/capacity-to-ship-packages-within-d-days.md +++ b/articles/capacity-to-ship-packages-within-d-days.md @@ -80,7 +80,8 @@ class Solution { shipWithinDays(weights, days) { let res = Math.max(...weights); while (true) { - let ships = 1, cap = res; + let ships = 1, + cap = res; for (let w of weights) { if (cap - w < 0) { ships++; @@ -97,12 +98,35 @@ class Solution { } ``` +```csharp +public class Solution { + public int ShipWithinDays(int[] weights, int days) { + int res = weights.Max(); + while (true) { + int ships = 1; + int cap = res; + foreach (int w in weights) { + if (cap - w < 0) { + ships++; + cap = res; + } + cap -= w; + } + if (ships <= days) { + return res; + } + res++; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -229,7 +253,8 @@ class Solution { let res = r; const canShip = (cap) => { - let ships = 1, currCap = cap; + let ships = 1, + currCap = cap; for (const w of weights) { if (currCap - w < 0) { ships++; @@ -258,9 +283,47 @@ class Solution { } ``` +```csharp +public class Solution { + public int ShipWithinDays(int[] weights, int days) { + int l = weights.Max(); + int r = weights.Sum(); + int res = r; + + bool CanShip(int cap) { + int ships = 1; + int currCap = cap; + + foreach (int w in weights) { + if (currCap - w < 0) { + ships++; + if (ships > days) return false; + currCap = cap; + } + currCap -= w; + } + + return true; + } + + while (l <= r) { + int cap = (l + r) / 2; + if (CanShip(cap)) { + res = Math.Min(res, cap); + r = cap - 1; + } else { + l = cap + 1; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ diff --git a/articles/car-fleet.md b/articles/car-fleet.md index 2d4e2ef35..3f863baf7 100644 --- a/articles/car-fleet.md +++ b/articles/car-fleet.md @@ -27,8 +27,8 @@ public class Solution { Stack stack = new Stack<>(); for (int[] p : pair) { stack.push((double) (target - p[0]) / p[1]); - if (stack.size() >= 2 && - stack.peek() <= stack.get(stack.size() - 2)) + if (stack.size() >= 2 && + stack.peek() <= stack.get(stack.size() - 2)) { stack.pop(); } @@ -50,8 +50,8 @@ public: vector stack; for (auto& p : pair) { stack.push_back((double)(target - p.first) / p.second); - if (stack.size() >= 2 && - stack.back() <= stack[stack.size() - 2]) + if (stack.size() >= 2 && + stack.back() <= stack[stack.size() - 2]) { stack.pop_back(); } @@ -75,9 +75,10 @@ class Solution { let stack = []; for (let [p, s] of pair) { stack.push((target - p) / s); - if (stack.length >= 2 && - stack[stack.length - 1] <= stack[stack.length - 2]) - { + if ( + stack.length >= 2 && + stack[stack.length - 1] <= stack[stack.length - 2] + ) { stack.pop(); } } @@ -113,11 +114,11 @@ func carFleet(target int, position []int, speed []int) int { for i := 0; i < n; i++ { pair[i] = [2]int{position[i], speed[i]} } - + sort.Slice(pair, func(i, j int) bool { return pair[i][0] > pair[j][0] }) - + stack := []float64{} for _, p := range pair { time := float64(target - p[0]) / float64(p[1]) @@ -126,7 +127,7 @@ func carFleet(target int, position []int, speed []int) int { stack = stack[:len(stack)-1] } } - + return len(stack) } ``` @@ -150,12 +151,32 @@ class Solution { } ``` +```swift +class Solution { + func carFleet(_ target: Int, _ position: [Int], _ speed: [Int]) -> Int { + var pair = zip(position, speed).map { ($0, $1) } + pair.sort { $0.0 > $1.0 } // Sort in descending order by position + + var stack = [Double]() + + for (p, s) in pair { + stack.append(Double(target - p) / Double(s)) + if stack.count >= 2 && stack.last! <= stack[stack.count - 2] { + stack.removeLast() + } + } + + return stack.count + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -168,7 +189,7 @@ class Solution: def carFleet(self, target: int, position: List[int], speed: List[int]) -> int: pair = [(p, s) for p, s in zip(position, speed)] pair.sort(reverse=True) - + fleets = 1 prevTime = (target - pair[0][0]) / pair[0][1] for i in range(1, len(pair)): @@ -190,7 +211,7 @@ public class Solution { pair[i][1] = speed[i]; } Arrays.sort(pair, (a, b) -> Integer.compare(b[0], a[0])); - + int fleets = 1; double prevTime = (double)(target - pair[0][0]) / pair[0][1]; for (int i = 1; i < n; i++) { @@ -215,7 +236,7 @@ public: pair.push_back({position[i], speed[i]}); } sort(pair.rbegin(), pair.rend()); - + int fleets = 1; double prevTime = (double)(target - pair[0].first) / pair[0].second; for (int i = 1; i < n; i++) { @@ -241,7 +262,7 @@ class Solution { carFleet(target, position, speed) { let pair = position.map((p, i) => [p, speed[i]]); pair.sort((a, b) => b[0] - a[0]); - + let fleets = 1; let prevTime = (target - pair[0][0]) / pair[0][1]; for (let i = 1; i < pair.length; i++) { @@ -265,7 +286,7 @@ public class Solution { pair[i] = new int[] { position[i], speed[i] }; } Array.Sort(pair, (a, b) => b[0].CompareTo(a[0])); - + int fleets = 1; double prevTime = (double)(target - pair[0][0]) / pair[0][1]; for (int i = 1; i < n; i++) { @@ -287,11 +308,11 @@ func carFleet(target int, position []int, speed []int) int { for i := 0; i < n; i++ { pair[i] = [2]int{position[i], speed[i]} } - + sort.Slice(pair, func(i, j int) bool { return pair[i][0] > pair[j][0] }) - + fleets := 1 prevTime := float64(target - pair[0][0]) / float64(pair[0][1]) for i := 1; i < n; i++ { @@ -301,7 +322,7 @@ func carFleet(target int, position []int, speed []int) int { prevTime = currTime } } - + return fleets } ``` @@ -310,7 +331,7 @@ func carFleet(target int, position []int, speed []int) int { class Solution { fun carFleet(target: Int, position: IntArray, speed: IntArray): Int { val pair = position.zip(speed).sortedByDescending { it.first } - + var fleets = 1 var prevTime = (target - pair[0].first).toDouble() / pair[0].second for (i in 1 until pair.size) { @@ -321,7 +342,31 @@ class Solution { prevTime = currTime } } - + + return fleets + } +} +``` + +```swift +class Solution { + func carFleet(_ target: Int, _ position: [Int], _ speed: [Int]) -> Int { + var pair = zip(position, speed).map { ($0, $1) } + pair.sort { $0.0 > $1.0 } // Sort in descending order by position + + var fleets = 1 + var prevTime = Double(target - pair[0].0) / Double(pair[0].1) + + for i in 1.. prevTime { + fleets += 1 + prevTime = currTime + } + } + return fleets } } @@ -331,5 +376,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/car-pooling.md b/articles/car-pooling.md index 3eac0695d..c67ff6e99 100644 --- a/articles/car-pooling.md +++ b/articles/car-pooling.md @@ -92,12 +92,34 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CarPooling(int[][] trips, int capacity) { + Array.Sort(trips, (a, b) => a[1].CompareTo(b[1])); + + for (int i = 0; i < trips.Length; i++) { + int curPass = trips[i][0]; + for (int j = 0; j < i; j++) { + if (trips[j][2] > trips[i][1]) { + curPass += trips[j][0]; + } + } + if (curPass > capacity) { + return false; + } + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -109,20 +131,20 @@ class Solution { class Solution: def carPooling(self, trips: List[List[int]], capacity: int) -> bool: trips.sort(key=lambda t: t[1]) - + minHeap = [] # pair of [end, numPassengers] curPass = 0 - + for numPass, start, end in trips: while minHeap and minHeap[0][0] <= start: curPass -= heapq.heappop(minHeap)[1] - + curPass += numPass if curPass > capacity: return False - + heapq.heappush(minHeap, [end, numPass]) - + return True ``` @@ -130,25 +152,25 @@ class Solution: public class Solution { public boolean carPooling(int[][] trips, int capacity) { Arrays.sort(trips, Comparator.comparingInt(a -> a[1])); - + PriorityQueue minHeap = new PriorityQueue<>(Comparator.comparingInt(a -> a[0])); // [end, numPassengers] int curPass = 0; - + for (int[] trip : trips) { int numPass = trip[0], start = trip[1], end = trip[2]; - + while (!minHeap.isEmpty() && minHeap.peek()[0] <= start) { curPass -= minHeap.poll()[1]; } - + curPass += numPass; if (curPass > capacity) { return false; } - + minHeap.offer(new int[]{end, numPass}); } - + return true; } } @@ -196,12 +218,12 @@ class Solution { carPooling(trips, capacity) { trips.sort((a, b) => a[1] - b[1]); - const minHeap = new MinPriorityQueue({ priority: x => x[0] }); // [end, numPassengers] + const minHeap = new MinPriorityQueue((x) => x[0]); // [end, numPassengers] let curPass = 0; for (const [numPass, start, end] of trips) { - while (!minHeap.isEmpty() && minHeap.front().element[0] <= start) { - curPass -= minHeap.dequeue().element[1]; + while (!minHeap.isEmpty() && minHeap.front()[0] <= start) { + curPass -= minHeap.dequeue()[1]; } curPass += numPass; @@ -217,12 +239,42 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CarPooling(int[][] trips, int capacity) { + Array.Sort(trips, (a, b) => a[1].CompareTo(b[1])); + + var minHeap = new PriorityQueue(); + int curPass = 0; + + foreach (var trip in trips) { + int numPass = trip[0]; + int start = trip[1]; + int end = trip[2]; + + while (minHeap.Count > 0 && minHeap.Peek()[0] <= start) { + curPass -= minHeap.Dequeue()[1]; + } + + curPass += numPass; + if (curPass > capacity) { + return false; + } + + minHeap.Enqueue(new int[] { end, numPass }, end); + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -237,14 +289,14 @@ class Solution: for passengers, start, end in trips: points.append([start, passengers]) points.append([end, -passengers]) - + points.sort() curPass = 0 for point, passengers in points: curPass += passengers if curPass > capacity: return False - + return True ``` @@ -257,9 +309,9 @@ public class Solution { points.add(new int[]{start, passengers}); points.add(new int[]{end, -passengers}); } - + points.sort((a, b) -> a[0] == b[0] ? Integer.compare(a[1], b[1]) : Integer.compare(a[0], b[0])); - + int curPass = 0; for (int[] point : points) { curPass += point[1]; @@ -267,7 +319,7 @@ public class Solution { return false; } } - + return true; } } @@ -314,9 +366,9 @@ class Solution { points.push([start, passengers]); points.push([end, -passengers]); } - - points.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]); - + + points.sort((a, b) => (a[0] === b[0] ? a[1] - b[1] : a[0] - b[0])); + let curPass = 0; for (const [point, passengers] of points) { curPass += passengers; @@ -324,7 +376,37 @@ class Solution { return false; } } - + + return true; + } +} +``` + +```csharp +public class Solution { + public bool CarPooling(int[][] trips, int capacity) { + List points = new List(); + + foreach (var trip in trips) { + int passengers = trip[0]; + int start = trip[1]; + int end = trip[2]; + + points.Add(new int[] { start, passengers }); + points.Add(new int[] { end, -passengers }); + } + + points.Sort((a, b) => { + if (a[0] == b[0]) return a[1] - b[1]; + return a[0] - b[0]; + }); + + int curPass = 0; + foreach (var point in points) { + curPass += point[1]; + if (curPass > capacity) return false; + } + return true; } } @@ -334,8 +416,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -350,19 +432,19 @@ class Solution: for _, start, end in trips: L = min(L, start) R = max(R, end) - + N = R - L + 1 passChange = [0] * (N + 1) for passengers, start, end in trips: passChange[start - L] += passengers passChange[end - L] -= passengers - + curPass = 0 for change in passChange: curPass += change if curPass > capacity: return False - + return True ``` @@ -433,7 +515,8 @@ class Solution { * @return {boolean} */ carPooling(trips, capacity) { - let L = Infinity, R = -Infinity; + let L = Infinity, + R = -Infinity; for (const [passengers, start, end] of trips) { L = Math.min(L, start); R = Math.max(R, end); @@ -459,11 +542,45 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CarPooling(int[][] trips, int capacity) { + int L = int.MaxValue, R = int.MinValue; + + foreach (var trip in trips) { + int start = trip[1], end = trip[2]; + L = Math.Min(L, start); + R = Math.Max(R, end); + } + + int N = R - L + 1; + int[] passChange = new int[N + 1]; + + foreach (var trip in trips) { + int passengers = trip[0]; + int start = trip[1]; + int end = trip[2]; + + passChange[start - L] += passengers; + passChange[end - L] -= passengers; + } + + int curPass = 0; + foreach (int change in passChange) { + curPass += change; + if (curPass > capacity) return false; + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n + N)$ -* Space complexity: $O(N)$ +- Time complexity: $O(n + N)$ +- Space complexity: $O(N)$ -> Where $n$ is the size of the array $trips$ and $N$ is the difference between the rightmost location and the leftmost location. \ No newline at end of file +> Where $n$ is the size of the array $trips$ and $N$ is the difference between the rightmost location and the leftmost location. diff --git a/articles/champagne-tower.md b/articles/champagne-tower.md index d2f36a28e..fa765bf91 100644 --- a/articles/champagne-tower.md +++ b/articles/champagne-tower.md @@ -8,15 +8,15 @@ class Solution: def rec(row, glass): if row < 0 or glass < 0 or glass > row: return 0 - + if row == 0 and glass == 0: return poured - + left_parent = max(0, rec(row - 1, glass - 1) - 1) right_parent = max(0, rec(row - 1, glass) - 1) - + return (left_parent + right_parent) / 2 - + return min(1, rec(query_row, query_glass)) ``` @@ -101,8 +101,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ > Where $n$ is the given $queryRow$. @@ -116,19 +116,19 @@ class Solution { class Solution: def champagneTower(self, poured: int, query_row: int, query_glass: int) -> float: memo = { (0, 0) : poured } - + def rec(row, glass): if row < 0 or glass < 0 or glass > row: return 0 if (row, glass) in memo: return memo[(row, glass)] - + left_parent = max(0, rec(row - 1, glass - 1) - 1) right_parent = max(0, rec(row - 1, glass) - 1) - + memo[(row, glass)] = (left_parent + right_parent) / 2 return memo[(row, glass)] - + return min(1, rec(query_row, query_glass)) ``` @@ -149,7 +149,7 @@ public class Solution { if (row < 0 || glass < 0 || glass > row) { return 0; } - + if (memo[row][glass] != -1) { return memo[row][glass]; } @@ -181,7 +181,7 @@ private: if (row < 0 || glass < 0 || glass > row) { return 0; } - + if (memo[row][glass] != -1) { return memo[row][glass]; } @@ -204,7 +204,9 @@ class Solution { * @return {number} */ champagneTower(poured, query_row, query_glass) { - const memo = Array.from({ length: query_row + 5 }, (_, i) => Array(i + 1).fill(-1)); + const memo = Array.from({ length: query_row + 5 }, (_, i) => + Array(i + 1).fill(-1), + ); memo[0][0] = poured; const rec = (row, glass) => { @@ -234,8 +236,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ > Where $n$ is the given $queryRow$ and $m$ is the given $queryGlass$. @@ -250,14 +252,14 @@ class Solution: def champagneTower(self, poured: int, query_row: int, query_glass: int) -> float: dp = [[0] * (i + 1) for i in range(query_row + 5)] dp[0][0] += poured - + for row in range(min(99, query_row + 1)): for glass in range(row + 1): excess = (dp[row][glass] - 1.0) / 2.0 if excess > 0: dp[row + 1][glass] += excess dp[row + 1][glass + 1] += excess - + return min(1.0, dp[query_row][query_glass]) ``` @@ -268,9 +270,9 @@ public class Solution { for (int i = 0; i < query_row + 5; i++) { dp[i] = new double[i + 1]; } - + dp[0][0] += poured; - + for (int row = 0; row < Math.min(99, query_row + 1); row++) { for (int glass = 0; glass <= row; glass++) { double excess = (dp[row][glass] - 1.0) / 2.0; @@ -280,7 +282,7 @@ public class Solution { } } } - + return Math.min(1.0, dp[query_row][query_glass]); } } @@ -294,9 +296,9 @@ public: for (int i = 0; i <= query_row + 4; i++) { dp[i].resize(i + 1, 0); } - + dp[0][0] += poured; - + for (int row = 0; row < min(99, query_row + 1); row++) { for (int glass = 0; glass <= row; glass++) { double excess = (dp[row][glass] - 1.0) / 2.0; @@ -306,7 +308,7 @@ public: } } } - + return min(1.0, dp[query_row][query_glass]); } }; @@ -321,7 +323,9 @@ class Solution { * @return {number} */ champagneTower(poured, query_row, query_glass) { - const dp = Array.from({ length: query_row + 5 }, (_, i) => Array(i + 1).fill(0)); + const dp = Array.from({ length: query_row + 5 }, (_, i) => + Array(i + 1).fill(0), + ); dp[0][0] += poured; for (let row = 0; row < Math.min(99, query_row + 1); row++) { @@ -343,8 +347,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ > Where $n$ is the given $queryRow$ and $m$ is the given $queryGlass$. @@ -375,7 +379,7 @@ class Solution: public class Solution { public double champagneTower(int poured, int query_row, int query_glass) { double[] prev_row = new double[] { poured }; // Flow - + for (int row = 1; row <= query_row; row++) { double[] cur_row = new double[row + 1]; for (int i = 0; i < row; i++) { @@ -387,7 +391,7 @@ public class Solution { } prev_row = cur_row; } - + return Math.min(1.0, prev_row[query_glass]); } } @@ -398,7 +402,7 @@ class Solution { public: double champagneTower(int poured, int query_row, int query_glass) { vector prev_row = {double(poured)}; // Flow - + for (int row = 1; row <= query_row; row++) { vector cur_row(row + 1, 0); for (int i = 0; i < row; i++) { @@ -410,7 +414,7 @@ public: } prev_row = cur_row; } - + return min(1.0, prev_row[query_glass]); } }; @@ -425,8 +429,8 @@ class Solution { * @return {number} */ champagneTower(poured, query_row, query_glass) { - let prev_row = [poured]; // Flow - + let prev_row = [poured]; // Flow + for (let row = 1; row <= query_row; row++) { let cur_row = new Array(row + 1).fill(0); for (let i = 0; i < row; i++) { @@ -438,7 +442,7 @@ class Solution { } prev_row = cur_row; } - + return Math.min(1, prev_row[query_glass]); } } @@ -448,8 +452,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n)$ > Where $n$ is the given $queryRow$ and $m$ is the given $queryGlass$. @@ -463,7 +467,7 @@ class Solution { class Solution: def champagneTower(self, poured: int, query_row: int, query_glass: int) -> float: dp = [poured] + [0] * query_row - + for row in range(1, query_row + 1): for i in range(row - 1, -1, -1): extra = dp[i] - 1 @@ -472,7 +476,7 @@ class Solution: dp[i + 1] += 0.5 * extra else: dp[i] = 0 - + return min(1, dp[query_glass]) ``` @@ -556,7 +560,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n)$ -> Where $n$ is the given $queryRow$ and $m$ is the given $queryGlass$. \ No newline at end of file +> Where $n$ is the given $queryRow$ and $m$ is the given $queryGlass$. diff --git a/articles/cheapest-flight-path.md b/articles/cheapest-flight-path.md index 6c23351be..7c0b87da3 100644 --- a/articles/cheapest-flight-path.md +++ b/articles/cheapest-flight-path.md @@ -10,7 +10,7 @@ class Solution: dist = [[INF] * (k + 5) for _ in range(n)] for u, v, cst in flights: adj[u].append([v, cst]) - + dist[src][0] = 0 minHeap = [(0, src, -1)] # cost, node, stops while len(minHeap): @@ -35,12 +35,12 @@ public class Solution { List[] adj = new ArrayList[n]; int[][] dist = new int[n][k + 5]; for (int i = 0; i < n; i++) Arrays.fill(dist[i], INF); - + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); for (int[] flight : flights) { adj[flight[0]].add(new int[]{flight[1], flight[2]}); } - + dist[src][0] = 0; PriorityQueue minHeap = new PriorityQueue<>( Comparator.comparingInt(a -> a[0]) @@ -74,16 +74,16 @@ public: int INF = 1e9; vector>> adj(n); vector> dist(n, vector(k + 5, INF)); - + for (auto& flight : flights) { adj[flight[0]].emplace_back(flight[1], flight[2]); } - + dist[src][0] = 0; - priority_queue, + priority_queue, vector>, greater<>> minHeap; minHeap.emplace(0, src, -1); - + while (!minHeap.empty()) { auto [cst, node, stops] = minHeap.top(); minHeap.pop(); @@ -116,15 +116,14 @@ class Solution { findCheapestPrice(n, flights, src, dst, k) { const INF = Infinity; const adj = Array.from({ length: n }, () => []); - const dist = Array.from({ length: n }, () => - Array(k + 5).fill(INF)); - + const dist = Array.from({ length: n }, () => Array(k + 5).fill(INF)); + for (let [u, v, cst] of flights) { adj[u].push([v, cst]); } - + dist[src][0] = 0; - const minHeap = new MinPriorityQueue(entry => entry[0]); + const minHeap = new MinPriorityQueue((entry) => entry[0]); minHeap.push([0, src, -1]); // cost, node, stops while (!minHeap.isEmpty()) { const [cst, node, stops] = minHeap.pop(); @@ -150,31 +149,31 @@ public class Solution { int INF = int.MaxValue; List[] adj = new List[n]; int[][] dist = new int[n][]; - + for (int i = 0; i < n; i++) { adj[i] = new List(); dist[i] = new int[k + 2]; Array.Fill(dist[i], INF); } - + foreach (var flight in flights) { adj[flight[0]].Add(new int[] { flight[1], flight[2] }); } - + dist[src][0] = 0; var minHeap = new PriorityQueue<(int cst, int node, int stops), int>(); minHeap.Enqueue((0, src, 0), 0); - + while (minHeap.Count > 0) { var (cst, node, stops) = minHeap.Dequeue(); if (node == dst) return cst; if (stops > k) continue; - + foreach (var neighbor in adj[node]) { int nei = neighbor[0], w = neighbor[1]; int nextCst = cst + w; int nextStops = stops + 1; - + if (dist[nei][nextStops] > nextCst) { dist[nei][nextStops] = nextCst; minHeap.Enqueue((nextCst, nei, nextStops), nextCst); @@ -258,12 +257,59 @@ class Solution { } ``` +```swift +struct Item: Comparable { + let cost: Int + let node: Int + let stops: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.cost < rhs.cost + } +} + +class Solution { + func findCheapestPrice(_ n: Int, _ flights: [[Int]], _ src: Int, _ dst: Int, _ k: Int) -> Int { + let INF = Int.max + var adj = Array(repeating: [(Int, Int)](), count: n) + var dist = Array(repeating: Array(repeating: INF, count: k + 5), count: n) + + for flight in flights { + let u = flight[0], v = flight[1], cst = flight[2] + adj[u].append((v, cst)) + } + + var minHeap = Heap() + minHeap.insert(Item(cost: 0, node: src, stops: -1)) + dist[src][0] = 0 + + while !minHeap.isEmpty { + let item = minHeap.removeMin() + let cst = item.cost, node = item.node, stops = item.stops + if node == dst { return cst } + if stops == k || dist[node][stops + 1] < cst { continue } + + for (nei, w) in adj[node] { + let nextCst = cst + w + let nextStops = stops + 1 + if dist[nei][nextStops + 1] > nextCst { + dist[nei][nextStops + 1] = nextCst + minHeap.insert(Item(cost: nextCst, node: nei, stops: nextStops)) + } + } + } + + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O((n + m) * k)$ -* Space complexity: $O(n * k)$ +- Time complexity: $O((n + m) * k)$ +- Space complexity: $O(n * k)$ > Where $n$ is the number of cities, $m$ is the number of flights and $k$ is the number of stops. @@ -429,7 +475,7 @@ func findCheapestPrice(n int, flights [][]int, src int, dst int, k int) int { for i := 0; i <= k; i++ { tmpPrices := make([]int, n) copy(tmpPrices, prices) - + for _, flight := range flights { s, d, p := flight[0], flight[1], flight[2] if prices[s] == math.MaxInt32 { @@ -441,7 +487,7 @@ func findCheapestPrice(n int, flights [][]int, src int, dst int, k int) int { } prices = tmpPrices } - + if prices[dst] == math.MaxInt32 { return -1 } @@ -471,12 +517,37 @@ class Solution { } ``` +```swift +class Solution { + func findCheapestPrice(_ n: Int, _ flights: [[Int]], _ src: Int, _ dst: Int, _ k: Int) -> Int { + var prices = Array(repeating: Int.max, count: n) + prices[src] = 0 + + for _ in 0...k { + var tmpPrices = prices + + for flight in flights { + let s = flight[0], d = flight[1], p = flight[2] + if prices[s] == Int.max { + continue + } + if prices[s] + p < tmpPrices[d] { + tmpPrices[d] = prices[s] + p + } + } + prices = tmpPrices + } + return prices[dst] == Int.max ? -1 : prices[dst] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n + (m * k))$ -* Space complexity: $O(n)$ +- Time complexity: $O(n + (m * k))$ +- Space complexity: $O(n)$ > Where $n$ is the number of cities, $m$ is the number of flights and $k$ is the number of stops. @@ -500,7 +571,7 @@ class Solution: cst, node, stops = q.popleft() if stops > k: continue - + for nei, w in adj[node]: nextCost = cst + w if nextCost < prices[nei]: @@ -593,7 +664,7 @@ class Solution { const prices = Array(n).fill(Infinity); prices[src] = 0; const adj = Array.from({ length: n }, () => []); - + for (const [u, v, cst] of flights) { adj[u].push([v, cst]); } @@ -727,11 +798,46 @@ class Solution { } ``` +```swift +class Solution { + func findCheapestPrice(_ n: Int, _ flights: [[Int]], _ src: Int, _ dst: Int, _ k: Int) -> Int { + var prices = Array(repeating: Int.max, count: n) + prices[src] = 0 + var adj = Array(repeating: [(Int, Int)](), count: n) + + for flight in flights { + let u = flight[0], v = flight[1], cst = flight[2] + adj[u].append((v, cst)) + } + + var queue = Deque<(Int, Int, Int)>() + queue.append((0, src, 0)) + + while !queue.isEmpty { + let (cst, node, stops) = queue.popFirst()! + if stops > k { + continue + } + + for (nei, w) in adj[node] { + let nextCost = cst + w + if nextCost < prices[nei] { + prices[nei] = nextCost + queue.append((nextCost, nei, stops + 1)) + } + } + } + + return prices[dst] == Int.max ? -1 : prices[dst] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * k)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n * k)$ +- Space complexity: $O(n + m)$ -> Where $n$ is the number of cities, $m$ is the number of flights and $k$ is the number of stops. \ No newline at end of file +> Where $n$ is the number of cities, $m$ is the number of flights and $k$ is the number of stops. diff --git a/articles/check-completeness-of-a-binary-tree.md b/articles/check-completeness-of-a-binary-tree.md new file mode 100644 index 000000000..86acd8fd4 --- /dev/null +++ b/articles/check-completeness-of-a-binary-tree.md @@ -0,0 +1,594 @@ +## 1. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def isCompleteTree(self, root: Optional[TreeNode]) -> bool: + q = deque([root]) + while q: + node = q.popleft() + if node: + q.append(node.left) + q.append(node.right) + else: + while q: + if q.popleft(): + return False + return True +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean isCompleteTree(TreeNode root) { + Queue q = new LinkedList<>(); + q.add(root); + + while (!q.isEmpty()) { + TreeNode node = q.poll(); + if (node != null) { + q.add(node.left); + q.add(node.right); + } else { + while (!q.isEmpty()) { + if (q.poll() != null) { + return false; + } + } + } + } + return true; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool isCompleteTree(TreeNode* root) { + queue q; + q.push(root); + + while (!q.empty()) { + TreeNode* node = q.front(); + q.pop(); + if (node) { + q.push(node->left); + q.push(node->right); + } else { + while (!q.empty()) { + if (q.front()) { + return false; + } + q.pop(); + } + } + } + return true; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {boolean} + */ + isCompleteTree(root) { + const queue = new Queue([root]); + + while (!queue.isEmpty()) { + const node = queue.pop(); + if (node) { + queue.push(node.left); + queue.push(node.right); + } else { + while (!queue.isEmpty()) { + if (queue.pop()) { + return false; + } + } + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Breadth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def isCompleteTree(self, root: Optional[TreeNode]) -> bool: + q = deque([root]) + nullSeen = False + while q: + node = q.popleft() + if node: + if nullSeen: + return False + q.append(node.left) + q.append(node.right) + else: + nullSeen = True + return True +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean isCompleteTree(TreeNode root) { + Queue q = new LinkedList<>(); + q.add(root); + boolean nullSeen = false; + + while (!q.isEmpty()) { + TreeNode node = q.poll(); + if (node != null) { + if (nullSeen) return false; + q.add(node.left); + q.add(node.right); + } else { + nullSeen = true; + } + } + return true; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool isCompleteTree(TreeNode* root) { + queue q; + q.push(root); + bool nullSeen = false; + + while (!q.empty()) { + TreeNode* node = q.front(); + q.pop(); + if (node) { + if (nullSeen) return false; + q.push(node->left); + q.push(node->right); + } else { + nullSeen = true; + } + } + return true; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {boolean} + */ + isCompleteTree(root) { + const queue = new Queue([root]); + let nullSeen = false; + + while (!queue.isEmpty()) { + const node = queue.pop(); + if (node) { + if (nullSeen) return false; + queue.push(node.left); + queue.push(node.right); + } else { + nullSeen = true; + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Depth First Search (Two Pass) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def isCompleteTree(self, root: Optional[TreeNode]) -> bool: + def dfs(node, index, n): + if not node: + return True + if index >= n: + return False + + left = dfs(node.left, 2 * index + 1, n) + right = dfs(node.right, 2 * index + 2, n) + return left and right + + def countNodes(node): + if not node: + return 0 + return 1 + countNodes(node.left) + countNodes(node.right) + + n = countNodes(root) + return dfs(root, 0, n) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private int countNodes(TreeNode root) { + if (root == null) return 0; + return 1 + countNodes(root.left) + countNodes(root.right); + } + + private boolean dfs(TreeNode node, int index, int n) { + if (node == null) return true; + if (index >= n) return false; + return dfs(node.left, 2 * index + 1, n) && dfs(node.right, 2 * index + 2, n); + } + + public boolean isCompleteTree(TreeNode root) { + int n = countNodes(root); + return dfs(root, 0, n); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int countNodes(TreeNode* root) { + if (!root) return 0; + return 1 + countNodes(root->left) + countNodes(root->right); + } + + bool dfs(TreeNode* node, int index, int n) { + if (!node) return true; + if (index >= n) return false; + return dfs(node->left, 2 * index + 1, n) && dfs(node->right, 2 * index + 2, n); + } + + bool isCompleteTree(TreeNode* root) { + int n = countNodes(root); + return dfs(root, 0, n); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {boolean} + */ + isCompleteTree(root) { + const countNodes = (node) => { + if (!node) return 0; + return 1 + countNodes(node.left) + countNodes(node.right); + }; + + const dfs = (node, index, n) => { + if (!node) return true; + if (index >= n) return false; + return ( + dfs(node.left, 2 * index + 1, n) && + dfs(node.right, 2 * index + 2, n) + ); + }; + + const n = countNodes(root); + return dfs(root, 0, n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 4. Depth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def isCompleteTree(self, root: Optional[TreeNode]) -> bool: + treeHgt = 0 + nullSeen = False + + def dfs(node, hgt): + nonlocal treeHgt, nullSeen + if not node: + if treeHgt == 0: + treeHgt = hgt + elif hgt == treeHgt - 1: + nullSeen = True + elif hgt != treeHgt: + return False + return not (hgt == treeHgt and nullSeen) + + return dfs(node.left, hgt + 1) and dfs(node.right, hgt + 1) + + return dfs(root, 0) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private int treeHgt = 0; + private boolean nullSeen = false; + + private boolean dfs(TreeNode node, int hgt) { + if (node == null) { + if (treeHgt == 0) { + treeHgt = hgt; + } else if (hgt == treeHgt - 1) { + nullSeen = true; + } else if (hgt != treeHgt) { + return false; + } + return !(hgt == treeHgt && nullSeen); + } + + return dfs(node.left, hgt + 1) && dfs(node.right, hgt + 1); + } + + public boolean isCompleteTree(TreeNode root) { + return dfs(root, 0); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int treeHgt = 0; + bool nullSeen = false; + + bool dfs(TreeNode* node, int hgt) { + if (!node) { + if (treeHgt == 0) { + treeHgt = hgt; + } else if (hgt == treeHgt - 1) { + nullSeen = true; + } else if (hgt != treeHgt) { + return false; + } + return !(hgt == treeHgt && nullSeen); + } + + return dfs(node->left, hgt + 1) && dfs(node->right, hgt + 1); + } + + bool isCompleteTree(TreeNode* root) { + return dfs(root, 0); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {boolean} + */ + isCompleteTree(root) { + let treeHgt = 0; + let nullSeen = false; + + const dfs = (node, hgt) => { + if (!node) { + if (treeHgt === 0) { + treeHgt = hgt; + } else if (hgt === treeHgt - 1) { + nullSeen = true; + } else if (hgt !== treeHgt) { + return false; + } + return !(hgt === treeHgt && nullSeen); + } + + return dfs(node.left, hgt + 1) && dfs(node.right, hgt + 1); + }; + + return dfs(root, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. diff --git a/articles/check-if-a-string-contains-all-binary-codes-of-size-k.md b/articles/check-if-a-string-contains-all-binary-codes-of-size-k.md index 917412238..fc0354181 100644 --- a/articles/check-if-a-string-contains-all-binary-codes-of-size-k.md +++ b/articles/check-if-a-string-contains-all-binary-codes-of-size-k.md @@ -67,11 +67,11 @@ class Solution { */ hasAllCodes(s, k) { const n = s.length; - if (n < (1 << k)) { + if (n < 1 << k) { return false; } - for (let num = 0; num < (1 << k); num++) { + for (let num = 0; num < 1 << k; num++) { const binaryCode = num.toString(2).padStart(k, '0'); if (!s.includes(binaryCode)) { return false; @@ -87,8 +87,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ k)$ -* Space complexity: $O(k)$ +- Time complexity: $O(n * 2 ^ k)$ +- Space complexity: $O(k)$ > Where $n$ is the length of the string $s$ and $k$ is the length of the binary code. @@ -103,11 +103,11 @@ class Solution: def hasAllCodes(self, s: str, k: int) -> bool: if len(s) < 2 ** k: return False - + codeSet = set() for i in range(len(s) - k + 1): codeSet.add(s[i:i + k]) - + return len(codeSet) == 2 ** k ``` @@ -117,12 +117,12 @@ public class Solution { if (s.length() < (1 << k)) { return false; } - + HashSet codeSet = new HashSet<>(); for (int i = 0; i <= s.length() - k; i++) { codeSet.add(s.substring(i, i + k)); } - + return codeSet.size() == (1 << k); } } @@ -135,12 +135,12 @@ public: if (s.size() < (1 << k)) { return false; } - + std::unordered_set codeSet; for (int i = 0; i <= s.size() - k; i++) { codeSet.insert(s.substr(i, k)); } - + return codeSet.size() == (1 << k); } }; @@ -154,16 +154,16 @@ class Solution { * @return {boolean} */ hasAllCodes(s, k) { - if (s.length < (1 << k)) { + if (s.length < 1 << k) { return false; } - + const codeSet = new Set(); for (let i = 0; i <= s.length - k; i++) { codeSet.add(s.substring(i, i + k)); } - - return codeSet.size === (1 << k); + + return codeSet.size === 1 << k; } } ``` @@ -172,8 +172,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * k)$ -* Space complexity: $O(2 ^ k)$ +- Time complexity: $O(n * k)$ +- Space complexity: $O(2 ^ k)$ > Where $n$ is the length of the string $s$ and $k$ is the length of the binary code. @@ -189,7 +189,7 @@ class Solution: n = len(s) if n < (1 << k): return False - + codeSet = [False] * (1 << k) cur = 0 i = j = 0 @@ -199,7 +199,7 @@ class Solution: cur |= (1 << bit) bit -= 1 j += 1 - + have = 1 codeSet[cur] = True while j < n: @@ -215,7 +215,7 @@ class Solution: if not codeSet[cur]: have += 1 codeSet[cur] = True - + return have == (1 << k) ``` @@ -321,17 +321,19 @@ class Solution { */ hasAllCodes(s, k) { const n = s.length; - if (n < (1 << k)) { + if (n < 1 << k) { return false; } const codeSet = new Array(1 << k).fill(false); let cur = 0; - let i = 0, j = 0, bit = k - 1; + let i = 0, + j = 0, + bit = k - 1; while (j < k) { if (s[j] === '1') { - cur |= (1 << bit); + cur |= 1 << bit; } bit--; j++; @@ -342,7 +344,7 @@ class Solution { while (j < n) { if (s[i] === '1') { - cur ^= (1 << (k - 1)); + cur ^= 1 << (k - 1); } i++; @@ -358,7 +360,7 @@ class Solution { } } - return have === (1 << k); + return have === 1 << k; } } ``` @@ -367,8 +369,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(2 ^ k)$ +- Time complexity: $O(n)$ +- Space complexity: $O(2 ^ k)$ > Where $n$ is the length of the string $s$ and $k$ is the length of the binary code. @@ -384,11 +386,11 @@ class Solution: n = len(s) if n < (1 << k): return False - + codeSet = [False] * (1 << k) cur = 0 have = 0 - + for i in range(n): cur = ((cur << 1) & ((1 << k) - 1)) | (ord(s[i]) - ord('0')) @@ -396,7 +398,7 @@ class Solution: if not codeSet[cur]: codeSet[cur] = True have += 1 - + return have == (1 << k) ``` @@ -464,12 +466,13 @@ class Solution { */ hasAllCodes(s, k) { const n = s.length; - if (n < (1 << k)) { + if (n < 1 << k) { return false; } const codeSet = new Array(1 << k).fill(false); - let cur = 0, have = 0; + let cur = 0, + have = 0; for (let i = 0; i < n; i++) { cur = ((cur << 1) & ((1 << k) - 1)) | (s[i] - '0'); @@ -482,7 +485,7 @@ class Solution { } } - return have === (1 << k); + return have === 1 << k; } } ``` @@ -491,7 +494,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(2 ^ k)$ +- Time complexity: $O(n)$ +- Space complexity: $O(2 ^ k)$ -> Where $n$ is the length of the string $s$ and $k$ is the length of the binary code. \ No newline at end of file +> Where $n$ is the length of the string $s$ and $k$ is the length of the binary code. diff --git a/articles/check-if-array-is-sorted-and-rotated.md b/articles/check-if-array-is-sorted-and-rotated.md new file mode 100644 index 000000000..0b258f9ea --- /dev/null +++ b/articles/check-if-array-is-sorted-and-rotated.md @@ -0,0 +1,307 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def check(self, nums: List[int]) -> bool: + sortedNums = sorted(nums) + arr = [] + + for i in range(len(nums)): + arr.insert(0, sortedNums.pop()) + if nums == arr + sortedNums: + return True + + return False +``` + +```java +public class Solution { + public boolean check(int[] nums) { + int n = nums.length; + int[] sortedNums = nums.clone(); + Arrays.sort(sortedNums); + + for (int i = 0; i < n; i++) { + boolean match = true; + int idx = 0; + for (int j = n - i; j < n && match; j++) { + if (nums[idx] != sortedNums[j]) { + match = false; + } + idx += 1; + } + + for (int j = 0; j < n - i && match; j++) { + if (nums[idx] != sortedNums[j]) { + match = false; + } + idx += 1; + } + + if (match) return true; + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool check(vector& nums) { + int n = nums.size(); + vector sortedNums = nums; + sort(sortedNums.begin(), sortedNums.end()); + + for (int i = 0; i < n; i++) { + bool match = true; + int idx = 0; + for (int j = n - i; j < n && match; j++) { + if (nums[idx] != sortedNums[j]) { + match = false; + } + idx++; + } + + for (int j = 0; j < n - i && match; j++) { + if (nums[idx] != sortedNums[j]) { + match = false; + } + idx++; + } + + if (match) return true; + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + check(nums) { + const n = nums.length; + const sortedNums = [...nums].sort((a, b) => a - b); + + for (let i = 0; i < n; i++) { + let match = true; + let idx = 0; + + for (let j = n - i; j < n && match; j++) { + if (nums[idx] !== sortedNums[j]) { + match = false; + } + idx++; + } + + for (let j = 0; j < n - i && match; j++) { + if (nums[idx] !== sortedNums[j]) { + match = false; + } + idx++; + } + + if (match) return true; + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 2. Sliding Window + +::tabs-start + +```python +class Solution: + def check(self, nums: List[int]) -> bool: + N = len(nums) + count = 1 + + for i in range(1, 2 * N): + if nums[(i - 1) % N] <= nums[i % N]: + count += 1 + else: + count = 1 + if count == N: + return True + + return N == 1 +``` + +```java +public class Solution { + public boolean check(int[] nums) { + int N = nums.length; + int count = 1; + + for (int i = 1; i < 2 * N; i++) { + if (nums[(i - 1) % N] <= nums[i % N]) { + count++; + } else { + count = 1; + } + if (count == N) { + return true; + } + } + + return N == 1; + } +} +``` + +```cpp +class Solution { +public: + bool check(vector& nums) { + int N = nums.size(); + int count = 1; + + for (int i = 1; i < 2 * N; i++) { + if (nums[(i - 1) % N] <= nums[i % N]) { + count++; + } else { + count = 1; + } + if (count == N) { + return true; + } + } + + return N == 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + check(nums) { + const N = nums.length; + let count = 1; + + for (let i = 1; i < 2 * N; i++) { + if (nums[(i - 1) % N] <= nums[i % N]) { + count++; + } else { + count = 1; + } + if (count === N) { + return true; + } + } + + return N === 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 3. Iteration + +::tabs-start + +```python +class Solution: + def check(self, nums: List[int]) -> bool: + count, N = 0, len(nums) + + for i in range(N): + if nums[i] > nums[(i + 1) % N]: + count += 1 + if count > 1: + return False + + return True +``` + +```java +public class Solution { + public boolean check(int[] nums) { + int count = 0, N = nums.length; + + for (int i = 0; i < N; i++) { + if (nums[i] > nums[(i + 1) % N] && ++count > 1) { + return false; + } + } + + return true; + } +} +``` + +```cpp +class Solution { +public: + bool check(vector& nums) { + int count = 0, N = nums.size(); + + for (int i = 0; i < N; i++) { + if (nums[i] > nums[(i + 1) % N] && ++count > 1) { + return false; + } + } + + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + check(nums) { + let count = 0, + N = nums.length; + + for (let i = 0; i < N; i++) { + if (nums[i] > nums[(i + 1) % N] && ++count > 1) { + return false; + } + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/check-if-move-is-legal.md b/articles/check-if-move-is-legal.md new file mode 100644 index 000000000..c1263c780 --- /dev/null +++ b/articles/check-if-move-is-legal.md @@ -0,0 +1,314 @@ +## 1. Iteration - I + +::tabs-start + +```python +class Solution: + def checkMove(self, board: List[List[str]], rMove: int, cMove: int, color: str) -> bool: + ROWS, COLS = len(board), len(board[0]) + direction = [[1, 0], [-1, 0], [0, 1], [0, -1], + [1, 1], [-1, -1], [1, -1], [-1, 1]] + + board[rMove][cMove] = color + + def legal(row, col, color, direc): + dr, dc = direc + row, col = row + dr, col + dc + length = 1 + + while 0 <= row < ROWS and 0 <= col < COLS: + length += 1 + if board[row][col] == ".": + return False + if board[row][col] == color: + return length >= 3 + row, col = row + dr, col + dc + return False + + for d in direction: + if legal(rMove, cMove, color, d): + return True + return False +``` + +```java +public class Solution { + public boolean checkMove(char[][] board, int rMove, int cMove, char color) { + int ROWS = board.length, COLS = board[0].length; + int[][] direction = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, + {1, 1}, {-1, -1}, {1, -1}, {-1, 1}}; + + board[rMove][cMove] = color; + + for (int[] d : direction) { + if (legal(board, rMove, cMove, color, d)) { + return true; + } + } + return false; + } + + private boolean legal(char[][] board, int row, int col, char color, int[] direc) { + int ROWS = board.length, COLS = board[0].length; + int dr = direc[0], dc = direc[1]; + row += dr; + col += dc; + int length = 1; + + while (row >= 0 && row < ROWS && col >= 0 && col < COLS) { + length++; + if (board[row][col] == '.') { + return false; + } + if (board[row][col] == color) { + return length >= 3; + } + row += dr; + col += dc; + } + return false; + } +} +``` + +```cpp +class Solution { +public: + bool checkMove(vector>& board, int rMove, int cMove, char color) { + int ROWS = board.size(), COLS = board[0].size(); + vector> direction = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}, + {1, 1}, {-1, -1}, {1, -1}, {-1, 1}}; + + board[rMove][cMove] = color; + + for (auto& d : direction) { + if (legal(board, rMove, cMove, color, d)) { + return true; + } + } + return false; + } + +private: + bool legal(vector>& board, int row, int col, char color, vector& direc) { + int ROWS = board.size(), COLS = board[0].size(); + int dr = direc[0], dc = direc[1]; + row += dr; + col += dc; + int length = 1; + + while (row >= 0 && row < ROWS && col >= 0 && col < COLS) { + length++; + if (board[row][col] == '.') { + return false; + } + if (board[row][col] == color) { + return length >= 3; + } + row += dr; + col += dc; + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {character[][]} board + * @param {number} rMove + * @param {number} cMove + * @param {character} color + * @return {boolean} + */ + checkMove(board, rMove, cMove, color) { + const ROWS = board.length, + COLS = board[0].length; + const direction = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + [1, 1], + [-1, -1], + [1, -1], + [-1, 1], + ]; + + board[rMove][cMove] = color; + + const legal = (row, col, color, [dr, dc]) => { + row += dr; + col += dc; + let length = 1; + + while (row >= 0 && row < ROWS && col >= 0 && col < COLS) { + length++; + if (board[row][col] === '.') { + return false; + } + if (board[row][col] === color) { + return length >= 3; + } + row += dr; + col += dc; + } + return false; + }; + + for (let d of direction) { + if (legal(rMove, cMove, color, d)) { + return true; + } + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +--- + +## 2. Iteration - II + +::tabs-start + +```python +class Solution: + def checkMove(self, board: List[List[str]], rMove: int, cMove: int, color: str) -> bool: + ROWS, COLS = len(board), len(board[0]) + direction = [0, 1, 0, -1, 0, 1, 1, -1, -1, 1] + + board[rMove][cMove] = color + + for d in range(9): + length = 1 + row, col = rMove, cMove + while True: + row += direction[d] + col += direction[d + 1] + + if row < 0 or col < 0 or row >= ROWS or col >= COLS or board[row][col] == ".": + break + if board[row][col] == color: + if length > 1: + return True + break + length += 1 + + return False +``` + +```java +public class Solution { + public boolean checkMove(char[][] board, int rMove, int cMove, char color) { + int ROWS = board.length, COLS = board[0].length; + int[] direction = {0, 1, 0, -1, 0, 1, 1, -1, -1, 1}; + + board[rMove][cMove] = color; + + for (int d = 0; d < 9; d++) { + int row = rMove, col = cMove; + for (int length = 1; ; ++length) { + row += direction[d]; + col += direction[d + 1]; + + if (row < 0 || col < 0 || row >= ROWS || col >= COLS || board[row][col] == '.') + break; + if (board[row][col] == color) { + if (length > 1) + return true; + break; + } + } + } + return false; + } +} + +``` + +```cpp +class Solution { +public: + bool checkMove(vector>& board, int rMove, int cMove, char color) { + int ROWS = board.size(), COLS = board[0].size(); + int direction[10] = {0, 1, 0, -1, 0, 1, 1, -1, -1, 1}; + + board[rMove][cMove] = color; + + for (int d = 0; d < 9; ++d) { + int row = rMove, col = cMove; + for (int length = 1; ; ++length) { + row += direction[d]; + col += direction[d + 1]; + + if (row < 0 || col < 0 || row >= ROWS || col >= COLS || board[row][col] == '.') + break; + if (board[row][col] == color) { + if (length > 1) + return true; + break; + } + } + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {character[][]} board + * @param {number} rMove + * @param {number} cMove + * @param {character} color + * @return {boolean} + */ + checkMove(board, rMove, cMove, color) { + const ROWS = board.length, + COLS = board[0].length; + const direction = [0, 1, 0, -1, 0, 1, 1, -1, -1, 1]; + + board[rMove][cMove] = color; + + for (let d = 0; d < 9; d++) { + let row = rMove, + col = cMove; + for (let length = 1; ; ++length) { + row += direction[d]; + col += direction[d + 1]; + + if ( + row < 0 || + col < 0 || + row >= ROWS || + col >= COLS || + board[row][col] === '.' + ) + break; + if (board[row][col] === color) { + if (length > 1) return true; + break; + } + } + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ diff --git a/articles/check-if-there-is-a-valid-partition-for-the-array.md b/articles/check-if-there-is-a-valid-partition-for-the-array.md index e855fd84d..fca7ab21e 100644 --- a/articles/check-if-there-is-a-valid-partition-for-the-array.md +++ b/articles/check-if-there-is-a-valid-partition-for-the-array.md @@ -8,17 +8,17 @@ class Solution: def dfs(i): if i == len(nums): return True - + res = False if i < len(nums) - 1 and nums[i] == nums[i + 1]: res = dfs(i + 2) if i < len(nums) - 2: - if ((nums[i] == nums[i + 1] == nums[i + 2]) or + if ((nums[i] == nums[i + 1] == nums[i + 2]) or (nums[i] + 1 == nums[i + 1] and nums[i + 1] + 1 == nums[i + 2]) ): res = res or dfs(i + 3) return res - + return dfs(0) ``` @@ -27,16 +27,16 @@ public class Solution { public boolean validPartition(int[] nums) { return dfs(nums, 0); } - + private boolean dfs(int[] nums, int i) { if (i == nums.length) return true; - + boolean res = false; if (i < nums.length - 1 && nums[i] == nums[i + 1]) { res = dfs(nums, i + 2); } if (i < nums.length - 2) { - if ((nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2]) || + if ((nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2]) || (nums[i] + 1 == nums[i + 1] && nums[i + 1] + 1 == nums[i + 2])) { res = res || dfs(nums, i + 3); } @@ -62,7 +62,7 @@ private: res = dfs(nums, i + 2); } if (i < nums.size() - 2) { - if ((nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2]) || + if ((nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2]) || (nums[i] + 1 == nums[i + 1] && nums[i + 1] + 1 == nums[i + 2])) { res = res || dfs(nums, i + 3); } @@ -87,8 +87,11 @@ class Solution { res = dfs(i + 2); } if (i < nums.length - 2) { - if ((nums[i] === nums[i + 1] && nums[i + 1] === nums[i + 2]) || - (nums[i] + 1 === nums[i + 1] && nums[i + 1] + 1 === nums[i + 2])) { + if ( + (nums[i] === nums[i + 1] && nums[i + 1] === nums[i + 2]) || + (nums[i] + 1 === nums[i + 1] && + nums[i + 1] + 1 === nums[i + 2]) + ) { res = res || dfs(i + 3); } } @@ -104,8 +107,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -120,19 +123,19 @@ class Solution: def dfs(i): if i in dp: return dp[i] - + res = False if i < len(nums) - 1 and nums[i] == nums[i + 1]: res = dfs(i + 2) if i < len(nums) - 2: - if ((nums[i] == nums[i + 1] == nums[i + 2]) or + if ((nums[i] == nums[i + 1] == nums[i + 2]) or (nums[i] + 1 == nums[i + 1] and nums[i + 1] + 1 == nums[i + 2]) ): res = res or dfs(i + 3) - + dp[i] = res return res - + return dfs(0) ``` @@ -143,22 +146,22 @@ public class Solution { public boolean validPartition(int[] nums) { return dfs(nums, 0); } - + private boolean dfs(int[] nums, int i) { if (i == nums.length) return true; if (memo.containsKey(i)) return memo.get(i); - + boolean res = false; if (i < nums.length - 1 && nums[i] == nums[i + 1]) { res = dfs(nums, i + 2); } if (i < nums.length - 2) { - if ((nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2]) || + if ((nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2]) || (nums[i] + 1 == nums[i + 1] && nums[i + 1] + 1 == nums[i + 2])) { res = res || dfs(nums, i + 3); } } - + memo.put(i, res); return res; } @@ -184,7 +187,7 @@ private: res = dfs(nums, i + 2); } if (i < nums.size() - 2) { - if ((nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2]) || + if ((nums[i] == nums[i + 1] && nums[i + 1] == nums[i + 2]) || (nums[i] + 1 == nums[i + 1] && nums[i + 1] + 1 == nums[i + 2])) { res = res || dfs(nums, i + 3); } @@ -213,8 +216,11 @@ class Solution { res = dfs(i + 2); } if (i < nums.length - 2) { - if ((nums[i] === nums[i + 1] && nums[i + 1] === nums[i + 2]) || - (nums[i] + 1 === nums[i + 1] && nums[i + 1] + 1 === nums[i + 2])) { + if ( + (nums[i] === nums[i + 1] && nums[i + 1] === nums[i + 2]) || + (nums[i] + 1 === nums[i + 1] && + nums[i + 1] + 1 === nums[i + 2]) + ) { res = res || dfs(i + 3); } } @@ -232,8 +238,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -250,7 +256,7 @@ class Solution: for i in range(2, len(nums) + 1): if nums[i - 1] == nums[i - 2]: dp[i] = dp[i] or dp[i - 2] - if i > 2 and ((nums[i - 1] == nums[i - 2] == nums[i - 3]) or + if i > 2 and ((nums[i - 1] == nums[i - 2] == nums[i - 3]) or (nums[i - 3] + 1 == nums[i - 2] and nums[i - 2] + 1 == nums[i - 1])): dp[i] = dp[i] or dp[i - 3] @@ -314,8 +320,12 @@ class Solution { if (nums[i - 1] === nums[i - 2]) { dp[i] = dp[i] || dp[i - 2]; } - if (i > 2 && ((nums[i - 1] === nums[i - 2] && nums[i - 2] === nums[i - 3]) || - (nums[i - 3] + 1 === nums[i - 2] && nums[i - 2] + 1 === nums[i - 1]))) { + if ( + i > 2 && + ((nums[i - 1] === nums[i - 2] && nums[i - 2] === nums[i - 3]) || + (nums[i - 3] + 1 === nums[i - 2] && + nums[i - 2] + 1 === nums[i - 1])) + ) { dp[i] = dp[i] || dp[i - 3]; } } @@ -329,8 +339,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -348,7 +358,7 @@ class Solution: if nums[i] == nums[i + 1] and dp[1]: dp[0] = True elif i < len(nums) - 2 and dp[2] and ( - (nums[i] == nums[i + 1] == nums[i + 2]) or + (nums[i] == nums[i + 1] == nums[i + 2]) or (nums[i] + 1 == nums[i + 1] and nums[i + 1] == nums[i + 2] - 1) ): dp[0] = True @@ -372,8 +382,8 @@ public class Solution { boolean dp1 = dp[0]; if (nums[i] == nums[i + 1] && dp[1]) { dp[0] = true; - } else if (i < nums.length - 2 && dp[2] && - ((nums[i] == nums[i + 1] && nums[i] == nums[i + 2]) || + } else if (i < nums.length - 2 && dp[2] && + ((nums[i] == nums[i + 1] && nums[i] == nums[i + 2]) || (nums[i] + 1 == nums[i + 1] && nums[i + 1] == nums[i + 2] - 1))) { dp[0] = true; } else { @@ -382,7 +392,7 @@ public class Solution { dp[2] = dp[1]; dp[1] = dp1; } - + return dp[0]; } } @@ -398,8 +408,8 @@ public: bool dp1 = dp[0]; if (nums[i] == nums[i + 1] && dp[1]) { dp[0] = true; - } else if (i < nums.size() - 2 && dp[2] && - ((nums[i] == nums[i + 1] && nums[i] == nums[i + 2]) || + } else if (i < nums.size() - 2 && dp[2] && + ((nums[i] == nums[i + 1] && nums[i] == nums[i + 2]) || (nums[i] + 1 == nums[i + 1] && nums[i + 1] == nums[i + 2] - 1))) { dp[0] = true; } else { @@ -427,9 +437,13 @@ class Solution { let dp1 = dp[0]; if (nums[i] === nums[i + 1] && dp[1]) { dp[0] = true; - } else if (i < nums.length - 2 && dp[2] && - ((nums[i] === nums[i + 1] && nums[i] === nums[i + 2]) || - (nums[i] + 1 === nums[i + 1] && nums[i + 1] === nums[i + 2] - 1))) { + } else if ( + i < nums.length - 2 && + dp[2] && + ((nums[i] === nums[i + 1] && nums[i] === nums[i + 2]) || + (nums[i] + 1 === nums[i + 1] && + nums[i + 1] === nums[i + 2] - 1)) + ) { dp[0] = true; } else { dp[0] = false; @@ -447,5 +461,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/check-if-two-string-arrays-are-equivalent.md b/articles/check-if-two-string-arrays-are-equivalent.md index 39805de58..ed6ece7b1 100644 --- a/articles/check-if-two-string-arrays-are-equivalent.md +++ b/articles/check-if-two-string-arrays-are-equivalent.md @@ -35,7 +35,7 @@ class Solution { * @return {boolean} */ arrayStringsAreEqual(word1, word2) { - return word1.join("") === word2.join(""); + return word1.join('') === word2.join(''); } } ``` @@ -44,8 +44,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ > Where $n$ and $m$ are the total number of characters in both the arrays $word1$ and $word2$, respectively. @@ -117,7 +117,7 @@ class Solution { * @return {boolean} */ arrayStringsAreEqual(word1, word2) { - let s1 = word1.join(""); + let s1 = word1.join(''); let i = 0; for (let w of word2) { @@ -137,8 +137,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n)$ > Where $n$ and $m$ are the total number of characters in both the arrays $word1$ and $word2$, respectively. @@ -235,8 +235,10 @@ class Solution { * @return {boolean} */ arrayStringsAreEqual(word1, word2) { - let w1 = 0, w2 = 0; // Index of word - let i = 0, j = 0; // Index of character + let w1 = 0, + w2 = 0; // Index of word + let i = 0, + j = 0; // Index of character while (w1 < word1.length && w2 < word2.length) { if (word1[w1][i] !== word2[w2][j]) { @@ -264,7 +266,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n + m)$ +- Space complexity: $O(1)$ extra space. -> Where $n$ and $m$ are the total number of characters in both the arrays $word1$ and $word2$, respectively. \ No newline at end of file +> Where $n$ and $m$ are the total number of characters in both the arrays $word1$ and $word2$, respectively. diff --git a/articles/cherry-pickup-ii.md b/articles/cherry-pickup-ii.md index cc5ccc3da..7dc14324b 100644 --- a/articles/cherry-pickup-ii.md +++ b/articles/cherry-pickup-ii.md @@ -12,14 +12,14 @@ class Solution: return 0 if r == ROWS - 1: return grid[r][c1] + (grid[r][c2] if c1 != c2 else 0) - + res = 0 for c1_d in [-1, 0, 1]: for c2_d in [-1, 0, 1]: res = max(res, dfs(r + 1, c1 + c1_d, c2 + c2_d)) - + return res + grid[r][c1] + (grid[r][c2] if c1 != c2 else 0) - + return dfs(0, 0, COLS - 1) ``` @@ -85,10 +85,12 @@ class Solution { * @return {number} */ cherryPickup(grid) { - const ROWS = grid.length, COLS = grid[0].length; + const ROWS = grid.length, + COLS = grid[0].length; const dfs = (r, c1, c2) => { - if (c1 < 0 || c2 < 0 || c1 >= COLS || c2 >= COLS || c1 > c2) return 0; + if (c1 < 0 || c2 < 0 || c1 >= COLS || c2 >= COLS || c1 > c2) + return 0; if (r === ROWS - 1) { return grid[r][c1] + (c1 === c2 ? 0 : grid[r][c2]); } @@ -111,8 +113,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * 9 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(m * 9 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. > Where $n$ is the number of rows and $m$ is the number of columns in the grid. @@ -135,15 +137,15 @@ class Solution: return 0 if r == ROWS - 1: return grid[r][c1] + grid[r][c2] - + res = 0 for c1_d in [-1, 0, 1]: for c2_d in [-1, 0, 1]: res = max(res, dfs(r + 1, c1 + c1_d, c2 + c2_d)) - + cache[(r, c1, c2)] = res + grid[r][c1] + (grid[r][c2] if c1 != c2 else 0) return cache[(r, c1, c2)] - + return dfs(0, 0, COLS - 1) ``` @@ -225,11 +227,10 @@ class Solution { * @return {number} */ cherryPickup(grid) { - const ROWS = grid.length, COLS = grid[0].length; + const ROWS = grid.length, + COLS = grid[0].length; const cache = Array.from({ length: ROWS }, () => - Array.from({ length: COLS }, () => - Array(COLS).fill(-1) - ) + Array.from({ length: COLS }, () => Array(COLS).fill(-1)), ); const dfs = (r, c1, c2) => { @@ -238,7 +239,8 @@ class Solution { } if (cache[r][c1][c2] !== -1) return cache[r][c1][c2]; if (r === ROWS - 1) { - return cache[r][c1][c2] = grid[r][c1] + (c1 === c2 ? 0 : grid[r][c2]); + return (cache[r][c1][c2] = + grid[r][c1] + (c1 === c2 ? 0 : grid[r][c2])); } let res = 0; @@ -247,7 +249,8 @@ class Solution { res = Math.max(res, dfs(r + 1, c1 + c1_d, c2 + c2_d)); } } - return cache[r][c1][c2] = res + grid[r][c1] + (c1 === c2 ? 0 : grid[r][c2]); + return (cache[r][c1][c2] = + res + grid[r][c1] + (c1 === c2 ? 0 : grid[r][c2])); }; return dfs(0, 0, COLS - 1); @@ -259,8 +262,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m ^ 2)$ -* Space complexity: $O(n * m ^ 2)$ +- Time complexity: $O(n * m ^ 2)$ +- Space complexity: $O(n * m ^ 2)$ > Where $n$ is the number of rows and $m$ is the number of columns in the grid. @@ -379,9 +382,10 @@ class Solution { * @return {number} */ cherryPickup(grid) { - const ROWS = grid.length, COLS = grid[0].length; + const ROWS = grid.length, + COLS = grid[0].length; const dp = Array.from({ length: ROWS }, () => - Array.from({ length: COLS }, () => Array(COLS).fill(0)) + Array.from({ length: COLS }, () => Array(COLS).fill(0)), ); for (let r = ROWS - 1; r >= 0; r--) { @@ -396,9 +400,18 @@ class Solution { let maxCherries = 0; for (let d1 = -1; d1 <= 1; d1++) { for (let d2 = -1; d2 <= 1; d2++) { - const nc1 = c1 + d1, nc2 = c2 + d2; - if (nc1 >= 0 && nc1 < COLS && nc2 >= 0 && nc2 < COLS) { - maxCherries = Math.max(maxCherries, dp[r + 1][nc1][nc2]); + const nc1 = c1 + d1, + nc2 = c2 + d2; + if ( + nc1 >= 0 && + nc1 < COLS && + nc2 >= 0 && + nc2 < COLS + ) { + maxCherries = Math.max( + maxCherries, + dp[r + 1][nc1][nc2], + ); } } } @@ -419,8 +432,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m ^ 2)$ -* Space complexity: $O(n * m ^ 2)$ +- Time complexity: $O(n * m ^ 2)$ +- Space complexity: $O(n * m ^ 2)$ > Where $n$ is the number of rows and $m$ is the number of columns in the grid. @@ -521,20 +534,33 @@ class Solution { * @return {number} */ cherryPickup(grid) { - const ROWS = grid.length, COLS = grid[0].length; + const ROWS = grid.length, + COLS = grid[0].length; let dp = Array.from({ length: COLS }, () => Array(COLS).fill(0)); for (let r = ROWS - 1; r >= 0; r--) { - const cur_dp = Array.from({ length: COLS }, () => Array(COLS).fill(0)); + const cur_dp = Array.from({ length: COLS }, () => + Array(COLS).fill(0), + ); for (let c1 = 0; c1 < COLS; c1++) { for (let c2 = c1; c2 < COLS; c2++) { let maxCherries = 0; - const cherries = grid[r][c1] + (c1 === c2 ? 0 : grid[r][c2]); + const cherries = + grid[r][c1] + (c1 === c2 ? 0 : grid[r][c2]); for (let d1 = -1; d1 <= 1; d1++) { for (let d2 = -1; d2 <= 1; d2++) { - const nc1 = c1 + d1, nc2 = c2 + d2; - if (nc1 >= 0 && nc1 < COLS && nc2 >= 0 && nc2 < COLS) { - maxCherries = Math.max(maxCherries, cherries + dp[nc1][nc2]); + const nc1 = c1 + d1, + nc2 = c2 + d2; + if ( + nc1 >= 0 && + nc1 < COLS && + nc2 >= 0 && + nc2 < COLS + ) { + maxCherries = Math.max( + maxCherries, + cherries + dp[nc1][nc2], + ); } } } @@ -553,7 +579,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m ^ 2)$ -* Space complexity: $O(m ^ 2)$ +- Time complexity: $O(n * m ^ 2)$ +- Space complexity: $O(m ^ 2)$ -> Where $n$ is the number of rows and $m$ is the number of columns in the grid. \ No newline at end of file +> Where $n$ is the number of rows and $m$ is the number of columns in the grid. diff --git a/articles/circular-sentence.md b/articles/circular-sentence.md new file mode 100644 index 000000000..f71c4dfc4 --- /dev/null +++ b/articles/circular-sentence.md @@ -0,0 +1,154 @@ +## 1. Splitting the String + +::tabs-start + +```python +class Solution: + def isCircularSentence(self, sentence: str) -> bool: + w = sentence.split(" ") + + for i in range(len(w)): + if w[i][0] != w[i - 1][-1]: + return False + + return True +``` + +```java +public class Solution { + public boolean isCircularSentence(String sentence) { + String[] w = sentence.split(" "); + int n = w.length; + + for (int i = 0; i < n; i++) { + char start = w[i].charAt(0); + char end = w[(i - 1 + n) % n].charAt(w[(i - 1 + n) % n].length() - 1); + if (start != end) { + return false; + } + } + + return true; + } +} +``` + +```cpp +class Solution { +public: + bool isCircularSentence(string sentence) { + vector w; + stringstream ss(sentence); + string word; + + while (ss >> word) { + w.push_back(word); + } + + for (int i = 0; i < w.size(); i++) { + char start = w[i][0]; + char end = w[(i - 1 + w.size()) % w.size()].back(); + if (start != end) { + return false; + } + } + + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} sentence + * @return {boolean} + */ + isCircularSentence(sentence) { + const w = sentence.split(' '); + + for (let i = 0; i < w.length; i++) { + const start = w[i][0]; + const prevEnd = w[(i - 1 + w.length) % w.length].slice(-1); + if (start !== prevEnd) { + return false; + } + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Iteration (Space Optimized) + +::tabs-start + +```python +class Solution: + def isCircularSentence(self, sentence: str) -> bool: + for i in range(len(sentence)): + if sentence[i] == " " and sentence[i - 1] != sentence[i + 1]: + return False + return sentence[0] == sentence[-1] +``` + +```java +public class Solution { + public boolean isCircularSentence(String sentence) { + for (int i = 0; i < sentence.length(); i++) { + if (sentence.charAt(i) == ' ' && sentence.charAt(i - 1) != sentence.charAt(i + 1)) { + return false; + } + } + return sentence.charAt(0) == sentence.charAt(sentence.length() - 1); + } +} +``` + +```cpp +class Solution { +public: + bool isCircularSentence(string sentence) { + for (int i = 0; i < sentence.size(); i++) { + if (sentence[i] == ' ' && sentence[i - 1] != sentence[i + 1]) { + return false; + } + } + return sentence.front() == sentence.back(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} sentence + * @return {boolean} + */ + isCircularSentence(sentence) { + for (let i = 0; i < sentence.length; i++) { + if (sentence[i] === ' ' && sentence[i - 1] !== sentence[i + 1]) { + return false; + } + } + return sentence[0] === sentence[sentence.length - 1]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/climbing-stairs.md b/articles/climbing-stairs.md index a1a70e0fa..2c4ca3de7 100644 --- a/articles/climbing-stairs.md +++ b/articles/climbing-stairs.md @@ -5,19 +5,19 @@ ```python class Solution: def climbStairs(self, n: int) -> int: - + def dfs(i): if i >= n: return i == n return dfs(i + 1) + dfs(i + 2) - + return dfs(0) ``` ```java public class Solution { public int climbStairs(int n) { - return dfs(n, 0); + return dfs(n, 0); } public int dfs(int n, int i) { @@ -48,11 +48,10 @@ class Solution { * @return {number} */ climbStairs(n) { - const dfs = (i) => { if (i >= n) return i == n; return dfs(i + 1) + dfs(i + 2); - } + }; return dfs(0); } } @@ -60,7 +59,7 @@ class Solution { ```csharp public class Solution { - public int ClimbStairs(int n) { + public int ClimbStairs(int n) { return Dfs(n, 0); } @@ -99,12 +98,27 @@ class Solution { } ``` +```swift +class Solution { + func climbStairs(_ n: Int) -> Int { + func dfs(_ i: Int) -> Int { + if i >= n { + return i == n ? 1 : 0 + } + return dfs(i + 1) + dfs(i + 2) + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -123,7 +137,7 @@ class Solution: return cache[i] cache[i] = dfs(i + 1) + dfs(i + 2) return cache[i] - + return dfs(0) ``` @@ -135,7 +149,7 @@ public class Solution { for (int i = 0; i < n; i++) { cache[i] = -1; } - return dfs(n, 0); + return dfs(n, 0); } public int dfs(int n, int i) { @@ -174,8 +188,8 @@ class Solution { const dfs = (i) => { if (i >= n) return i == n; if (cache[i] != -1) return cache[i]; - return cache[i] = dfs(i + 1) + dfs(i + 2); - } + return (cache[i] = dfs(i + 1) + dfs(i + 2)); + }; return dfs(0); } } @@ -184,11 +198,11 @@ class Solution { ```csharp public class Solution { int[] cache; - public int ClimbStairs(int n) { + public int ClimbStairs(int n) { cache = new int[n]; for (int i = 0; i < n; i++) { cache[i] = -1; - } + } return Dfs(n, 0); } @@ -240,12 +254,33 @@ class Solution { } ``` +```swift +class Solution { + func climbStairs(_ n: Int) -> Int { + var cache = Array(repeating: -1, count: n) + + func dfs(_ i: Int) -> Int { + if i >= n { + return i == n ? 1 : 0 + } + if cache[i] != -1 { + return cache[i] + } + cache[i] = dfs(i + 1) + dfs(i + 2) + return cache[i] + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -368,12 +403,29 @@ class Solution { } ``` +```swift +class Solution { + func climbStairs(_ n: Int) -> Int { + if n <= 2 { + return n + } + var dp = Array(repeating: 0, count: n + 1) + dp[1] = 1 + dp[2] = 2 + for i in 3...n { + dp[i] = dp[i - 1] + dp[i - 2] + } + return dp[n] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -390,7 +442,7 @@ class Solution: temp = one one = one + two two = temp - + return one ``` @@ -398,13 +450,13 @@ class Solution: public class Solution { public int climbStairs(int n) { int one = 1, two = 1; - + for (int i = 0; i < n - 1; i++) { int temp = one; one = one + two; two = temp; } - + return one; } } @@ -415,13 +467,13 @@ class Solution { public: int climbStairs(int n) { int one = 1, two = 1; - + for (int i = 0; i < n - 1; i++) { int temp = one; one = one + two; two = temp; } - + return one; } }; @@ -434,14 +486,15 @@ class Solution { * @return {number} */ climbStairs(n) { - let one = 1, two = 1; - + let one = 1, + two = 1; + for (let i = 0; i < n - 1; i++) { let temp = one; one = one + two; two = temp; } - + return one; } } @@ -451,13 +504,13 @@ class Solution { public class Solution { public int ClimbStairs(int n) { int one = 1, two = 1; - + for (int i = 0; i < n - 1; i++) { int temp = one; one = one + two; two = temp; } - + return one; } } @@ -495,12 +548,28 @@ class Solution { } ``` +```swift +class Solution { + func climbStairs(_ n: Int) -> Int { + var one = 1, two = 1 + + for _ in 0..<(n - 1) { + let temp = one + one = one + two + two = temp + } + + return one + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -515,13 +584,13 @@ class Solution: return 1 def matrix_mult(A, B): - return [[A[0][0] * B[0][0] + A[0][1] * B[1][0], + return [[A[0][0] * B[0][0] + A[0][1] * B[1][0], A[0][0] * B[0][1] + A[0][1] * B[1][1]], - [A[1][0] * B[0][0] + A[1][1] * B[1][0], + [A[1][0] * B[0][0] + A[1][1] * B[1][0], A[1][0] * B[0][1] + A[1][1] * B[1][1]]] def matrix_pow(M, p): - result = [[1, 0], [0, 1]] + result = [[1, 0], [0, 1]] base = M while p: @@ -558,7 +627,7 @@ public class Solution { } private int[][] matrixPow(int[][] M, int p) { - int[][] result = {{1, 0}, {0, 1}}; + int[][] result = {{1, 0}, {0, 1}}; int[][] base = M; while (p > 0) { @@ -579,13 +648,13 @@ class Solution { public: int climbStairs(int n) { if (n == 1) return 1; - + vector> M = {{1, 1}, {1, 0}}; vector> result = matrixPow(M, n); return result[0][0]; } - + private: vector> matrixMult(vector>& A, vector>& B) { return {{A[0][0] * B[0][0] + A[0][1] * B[1][0], @@ -595,7 +664,7 @@ private: } vector> matrixPow(vector>& M, int p) { - vector> result = {{1, 0}, {0, 1}}; + vector> result = {{1, 0}, {0, 1}}; vector> base = M; while (p > 0) { @@ -622,15 +691,22 @@ class Solution { const matrixMult = (A, B) => { return [ - [A[0][0] * B[0][0] + A[0][1] * B[1][0], - A[0][0] * B[0][1] + A[0][1] * B[1][1]], - [A[1][0] * B[0][0] + A[1][1] * B[1][0], - A[1][0] * B[0][1] + A[1][1] * B[1][1]] + [ + A[0][0] * B[0][0] + A[0][1] * B[1][0], + A[0][0] * B[0][1] + A[0][1] * B[1][1], + ], + [ + A[1][0] * B[0][0] + A[1][1] * B[1][0], + A[1][0] * B[0][1] + A[1][1] * B[1][1], + ], ]; }; const matrixPow = (M, p) => { - let result = [[1, 0], [0, 1]]; + let result = [ + [1, 0], + [0, 1], + ]; let base = M; while (p > 0) { @@ -644,7 +720,10 @@ class Solution { return result; }; - const M = [[1, 1], [1, 0]]; + const M = [ + [1, 1], + [1, 0], + ]; const result = matrixPow(M, n); return result[0][0]; @@ -673,7 +752,7 @@ public class Solution { } private int[,] MatrixPow(int[,] M, int p) { - int[,] result = new int[,] {{1, 0}, {0, 1}}; + int[,] result = new int[,] {{1, 0}, {0, 1}}; int[,] baseM = M; while (p > 0) { @@ -694,18 +773,18 @@ func climbStairs(n int) int { if n == 1 { return 1 } - + M := [][]int{{1, 1}, {1, 0}} result := matrixPow(M, n) - + return result[0][0] } func matrixMult(A, B [][]int) [][]int { return [][]int{ - {A[0][0]*B[0][0] + A[0][1]*B[1][0], + {A[0][0]*B[0][0] + A[0][1]*B[1][0], A[0][0]*B[0][1] + A[0][1]*B[1][1]}, - {A[1][0]*B[0][0] + A[1][1]*B[1][0], + {A[1][0]*B[0][0] + A[1][1]*B[1][0], A[1][0]*B[0][1] + A[1][1]*B[1][1]}, } } @@ -739,9 +818,9 @@ class Solution { private fun matrixMult(A: Array, B: Array): Array { return arrayOf( - intArrayOf(A[0][0] * B[0][0] + A[0][1] * B[1][0], + intArrayOf(A[0][0] * B[0][0] + A[0][1] * B[1][0], A[0][0] * B[0][1] + A[0][1] * B[1][1]), - intArrayOf(A[1][0] * B[0][0] + A[1][1] * B[1][0], + intArrayOf(A[1][0] * B[0][0] + A[1][1] * B[1][0], A[1][0] * B[0][1] + A[1][1] * B[1][1]) ) } @@ -764,12 +843,51 @@ class Solution { } ``` +```swift +class Solution { + func climbStairs(_ n: Int) -> Int { + if n == 1 { + return 1 + } + + func matrixMult(_ A: [[Int]], _ B: [[Int]]) -> [[Int]] { + return [ + [A[0][0] * B[0][0] + A[0][1] * B[1][0], + A[0][0] * B[0][1] + A[0][1] * B[1][1]], + [A[1][0] * B[0][0] + A[1][1] * B[1][0], + A[1][0] * B[0][1] + A[1][1] * B[1][1]] + ] + } + + func matrixPow(_ M: [[Int]], _ p: Int) -> [[Int]] { + var result = [[1, 0], [0, 1]] + var base = M + var power = p + + while power > 0 { + if power % 2 == 1 { + result = matrixMult(result, base) + } + base = matrixMult(base, base) + power /= 2 + } + + return result + } + + let M = [[1, 1], [1, 0]] + let result = matrixPow(M, n) + return result[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ --- @@ -824,15 +942,14 @@ class Solution { let phi = (1 + sqrt5) / 2; let psi = (1 - sqrt5) / 2; n++; - return Math.round((Math.pow(phi, n) - - Math.pow(psi, n)) / sqrt5); + return Math.round((Math.pow(phi, n) - Math.pow(psi, n)) / sqrt5); } } ``` ```csharp public class Solution { - public int ClimbStairs(int n) { + public int ClimbStairs(int n) { double sqrt5 = Math.Sqrt(5); double phi = (1 + sqrt5) / 2; double psi = (1 - sqrt5) / 2; @@ -849,7 +966,7 @@ func climbStairs(n int) int { phi := (1 + sqrt5) / 2 psi := (1 - sqrt5) / 2 n++ - return int(math.Round((math.Pow(phi, float64(n)) - + return int(math.Round((math.Pow(phi, float64(n)) - math.Pow(psi, float64(n))) / sqrt5)) } ``` @@ -865,9 +982,21 @@ class Solution { } ``` +```swift +class Solution { + func climbStairs(_ n: Int) -> Int { + let sqrt5 = sqrt(5.0) + let phi = (1.0 + sqrt5) / 2.0 + let psi = (1.0 - sqrt5) / 2.0 + let n = n + 1 + return Int(round((pow(phi, Double(n)) - pow(psi, Double(n))) / sqrt5)) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/clone-graph.md b/articles/clone-graph.md index ff2612c4c..e04f9c09b 100644 --- a/articles/clone-graph.md +++ b/articles/clone-graph.md @@ -267,24 +267,65 @@ func cloneGraph(node *Node) *Node { class Solution { fun cloneGraph(node: Node?): Node? { if (node == null) return null - + val oldToNew = HashMap() - + fun dfs(node: Node): Node { if (node in oldToNew) { return oldToNew[node]!! } - + val copy = Node(node.`val`) oldToNew[node] = copy - + for (nei in node.neighbors) { nei?.let { copy.neighbors.add(dfs(it)) } } - + + return copy + } + + return dfs(node) + } +} +``` + +```swift +/** + * Definition for a Node. + * public class Node { + * public var val: Int + * public var neighbors: [Node?] + * public init(_ val: Int) { + * self.val = val + * self.neighbors = [] + * } + * } + */ + +class Solution { + func cloneGraph(_ node: Node?) -> Node? { + var oldToNew = [Node: Node]() + + func dfs(_ node: Node?) -> Node? { + guard let node = node else { return nil } + + if let existingCopy = oldToNew[node] { + return existingCopy + } + + let copy = Node(node.val) + oldToNew[node] = copy + + for neighbor in node.neighbors { + if let clonedNeighbor = dfs(neighbor) { + copy.neighbors.append(clonedNeighbor) + } + } + return copy } - + return dfs(node) } } @@ -294,8 +335,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(V + E)$ -* Space complexity: $O(V)$ +- Time complexity: $O(V + E)$ +- Space complexity: $O(V)$ > Where $V$ is the number of vertices and $E$ is the number of edges. @@ -523,16 +564,16 @@ func cloneGraph(node *Node) *Node { if node == nil { return nil } - + oldToNew := make(map[*Node]*Node) oldToNew[node] = &Node{Val: node.Val, Neighbors: make([]*Node, 0)} queue := make([]*Node, 0) queue = append(queue, node) - + for len(queue) > 0 { cur := queue[0] queue = queue[1:] - + for _, nei := range cur.Neighbors { if _, exists := oldToNew[nei]; !exists { oldToNew[nei] = &Node{Val: nei.Val, Neighbors: make([]*Node, 0)} @@ -541,7 +582,7 @@ func cloneGraph(node *Node) *Node { oldToNew[cur].Neighbors = append(oldToNew[cur].Neighbors, oldToNew[nei]) } } - + return oldToNew[node] } ``` @@ -557,15 +598,15 @@ func cloneGraph(node *Node) *Node { class Solution { fun cloneGraph(node: Node?): Node? { if (node == null) return null - + val oldToNew = HashMap() oldToNew[node] = Node(node.`val`) val queue = ArrayDeque() queue.add(node) - + while (queue.isNotEmpty()) { val cur = queue.removeFirst() - + for (nei in cur.neighbors) { nei?.let { neighbor -> if (neighbor !in oldToNew) { @@ -576,17 +617,60 @@ class Solution { } } } - + return oldToNew[node] } } ``` +```swift +/** + * Definition for a Node. + * public class Node { + * public var val: Int + * public var neighbors: [Node?] + * public init(_ val: Int) { + * self.val = val + * self.neighbors = [] + * } + * } + */ + +class Solution { + func cloneGraph(_ node: Node?) -> Node? { + if node == nil { + return nil + } + + var oldToNew: [Node: Node] = [:] + let newNode = Node(node!.val) + oldToNew[node!] = newNode + var queue = Deque() + queue.append(node!) + + while !queue.isEmpty { + let cur = queue.popFirst()! + for nei in cur.neighbors { + if let nei = nei { + if oldToNew[nei] == nil { + oldToNew[nei] = Node(nei.val) + queue.append(nei) + } + oldToNew[cur]!.neighbors.append(oldToNew[nei]!) + } + } + } + + return oldToNew[node!] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V + E)$ -* Space complexity: $O(V)$ +- Time complexity: $O(V + E)$ +- Space complexity: $O(V)$ -> Where $V$ is the number of vertices and $E$ is the number of edges. \ No newline at end of file +> Where $V$ is the number of vertices and $E$ is the number of edges. diff --git a/articles/coin-change-ii.md b/articles/coin-change-ii.md index cdfd83983..0aaa6b61c 100644 --- a/articles/coin-change-ii.md +++ b/articles/coin-change-ii.md @@ -84,7 +84,7 @@ class Solution { */ change(amount, coins) { coins.sort((a, b) => a - b); - + const dfs = (i, a) => { if (a === 0) return 1; if (i >= coins.length) return 0; @@ -129,7 +129,7 @@ public class Solution { ```go func change(amount int, coins []int) int { - sort.Ints(coins) + sort.Ints(coins) var dfs func(i, a int) int dfs = func(i, a int) int { @@ -155,7 +155,7 @@ func change(amount int, coins []int) int { ```kotlin class Solution { fun change(amount: Int, coins: IntArray): Int { - coins.sort() + coins.sort() fun dfs(i: Int, a: Int): Int { if (a == 0) { @@ -178,12 +178,38 @@ class Solution { } ``` +```swift +class Solution { + func change(_ amount: Int, _ coins: [Int]) -> Int { + let coins = coins.sorted() + + func dfs(_ i: Int, _ a: Int) -> Int { + if a == 0 { + return 1 + } + if i >= coins.count { + return 0 + } + + var res = 0 + if a >= coins[i] { + res = dfs(i + 1, a) + res += dfs(i, a - coins[i]) + } + return res + } + + return dfs(0, amount) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ {max(n, \frac{a}{m})})$ -* Space complexity: $O(max(n, \frac{a}{m}))$ +- Time complexity: $O(2 ^ {max(n, \frac{a}{m})})$ +- Space complexity: $O(max(n, \frac{a}{m}))$ > Where $n$ is the number of coins, $a$ is the given amount and $m$ is the minimum value among all the coins. @@ -206,7 +232,7 @@ class Solution: return 0 if memo[i][a] != -1: return memo[i][a] - + res = 0 if a >= coins[i]: res = dfs(i + 1, a) @@ -251,7 +277,7 @@ class Solution { public: int change(int amount, vector& coins) { sort(coins.begin(), coins.end()); - vector> memo(coins.size() + 1, + vector> memo(coins.size() + 1, vector(amount + 1, -1)); return dfs(0, amount, coins, memo); @@ -283,7 +309,8 @@ class Solution { change(amount, coins) { coins.sort((a, b) => a - b); let memo = Array.from({ length: coins.length + 1 }, () => - Array(amount + 1).fill(-1)); + Array(amount + 1).fill(-1), + ); const dfs = (i, a) => { if (a === 0) return 1; @@ -399,12 +426,44 @@ class Solution { } ``` +```swift +class Solution { + func change(_ amount: Int, _ coins: [Int]) -> Int { + let coins = coins.sorted() + var memo = Array(repeating: Array(repeating: -1, count: amount + 1), count: coins.count + 1) + + func dfs(_ i: Int, _ a: Int) -> Int { + if a == 0 { + return 1 + } + if i >= coins.count { + return 0 + } + if memo[i][a] != -1 { + return memo[i][a] + } + + var res = 0 + if a >= coins[i] { + res = dfs(i + 1, a) + res += dfs(i, a - coins[i]) + } + + memo[i][a] = res + return res + } + + return dfs(0, amount) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * a)$ -* Space complexity: $O(n * a)$ +- Time complexity: $O(n * a)$ +- Space complexity: $O(n * a)$ > Where $n$ is the number of coins and $a$ is the given amount. @@ -420,15 +479,15 @@ class Solution: n = len(coins) coins.sort() dp = [[0] * (amount + 1) for _ in range(n + 1)] - + for i in range(n + 1): dp[i][0] = 1 - + for i in range(n - 1, -1, -1): for a in range(amount + 1): if a >= coins[i]: - dp[i][a] = dp[i + 1][a] - dp[i][a] += dp[i][a - coins[i]] + dp[i][a] = dp[i + 1][a] + dp[i][a] += dp[i][a - coins[i]] return dp[0][amount] ``` @@ -464,8 +523,8 @@ public: int change(int amount, vector& coins) { int n = coins.size(); sort(coins.begin(), coins.end()); - vector> dp(n + 1, vector(amount + 1, 0)); - + vector> dp(n + 1, vector(amount + 1, 0)); + for (int i = 0; i <= n; i++) { dp[i][0] = 1; } @@ -494,7 +553,9 @@ class Solution { change(amount, coins) { coins.sort((a, b) => a - b); const n = coins.length; - const dp = Array.from({ length: n + 1 }, () => Array(amount + 1).fill(0)); + const dp = Array.from({ length: n + 1 }, () => + Array(amount + 1).fill(0), + ); for (let i = 0; i <= n; i++) { dp[i][0] = 1; @@ -554,8 +615,8 @@ func change(amount int, coins []int) int { for i := n - 1; i >= 0; i-- { for a := 0; a <= amount; a++ { if a >= coins[i] { - dp[i][a] = dp[i+1][a] - dp[i][a] += dp[i][a-coins[i]] + dp[i][a] = dp[i+1][a] + dp[i][a] += dp[i][a-coins[i]] } else { dp[i][a] = dp[i+1][a] } @@ -579,10 +640,45 @@ class Solution { for (i in n - 1 downTo 0) { for (a in 0..amount) { if (a >= coins[i]) { - dp[i][a] = dp[i + 1][a] - dp[i][a] += dp[i][a - coins[i]] + dp[i][a] = dp[i + 1][a] + dp[i][a] += dp[i][a - coins[i]] } else { - dp[i][a] = dp[i + 1][a] + dp[i][a] = dp[i + 1][a] + } + } + } + + return dp[0][amount] + } +} +``` + +```swift +class Solution { + func change(_ amount: Int, _ coins: [Int]) -> Int { + let n = coins.count + let sortedCoins = coins.sorted() + var dp = Array( + repeating: Array(repeating: 0, count: amount + 1), + count: n + 1 + ) + + for i in 0...n { + dp[i][0] = 1 + } + + for i in stride(from: n - 1, through: 0, by: -1) { + for a in 0...amount { + let base = dp[i + 1][a] + if a >= sortedCoins[i] { + let addend = dp[i][a - sortedCoins[i]] + if base > Int.max - addend { + dp[i][a] = 0 + } else { + dp[i][a] = base + addend + } + } else { + dp[i][a] = base } } } @@ -596,8 +692,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * a)$ -* Space complexity: $O(n * a)$ +- Time complexity: $O(n * a)$ +- Space complexity: $O(n * a)$ > Where $n$ is the number of coins and $a$ is the given amount. @@ -650,10 +746,10 @@ public class Solution { class Solution { public: int change(int amount, vector& coins) { - vector dp(amount + 1, 0); + vector dp(amount + 1, 0); dp[0] = 1; for (int i = coins.size() - 1; i >= 0; i--) { - vector nextDP(amount + 1, 0); + vector nextDP(amount + 1, 0); nextDP[0] = 1; for (int a = 1; a <= amount; a++) { @@ -764,12 +860,42 @@ class Solution { } ``` +```swift +class Solution { + func change(_ amount: Int, _ coins: [Int]) -> Int { + var dp = [Int](repeating: 0, count: amount + 1) + dp[0] = 1 + + for i in stride(from: coins.count - 1, through: 0, by: -1) { + var nextDP = [Int](repeating: 0, count: amount + 1) + nextDP[0] = 1 + + for a in 1..<(amount + 1) { + nextDP[a] = dp[a] + if a - coins[i] >= 0 { + let addend = nextDP[a - coins[i]] + if nextDP[a] > Int.max - addend { + nextDP[a] = 0 + } else { + nextDP[a] += addend + } + } + } + + dp = nextDP + } + + return dp[amount] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * a)$ -* Space complexity: $O(a)$ +- Time complexity: $O(n * a)$ +- Space complexity: $O(a)$ > Where $n$ is the number of coins and $a$ is the given amount. @@ -793,12 +919,12 @@ class Solution: ```java public class Solution { public int change(int amount, int[] coins) { - int[] dp = new int[amount + 1]; + int[] dp = new int[amount + 1]; dp[0] = 1; for (int i = coins.length - 1; i >= 0; i--) - for (int a = 1; a <= amount; a++) + for (int a = 1; a <= amount; a++) dp[a] = dp[a] + (coins[i] <= a ? dp[a - coins[i]] : 0); - return dp[amount]; + return dp[amount]; } } ``` @@ -807,7 +933,7 @@ public class Solution { class Solution { public: int change(int amount, vector& coins) { - vector dp(amount + 1, 0); + vector dp(amount + 1, 0); dp[0] = 1; for (int i = coins.size() - 1; i >= 0; i--) { for (int a = 1; a <= amount; a++) { @@ -831,7 +957,7 @@ class Solution { dp[0] = 1; for (let i = coins.length - 1; i >= 0; i--) { for (let a = 1; a <= amount; a++) { - dp[a] += (coins[i] <= a ? dp[a - coins[i]] : 0); + dp[a] += coins[i] <= a ? dp[a - coins[i]] : 0; } } return dp[amount]; @@ -890,11 +1016,35 @@ class Solution { } ``` +```swift +class Solution { + func change(_ amount: Int, _ coins: [Int]) -> Int { + var dp = [Int](repeating: 0, count: amount + 1) + dp[0] = 1 + + for i in stride(from: coins.count - 1, through: 0, by: -1) { + for a in 1..<(amount + 1) { + if coins[i] <= a { + let addend = dp[a - coins[i]] + if dp[a] > Int.max - addend { + dp[a] = 0 + } else { + dp[a] += addend + } + } + } + } + + return dp[amount] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * a)$ -* Space complexity: $O(a)$ +- Time complexity: $O(n * a)$ +- Space complexity: $O(a)$ -> Where $n$ is the number of coins and $a$ is the given amount. \ No newline at end of file +> Where $n$ is the number of coins and $a$ is the given amount. diff --git a/articles/coin-change.md b/articles/coin-change.md index eb1f7e715..a4a16fa85 100644 --- a/articles/coin-change.md +++ b/articles/coin-change.md @@ -5,11 +5,11 @@ ```python class Solution: def coinChange(self, coins: List[int], amount: int) -> int: - + def dfs(amount): if amount == 0: return 0 - + res = 1e9 for coin in coins: if amount - coin >= 0: @@ -28,7 +28,7 @@ public class Solution { int res = (int) 1e9; for (int coin : coins) { if (amount - coin >= 0) { - res = Math.min(res, + res = Math.min(res, 1 + dfs(coins, amount - coin)); } } @@ -47,11 +47,11 @@ class Solution { public: int dfs(vector& coins, int amount) { if (amount == 0) return 0; - + int res = 1e9; for (int coin : coins) { if (amount - coin >= 0) { - res = min(res, + res = min(res, 1 + dfs(coins, amount - coin)); } } @@ -73,19 +73,17 @@ class Solution { * @return {number} */ coinChange(coins, amount) { - const dfs = (amount) => { if (amount === 0) return 0; let res = Infinity; for (let coin of coins) { if (amount - coin >= 0) { - res = Math.min(res, - 1 + dfs(amount - coin)); + res = Math.min(res, 1 + dfs(amount - coin)); } } return res; - } + }; const minCoins = dfs(amount); return minCoins === Infinity ? -1 : minCoins; @@ -101,7 +99,7 @@ public class Solution { int res = (int)1e9; foreach (var coin in coins) { if (amount - coin >= 0) { - res = Math.Min(res, + res = Math.Min(res, 1 + Dfs(coins, amount - coin)); } } @@ -122,14 +120,14 @@ func coinChange(coins []int, amount int) int { if amt == 0 { return 0 } - + res := math.MaxInt32 for _, coin := range coins { if amt - coin >= 0 { res = min(res, 1 + dfs(amt - coin)) } } - + return res } @@ -170,12 +168,35 @@ class Solution { } ``` +```swift +class Solution { + func coinChange(_ coins: [Int], _ amount: Int) -> Int { + func dfs(_ amount: Int) -> Int { + if amount == 0 { + return 0 + } + + var res = Int(1e9) + for coin in coins { + if amount - coin >= 0 { + res = min(res, 1 + dfs(amount - coin)) + } + } + return res + } + + let minCoins = dfs(amount) + return minCoins >= Int(1e9) ? -1 : minCoins + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ t)$ -* Space complexity: $O(t)$ +- Time complexity: $O(n ^ t)$ +- Space complexity: $O(t)$ > Where $n$ is the length of the array $coins$ and $t$ is the given $amount$. @@ -195,15 +216,15 @@ class Solution: return 0 if amount in memo: return memo[amount] - + res = 1e9 for coin in coins: if amount - coin >= 0: res = min(res, 1 + dfs(amount - coin)) - + memo[amount] = res return res - + minCoins = dfs(amount) return -1 if minCoins >= 1e9 else minCoins ``` @@ -214,7 +235,7 @@ public class Solution { public int dfs(int amount, int[] coins) { if (amount == 0) return 0; - if (memo.containsKey(amount)) + if (memo.containsKey(amount)) return memo.get(amount); int res = Integer.MAX_VALUE; @@ -226,7 +247,7 @@ public class Solution { } } } - + memo.put(amount, res); return res; } @@ -244,7 +265,7 @@ public: unordered_map memo; int dfs(int amount, vector& coins) { if (amount == 0) return 0; - if (memo.find(amount) != memo.end()) + if (memo.find(amount) != memo.end()) return memo[amount]; int res = INT_MAX; @@ -256,7 +277,7 @@ public: } } } - + memo[amount] = res; return res; } @@ -280,8 +301,7 @@ class Solution { const dfs = (amount) => { if (amount === 0) return 0; - if (memo[amount] !== undefined) - return memo[amount]; + if (memo[amount] !== undefined) return memo[amount]; let res = Infinity; for (let coin of coins) { @@ -292,7 +312,7 @@ class Solution { memo[amount] = res; return res; - } + }; const minCoins = dfs(amount); return minCoins === Infinity ? -1 : minCoins; @@ -306,7 +326,7 @@ public class Solution { private int Dfs(int amount, int[] coins) { if (amount == 0) return 0; - if (memo.ContainsKey(amount)) + if (memo.ContainsKey(amount)) return memo[amount]; int res = int.MaxValue; @@ -318,7 +338,7 @@ public class Solution { } } } - + memo[amount] = res; return res; } @@ -340,7 +360,7 @@ func coinChange(coins []int, amount int) int { if val, ok := memo[amt]; ok { return val } - + res := math.MaxInt32 for _, coin := range coins { if amt - coin >= 0 { @@ -393,12 +413,42 @@ class Solution { } ``` +```swift +class Solution { + func coinChange(_ coins: [Int], _ amount: Int) -> Int { + var memo = [Int: Int]() + + func dfs(_ amount: Int) -> Int { + if amount == 0 { + return 0 + } + if let cached = memo[amount] { + return cached + } + + var res = Int(1e9) + for coin in coins { + if amount - coin >= 0 { + res = min(res, 1 + dfs(amount - coin)) + } + } + + memo[amount] = res + return res + } + + let minCoins = dfs(amount) + return minCoins >= Int(1e9) ? -1 : minCoins + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * t)$ -* Space complexity: $O(t)$ +- Time complexity: $O(n * t)$ +- Space complexity: $O(t)$ > Where $n$ is the length of the array $coins$ and $t$ is the given $amount$. @@ -542,12 +592,35 @@ class Solution { } ``` +```swift +class Solution { + func coinChange(_ coins: [Int], _ amount: Int) -> Int { + if amount == 0 { + return 0 + } + + var dp = [Int](repeating: amount + 1, count: amount + 1) + dp[0] = 0 + + for a in 1...amount { + for coin in coins { + if a - coin >= 0 { + dp[a] = min(dp[a], 1 + dp[a - coin]) + } + } + } + + return dp[amount] == amount + 1 ? -1 : dp[amount] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * t)$ -* Space complexity: $O(t)$ +- Time complexity: $O(n * t)$ +- Space complexity: $O(t)$ > Where $n$ is the length of the array $coins$ and $t$ is the given $amount$. @@ -566,7 +639,7 @@ class Solution: q = deque([0]) seen = [False] * (amount + 1) seen[0] = True - res = 0 + res = 0 while q: res += 1 @@ -772,11 +845,46 @@ class Solution { } ``` +```swift +class Solution { + func coinChange(_ coins: [Int], _ amount: Int) -> Int { + if amount == 0 { + return 0 + } + + var q = Deque([0]) + var seen = Array(repeating: false, count: amount + 1) + seen[0] = true + var res = 0 + + while !q.isEmpty { + res += 1 + for _ in 0.. amount || seen[nxt] { + continue + } + seen[nxt] = true + q.append(nxt) + } + } + } + + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * t)$ -* Space complexity: $O(t)$ +- Time complexity: $O(n * t)$ +- Space complexity: $O(t)$ -> Where $n$ is the length of the array $coins$ and $t$ is the given $amount$. \ No newline at end of file +> Where $n$ is the length of the array $coins$ and $t$ is the given $amount$. diff --git a/articles/combination-sum-iv.md b/articles/combination-sum-iv.md index 3a607251c..b96dd0b4d 100644 --- a/articles/combination-sum-iv.md +++ b/articles/combination-sum-iv.md @@ -6,18 +6,18 @@ class Solution: def combinationSum4(self, nums: List[int], target: int) -> int: nums.sort() - + def dfs(total): if total == 0: return 1 - + res = 0 for i in range(len(nums)): if total < nums[i]: break res += dfs(total - nums[i]) return res - + return dfs(target) ``` @@ -28,12 +28,12 @@ public class Solution { return dfs(nums, target); } - + private int dfs(int[] nums, int total) { if (total == 0) { return 1; } - + int res = 0; for (int num : nums) { if (total < num) { @@ -53,12 +53,12 @@ public: sort(nums.begin(), nums.end()); return dfs(nums, target); } - + int dfs(vector& nums, int total) { if (total == 0) { return 1; } - + int res = 0; for (int num : nums) { if (total < num) { @@ -80,10 +80,10 @@ class Solution { */ combinationSum4(nums, target) { nums.sort((a, b) => a - b); - + const dfs = (total) => { if (total === 0) return 1; - + let res = 0; for (let num of nums) { if (total < num) break; @@ -97,12 +97,37 @@ class Solution { } ``` +```csharp +public class Solution { + public int CombinationSum4(int[] nums, int target) { + Array.Sort(nums); + return Dfs(nums, target); + } + + private int Dfs(int[] nums, int total) { + if (total == 0) { + return 1; + } + + int res = 0; + foreach (int num in nums) { + if (total < num) { + break; + } + res += Dfs(nums, total - num); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ t)$ -* Space complexity: $O(t)$ +- Time complexity: $O(n ^ t)$ +- Space complexity: $O(t)$ > Where $n$ is the size of the array $nums$ and $t$ is the given target. @@ -121,7 +146,7 @@ class Solution: def dfs(total): if total in memo: return memo[total] - + res = 0 for num in nums: if total < num: @@ -129,7 +154,7 @@ class Solution: res += dfs(total - num) memo[total] = res return res - + return dfs(target) ``` @@ -143,12 +168,12 @@ public class Solution { memo.put(0, 1); return dfs(nums, target); } - + private int dfs(int[] nums, int total) { if (memo.containsKey(total)) { return memo.get(total); } - + int res = 0; for (int num : nums) { if (total < num) { @@ -201,7 +226,7 @@ class Solution { */ combinationSum4(nums, target) { nums.sort((a, b) => a - b); - const memo = { 0 : 1 }; + const memo = { 0: 1 }; const dfs = (total) => { if (memo[total] !== undefined) { @@ -222,12 +247,42 @@ class Solution { } ``` +```csharp +public class Solution { + private Dictionary memo; + + public int CombinationSum4(int[] nums, int target) { + Array.Sort(nums); + memo = new Dictionary(); + memo[0] = 1; + return Dfs(nums, target); + } + + private int Dfs(int[] nums, int total) { + if (memo.ContainsKey(total)) { + return memo[total]; + } + + int res = 0; + foreach (int num in nums) { + if (total < num) { + break; + } + res += Dfs(nums, total - num); + } + + memo[total] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * t)$ -* Space complexity: $O(t)$ +- Time complexity: $O(n * t)$ +- Space complexity: $O(t)$ > Where $n$ is the size of the array $nums$ and $t$ is the given target. @@ -246,7 +301,7 @@ class Solution: dp[total] = 0 for num in nums: dp[total] += dp.get(total - num, 0) - + return dp[target] ``` @@ -255,7 +310,7 @@ public class Solution { public int combinationSum4(int[] nums, int target) { Map dp = new HashMap<>(); dp.put(0, 1); - + for (int total = 1; total <= target; total++) { dp.put(total, 0); for (int num : nums) { @@ -273,7 +328,7 @@ public: int combinationSum4(vector& nums, int target) { unordered_map dp; dp[0] = 1; - + for (int total = 1; total <= target; total++) { dp[total] = 0; for (int num : nums) { @@ -298,7 +353,7 @@ class Solution { * @return {number} */ combinationSum4(nums, target) { - let dp = {0: 1}; + let dp = { 0: 1 }; for (let total = 1; total <= target; total++) { dp[total] = 0; for (let num of nums) { @@ -310,12 +365,32 @@ class Solution { } ``` +```csharp +public class Solution { + public int CombinationSum4(int[] nums, int target) { + Dictionary dp = new Dictionary(); + dp[0] = 1; + + for (int total = 1; total <= target; total++) { + dp[total] = 0; + foreach (int num in nums) { + if (dp.ContainsKey(total - num)) { + dp[total] += dp[total - num]; + } + } + } + + return dp[target]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * t)$ -* Space complexity: $O(t)$ +- Time complexity: $O(n * t)$ +- Space complexity: $O(t)$ > Where $n$ is the size of the array $nums$ and $t$ is the given target. @@ -395,7 +470,10 @@ class Solution { for (let total = target; total > 0; total--) { for (const num of nums) { if (total < num) break; - dp.set(total - num, (dp.get(total - num) || 0) + (dp.get(total) || 0)); + dp.set( + total - num, + (dp.get(total - num) || 0) + (dp.get(total) || 0), + ); } } return dp.get(0) || 0; @@ -403,11 +481,35 @@ class Solution { } ``` +```csharp +public class Solution { + public int CombinationSum4(int[] nums, int target) { + Array.Sort(nums); + Dictionary dp = new Dictionary(); + dp[target] = 1; + + for (int total = target; total > 0; total--) { + if (!dp.ContainsKey(total)) continue; + foreach (int num in nums) { + if (total < num) break; + int key = total - num; + if (!dp.ContainsKey(key)) { + dp[key] = 0; + } + dp[key] += dp[total]; + } + } + + return dp.ContainsKey(0) ? dp[0] : 0; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * t)$ -* Space complexity: $O(t)$ +- Time complexity: $O(n * t)$ +- Space complexity: $O(t)$ -> Where $n$ is the size of the array $nums$ and $t$ is the given target. \ No newline at end of file +> Where $n$ is the size of the array $nums$ and $t$ is the given target. diff --git a/articles/combination-target-sum-ii.md b/articles/combination-target-sum-ii.md index 0c9a90f24..da1e85b65 100644 --- a/articles/combination-target-sum-ii.md +++ b/articles/combination-target-sum-ii.md @@ -10,7 +10,7 @@ class Solution: def generate_subsets(i, cur, total): if total == target: - res.add(tuple(cur)) + res.add(tuple(cur)) return if total > target or i == len(candidates): return @@ -22,7 +22,7 @@ class Solution: generate_subsets(i + 1, cur, total) generate_subsets(0, [], 0) - return [list(combination) for combination in res] + return [list(combination) for combination in res] ``` ```java @@ -101,7 +101,7 @@ class Solution { this.res.clear(); candidates.sort((a, b) => a - b); this.generateSubsets(candidates, target, 0, [], 0); - return Array.from(this.res, subset => JSON.parse(subset)); + return Array.from(this.res, (subset) => JSON.parse(subset)); } /** @@ -122,7 +122,13 @@ class Solution { } cur.push(candidates[i]); - this.generateSubsets(candidates, target, i + 1, cur, total + candidates[i]); + this.generateSubsets( + candidates, + target, + i + 1, + cur, + total + candidates[i], + ); cur.pop(); this.generateSubsets(candidates, target, i + 1, cur, total); @@ -216,12 +222,41 @@ class Solution { } ``` +```swift +class Solution { + func combinationSum2(_ candidates: [Int], _ target: Int) -> [[Int]] { + var res = Set<[Int]>() + let sortedCandidates = candidates.sorted() + + func generateSubsets(_ i: Int, _ cur: inout [Int], _ total: Int) { + if total == target { + res.insert(cur) + return + } + if total > target || i == sortedCandidates.count { + return + } + + cur.append(sortedCandidates[i]) + generateSubsets(i + 1, &cur, total + sortedCandidates[i]) + cur.removeLast() + + generateSubsets(i + 1, &cur, total) + } + + var cur: [Int] = [] + generateSubsets(0, &cur, 0) + return Array(res) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n * 2 ^ n)$ +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: $O(n * 2 ^ n)$ --- @@ -241,16 +276,16 @@ class Solution: return if total > target or i == len(candidates): return - + cur.append(candidates[i]) dfs(i + 1, cur, total + candidates[i]) cur.pop() - + while i + 1 < len(candidates) and candidates[i] == candidates[i+1]: i += 1 dfs(i + 1, cur, total) - + dfs(0, [], 0) return res ``` @@ -360,7 +395,10 @@ class Solution { this.dfs(candidates, target, i + 1, cur, total + candidates[i]); cur.pop(); - while (i + 1 < candidates.length && candidates[i] === candidates[i + 1]) { + while ( + i + 1 < candidates.length && + candidates[i] === candidates[i + 1] + ) { i++; } this.dfs(candidates, target, i + 1, cur, total); @@ -464,12 +502,45 @@ class Solution { } ``` +```swift +class Solution { + func combinationSum2(_ candidates: [Int], _ target: Int) -> [[Int]] { + var res = [[Int]]() + let sortedCandidates = candidates.sorted() + + func dfs(_ i: Int, _ cur: inout [Int], _ total: Int) { + if total == target { + res.append(cur) + return + } + if total > target || i == sortedCandidates.count { + return + } + + cur.append(sortedCandidates[i]) + dfs(i + 1, &cur, total + sortedCandidates[i]) + cur.removeLast() + + var j = i + while j + 1 < sortedCandidates.count && sortedCandidates[j] == sortedCandidates[j + 1] { + j += 1 + } + dfs(j + 1, &cur, total) + } + + var cur: [Int] = [] + dfs(0, &cur, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * 2 ^n)$ +- Space complexity: $O(n)$ --- @@ -484,7 +555,7 @@ class Solution: self.count = defaultdict(int) cur = [] A = [] - + for num in nums: if self.count[num] == 0: A.append(num) @@ -498,7 +569,7 @@ class Solution: return if target < 0 or i >= len(nums): return - + if self.count[nums[i]] > 0: cur.append(nums[i]) self.count[nums[i]] -= 1 @@ -513,11 +584,11 @@ class Solution: public class Solution { List> res = new ArrayList<>(); Map count = new HashMap<>(); - + public List> combinationSum2(int[] nums, int target) { List cur = new ArrayList<>(); List A = new ArrayList<>(); - + for (int num : nums) { if (!count.containsKey(num)) { A.add(num); @@ -605,7 +676,7 @@ class Solution { combinationSum2(nums, target) { const cur = []; const A = []; - + for (const num of nums) { if (!this.count.has(num)) { A.push(num); @@ -616,7 +687,7 @@ class Solution { return this.res; } - /** + /** * @param {number[]} nums * @param {number} target * @param {number[]} cur @@ -653,7 +724,7 @@ public class Solution { public List> CombinationSum2(int[] nums, int target) { List cur = new List(); List A = new List(); - + foreach (int num in nums) { if (!count.ContainsKey(num)) { A.Add(num); @@ -714,7 +785,7 @@ func combinationSum2(nums []int, target int) [][]int { if target < 0 || i >= len(uniqueNums) { return } - + if count[uniqueNums[i]] > 0 { cur = append(cur, uniqueNums[i]) count[uniqueNums[i]]-- @@ -758,7 +829,7 @@ class Solution { if (target < 0 || i >= nums.size) { return } - + if (count[nums[i]] ?: 0 > 0) { cur.add(nums[i]) count[nums[i]] = count[nums[i]]!! - 1 @@ -772,12 +843,53 @@ class Solution { } ``` +```swift +class Solution { + func combinationSum2(_ nums: [Int], _ target: Int) -> [[Int]] { + var res = [[Int]]() + var count = [Int: Int]() + var uniqueNums = [Int]() + + for num in nums { + if count[num] == nil { + uniqueNums.append(num) + } + count[num, default: 0] += 1 + } + + func backtrack(_ nums: [Int], _ target: Int, _ cur: inout [Int], _ i: Int) { + if target == 0 { + res.append(cur) + return + } + if target < 0 || i >= nums.count { + return + } + + if count[nums[i], default: 0] > 0 { + cur.append(nums[i]) + count[nums[i], default: 0] -= 1 + backtrack(nums, target - nums[i], &cur, i) + count[nums[i], default: 0] += 1 + cur.removeLast() + } + + backtrack(nums, target, &cur, i + 1) + } + + var cur: [Int] = [] + backtrack(uniqueNums, target, &cur, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -1008,9 +1120,42 @@ class Solution { } ``` +```swift +class Solution { + func combinationSum2(_ candidates: [Int], _ target: Int) -> [[Int]] { + var res = [[Int]]() + let sortedCandidates = candidates.sorted() + + func dfs(_ idx: Int, _ path: inout [Int], _ cur: Int) { + if cur == target { + res.append(path) + return + } + + for i in idx.. idx && sortedCandidates[i] == sortedCandidates[i - 1] { + continue + } + if cur + sortedCandidates[i] > target { + break + } + + path.append(sortedCandidates[i]) + dfs(i + 1, &path, cur + sortedCandidates[i]) + path.removeLast() + } + } + + var path: [Int] = [] + dfs(0, &path, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: $O(n)$ diff --git a/articles/combination-target-sum.md b/articles/combination-target-sum.md index 43a9f3cd1..562cfac27 100644 --- a/articles/combination-target-sum.md +++ b/articles/combination-target-sum.md @@ -116,7 +116,7 @@ class Solution { ```csharp public class Solution { - + List> res = new List>(); public void backtrack(int i, List cur, int total, int[] nums, int target) { @@ -124,15 +124,15 @@ public class Solution { res.Add(cur.ToList()); return; } - + if(total > target || i >= nums.Length) return; - + cur.Add(nums[i]); backtrack(i, cur, total + nums[i], nums, target); cur.Remove(cur.Last()); backtrack(i + 1, cur, total, nums, target); - + } public List> CombinationSum(int[] nums, int target) { backtrack(0, new List(), 0, nums, target); @@ -194,12 +194,39 @@ class Solution { } ``` +```swift +class Solution { + func combinationSum(_ nums: [Int], _ target: Int) -> [[Int]] { + var res: [[Int]] = [] + + func dfs(_ i: Int, _ cur: inout [Int], _ total: Int) { + if total == target { + res.append(cur) + return + } + if i >= nums.count || total > target { + return + } + + cur.append(nums[i]) + dfs(i, &cur, total + nums[i]) + cur.removeLast() + dfs(i + 1, &cur, total) + } + + var cur: [Int] = [] + dfs(0, &cur, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ \frac{t}{m})$ -* Space complexity: $O(\frac{t}{m})$ +- Time complexity: $O(2 ^ \frac{t}{m})$ +- Space complexity: $O(\frac{t}{m})$ > Where $t$ is the given $target$ and $m$ is the minimum value in $nums$. @@ -219,14 +246,14 @@ class Solution: if total == target: res.append(cur.copy()) return - + for j in range(i, len(nums)): if total + nums[j] > target: return cur.append(nums[j]) dfs(j, cur, total + nums[j]) cur.pop() - + dfs(0, [], 0) return res ``` @@ -237,7 +264,7 @@ public class Solution { public List> combinationSum(int[] nums, int target) { res = new ArrayList<>(); Arrays.sort(nums); - + dfs(0, new ArrayList<>(), 0, nums, target); return res; } @@ -247,7 +274,7 @@ public class Solution { res.add(new ArrayList<>(cur)); return; } - + for (int j = i; j < nums.length; j++) { if (total + nums[j] > target) { return; @@ -275,7 +302,7 @@ public: res.push_back(cur); return; } - + for (int j = i; j < nums.size(); j++) { if (total + nums[j] > target) { return; @@ -298,13 +325,13 @@ class Solution { combinationSum(nums, target) { const res = []; nums.sort((a, b) => a - b); - + const dfs = (i, cur, total) => { if (total === target) { res.push([...cur]); return; } - + for (let j = i; j < nums.length; j++) { if (total + nums[j] > target) { return; @@ -314,7 +341,7 @@ class Solution { cur.pop(); } }; - + dfs(0, [], 0); return res; } @@ -336,7 +363,7 @@ public class Solution { res.Add(new List(cur)); return; } - + for (int j = i; j < nums.Length; j++) { if (total + nums[j] > target) { return; @@ -362,7 +389,7 @@ func combinationSum(nums []int, target int) [][]int { res = append(res, temp) return } - + for j := i; j < len(nums); j++ { if total + nums[j] > target { return @@ -389,7 +416,7 @@ class Solution { res.add(ArrayList(cur)) return } - + for (j in i until nums.size) { if (total + nums[j] > target) { return @@ -406,11 +433,40 @@ class Solution { } ``` +```swift +class Solution { + func combinationSum(_ nums: [Int], _ target: Int) -> [[Int]] { + var res: [[Int]] = [] + let sortedNums = nums.sorted() + + func dfs(_ i: Int, _ cur: inout [Int], _ total: Int) { + if total == target { + res.append(cur) + return + } + + for j in i.. target { + return + } + cur.append(sortedNums[j]) + dfs(j, &cur, total + sortedNums[j]) + cur.removeLast() + } + } + + var cur: [Int] = [] + dfs(0, &cur, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ \frac{t}{m})$ -* Space complexity: $O(\frac{t}{m})$ +- Time complexity: $O(2 ^ \frac{t}{m})$ +- Space complexity: $O(\frac{t}{m})$ -> Where $t$ is the given $target$ and $m$ is the minimum value in $nums$. \ No newline at end of file +> Where $t$ is the given $target$ and $m$ is the minimum value in $nums$. diff --git a/articles/combinations-of-a-phone-number.md b/articles/combinations-of-a-phone-number.md index 941f7ebf6..7953164f9 100644 --- a/articles/combinations-of-a-phone-number.md +++ b/articles/combinations-of-a-phone-number.md @@ -1,4 +1,4 @@ -## 1. Bactracking +## 1. Backtracking ::tabs-start @@ -61,7 +61,7 @@ public class Solution { class Solution { public: vector res; - vector digitToChar = {"", "", "abc", "def", "ghi", "jkl", + vector digitToChar = {"", "", "abc", "def", "ghi", "jkl", "mno", "qprs", "tuv", "wxyz"}; vector letterCombinations(string digits) { @@ -93,14 +93,14 @@ class Solution { let res = []; if (digits.length === 0) return res; const digitToChar = { - "2": "abc", - "3": "def", - "4": "ghi", - "5": "jkl", - "6": "mno", - "7": "qprs", - "8": "tuv", - "9": "wxyz" + 2: 'abc', + 3: 'def', + 4: 'ghi', + 5: 'jkl', + 6: 'mno', + 7: 'qprs', + 8: 'tuv', + 9: 'wxyz', }; const backtrack = (i, curStr) => { @@ -111,8 +111,8 @@ class Solution { for (const c of digitToChar[digits[i]]) { backtrack(i + 1, curStr + c); } - } - backtrack(0, ""); + }; + backtrack(0, ''); return res; } } @@ -120,7 +120,7 @@ class Solution { ```csharp public class Solution { - + private List res = new List(); private Dictionary digitToChar = new Dictionary { {'2', "abc"}, {'3', "def"}, {'4', "ghi"}, {'5', "jkl"}, @@ -212,12 +212,45 @@ class Solution { } ``` +```swift +class Solution { + func letterCombinations(_ digits: String) -> [String] { + guard !digits.isEmpty else { return [] } + + let digitToChar: [Character: String] = [ + "2": "abc", "3": "def", "4": "ghi", "5": "jkl", + "6": "mno", "7": "pqrs", "8": "tuv", "9": "wxyz" + ] + + var res = [String]() + let digitsArray = Array(digits) + + func backtrack(_ i: Int, _ curStr: String) { + if curStr.count == digits.count { + res.append(curStr) + return + } + if let letters = digitToChar[digitsArray[i]] { + for c in letters { + backtrack(i + 1, curStr + String(c)) + } + } + } + + backtrack(0, "") + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 4 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * 4 ^ n)$ +- Space complexity: + - $O(n)$ extra space. + - $O(n * 4 ^ n)$ space for the output list. --- @@ -254,14 +287,14 @@ class Solution: ```java public class Solution { - + public List letterCombinations(String digits) { if (digits.isEmpty()) return new ArrayList<>(); - + List res = new ArrayList<>(); res.add(""); String[] digitToChar = { - "", "", "abc", "def", "ghi", "jkl", + "", "", "abc", "def", "ghi", "jkl", "mno", "qprs", "tuv", "wxyz" }; @@ -284,7 +317,7 @@ class Solution { public: vector letterCombinations(string digits) { if (digits.empty()) return {}; - + vector res = {""}; vector digitToChar = { "", "", "abc", "def", "ghi", "jkl", @@ -313,17 +346,17 @@ class Solution { */ letterCombinations(digits) { if (digits.length === 0) return []; - - let res = [""]; + + let res = ['']; const digitToChar = { - "2": "abc", - "3": "def", - "4": "ghi", - "5": "jkl", - "6": "mno", - "7": "qprs", - "8": "tuv", - "9": "wxyz" + 2: 'abc', + 3: 'def', + 4: 'ghi', + 5: 'jkl', + 6: 'mno', + 7: 'qprs', + 8: 'tuv', + 9: 'wxyz', }; for (const digit of digits) { @@ -345,7 +378,7 @@ public class Solution { public List LetterCombinations(string digits) { if (digits.Length == 0) return new List(); - + List res = new List { "" }; Dictionary digitToChar = new Dictionary { { '2', "abc" }, { '3', "def" }, { '4', "ghi" }, { '5', "jkl" }, @@ -429,9 +462,39 @@ class Solution { } ``` +```swift +class Solution { + func letterCombinations(_ digits: String) -> [String] { + guard !digits.isEmpty else { return [] } + + let digitToChar: [Character: String] = [ + "2": "abc", "3": "def", "4": "ghi", "5": "jkl", + "6": "mno", "7": "pqrs", "8": "tuv", "9": "wxyz" + ] + + var res = [""] + + for digit in digits { + guard let letters = digitToChar[digit] else { continue } + var tmp = [String]() + for curStr in res { + for c in letters { + tmp.append(curStr + String(c)) + } + } + res = tmp + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 4 ^ n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n * 4 ^ n)$ +- Space complexity: + - $O(n)$ extra space. + - $O(n * 4 ^ n)$ space for the output list. diff --git a/articles/combinations.md b/articles/combinations.md index d5e838baf..4c1594aaf 100644 --- a/articles/combinations.md +++ b/articles/combinations.md @@ -6,18 +6,18 @@ class Solution: def combine(self, n: int, k: int) -> List[List[int]]: res = [] - + def backtrack(i, comb): if i > n: if len(comb) == k: res.append(comb.copy()) return - + comb.append(i) backtrack(i + 1, comb) comb.pop() backtrack(i + 1, comb) - + backtrack(1, []) return res ``` @@ -25,13 +25,13 @@ class Solution: ```java public class Solution { private List> res; - + public List> combine(int n, int k) { res = new ArrayList<>(); backtrack(1, n, k, new ArrayList<>()); return res; } - + private void backtrack(int i, int n, int k, List comb) { if (i > n) { if (comb.size() == k) { @@ -39,7 +39,7 @@ public class Solution { } return; } - + comb.add(i); backtrack(i + 1, n, k, comb); comb.remove(comb.size() - 1); @@ -84,7 +84,7 @@ class Solution { */ combine(n, k) { const res = []; - + const backtrack = (i, comb) => { if (i > n) { if (comb.length === k) { @@ -92,25 +92,50 @@ class Solution { } return; } - + comb.push(i); backtrack(i + 1, comb); comb.pop(); backtrack(i + 1, comb); }; - + backtrack(1, []); return res; } } ``` +```csharp +public class Solution { + public List> Combine(int n, int k) { + List> res = new List>(); + + void Backtrack(int i, List comb) { + if (i > n) { + if (comb.Count == k) { + res.Add(new List(comb)); + } + return; + } + + comb.Add(i); + Backtrack(i + 1, comb); + comb.RemoveAt(comb.Count - 1); + Backtrack(i + 1, comb); + } + + Backtrack(1, new List()); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(k * \frac {n!}{(n - k)! * k!})$ -* Space complexity: $O(k * \frac {n!}{(n - k)! * k!})$ for the output array. +- Time complexity: $O(k * \frac {n!}{(n - k)! * k!})$ +- Space complexity: $O(k * \frac {n!}{(n - k)! * k!})$ for the output array. > Where $n$ is the number of elements and $k$ is the number of elements to be picked. @@ -200,7 +225,7 @@ class Solution { */ combine(n, k) { const res = []; - + const backtrack = (start, comb) => { if (comb.length === k) { res.push([...comb]); @@ -213,19 +238,43 @@ class Solution { comb.pop(); } }; - + backtrack(1, []); return res; } } ``` +```csharp +public class Solution { + public List> Combine(int n, int k) { + List> res = new List>(); + + void Backtrack(int start, List comb) { + if (comb.Count == k) { + res.Add(new List(comb)); + return; + } + + for (int i = start; i <= n; i++) { + comb.Add(i); + Backtrack(i + 1, comb); + comb.RemoveAt(comb.Count - 1); + } + } + + Backtrack(1, new List()); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(k * \frac {n!}{(n - k)! * k!})$ -* Space complexity: $O(k * \frac {n!}{(n - k)! * k!})$ for the output array. +- Time complexity: $O(k * \frac {n!}{(n - k)! * k!})$ +- Space complexity: $O(k * \frac {n!}{(n - k)! * k!})$ for the output array. > Where $n$ is the number of elements and $k$ is the number of elements to be picked. @@ -348,12 +397,39 @@ class Solution { } ``` +```csharp +public class Solution { + public List> Combine(int n, int k) { + List> res = new List>(); + int[] comb = new int[k]; + int i = 0; + + while (i >= 0) { + comb[i]++; + if (comb[i] > n) { + i--; + continue; + } + + if (i == k - 1) { + res.Add(new List(comb)); + } else { + i++; + comb[i] = comb[i - 1]; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(k * \frac {n!}{(n - k)! * k!})$ -* Space complexity: $O(k * \frac {n!}{(n - k)! * k!})$ for the output array. +- Time complexity: $O(k * \frac {n!}{(n - k)! * k!})$ +- Space complexity: $O(k * \frac {n!}{(n - k)! * k!})$ for the output array. > Where $n$ is the number of elements and $k$ is the number of elements to be picked. @@ -372,7 +448,7 @@ class Solution: for bit in range(n): if mask & (1 << bit): comb.append(bit + 1) - + if len(comb) == k: res.append(comb) return res @@ -428,8 +504,8 @@ class Solution { */ combine(n, k) { const res = []; - for (let mask = 0; mask < (1 << n); mask++) { - if (mask.toString(2).split("1").length - 1 !== k) { + for (let mask = 0; mask < 1 << n; mask++) { + if (mask.toString(2).split('1').length - 1 !== k) { continue; } @@ -446,11 +522,33 @@ class Solution { } ``` +```csharp +public class Solution { + public List> Combine(int n, int k) { + List> res = new List>(); + + for (int mask = 0; mask < (1 << n); mask++) { + List comb = new List(); + for (int bit = 0; bit < n; bit++) { + if ((mask & (1 << bit)) != 0) { + comb.Add(bit + 1); + } + } + if (comb.Count == k) { + res.Add(comb); + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(k * \frac {n!}{(n - k)! * k!})$ for the output array. +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: $O(k * \frac {n!}{(n - k)! * k!})$ for the output array. -> Where $n$ is the number of elements and $k$ is the number of elements to be picked. \ No newline at end of file +> Where $n$ is the number of elements and $k$ is the number of elements to be picked. diff --git a/articles/concatenated-words.md b/articles/concatenated-words.md new file mode 100644 index 000000000..1c1b24cd0 --- /dev/null +++ b/articles/concatenated-words.md @@ -0,0 +1,727 @@ +## 1. Brute Force (Backtracking) + +::tabs-start + +```python +class Solution: + def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]: + n = len(words) + res = [] + wordSet = set(words) + maxLen = 0 + for w in words: + maxLen = max(maxLen, len(w)) + + def dfs(concatWord, totLen): + if len(concatWord) > 1: + word = "".join(concatWord) + if word in wordSet: + res.append(word) + wordSet.remove(word) + + for i in range(len(words)): + if totLen + len(words[i]) > maxLen: + continue + concatWord.append(words[i]) + dfs(concatWord, totLen + len(words[i])) + concatWord.pop() + + dfs([], 0) + return res +``` + +```java +public class Solution { + private Set wordSet; + private int maxLen; + private List res; + private String[] words; + + public List findAllConcatenatedWordsInADict(String[] words) { + this.words = words; + this.wordSet = new HashSet<>(Arrays.asList(words)); + this.maxLen = 0; + this.res = new ArrayList<>(); + + for (String w : words) { + maxLen = Math.max(maxLen, w.length()); + } + + dfs(new ArrayList<>(), 0); + return res; + } + + private void dfs(List concatWord, int totLen) { + if (concatWord.size() > 1) { + String word = String.join("", concatWord); + if (wordSet.contains(word)) { + res.add(word); + wordSet.remove(word); + } + } + + for (String word : words) { + if (totLen + word.length() > maxLen) continue; + concatWord.add(word); + dfs(concatWord, totLen + word.length()); + concatWord.remove(concatWord.size() - 1); + } + } +} +``` + +```cpp +class Solution { +private: + unordered_set wordSet; + int maxLen; + vector res; + vector words; + +public: + vector findAllConcatenatedWordsInADict(vector& words) { + this->words = words; + wordSet = unordered_set(words.begin(), words.end()); + maxLen = 0; + res.clear(); + + for (const string& w : words) { + maxLen = max(maxLen, (int)w.length()); + } + + vector concatWord; + dfs(concatWord, 0); + return res; + } + +private: + void dfs(vector& concatWord, int totLen) { + if (concatWord.size() > 1) { + string word = accumulate(concatWord.begin(), concatWord.end(), string("")); + if (wordSet.count(word)) { + res.push_back(word); + wordSet.erase(word); + } + } + + for (const string& word : words) { + if (totLen + word.size() > maxLen) continue; + concatWord.push_back(word); + dfs(concatWord, totLen + word.length()); + concatWord.pop_back(); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + findAllConcatenatedWordsInADict(words) { + let n = words.length; + let res = []; + let wordSet = new Set(words); + let maxLen = 0; + + for (let w of words) { + maxLen = Math.max(maxLen, w.length); + } + + const dfs = (concatWord, totLen) => { + if (concatWord.length > 1) { + let word = concatWord.join(''); + if (wordSet.has(word)) { + res.push(word); + wordSet.delete(word); + } + } + + for (let i = 0; i < words.length; i++) { + if (totLen + words[i].length > maxLen) continue; + concatWord.push(words[i]); + dfs(concatWord, totLen + words[i].length); + concatWord.pop(); + } + }; + + dfs([], 0); + return res; + } +} +``` + +```csharp +public class Solution { + private HashSet wordSet; + private int maxLen; + private List res; + private string[] words; + + public List FindAllConcatenatedWordsInADict(string[] words) { + this.words = words; + this.wordSet = new HashSet(words); + this.maxLen = 0; + this.res = new List(); + + foreach (var w in words) { + maxLen = Math.Max(maxLen, w.Length); + } + + Dfs(new List(), 0); + return res; + } + + private void Dfs(List concatWord, int totLen) { + if (concatWord.Count > 1) { + string word = string.Concat(concatWord); + if (wordSet.Contains(word)) { + res.Add(word); + wordSet.Remove(word); + } + } + + foreach (var word in words) { + if (totLen + word.Length > maxLen) continue; + concatWord.Add(word); + Dfs(concatWord, totLen + word.Length); + concatWord.RemoveAt(concatWord.Count - 1); + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n ^ n)$ +- Space complexity: $O(m * n)$ + +> Where $n$ is the size of the string array $words$ and $m$ is the length of the longest word in the array. + +--- + +## 2. Recursion + +::tabs-start + +```python +class Solution: + def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]: + wordSet = set(words) + + def dfs(word): + for i in range(1, len(word)): + prefix, suffix = word[:i], word[i:] + if ((prefix in wordSet and suffix in wordSet) or + (prefix in wordSet and dfs(suffix)) + ): + return True + return False + + res = [] + for w in words: + if dfs(w): + res.append(w) + return res +``` + +```java +public class Solution { + public List findAllConcatenatedWordsInADict(String[] words) { + Set wordSet = new HashSet<>(Arrays.asList(words)); + List res = new ArrayList<>(); + + for (String w : words) { + if (dfs(w, wordSet)) { + res.add(w); + } + } + return res; + } + + private boolean dfs(String word, Set wordSet) { + for (int i = 1; i < word.length(); i++) { + String prefix = word.substring(0, i); + String suffix = word.substring(i); + + if ((wordSet.contains(prefix) && wordSet.contains(suffix)) || + (wordSet.contains(prefix) && dfs(suffix, wordSet))) { + return true; + } + } + return false; + } +} +``` + +```cpp +class Solution { +public: + vector findAllConcatenatedWordsInADict(vector& words) { + unordered_set wordSet(words.begin(), words.end()); + vector res; + + for (const string& w : words) { + if (dfs(w, wordSet)) { + res.push_back(w); + } + } + return res; + } + +private: + bool dfs(const string& word, unordered_set& wordSet) { + for (int i = 1; i < word.size(); i++) { + string prefix = word.substr(0, i); + string suffix = word.substr(i); + + if ((wordSet.count(prefix) && wordSet.count(suffix)) || + (wordSet.count(prefix) && dfs(suffix, wordSet))) { + return true; + } + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + findAllConcatenatedWordsInADict(words) { + const wordSet = new Set(words); + + const dfs = (word) => { + for (let i = 1; i < word.length; i++) { + const prefix = word.substring(0, i); + const suffix = word.substring(i); + + if ( + (wordSet.has(prefix) && wordSet.has(suffix)) || + (wordSet.has(prefix) && dfs(suffix)) + ) { + return true; + } + } + return false; + }; + + const res = []; + for (let w of words) { + if (dfs(w)) { + res.push(w); + } + } + return res; + } +} +``` + +```csharp +public class Solution { + private HashSet wordSet; + + public List FindAllConcatenatedWordsInADict(string[] words) { + wordSet = new HashSet(words); + var res = new List(); + foreach (var w in words) { + if (Dfs(w)) { + res.Add(w); + } + } + return res; + } + + private bool Dfs(string word) { + for (int i = 1; i < word.Length; i++) { + string prefix = word.Substring(0, i); + string suffix = word.Substring(i); + if ((wordSet.Contains(prefix) && wordSet.Contains(suffix)) || + (wordSet.Contains(prefix) && Dfs(suffix))) { + return true; + } + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m ^ 4)$ +- Space complexity: $O(n * m)$ + +> Where $n$ is the size of the string array $words$ and $m$ is the length of the longest word in the array. + +--- + +## 3. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]: + wordSet = set(words) + dp = {} + + def dfs(word): + if word in dp: + return dp[word] + + for i in range(1, len(word)): + prefix, suffix = word[:i], word[i:] + if ((prefix in wordSet and suffix in wordSet) or + (prefix in wordSet and dfs(suffix)) + ): + dp[word] = True + return True + dp[word] = False + return False + + res = [] + for w in words: + if dfs(w): + res.append(w) + return res +``` + +```java +public class Solution { + private Map dp; + + public List findAllConcatenatedWordsInADict(String[] words) { + Set wordSet = new HashSet<>(Arrays.asList(words)); + List res = new ArrayList<>(); + dp = new HashMap<>(); + + for (String w : words) { + if (dfs(w, wordSet)) { + res.add(w); + } + } + return res; + } + + private boolean dfs(String word, Set wordSet) { + if (dp.containsKey(word)) { + return dp.get(word); + } + + for (int i = 1; i < word.length(); i++) { + String prefix = word.substring(0, i); + String suffix = word.substring(i); + + if ((wordSet.contains(prefix) && wordSet.contains(suffix)) || + (wordSet.contains(prefix) && dfs(suffix, wordSet))) { + dp.put(word, true); + return true; + } + } + dp.put(word, false); + return false; + } +} +``` + +```cpp +class Solution { + unordered_map dp; + +public: + vector findAllConcatenatedWordsInADict(vector& words) { + unordered_set wordSet(words.begin(), words.end()); + vector res; + + for (const string& w : words) { + if (dfs(w, wordSet)) { + res.push_back(w); + } + } + return res; + } + +private: + bool dfs(const string& word, unordered_set& wordSet) { + if (dp.count(word)) { + return dp[word]; + } + + for (int i = 1; i < word.size(); i++) { + string prefix = word.substr(0, i); + string suffix = word.substr(i); + + if ((wordSet.count(prefix) && wordSet.count(suffix)) || + (wordSet.count(prefix) && dfs(suffix, wordSet))) { + dp[word] = true; + return true; + } + } + dp[word] = false; + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + findAllConcatenatedWordsInADict(words) { + const wordSet = new Set(words); + const dp = new Map(); + + const dfs = (word) => { + if (dp.has(word)) { + return dp.get(word); + } + + for (let i = 1; i < word.length; i++) { + const prefix = word.substring(0, i); + const suffix = word.substring(i); + + if ( + (wordSet.has(prefix) && wordSet.has(suffix)) || + (wordSet.has(prefix) && dfs(suffix)) + ) { + dp.set(word, true); + return true; + } + } + dp.set(word, false); + return false; + }; + + const res = []; + for (let w of words) { + if (dfs(w)) { + res.push(w); + } + } + return res; + } +} +``` + +```csharp +public class Solution { + private HashSet wordSet; + private Dictionary dp; + + public List FindAllConcatenatedWordsInADict(string[] words) { + wordSet = new HashSet(words); + dp = new Dictionary(); + var res = new List(); + foreach (var w in words) { + if (Dfs(w)) { + res.Add(w); + } + } + return res; + } + + private bool Dfs(string word) { + if (dp.TryGetValue(word, out bool val)) { + return val; + } + for (int i = 1; i < word.Length; i++) { + string prefix = word.Substring(0, i); + string suffix = word.Substring(i); + if ((wordSet.Contains(prefix) && wordSet.Contains(suffix)) || + (wordSet.Contains(prefix) && Dfs(suffix))) { + dp[word] = true; + return true; + } + } + dp[word] = false; + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m ^ 3)$ +- Space complexity: $O(n * m)$ + +> Where $n$ is the size of the string array $words$ and $m$ is the length of the longest word in the array. + +--- + +## 4. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def findAllConcatenatedWordsInADict(self, words: List[str]) -> List[str]: + wordSet = set(words) + res = [] + + for word in words: + m = len(word) + + dp = [False] * (m + 1) + dp[0] = True + + for i in range(1, m + 1): + for j in range(i): + if j == 0 and i == m: + continue + if dp[j] and word[j:i] in wordSet: + dp[i] = True + break + + if dp[m]: + res.append(word) + + return res +``` + +```java +public class Solution { + public List findAllConcatenatedWordsInADict(String[] words) { + Set wordSet = new HashSet<>(Arrays.asList(words)); + List res = new ArrayList<>(); + + for (String word : words) { + int m = word.length(); + boolean[] dp = new boolean[m + 1]; + dp[0] = true; + + for (int i = 1; i <= m; i++) { + for (int j = 0; j < i; j++) { + if (j == 0 && i == m) continue; + if (dp[j] && wordSet.contains(word.substring(j, i))) { + dp[i] = true; + break; + } + } + } + + if (dp[m]) { + res.add(word); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findAllConcatenatedWordsInADict(vector& words) { + unordered_set wordSet(words.begin(), words.end()); + vector res; + + for (string& word : words) { + int m = word.length(); + vector dp(m + 1, false); + dp[0] = true; + + for (int i = 1; i <= m; i++) { + for (int j = 0; j < i; j++) { + if (j == 0 && i == m) continue; + if (dp[j] && wordSet.count(word.substr(j, i - j))) { + dp[i] = true; + break; + } + } + } + + if (dp[m]) { + res.push_back(word); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + findAllConcatenatedWordsInADict(words) { + const wordSet = new Set(words); + const res = []; + + for (const word of words) { + const m = word.length; + const dp = new Array(m + 1).fill(false); + dp[0] = true; + + for (let i = 1; i <= m; i++) { + for (let j = 0; j < i; j++) { + if (j === 0 && i === m) continue; + if (dp[j] && wordSet.has(word.substring(j, i))) { + dp[i] = true; + break; + } + } + } + + if (dp[m]) { + res.push(word); + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public List FindAllConcatenatedWordsInADict(string[] words) { + var wordSet = new HashSet(words); + var res = new List(); + + foreach (var word in words) { + int m = word.Length; + var dp = new bool[m + 1]; + dp[0] = true; + + for (int i = 1; i <= m; i++) { + for (int j = 0; j < i; j++) { + if (j == 0 && i == m) continue; + if (dp[j] && wordSet.Contains(word.Substring(j, i - j))) { + dp[i] = true; + break; + } + } + } + + if (dp[m]) { + res.Add(word); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m ^ 3)$ +- Space complexity: $O(n * m)$ + +> Where $n$ is the size of the string array $words$ and $m$ is the length of the longest word in the array. diff --git a/articles/concatenation-of-array.md b/articles/concatenation-of-array.md index 3ea2a1e68..6c937a1b5 100644 --- a/articles/concatenation-of-array.md +++ b/articles/concatenation-of-array.md @@ -15,7 +15,7 @@ class Solution: ```java public class Solution { public int[] getConcatenation(int[] nums) { - int[] ans=new int[2 * nums.length]; + int[] ans = new int[2 * nums.length]; int idx = 0; for (int i = 0; i < 2; i++) { for (int num : nums) { @@ -60,12 +60,27 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] GetConcatenation(int[] nums) { + int[] ans = new int[2 * nums.Length]; + int idx = 0; + for (int i = 0; i < 2; i++) { + foreach (int num in nums) { + ans[idx++] = num; + } + } + return ans; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for the output array. +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for the output array. --- @@ -127,9 +142,22 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] GetConcatenation(int[] nums) { + int n = nums.Length; + int[] ans = new int[2 * n]; + for (int i = 0; i < n; i++) { + ans[i] = ans[i + n] = nums[i]; + } + return ans; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for the output array. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for the output array. diff --git a/articles/constrained-subsequence-sum.md b/articles/constrained-subsequence-sum.md new file mode 100644 index 000000000..5911f55dc --- /dev/null +++ b/articles/constrained-subsequence-sum.md @@ -0,0 +1,701 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def constrainedSubsetSum(self, nums: List[int], k: int) -> int: + memo = [None] * len(nums) + + def dfs(i): + if memo[i] != None: + return memo[i] + + res = nums[i] + for j in range(i + 1, len(nums)): + if j - i > k: + break + res = max(res, nums[i] + dfs(j)) + + memo[i] = res + return res + + ans = float('-inf') + for i in range(len(nums)): + ans = max(ans, dfs(i)) + return ans +``` + +```java +public class Solution { + private int[] nums; + private Integer[] memo; + private int k; + + public int constrainedSubsetSum(int[] nums, int k) { + this.nums = nums; + this.memo = new Integer[nums.length]; + this.k = k; + + int ans = Integer.MIN_VALUE; + for (int i = 0; i < nums.length; i++) { + ans = Math.max(ans, dfs(i)); + } + return ans; + } + + private int dfs(int i) { + if (memo[i] != null) { + return memo[i]; + } + + int res = nums[i]; + for (int j = i + 1; j < nums.length && j - i <= k; j++) { + res = Math.max(res, nums[i] + dfs(j)); + } + + memo[i] = res; + return res; + } +} +``` + +```cpp +class Solution { +public: + int constrainedSubsetSum(vector& nums, int k) { + vector memo(nums.size(), INT_MIN); + int ans = INT_MIN; + for (int i = 0; i < nums.size(); i++) { + ans = max(ans, dfs(nums, memo, k, i)); + } + return ans; + } + +private: + int dfs(vector& nums, vector& memo, int k, int i) { + if (memo[i] != INT_MIN) { + return memo[i]; + } + + int res = nums[i]; + for (int j = i + 1; j < nums.size() && j - i <= k; j++) { + res = max(res, nums[i] + dfs(nums, memo, k, j)); + } + + memo[i] = res; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + constrainedSubsetSum(nums, k) { + const memo = new Array(nums.length).fill(null); + + const dfs = (i) => { + if (memo[i] !== null) { + return memo[i]; + } + + let res = nums[i]; + for (let j = i + 1; j < nums.length && j - i <= k; j++) { + res = Math.max(res, nums[i] + dfs(j)); + } + + memo[i] = res; + return res; + }; + + let ans = -Infinity; + for (let i = 0; i < nums.length; i++) { + ans = Math.max(ans, dfs(i)); + } + return ans; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * k)$ +- Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def constrainedSubsetSum(self, nums: List[int], k: int) -> int: + dp = [num for num in nums] + + for i in range(1, len(nums)): + for j in range(max(0, i - k), i): + dp[i] = max(dp[i], nums[i] + dp[j]) + + return max(dp) +``` + +```java +public class Solution { + public int constrainedSubsetSum(int[] nums, int k) { + int n = nums.length; + int[] dp = new int[n]; + System.arraycopy(nums, 0, dp, 0, n); + + for (int i = 1; i < n; i++) { + for (int j = Math.max(0, i - k); j < i; j++) { + dp[i] = Math.max(dp[i], nums[i] + dp[j]); + } + } + + int res = Integer.MIN_VALUE; + for (int val : dp) { + res = Math.max(res, val); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int constrainedSubsetSum(vector& nums, int k) { + int n = nums.size(); + vector dp(nums.begin(), nums.end()); + + for (int i = 1; i < n; i++) { + for (int j = max(0, i - k); j < i; j++) { + dp[i] = max(dp[i], nums[i] + dp[j]); + } + } + + return *max_element(dp.begin(), dp.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + constrainedSubsetSum(nums, k) { + const n = nums.length; + const dp = [...nums]; + + for (let i = 1; i < n; i++) { + for (let j = Math.max(0, i - k); j < i; j++) { + dp[i] = Math.max(dp[i], nums[i] + dp[j]); + } + } + + return Math.max(...dp); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * k)$ +- Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming + Segment Tree + +::tabs-start + +```python +class SegmentTree: + def __init__(self, N): + self.n = N + while (self.n & (self.n - 1)) != 0: + self.n += 1 + self.tree = [float('-inf')] * (2 * self.n) + + def update(self, i, val): + i += self.n + self.tree[i] = val + while i > 1: + i >>= 1 + self.tree[i] = max(self.tree[i << 1], self.tree[i << 1 | 1]) + + def query(self, l, r): + res = float('-inf') + l += self.n + r += self.n + 1 + while l < r: + if l & 1: + res = max(res, self.tree[l]) + l += 1 + if r & 1: + r -= 1 + res = max(res, self.tree[r]) + l >>= 1 + r >>= 1 + return max(0, res) + +class Solution: + def constrainedSubsetSum(self, nums: List[int], k: int) -> int: + n = len(nums) + maxSegTree = SegmentTree(n) + maxSegTree.update(0, nums[0]) + res = nums[0] + + for i in range(1, n): + cur = nums[i] + maxSegTree.query(max(0, i - k), i - 1) + maxSegTree.update(i, cur) + res = max(res, cur) + + return res +``` + +```java +class SegmentTree { + int n; + int[] tree; + + public SegmentTree(int N) { + this.n = N; + while ((this.n & (this.n - 1)) != 0) { + this.n++; + } + tree = new int[2 * this.n]; + for (int i = 0; i < 2 * this.n; i++) { + tree[i] = Integer.MIN_VALUE; + } + } + + public void update(int i, int val) { + i += n; + tree[i] = val; + while (i > 1) { + i >>= 1; + tree[i] = Math.max(tree[i << 1], tree[(i << 1) | 1]); + } + } + + public int query(int l, int r) { + int res = Integer.MIN_VALUE; + l += n; + r += n + 1; + while (l < r) { + if ((l & 1) == 1) { + res = Math.max(res, tree[l]); + l++; + } + if ((r & 1) == 1) { + r--; + res = Math.max(res, tree[r]); + } + l >>= 1; + r >>= 1; + } + return Math.max(0, res); + } +} + +public class Solution { + public int constrainedSubsetSum(int[] nums, int k) { + int n = nums.length; + SegmentTree maxSegTree = new SegmentTree(n); + maxSegTree.update(0, nums[0]); + int res = nums[0]; + + for (int i = 1; i < n; i++) { + int cur = nums[i] + maxSegTree.query(Math.max(0, i - k), i - 1); + maxSegTree.update(i, cur); + res = Math.max(res, cur); + } + + return res; + } +} +``` + +```cpp +class SegmentTree { +public: + int n; + vector tree; + + SegmentTree(int N) { + n = N; + while ((n & (n - 1)) != 0) { + n++; + } + tree.assign(2 * n, INT_MIN); + } + + void update(int i, int val) { + i += n; + tree[i] = val; + while (i > 1) { + i >>= 1; + tree[i] = max(tree[i << 1], tree[i << 1 | 1]); + } + } + + int query(int l, int r) { + int res = INT_MIN; + l += n; + r += n + 1; + while (l < r) { + if (l & 1) { + res = max(res, tree[l]); + l++; + } + if (r & 1) { + r--; + res = max(res, tree[r]); + } + l >>= 1; + r >>= 1; + } + return max(0, res); + } +}; + +class Solution { +public: + int constrainedSubsetSum(vector& nums, int k) { + int n = nums.size(); + SegmentTree maxSegTree(n); + maxSegTree.update(0, nums[0]); + int res = nums[0]; + + for (int i = 1; i < n; i++) { + int cur = nums[i] + maxSegTree.query(max(0, i - k), i - 1); + maxSegTree.update(i, cur); + res = max(res, cur); + } + + return res; + } +}; +``` + +```javascript +class SegmentTree { + /** + * @constructor + * @param {number} N + */ + constructor(N) { + this.n = N; + while ((this.n & (this.n - 1)) !== 0) { + this.n++; + } + this.tree = new Array(2 * this.n).fill(-Infinity); + } + + /** + * @param {number} i + * @param {number} val + * @return {void} + */ + update(i, val) { + i += this.n; + this.tree[i] = val; + while (i > 1) { + i >>= 1; + this.tree[i] = Math.max(this.tree[i << 1], this.tree[(i << 1) | 1]); + } + } + + /** + * @param {number} l + * @param {number} r + * @return {number} + */ + query(l, r) { + let res = -Infinity; + l += this.n; + r += this.n + 1; + while (l < r) { + if (l & 1) { + res = Math.max(res, this.tree[l]); + l++; + } + if (r & 1) { + r--; + res = Math.max(res, this.tree[r]); + } + l >>= 1; + r >>= 1; + } + return Math.max(0, res); + } +} + +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + constrainedSubsetSum(nums, k) { + const n = nums.length; + const maxSegTree = new SegmentTree(n); + maxSegTree.update(0, nums[0]); + let res = nums[0]; + + for (let i = 1; i < n; i++) { + let cur = nums[i] + maxSegTree.query(Math.max(0, i - k), i - 1); + maxSegTree.update(i, cur); + res = Math.max(res, cur); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Max-Heap + +::tabs-start + +```python +class Solution: + def constrainedSubsetSum(self, nums: List[int], k: int) -> int: + res = nums[0] + max_heap = [(-nums[0], 0)] # max_sum, index + + for i in range(1, len(nums)): + while i - max_heap[0][1] > k: + heapq.heappop(max_heap) + + cur_max = max(nums[i], nums[i] - max_heap[0][0]) + res = max(res, cur_max) + heapq.heappush(max_heap, (-cur_max, i)) + + return res +``` + +```java +public class Solution { + public int constrainedSubsetSum(int[] nums, int k) { + int res = nums[0]; + PriorityQueue maxHeap = new PriorityQueue<>( + (a, b) -> b[0] - a[0] // max_sum, index + ); + maxHeap.offer(new int[]{nums[0], 0}); + + for (int i = 1; i < nums.length; i++) { + while (i - maxHeap.peek()[1] > k) { + maxHeap.poll(); + } + + int curMax = Math.max(nums[i], nums[i] + maxHeap.peek()[0]); + res = Math.max(res, curMax); + maxHeap.offer(new int[]{curMax, i}); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int constrainedSubsetSum(vector& nums, int k) { + int res = nums[0]; + priority_queue> maxHeap; // max_sum, index + maxHeap.emplace(nums[0], 0); + + for (int i = 1; i < nums.size(); i++) { + while (i - maxHeap.top().second > k) { + maxHeap.pop(); + } + + int curMax = max(nums[i], nums[i] + maxHeap.top().first); + res = max(res, curMax); + maxHeap.emplace(curMax, i); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + constrainedSubsetSum(nums, k) { + let res = nums[0]; + const maxHeap = new PriorityQueue( + (a, b) => b[0] - a[0], // max_sum, index + ); + maxHeap.enqueue([nums[0], 0]); + + for (let i = 1; i < nums.length; i++) { + while (i - maxHeap.front()[1] > k) { + maxHeap.dequeue(); + } + + let curMax = Math.max(nums[i], nums[i] + maxHeap.front()[0]); + res = Math.max(res, curMax); + maxHeap.enqueue([curMax, i]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 5. Monotonic Deque + +::tabs-start + +```python +class Solution: + def constrainedSubsetSum(self, nums: List[int], k: int) -> int: + n = len(nums) + dq = deque([(0, nums[0])]) + res = nums[0] + + for i in range(1, n): + if dq and dq[0][0] < i - k: + dq.popleft() + + cur = max(0, dq[0][1]) + nums[i] + while dq and cur > dq[-1][1]: + dq.pop() + + dq.append((i, cur)) + res = max(res, cur) + + return res +``` + +```java +public class Solution { + public int constrainedSubsetSum(int[] nums, int k) { + int n = nums.length; + Deque dq = new ArrayDeque<>(); + dq.offer(new int[]{0, nums[0]}); + int res = nums[0]; + + for (int i = 1; i < n; i++) { + if (!dq.isEmpty() && dq.peekFirst()[0] < i - k) { + dq.pollFirst(); + } + + int cur = Math.max(0, dq.peekFirst()[1]) + nums[i]; + while (!dq.isEmpty() && cur > dq.peekLast()[1]) { + dq.pollLast(); + } + + dq.offer(new int[]{i, cur}); + res = Math.max(res, cur); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int constrainedSubsetSum(vector& nums, int k) { + int n = nums.size(); + deque> dq{{0, nums[0]}}; + int res = nums[0]; + + for (int i = 1; i < n; i++) { + if (!dq.empty() && dq.front().first < i - k) { + dq.pop_front(); + } + + int cur = max(0, dq.front().second) + nums[i]; + while (!dq.empty() && cur > dq.back().second) { + dq.pop_back(); + } + + dq.emplace_back(i, cur); + res = max(res, cur); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + constrainedSubsetSum(nums, k) { + const n = nums.length; + const dq = new Deque([[0, nums[0]]]); + let res = nums[0]; + + for (let i = 1; i < n; i++) { + if (!dq.isEmpty() && dq.front()[0] < i - k) { + dq.popFront(); + } + + let cur = Math.max(0, dq.front()[1]) + nums[i]; + while (!dq.isEmpty() && cur > dq.back()[1]) { + dq.popBack(); + } + + dq.pushBack([i, cur]); + res = Math.max(res, cur); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(k)$ diff --git a/articles/construct-binary-tree-from-inorder-and-postorder-traversal.md b/articles/construct-binary-tree-from-inorder-and-postorder-traversal.md new file mode 100644 index 000000000..5a538b401 --- /dev/null +++ b/articles/construct-binary-tree-from-inorder-and-postorder-traversal.md @@ -0,0 +1,476 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]: + if not postorder or not inorder: + return None + + root = TreeNode(postorder[-1]) + mid = inorder.index(postorder[-1]) + root.left = self.buildTree(inorder[:mid], postorder[:mid]) + root.right = self.buildTree(inorder[mid + 1:], postorder[mid:-1]) + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode buildTree(int[] inorder, int[] postorder) { + if (postorder.length == 0 || inorder.length == 0) { + return null; + } + + TreeNode root = new TreeNode(postorder[postorder.length - 1]); + int mid = 0; + for (int i = 0; i < inorder.length; i++) { + if (inorder[i] == postorder[postorder.length - 1]) { + mid = i; + break; + } + } + + root.left = buildTree( + Arrays.copyOfRange(inorder, 0, mid), + Arrays.copyOfRange(postorder, 0, mid) + ); + root.right = buildTree( + Arrays.copyOfRange(inorder, mid + 1, inorder.length), + Arrays.copyOfRange(postorder, mid, postorder.length - 1) + ); + + return root; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* buildTree(vector& inorder, vector& postorder) { + if (postorder.empty() || inorder.empty()) { + return nullptr; + } + + TreeNode* root = new TreeNode(postorder.back()); + auto it = find(inorder.begin(), inorder.end(), postorder.back()); + int mid = distance(inorder.begin(), it); + + vector leftInorder(inorder.begin(), inorder.begin() + mid); + vector rightInorder(inorder.begin() + mid + 1, inorder.end()); + vector leftPostorder(postorder.begin(), postorder.begin() + mid); + vector rightPostorder(postorder.begin() + mid, postorder.end() - 1); + + root->left = buildTree(leftInorder, leftPostorder); + root->right = buildTree(rightInorder, rightPostorder); + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number[]} inorder + * @param {number[]} postorder + * @return {TreeNode} + */ + buildTree(inorder, postorder) { + if (postorder.length === 0 || inorder.length === 0) { + return null; + } + + const rootVal = postorder[postorder.length - 1]; + const root = new TreeNode(rootVal); + const mid = inorder.indexOf(rootVal); + + root.left = this.buildTree( + inorder.slice(0, mid), + postorder.slice(0, mid), + ); + root.right = this.buildTree( + inorder.slice(mid + 1), + postorder.slice(mid, postorder.length - 1), + ); + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 2. Hash Map + Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]: + inorderIdx = {v: i for i, v in enumerate(inorder)} + + def dfs(l, r): + if l > r: + return None + + root = TreeNode(postorder.pop()) + idx = inorderIdx[root.val] + root.right = dfs(idx + 1, r) + root.left = dfs(l, idx - 1) + return root + + return dfs(0, len(inorder) - 1) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private HashMap inorderIdx; + private int postIdx; + + public TreeNode buildTree(int[] inorder, int[] postorder) { + inorderIdx = new HashMap<>(); + for (int i = 0; i < inorder.length; i++) { + inorderIdx.put(inorder[i], i); + } + postIdx = postorder.length - 1; + + return dfs(0, inorder.length - 1, postorder); + } + + private TreeNode dfs(int l, int r, int[] postorder) { + if (l > r) { + return null; + } + + TreeNode root = new TreeNode(postorder[postIdx--]); + int idx = inorderIdx.get(root.val); + root.right = dfs(idx + 1, r, postorder); + root.left = dfs(l, idx - 1, postorder); + return root; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + unordered_map inorderIdx; + int postIdx; + + TreeNode* buildTree(vector& inorder, vector& postorder) { + for (int i = 0; i < inorder.size(); i++) { + inorderIdx[inorder[i]] = i; + } + postIdx = postorder.size() - 1; + + return dfs(0, inorder.size() - 1, postorder); + } + +private: + TreeNode* dfs(int l, int r, vector& postorder) { + if (l > r) { + return nullptr; + } + + TreeNode* root = new TreeNode(postorder[postIdx--]); + int idx = inorderIdx[root->val]; + root->right = dfs(idx + 1, r, postorder); + root->left = dfs(l, idx - 1, postorder); + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number[]} inorder + * @param {number[]} postorder + * @return {TreeNode} + */ + buildTree(inorder, postorder) { + const inorderIdx = new Map(); + inorder.forEach((val, idx) => inorderIdx.set(val, idx)); + let postIdx = postorder.length - 1; + + const dfs = (l, r) => { + if (l > r) return null; + + const root = new TreeNode(postorder[postIdx--]); + const idx = inorderIdx.get(root.val); + root.right = dfs(idx + 1, r); + root.left = dfs(l, idx - 1); + return root; + }; + + return dfs(0, inorder.length - 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Depth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def buildTree(self, inorder: List[int], postorder: List[int]) -> Optional[TreeNode]: + postIdx = inIdx = len(postorder) - 1 + def dfs(limit): + nonlocal postIdx, inIdx + if postIdx < 0: + return None + if inorder[inIdx] == limit: + inIdx -= 1 + return None + + root = TreeNode(postorder[postIdx]) + postIdx -= 1 + root.right = dfs(root.val) + root.left = dfs(limit) + return root + return dfs(float('inf')) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private int postIdx; + private int inIdx; + + public TreeNode buildTree(int[] inorder, int[] postorder) { + postIdx = postorder.length - 1; + inIdx = inorder.length - 1; + + return dfs(postorder, inorder, Integer.MAX_VALUE); + } + + private TreeNode dfs(int[] postorder, int[] inorder, int limit) { + if (postIdx < 0) { + return null; + } + + if (inorder[inIdx] == limit) { + inIdx--; + return null; + } + + TreeNode root = new TreeNode(postorder[postIdx--]); + root.right = dfs(postorder, inorder, root.val); + root.left = dfs(postorder, inorder, limit); + return root; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int postIdx; + int inIdx; + + TreeNode* buildTree(vector& inorder, vector& postorder) { + postIdx = postorder.size() - 1; + inIdx = inorder.size() - 1; + + return dfs(postorder, inorder, numeric_limits::max()); + } + +private: + TreeNode* dfs(vector& postorder, vector& inorder, int limit) { + if (postIdx < 0) { + return nullptr; + } + + if (inorder[inIdx] == limit) { + inIdx--; + return nullptr; + } + + TreeNode* root = new TreeNode(postorder[postIdx--]); + root->right = dfs(postorder, inorder, root->val); + root->left = dfs(postorder, inorder, limit); + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number[]} inorder + * @param {number[]} postorder + * @return {TreeNode} + */ + buildTree(inorder, postorder) { + let postIdx = postorder.length - 1; + let inIdx = inorder.length - 1; + + const dfs = (limit) => { + if (postIdx < 0) return null; + + if (inorder[inIdx] === limit) { + inIdx--; + return null; + } + + const root = new TreeNode(postorder[postIdx--]); + root.right = dfs(root.val); + root.left = dfs(limit); + return root; + }; + + return dfs(Infinity); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. diff --git a/articles/construct-quad-tree.md b/articles/construct-quad-tree.md index 48e117a86..2b852c4f7 100644 --- a/articles/construct-quad-tree.md +++ b/articles/construct-quad-tree.md @@ -26,15 +26,15 @@ class Solution: break if allSame: return Node(grid[r][c], True) - + n = n // 2 topleft = dfs(n, r, c) topright = dfs(n, r, c + n) bottomleft = dfs(n, r + n, c) bottomright = dfs(n, r + n, c + n) - + return Node(0, False, topleft, topright, bottomleft, bottomright) - + return dfs(len(grid), 0, 0) ``` @@ -49,7 +49,7 @@ class Node { public Node bottomLeft; public Node bottomRight; - + public Node() { this.val = false; this.isLeaf = false; @@ -58,7 +58,7 @@ class Node { this.bottomLeft = null; this.bottomRight = null; } - + public Node(boolean val, boolean isLeaf) { this.val = val; this.isLeaf = isLeaf; @@ -67,7 +67,7 @@ class Node { this.bottomLeft = null; this.bottomRight = null; } - + public Node(boolean val, boolean isLeaf, Node topLeft, Node topRight, Node bottomLeft, Node bottomRight) { this.val = val; this.isLeaf = isLeaf; @@ -122,7 +122,7 @@ public: Node* topRight; Node* bottomLeft; Node* bottomRight; - + Node() { val = false; isLeaf = false; @@ -131,7 +131,7 @@ public: bottomLeft = NULL; bottomRight = NULL; } - + Node(bool _val, bool _isLeaf) { val = _val; isLeaf = _isLeaf; @@ -140,7 +140,7 @@ public: bottomLeft = NULL; bottomRight = NULL; } - + Node(bool _val, bool _isLeaf, Node* _topLeft, Node* _topRight, Node* _bottomLeft, Node* _bottomRight) { val = _val; isLeaf = _isLeaf; @@ -229,7 +229,14 @@ class Solution { const bottomLeft = dfs(mid, r + mid, c); const bottomRight = dfs(mid, r + mid, c + mid); - return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + return new Node( + false, + false, + topLeft, + topRight, + bottomLeft, + bottomRight, + ); }; return dfs(grid.length, 0, 0); @@ -237,12 +244,82 @@ class Solution { } ``` +```csharp +/* +// Definition for a QuadTree node. +public class Node { + public bool val; + public bool isLeaf; + public Node topLeft; + public Node topRight; + public Node bottomLeft; + public Node bottomRight; + + public Node() { + val = false; + isLeaf = false; + topLeft = null; + topRight = null; + bottomLeft = null; + bottomRight = null; + } + + public Node(bool _val, bool _isLeaf) { + val = _val; + isLeaf = _isLeaf; + topLeft = null; + topRight = null; + bottomLeft = null; + bottomRight = null; + } + + public Node(bool _val,bool _isLeaf,Node _topLeft,Node _topRight,Node _bottomLeft,Node _bottomRight) { + val = _val; + isLeaf = _isLeaf; + topLeft = _topLeft; + topRight = _topRight; + bottomLeft = _bottomLeft; + bottomRight = _bottomRight; + } +} +*/ + +public class Solution { + public Node Construct(int[][] grid) { + return Dfs(grid, grid.Length, 0, 0); + } + + private Node Dfs(int[][] grid, int n, int r, int c) { + bool allSame = true; + for (int i = 0; i < n && allSame; i++) { + for (int j = 0; j < n && allSame; j++) { + if (grid[r][c] != grid[r + i][c + j]) { + allSame = false; + } + } + } + + if (allSame) { + return new Node(grid[r][c] == 1, true); + } + + int half = n / 2; + Node topLeft = Dfs(grid, half, r, c); + Node topRight = Dfs(grid, half, r, c + half); + Node bottomLeft = Dfs(grid, half, r + half, c); + Node bottomRight = Dfs(grid, half, r + half, c + half); + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2 \log n)$ -* Space complexity: $O(\log n)$ for recursion stack. +- Time complexity: $O(n ^ 2 \log n)$ +- Space complexity: $O(\log n)$ for recursion stack. --- @@ -275,7 +352,7 @@ class Solution: bottomLeft = dfs(mid, r + mid, c) bottomRight = dfs(mid, r + mid, c + mid) - if (topLeft.isLeaf and topRight.isLeaf and + if (topLeft.isLeaf and topRight.isLeaf and bottomLeft.isLeaf and bottomRight.isLeaf and topLeft.val == topRight.val == bottomLeft.val == bottomRight.val): return Node(topLeft.val, True) @@ -296,7 +373,7 @@ class Node { public Node bottomLeft; public Node bottomRight; - + public Node() { this.val = false; this.isLeaf = false; @@ -305,7 +382,7 @@ class Node { this.bottomLeft = null; this.bottomRight = null; } - + public Node(boolean val, boolean isLeaf) { this.val = val; this.isLeaf = isLeaf; @@ -314,7 +391,7 @@ class Node { this.bottomLeft = null; this.bottomRight = null; } - + public Node(boolean val, boolean isLeaf, Node topLeft, Node topRight, Node bottomLeft, Node bottomRight) { this.val = val; this.isLeaf = isLeaf; @@ -342,10 +419,10 @@ public class Solution { Node bottomLeft = dfs(grid, mid, r + mid, c); Node bottomRight = dfs(grid, mid, r + mid, c + mid); - if (topLeft.isLeaf && topRight.isLeaf && + if (topLeft.isLeaf && topRight.isLeaf && bottomLeft.isLeaf && bottomRight.isLeaf && - topLeft.val == topRight.val && - topLeft.val == bottomLeft.val && + topLeft.val == topRight.val && + topLeft.val == bottomLeft.val && topLeft.val == bottomRight.val) { return new Node(topLeft.val, true); } @@ -366,7 +443,7 @@ public: Node* topRight; Node* bottomLeft; Node* bottomRight; - + Node() { val = false; isLeaf = false; @@ -375,7 +452,7 @@ public: bottomLeft = NULL; bottomRight = NULL; } - + Node(bool _val, bool _isLeaf) { val = _val; isLeaf = _isLeaf; @@ -384,7 +461,7 @@ public: bottomLeft = NULL; bottomRight = NULL; } - + Node(bool _val, bool _isLeaf, Node* _topLeft, Node* _topRight, Node* _bottomLeft, Node* _bottomRight) { val = _val; isLeaf = _isLeaf; @@ -459,15 +536,26 @@ class Solution { const bottomLeft = dfs(mid, r + mid, c); const bottomRight = dfs(mid, r + mid, c + mid); - if (topLeft.isLeaf && topRight.isLeaf && - bottomLeft.isLeaf && bottomRight.isLeaf && + if ( + topLeft.isLeaf && + topRight.isLeaf && + bottomLeft.isLeaf && + bottomRight.isLeaf && topLeft.val === topRight.val && topLeft.val === bottomLeft.val && - topLeft.val === bottomRight.val) { + topLeft.val === bottomRight.val + ) { return new Node(topLeft.val, true); } - return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + return new Node( + false, + false, + topLeft, + topRight, + bottomLeft, + bottomRight, + ); }; return dfs(grid.length, 0, 0); @@ -475,12 +563,81 @@ class Solution { } ``` +```csharp +/* +// Definition for a QuadTree node. +public class Node { + public bool val; + public bool isLeaf; + public Node topLeft; + public Node topRight; + public Node bottomLeft; + public Node bottomRight; + + public Node() { + val = false; + isLeaf = false; + topLeft = null; + topRight = null; + bottomLeft = null; + bottomRight = null; + } + + public Node(bool _val, bool _isLeaf) { + val = _val; + isLeaf = _isLeaf; + topLeft = null; + topRight = null; + bottomLeft = null; + bottomRight = null; + } + + public Node(bool _val,bool _isLeaf,Node _topLeft,Node _topRight,Node _bottomLeft,Node _bottomRight) { + val = _val; + isLeaf = _isLeaf; + topLeft = _topLeft; + topRight = _topRight; + bottomLeft = _bottomLeft; + bottomRight = _bottomRight; + } +} +*/ + +public class Solution { + public Node Construct(int[][] grid) { + return Dfs(grid, grid.Length, 0, 0); + } + + private Node Dfs(int[][] grid, int n, int r, int c) { + if (n == 1) { + return new Node(grid[r][c] == 1, true); + } + + int mid = n / 2; + Node topLeft = Dfs(grid, mid, r, c); + Node topRight = Dfs(grid, mid, r, c + mid); + Node bottomLeft = Dfs(grid, mid, r + mid, c); + Node bottomRight = Dfs(grid, mid, r + mid, c + mid); + + if (topLeft.isLeaf && topRight.isLeaf && + bottomLeft.isLeaf && bottomRight.isLeaf && + topLeft.val == topRight.val && + topRight.val == bottomLeft.val && + bottomLeft.val == bottomRight.val) { + return new Node(topLeft.val, true); + } + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(\log n)$ for recursion stack. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(\log n)$ for recursion stack. --- @@ -518,7 +675,7 @@ class Solution: bottomLeft = dfs(n, r + n, c) bottomRight = dfs(n, r + n, c + n) - if (topLeft.isLeaf and topRight.isLeaf and + if (topLeft.isLeaf and topRight.isLeaf and bottomLeft.isLeaf and bottomRight.isLeaf and topLeft.val == topRight.val == bottomLeft.val == bottomRight.val): return topLeft @@ -539,7 +696,7 @@ class Node { public Node bottomLeft; public Node bottomRight; - + public Node() { this.val = false; this.isLeaf = false; @@ -548,7 +705,7 @@ class Node { this.bottomLeft = null; this.bottomRight = null; } - + public Node(boolean val, boolean isLeaf) { this.val = val; this.isLeaf = isLeaf; @@ -557,7 +714,7 @@ class Node { this.bottomLeft = null; this.bottomRight = null; } - + public Node(boolean val, boolean isLeaf, Node topLeft, Node topRight, Node bottomLeft, Node bottomRight) { this.val = val; this.isLeaf = isLeaf; @@ -588,9 +745,9 @@ public class Solution { Node bottomLeft = dfs(grid, n, r + n, c); Node bottomRight = dfs(grid, n, r + n, c + n); - if (topLeft.isLeaf && topRight.isLeaf && + if (topLeft.isLeaf && topRight.isLeaf && bottomLeft.isLeaf && bottomRight.isLeaf && - topLeft.val == topRight.val && topLeft.val == bottomLeft.val && + topLeft.val == topRight.val && topLeft.val == bottomLeft.val && topLeft.val == bottomRight.val) { return topLeft; } @@ -611,7 +768,7 @@ public: Node* topRight; Node* bottomLeft; Node* bottomRight; - + Node() { val = false; isLeaf = false; @@ -620,7 +777,7 @@ public: bottomLeft = NULL; bottomRight = NULL; } - + Node(bool _val, bool _isLeaf) { val = _val; isLeaf = _isLeaf; @@ -629,7 +786,7 @@ public: bottomLeft = NULL; bottomRight = NULL; } - + Node(bool _val, bool _isLeaf, Node* _topLeft, Node* _topRight, Node* _bottomLeft, Node* _bottomRight) { val = _val; isLeaf = _isLeaf; @@ -710,14 +867,26 @@ class Solution { const bottomLeft = dfs(n, r + n, c); const bottomRight = dfs(n, r + n, c + n); - if (topLeft.isLeaf && topRight.isLeaf && - bottomLeft.isLeaf && bottomRight.isLeaf && - topLeft.val === topRight.val && topLeft.val === bottomLeft.val && - topLeft.val === bottomRight.val) { + if ( + topLeft.isLeaf && + topRight.isLeaf && + bottomLeft.isLeaf && + bottomRight.isLeaf && + topLeft.val === topRight.val && + topLeft.val === bottomLeft.val && + topLeft.val === bottomRight.val + ) { return topLeft; } - return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + return new Node( + false, + false, + topLeft, + topRight, + bottomLeft, + bottomRight, + ); }; return dfs(grid.length, 0, 0); @@ -725,9 +894,82 @@ class Solution { } ``` +```csharp +/* +// Definition for a QuadTree node. +public class Node { + public bool val; + public bool isLeaf; + public Node topLeft; + public Node topRight; + public Node bottomLeft; + public Node bottomRight; + + public Node() { + val = false; + isLeaf = false; + topLeft = null; + topRight = null; + bottomLeft = null; + bottomRight = null; + } + + public Node(bool _val, bool _isLeaf) { + val = _val; + isLeaf = _isLeaf; + topLeft = null; + topRight = null; + bottomLeft = null; + bottomRight = null; + } + + public Node(bool _val,bool _isLeaf,Node _topLeft,Node _topRight,Node _bottomLeft,Node _bottomRight) { + val = _val; + isLeaf = _isLeaf; + topLeft = _topLeft; + topRight = _topRight; + bottomLeft = _bottomLeft; + bottomRight = _bottomRight; + } +} +*/ + +public class Solution { + private readonly Node falseLeaf = new Node(false, true); + private readonly Node trueLeaf = new Node(true, true); + + public Node Construct(int[][] grid) { + int n = grid.Length; + return Dfs(grid, n, 0, 0); + } + + private Node Dfs(int[][] grid, int n, int r, int c) { + if (n == 1) { + return grid[r][c] == 1 ? trueLeaf : falseLeaf; + } + + int half = n / 2; + Node topLeft = Dfs(grid, half, r, c); + Node topRight = Dfs(grid, half, r, c + half); + Node bottomLeft = Dfs(grid, half, r + half, c); + Node bottomRight = Dfs(grid, half, r + half, c + half); + + if (topLeft.isLeaf && topRight.isLeaf && + bottomLeft.isLeaf && bottomRight.isLeaf && + topLeft.val == topRight.val && + topLeft.val == bottomLeft.val && + topLeft.val == bottomRight.val) { + return topLeft; + } + + return new Node(false, false, topLeft, topRight, bottomLeft, bottomRight); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(\log n)$ for recursion stack. \ No newline at end of file +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(\log n)$ for recursion stack. diff --git a/articles/construct-string-from-binary-tree.md b/articles/construct-string-from-binary-tree.md new file mode 100644 index 000000000..56a3a5b84 --- /dev/null +++ b/articles/construct-string-from-binary-tree.md @@ -0,0 +1,518 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def tree2str(self, root: Optional[TreeNode]) -> str: + if not root: + return "" + + cur = root.val + left = self.tree2str(root.left) + right = self.tree2str(root.right) + + if left and right: + return f"{cur}({left})({right})" + + if right: + return f"{cur}()({right})" + + if left: + return f"{cur}({left})" + + return str(cur) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public String tree2str(TreeNode root) { + if (root == null) { + return ""; + } + + String cur = Integer.toString(root.val); + String left = tree2str(root.left); + String right = tree2str(root.right); + + if (!left.isEmpty() && !right.isEmpty()) { + return cur + "(" + left + ")" + "(" + right + ")"; + } + + if (!right.isEmpty()) { + return cur + "()" + "(" + right + ")"; + } + + if (!left.isEmpty()) { + return cur + "(" + left + ")"; + } + + return cur; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + string tree2str(TreeNode* root) { + if (!root) { + return ""; + } + + string cur = to_string(root->val); + string left = tree2str(root->left); + string right = tree2str(root->right); + + if (!left.empty() && !right.empty()) { + return cur + "(" + left + ")(" + right + ")"; + } + + if (!right.empty()) { + return cur + "()(" + right + ")"; + } + + if (!left.empty()) { + return cur + "(" + left + ")"; + } + + return cur; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {string} + */ + tree2str(root) { + if (!root) { + return ''; + } + + const cur = root.val.toString(); + const left = this.tree2str(root.left); + const right = this.tree2str(root.right); + + if (left && right) { + return `${cur}(${left})(${right})`; + } + + if (right) { + return `${cur}()(${right})`; + } + + if (left) { + return `${cur}(${left})`; + } + + return cur; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 2. Depth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def tree2str(self, root: Optional[TreeNode]) -> str: + res = [] + + def preorder(root): + if not root: + return + res.append("(") + res.append(str(root.val)) + if not root.left and root.right: + res.append("()") + preorder(root.left) + preorder(root.right) + res.append(")") + + preorder(root) + return "".join(res)[1:-1] +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public String tree2str(TreeNode root) { + StringBuilder res = new StringBuilder(); + + preorder(root, res); + return res.substring(1, res.length() - 1); + } + + private void preorder(TreeNode root, StringBuilder res) { + if (root == null) return; + + res.append("(").append(root.val); + if (root.left == null && root.right != null) { + res.append("()"); + } + preorder(root.left, res); + preorder(root.right, res); + res.append(")"); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + string tree2str(TreeNode* root) { + string res; + preorder(root, res); + return res.substr(1, res.size() - 2); + } + +private: + void preorder(TreeNode* root, string& res) { + if (!root) return; + + res += "(" + to_string(root->val); + if (!root->left && root->right) { + res += "()"; + } + preorder(root->left, res); + preorder(root->right, res); + res += ")"; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {string} + */ + tree2str(root) { + let res = []; + + const preorder = (root) => { + if (!root) return; + + res.push('('); + res.push(root.val.toString()); + if (!root.left && root.right) { + res.push('()'); + } + preorder(root.left); + preorder(root.right); + res.push(')'); + }; + + preorder(root); + return res.join('').slice(1, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def tree2str(self, root: Optional[TreeNode]) -> str: + if not root: + return "" + + res = [] + stack = [] + last_visited = None + cur = root + + while cur or stack: + if cur: + res.append(f"({cur.val}") + if not cur.left and cur.right: + res.append("()") + + stack.append(cur) + cur = cur.left + else: + top = stack[-1] + if top.right and last_visited != top.right: + cur = top.right + else: + stack.pop() + res.append(")") + last_visited = top + + return "".join(res)[1:-1] +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public String tree2str(TreeNode root) { + if (root == null) { + return ""; + } + + StringBuilder res = new StringBuilder(); + Stack stack = new Stack<>(); + TreeNode lastVisited = null; + TreeNode cur = root; + + while (cur != null || !stack.isEmpty()) { + if (cur != null) { + res.append("(").append(cur.val); + if (cur.left == null && cur.right != null) { + res.append("()"); + } + + stack.push(cur); + cur = cur.left; + } else { + TreeNode top = stack.peek(); + if (top.right != null && lastVisited != top.right) { + cur = top.right; + } else { + stack.pop(); + res.append(")"); + lastVisited = top; + } + } + } + + return res.substring(1, res.length() - 1); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + string tree2str(TreeNode* root) { + if (!root) { + return ""; + } + + string res; + stack stack; + TreeNode* lastVisited = nullptr; + TreeNode* cur = root; + + while (cur || !stack.empty()) { + if (cur) { + res += "(" + to_string(cur->val); + if (!cur->left && cur->right) { + res += "()"; + } + + stack.push(cur); + cur = cur->left; + } else { + TreeNode* top = stack.top(); + if (top->right && lastVisited != top->right) { + cur = top->right; + } else { + stack.pop(); + res += ")"; + lastVisited = top; + } + } + } + + return res.substr(1, res.size() - 2); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {string} + */ + tree2str(root) { + if (!root) { + return ''; + } + + let res = []; + let stack = []; + let lastVisited = null; + let cur = root; + + while (cur || stack.length > 0) { + if (cur) { + res.push(`(${cur.val}`); + if (!cur.left && cur.right) { + res.push('()'); + } + + stack.push(cur); + cur = cur.left; + } else { + let top = stack[stack.length - 1]; + if (top.right && lastVisited !== top.right) { + cur = top.right; + } else { + stack.pop(); + res.push(')'); + lastVisited = top; + } + } + } + + return res.join('').slice(1, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/contains-duplicate-ii.md b/articles/contains-duplicate-ii.md index 9e1c9367e..63116d5da 100644 --- a/articles/contains-duplicate-ii.md +++ b/articles/contains-duplicate-ii.md @@ -63,12 +63,27 @@ class Solution { } ``` +```csharp +public class Solution { + public bool ContainsNearbyDuplicate(int[] nums, int k) { + for (int L = 0; L < nums.Length; L++) { + for (int R = L + 1; R < Math.Min(nums.Length, L + k + 1); R++) { + if (nums[L] == nums[R]) { + return true; + } + } + } + return false; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * min(n, k))$ -* Space complexity: $O(1)$ +- Time complexity: $O(n * min(n, k))$ +- Space complexity: $O(1)$ > Where $n$ is the size of the array $nums$ and $k$ is the maximum distance between two equal numbers. @@ -87,22 +102,22 @@ class Solution: if nums[i] in mp and i - mp[nums[i]] <= k: return True mp[nums[i]] = i - - return False + + return False ``` ```java public class Solution { public boolean containsNearbyDuplicate(int[] nums, int k) { Map map = new HashMap<>(); - + for (int i = 0; i < nums.length; i++) { if (map.containsKey(nums[i]) && i - map.get(nums[i]) <= k) { return true; } map.put(nums[i], i); } - + return false; } } @@ -113,14 +128,14 @@ class Solution { public: bool containsNearbyDuplicate(vector& nums, int k) { unordered_map mp; - + for (int i = 0; i < nums.size(); i++) { if (mp.find(nums[i]) != mp.end() && i - mp[nums[i]] <= k) { return true; } mp[nums[i]] = i; } - + return false; } }; @@ -148,12 +163,29 @@ class Solution { } ``` +```csharp +public class Solution { + public bool ContainsNearbyDuplicate(int[] nums, int k) { + Dictionary mp = new Dictionary(); + + for (int i = 0; i < nums.Length; i++) { + if (mp.ContainsKey(nums[i]) && i - mp[nums[i]] <= k) { + return true; + } + mp[nums[i]] = i; + } + + return false; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ > Where $n$ is the size of the array $nums$ and $k$ is the maximum distance between two equal numbers. @@ -176,7 +208,7 @@ class Solution: if nums[R] in window: return True window.add(nums[R]) - + return False ``` @@ -249,11 +281,33 @@ class Solution { } ``` +```csharp +public class Solution { + public bool ContainsNearbyDuplicate(int[] nums, int k) { + HashSet window = new HashSet(); + int L = 0; + + for (int R = 0; R < nums.Length; R++) { + if (R - L > k) { + window.Remove(nums[L]); + L++; + } + if (window.Contains(nums[R])) { + return true; + } + window.Add(nums[R]); + } + + return false; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(min(n, k))$ +- Time complexity: $O(n)$ +- Space complexity: $O(min(n, k))$ -> Where $n$ is the size of the array $nums$ and $k$ is the maximum distance between two equal numbers. \ No newline at end of file +> Where $n$ is the size of the array $nums$ and $k$ is the maximum distance between two equal numbers. diff --git a/articles/contiguous-array.md b/articles/contiguous-array.md index f13825744..78d3ca5fd 100644 --- a/articles/contiguous-array.md +++ b/articles/contiguous-array.md @@ -14,10 +14,10 @@ class Solution: ones += 1 else: zeros += 1 - + if ones == zeros and res < (j - i + 1): res = j - i + 1 - + return res ``` @@ -77,17 +77,19 @@ class Solution { * @return {number} */ findMaxLength(nums) { - let n = nums.length, res = 0; + let n = nums.length, + res = 0; for (let i = 0; i < n; i++) { - let zeros = 0, ones = 0; + let zeros = 0, + ones = 0; for (let j = i; j < n; j++) { if (nums[j] === 1) { ones++; } else { zeros++; } - if (ones === zeros && res < (j - i + 1)) { + if (ones === zeros && res < j - i + 1) { res = j - i + 1; } } @@ -102,8 +104,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -183,7 +185,8 @@ class Solution { */ findMaxLength(nums) { const n = nums.length; - let res = 0, count = 0; + let res = 0, + count = 0; const diffIndex = new Array(2 * n + 1).fill(-2); diffIndex[n] = -1; @@ -205,8 +208,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -306,7 +309,9 @@ class Solution { * @return {number} */ findMaxLength(nums) { - let zero = 0, one = 0, res = 0; + let zero = 0, + one = 0, + res = 0; const diffIndex = new Map(); for (let i = 0; i < nums.length; i++) { @@ -337,5 +342,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/continuous-subarray-sum.md b/articles/continuous-subarray-sum.md index a6509f498..a55bdad78 100644 --- a/articles/continuous-subarray-sum.md +++ b/articles/continuous-subarray-sum.md @@ -69,8 +69,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -91,7 +91,7 @@ class Solution: remainder[r] = i elif i - remainder[r] > 1: return True - + return False ``` @@ -171,7 +171,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(k)$ +- Time complexity: $O(n)$ +- Space complexity: $O(k)$ -> Where $n$ is the size of the array $nums$ and $k$ is the number that a subarray sum needs to be multiple of. \ No newline at end of file +> Where $n$ is the size of the array $nums$ and $k$ is the number that a subarray sum needs to be multiple of. diff --git a/articles/convert-an-array-into-a-2d-array-with-conditions.md b/articles/convert-an-array-into-a-2d-array-with-conditions.md index 7f5906f0d..671e10b85 100644 --- a/articles/convert-an-array-into-a-2d-array-with-conditions.md +++ b/articles/convert-an-array-into-a-2d-array-with-conditions.md @@ -16,7 +16,7 @@ class Solution: if r == len(res): res.append([]) res[r].append(num) - + return res ``` @@ -38,7 +38,7 @@ public class Solution { } res.get(r).add(num); } - + return res; } } @@ -63,7 +63,7 @@ public: } res[r].push_back(num); } - + return res; } }; @@ -91,7 +91,7 @@ class Solution { } res[r].push(num); } - + return res; } } @@ -101,8 +101,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n)$ for the output array. +- Time complexity: $O(n * m)$ +- Space complexity: $O(n)$ for the output array. > Where $n$ is the size of the array $nums$ and $m$ is the frequency of the most frequent element in the given array. @@ -129,7 +129,7 @@ class Solution: r += 1 j += 1 i = j - + return res ``` @@ -138,7 +138,7 @@ public class Solution { public List> findMatrix(int[] nums) { Arrays.sort(nums); List> res = new ArrayList<>(); - + int i = 0; while (i < nums.length) { int j = i; @@ -153,7 +153,7 @@ public class Solution { } i = j; } - + return res; } } @@ -179,7 +179,7 @@ public: } i = j; } - + return res; } }; @@ -209,7 +209,7 @@ class Solution { } i = j; } - + return res; } } @@ -219,8 +219,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ for the output array. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ for the output array. --- @@ -313,5 +313,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/convert-bst-to-greater-tree.md b/articles/convert-bst-to-greater-tree.md new file mode 100644 index 000000000..eacedd3f4 --- /dev/null +++ b/articles/convert-bst-to-greater-tree.md @@ -0,0 +1,800 @@ +## 1. Depth First Search (Two Pass) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]: + def getSum(node): + if not node: + return 0 + return node.val + getSum(node.left) + getSum(node.right) + + totalSum = getSum(root) + + def dfs(node): + nonlocal totalSum + if not node: + return + + dfs(node.left) + tmp = node.val + node.val = totalSum + totalSum -= tmp + dfs(node.right) + + dfs(root) + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private int totalSum; + + public TreeNode convertBST(TreeNode root) { + totalSum = getSum(root); + dfs(root); + return root; + } + + private int getSum(TreeNode node) { + if (node == null) return 0; + return node.val + getSum(node.left) + getSum(node.right); + } + + private void dfs(TreeNode node) { + if (node == null) return; + + dfs(node.left); + int tmp = node.val; + node.val = totalSum; + totalSum -= tmp; + dfs(node.right); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int totalSum; + + TreeNode* convertBST(TreeNode* root) { + totalSum = getSum(root); + dfs(root); + return root; + } + +private: + int getSum(TreeNode* node) { + if (!node) return 0; + return node->val + getSum(node->left) + getSum(node->right); + } + + void dfs(TreeNode* node) { + if (!node) return; + + dfs(node->left); + int tmp = node->val; + node->val = totalSum; + totalSum -= tmp; + dfs(node->right); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {TreeNode} + */ + convertBST(root) { + const getSum = (node) => { + if (!node) return 0; + return node.val + getSum(node.left) + getSum(node.right); + }; + + let totalSum = getSum(root); + + const dfs = (node) => { + if (!node) return; + + dfs(node.left); + let tmp = node.val; + node.val = totalSum; + totalSum -= tmp; + dfs(node.right); + }; + + dfs(root); + return root; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public TreeNode ConvertBST(TreeNode root) { + int GetSum(TreeNode node) { + if (node == null) return 0; + return node.val + GetSum(node.left) + GetSum(node.right); + } + + int totalSum = GetSum(root); + + void Dfs(TreeNode node) { + if (node == null) return; + + Dfs(node.left); + int tmp = node.val; + node.val = totalSum; + totalSum -= tmp; + Dfs(node.right); + } + + Dfs(root); + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Depth First Search (One Pass) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]: + curSum = 0 + + def dfs(node): + nonlocal curSum + if not node: + return + + dfs(node.right) + tmp = node.val + node.val += curSum + curSum += tmp + dfs(node.left) + + dfs(root) + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private int curSum = 0; + + public TreeNode convertBST(TreeNode root) { + dfs(root); + return root; + } + + private void dfs(TreeNode node) { + if (node == null) return; + + dfs(node.right); + int tmp = node.val; + node.val += curSum; + curSum += tmp; + dfs(node.left); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int curSum = 0; + + TreeNode* convertBST(TreeNode* root) { + dfs(root); + return root; + } + +private: + void dfs(TreeNode* node) { + if (!node) return; + + dfs(node->right); + int tmp = node->val; + node->val += curSum; + curSum += tmp; + dfs(node->left); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {TreeNode} + */ + convertBST(root) { + let curSum = 0; + + const dfs = (node) => { + if (!node) return; + + dfs(node.right); + let tmp = node.val; + node.val += curSum; + curSum += tmp; + dfs(node.left); + }; + + dfs(root); + return root; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public TreeNode ConvertBST(TreeNode root) { + int curSum = 0; + + void Dfs(TreeNode node) { + if (node == null) return; + + Dfs(node.right); + int tmp = node.val; + node.val += curSum; + curSum += tmp; + Dfs(node.left); + } + + Dfs(root); + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]: + curSum = 0 + stack = [] + node = root + + while stack or node: + while node: + stack.append(node) + node = node.right + + node = stack.pop() + curSum += node.val + node.val = curSum + node = node.left + + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode convertBST(TreeNode root) { + int curSum = 0; + Stack stack = new Stack<>(); + TreeNode node = root; + + while (!stack.isEmpty() || node != null) { + while (node != null) { + stack.push(node); + node = node.right; + } + + node = stack.pop(); + curSum += node.val; + node.val = curSum; + node = node.left; + } + return root; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* convertBST(TreeNode* root) { + int curSum = 0; + stack st; + TreeNode* node = root; + + while (!st.empty() || node) { + while (node) { + st.push(node); + node = node->right; + } + + node = st.top(); st.pop(); + curSum += node->val; + node->val = curSum; + node = node->left; + } + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {TreeNode} + */ + convertBST(root) { + let curSum = 0; + const stack = []; + let node = root; + + while (stack.length || node) { + while (node) { + stack.push(node); + node = node.right; + } + + node = stack.pop(); + curSum += node.val; + node.val = curSum; + node = node.left; + } + return root; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public TreeNode ConvertBST(TreeNode root) { + int curSum = 0; + Stack stack = new Stack(); + TreeNode node = root; + + while (stack.Count > 0 || node != null) { + while (node != null) { + stack.Push(node); + node = node.right; + } + + node = stack.Pop(); + curSum += node.val; + node.val = curSum; + node = node.left; + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Morris Traversal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def convertBST(self, root: Optional[TreeNode]) -> Optional[TreeNode]: + curSum = 0 + cur = root + + while cur: + if cur.right: + prev = cur.right + while prev.left and prev.left != cur: + prev = prev.left + + if not prev.left: + prev.left = cur + cur = cur.right + else: + prev.left = None + curSum += cur.val + cur.val = curSum + cur = cur.left + else: + curSum += cur.val + cur.val = curSum + cur = cur.left + + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode convertBST(TreeNode root) { + int curSum = 0; + TreeNode cur = root; + + while (cur != null) { + if (cur.right != null) { + TreeNode prev = cur.right; + while (prev.left != null && prev.left != cur) { + prev = prev.left; + } + + if (prev.left == null) { + prev.left = cur; + cur = cur.right; + } else { + prev.left = null; + curSum += cur.val; + cur.val = curSum; + cur = cur.left; + } + } else { + curSum += cur.val; + cur.val = curSum; + cur = cur.left; + } + } + return root; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* convertBST(TreeNode* root) { + int curSum = 0; + TreeNode* cur = root; + + while (cur) { + if (cur->right) { + TreeNode* prev = cur->right; + while (prev->left && prev->left != cur) { + prev = prev->left; + } + + if (!prev->left) { + prev->left = cur; + cur = cur->right; + } else { + prev->left = nullptr; + curSum += cur->val; + cur->val = curSum; + cur = cur->left; + } + } else { + curSum += cur->val; + cur->val = curSum; + cur = cur->left; + } + } + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {TreeNode} + */ + convertBST(root) { + let curSum = 0; + let cur = root; + + while (cur) { + if (cur.right) { + let prev = cur.right; + while (prev.left && prev.left !== cur) { + prev = prev.left; + } + + if (!prev.left) { + prev.left = cur; + cur = cur.right; + } else { + prev.left = null; + curSum += cur.val; + cur.val = curSum; + cur = cur.left; + } + } else { + curSum += cur.val; + cur.val = curSum; + cur = cur.left; + } + } + return root; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public TreeNode ConvertBST(TreeNode root) { + int curSum = 0; + TreeNode cur = root; + + while (cur != null) { + if (cur.right != null) { + TreeNode prev = cur.right; + while (prev.left != null && prev.left != cur) { + prev = prev.left; + } + + if (prev.left == null) { + prev.left = cur; + cur = cur.right; + } else { + prev.left = null; + curSum += cur.val; + cur.val = curSum; + cur = cur.left; + } + } else { + curSum += cur.val; + cur.val = curSum; + cur = cur.left; + } + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/convert-sorted-array-to-binary-search-tree.md b/articles/convert-sorted-array-to-binary-search-tree.md new file mode 100644 index 000000000..366f0e2e7 --- /dev/null +++ b/articles/convert-sorted-array-to-binary-search-tree.md @@ -0,0 +1,437 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def sortedArrayToBST(self, nums: List[int]) -> Optional[TreeNode]: + if not nums: + return None + + mid = len(nums) // 2 + root = TreeNode(nums[mid]) + root.left = self.sortedArrayToBST(nums[:mid]) + root.right = self.sortedArrayToBST(nums[mid + 1:]) + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode sortedArrayToBST(int[] nums) { + if (nums.length == 0) { + return null; + } + + int mid = nums.length / 2; + TreeNode root = new TreeNode(nums[mid]); + root.left = sortedArrayToBST(Arrays.copyOfRange(nums, 0, mid)); + root.right = sortedArrayToBST(Arrays.copyOfRange(nums, mid + 1, nums.length)); + return root; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* sortedArrayToBST(vector& nums) { + if (nums.empty()) { + return nullptr; + } + + int mid = nums.size() / 2; + TreeNode* root = new TreeNode(nums[mid]); + vector left(nums.begin(), nums.begin() + mid); + vector right(nums.begin() + mid + 1, nums.end()); + root->left = sortedArrayToBST(left); + root->right = sortedArrayToBST(right); + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number[]} nums + * @return {TreeNode} + */ + sortedArrayToBST(nums) { + if (nums.length === 0) { + return null; + } + + const mid = Math.floor(nums.length / 2); + const root = new TreeNode(nums[mid]); + root.left = this.sortedArrayToBST(nums.slice(0, mid)); + root.right = this.sortedArrayToBST(nums.slice(mid + 1)); + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Depth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def sortedArrayToBST(self, nums: List[int]) -> TreeNode: + def helper(l, r): + if l > r: + return None + m = (l + r) // 2 + root = TreeNode(nums[m]) + root.left = helper(l, m - 1) + root.right = helper(m + 1, r) + return root + + return helper(0, len(nums) - 1) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode sortedArrayToBST(int[] nums) { + return helper(nums, 0, nums.length - 1); + } + + private TreeNode helper(int[] nums, int l, int r) { + if (l > r) { + return null; + } + int m = (l + r) / 2; + TreeNode root = new TreeNode(nums[m]); + root.left = helper(nums, l, m - 1); + root.right = helper(nums, m + 1, r); + return root; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* sortedArrayToBST(vector& nums) { + return helper(nums, 0, nums.size() - 1); + } + +private: + TreeNode* helper(vector& nums, int l, int r) { + if (l > r) { + return nullptr; + } + int m = (l + r) / 2; + TreeNode* root = new TreeNode(nums[m]); + root->left = helper(nums, l, m - 1); + root->right = helper(nums, m + 1, r); + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number[]} nums + * @return {TreeNode} + */ + sortedArrayToBST(nums) { + const helper = (l, r) => { + if (l > r) { + return null; + } + const m = Math.floor((l + r) / 2); + const root = new TreeNode(nums[m]); + root.left = helper(l, m - 1); + root.right = helper(m + 1, r); + return root; + }; + + return helper(0, nums.length - 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: + - $O(\log n)$ space for recursion stack. + - $O(n)$ space for the output. + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def sortedArrayToBST(self, nums: List[int]) -> TreeNode: + if not nums: + return None + + root = TreeNode(0) + stack = [(root, 0, len(nums) - 1)] + + while stack: + node, l, r = stack.pop() + m = (l + r) // 2 + node.val = nums[m] + if l <= m - 1: + node.left = TreeNode(0) + stack.append((node.left, l, m - 1)) + if m + 1 <= r: + node.right = TreeNode(0) + stack.append((node.right, m + 1, r)) + + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode sortedArrayToBST(int[] nums) { + if (nums.length == 0) { + return null; + } + + TreeNode root = new TreeNode(0); + Stack stack = new Stack<>(); + Stack nodes = new Stack<>(); + stack.push(new int[]{0, nums.length - 1}); + nodes.push(root); + + while (!stack.isEmpty()) { + int[] range = stack.pop(); + TreeNode node = nodes.pop(); + int l = range[0], r = range[1]; + int m = (l + r) / 2; + node.val = nums[m]; + + if (l <= m - 1) { + node.left = new TreeNode(0); + stack.push(new int[]{l, m - 1}); + nodes.push(node.left); + } + if (m + 1 <= r) { + node.right = new TreeNode(0); + stack.push(new int[]{m + 1, r}); + nodes.push(node.right); + } + } + + return root; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* sortedArrayToBST(vector& nums) { + if (nums.empty()) return nullptr; + + TreeNode* root = new TreeNode(0); + stack> stack; + stack.push({root, 0, (int)nums.size() - 1}); + + while (!stack.empty()) { + auto [node, l, r] = stack.top(); + stack.pop(); + int m = (l + r) / 2; + node->val = nums[m]; + + if (l <= m - 1) { + node->left = new TreeNode(0); + stack.push({node->left, l, m - 1}); + } + if (m + 1 <= r) { + node->right = new TreeNode(0); + stack.push({node->right, m + 1, r}); + } + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number[]} nums + * @return {TreeNode} + */ + sortedArrayToBST(nums) { + if (nums.length === 0) { + return null; + } + + const root = new TreeNode(0); + const stack = [[root, 0, nums.length - 1]]; + + while (stack.length) { + const [node, l, r] = stack.pop(); + const m = Math.floor((l + r) / 2); + node.val = nums[m]; + + if (l <= m - 1) { + node.left = new TreeNode(0); + stack.push([node.left, l, m - 1]); + } + if (m + 1 <= r) { + node.right = new TreeNode(0); + stack.push([node.right, m + 1, r]); + } + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: + - $O(\log n)$ space for the stack. + - $O(n)$ space for the output. diff --git a/articles/copy-linked-list-with-random-pointer.md b/articles/copy-linked-list-with-random-pointer.md index 2c8acaed9..c5306458c 100644 --- a/articles/copy-linked-list-with-random-pointer.md +++ b/articles/copy-linked-list-with-random-pointer.md @@ -1,4 +1,4 @@ -## 1. Hash Map (Recursion) +## 1. Recursion + Hash Map ::tabs-start @@ -21,7 +21,7 @@ class Solution: return None if head in self.map: return self.map[head] - + copy = Node(head.val) self.map[head] = copy copy.next = self.copyRandomList(head.next) @@ -69,7 +69,7 @@ public: int val; Node* next; Node* random; - + Node(int _val) { val = _val; next = NULL; @@ -115,7 +115,7 @@ class Solution { copyRandomList(head) { if (head === null) return null; if (this.map.has(head)) return this.map.get(head); - + const copy = new Node(head.val); this.map.set(head, copy); copy.next = this.copyRandomList(head.next); @@ -132,7 +132,7 @@ public class Node { public int val; public Node next; public Node random; - + public Node(int _val) { val = _val; next = null; @@ -151,7 +151,7 @@ public class Solution { Node copy = new Node(head.val); map[head] = copy; copy.next = copyRandomList(head.next); - + if (head.random != null) { copy.random = copyRandomList(head.random); } else { @@ -182,7 +182,7 @@ func copyRandomList(head *Node) *Node { if val, exists := m[head]; exists { return val } - + copy := &Node{Val: head.Val} m[head] = copy copy.Next = copyRandomList(head.Next) @@ -213,7 +213,7 @@ class Solution { if (map.containsKey(head)) { return map[head] } - + val copy = Node(head.`val`) map[head] = copy copy.next = copyRandomList(head.next) @@ -223,12 +223,50 @@ class Solution { } ``` +```swift +/** + * Definition for a Node. + * public class Node { + * public var val: Int + * public var next: Node? + * public var random: Node? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * self.random = nil + * } + * } + */ + +class Solution { + private var map = [Node: Node]() + + func copyRandomList(_ head: Node?) -> Node? { + if head == nil { + return nil + } + + if let copied = map[head!] { + return copied + } + + let copy = Node(head!.val) + map[head!] = copy + + copy.next = copyRandomList(head!.next) + copy.random = copyRandomList(head!.random) + + return copy + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -313,7 +351,7 @@ public: int val; Node* next; Node* random; - + Node(int _val) { val = _val; next = NULL; @@ -393,7 +431,7 @@ public class Node { public int val; public Node next; public Node random; - + public Node(int _val) { val = _val; next = null; @@ -494,12 +532,51 @@ class Solution { } ``` +```swift +/** + * Definition for a Node. + * public class Node { + * public var val: Int + * public var next: Node? + * public var random: Node? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * self.random = nil + * } + * } + */ + +class Solution { + func copyRandomList(_ head: Node?) -> Node? { + var oldToCopy: [Node?: Node?] = [nil: nil] + + var cur = head + while cur != nil { + let copy = Node(cur!.val) + oldToCopy[cur] = copy + cur = cur?.next + } + + cur = head + while cur != nil { + let copy = oldToCopy[cur]! + copy?.next = oldToCopy[cur?.next]! + copy?.random = oldToCopy[cur?.random]! + cur = cur?.next + } + + return oldToCopy[head]! + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -521,7 +598,7 @@ class Solution: def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]': oldToCopy = collections.defaultdict(lambda: Node(0)) oldToCopy[None] = None - + cur = head while cur: oldToCopy[cur].val = cur.val @@ -583,7 +660,7 @@ public: int val; Node* next; Node* random; - + Node(int _val) { val = _val; next = NULL; @@ -665,7 +742,7 @@ public class Node { public int val; public Node next; public Node random; - + public Node(int _val) { val = _val; next = null; @@ -789,12 +866,52 @@ class Solution { } ``` +```swift +/** + * Definition for a Node. + * public class Node { + * public var val: Int + * public var next: Node? + * public var random: Node? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * self.random = nil + * } + * } + */ + +class Solution { + func copyRandomList(_ head: Node?) -> Node? { + var oldToCopy = [Node?: Node?]() + + func getNode(_ node: Node?) -> Node? { + if node == nil { return nil } + if oldToCopy[node] == nil { + oldToCopy[node] = Node(0) + } + return oldToCopy[node]! + } + + var cur = head + while cur != nil { + getNode(cur)!.val = cur!.val + getNode(cur)!.next = getNode(cur!.next) + getNode(cur)!.random = getNode(cur!.random) + cur = cur!.next + } + + return getNode(head) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -816,22 +933,22 @@ class Solution: def copyRandomList(self, head: 'Optional[Node]') -> 'Optional[Node]': if head is None: return None - + l1 = head while l1 is not None: l2 = Node(l1.val) l2.next = l1.next l1.next = l2 l1 = l2.next - + newHead = head.next - + l1 = head while l1 is not None: if l1.random is not None: l1.next.random = l1.random.next l1 = l1.next.next - + l1 = head while l1 is not None: l2 = l1.next @@ -839,7 +956,7 @@ class Solution: if l2.next is not None: l2.next = l2.next.next l1 = l1.next - + return newHead ``` @@ -864,7 +981,7 @@ public class Solution { if (head == null) { return null; } - + Node l1 = head; while (l1 != null) { Node l2 = new Node(l1.val); @@ -906,7 +1023,7 @@ public: int val; Node* next; Node* random; - + Node(int _val) { val = _val; next = NULL; @@ -973,7 +1090,7 @@ class Solution { if (!head) { return null; } - + let l1 = head; while (l1) { const l2 = new Node(l1.val); @@ -1014,7 +1131,7 @@ public class Node { public int val; public Node next; public Node random; - + public Node(int _val) { val = _val; next = null; @@ -1028,7 +1145,7 @@ public class Solution { if (head == null) { return null; } - + Node l1 = head; while (l1 != null) { Node l2 = new Node(l1.val); @@ -1149,7 +1266,7 @@ class Solution { while (l1 != null) { val l2 = l1.next l1.next = l2?.next - val nextL2 = l2?.next + val nextL2 = l2?.next if (nextL2 != null) { l2.next = nextL2.next } @@ -1161,12 +1278,67 @@ class Solution { } ``` +```swift +/** + * Definition for a Node. + * public class Node { + * public var val: Int + * public var next: Node? + * public var random: Node? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * self.random = nil + * } + * } + */ + +class Solution { + func copyRandomList(_ head: Node?) -> Node? { + if head == nil { + return nil + } + + var l1 = head + while l1 != nil { + let l2 = Node(l1!.val) + l2.next = l1?.next + l1?.next = l2 + l1 = l2.next + } + + let newHead = head?.next + l1 = head + while l1 != nil { + if let random = l1?.random { + l1?.next?.random = random.next + } + l1 = l1?.next?.next + } + + l1 = head + while l1 != nil { + let l2 = l1?.next + l1?.next = l2?.next + if l2?.next != nil { + l2?.next = l2?.next?.next + } + l1 = l1?.next + } + + return newHead + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ for the output. --- @@ -1195,15 +1367,15 @@ class Solution: l2.next = l1.random l1.random = l2 l1 = l1.next - + newHead = head.random - + l1 = head while l1: l2 = l1.random l2.random = l2.next.random if l2.next else None l1 = l1.next - + l1 = head while l1 is not None: l2 = l1.random @@ -1274,7 +1446,7 @@ public: int val; Node* next; Node* random; - + Node(int _val) { val = _val; next = NULL; @@ -1376,7 +1548,7 @@ public class Node { public int val; public Node next; public Node random; - + public Node(int _val) { val = _val; next = null; @@ -1525,9 +1697,62 @@ class Solution { } ``` +```swift +/** + * Definition for a Node. + * public class Node { + * public var val: Int + * public var next: Node? + * public var random: Node? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * self.random = nil + * } + * } + */ + +class Solution { + func copyRandomList(_ head: Node?) -> Node? { + if head == nil { + return nil + } + + var l1 = head + while l1 != nil { + let l2 = Node(l1!.val) + l2.next = l1?.random + l1?.random = l2 + l1 = l1?.next + } + + let newHead = head?.random + + l1 = head + while l1 != nil { + let l2 = l1?.random + l2?.random = l2?.next?.random + l1 = l1?.next + } + + l1 = head + while l1 != nil { + let l2 = l1?.random + l1?.random = l2?.next + l2?.next = l1?.next?.random + l1 = l1?.next + } + + return newHead + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ for the output. diff --git a/articles/count-all-valid-pickup-and-delivery-options.md b/articles/count-all-valid-pickup-and-delivery-options.md new file mode 100644 index 000000000..cb4cccaaa --- /dev/null +++ b/articles/count-all-valid-pickup-and-delivery-options.md @@ -0,0 +1,671 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def countOrders(self, n: int) -> int: + MOD = 1000000007 + + def dfs(picked, delivered): + if picked == n and delivered == n: + return 1 + + res = 0 + if picked < n: + res = (res + (n - picked) * dfs(picked + 1, delivered)) % MOD + if delivered < picked: + res = (res + (picked - delivered) * dfs(picked, delivered + 1)) % MOD + + return res + + return dfs(0, 0) +``` + +```java +public class Solution { + private static final int MOD = 1_000_000_007; + + public int countOrders(int n) { + return dfs(0, 0, n); + } + + private int dfs(int picked, int delivered, int n) { + if (picked == n && delivered == n) { + return 1; + } + + long res = 0; + if (picked < n) { + res = ((res + (n - picked) * 1L * dfs(picked + 1, delivered, n)) % MOD); + } + if (delivered < picked) { + res = ((res + (picked - delivered) * 1L * dfs(picked, delivered + 1, n)) % MOD); + } + + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + static const int MOD = 1'000'000'007; + + int countOrders(int n) { + return dfs(0, 0, n); + } + +private: + int dfs(int picked, int delivered, int n) { + if (picked == n && delivered == n) { + return 1; + } + + int res = 0; + if (picked < n) { + res = (res + (n - picked) * 1LL * dfs(picked + 1, delivered, n)) % MOD; + } + if (delivered < picked) { + res = (res + (picked - delivered) * 1LL * dfs(picked, delivered + 1, n)) % MOD; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + countOrders(n) { + const MOD = 1_000_000_007; + + const dfs = (picked, delivered) => { + if (picked === n && delivered === n) { + return 1; + } + + let res = 0; + if (picked < n) { + res = (res + (n - picked) * dfs(picked + 1, delivered)) % MOD; + } + if (delivered < picked) { + res = + (res + (picked - delivered) * dfs(picked, delivered + 1)) % + MOD; + } + + return res; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def countOrders(self, n: int) -> int: + MOD = 1000000007 + dp = [[-1] * (n + 1) for _ in range(n + 1)] + dp[n][n] = 1 + + def dfs(picked, delivered): + if dp[picked][delivered] != -1: + return dp[picked][delivered] + + res = 0 + if picked < n: + res = (res + (n - picked) * dfs(picked + 1, delivered)) % MOD + if delivered < picked: + res = (res + (picked - delivered) * dfs(picked, delivered + 1)) % MOD + + dp[picked][delivered] = res + return res + + return dfs(0, 0) +``` + +```java +public class Solution { + private static final int MOD = 1_000_000_007; + private int[][] dp; + + public int countOrders(int n) { + dp = new int[n + 1][n + 1]; + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= n; j++) { + dp[i][j] = -1; + } + } + dp[n][n] = 1; + return dfs(0, 0, n); + } + + private int dfs(int picked, int delivered, int n) { + if (dp[picked][delivered] != -1) { + return dp[picked][delivered]; + } + + long res = 0; + if (picked < n) { + res = ((res + (n - picked) * 1L * dfs(picked + 1, delivered, n)) % MOD); + } + if (delivered < picked) { + res = ((res + (picked - delivered) * 1L * dfs(picked, delivered + 1, n)) % MOD); + } + + return dp[picked][delivered] = (int)res; + } +} +``` + +```cpp +class Solution { +public: + static const int MOD = 1'000'000'007; + vector> dp; + + int countOrders(int n) { + dp.assign(n + 1, vector(n + 1, -1)); + dp[n][n] = 1; + return dfs(0, 0, n); + } + +private: + int dfs(int picked, int delivered, int n) { + if (dp[picked][delivered] != -1) { + return dp[picked][delivered]; + } + + int res = 0; + if (picked < n) { + res = (res + (n - picked) * 1LL * dfs(picked + 1, delivered, n)) % MOD; + } + if (delivered < picked) { + res = (res + (picked - delivered) * 1LL * dfs(picked, delivered + 1, n)) % MOD; + } + + return dp[picked][delivered] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + countOrders(n) { + const MOD = 1_000_000_007; + const dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(-1)); + + const dfs = (picked, delivered) => { + if (picked === n && delivered === n) { + return 1; + } + if (dp[picked][delivered] !== -1) { + return dp[picked][delivered]; + } + + let res = 0; + if (picked < n) { + res = (res + (n - picked) * dfs(picked + 1, delivered)) % MOD; + } + if (delivered < picked) { + res = + (res + (picked - delivered) * dfs(picked, delivered + 1)) % + MOD; + } + + dp[picked][delivered] = res; + return res; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def countOrders(self, n: int) -> int: + MOD = 1000000007 + dp = [[0] * (n + 1) for _ in range(n + 1)] + dp[0][0] = 1 + + for picked in range(n + 1): + for delivered in range(n + 1): + if picked < n: + dp[picked + 1][delivered] = ( + (dp[picked + 1][delivered] + + (n - picked) * dp[picked][delivered]) % MOD + ) + + if delivered < picked: + dp[picked][delivered + 1] = ( + (dp[picked][delivered + 1] + + (picked - delivered) * dp[picked][delivered]) % MOD + ) + + return dp[n][n] +``` + +```java +public class Solution { + public int countOrders(int n) { + final int MOD = 1_000_000_007; + int[][] dp = new int[n + 1][n + 1]; + dp[0][0] = 1; + + for (int picked = 0; picked <= n; picked++) { + for (int delivered = 0; delivered <= n; delivered++) { + if (picked < n) { + dp[picked + 1][delivered] = (int) ((dp[picked + 1][delivered] + + (n - picked) * 1L * dp[picked][delivered]) % MOD); + } + if (delivered < picked) { + dp[picked][delivered + 1] = (int) ((dp[picked][delivered + 1] + + (picked - delivered) * 1L * dp[picked][delivered]) % MOD); + } + } + } + + return dp[n][n]; + } +} +``` + +```cpp +class Solution { +public: + int countOrders(int n) { + const int MOD = 1'000'000'007; + vector> dp(n + 1, vector(n + 1, 0)); + dp[0][0] = 1; + + for (int picked = 0; picked <= n; picked++) { + for (int delivered = 0; delivered <= n; delivered++) { + if (picked < n) { + dp[picked + 1][delivered] = (dp[picked + 1][delivered] + + (n - picked) * 1LL * dp[picked][delivered]) % MOD; + } + if (delivered < picked) { + dp[picked][delivered + 1] = (dp[picked][delivered + 1] + + (picked - delivered) * 1LL * dp[picked][delivered]) % MOD; + } + } + } + + return dp[n][n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + countOrders(n) { + const MOD = 1_000_000_007; + const dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(0)); + dp[0][0] = 1; + + for (let picked = 0; picked <= n; picked++) { + for (let delivered = 0; delivered <= n; delivered++) { + if (picked < n) { + dp[picked + 1][delivered] = + (dp[picked + 1][delivered] + + (n - picked) * dp[picked][delivered]) % + MOD; + } + + if (delivered < picked) { + dp[picked][delivered + 1] = + (dp[picked][delivered + 1] + + (picked - delivered) * dp[picked][delivered]) % + MOD; + } + } + } + + return dp[n][n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def countOrders(self, n: int) -> int: + MOD = 1000000007 + dp = [0] * (n + 1) + dp[0] = 1 + + for picked in range(n + 1): + for delivered in range(picked): + dp[delivered + 1] = ( + (dp[delivered + 1] + + (picked - delivered) * dp[delivered]) % MOD + ) + + if picked < n: + next_dp = [0] * (n + 1) + for delivered in range(picked + 1): + next_dp[delivered] = ( + (next_dp[delivered] + + (n - picked) * dp[delivered]) % MOD + ) + dp = next_dp + + return dp[n] +``` + +```java +public class Solution { + public int countOrders(int n) { + int MOD = 1000000007; + int[] dp = new int[n + 1]; + dp[0] = 1; + + for (int picked = 0; picked <= n; picked++) { + for (int delivered = 0; delivered < picked; delivered++) { + dp[delivered + 1] = (int)((dp[delivered + 1] + + (picked - delivered) * 1L * dp[delivered]) % MOD); + } + + if (picked < n) { + int[] next_dp = new int[n + 1]; + for (int delivered = 0; delivered <= picked; delivered++) { + next_dp[delivered] = (int)((next_dp[delivered] + + (n - picked) * 1L *dp[delivered]) % MOD); + } + dp = next_dp; + } + } + + return dp[n]; + } +} +``` + +```cpp +class Solution { +public: + int countOrders(int n) { + const int MOD = 1000000007; + vector dp(n + 1); + dp[0] = 1; + + for (int picked = 0; picked <= n; picked++) { + for (int delivered = 0; delivered < picked; delivered++) { + dp[delivered + 1] = (int)((dp[delivered + 1] + + (picked - delivered) * 1LL * dp[delivered]) % MOD); + } + if (picked < n) { + vector next_dp(n + 1); + for (int delivered = 0; delivered <= picked; delivered++) { + next_dp[delivered] = (int)((next_dp[delivered] + + (n - picked) * 1LL * dp[delivered]) % MOD); + } + dp = next_dp; + } + } + + return dp[n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + countOrders(n) { + const MOD = 1000000007; + let dp = new Array(n + 1).fill(0); + dp[0] = 1; + + for (let picked = 0; picked <= n; picked++) { + for (let delivered = 0; delivered < picked; delivered++) { + dp[delivered + 1] = + (dp[delivered + 1] + (picked - delivered) * dp[delivered]) % + MOD; + } + + if (picked < n) { + let next_dp = new Array(n + 1).fill(0); + for (let delivered = 0; delivered <= picked; delivered++) { + next_dp[delivered] = + (next_dp[delivered] + (n - picked) * dp[delivered]) % + MOD; + } + dp = next_dp; + } + } + + return dp[n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 5. Combinatorics + +::tabs-start + +```python +class Solution: + def countOrders(self, n: int) -> int: + MOD = 1000000007 + slots, res = 2 * n, 1 + while slots > 0: + valid_choices = slots * (slots - 1) // 2 + res = (res * valid_choices) % MOD + slots -= 2 + return res +``` + +```java +public class Solution { + public int countOrders(int n) { + int MOD = 1000000007; + long slots = 2 * n, res = 1; + + while (slots > 0) { + long validChoices = slots * (slots - 1) / 2; + res = (res * validChoices) % MOD; + slots -= 2; + } + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int countOrders(int n) { + const int MOD = 1000000007; + long long slots = 2 * n, res = 1; + + while (slots > 0) { + long long validChoices = slots * (slots - 1) / 2; + res = (res * validChoices) % MOD; + slots -= 2; + } + return (int) res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + countOrders(n) { + const MOD = 1000000007; + let slots = 2 * n, + res = 1; + + while (slots > 0) { + let validChoices = (slots * (slots - 1)) / 2; + res = (res * validChoices) % MOD; + slots -= 2; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 6. Probability + +::tabs-start + +```python +class Solution: + def countOrders(self, n: int) -> int: + MOD = 1000000007 + res = 1 + + for slot in range(1, 2 * n + 1): + res *= slot + if slot % 2 == 0: + res >>= 1 + res %= MOD + + return res +``` + +```java +public class Solution { + public int countOrders(int n) { + int MOD = 1000000007; + long res = 1; + + for (int slot = 1; slot <= 2 * n; slot++) { + res *= slot; + if (slot % 2 == 0) { + res >>= 1; + } + res %= MOD; + } + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int countOrders(int n) { + const int MOD = 1000000007; + long long res = 1; + + for (int slot = 1; slot <= 2 * n; slot++) { + res *= slot; + if (slot % 2 == 0) { + res >>= 1; + } + res %= MOD; + } + return (int) res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + countOrders(n) { + const MOD = BigInt(1000000007); + let res = BigInt(1); + + for (let slot = 1; slot <= 2 * n; slot++) { + res *= BigInt(slot); + if (slot % 2 === 0) { + res /= BigInt(2); + } + res %= MOD; + } + return Number(res); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/count-connected-components.md b/articles/count-connected-components.md index 0f0dc28ba..6027f2b24 100644 --- a/articles/count-connected-components.md +++ b/articles/count-connected-components.md @@ -16,7 +16,7 @@ class Solution: if not visit[nei]: visit[nei] = True dfs(nei) - + res = 0 for node in range(n): if not visit[node]: @@ -229,12 +229,47 @@ class Solution { } ``` +```swift +class Solution { + func countComponents(_ n: Int, _ edges: [[Int]]) -> Int { + var adj = Array(repeating: [Int](), count: n) + var visit = Array(repeating: false, count: n) + + for edge in edges { + let u = edge[0], v = edge[1] + adj[u].append(v) + adj[v].append(u) + } + + func dfs(_ node: Int) { + for nei in adj[node] { + if !visit[nei] { + visit[nei] = true + dfs(nei) + } + } + } + + var res = 0 + for node in 0.. Where $V$ is the number of vertices and $E$ is the number of edges in the graph. @@ -262,7 +297,7 @@ class Solution: if not visit[nei]: visit[nei] = True q.append(nei) - + res = 0 for node in range(n): if not visit[node]: @@ -448,11 +483,11 @@ func countComponents(n int, edges [][]int) int { visit[node] = true for len(q) > 0 { cur := q[0] - q = q[1:] + q = q[1:] for _, nei := range adj[cur] { if !visit[nei] { visit[nei] = true - q = append(q, nei) + q = append(q, nei) } } } @@ -506,12 +541,50 @@ class Solution { } ``` +```swift +class Solution { + func countComponents(_ n: Int, _ edges: [[Int]]) -> Int { + var adj = Array(repeating: [Int](), count: n) + var visit = Array(repeating: false, count: n) + for edge in edges { + let u = edge[0], v = edge[1] + adj[u].append(v) + adj[v].append(u) + } + + func bfs(_ node: Int) { + var q = Deque() + q.append(node) + visit[node] = true + while !q.isEmpty { + let cur = q.removeFirst() + for nei in adj[cur] { + if !visit[nei] { + visit[nei] = true + q.append(nei) + } + } + } + } + + var res = 0 + for node in 0.. Where $V$ is the number of vertices and $E$ is the number of edges in the graph. @@ -556,7 +629,7 @@ class Solution: ``` ```java -public class DSU { +class DSU { int[] parent; int[] rank; @@ -877,11 +950,60 @@ class Solution { } ``` +```swift +class DSU { + var parent: [Int] + var rank: [Int] + + init(_ n: Int) { + parent = Array(0.. Int { + var cur = node + while cur != parent[cur] { + parent[cur] = parent[parent[cur]] + cur = parent[cur] + } + return cur + } + + func union(_ u: Int, _ v: Int) -> Bool { + let pu = find(u) + let pv = find(v) + if pu == pv { return false } + var rootU = pu + var rootV = pv + if rank[rootV] > rank[rootU] { + swap(&rootU, &rootV) + } + parent[rootV] = rootU + rank[rootU] += rank[rootV] + return true + } +} + +class Solution { + func countComponents(_ n: Int, _ edges: [[Int]]) -> Int { + let dsu = DSU(n) + var res = n + for edge in edges { + let u = edge[0], v = edge[1] + if dsu.union(u, v) { + res -= 1 + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V + (E * α(V)))$ -* Space complexity: $O(V)$ +- Time complexity: $O(V + (E * α(V)))$ +- Space complexity: $O(V)$ -> Where $V$ is the number of vertices and $E$ is the number of edges in the graph. $α()$ is used for amortized complexity. \ No newline at end of file +> Where $V$ is the number of vertices and $E$ is the number of edges in the graph. $α()$ is used for amortized complexity. diff --git a/articles/count-good-nodes-in-binary-tree.md b/articles/count-good-nodes-in-binary-tree.md index 1eda1a860..f1d78248e 100644 --- a/articles/count-good-nodes-in-binary-tree.md +++ b/articles/count-good-nodes-in-binary-tree.md @@ -44,7 +44,7 @@ class Solution: */ class Solution { - + public int goodNodes(TreeNode root) { return dfs(root, root.val); } @@ -153,7 +153,7 @@ class Solution { */ public class Solution { - + public int GoodNodes(TreeNode root) { return Dfs(root, root.val); } @@ -196,11 +196,11 @@ func goodNodes(root *TreeNode) int { if node.Val >= maxVal { res = 1 } - + maxVal = max(maxVal, node.Val) res += dfs(node.Left, maxVal) res += dfs(node.Right, maxVal) - + return res } @@ -250,12 +250,45 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func goodNodes(_ root: TreeNode?) -> Int { + func dfs(_ node: TreeNode?, _ maxVal: Int) -> Int { + guard let node = node else { return 0 } + + var res = node.val >= maxVal ? 1 : 0 + let newMaxVal = max(maxVal, node.val) + res += dfs(node.left, newMaxVal) + res += dfs(node.right, newMaxVal) + return res + } + + return dfs(root, root?.val ?? Int.min) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -275,20 +308,20 @@ class Solution: def goodNodes(self, root: TreeNode) -> int: res = 0 q = deque() - + q.append((root,-float('inf'))) while q: node,maxval = q.popleft() - if node.val >= maxval: + if node.val >= maxval: res += 1 - - if node.left: + + if node.left: q.append((node.left,max(maxval,node.val))) - + if node.right: q.append((node.right,max(maxval,node.val))) - + return res ``` @@ -545,9 +578,54 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func goodNodes(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + + var res = 0 + var q = Deque<(TreeNode, Int)>() + q.append((root, Int.min)) + + while !q.isEmpty { + let (node, maxVal) = q.popFirst()! + if node.val >= maxVal { + res += 1 + } + + let newMaxVal = max(maxVal, node.val) + + if let left = node.left { + q.append((left, newMaxVal)) + } + if let right = node.right { + q.append((right, newMaxVal)) + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/count-number-of-bad-pairs.md b/articles/count-number-of-bad-pairs.md new file mode 100644 index 000000000..7f5cee56e --- /dev/null +++ b/articles/count-number-of-bad-pairs.md @@ -0,0 +1,159 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def countBadPairs(self, nums: List[int]) -> int: + n, res = len(nums), 0 + for i in range(n - 1): + for j in range(i + 1, n): + if j - i != nums[j] - nums[i]: + res += 1 + return res +``` + +```java +public class Solution { + public long countBadPairs(int[] nums) { + int n = nums.length; + long res = 0; + for (int i = 0; i < n - 1; i++) { + for (int j = i + 1; j < n; j++) { + if (j - i != nums[j] - nums[i]) { + res++; + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + long long countBadPairs(vector& nums) { + int n = nums.size(); + long long res = 0; + for (int i = 0; i < n - 1; i++) { + for (int j = i + 1; j < n; j++) { + if (j - i != nums[j] - nums[i]) { + res++; + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + countBadPairs(nums) { + let n = nums.length, + res = 0; + for (let i = 0; i < n - 1; i++) { + for (let j = i + 1; j < n; j++) { + if (j - i !== nums[j] - nums[i]) { + res++; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Hash Map + +::tabs-start + +```python +class Solution: + def countBadPairs(self, nums: List[int]) -> int: + good_pairs = 0 + total_pairs = 0 + count = defaultdict(int) + + for i in range(len(nums)): + total_pairs += i + good_pairs += count[nums[i] - i] + count[nums[i] - i] += 1 + + return total_pairs - good_pairs +``` + +```java +public class Solution { + public long countBadPairs(int[] nums) { + Map count = new HashMap<>(); + long total = 0, good = 0; + for (int i = 0; i < nums.length; i++) { + int key = nums[i] - i; + good += count.getOrDefault(key, 0); + count.put(key, count.getOrDefault(key, 0) + 1); + total += i; + } + return total - good; + } +} +``` + +```cpp +class Solution { +public: + long long countBadPairs(vector& nums) { + unordered_map count; + long long total = 0, good = 0; + for (int i = 0; i < nums.size(); i++) { + int key = nums[i] - i; + good += count[key]; + count[key]++; + total += i; + } + return total - good; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + countBadPairs(nums) { + let count = new Map(); + let total = 0, + good = 0; + for (let i = 0; i < nums.length; i++) { + let key = nums[i] - i; + good += count.get(key) || 0; + count.set(key, (count.get(key) || 0) + 1); + total += i; + } + return total - good; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/count-number-of-islands.md b/articles/count-number-of-islands.md index cee406700..8b5a4322f 100644 --- a/articles/count-number-of-islands.md +++ b/articles/count-number-of-islands.md @@ -10,11 +10,11 @@ class Solution: islands = 0 def dfs(r, c): - if (r < 0 or c < 0 or r >= ROWS or + if (r < 0 or c < 0 or r >= ROWS or c >= COLS or grid[r][c] == "0" ): return - + grid[r][c] = "0" for dr, dc in directions: dfs(r + dr, c + dc) @@ -30,13 +30,13 @@ class Solution: ```java public class Solution { - private static final int[][] directions = {{1, 0}, {-1, 0}, + private static final int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; - + public int numIslands(char[][] grid) { int ROWS = grid.length, COLS = grid[0].length; int islands = 0; - + for (int r = 0; r < ROWS; r++) { for (int c = 0; c < COLS; c++) { if (grid[r][c] == '1') { @@ -45,16 +45,16 @@ public class Solution { } } } - + return islands; } - + private void dfs(char[][] grid, int r, int c) { - if (r < 0 || c < 0 || r >= grid.length || + if (r < 0 || c < 0 || r >= grid.length || c >= grid[0].length || grid[r][c] == '0') { return; } - + grid[r][c] = '0'; for (int[] dir : directions) { dfs(grid, r + dir[0], c + dir[1]); @@ -79,16 +79,16 @@ public: } } } - + return islands; } - + void dfs(vector>& grid, int r, int c) { - if (r < 0 || c < 0 || r >= grid.size() || + if (r < 0 || c < 0 || r >= grid.size() || c >= grid[0].size() || grid[r][c] == '0') { return; } - + grid[r][c] = '0'; for (int i = 0; i < 4; i++) { dfs(grid, r + directions[i][0], c + directions[i][1]); @@ -104,14 +104,20 @@ class Solution { * @return {number} */ numIslands(grid) { - const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; - const ROWS = grid.length, COLS = grid[0].length; + const directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; + const ROWS = grid.length, + COLS = grid[0].length; let islands = 0; const dfs = (r, c) => { - if (r < 0 || c < 0 || r >= ROWS || - c >= COLS || grid[r][c] === '0') return; - + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] === '0') + return; + grid[r][c] = '0'; for (const [dr, dc] of directions) { dfs(r + dr, c + dc); @@ -135,10 +141,10 @@ class Solution { ```csharp public class Solution { private static readonly int[][] directions = new int[][] { - new int[] {1, 0}, new int[] {-1, 0}, + new int[] {1, 0}, new int[] {-1, 0}, new int[] {0, 1}, new int[] {0, -1} }; - + public int NumIslands(char[][] grid) { int ROWS = grid.Length, COLS = grid[0].Length; int islands = 0; @@ -156,7 +162,7 @@ public class Solution { } private void Dfs(char[][] grid, int r, int c) { - if (r < 0 || c < 0 || r >= grid.Length || + if (r < 0 || c < 0 || r >= grid.Length || c >= grid[0].Length || grid[r][c] == '0') { return; } @@ -177,7 +183,7 @@ func numIslands(grid [][]byte) int { var dfs func(r, c int) dfs = func(r, c int) { - if r < 0 || c < 0 || r >= rows || + if r < 0 || c < 0 || r >= rows || c >= cols || grid[r][c] == '0' { return } @@ -203,16 +209,16 @@ func numIslands(grid [][]byte) int { ```kotlin class Solution { fun numIslands(grid: Array): Int { - val directions = arrayOf(intArrayOf(1, 0), - intArrayOf(-1, 0), - intArrayOf(0, 1), + val directions = arrayOf(intArrayOf(1, 0), + intArrayOf(-1, 0), + intArrayOf(0, 1), intArrayOf(0, -1)) val rows = grid.size val cols = grid[0].size var islands = 0 fun dfs(r: Int, c: Int) { - if (r < 0 || c < 0 || r >= rows || + if (r < 0 || c < 0 || r >= rows || c >= cols || grid[r][c] == '0') { return } @@ -236,12 +242,46 @@ class Solution { } ``` +```swift +class Solution { + func numIslands(_ grid: [[Character]]) -> Int { + let directions = [[1, 0], [-1, 0], [0, 1], [0, -1]] + let ROWS = grid.count + let COLS = grid[0].count + var islands = 0 + var grid = grid + + func dfs(_ r: Int, _ c: Int) { + if r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == "0" { + return + } + + grid[r][c] = "0" + for dir in directions { + dfs(r + dir[0], c + dir[1]) + } + } + + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. @@ -264,7 +304,7 @@ class Solution: q.append((r, c)) while q: - row, col = q.popleft() + row, col = q.popleft() for dr, dc in directions: nr, nc = dr + row, dc + col if (nr < 0 or nc < 0 or nr >= ROWS or @@ -285,13 +325,13 @@ class Solution: ```java public class Solution { - private static final int[][] directions = {{1, 0}, {-1, 0}, + private static final int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; - + public int numIslands(char[][] grid) { int ROWS = grid.length, COLS = grid[0].length; int islands = 0; - + for (int r = 0; r < ROWS; r++) { for (int c = 0; c < COLS; c++) { if (grid[r][c] == '1') { @@ -300,22 +340,22 @@ public class Solution { } } } - + return islands; } - + private void bfs(char[][] grid, int r, int c) { Queue q = new LinkedList<>(); grid[r][c] = '0'; q.add(new int[]{r, c}); - + while (!q.isEmpty()) { int[] node = q.poll(); int row = node[0], col = node[1]; - + for (int[] dir : directions) { int nr = row + dir[0], nc = col + dir[1]; - if (nr >= 0 && nc >= 0 && nr < grid.length && + if (nr >= 0 && nc >= 0 && nr < grid.length && nc < grid[0].length && grid[nr][nc] == '1') { q.add(new int[]{nr, nc}); grid[nr][nc] = '0'; @@ -328,7 +368,7 @@ public class Solution { ```cpp class Solution { - int directions[4][2] = {{1, 0}, {-1, 0}, + int directions[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; public: int numIslands(vector>& grid) { @@ -358,7 +398,7 @@ public: for (int i = 0; i < 4; i++) { int nr = row + directions[i][0]; int nc = col + directions[i][1]; - if (nr >= 0 && nc >= 0 && nr < grid.size() && + if (nr >= 0 && nc >= 0 && nr < grid.size() && nc < grid[0].size() && grid[nr][nc] == '1') { q.push({nr, nc}); grid[nr][nc] = '0'; @@ -376,21 +416,33 @@ class Solution { * @return {number} */ numIslands(grid) { - const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; - const ROWS = grid.length, COLS = grid[0].length; + const directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; + const ROWS = grid.length, + COLS = grid[0].length; let islands = 0; const bfs = (r, c) => { const q = new Queue(); q.push([r, c]); grid[r][c] = '0'; - + while (!q.isEmpty()) { const [row, col] = q.pop(); for (const [dr, dc] of directions) { - const nr = row + dr, nc = col + dc; - if (nr >= 0 && nc >= 0 && nr < ROWS && - nc < COLS && grid[nr][nc] === '1') { + const nr = row + dr, + nc = col + dc; + if ( + nr >= 0 && + nc >= 0 && + nr < ROWS && + nc < COLS && + grid[nr][nc] === '1' + ) { q.push([nr, nc]); grid[nr][nc] = '0'; } @@ -415,7 +467,7 @@ class Solution { ```csharp public class Solution { private static readonly int[][] directions = new int[][] { - new int[] {1, 0}, new int[] {-1, 0}, + new int[] {1, 0}, new int[] {-1, 0}, new int[] {0, 1}, new int[] {0, -1} }; @@ -446,7 +498,7 @@ public class Solution { foreach (var dir in directions) { int nr = row + dir[0], nc = col + dir[1]; - if (nr >= 0 && nc >= 0 && nr < grid.Length && + if (nr >= 0 && nc >= 0 && nr < grid.Length && nc < grid[0].Length && grid[nr][nc] == '1') { q.Enqueue(new int[] { nr, nc }); grid[nr][nc] = '0'; @@ -474,7 +526,7 @@ func numIslands(grid [][]byte) int { row, col := front[0], front[1] for _, dir := range directions { nr, nc := row+dir[0], col+dir[1] - if nr < 0 || nc < 0 || nr >= rows || + if nr < 0 || nc < 0 || nr >= rows || nc >= cols || grid[nr][nc] == '0' { continue } @@ -500,9 +552,9 @@ func numIslands(grid [][]byte) int { ```kotlin class Solution { fun numIslands(grid: Array): Int { - val directions = arrayOf(intArrayOf(1, 0), - intArrayOf(-1, 0), - intArrayOf(0, 1), + val directions = arrayOf(intArrayOf(1, 0), + intArrayOf(-1, 0), + intArrayOf(0, 1), intArrayOf(0, -1)) val rows = grid.size val cols = grid[0].size @@ -518,7 +570,7 @@ class Solution { for (dir in directions) { val nr = row + dir[0] val nc = col + dir[1] - if (nr < 0 || nc < 0 || nr >= rows || + if (nr < 0 || nc < 0 || nr >= rows || nc >= cols || grid[nr][nc] == '0') { continue } @@ -542,12 +594,54 @@ class Solution { } ``` +```swift +class Solution { + func numIslands(_ grid: [[Character]]) -> Int { + let directions = [[1, 0], [-1, 0], [0, 1], [0, -1]] + let ROWS = grid.count + let COLS = grid[0].count + var islands = 0 + var grid = grid + + func bfs(_ r: Int, _ c: Int) { + var queue = Deque<(Int, Int)>() + grid[r][c] = "0" + queue.append((r, c)) + + while !queue.isEmpty { + let (row, col) = queue.popFirst()! + for dir in directions { + let nr = row + dir[0] + let nc = col + dir[1] + if nr < 0 || nc < 0 || nr >= ROWS || nc >= COLS || grid[nr][nc] == "0" { + continue + } + queue.append((nr, nc)) + grid[nr][nc] = "0" + } + } + } + + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. @@ -602,7 +696,7 @@ class Solution: nc >= COLS or grid[nr][nc] == "0" ): continue - + if dsu.union(index(r, c), index(nr, nc)): islands -= 1 @@ -610,7 +704,7 @@ class Solution: ``` ```java -public class DSU { +class DSU { private int[] Parent, Size; public DSU(int n) { @@ -660,7 +754,7 @@ public class Solution { for (int[] d : directions) { int nr = r + d[0]; int nc = c + d[1]; - if (nr >= 0 && nc >= 0 && nr < ROWS && + if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS && grid[nr][nc] == '1') { if (dsu.union(r * COLS + c, nr * COLS + nc)) { islands--; @@ -732,7 +826,7 @@ public: for (auto& d : directions) { int nr = r + d[0]; int nc = c + d[1]; - if (nr >= 0 && nc >= 0 && nr < ROWS && + if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS && grid[nr][nc] == '1') { if (dsu.unionBySize(index(r, c), index(nr, nc))) { islands--; @@ -751,7 +845,9 @@ public: ```javascript class DSU { constructor(n) { - this.Parent = Array(n + 1).fill(0).map((_, i) => i); + this.Parent = Array(n + 1) + .fill(0) + .map((_, i) => i); this.Size = Array(n + 1).fill(1); } @@ -797,7 +893,10 @@ class Solution { const dsu = new DSU(ROWS * COLS); const directions = [ - [1, 0], [-1, 0], [0, 1], [0, -1] + [1, 0], + [-1, 0], + [0, 1], + [0, -1], ]; let islands = 0; @@ -809,9 +908,15 @@ class Solution { if (grid[r][c] === '1') { islands++; for (let [dr, dc] of directions) { - let nr = r + dr, nc = c + dc; - if (nr >= 0 && nc >= 0 && nr < ROWS && - nc < COLS && grid[nr][nc] === '1') { + let nr = r + dr, + nc = c + dc; + if ( + nr >= 0 && + nc >= 0 && + nr < ROWS && + nc < COLS && + grid[nr][nc] === '1' + ) { if (dsu.union(index(r, c), index(nr, nc))) { islands--; } @@ -868,7 +973,7 @@ public class Solution { DSU dsu = new DSU(ROWS * COLS); int[][] directions = new int[][] { - new int[] { 1, 0 }, new int[] { -1, 0 }, + new int[] { 1, 0 }, new int[] { -1, 0 }, new int[] { 0, 1 }, new int[] { 0, -1 } }; int islands = 0; @@ -880,7 +985,7 @@ public class Solution { foreach (var d in directions) { int nr = r + d[0]; int nc = c + d[1]; - if (nr >= 0 && nc >= 0 && nr < ROWS && + if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS && grid[nr][nc] == '1') { if (dsu.Union(r * COLS + c, nr * COLS + nc)) { islands--; @@ -953,7 +1058,7 @@ func numIslands(grid [][]byte) int { islands++ for _, dir := range directions { nr, nc := r+dir[0], c+dir[1] - if nr < 0 || nc < 0 || nr >= rows || + if nr < 0 || nc < 0 || nr >= rows || nc >= cols || grid[nr][nc] == '0' { continue } @@ -1001,9 +1106,9 @@ class Solution { val rows = grid.size val cols = grid[0].size val dsu = DSU(rows * cols) - val directions = arrayOf(intArrayOf(1, 0), - intArrayOf(-1, 0), - intArrayOf(0, 1), + val directions = arrayOf(intArrayOf(1, 0), + intArrayOf(-1, 0), + intArrayOf(0, 1), intArrayOf(0, -1)) var islands = 0 @@ -1018,7 +1123,7 @@ class Solution { for (dir in directions) { val nr = r + dir[0] val nc = c + dir[1] - if (nr < 0 || nc < 0 || nr >= rows || + if (nr < 0 || nc < 0 || nr >= rows || nc >= cols || grid[nr][nc] == '0') { continue } @@ -1035,11 +1140,82 @@ class Solution { } ``` +```swift +class DSU { + private var parent: [Int] + private var size: [Int] + + init(_ n: Int) { + parent = Array(0...n) + size = Array(repeating: 1, count: n + 1) + } + + func find(_ node: Int) -> Int { + if parent[node] != node { + parent[node] = find(parent[node]) + } + return parent[node] + } + + func union(_ u: Int, _ v: Int) -> Bool { + let pu = find(u) + let pv = find(v) + if pu == pv { + return false + } + if size[pu] >= size[pv] { + size[pu] += size[pv] + parent[pv] = pu + } else { + size[pv] += size[pu] + parent[pu] = pv + } + return true + } +} + +class Solution { + func numIslands(_ grid: [[Character]]) -> Int { + let ROWS = grid.count + let COLS = grid[0].count + let dsu = DSU(ROWS * COLS) + + func index(_ r: Int, _ c: Int) -> Int { + return r * COLS + c + } + + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + var islands = 0 + var grid = grid + + for r in 0..= ROWS || nc >= COLS || grid[nr][nc] == "0" { + continue + } + if dsu.union(index(r, c), index(nr, nc)) { + islands -= 1 + } + } + } + } + } + + return islands + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ -> Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. diff --git a/articles/count-odd-numbers-in-an-interval-range.md b/articles/count-odd-numbers-in-an-interval-range.md new file mode 100644 index 000000000..18c11c75b --- /dev/null +++ b/articles/count-odd-numbers-in-an-interval-range.md @@ -0,0 +1,222 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def countOdds(self, low: int, high: int) -> int: + odd = 0 + for num in range(low, high + 1): + if num & 1: + odd += 1 + return odd +``` + +```java +public class Solution { + public int countOdds(int low, int high) { + int odd = 0; + for (int num = low; num <= high; num++) { + if ((num & 1) == 1) { + odd++; + } + } + return odd; + } +} +``` + +```cpp +class Solution { +public: + int countOdds(int low, int high) { + int odd = 0; + for (int num = low; num <= high; num++) { + if (num & 1) { + odd++; + } + } + return odd; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} low + * @param {number} high + * @return {number} + */ + countOdds(low, high) { + let odd = 0; + for (let num = low; num <= high; num++) { + if (num & 1) { + odd++; + } + } + return odd; + } +} +``` + +```csharp +public class Solution { + public int CountOdds(int low, int high) { + int odd = 0; + for (int num = low; num <= high; num++) { + if ((num & 1) == 1) { + odd++; + } + } + return odd; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +> Where $n$ is the number of integers in the given range. + +--- + +## 2. Math + +::tabs-start + +```python +class Solution: + def countOdds(self, low: int, high: int) -> int: + length = high - low + 1 + count = length // 2 + if length % 2 and low % 2: + count += 1 + return count +``` + +```java +public class Solution { + public int countOdds(int low, int high) { + int length = high - low + 1; + int count = length / 2; + if (length % 2 == 1 && low % 2 == 1) { + count++; + } + return count; + } +} +``` + +```cpp +class Solution { +public: + int countOdds(int low, int high) { + int length = high - low + 1; + int count = length / 2; + if (length % 2 == 1 && low % 2 == 1) { + count++; + } + return count; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} low + * @param {number} high + * @return {number} + */ + countOdds(low, high) { + let length = high - low + 1; + let count = Math.floor(length / 2); + if (length % 2 === 1 && low % 2 === 1) { + count++; + } + return count; + } +} +``` + +```csharp +public class Solution { + public int CountOdds(int low, int high) { + int length = high - low + 1; + int count = length / 2; + if ((length % 2 == 1) && (low % 2 == 1)) { + count++; + } + return count; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +--- + +## 3. Math (One Liner) + +::tabs-start + +```python +class Solution: + def countOdds(self, low: int, high: int) -> int: + return ((high + 1) >> 1) - (low >> 1) +``` + +```java +public class Solution { + public int countOdds(int low, int high) { + return ((high + 1) >> 1) - (low >> 1); + } +} +``` + +```cpp +class Solution { +public: + int countOdds(int low, int high) { + return ((high + 1) >> 1) - (low >> 1); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} low + * @param {number} high + * @return {number} + */ + countOdds(low, high) { + return ((high + 1) >> 1) - (low >> 1); + } +} +``` + +```csharp +public class Solution { + public int CountOdds(int low, int high) { + return ((high + 1) >> 1) - (low >> 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ diff --git a/articles/count-of-matches-in-tournament.md b/articles/count-of-matches-in-tournament.md new file mode 100644 index 000000000..07623949f --- /dev/null +++ b/articles/count-of-matches-in-tournament.md @@ -0,0 +1,120 @@ +## 1. Simulation + +::tabs-start + +```python +class Solution: + def numberOfMatches(self, n: int) -> int: + res = 0 + + while n > 1: + res += n // 2 + n = (n + 1) // 2 + + return res +``` + +```java +public class Solution { + public int numberOfMatches(int n) { + int res = 0; + + while (n > 1) { + res += n / 2; + n = (n + 1) / 2; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int numberOfMatches(int n) { + int res = 0; + + while (n > 1) { + res += n / 2; + n = (n + 1) / 2; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + numberOfMatches(n) { + let res = 0; + + while (n > 1) { + res += Math.floor(n / 2); + n = Math.ceil(n / 2); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ + +--- + +## 2. Math + +::tabs-start + +```python +class Solution: + def numberOfMatches(self, n: int) -> int: + return n - 1 +``` + +```java +public class Solution { + public int numberOfMatches(int n) { + return n - 1; + } +} +``` + +```cpp +class Solution { +public: + int numberOfMatches(int n) { + return n - 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + numberOfMatches(n) { + return n - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ diff --git a/articles/count-paths.md b/articles/count-paths.md index 61ab8e148..fd59ec46a 100644 --- a/articles/count-paths.md +++ b/articles/count-paths.md @@ -5,14 +5,14 @@ ```python class Solution: def uniquePaths(self, m: int, n: int) -> int: - + def dfs(i, j): if i == (m - 1) and j == (n - 1): return 1 if i >= m or j >= n: return 0 return dfs(i, j + 1) + dfs(i + 1, j) - + return dfs(0, 0) ``` @@ -27,7 +27,7 @@ public class Solution { return 1; } if (i >= m || j >= n) return 0; - return dfs(i, j + 1, m, n) + + return dfs(i, j + 1, m, n) + dfs(i + 1, j, m, n); } } @@ -45,7 +45,7 @@ public: return 1; } if (i >= m || j >= n) return 0; - return dfs(i, j + 1, m, n) + + return dfs(i, j + 1, m, n) + dfs(i + 1, j, m, n); } }; @@ -59,14 +59,13 @@ class Solution { * @return {number} */ uniquePaths(m, n) { - const dfs = (i, j) => { - if (i == (m - 1) && j == (n - 1)) { + if (i == m - 1 && j == n - 1) { return 1; } if (i >= m || j >= n) return 0; return dfs(i, j + 1) + dfs(i + 1, j); - } + }; return dfs(0, 0); } @@ -84,7 +83,7 @@ public class Solution { return 1; } if (i >= m || j >= n) return 0; - return Dfs(i, j + 1, m, n) + + return Dfs(i, j + 1, m, n) + Dfs(i + 1, j, m, n); } } @@ -102,7 +101,7 @@ func uniquePaths(m int, n int) int { } return dfs(i, j+1) + dfs(i+1, j) } - + return dfs(0, 0) } ``` @@ -115,7 +114,25 @@ class Solution { if (i >= m || j >= n) return 0 return dfs(i, j + 1) + dfs(i + 1, j) } - + + return dfs(0, 0) + } +} +``` + +```swift +class Solution { + func uniquePaths(_ m: Int, _ n: Int) -> Int { + func dfs(_ i: Int, _ j: Int) -> Int { + if i == m - 1 && j == n - 1 { + return 1 + } + if i >= m || j >= n { + return 0 + } + return dfs(i, j + 1) + dfs(i + 1, j) + } + return dfs(0, 0) } } @@ -125,8 +142,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ {m + n})$ -* Space complexity: $O(m + n)$ +- Time complexity: $O(2 ^ {m + n})$ +- Space complexity: $O(m + n)$ > Where $m$ is the number of rows and $n$ is the number of columns. @@ -147,10 +164,10 @@ class Solution: return 0 if memo[i][j] != -1: return memo[i][j] - + memo[i][j] = dfs(i, j + 1) + dfs(i + 1, j) return memo[i][j] - + return dfs(0, 0) ``` @@ -173,7 +190,7 @@ public class Solution { if (memo[i][j] != -1) { return memo[i][j]; } - return memo[i][j] = dfs(i, j + 1, m, n) + + return memo[i][j] = dfs(i, j + 1, m, n) + dfs(i + 1, j, m, n); } } @@ -196,7 +213,7 @@ public: if (memo[i][j] != -1) { return memo[i][j]; } - return memo[i][j] = dfs(i, j + 1, m, n) + + return memo[i][j] = dfs(i, j + 1, m, n) + dfs(i + 1, j, m, n); } }; @@ -210,10 +227,9 @@ class Solution { * @return {number} */ uniquePaths(m, n) { - const memo = Array.from({ length: m }, () => - Array(n).fill(-1)); + const memo = Array.from({ length: m }, () => Array(n).fill(-1)); const dfs = (i, j) => { - if (i == (m - 1) && j == (n - 1)) { + if (i == m - 1 && j == n - 1) { return 1; } if (i >= m || j >= n) return 0; @@ -222,7 +238,7 @@ class Solution { } memo[i][j] = dfs(i, j + 1) + dfs(i + 1, j); return memo[i][j]; - } + }; return dfs(0, 0); } @@ -249,7 +265,7 @@ public class Solution { if (memo[i, j] != -1) { return memo[i, j]; } - return memo[i, j] = Dfs(i, j + 1, m, n) + + return memo[i, j] = Dfs(i, j + 1, m, n) + Dfs(i + 1, j, m, n); } } @@ -276,11 +292,11 @@ func uniquePaths(m int, n int) int { if memo[i][j] != -1 { return memo[i][j] } - + memo[i][j] = dfs(i, j+1) + dfs(i+1, j) return memo[i][j] } - + return dfs(0, 0) } ``` @@ -304,12 +320,37 @@ class Solution { } ``` +```swift +class Solution { + func uniquePaths(_ m: Int, _ n: Int) -> Int { + var memo = Array(repeating: Array(repeating: -1, count: n), count: m) + + func dfs(_ i: Int, _ j: Int) -> Int { + if i == m - 1 && j == n - 1 { + return 1 + } + if i >= m || j >= n { + return 0 + } + if memo[i][j] != -1 { + return memo[i][j] + } + + memo[i][j] = dfs(i, j + 1) + dfs(i + 1, j) + return memo[i][j] + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns. @@ -375,8 +416,7 @@ class Solution { * @return {number} */ uniquePaths(m, n) { - let dp = Array.from({ length: m + 1 }, () => - Array(n + 1).fill(0)); + let dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); dp[m - 1][n - 1] = 1; for (let i = m - 1; i >= 0; i--) { @@ -442,12 +482,29 @@ class Solution { } ``` +```swift +class Solution { + func uniquePaths(_ m: Int, _ n: Int) -> Int { + var dp = Array(repeating: Array(repeating: 0, count: n + 1), count: m + 1) + dp[m - 1][n - 1] = 1 + + for i in stride(from: m - 1, through: 0, by: -1) { + for j in stride(from: n - 1, through: 0, by: -1) { + dp[i][j] += dp[i + 1][j] + dp[i][j + 1] + } + } + + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns. @@ -537,7 +594,7 @@ public class Solution { for (int i = 0; i < m - 1; i++) { var newRow = new int[n]; Array.Fill(newRow, 1); - for (int j = n - 2; j >=0; j--) { + for (int j = n - 2; j >=0; j--) { newRow[j] = newRow[j + 1] + row[j]; } row = newRow; @@ -585,12 +642,29 @@ class Solution { } ``` +```swift +class Solution { + func uniquePaths(_ m: Int, _ n: Int) -> Int { + var row = Array(repeating: 1, count: n) + + for _ in 0..<(m - 1) { + var newRow = Array(repeating: 1, count: n) + for j in stride(from: n - 2, through: 0, by: -1) { + newRow[j] = newRow[j + 1] + row[j] + } + row = newRow + } + return row[0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(n)$ > Where $m$ is the number of rows and $n$ is the number of columns. @@ -607,7 +681,7 @@ class Solution: for i in range(m - 2, -1, -1): for j in range(n - 2, -1, -1): dp[j] += dp[j + 1] - + return dp[0] ``` @@ -616,13 +690,13 @@ public class Solution { public int uniquePaths(int m, int n) { int[] dp = new int[n]; Arrays.fill(dp, 1); - + for (int i = m - 2; i >= 0; i--) { for (int j = n - 2; j >= 0; j--) { dp[j] += dp[j + 1]; } } - + return dp[0]; } } @@ -633,13 +707,13 @@ class Solution { public: int uniquePaths(int m, int n) { vector dp(n, 1); - + for (int i = m - 2; i >= 0; i--) { for (int j = n - 2; j >= 0; j--) { dp[j] += dp[j + 1]; } } - + return dp[0]; } }; @@ -654,13 +728,13 @@ class Solution { */ uniquePaths(m, n) { let dp = new Array(n).fill(1); - + for (let i = m - 2; i >= 0; i--) { for (let j = n - 2; j >= 0; j--) { dp[j] += dp[j + 1]; } } - + return dp[0]; } } @@ -671,13 +745,13 @@ public class Solution { public int UniquePaths(int m, int n) { int[] dp = new int[n]; Array.Fill(dp, 1); - + for (int i = m - 2; i >= 0; i--) { for (int j = n - 2; j >= 0; j--) { dp[j] += dp[j + 1]; } } - + return dp[0]; } } @@ -716,12 +790,28 @@ class Solution { } ``` +```swift +class Solution { + func uniquePaths(_ m: Int, _ n: Int) -> Int { + var dp = Array(repeating: 1, count: n) + + for _ in stride(from: m - 2, through: 0, by: -1) { + for j in stride(from: n - 2, through: 0, by: -1) { + dp[j] += dp[j + 1] + } + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(n)$ > Where $m$ is the number of rows and $n$ is the number of columns. @@ -812,7 +902,8 @@ class Solution { [m, n] = [n, m]; } - let res = 1, j = 1; + let res = 1, + j = 1; for (let i = m; i < m + n - 1; i++) { res *= i; res = Math.floor(res / j); @@ -890,17 +981,41 @@ class Solution { res /= j j++ } - + return res.toInt() } } ``` +```swift +class Solution { + func uniquePaths(_ m: Int, _ n: Int) -> Int { + if m == 1 || n == 1 { + return 1 + } + var m = m, n = n + if m < n { + swap(&m, &n) + } + + var res = 1 + var j = 1 + for i in m..<(m + n - 1) { + res *= i + res /= j + j += 1 + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(min(m, n))$ -* Space complexity: $O(1)$ +- Time complexity: $O(min(m, n))$ +- Space complexity: $O(1)$ -> Where $m$ is the number of rows and $n$ is the number of columns. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns. diff --git a/articles/count-squares.md b/articles/count-squares.md index 6b27ebb50..b1d133d73 100644 --- a/articles/count-squares.md +++ b/articles/count-squares.md @@ -46,7 +46,7 @@ public class CountSquares { if (Math.abs(py - y) != Math.abs(px - x) || x == px || y == py) { continue; } - res += ptsCount.getOrDefault(Arrays.asList(x, py), 0) * + res += ptsCount.getOrDefault(Arrays.asList(x, py), 0) * ptsCount.getOrDefault(Arrays.asList(px, y), 0); } return res; @@ -70,10 +70,10 @@ public: void add(vector point) { long key = getKey(point[0], point[1]); - ptsCount[key]++; - pts.push_back(point); + ptsCount[key]++; + pts.push_back(point); } - + int count(vector point) { int res = 0; int px = point[0], py = point[1]; @@ -139,7 +139,7 @@ public class CountSquares { var tuplePoint = (point[0], point[1]); if (!ptsCount.ContainsKey(tuplePoint)) ptsCount[tuplePoint] = 0; - + ptsCount[tuplePoint]++; pts.Add(point); } @@ -148,7 +148,7 @@ public class CountSquares { int res = 0; int px = point[0]; int py = point[1]; - + foreach (var pt in pts) { int x = pt[0]; int y = pt[1]; @@ -156,7 +156,7 @@ public class CountSquares { if (Math.Abs(py - y) != Math.Abs(px - x) || x == px || y == py) continue; - res += (ptsCount.GetValueOrDefault((x, py)) * + res += (ptsCount.GetValueOrDefault((x, py)) * ptsCount.GetValueOrDefault((px, y))); } return res; @@ -195,13 +195,13 @@ func (this *CountSquares) Count(point []int) int { if abs(py-pt.y) != abs(px-pt.x) || pt.x == px || pt.y == py { continue } - + p1 := Point{pt.x, py} p2 := Point{px, pt.y} - + res += this.ptsCount[p1] * this.ptsCount[p2] } - + return res } @@ -229,7 +229,7 @@ class CountSquares() { val (px, py) = point for ((x, y) in points) { - if (kotlin.math.abs(py - y) != kotlin.math.abs(px - x) || + if (kotlin.math.abs(py - y) != kotlin.math.abs(px - x) || x == px || y == py) { continue } @@ -240,12 +240,46 @@ class CountSquares() { } ``` +```swift +class CountSquares { + private var ptsCount: [String: Int] + private var pts: [[Int]] + + init() { + self.ptsCount = [:] + self.pts = [] + } + + func add(_ point: [Int]) { + let key = "\(point[0]),\(point[1])" + ptsCount[key, default: 0] += 1 + pts.append(point) + } + + func count(_ point: [Int]) -> Int { + var res = 0 + let px = point[0], py = point[1] + + for pt in pts { + let x = pt[0], y = pt[1] + if abs(py - y) != abs(px - x) || x == px || y == py { + continue + } + let key1 = "\(x),\(py)" + let key2 = "\(px),\(y)" + res += (ptsCount[key1] ?? 0) * (ptsCount[key2] ?? 0) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ for $add()$, $O(n)$ for $count()$. -* Space complexity: $O(n)$ +- Time complexity: $O(1)$ for $add()$, $O(n)$ for $count()$. +- Space complexity: $O(n)$ --- @@ -320,11 +354,10 @@ public class CountSquares { ```cpp class CountSquares { unordered_map> ptsCount; + public: - CountSquares() { - - } - + CountSquares() {} + void add(vector point) { ptsCount[point[0]][point[1]]++; } @@ -381,13 +414,15 @@ class CountSquares { const x3 = x1 + side; const x4 = x1 - side; - res += cnt * - (this.ptsCount.get(x3)?.get(y1) || 0) * - (this.ptsCount.get(x3)?.get(y2) || 0); + res += + cnt * + (this.ptsCount.get(x3)?.get(y1) || 0) * + (this.ptsCount.get(x3)?.get(y2) || 0); - res += cnt * - (this.ptsCount.get(x4)?.get(y1) || 0) * - (this.ptsCount.get(x4)?.get(y2) || 0); + res += + cnt * + (this.ptsCount.get(x4)?.get(y1) || 0) * + (this.ptsCount.get(x4)?.get(y2) || 0); } return res; @@ -426,15 +461,15 @@ public class CountSquares { int x3 = x1 + side, x4 = x1 - side; res += cnt * - (ptsCount.ContainsKey(x3) && + (ptsCount.ContainsKey(x3) && ptsCount[x3].ContainsKey(y1) ? ptsCount[x3][y1] : 0) * - (ptsCount.ContainsKey(x3) && + (ptsCount.ContainsKey(x3) && ptsCount[x3].ContainsKey(y2) ? ptsCount[x3][y2] : 0); res += cnt * - (ptsCount.ContainsKey(x4) && + (ptsCount.ContainsKey(x4) && ptsCount[x4].ContainsKey(y1) ? ptsCount[x4][y1] : 0) * - (ptsCount.ContainsKey(x4) && + (ptsCount.ContainsKey(x4) && ptsCount[x4].ContainsKey(y2) ? ptsCount[x4][y2] : 0); } @@ -489,15 +524,15 @@ func (this *CountSquares) Count(point []int) int { ```kotlin class CountSquares { private val points = HashMap>() - + fun add(point: IntArray) { val x = point[0] val y = point[1] - + if (!points.containsKey(x)) { points[x] = hashMapOf() } - + points[x]?.put(y, (points[x]?.get(y) ?: 0) + 1) } @@ -505,19 +540,19 @@ class CountSquares { var result = 0 val x1 = point[0] val y1 = point[1] - + points[x1]?.forEach { (y2, count1) -> if (y2 == y1) return@forEach - + val side = Math.abs(y2 - y1) - + val x3 = x1 + side if (points.containsKey(x3)) { val count2 = points[x3]?.get(y1) ?: 0 val count3 = points[x3]?.get(y2) ?: 0 result += count1 * count2 * count3 } - + val x4 = x1 - side if (points.containsKey(x4)) { val count2 = points[x4]?.get(y1) ?: 0 @@ -525,15 +560,49 @@ class CountSquares { result += count1 * count2 * count3 } } - + return result } } ``` +```swift +class CountSquares { + var ptsCount: [Int: [Int: Int]] + + init() { + ptsCount = [:] + } + + func add(_ point: [Int]) { + let x = point[0] + let y = point[1] + ptsCount[x, default: [:]][y, default: 0] += 1 + } + + func count(_ point: [Int]) -> Int { + var res = 0 + let x1 = point[0] + let y1 = point[1] + + if let yMap = ptsCount[x1] { + for (y2, countXY2) in yMap { + let side = y2 - y1 + if side == 0 { continue } + let x3 = x1 + side + let x4 = x1 - side + res += countXY2 * (ptsCount[x3]?[y1] ?? 0) * (ptsCount[x3]?[y2] ?? 0) + res += countXY2 * (ptsCount[x4]?[y1] ?? 0) * (ptsCount[x4]?[y2] ?? 0) + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ for $add()$, $O(n)$ for $count()$. -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(1)$ for $add()$, $O(n)$ for $count()$. +- Space complexity: $O(n)$ diff --git a/articles/count-sub-islands.md b/articles/count-sub-islands.md index 22a7598f7..7f7357ff6 100644 --- a/articles/count-sub-islands.md +++ b/articles/count-sub-islands.md @@ -9,19 +9,19 @@ class Solution: visit = set() def dfs(r, c): - if (min(r, c) < 0 or r == ROWS or c == COLS or + if (min(r, c) < 0 or r == ROWS or c == COLS or grid2[r][c] == 0 or (r, c) in visit): return True - + visit.add((r, c)) res = grid1[r][c] - + res &= dfs(r - 1, c) res &= dfs(r + 1, c) res &= dfs(r, c - 1) res &= dfs(r, c + 1) return res - + count = 0 for r in range(ROWS): for c in range(COLS): @@ -49,7 +49,7 @@ public class Solution { } private boolean dfs(int r, int c, int[][] grid1, int[][] grid2) { - if (r < 0 || c < 0 || r >= grid1.length || c >= grid1[0].length || + if (r < 0 || c < 0 || r >= grid1.length || c >= grid1[0].length || grid2[r][c] == 0 || visit[r][c]) { return true; } @@ -61,7 +61,7 @@ public class Solution { res &= dfs(r, c + 1, grid1, grid2); return res; } - + } ``` @@ -87,7 +87,7 @@ public: private: bool dfs(int r, int c, vector>& grid1, vector>& grid2) { - if (r < 0 || c < 0 || r >= grid1.size() || c >= grid1[0].size() || + if (r < 0 || c < 0 || r >= grid1.size() || c >= grid1[0].size() || grid2[r][c] == 0 || visit[r][c]) { return true; } @@ -111,11 +111,21 @@ class Solution { * @return {number} */ countSubIslands(grid1, grid2) { - const ROWS = grid1.length, COLS = grid1[0].length; - const visit = Array.from({ length: ROWS }, () => Array(COLS).fill(false)); + const ROWS = grid1.length, + COLS = grid1[0].length; + const visit = Array.from({ length: ROWS }, () => + Array(COLS).fill(false), + ); const dfs = (r, c) => { - if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid2[r][c] === 0 || visit[r][c]) + if ( + r < 0 || + c < 0 || + r >= ROWS || + c >= COLS || + grid2[r][c] === 0 || + visit[r][c] + ) return true; visit[r][c] = true; let res = grid1[r][c] === 1; @@ -143,8 +153,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns. @@ -291,8 +301,11 @@ class Solution { * @return {number} */ countSubIslands(grid1, grid2) { - const ROWS = grid1.length, COLS = grid1[0].length; - const visit = Array.from({ length: ROWS }, () => Array(COLS).fill(false)); + const ROWS = grid1.length, + COLS = grid1[0].length; + const visit = Array.from({ length: ROWS }, () => + Array(COLS).fill(false), + ); const directions = [1, 0, -1, 0, 1]; let count = 0; @@ -306,9 +319,16 @@ class Solution { if (grid1[r][c] === 0) res = false; for (let i = 0; i < 4; i++) { - const nr = r + directions[i], nc = c + directions[i + 1]; - if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && - grid2[nr][nc] === 1 && !visit[nr][nc]) { + const nr = r + directions[i], + nc = c + directions[i + 1]; + if ( + nr >= 0 && + nr < ROWS && + nc >= 0 && + nc < COLS && + grid2[nr][nc] === 1 && + !visit[nr][nc] + ) { visit[nr][nc] = true; queue.push([nr, nc]); } @@ -333,8 +353,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns. @@ -374,7 +394,7 @@ class Solution: def getId(r, c): return r * COLS + c - + land = unions = 0 for r in range(ROWS): for c in range(COLS): @@ -387,7 +407,7 @@ class Solution: unions += dsu.union(getId(r, c), getId(r, c + 1)) if not grid1[r][c]: unions += dsu.union(getId(r, c), N) - + return land - unions ``` @@ -497,7 +517,7 @@ class DSU { this.Parent = Array.from({ length: n + 1 }, (_, i) => i); this.Size = Array(n + 1).fill(1); } - + /** * @param {number} node * @return {number} @@ -515,7 +535,8 @@ class DSU { * @return {boolean} */ union(u, v) { - let pu = this.find(u), pv = this.find(v); + let pu = this.find(u), + pv = this.find(v); if (pu === pv) return false; if (this.Size[pu] < this.Size[pv]) [pu, pv] = [pv, pu]; this.Size[pu] += this.Size[pv]; @@ -531,12 +552,15 @@ class Solution { * @return {number} */ countSubIslands(grid1, grid2) { - const ROWS = grid1.length, COLS = grid1[0].length, N = ROWS * COLS; + const ROWS = grid1.length, + COLS = grid1[0].length, + N = ROWS * COLS; const dsu = new DSU(N); const getId = (r, c) => r * COLS + c; - let land = 0, unions = 0; + let land = 0, + unions = 0; for (let r = 0; r < ROWS; r++) { for (let c = 0; c < COLS; c++) { if (grid2[r][c] === 0) continue; @@ -545,8 +569,7 @@ class Solution { unions += dsu.union(getId(r, c), getId(r + 1, c)); if (c + 1 < COLS && grid2[r][c + 1] === 1) unions += dsu.union(getId(r, c), getId(r, c + 1)); - if (grid1[r][c] === 0) - unions += dsu.union(getId(r, c), N); + if (grid1[r][c] === 0) unions += dsu.union(getId(r, c), N); } } return land - unions; @@ -558,7 +581,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ -> Where $m$ is the number of rows and $n$ is the number of columns. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns. diff --git a/articles/count-subarrays-where-max-element-appears-at-least-k-times.md b/articles/count-subarrays-where-max-element-appears-at-least-k-times.md new file mode 100644 index 000000000..b57ff83d0 --- /dev/null +++ b/articles/count-subarrays-where-max-element-appears-at-least-k-times.md @@ -0,0 +1,597 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def countSubarrays(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + maxi = max(nums) + + for i in range(n): + cnt = 0 + for j in range(i, n): + if nums[j] == maxi: + cnt += 1 + + if cnt >= k: + res += 1 + + return res +``` + +```java +public class Solution { + public long countSubarrays(int[] nums, int k) { + int n = nums.length; + long res = 0; + int maxi = Integer.MIN_VALUE; + + for (int num : nums) { + maxi = Math.max(maxi, num); + } + + for (int i = 0; i < n; i++) { + int cnt = 0; + for (int j = i; j < n; j++) { + if (nums[j] == maxi) { + cnt++; + } + + if (cnt >= k) { + res++; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long countSubarrays(vector& nums, int k) { + int n = nums.size(); + long long res = 0; + int maxi = *max_element(nums.begin(), nums.end()); + + for (int i = 0; i < n; i++) { + int cnt = 0; + for (int j = i; j < n; j++) { + if (nums[j] == maxi) { + cnt++; + } + + if (cnt >= k) { + res++; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + countSubarrays(nums, k) { + let n = nums.length, + res = 0; + let maxi = Math.max(...nums); + + for (let i = 0; i < n; i++) { + let cnt = 0; + for (let j = i; j < n; j++) { + if (nums[j] === maxi) { + cnt++; + } + + if (cnt >= k) { + res++; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Variable Size Sliding Window + +::tabs-start + +```python +class Solution: + def countSubarrays(self, nums: List[int], k: int) -> int: + max_n, max_cnt = max(nums), 0 + l = 0 + res = 0 + + for r in range(len(nums)): + if nums[r] == max_n: + max_cnt += 1 + + while max_cnt > k or (l <= r and max_cnt == k and nums[l] != max_n): + if nums[l] == max_n: + max_cnt -= 1 + l += 1 + + if max_cnt == k: + res += l + 1 + + return res +``` + +```java +public class Solution { + public long countSubarrays(int[] nums, int k) { + int maxN = Integer.MIN_VALUE, maxCnt = 0, l = 0; + long res = 0; + for (int num : nums) { + maxN = Math.max(maxN, num); + } + + for (int r = 0; r < nums.length; r++) { + if (nums[r] == maxN) { + maxCnt++; + } + + while (maxCnt > k || (l <= r && maxCnt == k && nums[l] != maxN)) { + if (nums[l] == maxN) { + maxCnt--; + } + l++; + } + + if (maxCnt == k) { + res += l + 1; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long countSubarrays(vector& nums, int k) { + int maxN = *max_element(nums.begin(), nums.end()); + int maxCnt = 0, l = 0; + long long res = 0; + + for (int r = 0; r < nums.size(); r++) { + if (nums[r] == maxN) { + maxCnt++; + } + + while (maxCnt > k || (l <= r && maxCnt == k && nums[l] != maxN)) { + if (nums[l] == maxN) { + maxCnt--; + } + l++; + } + + if (maxCnt == k) { + res += l + 1; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + countSubarrays(nums, k) { + let maxN = Math.max(...nums); + let maxCnt = 0, + l = 0, + res = 0; + + for (let r = 0; r < nums.length; r++) { + if (nums[r] === maxN) { + maxCnt++; + } + + while (maxCnt > k || (l <= r && maxCnt === k && nums[l] !== maxN)) { + if (nums[l] === maxN) { + maxCnt--; + } + l++; + } + + if (maxCnt === k) { + res += l + 1; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 3. Variable Size Sliding Window (Optimal) + +::tabs-start + +```python +class Solution: + def countSubarrays(self, nums: List[int], k: int) -> int: + max_n, max_cnt = max(nums), 0 + l = res = 0 + + for r in range(len(nums)): + if nums[r] == max_n: + max_cnt += 1 + while max_cnt == k: + if nums[l] == max_n: + max_cnt -= 1 + l += 1 + res += l + + return res +``` + +```java +public class Solution { + public long countSubarrays(int[] nums, int k) { + int max_n = Integer.MIN_VALUE, max_cnt = 0, l = 0; + long res = 0; + for (int num : nums) { + max_n = Math.max(max_n, num); + } + + for (int r = 0; r < nums.length; r++) { + if (nums[r] == max_n) { + max_cnt++; + } + while (max_cnt == k) { + if (nums[l] == max_n) { + max_cnt--; + } + l++; + } + res += l; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long countSubarrays(vector& nums, int k) { + int max_n = *max_element(nums.begin(), nums.end()); + int max_cnt = 0, l = 0; + long long res = 0; + + for (int r = 0; r < nums.size(); r++) { + if (nums[r] == max_n) { + max_cnt++; + } + while (max_cnt == k) { + if (nums[l] == max_n) { + max_cnt--; + } + l++; + } + res += l; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + countSubarrays(nums, k) { + let max_n = Math.max(...nums), + max_cnt = 0, + l = 0, + res = 0; + + for (let r = 0; r < nums.length; r++) { + if (nums[r] === max_n) { + max_cnt++; + } + while (max_cnt === k) { + if (nums[l] === max_n) { + max_cnt--; + } + l++; + } + res += l; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 4. Fixed Size Sliding Window + Math + +::tabs-start + +```python +class Solution: + def countSubarrays(self, nums: List[int], k: int) -> int: + n = len(nums) + max_n = max(nums) + max_indexes = [-1] + for i, num in enumerate(nums): + if num == max_n: + max_indexes.append(i) + + res = 0 + for i in range(1, len(max_indexes) - k + 1): + cur = (max_indexes[i] - max_indexes[i - 1]) + cur *= (n - max_indexes[i + k - 1]) + res += cur + + return res +``` + +```java +public class Solution { + public long countSubarrays(int[] nums, int k) { + int n = nums.length; + int max_n = Integer.MIN_VALUE; + for (int num : nums) { + max_n = Math.max(max_n, num); + } + + List max_indexes = new ArrayList<>(); + max_indexes.add(-1); + for (int i = 0; i < n; i++) { + if (nums[i] == max_n) { + max_indexes.add(i); + } + } + + long res = 0; + for (int i = 1; i <= max_indexes.size() - k; i++) { + long cur = (max_indexes.get(i) - max_indexes.get(i - 1)); + cur *= (n - max_indexes.get(i + k - 1)); + res += cur; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long countSubarrays(vector& nums, int k) { + int n = nums.size(); + int max_n = *max_element(nums.begin(), nums.end()); + vector max_indexes = {-1}; + + for (int i = 0; i < n; i++) { + if (nums[i] == max_n) { + max_indexes.push_back(i); + } + } + + long long res = 0; + for (int i = 1; i <= int(max_indexes.size()) - k; i++) { + long long cur = (max_indexes[i] - max_indexes[i - 1]); + cur *= (n - max_indexes[i + k - 1]); + res += cur; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + countSubarrays(nums, k) { + const n = nums.length; + const max_n = Math.max(...nums); + const max_indexes = [-1]; + + for (let i = 0; i < n; i++) { + if (nums[i] === max_n) { + max_indexes.push(i); + } + } + + let res = 0; + for (let i = 1; i <= max_indexes.length - k; i++) { + res += + (max_indexes[i] - max_indexes[i - 1]) * + (n - max_indexes[i + k - 1]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 5. Fixed Size Sliding Window (Optimal) + +::tabs-start + +```python +class Solution: + def countSubarrays(self, nums: List[int], k: int) -> int: + max_n = max(nums) + max_indexes = deque() + res = 0 + + for i, num in enumerate(nums): + if num == max_n: + max_indexes.append(i) + + if len(max_indexes) > k: + max_indexes.popleft() + + if len(max_indexes) == k: + res += max_indexes[0] + 1 + + return res +``` + +```java +public class Solution { + public long countSubarrays(int[] nums, int k) { + int maxN = Integer.MIN_VALUE; + for (int num : nums) { + maxN = Math.max(maxN, num); + } + + Queue maxIndexes = new LinkedList<>(); + long res = 0; + + for (int i = 0; i < nums.length; i++) { + if (nums[i] == maxN) { + maxIndexes.add(i); + } + + if (maxIndexes.size() > k) { + maxIndexes.poll(); + } + + if (maxIndexes.size() == k) { + res += maxIndexes.peek() + 1; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long countSubarrays(vector& nums, int k) { + int maxN = *max_element(nums.begin(), nums.end()); + queue maxIndexes; + long long res = 0; + + for (int i = 0; i < nums.size(); i++) { + if (nums[i] == maxN) { + maxIndexes.push(i); + } + + if (maxIndexes.size() > k) { + maxIndexes.pop(); + } + + if (maxIndexes.size() == k) { + res += maxIndexes.front() + 1; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + countSubarrays(nums, k) { + const maxN = Math.max(...nums); + const maxIndexes = new Queue(); + let res = 0; + + for (let i = 0; i < nums.length; i++) { + if (nums[i] === maxN) { + maxIndexes.push(i); + } + + if (maxIndexes.size() > k) { + maxIndexes.pop(); + } + + if (maxIndexes.size() === k) { + res += maxIndexes.front() + 1; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/count-subsequences.md b/articles/count-subsequences.md index 04fd77389..30cd51025 100644 --- a/articles/count-subsequences.md +++ b/articles/count-subsequences.md @@ -7,18 +7,18 @@ class Solution: def numDistinct(self, s: str, t: str) -> int: if len(t) > len(s): return 0 - + def dfs(i, j): if j == len(t): return 1 if i == len(s): return 0 - + res = dfs(i + 1, j) if s[i] == t[j]: res += dfs(i + 1, j + 1) return res - + return dfs(0, 0) ``` @@ -87,7 +87,7 @@ class Solution { if (t.length > s.length) { return 0; } - + const dfs = (i, j) => { if (j === t.length) { return 1; @@ -101,7 +101,7 @@ class Solution { res += dfs(i + 1, j + 1); } return res; - } + }; return dfs(0, 0); } @@ -181,12 +181,37 @@ class Solution { } ``` +```swift +class Solution { + func numDistinct(_ s: String, _ t: String) -> Int { + let sArray = Array(s), tArray = Array(t) + let sLen = sArray.count, tLen = tArray.count + if tLen > sLen { return 0 } + + func dfs(_ i: Int, _ j: Int) -> Int { + if j == tLen { return 1 } + if i == sLen { return 0 } + + var res = dfs(i + 1, j) + if sArray[i] == tArray[j] { + res += dfs(i + 1, j + 1) + } + return res + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(2 ^ m)$ +- Space complexity: $O(m)$ + +> Where $m$ is the length of the string $s$. --- @@ -199,7 +224,7 @@ class Solution: def numDistinct(self, s: str, t: str) -> int: if len(t) > len(s): return 0 - + dp = {} def dfs(i, j): if j == len(t): @@ -208,7 +233,7 @@ class Solution: return 0 if (i, j) in dp: return dp[(i, j)] - + res = dfs(i + 1, j) if s[i] == t[j]: res += dfs(i + 1, j + 1) @@ -282,10 +307,12 @@ class Solution { * @return {number} */ numDistinct(s, t) { - let m = s.length, n = t.length; + let m = s.length, + n = t.length; if (n > m) return 0; - let dp = Array(m + 1).fill().map(() => - Array(n + 1).fill(-1)); + let dp = Array(m + 1) + .fill() + .map(() => Array(n + 1).fill(-1)); const dfs = (i, j) => { if (j === n) return 1; @@ -298,7 +325,7 @@ class Solution { } dp[i][j] = res; return res; - } + }; return dfs(0, 0); } @@ -344,7 +371,7 @@ func numDistinct(s string, t string) int { dp[i][j] = -1 } } - + var dfs func(i, j int) int dfs = func(i, j int) int { if j == len(t) { @@ -396,12 +423,39 @@ class Solution { } ``` +```swift +class Solution { + func numDistinct(_ s: String, _ t: String) -> Int { + let sArray = Array(s), tArray = Array(t) + let sLen = sArray.count, tLen = tArray.count + if tLen > sLen { return 0 } + + var dp = [[Int]: Int]() + + func dfs(_ i: Int, _ j: Int) -> Int { + if j == tLen { return 1 } + if i == sLen { return 0 } + if let val = dp[[i, j]] { return val } + + var res = dfs(i + 1, j) + if sArray[i] == tArray[j] { + res += dfs(i + 1, j + 1) + } + dp[[i, j]] = res + return res + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the length of the string $s$ and $n$ is the length of the string $t$. @@ -419,13 +473,13 @@ class Solution: for i in range(m + 1): dp[i][n] = 1 - + for i in range(m - 1, -1, -1): for j in range(n - 1, -1, -1): dp[i][j] = dp[i + 1][j] if s[i] == t[j]: dp[i][j] += dp[i + 1][j + 1] - + return dp[0][0] ``` @@ -458,7 +512,7 @@ class Solution { public: int numDistinct(string s, string t) { int m = s.length(), n = t.length(); - vector> dp(m + 1, vector(n + 1, 0)); + vector> dp(m + 1, vector(n + 1, 0)); for (int i = 0; i <= m; i++) { dp[i][n] = 1; @@ -486,9 +540,9 @@ class Solution { * @return {number} */ numDistinct(s, t) { - let m = s.length, n = t.length; - let dp = Array.from({ length: m + 1 }, () => - Array(n + 1).fill(0)); + let m = s.length, + n = t.length; + let dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); for (let i = 0; i <= m; i++) { dp[i][n] = 1; @@ -582,12 +636,48 @@ class Solution { } ``` +```swift +class Solution { + func numDistinct(_ s: String, _ t: String) -> Int { + let m = s.count, n = t.count + var dp = Array( + repeating: Array(repeating: 0, count: n + 1), + count: m + 1 + ) + + let sArray = Array(s) + let tArray = Array(t) + + for i in 0...m { + dp[i][n] = 1 + } + + for i in stride(from: m - 1, through: 0, by: -1) { + for j in stride(from: n - 1, through: 0, by: -1) { + let base = dp[i + 1][j] + dp[i][j] = base + if sArray[i] == tArray[j] { + let addend = dp[i + 1][j + 1] + if base > Int.max - addend { + dp[i][j] = 0 + } else { + dp[i][j] += addend + } + } + } + } + + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the length of the string $s$ and $n$ is the length of the string $t$. @@ -643,8 +733,8 @@ class Solution { public: int numDistinct(string s, string t) { int m = s.size(), n = t.size(); - vector dp(n + 1, 0); - vector nextDp(n + 1, 0); + vector dp(n + 1, 0); + vector nextDp(n + 1, 0); dp[n] = nextDp[n] = 1; for (int i = m - 1; i >= 0; i--) { @@ -670,7 +760,8 @@ class Solution { * @return {number} */ numDistinct(s, t) { - let m = s.length, n = t.length; + let m = s.length, + n = t.length; let dp = new Array(n + 1).fill(0); let nextDp = new Array(n + 1).fill(0); @@ -729,7 +820,7 @@ func numDistinct(s string, t string) int { nextDp[j] += dp[j+1] } } - dp = append([]int(nil), nextDp...) + dp = append([]int(nil), nextDp...) } return dp[0] @@ -762,12 +853,44 @@ class Solution { } ``` +```swift +class Solution { + func numDistinct(_ s: String, _ t: String) -> Int { + let m = s.count, n = t.count + var dp = [Int](repeating: 0, count: n + 1) + var nextDp = [Int](repeating: 0, count: n + 1) + dp[n] = 1 + nextDp[n] = 1 + + let sArr = Array(s) + let tArr = Array(t) + + for i in stride(from: m - 1, through: 0, by: -1) { + for j in stride(from: n - 1, through: 0, by: -1) { + nextDp[j] = dp[j] + if sArr[i] == tArr[j] { + let addend = dp[j + 1] + if nextDp[j] > Int.max - addend { + nextDp[j] = 0 + } else { + nextDp[j] += addend + } + } + } + dp = nextDp + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(n)$ > Where $m$ is the length of the string $s$ and $n$ is the length of the string $t$. @@ -792,8 +915,8 @@ class Solution: res += prev prev = dp[j] - dp[j] = res - + dp[j] = res + return dp[0] ``` @@ -816,7 +939,7 @@ public class Solution { dp[j] = res; } } - + return dp[0]; } } @@ -827,13 +950,13 @@ class Solution { public: int numDistinct(string s, string t) { int m = s.size(), n = t.size(); - vector dp(n + 1, 0); + vector dp(n + 1, 0); dp[n] = 1; for (int i = m - 1; i >= 0; i--) { int prev = 1; for (int j = n - 1; j >= 0; j--) { - int res = dp[j]; + uint res = dp[j]; if (s[i] == t[j]) { res += prev; } @@ -856,7 +979,8 @@ class Solution { * @return {number} */ numDistinct(s, t) { - let m = s.length, n = t.length; + let m = s.length, + n = t.length; let dp = new Array(n + 1).fill(0); dp[n] = 1; @@ -950,11 +1074,42 @@ class Solution { } ``` +```swift +class Solution { + func numDistinct(_ s: String, _ t: String) -> Int { + let m = s.count, n = t.count + var dp = [Int](repeating: 0, count: n + 1) + dp[n] = 1 + let sArr = Array(s) + let tArr = Array(t) + + for i in stride(from: m - 1, through: 0, by: -1) { + var prev = 1 + for j in stride(from: n - 1, through: 0, by: -1) { + let base = dp[j] + var res = base + if sArr[i] == tArr[j] { + if base > Int.max - prev { + res = 0 + } else { + res += prev + } + } + prev = dp[j] + dp[j] = res + } + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(n)$ -> Where $m$ is the length of the string $s$ and $n$ is the length of the string $t$. \ No newline at end of file +> Where $m$ is the length of the string $s$ and $n$ is the length of the string $t$. diff --git a/articles/count-the-number-of-consistent-strings.md b/articles/count-the-number-of-consistent-strings.md new file mode 100644 index 000000000..abbbc5a2c --- /dev/null +++ b/articles/count-the-number-of-consistent-strings.md @@ -0,0 +1,415 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def countConsistentStrings(self, allowed: str, words: List[str]) -> int: + res = 0 + + for w in words: + flag = 1 + for c in w: + if c not in allowed: + flag = 0 + break + res += flag + + return res +``` + +```java +public class Solution { + public int countConsistentStrings(String allowed, String[] words) { + int res = 0; + + for (String w : words) { + boolean flag = true; + for (char c : w.toCharArray()) { + if (allowed.indexOf(c) == -1) { + flag = false; + break; + } + } + if (flag) res++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int countConsistentStrings(string allowed, vector& words) { + int res = 0; + + for (string& w : words) { + bool flag = true; + for (char c : w) { + if (allowed.find(c) == string::npos) { + flag = false; + break; + } + } + res += flag; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} allowed + * @param {string[]} words + * @return {number} + */ + countConsistentStrings(allowed, words) { + let res = 0; + + for (let w of words) { + let flag = 1; + for (let c of w) { + if (!allowed.includes(c)) { + flag = 0; + break; + } + } + res += flag; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m * l)$ +- Space complexity: $O(1)$ + +> Where $n$ is the number of words, $m$ is the length of the string $allowed$, and $l$ is the length of the longest word. + +--- + +## 2. Hash Set + +::tabs-start + +```python +class Solution: + def countConsistentStrings(self, allowed: str, words: List[str]) -> int: + allowed = set(allowed) + + res = len(words) + for w in words: + for c in w: + if c not in allowed: + res -= 1 + break + + return res +``` + +```java +public class Solution { + public int countConsistentStrings(String allowed, String[] words) { + Set allowedSet = new HashSet<>(); + for (char c : allowed.toCharArray()) { + allowedSet.add(c); + } + + int res = words.length; + for (String w : words) { + for (char c : w.toCharArray()) { + if (!allowedSet.contains(c)) { + res--; + break; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int countConsistentStrings(string allowed, vector& words) { + unordered_set allowedSet(allowed.begin(), allowed.end()); + + int res = words.size(); + for (string& w : words) { + for (char c : w) { + if (allowedSet.find(c) == allowedSet.end()) { + res--; + break; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} allowed + * @param {string[]} words + * @return {number} + */ + countConsistentStrings(allowed, words) { + const allowedSet = new Set(allowed); + let res = words.length; + + for (let w of words) { + for (let c of w) { + if (!allowedSet.has(c)) { + res--; + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * l + m)$ +- Space complexity: $O(m)$ + +> Where $n$ is the number of words, $m$ is the length of the string $allowed$, and $l$ is the length of the longest word. + +--- + +## 3. Boolean Array + +::tabs-start + +```python +class Solution: + def countConsistentStrings(self, allowed: str, words: List[str]) -> int: + allowedArr = [False] * 26 + for c in allowed: + allowedArr[ord(c) - ord('a')] = True + + res = len(words) + for w in words: + for c in w: + if not allowedArr[ord(c) - ord('a')]: + res -= 1 + break + + return res +``` + +```java +public class Solution { + public int countConsistentStrings(String allowed, String[] words) { + Set allowedSet = new HashSet<>(); + for (char c : allowed.toCharArray()) { + allowedSet.add(c); + } + + int res = words.length; + for (String w : words) { + for (char c : w.toCharArray()) { + if (!allowedSet.contains(c)) { + res--; + break; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int countConsistentStrings(string allowed, vector& words) { + bool allowedArr[26] = {}; + for (char c : allowed) { + allowedArr[c - 'a'] = true; + } + + int res = words.size(); + for (const string& w : words) { + for (char c : w) { + if (!allowedArr[c - 'a']) { + res--; + break; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} allowed + * @param {string[]} words + * @return {number} + */ + countConsistentStrings(allowed, words) { + const allowedArr = new Array(26).fill(false); + for (let c of allowed) { + allowedArr[c.charCodeAt(0) - 97] = true; + } + + let res = words.length; + for (let w of words) { + for (let c of w) { + if (!allowedArr[c.charCodeAt(0) - 97]) { + res--; + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * l + m)$ +- Space complexity: $O(m)$ + +> Where $n$ is the number of words, $m$ is the length of the string $allowed$, and $l$ is the length of the longest word. + +--- + +## 4. Bitmask + +::tabs-start + +```python +class Solution: + def countConsistentStrings(self, allowed: str, words: List[str]) -> int: + bit_mask = 0 + for c in allowed: + bit = 1 << (ord(c) - ord('a')) + bit_mask = bit_mask | bit + + res = len(words) + for w in words: + for c in w: + bit = 1 << (ord(c) - ord('a')) + if bit & bit_mask == 0: + res -= 1 + break + + return res +``` + +```java +public class Solution { + public int countConsistentStrings(String allowed, String[] words) { + int bitMask = 0; + for (char c : allowed.toCharArray()) { + bitMask |= 1 << (c - 'a'); + } + + int res = words.length; + for (String w : words) { + for (char c : w.toCharArray()) { + int bit = 1 << (c - 'a'); + if ((bit & bitMask) == 0) { + res--; + break; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int countConsistentStrings(string allowed, vector& words) { + int bitMask = 0; + for (char c : allowed) { + bitMask |= (1 << (c - 'a')); + } + + int res = words.size(); + for (const string& w : words) { + for (char c : w) { + int bit = 1 << (c - 'a'); + if ((bit & bitMask) == 0) { + res--; + break; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} allowed + * @param {string[]} words + * @return {number} + */ + countConsistentStrings(allowed, words) { + let bitMask = 0; + for (let c of allowed) { + bitMask |= 1 << (c.charCodeAt(0) - 97); + } + + let res = words.length; + for (let w of words) { + for (let c of w) { + const bit = 1 << (c.charCodeAt(0) - 97); + if ((bit & bitMask) === 0) { + res--; + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * l + m)$ +- Space complexity: $O(1)$ + +> Where $n$ is the number of words, $m$ is the length of the string $allowed$, and $l$ is the length of the longest word. diff --git a/articles/count-triplets-that-can-form-two-arrays-of-equal-xor.md b/articles/count-triplets-that-can-form-two-arrays-of-equal-xor.md new file mode 100644 index 000000000..10c0d16c0 --- /dev/null +++ b/articles/count-triplets-that-can-form-two-arrays-of-equal-xor.md @@ -0,0 +1,434 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def countTriplets(self, arr: List[int]) -> int: + N = len(arr) + res = 0 + + for i in range(N - 1): + for j in range(i + 1, N): + for k in range(j, N): + a = b = 0 + for idx in range(i, j): + a ^= arr[idx] + for idx in range(j, k + 1): + b ^= arr[idx] + if a == b: + res += 1 + + return res +``` + +```java +public class Solution { + public int countTriplets(int[] arr) { + int N = arr.length; + int res = 0; + + for (int i = 0; i < N - 1; i++) { + for (int j = i + 1; j < N; j++) { + for (int k = j; k < N; k++) { + int a = 0, b = 0; + for (int idx = i; idx < j; idx++) { + a ^= arr[idx]; + } + for (int idx = j; idx <= k; idx++) { + b ^= arr[idx]; + } + if (a == b) { + res++; + } + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int countTriplets(vector& arr) { + int N = arr.size(); + int res = 0; + + for (int i = 0; i < N - 1; ++i) { + for (int j = i + 1; j < N; ++j) { + for (int k = j; k < N; ++k) { + int a = 0, b = 0; + for (int idx = i; idx < j; ++idx) { + a ^= arr[idx]; + } + for (int idx = j; idx <= k; ++idx) { + b ^= arr[idx]; + } + if (a == b) { + res++; + } + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + countTriplets(arr) { + const N = arr.length; + let res = 0; + + for (let i = 0; i < N - 1; i++) { + for (let j = i + 1; j < N; j++) { + for (let k = j; k < N; k++) { + let a = 0, + b = 0; + for (let idx = i; idx < j; idx++) { + a ^= arr[idx]; + } + for (let idx = j; idx <= k; idx++) { + b ^= arr[idx]; + } + if (a === b) { + res++; + } + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 4)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 2. Brute Force (Optimized) + +::tabs-start + +```python +class Solution: + def countTriplets(self, arr: List[int]) -> int: + N = len(arr) + res = 0 + + for i in range(N - 1): + a = 0 + for j in range(i + 1, N): + a ^= arr[j - 1] + b = 0 + for k in range(j, N): + b ^= arr[k] + if a == b: + res += 1 + + return res +``` + +```java +public class Solution { + public int countTriplets(int[] arr) { + int N = arr.length; + int res = 0; + + for (int i = 0; i < N - 1; i++) { + int a = 0; + for (int j = i + 1; j < N; j++) { + a ^= arr[j - 1]; + int b = 0; + for (int k = j; k < N; k++) { + b ^= arr[k]; + if (a == b) { + res++; + } + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int countTriplets(vector& arr) { + int N = arr.size(); + int res = 0; + + for (int i = 0; i < N - 1; ++i) { + int a = 0; + for (int j = i + 1; j < N; ++j) { + a ^= arr[j - 1]; + int b = 0; + for (int k = j; k < N; ++k) { + b ^= arr[k]; + if (a == b) { + res++; + } + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + countTriplets(arr) { + const N = arr.length; + let res = 0; + + for (let i = 0; i < N - 1; i++) { + let a = 0; + for (let j = i + 1; j < N; j++) { + a ^= arr[j - 1]; + let b = 0; + for (let k = j; k < N; k++) { + b ^= arr[k]; + if (a === b) { + res++; + } + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 3. Math + Bitwise XOR + +::tabs-start + +```python +class Solution: + def countTriplets(self, arr: List[int]) -> int: + N = len(arr) + res = 0 + + for i in range(N - 1): + cur_xor = arr[i] + for k in range(i + 1, N): + cur_xor ^= arr[k] + if cur_xor == 0: + res += k - i + + return res +``` + +```java +public class Solution { + public int countTriplets(int[] arr) { + int N = arr.length; + int res = 0; + + for (int i = 0; i < N - 1; i++) { + int curXor = arr[i]; + for (int k = i + 1; k < N; k++) { + curXor ^= arr[k]; + if (curXor == 0) { + res += k - i; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int countTriplets(vector& arr) { + int N = arr.size(); + int res = 0; + + for (int i = 0; i < N - 1; ++i) { + int curXor = arr[i]; + for (int k = i + 1; k < N; ++k) { + curXor ^= arr[k]; + if (curXor == 0) { + res += k - i; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + countTriplets(arr) { + const N = arr.length; + let res = 0; + + for (let i = 0; i < N - 1; i++) { + let curXor = arr[i]; + for (let k = i + 1; k < N; k++) { + curXor ^= arr[k]; + if (curXor === 0) { + res += k - i; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 4. Math + Bitwise XOR (Optimal) + +::tabs-start + +```python +class Solution: + def countTriplets(self, arr: List[int]) -> int: + N = len(arr) + res = prefix = 0 + count = defaultdict(int) # number of prefixes + index_sum = defaultdict(int) # sum of indices with that prefix + count[0] = 1 + + for i in range(N): + prefix ^= arr[i] + if prefix in count: + res += i * count[prefix] - index_sum[prefix] + count[prefix] += 1 + index_sum[prefix] += i + 1 + + return res +``` + +```java +public class Solution { + public int countTriplets(int[] arr) { + int N = arr.length, res = 0, prefix = 0; + Map count = new HashMap<>(); // number of prefixes + Map indexSum = new HashMap<>(); // sum of indices with that prefix + count.put(0, 1); + + for (int i = 0; i < N; i++) { + prefix ^= arr[i]; + if (count.containsKey(prefix)) { + res += i * count.get(prefix) - indexSum.getOrDefault(prefix, 0); + } + count.put(prefix, count.getOrDefault(prefix, 0) + 1); + indexSum.put(prefix, indexSum.getOrDefault(prefix, 0) + i + 1); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int countTriplets(vector& arr) { + int N = arr.size(), res = 0, prefix = 0; + unordered_map count; // number of prefixes + unordered_map indexSum; // sum of indices with that prefix + count[0] = 1; + + for (int i = 0; i < N; i++) { + prefix ^= arr[i]; + if (count.count(prefix)) { + res += i * count[prefix] - indexSum[prefix]; + } + count[prefix]++; + indexSum[prefix] += i + 1; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + countTriplets(arr) { + const N = arr.length; + let res = 0, + prefix = 0; + const count = new Map(); // number of prefixes + const indexSum = new Map(); // sum of indices with that prefix + count.set(0, 1); + + for (let i = 0; i < N; i++) { + prefix ^= arr[i]; + if (count.has(prefix)) { + res += i * count.get(prefix) - (indexSum.get(prefix) || 0); + } + count.set(prefix, (count.get(prefix) || 0) + 1); + indexSum.set(prefix, (indexSum.get(prefix) || 0) + i + 1); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/count-vowel-strings-in-ranges.md b/articles/count-vowel-strings-in-ranges.md new file mode 100644 index 000000000..5e50ee28a --- /dev/null +++ b/articles/count-vowel-strings-in-ranges.md @@ -0,0 +1,336 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def vowelStrings(self, words: List[str], queries: List[List[int]]) -> List[int]: + vowels = set("aeiou") + res = [] + + for start, end in queries: + cnt = 0 + for i in range(start, end + 1): + if words[i][0] in vowels and words[i][-1] in vowels: + cnt += 1 + res.append(cnt) + + return res +``` + +```java +public class Solution { + public int[] vowelStrings(String[] words, int[][] queries) { + Set vowels = Set.of('a', 'e', 'i', 'o', 'u'); + int[] res = new int[queries.length]; + + for (int k = 0; k < queries.length; k++) { + int start = queries[k][0], end = queries[k][1], count = 0; + + for (int i = start; i <= end; i++) { + String word = words[i]; + if (vowels.contains(word.charAt(0)) && vowels.contains(word.charAt(word.length() - 1))) { + count++; + } + } + + res[k] = count; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector vowelStrings(vector& words, vector>& queries) { + unordered_set vowels = {'a', 'e', 'i', 'o', 'u'}; + vector res; + + for (auto& q : queries) { + int start = q[0], end = q[1], count = 0; + + for (int i = start; i <= end; i++) { + if (vowels.count(words[i][0]) && vowels.count(words[i].back())) { + count++; + } + } + + res.push_back(count); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {number[][]} queries + * @return {number[]} + */ + vowelStrings(words, queries) { + const vowels = new Set(['a', 'e', 'i', 'o', 'u']); + const res = []; + + for (let [start, end] of queries) { + let count = 0; + for (let i = start; i <= end; i++) { + const word = words[i]; + if (vowels.has(word[0]) && vowels.has(word[word.length - 1])) { + count++; + } + } + res.push(count); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m)$ +- Space complexity: + - $O(1)$ extra space. + - $O(m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the number of queries. + +--- + +## 2. Prefix Sum + Hash Set + +::tabs-start + +```python +class Solution: + def vowelStrings(self, words: List[str], queries: List[List[int]]) -> List[int]: + vowel_set = set("aeiou") + prefix_cnt = [0] * (len(words) + 1) + prev = 0 + + for i, w in enumerate(words): + if w[0] in vowel_set and w[-1] in vowel_set: + prev += 1 + prefix_cnt[i + 1] = prev + + res = [0] * len(queries) + for i, q in enumerate(queries): + l, r = q + res[i] = prefix_cnt[r + 1] - prefix_cnt[l] + + return res +``` + +```java +public class Solution { + public int[] vowelStrings(String[] words, int[][] queries) { + Set vowels = Set.of('a', 'e', 'i', 'o', 'u'); + int n = words.length; + int[] prefixCnt = new int[n + 1]; + + for (int i = 0; i < n; i++) { + String w = words[i]; + prefixCnt[i + 1] = prefixCnt[i]; + if (vowels.contains(w.charAt(0)) && vowels.contains(w.charAt(w.length() - 1))) { + prefixCnt[i + 1]++; + } + } + + int[] res = new int[queries.length]; + for (int i = 0; i < queries.length; i++) { + int l = queries[i][0], r = queries[i][1]; + res[i] = prefixCnt[r + 1] - prefixCnt[l]; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector vowelStrings(vector& words, vector>& queries) { + unordered_set vowels = {'a', 'e', 'i', 'o', 'u'}; + int n = words.size(); + vector prefixCnt(n + 1, 0); + + for (int i = 0; i < n; i++) { + prefixCnt[i + 1] = prefixCnt[i]; + if (vowels.count(words[i][0]) && vowels.count(words[i].back())) { + prefixCnt[i + 1]++; + } + } + + vector res; + for (auto& q : queries) { + int l = q[0], r = q[1]; + res.push_back(prefixCnt[r + 1] - prefixCnt[l]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {number[][]} queries + * @return {number[]} + */ + vowelStrings(words, queries) { + const vowels = new Set(['a', 'e', 'i', 'o', 'u']); + const n = words.length; + const prefixCnt = new Array(n + 1).fill(0); + + for (let i = 0; i < n; i++) { + prefixCnt[i + 1] = prefixCnt[i]; + const w = words[i]; + if (vowels.has(w[0]) && vowels.has(w[w.length - 1])) { + prefixCnt[i + 1]++; + } + } + + const res = new Array(queries.length); + for (let i = 0; i < queries.length; i++) { + const [l, r] = queries[i]; + res[i] = prefixCnt[r + 1] - prefixCnt[l]; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m)$ +- Space complexity: + - $O(n)$ extra space. + - $O(m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the number of queries. + +--- + +## 3. Prefix Sum + Bitmask + +::tabs-start + +```python +class Solution: + def vowelStrings(self, words: List[str], queries: List[List[int]]) -> List[int]: + vowels = sum(1 << (ord(c) - ord('a')) for c in "aeiou") + prefix = [0] + for w in words: + prefix.append(prefix[-1]) + if (1 << (ord(w[0]) - ord('a'))) & vowels and (1 << (ord(w[-1]) - ord('a'))) & vowels: + prefix[-1] += 1 + return [prefix[r + 1] - prefix[l] for l, r in queries] +``` + +```java +public class Solution { + public int[] vowelStrings(String[] words, int[][] queries) { + int vowels = 0; + for (char c : "aeiou".toCharArray()) { + vowels |= 1 << (c - 'a'); + } + + int[] prefix = new int[words.length + 1]; + for (int i = 0; i < words.length; i++) { + int f = words[i].charAt(0) - 'a'; + int l = words[i].charAt(words[i].length() - 1) - 'a'; + int isVowel = ((1 << f) & vowels) != 0 && ((1 << l) & vowels) != 0 ? 1 : 0; + prefix[i + 1] = prefix[i] + isVowel; + } + + int[] res = new int[queries.length]; + for (int i = 0; i < queries.length; i++) { + int l = queries[i][0], r = queries[i][1]; + res[i] = prefix[r + 1] - prefix[l]; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector vowelStrings(vector& words, vector>& queries) { + int vowels = 0; + for (char c : string("aeiou")) { + vowels |= (1 << (c - 'a')); + } + + int n = words.size(); + vector prefix(n + 1); + for (int i = 0; i < n; i++) { + int f = words[i][0] - 'a'; + int l = words[i].back() - 'a'; + int isVowel = ((1 << f) & vowels) && ((1 << l) & vowels); + prefix[i + 1] = prefix[i] + isVowel; + } + + vector res; + for (auto& q : queries) { + int l = q[0], r = q[1]; + res.push_back(prefix[r + 1] - prefix[l]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {number[][]} queries + * @return {number[]} + */ + vowelStrings(words, queries) { + let vowels = 0; + for (let c of 'aeiou') { + vowels |= 1 << (c.charCodeAt(0) - 97); + } + + const prefix = [0]; + for (let w of words) { + const f = w.charCodeAt(0) - 97; + const l = w.charCodeAt(w.length - 1) - 97; + const isVowel = (1 << f) & vowels && (1 << l) & vowels ? 1 : 0; + prefix.push(prefix[prefix.length - 1] + isVowel); + } + + return queries.map(([l, r]) => prefix[r + 1] - prefix[l]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m)$ +- Space complexity: + - $O(n)$ extra space. + - $O(m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the number of queries. diff --git a/articles/count-vowels-permutation.md b/articles/count-vowels-permutation.md index c2f561f56..51b5027c5 100644 --- a/articles/count-vowels-permutation.md +++ b/articles/count-vowels-permutation.md @@ -17,7 +17,7 @@ class Solution: def dfs(i, v): if i == n: return 1 - + total = 0 for nxt in follows[v]: total = (total + dfs(i + 1, nxt)) % MOD @@ -26,7 +26,7 @@ class Solution: res = 0 for vowel in ['a', 'e', 'i', 'o', 'u']: res = (res + dfs(1, vowel)) % MOD - + return res ``` @@ -53,7 +53,7 @@ public class Solution { if (i == n) { return 1; } - + int total = 0; for (char next : follows.get(v)) { total = (total + dfs(i + 1, next, n)) % MOD; @@ -76,7 +76,7 @@ class Solution { public: int countVowelPermutation(int n) { - + int res = 0; for (char vowel : string("aeiou")) { res = (res + dfs(1, vowel, n)) % MOD; @@ -89,7 +89,7 @@ private: if (i == n) { return 1; } - + int total = 0; for (char& next : follows[v]) { total = (total + dfs(i + 1, next, n)) % MOD; @@ -113,14 +113,14 @@ class Solution { e: ['a', 'i'], i: ['a', 'e', 'o', 'u'], o: ['i', 'u'], - u: ['a'] + u: ['a'], }; const dfs = (i, v) => { if (i === n) { return 1; } - + let total = 0; for (const next of follows[v]) { total = (total + dfs(i + 1, next)) % MOD; @@ -142,8 +142,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(4 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(4 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -169,7 +169,7 @@ class Solution: return 1 if (i, v) in cache: return cache[(i, v)] - + total = 0 for nxt in follows[v]: total = (total + dfs(i + 1, nxt)) % MOD @@ -179,7 +179,7 @@ class Solution: res = 0 for vowel in ['a', 'e', 'i', 'o', 'u']: res = (res + dfs(1, vowel)) % MOD - + return res ``` @@ -213,7 +213,7 @@ public class Solution { return 1; } if (dp[i][v] != -1) return dp[i][v]; - + int total = 0; for (int next : follows.get(v)) { total = (total + dfs(i + 1, next, n)) % MOD; @@ -271,11 +271,11 @@ class Solution { const dp = Array.from({ length: n }, () => Array(5).fill(-1)); const follows = { - 0: [1], // 'a' -> 'e' - 1: [0, 2], // 'e' -> 'a', 'i' - 2: [0, 1, 3, 4], // 'i' -> 'a', 'e', 'o', 'u' - 3: [2, 4], // 'o' -> 'i', 'u' - 4: [0], // 'u' -> 'a' + 0: [1], // 'a' -> 'e' + 1: [0, 2], // 'e' -> 'a', 'i' + 2: [0, 1, 3, 4], // 'i' -> 'a', 'e', 'o', 'u' + 3: [2, 4], // 'o' -> 'i', 'u' + 4: [0], // 'u' -> 'a' }; const dfs = (i, v) => { @@ -303,8 +303,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -412,11 +412,11 @@ class Solution { const MOD = 1e9 + 7; const dp = Array.from({ length: n + 1 }, () => Array(5).fill(0)); const follows = [ - [1], // 'a' -> 'e' - [0, 2], // 'e' -> 'a', 'i' + [1], // 'a' -> 'e' + [0, 2], // 'e' -> 'a', 'i' [0, 1, 3, 4], // 'i' -> 'a', 'e', 'o', 'u' - [2, 4], // 'o' -> 'i', 'u' - [0] // 'u' -> 'a' + [2, 4], // 'o' -> 'i', 'u' + [0], // 'u' -> 'a' ]; for (let v = 0; v < 5; v++) { @@ -440,8 +440,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -551,11 +551,11 @@ class Solution { countVowelPermutation(n) { const MOD = 1e9 + 7; const follows = [ - [1], // 'a' -> 'e' - [0, 2], // 'e' -> 'a', 'i' + [1], // 'a' -> 'e' + [0, 2], // 'e' -> 'a', 'i' [0, 1, 3, 4], // 'i' -> 'a', 'e', 'o', 'u' - [2, 4], // 'o' -> 'i', 'u' - [0] // 'u' -> 'a' + [2, 4], // 'o' -> 'i', 'u' + [0], // 'u' -> 'a' ]; let dp = [1, 1, 1, 1, 1]; @@ -579,8 +579,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since we used array of size $5$. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we used array of size $5$. --- @@ -805,7 +805,6 @@ class M { } class Solution { - /** * @param {M} * @param {number} exp @@ -834,11 +833,11 @@ class Solution { countVowelPermutation(n) { const MOD = 1e9 + 7; const follows = [ - [0, 1, 0, 0, 0], // 'a' -> 'e' - [1, 0, 1, 0, 0], // 'e' -> 'a', 'i' - [1, 1, 0, 1, 1], // 'i' -> 'a', 'e', 'o', 'u' - [0, 0, 1, 0, 1], // 'o' -> 'i', 'u' - [1, 0, 0, 0, 0] // 'u' -> 'a' + [0, 1, 0, 0, 0], // 'a' -> 'e' + [1, 0, 1, 0, 0], // 'e' -> 'a', 'i' + [1, 1, 0, 1, 1], // 'i' -> 'a', 'e', 'o', 'u' + [0, 0, 1, 0, 1], // 'o' -> 'i', 'u' + [1, 0, 0, 0, 0], // 'u' -> 'a' ]; const base = new M(5); base.a = follows; @@ -858,7 +857,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m ^ 3 \log n)$ -* Space complexity: $O(m ^ 2)$ +- Time complexity: $O(m ^ 3 \log n)$ +- Space complexity: $O(m ^ 2)$ -> Where $m$ is the size of the matrix used in matrix exponentiation $(5 X 5)$ and $n$ is the length of the permutation. \ No newline at end of file +> Where $m$ is the size of the matrix used in matrix exponentiation $(5 X 5)$ and $n$ is the length of the permutation. diff --git a/articles/count-ways-to-build-good-strings.md b/articles/count-ways-to-build-good-strings.md index a18b90526..5642378ea 100644 --- a/articles/count-ways-to-build-good-strings.md +++ b/articles/count-ways-to-build-good-strings.md @@ -66,7 +66,7 @@ class Solution { countGoodStrings(low, high, zero, one) { const mod = 1e9 + 7; - const dfs = length => { + const dfs = (length) => { if (length > high) return 0; let res = length >= low ? 1 : 0; res = (res + dfs(length + zero)) % mod; @@ -83,8 +83,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. > Where $n$ is equal to the given $high$ value. @@ -172,7 +172,7 @@ class Solution { const mod = 1e9 + 7; const dp = new Array(high + 1).fill(-1); - const dfs = length => { + const dfs = (length) => { if (length > high) return 0; if (dp[length] !== -1) return dp[length]; dp[length] = length >= low ? 1 : 0; @@ -190,8 +190,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ > Where $n$ is equal to the given $high$ value. @@ -209,7 +209,7 @@ class Solution: for i in range(1, high + 1): dp[i] = (dp.get(i - one, 0) + dp.get(i - zero, 0)) % mod - + return sum(dp[i] for i in range(low, high + 1)) % mod ``` @@ -277,7 +277,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ -> Where $n$ is equal to the given $high$ value. \ No newline at end of file +> Where $n$ is equal to the given $high$ value. diff --git a/articles/counting-bits.md b/articles/counting-bits.md index 514bef953..67980b8b6 100644 --- a/articles/counting-bits.md +++ b/articles/counting-bits.md @@ -25,7 +25,7 @@ public class Solution { res[num]++; } } - } + } return res; } } @@ -80,7 +80,7 @@ public class Solution { res[num]++; } } - } + } return res; } } @@ -120,12 +120,32 @@ class Solution { } ``` +```swift +class Solution { + func countBits(_ n: Int) -> [Int] { + var res = [Int]() + for num in 0...n { + var one = 0 + for i in 0..<32 { + if num & (1 << i) != 0 { + one += 1 + } + } + res.append(one) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n \log n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output array. --- @@ -190,7 +210,7 @@ class Solution { let num = i; while (num !== 0) { res[i]++; - num &= (num - 1); + num &= num - 1; } } return res; @@ -244,12 +264,30 @@ class Solution { } ``` +```swift +class Solution { + func countBits(_ n: Int) -> [Int] { + var res = [Int](repeating: 0, count: n + 1) + for i in 1..<(n + 1) { + var num = i + while num != 0 { + res[i] += 1 + num &= (num - 1) + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n \log n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output array. --- @@ -334,12 +372,26 @@ class Solution { } ``` +```swift +class Solution { + func countBits(_ n: Int) -> [Int] { + var res = [Int](repeating: 0, count: n + 1) + for num in 1..<(n + 1) { + res[num] = num.nonzeroBitCount + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n \log n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output array. --- @@ -465,12 +517,31 @@ class Solution { } ``` +```swift +class Solution { + func countBits(_ n: Int) -> [Int] { + var dp = [Int](repeating: 0, count: n + 1) + var offset = 1 + + for i in 1..<(n + 1) { + if offset * 2 == i { + offset = i + } + dp[i] = 1 + dp[i - offset] + } + return dp + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output array. --- @@ -562,9 +633,23 @@ class Solution { } ``` +```swift +class Solution { + func countBits(_ n: Int) -> [Int] { + var dp = [Int](repeating: 0, count: n + 1) + for i in 0..<(n + 1) { + dp[i] = dp[i >> 1] + (i & 1) + } + return dp + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output array. diff --git a/articles/course-schedule-ii.md b/articles/course-schedule-ii.md index 7980e9e5e..7f110a71c 100644 --- a/articles/course-schedule-ii.md +++ b/articles/course-schedule-ii.md @@ -38,7 +38,7 @@ public class Solution { public int[] findOrder(int numCourses, int[][] prerequisites) { Map> prereq = new HashMap<>(); for (int[] pair : prerequisites) { - prereq.computeIfAbsent(pair[0], + prereq.computeIfAbsent(pair[0], k -> new ArrayList<>()).add(pair[1]); } @@ -60,7 +60,7 @@ public class Solution { } private boolean dfs(int course, Map> prereq, - Set visit, Set cycle, + Set visit, Set cycle, List output) { if (cycle.contains(course)) { @@ -108,9 +108,9 @@ public: private: bool dfs(int course, const unordered_map>& prereq, - unordered_set& visit, unordered_set& cycle, + unordered_set& visit, unordered_set& cycle, vector& output) { - + if (cycle.count(course)) { return false; } @@ -218,9 +218,9 @@ public class Solution { } private bool Dfs(int course, Dictionary> prereq, - HashSet visit, HashSet cycle, + HashSet visit, HashSet cycle, List output) { - + if (cycle.Contains(course)) { return false; } @@ -285,7 +285,7 @@ func findOrder(numCourses int, prerequisites [][]int) []int { return []int{} } } - + return output } ``` @@ -329,12 +329,57 @@ class Solution { } ``` +```swift +class Solution { + func findOrder(_ numCourses: Int, _ prerequisites: [[Int]]) -> [Int] { + var prereq = [Int: [Int]]() + for c in 0..() + var cycle = Set() + + func dfs(_ crs: Int) -> Bool { + if cycle.contains(crs) { + return false + } + if visit.contains(crs) { + return true + } + + cycle.insert(crs) + for pre in prereq[crs]! { + if !dfs(pre) { + return false + } + } + cycle.remove(crs) + visit.insert(crs) + output.append(crs) + return true + } + + for c in 0.. Where $V$ is the number of courses and $E$ is the number of prerequisites. @@ -357,7 +402,7 @@ class Solution: for n in range(numCourses): if indegree[n] == 0: q.append(n) - + finish, output = 0, [] while q: node = q.popleft() @@ -367,7 +412,7 @@ class Solution: indegree[nei] -= 1 if indegree[nei] == 0: q.append(nei) - + if finish != numCourses: return [] return output[::-1] @@ -406,7 +451,7 @@ public class Solution { } } } - + if (finish != numCourses) { return new int[0]; } @@ -421,7 +466,7 @@ public: vector findOrder(int numCourses, vector>& prerequisites) { vector indegree(numCourses, 0); vector> adj(numCourses); - + for (auto& pre : prerequisites) { indegree[pre[1]]++; adj[pre[0]].push_back(pre[1]); @@ -590,7 +635,7 @@ class Solution { fun findOrder(numCourses: Int, prerequisites: Array): IntArray { val indegree = IntArray(numCourses) val adj = Array(numCourses) { mutableListOf() } - + for (pair in prerequisites) { val (src, dst) = pair indegree[dst]++ @@ -624,12 +669,51 @@ class Solution { } ``` +```swift +class Solution { + func findOrder(_ numCourses: Int, _ prerequisites: [[Int]]) -> [Int] { + var indegree = Array(repeating: 0, count: numCourses) + var adj = Array(repeating: [Int](), count: numCourses) + + for pair in prerequisites { + let src = pair[0] + let dst = pair[1] + indegree[dst] += 1 + adj[src].append(dst) + } + + var queue = Deque() + for n in 0.. Where $V$ is the number of courses and $E$ is the number of prerequisites. @@ -647,7 +731,7 @@ class Solution: for nxt, pre in prerequisites: indegree[nxt] += 1 adj[pre].append(nxt) - + output = [] def dfs(node): @@ -657,11 +741,11 @@ class Solution: indegree[nei] -= 1 if indegree[nei] == 0: dfs(nei) - + for i in range(numCourses): if indegree[i] == 0: dfs(i) - + return output if len(output) == numCourses else [] ``` @@ -670,7 +754,7 @@ public class Solution { private List output = new ArrayList<>(); private int[] indegree; private List> adj; - + private void dfs(int node) { output.add(node); indegree[node]--; @@ -714,7 +798,7 @@ class Solution { vector output; vector indegree; vector> adj; - + void dfs(int node) { output.push_back(node); indegree[node]--; @@ -757,7 +841,7 @@ class Solution { findOrder(numCourses, prerequisites) { let adj = Array.from({ length: numCourses }, () => []); let indegree = Array(numCourses).fill(0); - + for (let [nxt, pre] of prerequisites) { indegree[nxt]++; adj[pre].push(nxt); @@ -898,11 +982,48 @@ class Solution { } ``` +```swift +class Solution { + func findOrder(_ numCourses: Int, _ prerequisites: [[Int]]) -> [Int] { + var adj = Array(repeating: [Int](), count: numCourses) + var indegree = Array(repeating: 0, count: numCourses) + + for pair in prerequisites { + let nxt = pair[0] + let pre = pair[1] + indegree[nxt] += 1 + adj[pre].append(nxt) + } + + var output = [Int]() + + func dfs(_ node: Int) { + output.append(node) + indegree[node] -= 1 + for nei in adj[node] { + indegree[nei] -= 1 + if indegree[nei] == 0 { + dfs(nei) + } + } + } + + for i in 0.. Where $V$ is the number of courses and $E$ is the number of prerequisites. \ No newline at end of file +> Where $V$ is the number of courses and $E$ is the number of prerequisites. diff --git a/articles/course-schedule-iv.md b/articles/course-schedule-iv.md index 0768d9038..19e758112 100644 --- a/articles/course-schedule-iv.md +++ b/articles/course-schedule-iv.md @@ -8,7 +8,7 @@ class Solution: adj = [[] for _ in range(numCourses)] for u, v in prerequisites: adj[u].append(v) - + def dfs(node, target): if node == target: return True @@ -52,7 +52,7 @@ public class Solution { ```cpp class Solution { vector> adj; - + public: vector checkIfPrerequisite(int numCourses, vector>& prerequisites, vector>& queries) { adj.assign(numCourses, vector()); @@ -109,12 +109,41 @@ class Solution { } ``` +```csharp +public class Solution { + public List CheckIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + List[] adj = new List[numCourses]; + for (int i = 0; i < numCourses; i++) { + adj[i] = new List(); + } + + foreach (var pre in prerequisites) { + adj[pre[0]].Add(pre[1]); + } + + bool Dfs(int node, int target) { + if (node == target) return true; + foreach (var nei in adj[node]) { + if (Dfs(nei, target)) return true; + } + return false; + } + + var res = new List(); + foreach (var q in queries) { + res.Add(Dfs(q[0], q[1])); + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O((V + E) * m)$ -* Space complexity: $O(V + E + m)$ +- Time complexity: $O((V + E) * m)$ +- Space complexity: $O(V + E + m)$ > Where $m$ is the number of queries, $V$ is the number of courses, and $E$ is the number of prerequisites. @@ -237,7 +266,6 @@ class Solution { adj[crs].push(pre); } - const dfs = (crs) => { if (prereqMap.has(crs)) { return prereqMap.get(crs); @@ -259,12 +287,52 @@ class Solution { } ``` +```csharp +public class Solution { + public List CheckIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + Dictionary> adj = new Dictionary>(); + for (int i = 0; i < numCourses; i++) { + adj[i] = new List(); + } + + foreach (var pair in prerequisites) { + int prereq = pair[0], crs = pair[1]; + adj[crs].Add(prereq); + } + + Dictionary> prereqMap = new Dictionary>(); + + HashSet Dfs(int crs) { + if (!prereqMap.ContainsKey(crs)) { + prereqMap[crs] = new HashSet(); + foreach (var prereq in adj[crs]) { + prereqMap[crs].UnionWith(Dfs(prereq)); + } + prereqMap[crs].Add(crs); + } + return prereqMap[crs]; + } + + for (int crs = 0; crs < numCourses; crs++) { + Dfs(crs); + } + + List res = new List(); + foreach (var q in queries) { + res.Add(prereqMap.ContainsKey(q[1]) && prereqMap[q[1]].Contains(q[0])); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V * (V + E) + m)$ -* Space complexity: $O(V ^ 2 + E + m)$ +- Time complexity: $O(V * (V + E) + m)$ +- Space complexity: $O(V ^ 2 + E + m)$ > Where $m$ is the number of queries, $V$ is the number of courses, and $E$ is the number of prerequisites. @@ -282,19 +350,19 @@ class Solution: for prereq, crs in prerequisites: adj[crs].append(prereq) isPrereq[crs][prereq] = True - + def dfs(crs, prereq): if isPrereq[crs][prereq] != -1: return isPrereq[crs][prereq] == 1 - + for pre in adj[crs]: if pre == prereq or dfs(pre, prereq): isPrereq[crs][prereq] = 1 return True - + isPrereq[crs][prereq] = 0 return False - + res = [] for u, v in queries: res.append(dfs(v, u)) @@ -313,7 +381,7 @@ public class Solution { adj[i] = new ArrayList<>(); Arrays.fill(isPrereq[i], -1); } - + for (int[] pre : prerequisites) { adj[pre[1]].add(pre[0]); isPrereq[pre[1]][pre[0]] = 1; @@ -391,7 +459,9 @@ class Solution { */ checkIfPrerequisite(numCourses, prerequisites, queries) { const adj = Array.from({ length: numCourses }, () => []); - const isPrereq = Array.from({ length: numCourses }, () => Array(numCourses).fill(-1)); + const isPrereq = Array.from({ length: numCourses }, () => + Array(numCourses).fill(-1), + ); for (const [prereq, crs] of prerequisites) { adj[crs].push(prereq); isPrereq[crs][prereq] = 1; @@ -416,12 +486,59 @@ class Solution { } ``` +```csharp +public class Solution { + public List CheckIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + List[] adj = new List[numCourses]; + for (int i = 0; i < numCourses; i++) { + adj[i] = new List(); + } + + int[,] isPrereq = new int[numCourses, numCourses]; + for (int i = 0; i < numCourses; i++) { + for (int j = 0; j < numCourses; j++) { + isPrereq[i, j] = -1; + } + } + + foreach (var pair in prerequisites) { + int prereq = pair[0], crs = pair[1]; + adj[crs].Add(prereq); + isPrereq[crs, prereq] = 1; + } + + bool Dfs(int crs, int prereq) { + if (isPrereq[crs, prereq] != -1) { + return isPrereq[crs, prereq] == 1; + } + + foreach (int pre in adj[crs]) { + if (pre == prereq || Dfs(pre, prereq)) { + isPrereq[crs, prereq] = 1; + return true; + } + } + + isPrereq[crs, prereq] = 0; + return false; + } + + List res = new List(); + foreach (var q in queries) { + res.Add(Dfs(q[1], q[0])); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V * (V + E) + m)$ -* Space complexity: $O(V ^ 2 + E + m)$ +- Time complexity: $O(V * (V + E) + m)$ +- Space complexity: $O(V ^ 2 + E + m)$ > Where $m$ is the number of queries, $V$ is the number of courses, and $E$ is the number of prerequisites. @@ -437,13 +554,13 @@ class Solution: adj = [set() for _ in range(numCourses)] indegree = [0] * numCourses isPrereq = [set() for _ in range(numCourses)] - + for pre, crs in prerequisites: adj[pre].add(crs) indegree[crs] += 1 - + q = deque([i for i in range(numCourses) if indegree[i] == 0]) - + while q: node = q.popleft() for neighbor in adj[node]: @@ -452,7 +569,7 @@ class Solution: indegree[neighbor] -= 1 if indegree[neighbor] == 0: q.append(neighbor) - + return [u in isPrereq[v] for u, v in queries] ``` @@ -572,12 +689,62 @@ class Solution { } ``` +```csharp +public class Solution { + public List CheckIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + List> adj = new List>(); + List> isPrereq = new List>(); + int[] indegree = new int[numCourses]; + + for (int i = 0; i < numCourses; i++) { + adj.Add(new HashSet()); + isPrereq.Add(new HashSet()); + } + + foreach (var pair in prerequisites) { + int pre = pair[0], crs = pair[1]; + adj[pre].Add(crs); + indegree[crs]++; + } + + Queue q = new Queue(); + for (int i = 0; i < numCourses; i++) { + if (indegree[i] == 0) { + q.Enqueue(i); + } + } + + while (q.Count > 0) { + int node = q.Dequeue(); + foreach (int neighbor in adj[node]) { + isPrereq[neighbor].Add(node); + foreach (int p in isPrereq[node]) { + isPrereq[neighbor].Add(p); + } + indegree[neighbor]--; + if (indegree[neighbor] == 0) { + q.Enqueue(neighbor); + } + } + } + + List result = new List(); + foreach (var query in queries) { + int u = query[0], v = query[1]; + result.Add(isPrereq[v].Contains(u)); + } + + return result; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V * (V + E) + m)$ -* Space complexity: $O(V ^ 2 + E + m)$ +- Time complexity: $O(V * (V + E) + m)$ +- Space complexity: $O(V ^ 2 + E + m)$ > Where $m$ is the number of queries, $V$ is the number of courses, and $E$ is the number of prerequisites. @@ -592,18 +759,18 @@ class Solution: def checkIfPrerequisite(self, numCourses: int, prerequisites: List[List[int]], queries: List[List[int]]) -> List[bool]: res = [] adj = [[False] * numCourses for _ in range(numCourses)] - + for pre, crs in prerequisites: adj[pre][crs] = True - + for k in range(numCourses): for i in range(numCourses): for j in range(numCourses): adj[i][j] = adj[i][j] or (adj[i][k] and adj[k][j]) - + for u, v in queries: res.append(adj[u][v]) - + return res ``` @@ -612,11 +779,11 @@ public class Solution { public List checkIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { boolean[][] adj = new boolean[numCourses][numCourses]; List res = new ArrayList<>(); - + for (int[] pre : prerequisites) { adj[pre[0]][pre[1]] = true; } - + for (int k = 0; k < numCourses; k++) { for (int i = 0; i < numCourses; i++) { for (int j = 0; j < numCourses; j++) { @@ -624,11 +791,11 @@ public class Solution { } } } - + for (int[] q : queries) { res.add(adj[q[0]][q[1]]); } - + return res; } } @@ -640,11 +807,11 @@ public: vector checkIfPrerequisite(int numCourses, vector>& prerequisites, vector>& queries) { vector> adj(numCourses, vector(numCourses, false)); vector res; - + for (auto& pre : prerequisites) { adj[pre[0]][pre[1]] = true; } - + for (int k = 0; k < numCourses; k++) { for (int i = 0; i < numCourses; i++) { for (int j = 0; j < numCourses; j++) { @@ -652,11 +819,11 @@ public: } } } - + for (auto& q : queries) { res.push_back(adj[q[0]][q[1]]); } - + return res; } }; @@ -671,13 +838,15 @@ class Solution { * @return {boolean[]} */ checkIfPrerequisite(numCourses, prerequisites, queries) { - let adj = Array.from({ length: numCourses }, () => Array(numCourses).fill(false)); + let adj = Array.from({ length: numCourses }, () => + Array(numCourses).fill(false), + ); let res = []; - + for (let [pre, crs] of prerequisites) { adj[pre][crs] = true; } - + for (let k = 0; k < numCourses; k++) { for (let i = 0; i < numCourses; i++) { for (let j = 0; j < numCourses; j++) { @@ -685,11 +854,40 @@ class Solution { } } } - + for (let [u, v] of queries) { res.push(adj[u][v]); } - + + return res; + } +} +``` + +```csharp +public class Solution { + public List CheckIfPrerequisite(int numCourses, int[][] prerequisites, int[][] queries) { + bool[,] adj = new bool[numCourses, numCourses]; + + foreach (var pair in prerequisites) { + int pre = pair[0], crs = pair[1]; + adj[pre, crs] = true; + } + + for (int k = 0; k < numCourses; k++) { + for (int i = 0; i < numCourses; i++) { + for (int j = 0; j < numCourses; j++) { + adj[i, j] = adj[i, j] || (adj[i, k] && adj[k, j]); + } + } + } + + List res = new List(); + foreach (var query in queries) { + int u = query[0], v = query[1]; + res.Add(adj[u, v]); + } + return res; } } @@ -699,7 +897,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(V ^ 3 + E + m)$ -* Space complexity: $O(V ^ 2 + E + m)$ +- Time complexity: $O(V ^ 3 + E + m)$ +- Space complexity: $O(V ^ 2 + E + m)$ -> Where $m$ is the number of queries, $V$ is the number of courses, and $E$ is the number of prerequisites. \ No newline at end of file +> Where $m$ is the number of queries, $V$ is the number of courses, and $E$ is the number of prerequisites. diff --git a/articles/course-schedule.md b/articles/course-schedule.md index b499babdf..2138d1628 100644 --- a/articles/course-schedule.md +++ b/articles/course-schedule.md @@ -160,9 +160,9 @@ class Solution { } } visiting.delete(crs); - preMap.set(crs, []); + preMap.set(crs, []); return true; - } + }; for (let c = 0; c < numCourses; c++) { if (!dfs(c)) { @@ -310,12 +310,57 @@ class Solution { } ``` +```swift +class Solution { + func canFinish(_ numCourses: Int, _ prerequisites: [[Int]]) -> Bool { + // Map each course to its prerequisites + var preMap = [Int: [Int]]() + for i in 0..() + + func dfs(_ crs: Int) -> Bool { + if visiting.contains(crs) { + // Cycle detected + return false + } + if preMap[crs]!.isEmpty { + return true + } + + visiting.insert(crs) + for pre in preMap[crs]! { + if !dfs(pre) { + return false + } + } + visiting.remove(crs) + preMap[crs] = [] + return true + } + + for c in 0.. Where $V$ is the number of courses and $E$ is the number of prerequisites. @@ -338,7 +383,7 @@ class Solution: for n in range(numCourses): if indegree[n] == 0: q.append(n) - + finish = 0 while q: node = q.popleft() @@ -347,7 +392,7 @@ class Solution: indegree[nei] -= 1 if indegree[nei] == 0: q.append(nei) - + return finish == numCourses ``` @@ -394,7 +439,7 @@ public: bool canFinish(int numCourses, vector>& prerequisites) { vector indegree(numCourses, 0); vector> adj(numCourses); - + for (auto& pre : prerequisites) { indegree[pre[1]]++; adj[pre[0]].push_back(pre[1]); @@ -544,7 +589,7 @@ class Solution { fun canFinish(numCourses: Int, prerequisites: Array): Boolean { val indegree = IntArray(numCourses) { 0 } val adj = Array(numCourses) { mutableListOf() } - + for (prereq in prerequisites) { val (src, dst) = prereq indegree[dst]++ @@ -575,11 +620,48 @@ class Solution { } ``` +```swift +class Solution { + func canFinish(_ numCourses: Int, _ prerequisites: [[Int]]) -> Bool { + var indegree = Array(repeating: 0, count: numCourses) + var adj = Array(repeating: [Int](), count: numCourses) + + for pair in prerequisites { + let src = pair[0] + let dst = pair[1] + indegree[dst] += 1 + adj[src].append(dst) + } + + var queue = Deque() + for n in 0.. Where $V$ is the number of courses and $E$ is the number of prerequisites. \ No newline at end of file +> Where $V$ is the number of courses and $E$ is the number of prerequisites. diff --git a/articles/crawler-log-folder.md b/articles/crawler-log-folder.md new file mode 100644 index 000000000..383bab91e --- /dev/null +++ b/articles/crawler-log-folder.md @@ -0,0 +1,208 @@ +## 1. Stack + +::tabs-start + +```python +class Solution: + def minOperations(self, logs: List[str]) -> int: + stack = [] + for log in logs: + if log == "../": + if stack: + stack.pop() + elif log != "./": + stack.append(log) + return len(stack) +``` + +```java +public class Solution { + public int minOperations(String[] logs) { + Stack stack = new Stack<>(); + for (String log : logs) { + if (log.equals("../")) { + if (!stack.isEmpty()) { + stack.pop(); + } + } else if (!log.equals("./")) { + stack.push(log); + } + } + return stack.size(); + } +} +``` + +```cpp +class Solution { +public: + int minOperations(vector& logs) { + stack st; + for (auto& log : logs) { + if (log == "../") { + if (!st.empty()) { + st.pop(); + } + } else if (log != "./") { + st.push(log); + } + } + return st.size(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} logs + * @return {number} + */ + minOperations(logs) { + let stack = []; + for (let log of logs) { + if (log === "../") { + if (stack.length > 0) { + stack.pop(); + } + } else if (log !== "./") { + stack.push(log); + } + } + return stack.length; + } +} +``` + +```csharp +public class Solution { + public int MinOperations(string[] logs) { + Stack stack = new Stack(); + foreach (string log in logs) { + if (log == "../") { + if (stack.Count > 0) { + stack.Pop(); + } + } else if (log != "./") { + stack.Push(log); + } + } + return stack.Count; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Iteration + +::tabs-start + +```python +class Solution: + def minOperations(self, logs: List[str]) -> int: + res = 0 + for log in logs: + if log == "./": + continue + if log == "../": + res = max(0, res - 1) + else: + res += 1 + return res +``` + +```java +public class Solution { + public int minOperations(String[] logs) { + int res = 0; + for (String log : logs) { + if (log.equals("./")) { + continue; + } + if (log.equals("../")) { + res = Math.max(0, res - 1); + } else { + res++; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minOperations(vector& logs) { + int res = 0; + for (auto& log : logs) { + if (log == "./") { + continue; + } + if (log == "../") { + res = max(0, res - 1); + } else { + res++; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} logs + * @return {number} + */ + minOperations(logs) { + let res = 0; + for (let log of logs) { + if (log === "./") { + continue; + } + if (log === "../") { + res = Math.max(0, res - 1); + } else { + res++; + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public int MinOperations(string[] logs) { + int res = 0; + foreach (string log in logs) { + if (log == "./") { + continue; + } + if (log == "../") { + res = Math.Max(0, res - 1); + } else { + res++; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/custom-sort-string.md b/articles/custom-sort-string.md new file mode 100644 index 000000000..2a6df0b0d --- /dev/null +++ b/articles/custom-sort-string.md @@ -0,0 +1,263 @@ +## 1. Custom Comparator + +::tabs-start + +```python +class Solution: + def customSortString(self, order: str, s: str) -> str: + rank = {c: i for i, c in enumerate(order)} + return ''.join(sorted(s, key=lambda c: rank.get(c, 26))) +``` + +```java +public class Solution { + public String customSortString(String order, String s) { + int[] rank = new int[26]; + for (int i = 0; i < order.length(); i++) { + rank[order.charAt(i) - 'a'] = i + 1; + } + + Character[] arr = new Character[s.length()]; + for (int i = 0; i < s.length(); i++) { + arr[i] = s.charAt(i); + } + + Arrays.sort(arr, (a, b) -> rank[a - 'a'] - rank[b - 'a']); + + StringBuilder sb = new StringBuilder(); + for (char c : arr) { + sb.append(c); + } + return sb.toString(); + } +} +``` + +```cpp +class Solution { +public: + string customSortString(string order, string s) { + vector rank(26, 26); + for (int i = 0; i < order.size(); ++i) { + rank[order[i] - 'a'] = i; + } + + sort(s.begin(), s.end(), [&](char a, char b) { + return rank[a - 'a'] < rank[b - 'a']; + }); + + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} order + * @param {string} s + * @return {string} + */ + customSortString(order, s) { + const rank = {}; + for (let i = 0; i < order.length; i++) { + rank[order[i]] = i; + } + + return [...s].sort((a, b) => { + const ra = rank[a] ?? 26; + const rb = rank[b] ?? 26; + return ra - rb; + }).join(''); + } +} +``` + +```csharp +public class Solution { + public string CustomSortString(string order, string s) { + Dictionary rank = new Dictionary(); + for (int i = 0; i < order.Length; i++) { + rank[order[i]] = i; + } + + char[] arr = s.ToCharArray(); + Array.Sort(arr, (a, b) => { + int ra = rank.ContainsKey(a) ? rank[a] : 26; + int rb = rank.ContainsKey(b) ? rank[b] : 26; + return ra - rb; + }); + + return new string(arr); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 2. Frequency Count + +::tabs-start + +```python +class Solution: + def customSortString(self, order: str, s: str) -> str: + count = [0] * 26 + for c in s: + count[ord(c) - ord('a')] += 1 + + res = [] + for c in order: + idx = ord(c) - ord('a') + while count[idx]: + res.append(c) + count[idx] -= 1 + + for idx in range(26): + c = chr(ord('a') + idx) + while count[idx]: + count[idx] -= 1 + res.append(c) + + return ''.join(res) +``` + +```java +public class Solution { + public String customSortString(String order, String s) { + int[] count = new int[26]; + for (char c : s.toCharArray()) { + count[c - 'a']++; + } + + StringBuilder res = new StringBuilder(); + for (char c : order.toCharArray()) { + int idx = c - 'a'; + while (count[idx] > 0) { + res.append(c); + count[idx]--; + } + } + + for (int idx = 0; idx < 26; idx++) { + char c = (char) ('a' + idx); + while (count[idx] > 0) { + res.append(c); + count[idx]--; + } + } + + return res.toString(); + } +} +``` + +```cpp +class Solution { +public: + string customSortString(string order, string s) { + vector count(26, 0); + for (char c : s) { + count[c - 'a']++; + } + + string res; + for (char c : order) { + int idx = c - 'a'; + while (count[idx] > 0) { + res += c; + count[idx]--; + } + } + + for (int idx = 0; idx < 26; ++idx) { + char c = 'a' + idx; + while (count[idx] > 0) { + res += c; + count[idx]--; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} order + * @param {string} s + * @return {string} + */ + customSortString(order, s) { + const count = new Array(26).fill(0); + for (let c of s) { + count[c.charCodeAt(0) - 97]++; + } + + const res = []; + for (let c of order) { + let idx = c.charCodeAt(0) - 97; + while (count[idx] > 0) { + res.push(c); + count[idx]--; + } + } + + for (let idx = 0; idx < 26; idx++) { + let c = String.fromCharCode(97 + idx); + while (count[idx] > 0) { + res.push(c); + count[idx]--; + } + } + + return res.join(''); + } +} +``` + +```csharp +public class Solution { + public string CustomSortString(string order, string s) { + int[] count = new int[26]; + foreach (char c in s) { + count[c - 'a']++; + } + + StringBuilder res = new StringBuilder(); + foreach (char c in order) { + int idx = c - 'a'; + while (count[idx] > 0) { + res.Append(c); + count[idx]--; + } + } + + for (int idx = 0; idx < 26; idx++) { + char c = (char)('a' + idx); + while (count[idx] > 0) { + res.Append(c); + count[idx]--; + } + } + + return res.ToString(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/daily-temperatures.md b/articles/daily-temperatures.md index 786847104..2c100dab5 100644 --- a/articles/daily-temperatures.md +++ b/articles/daily-temperatures.md @@ -90,7 +90,7 @@ class Solution { j++; count++; } - count = (j === n) ? 0 : count; + count = j === n ? 0 : count; res[i] = count; } return res; @@ -126,11 +126,11 @@ public class Solution { func dailyTemperatures(temperatures []int) []int { n := len(temperatures) res := make([]int, 0) - + for i := 0; i < n; i++ { count := 1 j := i + 1 - + for j < n { if temperatures[j] > temperatures[i] { break @@ -138,14 +138,14 @@ func dailyTemperatures(temperatures []int) []int { j++ count++ } - + if j == n { count = 0 } - + res = append(res, count) } - + return res } ``` @@ -155,11 +155,11 @@ class Solution { fun dailyTemperatures(temperatures: IntArray): IntArray { val n = temperatures.size val res = mutableListOf() - + for (i in 0 until n) { var count = 1 var j = i + 1 - + while (j < n) { if (temperatures[j] > temperatures[i]) { break @@ -167,22 +167,48 @@ class Solution { j++ count++ } - + count = if (j == n) 0 else count res.add(count) } - + return res.toIntArray() } } ``` +```swift +class Solution { + func dailyTemperatures(_ temperatures: [Int]) -> [Int] { + let n = temperatures.count + var res = [Int]() + + for i in 0.. temperatures[i] { + break + } + j += 1 + count += 1 + } + count = (j == n) ? 0 : count + res.append(count) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output array. --- @@ -308,7 +334,7 @@ func dailyTemperatures(temperatures []int) []int { class Solution { fun dailyTemperatures(temperatures: IntArray): IntArray { val res = IntArray(temperatures.size) { 0 } - val stack = mutableListOf() + val stack = mutableListOf() for (i in temperatures.indices) { while (stack.isNotEmpty() && temperatures[i] > temperatures[stack.last()]) { @@ -323,12 +349,30 @@ class Solution { } ``` +```swift +class Solution { + func dailyTemperatures(_ temperatures: [Int]) -> [Int] { + var res = [Int](repeating: 0, count: temperatures.count) + var stack = [(Int, Int)]() // Pair: (temperature, index) + + for (i, t) in temperatures.enumerated() { + while !stack.isEmpty && t > stack.last!.0 { + let (stackT, stackInd) = stack.removeLast() + res[stackInd] = i - stackInd + } + stack.append((t, i)) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -349,7 +393,7 @@ class Solution: j = n break j += res[j] - + if j < n: res[i] = j - i return res @@ -474,7 +518,7 @@ func dailyTemperatures(temperatures []int) []int { } j += res[j] } - + if j < n { res[i] = j - i } @@ -498,7 +542,7 @@ class Solution { } j += res[j] } - + if (j < n) { res[i] = j - i } @@ -508,9 +552,36 @@ class Solution { } ``` +```swift +class Solution { + func dailyTemperatures(_ temperatures: [Int]) -> [Int] { + let n = temperatures.count + var res = [Int](repeating: 0, count: n) + + for i in stride(from: n - 2, through: 0, by: -1) { + var j = i + 1 + while j < n && temperatures[j] <= temperatures[i] { + if res[j] == 0 { + j = n + break + } + j += res[j] + } + + if j < n { + res[i] = j - i + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output array. diff --git a/articles/data-stream-as-disjoint-intervals.md b/articles/data-stream-as-disjoint-intervals.md new file mode 100644 index 000000000..c0aa4b934 --- /dev/null +++ b/articles/data-stream-as-disjoint-intervals.md @@ -0,0 +1,450 @@ +## 1. Brute Force (Sorting) + +::tabs-start + +```python +class SummaryRanges: + + def __init__(self): + self.arr = [] + + def addNum(self, value: int) -> None: + self.arr.append(value) + + def getIntervals(self) -> List[List[int]]: + if not self.arr: + return [] + + self.arr.sort() + n = len(self.arr) + start = self.arr[0] + res = [] + for i in range(1, n): + if self.arr[i] - self.arr[i - 1] > 1: + res.append([start, self.arr[i - 1]]) + start = self.arr[i] + + res.append([start, self.arr[n - 1]]) + return res +``` + +```java +public class SummaryRanges { + private List arr; + + public SummaryRanges() { + arr = new ArrayList<>(); + } + + public void addNum(int value) { + arr.add(value); + } + + public List getIntervals() { + List res = new ArrayList<>(); + if (arr.isEmpty()) return res; + + Collections.sort(arr); + int start = arr.get(0); + for (int i = 1; i < arr.size(); i++) { + if (arr.get(i) - arr.get(i - 1) > 1) { + res.add(new int[]{start, arr.get(i - 1)}); + start = arr.get(i); + } + } + res.add(new int[]{start, arr.get(arr.size() - 1)}); + return res; + } +} +``` + +```cpp +class SummaryRanges { +private: + vector arr; + +public: + SummaryRanges() {} + + void addNum(int value) { + arr.push_back(value); + } + + vector> getIntervals() { + vector> res; + if (arr.empty()) return res; + + sort(arr.begin(), arr.end()); + int start = arr[0]; + for (int i = 1; i < arr.size(); i++) { + if (arr[i] - arr[i - 1] > 1) { + res.push_back({start, arr[i - 1]}); + start = arr[i]; + } + } + res.push_back({start, arr.back()}); + return res; + } +}; +``` + +```javascript +class SummaryRanges { + constructor() { + this.arr = []; + } + + /** + * @param {number} value + * @return {void} + */ + addNum(value) { + this.arr.push(value); + } + + /** + * @return {number[][]} + */ + getIntervals() { + if (this.arr.length === 0) return []; + + this.arr.sort((a, b) => a - b); + let start = this.arr[0]; + let res = []; + + for (let i = 1; i < this.arr.length; i++) { + if (this.arr[i] - this.arr[i - 1] > 1) { + res.push([start, this.arr[i - 1]]); + start = this.arr[i]; + } + } + res.push([start, this.arr[this.arr.length - 1]]); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $addNum()$ function call. + - $O(n \log n)$ time for each $getIntervals()$ function call. +- Space complexity: $O(n)$ + +--- + +## 2. Hash Set + Sorting + +::tabs-start + +```python +class SummaryRanges: + + def __init__(self): + self.arr = set() + + def addNum(self, value: int) -> None: + self.arr.add(value) + + def getIntervals(self) -> List[List[int]]: + if not self.arr: + return [] + + lst = sorted(list(self.arr)) + n = len(lst) + start = lst[0] + res = [] + for i in range(1, n): + if lst[i] - lst[i - 1] > 1: + res.append([start, lst[i - 1]]) + start = lst[i] + + res.append([start, lst[n - 1]]) + return res +``` + +```java +public class SummaryRanges { + private Set arr; + + public SummaryRanges() { + arr = new TreeSet<>(); + } + + public void addNum(int value) { + arr.add(value); + } + + public List getIntervals() { + List res = new ArrayList<>(); + if (arr.isEmpty()) return res; + + List lst = new ArrayList<>(arr); + int start = lst.get(0); + for (int i = 1; i < lst.size(); i++) { + if (lst.get(i) - lst.get(i - 1) > 1) { + res.add(new int[]{start, lst.get(i - 1)}); + start = lst.get(i); + } + } + res.add(new int[]{start, lst.get(lst.size() - 1)}); + return res; + } +} +``` + +```cpp +class SummaryRanges { +private: + set arr; + +public: + SummaryRanges() {} + + void addNum(int value) { + arr.insert(value); + } + + vector> getIntervals() { + vector> res; + if (arr.empty()) return res; + + vector lst(arr.begin(), arr.end()); + int start = lst[0]; + + for (int i = 1; i < lst.size(); i++) { + if (lst[i] - lst[i - 1] > 1) { + res.push_back({start, lst[i - 1]}); + start = lst[i]; + } + } + res.push_back({start, lst.back()}); + return res; + } +}; +``` + +```javascript +class SummaryRanges { + constructor() { + this.arr = new Set(); + } + + /** + * @param {number} value + * @return {number[][]} + */ + addNum(value) { + this.arr.add(value); + } + + /** + * @return {number[][]} + */ + getIntervals() { + if (this.arr.size === 0) return []; + + let lst = Array.from(this.arr).sort((a, b) => a - b); + let start = lst[0]; + let res = []; + + for (let i = 1; i < lst.length; i++) { + if (lst[i] - lst[i - 1] > 1) { + res.push([start, lst[i - 1]]); + start = lst[i]; + } + } + res.push([start, lst[lst.length - 1]]); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $addNum()$ function call. + - $O(n \log n)$ time for each $getIntervals()$ function call. +- Space complexity: $O(n)$ + +--- + +## 3. Ordered Map + +::tabs-start + +```python +from sortedcontainers import SortedDict + +class SummaryRanges: + def __init__(self): + self.treeMap = SortedDict() + + def addNum(self, value: int) -> None: + self.treeMap[value] = True + + def getIntervals(self) -> List[List[int]]: + res = [] + for n in self.treeMap: + if res and res[-1][1] + 1 == n: + res[-1][1] = n + else: + res.append([n, n]) + return res +``` + +```java +public class SummaryRanges { + private TreeMap treeMap; + + public SummaryRanges() { + treeMap = new TreeMap<>(); + } + + public void addNum(int value) { + treeMap.put(value, true); + } + + public List getIntervals() { + List res = new ArrayList<>(); + for (int n : treeMap.keySet()) { + if (!res.isEmpty() && res.get(res.size() - 1)[1] + 1 == n) { + res.get(res.size() - 1)[1] = n; + } else { + res.add(new int[]{n, n}); + } + } + return res; + } +} +``` + +```cpp +class SummaryRanges { +private: + map treeMap; + +public: + SummaryRanges() {} + + void addNum(int value) { + treeMap[value] = true; + } + + vector> getIntervals() { + vector> res; + for (auto& [n, _] : treeMap) { + if (!res.empty() && res.back()[1] + 1 == n) { + res.back()[1] = n; + } else { + res.push_back({n, n}); + } + } + return res; + } +}; +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(\log n)$ time for each $addNum()$ function call. + - $O(n)$ time for each $getIntervals()$ function call. +- Space complexity: $O(n)$ + +--- + +## 4. Ordered Set + +::tabs-start + +```python +from sortedcontainers import SortedSet + +class SummaryRanges: + def __init__(self): + self.orderedSet = SortedSet() + + def addNum(self, value: int) -> None: + self.orderedSet.add(value) + + def getIntervals(self) -> List[List[int]]: + res = [] + for n in self.orderedSet: + if res and res[-1][1] + 1 == n: + res[-1][1] = n + else: + res.append([n, n]) + return res +``` + +```java +public class SummaryRanges { + private TreeSet orderedSet; + + public SummaryRanges() { + orderedSet = new TreeSet<>(); + } + + public void addNum(int value) { + orderedSet.add(value); + } + + public List getIntervals() { + List res = new ArrayList<>(); + for (int n : orderedSet) { + if (!res.isEmpty() && res.get(res.size() - 1)[1] + 1 == n) { + res.get(res.size() - 1)[1] = n; + } else { + res.add(new int[]{n, n}); + } + } + return res; + } +} +``` + +```cpp +class SummaryRanges { +private: + set orderedSet; + +public: + SummaryRanges() {} + + void addNum(int value) { + orderedSet.insert(value); + } + + vector> getIntervals() { + vector> res; + for (int n : orderedSet) { + if (!res.empty() && res.back()[1] + 1 == n) { + res.back()[1] = n; + } else { + res.push_back({n, n}); + } + } + return res; + } +}; +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(\log n)$ time for each $addNum()$ function call. + - $O(n)$ time for each $getIntervals()$ function call. +- Space complexity: $O(n)$ diff --git a/articles/decode-string.md b/articles/decode-string.md index c5363f71b..43b20f525 100644 --- a/articles/decode-string.md +++ b/articles/decode-string.md @@ -6,14 +6,14 @@ class Solution: def decodeString(self, s: str) -> str: self.i = 0 - + def helper(): res = "" k = 0 - + while self.i < len(s): c = s[self.i] - + if c.isdigit(): k = k * 10 + int(c) elif c == "[": @@ -24,28 +24,28 @@ class Solution: return res else: res += c - + self.i += 1 return res - + return helper() ``` ```java public class Solution { private int i = 0; - + public String decodeString(String s) { return helper(s); } - + private String helper(String s) { StringBuilder res = new StringBuilder(); int k = 0; - + while (i < s.length()) { char c = s.charAt(i); - + if (Character.isDigit(c)) { k = k * 10 + (c - '0'); } else if (c == '[') { @@ -58,10 +58,10 @@ public class Solution { } else { res.append(c); } - + i++; } - + return res.toString(); } } @@ -114,7 +114,7 @@ class Solution { let i = 0; const helper = () => { - let res = ""; + let res = ''; let k = 0; while (i < s.length) { @@ -122,11 +122,11 @@ class Solution { if (!isNaN(c)) { k = k * 10 + parseInt(c, 10); - } else if (c === "[") { + } else if (c === '[') { i++; res += helper().repeat(k); k = 0; - } else if (c === "]") { + } else if (c === ']') { return res; } else { res += c; @@ -143,12 +143,52 @@ class Solution { } ``` +```csharp +public class Solution { + private int i; + + public string DecodeString(string s) { + i = 0; + return Helper(s); + } + + private string Helper(string s) { + string res = ""; + int k = 0; + + while (i < s.Length) { + char c = s[i]; + + if (char.IsDigit(c)) { + k = k * 10 + (c - '0'); + } else if (c == '[') { + i++; + string inner = Helper(s); + res += new string(' ', 0).PadLeft(0); + for (int j = 0; j < k; j++) { + res += inner; + } + k = 0; + } else if (c == ']') { + return res; + } else { + res += c; + } + + i++; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n + N)$ -* Space complexity: $O(n + N)$ +- Time complexity: $O(n + N)$ +- Space complexity: $O(n + N)$ > Where $n$ is the length of the input string and $N$ is the length of the output string. @@ -268,16 +308,16 @@ class Solution { for (let i = 0; i < s.length; i++) { const char = s[i]; - if (char !== "]") { + if (char !== ']') { stack.push(char); } else { - let substr = ""; - while (stack[stack.length - 1] !== "[") { + let substr = ''; + while (stack[stack.length - 1] !== '[') { substr = stack.pop() + substr; } stack.pop(); - let k = ""; + let k = ''; while (stack.length > 0 && !isNaN(stack[stack.length - 1])) { k = stack.pop() + k; } @@ -285,7 +325,42 @@ class Solution { } } - return stack.join(""); + return stack.join(''); + } +} +``` + +```csharp +public class Solution { + public string DecodeString(string s) { + Stack stack = new Stack(); + + for (int i = 0; i < s.Length; i++) { + if (s[i] != ']') { + stack.Push(s[i].ToString()); + } else { + string substr = ""; + while (stack.Peek() != "[") { + substr = stack.Pop() + substr; + } + stack.Pop(); // remove '[' + + string k = ""; + while (stack.Count > 0 && char.IsDigit(stack.Peek()[0])) { + k = stack.Pop() + k; + } + + int repeat = int.Parse(k); + string expanded = new StringBuilder().Insert(0, substr, repeat).ToString(); + stack.Push(expanded); + } + } + + var result = new StringBuilder(); + foreach (string part in stack) { + result.Insert(0, part); + } + return result.ToString(); } } ``` @@ -294,8 +369,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + N ^ 2)$ -* Space complexity: $O(n + N)$ +- Time complexity: $O(n + N ^ 2)$ +- Space complexity: $O(n + N)$ > Where $n$ is the length of the input string and $N$ is the length of the output string. @@ -410,18 +485,18 @@ class Solution { decodeString(s) { const stringStack = []; const countStack = []; - let cur = ""; + let cur = ''; let k = 0; for (const c of s) { if (!isNaN(c)) { k = k * 10 + parseInt(c, 10); - } else if (c === "[") { + } else if (c === '[') { stringStack.push(cur); countStack.push(k); - cur = ""; + cur = ''; k = 0; - } else if (c === "]") { + } else if (c === ']') { const temp = cur; cur = stringStack.pop(); const count = countStack.pop(); @@ -436,11 +511,44 @@ class Solution { } ``` +```csharp +public class Solution { + public string DecodeString(string s) { + Stack stringStack = new Stack(); + Stack countStack = new Stack(); + string cur = ""; + int k = 0; + + foreach (char c in s) { + if (char.IsDigit(c)) { + k = k * 10 + (c - '0'); + } else if (c == '[') { + stringStack.Push(cur); + countStack.Push(k); + cur = ""; + k = 0; + } else if (c == ']') { + string temp = cur; + cur = stringStack.Pop(); + int count = countStack.Pop(); + for (int i = 0; i < count; i++) { + cur += temp; + } + } else { + cur += c; + } + } + + return cur; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n + N)$ -* Space complexity: $O(n + N)$ +- Time complexity: $O(n + N)$ +- Space complexity: $O(n + N)$ -> Where $n$ is the length of the input string and $N$ is the length of the output string. \ No newline at end of file +> Where $n$ is the length of the input string and $N$ is the length of the output string. diff --git a/articles/decode-ways.md b/articles/decode-ways.md index bfda19321..7d227fcd0 100644 --- a/articles/decode-ways.md +++ b/articles/decode-ways.md @@ -5,7 +5,7 @@ ```python class Solution: def numDecodings(self, s: str) -> int: - + def dfs(i): if i == len(s): return 1 @@ -14,7 +14,7 @@ class Solution: res = dfs(i + 1) if i < len(s) - 1: - if (s[i] == '1' or + if (s[i] == '1' or (s[i] == '2' and s[i + 1] < '7')): res += dfs(i + 2) @@ -31,7 +31,7 @@ public class Solution { int res = dfs(i + 1, s); if (i < s.length() - 1) { - if (s.charAt(i) == '1' || + if (s.charAt(i) == '1' || (s.charAt(i) == '2' && s.charAt(i + 1) < '7')) { res += dfs(i + 2, s); } @@ -51,10 +51,10 @@ public: int dfs(int i, string& s) { if (i == s.size()) return 1; if (s[i] == '0') return 0; - + int res = dfs(i + 1, s); if (i < s.size() - 1) { - if (s[i] == '1' || + if (s[i] == '1' || (s[i] == '2' && s[i + 1] < '7')) { res += dfs(i + 2, s); } @@ -75,15 +75,13 @@ class Solution { * @return {number} */ numDecodings(s) { - const dfs = (i) => { if (i === s.length) return 1; if (s[i] === '0') return 0; let res = dfs(i + 1); if (i < s.length - 1) { - if (s[i] === '1' || - (s[i] === '2' && s[i + 1] < '7')) { + if (s[i] === '1' || (s[i] === '2' && s[i + 1] < '7')) { res += dfs(i + 2); } } @@ -104,7 +102,7 @@ public class Solution { int res = Dfs(i + 1); if (i < s.Length - 1) { - if (s[i] == '1' || + if (s[i] == '1' || (s[i] == '2' && s[i + 1] < '7')) { res += Dfs(i + 2); } @@ -163,12 +161,40 @@ class Solution { } ``` +```swift +class Solution { + func numDecodings(_ s: String) -> Int { + let chars = Array(s) + + func dfs(_ i: Int) -> Int { + if i == chars.count { + return 1 + } + if chars[i] == "0" { + return 0 + } + + var res = dfs(i + 1) + if i < chars.count - 1 { + if chars[i] == "1" || (chars[i] == "2" && chars[i + 1] < "7") { + res += dfs(i + 2) + } + } + + return res + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -201,7 +227,7 @@ class Solution: ```java public class Solution { - + public int numDecodings(String s) { Map dp = new HashMap<>(); dp.put(s.length(), 1); @@ -218,7 +244,7 @@ public class Solution { } int res = dfs(s, i + 1, dp); - if (i + 1 < s.length() && (s.charAt(i) == '1' || + if (i + 1 < s.length() && (s.charAt(i) == '1' || s.charAt(i) == '2' && s.charAt(i + 1) < '7')) { res += dfs(s, i + 2, dp); } @@ -247,7 +273,7 @@ private: } int res = dfs(s, i + 1, dp); - if (i + 1 < s.size() && (s[i] == '1' || + if (i + 1 < s.size() && (s[i] == '1' || s[i] == '2' && s[i + 1] < '7')) { res += dfs(s, i + 2, dp); } @@ -285,8 +311,11 @@ class Solution { } let res = this.dfs(s, i + 1, dp); - if (i + 1 < s.length && (s.charAt(i) === '1' || - (s.charAt(i) === '2' && s.charAt(i + 1) < '7'))) { + if ( + i + 1 < s.length && + (s.charAt(i) === '1' || + (s.charAt(i) === '2' && s.charAt(i + 1) < '7')) + ) { res += this.dfs(s, i + 2, dp); } dp.set(i, res); @@ -313,7 +342,7 @@ public class Solution { } int res = Dfs(s, i + 1, dp); - if (i + 1 < s.Length && (s[i] == '1' || + if (i + 1 < s.Length && (s[i] == '1' || s[i] == '2' && s[i + 1] < '7')) { res += Dfs(s, i + 2, dp); } @@ -339,7 +368,7 @@ func dfs(s string, i int, dp map[int]int) int { return 0 } res := dfs(s, i+1, dp) - if i+1 < len(s) && (s[i] == '1' || + if i+1 < len(s) && (s[i] == '1' || (s[i] == '2' && s[i+1] <= '6')) { res += dfs(s, i+2, dp) } @@ -365,7 +394,7 @@ class Solution { return 0 } var res = dfs(s, i + 1, dp) - if (i + 1 < s.length && (s[i] == '1' || + if (i + 1 < s.length && (s[i] == '1' || (s[i] == '2' && s[i + 1] <= '6'))) { res += dfs(s, i + 2, dp) } @@ -375,12 +404,41 @@ class Solution { } ``` +```swift +class Solution { + func numDecodings(_ s: String) -> Int { + let chars = Array(s) + var dp = [Int: Int]() + dp[chars.count] = 1 + + func dfs(_ i: Int) -> Int { + if let cached = dp[i] { + return cached + } + if chars[i] == "0" { + return 0 + } + + var res = dfs(i + 1) + if i + 1 < chars.count, + chars[i] == "1" || (chars[i] == "2" && "0123456".contains(chars[i + 1])) { + res += dfs(i + 2) + } + dp[i] = res + return res + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -407,7 +465,7 @@ class Solution: ```java public class Solution { - public int numDecodings(String s) { + public int numDecodings(String s) { int[] dp = new int[s.length() + 1]; dp[s.length()] = 1; for (int i = s.length() - 1; i >= 0; i--) { @@ -415,7 +473,7 @@ public class Solution { dp[i] = 0; } else { dp[i] = dp[i + 1]; - if (i + 1 < s.length() && (s.charAt(i) == '1' || + if (i + 1 < s.length() && (s.charAt(i) == '1' || s.charAt(i) == '2' && s.charAt(i + 1) < '7')) { dp[i] += dp[i + 2]; } @@ -437,7 +495,7 @@ public: dp[i] = 0; } else { dp[i] = dp[i + 1]; - if (i + 1 < s.size() && (s[i] == '1' || + if (i + 1 < s.size() && (s[i] == '1' || s[i] == '2' && s[i + 1] < '7')) { dp[i] += dp[i + 2]; } @@ -462,9 +520,12 @@ class Solution { dp[i] = 0; } else { dp[i] = dp[i + 1]; - if (i + 1 < s.length && (s.charAt(i) === '1' || - (s.charAt(i) === '2' && s.charAt(i + 1) < '7'))) { - dp[i] += dp[i + 2]; + if ( + i + 1 < s.length && + (s.charAt(i) === '1' || + (s.charAt(i) === '2' && s.charAt(i + 1) < '7')) + ) { + dp[i] += dp[i + 2]; } } } @@ -483,7 +544,7 @@ public class Solution { dp[i] = 0; } else { dp[i] = dp[i + 1]; - if (i + 1 < s.Length && (s[i] == '1' || + if (i + 1 < s.Length && (s[i] == '1' || s[i] == '2' && s[i + 1] < '7')) { dp[i] += dp[i + 2]; } @@ -503,7 +564,7 @@ func numDecodings(s string) int { dp[i] = 0 } else { dp[i] = dp[i+1] - if i+1 < len(s) && (s[i] == '1' || + if i+1 < len(s) && (s[i] == '1' || (s[i] == '2' && s[i+1] <= '6')) { dp[i] += dp[i+2] } @@ -522,7 +583,7 @@ class Solution { dp[i] = 0 } else { dp[i] = dp[i + 1] ?: 0 - if (i + 1 < s.length && (s[i] == '1' || + if (i + 1 < s.length && (s[i] == '1' || (s[i] == '2' && s[i + 1] <= '6'))) { dp[i] = dp[i]!! + (dp[i + 2] ?: 0) } @@ -533,12 +594,36 @@ class Solution { } ``` +```swift +class Solution { + func numDecodings(_ s: String) -> Int { + let chars = Array(s) + var dp = [Int: Int]() + dp[chars.count] = 1 + + for i in stride(from: chars.count - 1, through: 0, by: -1) { + if chars[i] == "0" { + dp[i] = 0 + } else { + dp[i] = dp[i + 1] ?? 0 + } + + if i + 1 < chars.count, + chars[i] == "1" || (chars[i] == "2" && "0123456".contains(chars[i + 1])) { + dp[i]! += dp[i + 2] ?? 0 + } + } + return dp[0] ?? 0 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -567,7 +652,7 @@ class Solution: ```java public class Solution { - public int numDecodings(String s) { + public int numDecodings(String s) { int dp = 0, dp2 = 0; int dp1 = 1; for (int i = s.length() - 1; i >= 0; i--) { @@ -575,7 +660,7 @@ public class Solution { dp = 0; } else { dp = dp1; - if (i + 1 < s.length() && (s.charAt(i) == '1' || + if (i + 1 < s.length() && (s.charAt(i) == '1' || s.charAt(i) == '2' && s.charAt(i + 1) < '7')) { dp += dp2; } @@ -600,7 +685,7 @@ public: dp = 0; } else { dp = dp1; - if (i + 1 < s.size() && (s[i] == '1' || + if (i + 1 < s.size() && (s[i] == '1' || s[i] == '2' && s[i + 1] < '7')) { dp += dp2; } @@ -621,16 +706,20 @@ class Solution { * @return {number} */ numDecodings(s) { - let dp2 = 0, dp = 0; + let dp2 = 0, + dp = 0; let dp1 = 1; for (let i = s.length - 1; i >= 0; i--) { if (s.charAt(i) === '0') { dp = 0; } else { dp = dp1; - if (i + 1 < s.length && (s.charAt(i) === '1' || - (s.charAt(i) === '2' && s.charAt(i + 1) < '7'))) { - dp += dp2; + if ( + i + 1 < s.length && + (s.charAt(i) === '1' || + (s.charAt(i) === '2' && s.charAt(i + 1) < '7')) + ) { + dp += dp2; } } dp2 = dp1; @@ -651,7 +740,7 @@ public class Solution { dp = 0; } else { dp = dp1; - if (i + 1 < s.Length && (s[i] == '1' || + if (i + 1 < s.Length && (s[i] == '1' || s[i] == '2' && s[i + 1] < '7')) { dp += dp2; } @@ -675,7 +764,7 @@ func numDecodings(s string) int { } else { dp = dp1 } - if i+1 < len(s) && (s[i] == '1' || + if i+1 < len(s) && (s[i] == '1' || s[i] == '2' && s[i+1] <= '6') { dp += dp2 } @@ -699,7 +788,7 @@ class Solution { } else { dp = dp1 } - if (i + 1 < s.length && (s[i] == '1' || + if (i + 1 < s.length && (s[i] == '1' || (s[i] == '2' && s[i + 1] <= '6'))) { dp += dp2 } @@ -711,9 +800,33 @@ class Solution { } ``` +```swift +class Solution { + func numDecodings(_ s: String) -> Int { + let chars = Array(s) + var dp = 0, dp1 = 1, dp2 = 0 + + for i in stride(from: chars.count - 1, through: 0, by: -1) { + if chars[i] == "0" { + dp = 0 + } else { + dp = dp1 + } + + if i + 1 < chars.count, + chars[i] == "1" || (chars[i] == "2" && "0123456".contains(chars[i + 1])) { + dp += dp2 + } + (dp, dp1, dp2) = (0, dp, dp1) + } + return dp1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/delete-and-earn.md b/articles/delete-and-earn.md index ae00ea5db..38521d451 100644 --- a/articles/delete-and-earn.md +++ b/articles/delete-and-earn.md @@ -10,20 +10,20 @@ class Solution: def dfs(i): if i >= len(nums): return 0 - + cur = nums[i] pick = 0 while i < len(nums) and nums[i] == cur: pick += nums[i] i += 1 - + res = dfs(i) while i < len(nums) and nums[i] == 1 + cur: i += 1 - + res = max(res, pick + dfs(i)) return res - + return dfs(0) ``` @@ -94,18 +94,19 @@ class Solution { const dfs = (i) => { if (i >= nums.length) return 0; - - let cur = nums[i], pick = 0; + + let cur = nums[i], + pick = 0; while (i < nums.length && nums[i] === cur) { pick += nums[i]; i++; } - + let res = dfs(i); while (i < nums.length && nums[i] === cur + 1) { i++; } - + res = Math.max(res, pick + dfs(i)); return res; }; @@ -119,8 +120,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -142,17 +143,17 @@ class Solution: return 0 if memo[i] != -1: return memo[i] - + res = val[nums[i]] if i + 1 < len(nums) and nums[i] + 1 == nums[i + 1]: res += dfs(i + 2) else: res += dfs(i + 1) - + res = max(res, dfs(i + 1)) memo[i] = res return res - + return dfs(0) ``` @@ -241,7 +242,7 @@ class Solution { */ deleteAndEarn(nums) { const val = new Map(); - nums.forEach(num => { + nums.forEach((num) => { val.set(num, (val.get(num) || 0) + num); }); const uniqueNums = Array.from(new Set(nums)).sort((a, b) => a - b); @@ -272,8 +273,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -288,7 +289,7 @@ class Solution: for num in nums: val[num] += num nums = sorted(list(set(nums))) - + dp = [0] * (len(nums) + 1) for i in range(len(nums) - 1, -1, -1): take = val[nums[i]] @@ -297,7 +298,7 @@ class Solution: else: take += dp[i + 1] dp[i] = max(dp[i + 1], take) - + return dp[0] ``` @@ -334,7 +335,7 @@ public: vector sortedNums; for (auto& [key, _] : val) sortedNums.push_back(key); sort(sortedNums.begin(), sortedNums.end()); - + vector dp(sortedNums.size() + 1); for (int i = sortedNums.size() - 1; i >= 0; i--) { int take = val[sortedNums[i]]; @@ -345,7 +346,7 @@ public: } dp[i] = max(dp[i + 1], take); } - + return dp[0]; } }; @@ -359,13 +360,16 @@ class Solution { */ deleteAndEarn(nums) { const val = new Map(); - nums.forEach(num => val.set(num, (val.get(num) || 0) + num)); + nums.forEach((num) => val.set(num, (val.get(num) || 0) + num)); const sortedNums = Array.from(val.keys()).sort((a, b) => a - b); const dp = Array(sortedNums.length + 1).fill(0); for (let i = sortedNums.length - 1; i >= 0; i--) { let take = val.get(sortedNums[i]); - if (i + 1 < sortedNums.length && sortedNums[i + 1] === sortedNums[i] + 1) { + if ( + i + 1 < sortedNums.length && + sortedNums[i + 1] === sortedNums[i] + 1 + ) { take += dp[i + 2]; } else { take += dp[i + 1]; @@ -382,8 +386,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -401,7 +405,7 @@ class Solution: dp[num] += num for i in range(m - 1, 0, -1): dp[i] = max(dp[i + 1], dp[i + 2] + dp[i]) - + return dp[1] ``` @@ -430,7 +434,7 @@ public: for (auto& num : nums) { dp[num] += num; } - + for (int i = m - 1; i > 0; i--) { dp[i] = max(dp[i + 1], dp[i + 2] + dp[i]); } @@ -464,8 +468,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m + n)$ -* Space complexity: $O(m)$ +- Time complexity: $O(m + n)$ +- Space complexity: $O(m)$ > Where $m$ is the maximum element in the array and $n$ is the size of the array. @@ -557,10 +561,11 @@ class Solution { */ deleteAndEarn(nums) { const count = new Map(); - nums.forEach(num => count.set(num, (count.get(num) || 0) + num)); + nums.forEach((num) => count.set(num, (count.get(num) || 0) + num)); const uniqueNums = [...count.keys()].sort((a, b) => a - b); - let earn1 = 0, earn2 = 0; + let earn1 = 0, + earn2 = 0; for (let i = 0; i < uniqueNums.length; i++) { const curEarn = count.get(uniqueNums[i]); if (i > 0 && uniqueNums[i] === uniqueNums[i - 1] + 1) { @@ -582,5 +587,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/delete-leaves-with-a-given-value.md b/articles/delete-leaves-with-a-given-value.md index ccfb4637b..38471c91d 100644 --- a/articles/delete-leaves-with-a-given-value.md +++ b/articles/delete-leaves-with-a-given-value.md @@ -122,12 +122,42 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public TreeNode RemoveLeafNodes(TreeNode root, int target) { + if (root == null) return null; + + root.left = RemoveLeafNodes(root.left, target); + root.right = RemoveLeafNodes(root.right, target); + + if (root.left == null && root.right == null && root.val == target) { + return null; + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -343,12 +373,68 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public TreeNode RemoveLeafNodes(TreeNode root, int target) { + if (root == null) return null; + + Stack stack = new Stack(); + HashSet visited = new HashSet(); + Dictionary parents = new Dictionary(); + + stack.Push(root); + parents[root] = null; + + while (stack.Count > 0) { + TreeNode node = stack.Pop(); + + if (node.left == null && node.right == null) { + if (node.val == target) { + TreeNode parent = parents[node]; + if (parent == null) { + return null; + } + if (parent.left == node) parent.left = null; + if (parent.right == node) parent.right = null; + } + } else if (!visited.Contains(node)) { + visited.Add(node); + stack.Push(node); + if (node.left != null) { + stack.Push(node.left); + parents[node.left] = node; + } + if (node.right != null) { + stack.Push(node.right); + parents[node.right] = node; + } + } + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -533,7 +619,8 @@ class Solution { if (!root) return null; const stack = []; - let cur = root, visited = null; + let cur = root, + visited = null; while (stack.length > 0 || cur !== null) { while (cur !== null) { @@ -569,9 +656,65 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public TreeNode RemoveLeafNodes(TreeNode root, int target) { + if (root == null) return null; + + Stack stack = new Stack(); + TreeNode cur = root; + TreeNode visited = null; + + while (stack.Count > 0 || cur != null) { + while (cur != null) { + stack.Push(cur); + cur = cur.left; + } + + cur = stack.Peek(); + if (cur.right != null && cur.right != visited) { + cur = cur.right; + continue; + } + + stack.Pop(); + if (cur.left == null && cur.right == null && cur.val == target) { + if (stack.Count == 0) return null; + + TreeNode parent = stack.Peek(); + if (parent.left == cur) { + parent.left = null; + } else if (parent.right == cur) { + parent.right = null; + } + } else { + visited = cur; + } + + cur = null; + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/delete-node-in-a-bst.md b/articles/delete-node-in-a-bst.md index 4b086145a..a84c6e82b 100644 --- a/articles/delete-node-in-a-bst.md +++ b/articles/delete-node-in-a-bst.md @@ -153,12 +153,51 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public TreeNode DeleteNode(TreeNode root, int key) { + if (root == null) return null; + + if (key > root.val) { + root.right = DeleteNode(root.right, key); + } else if (key < root.val) { + root.left = DeleteNode(root.left, key); + } else { + if (root.left == null) return root.right; + if (root.right == null) return root.left; + + TreeNode cur = root.right; + while (cur.left != null) { + cur = cur.left; + } + root.val = cur.val; + root.right = DeleteNode(root.right, root.val); + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(h)$ -* Space complexity: $O(h)$ for the recursion stack. +- Time complexity: $O(h)$ +- Space complexity: $O(h)$ for the recursion stack. > Where $h$ is the height of the given binary search tree. @@ -327,12 +366,52 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public TreeNode DeleteNode(TreeNode root, int key) { + if (root == null) return null; + + if (key > root.val) { + root.right = DeleteNode(root.right, key); + } else if (key < root.val) { + root.left = DeleteNode(root.left, key); + } else { + if (root.left == null) return root.right; + if (root.right == null) return root.left; + + TreeNode cur = root.right; + while (cur.left != null) { + cur = cur.left; + } + cur.left = root.left; + TreeNode res = root.right; + return res; + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(h)$ -* Space complexity: $O(h)$ for the recursion stack. +- Time complexity: $O(h)$ +- Space complexity: $O(h)$ for the recursion stack. > Where $h$ is the height of the given binary search tree. @@ -353,10 +432,10 @@ class Solution: def deleteNode(self, root: Optional[TreeNode], key: int) -> Optional[TreeNode]: if not root: return root - + parent = None cur = root - + # Find the node to delete while cur and cur.val != key: parent = cur @@ -364,10 +443,10 @@ class Solution: cur = cur.right else: cur = cur.left - + if not cur: return root - + # Node with only one child or no child if not cur.left or not cur.right: child = cur.left if cur.left else cur.right @@ -385,21 +464,21 @@ class Solution: while cur.left: par = cur cur = cur.left - + if par: # if there was a left traversal par.left = cur.right cur.right = delNode.right - + cur.left = delNode.left - + if not parent: # if we're deleting root return cur - + if parent.left == delNode: parent.left = cur else: parent.right = cur - + return root ``` @@ -422,10 +501,10 @@ class Solution: public class Solution { public TreeNode deleteNode(TreeNode root, int key) { if (root == null) return root; - + TreeNode parent = null; TreeNode cur = root; - + // Find the node to delete while (cur != null && cur.val != key) { parent = cur; @@ -435,9 +514,9 @@ public class Solution { cur = cur.left; } } - + if (cur == null) return root; - + // Node with only one child or no child if (cur.left == null || cur.right == null) { TreeNode child = (cur.left != null) ? cur.left : cur.right; @@ -456,22 +535,22 @@ public class Solution { par = cur; cur = cur.left; } - + if (par != null) { // if there was a left traversal par.left = cur.right; cur.right = delNode.right; } cur.left = delNode.left; - + if (parent == null) return cur; // if deleting root - + if (parent.left == delNode) { parent.left = cur; } else { parent.right = cur; } } - + return root; } } @@ -493,10 +572,10 @@ class Solution { public: TreeNode* deleteNode(TreeNode* root, int key) { if (!root) return root; - + TreeNode* parent = nullptr; TreeNode* cur = root; - + // Find the node to delete while (cur && cur->val != key) { parent = cur; @@ -506,9 +585,9 @@ public: cur = cur->left; } } - + if (!cur) return root; - + // Node with only one child or no child if (!cur->left || !cur->right) { TreeNode* child = cur->left ? cur->left : cur->right; @@ -527,22 +606,22 @@ public: par = cur; cur = cur->left; } - + if (par) { // if there was a left traversal par->left = cur->right; cur->right = delNode->right; } cur->left = delNode->left; - + if (!parent) return cur; // if deleting root - + if (parent->left == delNode) { parent->left = cur; } else { parent->right = cur; } } - + return root; } }; @@ -567,10 +646,10 @@ class Solution { */ deleteNode(root, key) { if (!root) return root; - + let parent = null; let cur = root; - + // Find the node to delete while (cur && cur.val !== key) { parent = cur; @@ -580,9 +659,9 @@ class Solution { cur = cur.left; } } - + if (!cur) return root; - + // Node with only one child or no child if (!cur.left || !cur.right) { const child = cur.left || cur.right; @@ -601,22 +680,102 @@ class Solution { par = cur; cur = cur.left; } - - if (par) { // if there was a left traversal + + if (par) { + // if there was a left traversal par.left = cur.right; cur.right = delNode.right; } cur.left = delNode.left; - + if (!parent) return cur; // if deleting root - + if (parent.left === delNode) { parent.left = cur; } else { parent.right = cur; } } - + + return root; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public TreeNode DeleteNode(TreeNode root, int key) { + if (root == null) return null; + + TreeNode parent = null; + TreeNode cur = root; + + // Find the node to delete + while (cur != null && cur.val != key) { + parent = cur; + if (key > cur.val) { + cur = cur.right; + } else { + cur = cur.left; + } + } + + if (cur == null) return root; + + // Node with one or no child + if (cur.left == null || cur.right == null) { + TreeNode child = cur.left != null ? cur.left : cur.right; + + if (parent == null) { + return child; + } + + if (parent.left == cur) { + parent.left = child; + } else { + parent.right = child; + } + } else { + // Node with two children + TreeNode par = null; + TreeNode delNode = cur; + cur = cur.right; + while (cur.left != null) { + par = cur; + cur = cur.left; + } + + if (par != null) { + par.left = cur.right; + cur.right = delNode.right; + } + + cur.left = delNode.left; + + if (parent == null) { + return cur; + } + + if (parent.left == delNode) { + parent.left = cur; + } else { + parent.right = cur; + } + } + return root; } } @@ -626,7 +785,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(h)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(h)$ +- Space complexity: $O(1)$ extra space. -> Where $h$ is the height of the given binary search tree. \ No newline at end of file +> Where $h$ is the height of the given binary search tree. diff --git a/articles/depth-of-binary-tree.md b/articles/depth-of-binary-tree.md index efd76b64d..35876c27c 100644 --- a/articles/depth-of-binary-tree.md +++ b/articles/depth-of-binary-tree.md @@ -171,14 +171,38 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func maxDepth(_ root: TreeNode?) -> Int { + guard let root = root else { return 0 } + return 1 + max(maxDepth(root.left), maxDepth(root.right)) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(h)$ - * Best Case ([balanced tree](https://www.geeksforgeeks.org/balanced-binary-tree/)): $O(log(n))$ - * Worst Case ([degenerate tree](https://www.geeksforgeeks.org/introduction-to-degenerate-binary-tree/)): $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(h)$ + - Best Case ([balanced tree](https://www.geeksforgeeks.org/balanced-binary-tree/)): $O(log(n))$ + - Worst Case ([degenerate tree](https://www.geeksforgeeks.org/introduction-to-degenerate-binary-tree/)): $O(n)$ > Where $n$ is the number of nodes in the tree and $h$ is the height of the tree. @@ -374,25 +398,25 @@ func maxDepth(root *TreeNode) int { if root == nil { return 0 } - + stack := list.New() stack.PushBack([]interface{}{root, 1}) res := 0 - + for stack.Len() > 0 { back := stack.Back() stack.Remove(back) pair := back.Value.([]interface{}) node := pair[0].(*TreeNode) depth := pair[1].(int) - + if node != nil { res = max(res, depth) stack.PushBack([]interface{}{node.Left, depth + 1}) stack.PushBack([]interface{}{node.Right, depth + 1}) } } - + return res } @@ -420,21 +444,56 @@ class Solution { if (root == null) { return 0 } - + val stack = ArrayDeque>() stack.addLast(Pair(root, 1)) var res = 0 - + while (stack.isNotEmpty()) { val (node, depth) = stack.removeLast() - + if (node != null) { res = maxOf(res, depth) stack.addLast(Pair(node.left, depth + 1)) stack.addLast(Pair(node.right, depth + 1)) } } - + + return res + } +} +``` + +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func maxDepth(_ root: TreeNode?) -> Int { + var stack: [(TreeNode?, Int)] = [(root, 1)] + var res = 0 + + while !stack.isEmpty { + let (node, depth) = stack.removeLast() + + if let node = node { + res = max(res, depth) + stack.append((node.left, depth + 1)) + stack.append((node.right, depth + 1)) + } + } return res } } @@ -444,12 +503,12 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- -## 3. Breadth First Search +## 3. Breadth First Search ::tabs-start @@ -659,18 +718,18 @@ func maxDepth(root *TreeNode) int { if root == nil { return 0 } - + q := linkedlistqueue.New() q.Enqueue(root) level := 0 - + for !q.Empty() { size := q.Size() - + for i := 0; i < size; i++ { val, _ := q.Dequeue() node := val.(*TreeNode) - + if node.Left != nil { q.Enqueue(node.Left) } @@ -680,7 +739,7 @@ func maxDepth(root *TreeNode) int { } level++ } - + return level } ``` @@ -701,23 +760,64 @@ class Solution { if (root == null) { return 0 } - + val q = ArrayDeque() q.addLast(root) var level = 0 - + while (q.isNotEmpty()) { val size = q.size - + repeat(size) { val node = q.removeFirst() - + node.left?.let { q.addLast(it) } node.right?.let { q.addLast(it) } } level++ } - + + return level + } +} +``` + +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func maxDepth(_ root: TreeNode?) -> Int { + var queue = Deque() + if let root = root { + queue.append(root) + } + + var level = 0 + while !queue.isEmpty { + for _ in 0.. rating + self.cuisineToFood = defaultdict(list) # cuisine -> [food] + for i in range(len(foods)): + self.foodToRating[foods[i]] = ratings[i] + self.cuisineToFood[cuisines[i]].append(foods[i]) + + def changeRating(self, food: str, newRating: int) -> None: + self.foodToRating[food] = newRating + + def highestRated(self, cuisine: str) -> str: + maxR, res = 0, "" + for food in self.cuisineToFood[cuisine]: + r = self.foodToRating[food] + if r > maxR or (r == maxR and food < res): + res = food + maxR = r + return res +``` + +```java +public class FoodRatings { + private Map foodToRating; + private Map> cuisineToFood; + + public FoodRatings(String[] foods, String[] cuisines, int[] ratings) { + foodToRating = new HashMap<>(); + cuisineToFood = new HashMap<>(); + for (int i = 0; i < foods.length; i++) { + foodToRating.put(foods[i], ratings[i]); + cuisineToFood.computeIfAbsent(cuisines[i], k -> new ArrayList<>()).add(foods[i]); + } + } + + public void changeRating(String food, int newRating) { + foodToRating.put(food, newRating); + } + + public String highestRated(String cuisine) { + int maxR = 0; + String res = ""; + for (String food : cuisineToFood.get(cuisine)) { + int r = foodToRating.get(food); + if (r > maxR || (r == maxR && food.compareTo(res) < 0)) { + res = food; + maxR = r; + } + } + return res; + } +} +``` + +```cpp +class FoodRatings { +private: + unordered_map foodToRating; + unordered_map> cuisineToFood; + +public: + FoodRatings(vector& foods, vector& cuisines, vector& ratings) { + for (size_t i = 0; i < foods.size(); i++) { + foodToRating[foods[i]] = ratings[i]; + cuisineToFood[cuisines[i]].push_back(foods[i]); + } + } + + void changeRating(string food, int newRating) { + foodToRating[food] = newRating; + } + + string highestRated(string cuisine) { + int maxR = 0; + string res = ""; + for (const string& food : cuisineToFood[cuisine]) { + int r = foodToRating[food]; + if (r > maxR || (r == maxR && food < res)) { + res = food; + maxR = r; + } + } + return res; + } +}; +``` + +```javascript +class FoodRatings { + /** + * @param {string[]} foods + * @param {string[]} cuisines + * @param {number[]} ratings + */ + constructor(foods, cuisines, ratings) { + this.foodToRating = new Map(); + this.cuisineToFood = new Map(); + + for (let i = 0; i < foods.length; i++) { + this.foodToRating.set(foods[i], ratings[i]); + if (!this.cuisineToFood.has(cuisines[i])) { + this.cuisineToFood.set(cuisines[i], []); + } + this.cuisineToFood.get(cuisines[i]).push(foods[i]); + } + } + + /** + * @param {string} food + * @param {number} newRating + * @return {void} + */ + changeRating(food, newRating) { + this.foodToRating.set(food, newRating); + } + + /** + * @param {string} cuisine + * @return {string} + */ + highestRated(cuisine) { + let maxR = 0, + res = ''; + for (let food of this.cuisineToFood.get(cuisine)) { + let r = this.foodToRating.get(food); + if (r > maxR || (r === maxR && food < res)) { + res = food; + maxR = r; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(n)$ time for initialization. + - $O(1)$ time for each $changeRating()$ function call. + - $O(n)$ time for each $highestRated()$ function call. +- Space complexity: $O(n)$ + +--- + +## 2. Heap + +::tabs-start + +```python +class FoodRatings: + + def __init__(self, foods: List[str], cuisines: List[str], ratings: List[int]): + self.foodToRating = {} # food -> rating + self.foodToCuisine = {} # food -> cuisine + self.cuisineToHeap = defaultdict(list) # cuisine -> max_heap + + for i in range(len(foods)): + self.foodToRating[foods[i]] = ratings[i] + self.foodToCuisine[foods[i]] = cuisines[i] + heappush(self.cuisineToHeap[cuisines[i]], (-ratings[i], foods[i])) + + def changeRating(self, food: str, newRating: int) -> None: + cuisine = self.foodToCuisine[food] + self.foodToRating[food] = newRating + heappush(self.cuisineToHeap[cuisine], (-newRating, food)) + + def highestRated(self, cuisine: str) -> str: + heap = self.cuisineToHeap[cuisine] + while heap: + rating, food = heap[0] + if -rating == self.foodToRating[food]: + return food + heappop(heap) +``` + +```java +public class FoodRatings { + private Map foodToRating; + private Map foodToCuisine; + private Map> cuisineToHeap; + + private static class Food { + int rating; + String name; + + Food(int rating, String name) { + this.rating = rating; + this.name = name; + } + } + + public FoodRatings(String[] foods, String[] cuisines, int[] ratings) { + foodToRating = new HashMap<>(); + foodToCuisine = new HashMap<>(); + cuisineToHeap = new HashMap<>(); + + for (int i = 0; i < foods.length; i++) { + foodToRating.put(foods[i], ratings[i]); + foodToCuisine.put(foods[i], cuisines[i]); + cuisineToHeap + .computeIfAbsent(cuisines[i], k -> new PriorityQueue<>( + (a, b) -> a.rating == b.rating ? a.name.compareTo(b.name) : b.rating - a.rating)) + .offer(new Food(ratings[i], foods[i])); + } + } + + public void changeRating(String food, int newRating) { + String cuisine = foodToCuisine.get(food); + foodToRating.put(food, newRating); + cuisineToHeap.get(cuisine).offer(new Food(newRating, food)); + } + + public String highestRated(String cuisine) { + PriorityQueue heap = cuisineToHeap.get(cuisine); + while (!heap.isEmpty()) { + Food top = heap.peek(); + if (foodToRating.get(top.name) == top.rating) { + return top.name; + } + heap.poll(); + } + return ""; + } +} +``` + +```cpp +class FoodRatings { + unordered_map foodToRating; + unordered_map foodToCuisine; + struct cmp { + bool operator()(const pair& a, const pair& b) { + if (a.first == b.first) return a.second > b.second; + return a.first < b.first; + } + }; + unordered_map, + vector>, cmp>> cuisineToHeap; + +public: + FoodRatings(vector& foods, vector& cuisines, vector& ratings) { + for (int i = 0; i < foods.size(); i++) { + foodToRating[foods[i]] = ratings[i]; + foodToCuisine[foods[i]] = cuisines[i]; + cuisineToHeap[cuisines[i]].push({ratings[i], foods[i]}); + } + } + + void changeRating(string food, int newRating) { + string cuisine = foodToCuisine[food]; + foodToRating[food] = newRating; + cuisineToHeap[cuisine].push({newRating, food}); + } + + string highestRated(string cuisine) { + auto &heap = cuisineToHeap[cuisine]; + while (!heap.empty()) { + auto [rating, food] = heap.top(); + if (foodToRating[food] == rating) return food; + heap.pop(); + } + return ""; + } +}; +``` + +```javascript +class FoodRatings { + /** + * @param {string[]} foods + * @param {string[]} cuisines + * @param {number[]} ratings + */ + constructor(foods, cuisines, ratings) { + this.foodToRating = new Map(); + this.foodToCuisine = new Map(); + this.cuisineToHeap = new Map(); + + for (let i = 0; i < foods.length; i++) { + this.foodToRating.set(foods[i], ratings[i]); + this.foodToCuisine.set(foods[i], cuisines[i]); + if (!this.cuisineToHeap.has(cuisines[i])) { + this.cuisineToHeap.set( + cuisines[i], + new PriorityQueue( + (a, b) => + b.rating - a.rating || a.name.localeCompare(b.name), + ), + ); + } + this.cuisineToHeap + .get(cuisines[i]) + .enqueue({ rating: ratings[i], name: foods[i] }); + } + } + + /** + * @param {string} food + * @param {number} newRating + * @return {void} + */ + changeRating(food, newRating) { + let cuisine = this.foodToCuisine.get(food); + this.foodToRating.set(food, newRating); + this.cuisineToHeap + .get(cuisine) + .enqueue({ rating: newRating, name: food }); + } + + /** + * @param {string} cuisine + * @return {string} + */ + highestRated(cuisine) { + let heap = this.cuisineToHeap.get(cuisine); + while (!heap.isEmpty()) { + let top = heap.front(); + if (this.foodToRating.get(top.name) === top.rating) { + return top.name; + } + heap.dequeue(); + } + return ''; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(n \log n)$ time for initialization. + - $O(\log n)$ time for each $changeRating()$ function call. + - $O(\log n)$ time for each $highestRated()$ function call. +- Space complexity: $O(n)$ + +--- + +## 3. Sorted Set + +::tabs-start + +```python +class FoodRatings: + + def __init__(self, foods: List[str], cuisines: List[str], ratings: List[int]): + self.foodToRating = {} # food -> rating + self.foodToCuisine = {} # food -> cuisine + self.cuisineToSortedSet = defaultdict(SortedSet) # cuisine -> SortedSet[(rating, food)] + + for i in range(len(foods)): + self.foodToRating[foods[i]] = ratings[i] + self.foodToCuisine[foods[i]] = cuisines[i] + self.cuisineToSortedSet[cuisines[i]].add((-ratings[i], foods[i])) + + def changeRating(self, food: str, newRating: int) -> None: + cuisine = self.foodToCuisine[food] + oldRating = self.foodToRating[food] + + self.cuisineToSortedSet[cuisine].remove((-oldRating, food)) + self.foodToRating[food] = newRating + self.cuisineToSortedSet[cuisine].add((-newRating, food)) + + def highestRated(self, cuisine: str) -> str: + return self.cuisineToSortedSet[cuisine][0][1] +``` + +```java +public class FoodRatings { + private Map foodToRating; + private Map foodToCuisine; + private Map> cuisineToSortedSet; + + private static class FoodPair { + int rating; + String food; + + FoodPair(int rating, String food) { + this.rating = rating; + this.food = food; + } + } + + public FoodRatings(String[] foods, String[] cuisines, int[] ratings) { + foodToRating = new HashMap<>(); + foodToCuisine = new HashMap<>(); + cuisineToSortedSet = new HashMap<>(); + + for (int i = 0; i < foods.length; i++) { + foodToRating.put(foods[i], ratings[i]); + foodToCuisine.put(foods[i], cuisines[i]); + cuisineToSortedSet.computeIfAbsent(cuisines[i], k -> new TreeSet<>((a, b) -> { + if (a.rating != b.rating) return b.rating - a.rating; + return a.food.compareTo(b.food); + })).add(new FoodPair(ratings[i], foods[i])); + } + } + + public void changeRating(String food, int newRating) { + String cuisine = foodToCuisine.get(food); + int oldRating = foodToRating.get(food); + TreeSet set = cuisineToSortedSet.get(cuisine); + set.remove(new FoodPair(oldRating, food)); + foodToRating.put(food, newRating); + set.add(new FoodPair(newRating, food)); + } + + public String highestRated(String cuisine) { + return cuisineToSortedSet.get(cuisine).first().food; + } +} +``` + +```cpp +class FoodRatings { + unordered_map foodToRating; + unordered_map foodToCuisine; + unordered_map>> cuisineToSet; + +public: + FoodRatings(vector& foods, vector& cuisines, vector& ratings) { + for (int i = 0; i < foods.size(); i++) { + foodToRating[foods[i]] = ratings[i]; + foodToCuisine[foods[i]] = cuisines[i]; + cuisineToSet[cuisines[i]].insert({-ratings[i], foods[i]}); + } + } + + void changeRating(string food, int newRating) { + string cuisine = foodToCuisine[food]; + auto& s = cuisineToSet[cuisine]; + + s.erase({-foodToRating[food], food}); + foodToRating[food] = newRating; + s.insert({-newRating, food}); + } + + string highestRated(string cuisine) { + return begin(cuisineToSet[cuisine])->second; + } +}; +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(n \log n)$ time for initialization. + - $O(\log n)$ time for each $changeRating()$ function call. + - $O(1)$ in Python and $O(\log n)$ in other languages for each $highestRated()$ function call. +- Space complexity: $O(n)$ diff --git a/articles/design-browser-history.md b/articles/design-browser-history.md new file mode 100644 index 000000000..8035bf24f --- /dev/null +++ b/articles/design-browser-history.md @@ -0,0 +1,640 @@ +## 1. Two Stacks + +::tabs-start + +```python +class BrowserHistory: + + def __init__(self, homepage: str): + self.back_history = [homepage] + self.front_history = [] + + def visit(self, url: str) -> None: + self.back_history.append(url) + self.front_history = [] + + def back(self, steps: int) -> str: + while steps and len(self.back_history) > 1: + self.front_history.append(self.back_history.pop()) + steps -= 1 + return self.back_history[-1] + + def forward(self, steps: int) -> str: + while steps and self.front_history: + self.back_history.append(self.front_history.pop()) + steps -= 1 + return self.back_history[-1] +``` + +```java +public class BrowserHistory { + private Stack backHistory; + private Stack frontHistory; + + public BrowserHistory(String homepage) { + backHistory = new Stack<>(); + frontHistory = new Stack<>(); + backHistory.push(homepage); + } + + public void visit(String url) { + backHistory.push(url); + frontHistory = new Stack<>(); + } + + public String back(int steps) { + while (steps > 0 && backHistory.size() > 1) { + frontHistory.push(backHistory.pop()); + steps--; + } + return backHistory.peek(); + } + + public String forward(int steps) { + while (steps > 0 && !frontHistory.isEmpty()) { + backHistory.push(frontHistory.pop()); + steps--; + } + return backHistory.peek(); + } +} +``` + +```cpp +class BrowserHistory { +private: + stack backHistory, frontHistory; + +public: + BrowserHistory(string homepage) { + backHistory.push(homepage); + } + + void visit(string url) { + backHistory.push(url); + frontHistory = stack(); + } + + string back(int steps) { + while (steps-- && backHistory.size() > 1) { + frontHistory.push(backHistory.top()); + backHistory.pop(); + } + return backHistory.top(); + } + + string forward(int steps) { + while (steps-- && !frontHistory.empty()) { + backHistory.push(frontHistory.top()); + frontHistory.pop(); + } + return backHistory.top(); + } +}; +``` + +```javascript +class BrowserHistory { + /** + * @constructor + * @param {string} homepage + */ + constructor(homepage) { + this.backHistory = [homepage]; + this.frontHistory = []; + } + + /** + * @param {string} url + * @return {void} + */ + visit(url) { + this.backHistory.push(url); + this.frontHistory = []; + } + + /** + * @param {number} steps + * @return {string} + */ + back(steps) { + while (steps-- > 0 && this.backHistory.length > 1) { + this.frontHistory.push(this.backHistory.pop()); + } + return this.backHistory[this.backHistory.length - 1]; + } + + /** + * @param {number} steps + * @return {string} + */ + forward(steps) { + while (steps-- > 0 && this.frontHistory.length > 0) { + this.backHistory.push(this.frontHistory.pop()); + } + return this.backHistory[this.backHistory.length - 1]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $visit()$ function call. + - $O(min(n, steps))$ time for each $back()$ and $forward()$ function calls. +- Space complexity: $O(m * n)$ + +> Where $n$ is the number of visited urls, $m$ is the average length of each url, and $steps$ is the number of steps we go forward or back. + +--- + +## 2. Dynamic Array + +::tabs-start + +```python +class BrowserHistory: + + def __init__(self, homepage: str): + self.history = [homepage] + self.cur = 0 + + def visit(self, url: str) -> None: + self.cur += 1 + self.history = self.history[:self.cur] + self.history.append(url) + + def back(self, steps: int) -> str: + self.cur = max(0, self.cur - steps) + return self.history[self.cur] + + def forward(self, steps: int) -> str: + self.cur = min(len(self.history) - 1, self.cur + steps) + return self.history[self.cur] +``` + +```java +public class BrowserHistory { + private List history; + private int cur; + + public BrowserHistory(String homepage) { + history = new ArrayList<>(); + history.add(homepage); + cur = 0; + } + + public void visit(String url) { + cur++; + history = history.subList(0, cur); + history.add(url); + } + + public String back(int steps) { + cur = Math.max(0, cur - steps); + return history.get(cur); + } + + public String forward(int steps) { + cur = Math.min(history.size() - 1, cur + steps); + return history.get(cur); + } +} +``` + +```cpp +class BrowserHistory { +private: + vector history; + int cur; + +public: + BrowserHistory(string homepage) { + history.push_back(homepage); + cur = 0; + } + + void visit(string url) { + cur++; + history.resize(cur); + history.push_back(url); + } + + string back(int steps) { + cur = max(0, cur - steps); + return history[cur]; + } + + string forward(int steps) { + cur = min((int)history.size() - 1, cur + steps); + return history[cur]; + } +}; +``` + +```javascript +class BrowserHistory { + /** + * @constructor + * @param {string} homepage + */ + constructor(homepage) { + this.history = [homepage]; + this.cur = 0; + } + + /** + * @param {string} url + * @return {void} + */ + visit(url) { + this.cur++; + this.history = this.history.slice(0, this.cur); + this.history.push(url); + } + + /** + * @param {number} steps + * @return {string} + */ + back(steps) { + this.cur = Math.max(0, this.cur - steps); + return this.history[this.cur]; + } + + /** + * @param {number} steps + * @return {string} + */ + forward(steps) { + this.cur = Math.min(this.history.length - 1, this.cur + steps); + return this.history[this.cur]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(n)$ time for each $visit()$ function call. + - $O(1)$ time for each $back()$ and $forward()$ function calls. +- Space complexity: $O(m * n)$ + +> Where $n$ is the number of visited urls and $m$ is the average length of each url. + +--- + +## 3. Dynamic Array (Optimal) + +::tabs-start + +```python +class BrowserHistory: + + def __init__(self, homepage: str): + self.history = [homepage] + self.cur = 0 + self.n = 1 + + def visit(self, url: str) -> None: + self.cur += 1 + if self.cur == len(self.history): + self.history.append(url) + self.n += 1 + else: + self.history[self.cur] = url + self.n = self.cur + 1 + + def back(self, steps: int) -> str: + self.cur = max(0, self.cur - steps) + return self.history[self.cur] + + def forward(self, steps: int) -> str: + self.cur = min(self.n - 1, self.cur + steps) + return self.history[self.cur] +``` + +```java +public class BrowserHistory { + private List history; + private int cur; + private int n; + + public BrowserHistory(String homepage) { + history = new ArrayList<>(); + history.add(homepage); + cur = 0; + n = 1; + } + + public void visit(String url) { + cur++; + if (cur == history.size()) { + history.add(url); + n++; + } else { + history.set(cur, url); + n = cur + 1; + } + } + + public String back(int steps) { + cur = Math.max(0, cur - steps); + return history.get(cur); + } + + public String forward(int steps) { + cur = Math.min(n - 1, cur + steps); + return history.get(cur); + } +} +``` + +```cpp +class BrowserHistory { +private: + vector history; + int cur, n; + +public: + BrowserHistory(string homepage) { + history.push_back(homepage); + cur = 0; + n = 1; + } + + void visit(string url) { + cur++; + if (cur == history.size()) { + history.push_back(url); + n++; + } else { + history[cur] = url; + n = cur + 1; + } + } + + string back(int steps) { + cur = max(0, cur - steps); + return history[cur]; + } + + string forward(int steps) { + cur = min(n - 1, cur + steps); + return history[cur]; + } +}; +``` + +```javascript +class BrowserHistory { + /** + * @constructor + * @param {string} homepage + */ + constructor(homepage) { + this.history = [homepage]; + this.cur = 0; + this.n = 1; + } + + /** + * @param {string} url + * @return {void} + */ + visit(url) { + this.cur++; + if (this.cur === this.history.length) { + this.history.push(url); + this.n++; + } else { + this.history[this.cur] = url; + this.n = this.cur + 1; + } + } + + /** + * @param {number} steps + * @return {string} + */ + back(steps) { + this.cur = Math.max(0, this.cur - steps); + return this.history[this.cur]; + } + + /** + * @param {number} steps + * @return {string} + */ + forward(steps) { + this.cur = Math.min(this.n - 1, this.cur + steps); + return this.history[this.cur]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $visit()$ function call. + - $O(1)$ time for each $back()$ and $forward()$ function calls. +- Space complexity: $O(m * n)$ + +> Where $n$ is the number of visited urls and $m$ is the average length of each url. + +--- + +## 4. Doubly Linked List + +::tabs-start + +```python +class ListNode: + def __init__(self, val, prev=None, next=None): + self.val = val + self.prev = prev + self.next = next + +class BrowserHistory: + + def __init__(self, homepage: str): + self.cur = ListNode(homepage) + + def visit(self, url: str) -> None: + self.cur.next = ListNode(url, self.cur) + self.cur = self.cur.next + + def back(self, steps: int) -> str: + while self.cur.prev and steps > 0: + self.cur = self.cur.prev + steps -= 1 + return self.cur.val + + def forward(self, steps: int) -> str: + while self.cur.next and steps > 0: + self.cur = self.cur.next + steps -= 1 + return self.cur.val +``` + +```java +class ListNode { + String val; + ListNode prev, next; + + public ListNode(String val, ListNode prev, ListNode next) { + this.val = val; + this.prev = prev; + this.next = next; + } + + public ListNode(String val) { + this(val, null, null); + } +} + +public class BrowserHistory { + private ListNode cur; + + public BrowserHistory(String homepage) { + cur = new ListNode(homepage); + } + + public void visit(String url) { + cur.next = new ListNode(url, cur, null); + cur = cur.next; + } + + public String back(int steps) { + while (cur.prev != null && steps > 0) { + cur = cur.prev; + steps--; + } + return cur.val; + } + + public String forward(int steps) { + while (cur.next != null && steps > 0) { + cur = cur.next; + steps--; + } + return cur.val; + } +} +``` + +```cpp +class BrowserHistory { + struct ListNode { + public: + string val; + ListNode* prev; + ListNode* next; + + ListNode(string val, ListNode* prev = nullptr, ListNode* next = nullptr) + : val(val), prev(prev), next(next) {} + }; + + ListNode* cur; + +public: + BrowserHistory(string homepage) { + cur = new ListNode(homepage); + } + + void visit(string url) { + cur->next = new ListNode(url, cur, nullptr); + cur = cur->next; + } + + string back(int steps) { + while (cur->prev != nullptr && steps > 0) { + cur = cur->prev; + steps--; + } + return cur->val; + } + + string forward(int steps) { + while (cur->next != nullptr && steps > 0) { + cur = cur->next; + steps--; + } + return cur->val; + } +}; +``` + +```javascript +class ListNode { + constructor(val, prev = null, next = null) { + this.val = val; + this.prev = prev; + this.next = next; + } +} + +class BrowserHistory { + /** + * @constructor + * @param {string} homepage + */ + constructor(homepage) { + this.cur = new ListNode(homepage); + } + + /** + * @param {string} url + * @return {void} + */ + visit(url) { + this.cur.next = new ListNode(url, this.cur, null); + this.cur = this.cur.next; + } + + /** + * @param {number} steps + * @return {string} + */ + back(steps) { + while (this.cur.prev !== null && steps > 0) { + this.cur = this.cur.prev; + steps--; + } + return this.cur.val; + } + + /** + * @param {number} steps + * @return {string} + */ + forward(steps) { + while (this.cur.next !== null && steps > 0) { + this.cur = this.cur.next; + steps--; + } + return this.cur.val; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $visit()$ function call. + - $O(min(n, steps))$ time for each $back()$ and $forward()$ function calls. +- Space complexity: $O(m * n)$ + +> Where $n$ is the number of visited urls, $m$ is the average length of each url, and $steps$ is the number of steps we go forward or back. diff --git a/articles/design-circular-queue.md b/articles/design-circular-queue.md index 033e2cfd6..9d79a45aa 100644 --- a/articles/design-circular-queue.md +++ b/articles/design-circular-queue.md @@ -190,15 +190,57 @@ class MyCircularQueue { } ``` +```csharp +public class MyCircularQueue { + private List q; + private int k; + + public MyCircularQueue(int k) { + this.k = k; + q = new List(); + } + + public bool EnQueue(int value) { + if (q.Count == k) return false; + q.Add(value); + return true; + } + + public bool DeQueue() { + if (q.Count == 0) return false; + q.RemoveAt(0); + return true; + } + + public int Front() { + if (q.Count > 0) return q[0]; + return -1; + } + + public int Rear() { + if (q.Count > 0) return q[q.Count - 1]; + return -1; + } + + public bool IsEmpty() { + return q.Count == 0; + } + + public bool IsFull() { + return q.Count == k; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(1)$ time for initialization. - * $O(1)$ time for each $enQueue()$, $Front()$, $Rear()$, $isEmpty()$ and $isFull()$ function calls. - * $O(n)$ time for each $deQueue()$ function call. -* Space complexity: $O(n)$ +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $enQueue()$, $Front()$, $Rear()$, $isEmpty()$ and $isFull()$ function calls. + - $O(n)$ time for each $deQueue()$ function call. +- Space complexity: $O(n)$ > Where $n$ is the size of the queue. @@ -210,14 +252,14 @@ class MyCircularQueue { ```python class MyCircularQueue: - + def __init__(self, k: int): self.q = [0] * k self.k = k self.front = 0 self.rear = -1 self.size = 0 - + def enQueue(self, value: int) -> bool: if self.isFull(): return False @@ -225,27 +267,27 @@ class MyCircularQueue: self.q[self.rear] = value self.size += 1 return True - + def deQueue(self) -> bool: if self.isEmpty(): return False self.front = (self.front + 1) % self.k self.size -= 1 return True - + def Front(self) -> int: if self.isEmpty(): return -1 return self.q[self.front] - + def Rear(self) -> int: if self.isEmpty(): return -1 return self.q[self.rear] - + def isEmpty(self) -> bool: return self.size == 0 - + def isFull(self) -> bool: return self.size == self.k ``` @@ -425,14 +467,65 @@ class MyCircularQueue { } ``` +```csharp +public class MyCircularQueue { + private int[] q; + private int k; + private int front; + private int rear; + private int size; + + public MyCircularQueue(int k) { + this.k = k; + this.q = new int[k]; + this.front = 0; + this.rear = -1; + this.size = 0; + } + + public bool EnQueue(int value) { + if (IsFull()) return false; + rear = (rear + 1) % k; + q[rear] = value; + size++; + return true; + } + + public bool DeQueue() { + if (IsEmpty()) return false; + front = (front + 1) % k; + size--; + return true; + } + + public int Front() { + if (IsEmpty()) return -1; + return q[front]; + } + + public int Rear() { + if (IsEmpty()) return -1; + return q[rear]; + } + + public bool IsEmpty() { + return size == 0; + } + + public bool IsFull() { + return size == k; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(n)$ time for initialization. - * $O(1)$ time for each $enQueue()$, $deQueue()$, $Front()$, $Rear()$, $isEmpty()$ and $isFull()$ function calls. -* Space complexity: $O(n)$ +- Time complexity: + - $O(n)$ time for initialization. + - $O(1)$ time for each $enQueue()$, $deQueue()$, $Front()$, $Rear()$, $isEmpty()$ and $isFull()$ function calls. +- Space complexity: $O(n)$ > Where $n$ is the size of the queue. @@ -611,9 +704,9 @@ public: ```javascript class ListNode { /** - * @param {number} val - * @param {ListNode} next - * @param {ListNode} prev + * @param {number} val + * @param {ListNode} next + * @param {ListNode} prev */ constructor(val, next = null, prev = null) { this.val = val; @@ -687,14 +780,77 @@ class MyCircularQueue { } ``` +```csharp +public class ListNode { + public int val; + public ListNode next, prev; + + public ListNode(int val, ListNode next = null, ListNode prev = null) { + this.val = val; + this.next = next; + this.prev = prev; + } +} + +public class MyCircularQueue { + private int space; + private ListNode left, right; + + public MyCircularQueue(int k) { + space = k; + left = new ListNode(0); + right = new ListNode(0); + left.next = right; + right.prev = left; + } + + public bool EnQueue(int value) { + if (IsFull()) { + return false; + } + ListNode cur = new ListNode(value, right, right.prev); + right.prev.next = cur; + right.prev = cur; + space--; + return true; + } + + public bool DeQueue() { + if (IsEmpty()) { + return false; + } + left.next = left.next.next; + left.next.prev = left; + space++; + return true; + } + + public int Front() { + return IsEmpty() ? -1 : left.next.val; + } + + public int Rear() { + return IsEmpty() ? -1 : right.prev.val; + } + + public bool IsEmpty() { + return left.next == right; + } + + public bool IsFull() { + return space == 0; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(n)$ time for initialization. - * $O(1)$ time for each $enQueue()$, $deQueue()$, $Front()$, $Rear()$, $isEmpty()$ and $isFull()$ function calls. -* Space complexity: $O(n)$ +- Time complexity: + - $O(n)$ time for initialization. + - $O(1)$ time for each $enQueue()$, $deQueue()$, $Front()$, $Rear()$, $isEmpty()$ and $isFull()$ function calls. +- Space complexity: $O(n)$ > Where $n$ is the size of the queue. @@ -715,10 +871,10 @@ class MyCircularQueue: self.space = k self.left = ListNode(0) self.right = self.left - + def enQueue(self, value: int) -> bool: if self.isFull(): return False - + cur = ListNode(value) if self.isEmpty(): self.left.next = cur @@ -726,31 +882,31 @@ class MyCircularQueue: else: self.right.next = cur self.right = cur - + self.space -= 1 return True - + def deQueue(self) -> bool: if self.isEmpty(): return False - + self.left.next = self.left.next.next if self.left.next is None: self.right = self.left - + self.space += 1 return True - + def Front(self) -> int: if self.isEmpty(): return -1 return self.left.next.val - + def Rear(self) -> int: if self.isEmpty(): return -1 return self.right.val - + def isEmpty(self) -> bool: return self.left.next is None - + def isFull(self) -> bool: return self.space == 0 ``` @@ -978,13 +1134,81 @@ class MyCircularQueue { } ``` +```csharp +public class ListNode { + public int val; + public ListNode next; + + public ListNode(int val) { + this.val = val; + this.next = null; + } +} + +public class MyCircularQueue { + private int space; + private ListNode left; + private ListNode right; + + public MyCircularQueue(int k) { + this.space = k; + this.left = new ListNode(0); + this.right = this.left; + } + + public bool EnQueue(int value) { + if (IsFull()) return false; + + ListNode cur = new ListNode(value); + if (IsEmpty()) { + this.left.next = cur; + this.right = cur; + } else { + this.right.next = cur; + this.right = cur; + } + + this.space--; + return true; + } + + public bool DeQueue() { + if (IsEmpty()) return false; + + this.left.next = this.left.next.next; + if (this.left.next == null) { + this.right = this.left; + } + + this.space++; + return true; + } + + public int Front() { + return IsEmpty() ? -1 : this.left.next.val; + } + + public int Rear() { + return IsEmpty() ? -1 : this.right.val; + } + + public bool IsEmpty() { + return this.left.next == null; + } + + public bool IsFull() { + return this.space == 0; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(n)$ time for initialization. - * $O(1)$ time for each $enQueue()$, $deQueue()$, $Front()$, $Rear()$, $isEmpty()$ and $isFull()$ function calls. -* Space complexity: $O(n)$ +- Time complexity: + - $O(n)$ time for initialization. + - $O(1)$ time for each $enQueue()$, $deQueue()$, $Front()$, $Rear()$, $isEmpty()$ and $isFull()$ function calls. +- Space complexity: $O(n)$ -> Where $n$ is the size of the queue. \ No newline at end of file +> Where $n$ is the size of the queue. diff --git a/articles/design-hashmap.md b/articles/design-hashmap.md index 4a64bdee1..c8ce07de0 100644 --- a/articles/design-hashmap.md +++ b/articles/design-hashmap.md @@ -69,8 +69,8 @@ class MyHashMap { this.map = new Array(1000001).fill(-1); } - /** - * @param {number} key + /** + * @param {number} key * @param {number} value * @return {void} */ @@ -78,7 +78,7 @@ class MyHashMap { this.map[key] = value; } - /** + /** * @param {number} key * @return {number} */ @@ -86,7 +86,7 @@ class MyHashMap { return this.map[key]; } - /** + /** * @param {number} key * @return {void} */ @@ -94,15 +94,39 @@ class MyHashMap { this.map[key] = -1; } } +``` + +```csharp +public class MyHashMap { + private int[] map; + + public MyHashMap() { + map = new int[1000001]; + for (int i = 0; i < map.Length; i++) { + map[i] = -1; + } + } + public void Put(int key, int value) { + map[key] = value; + } + + public int Get(int key) { + return map[key]; + } + + public void Remove(int key) { + map[key] = -1; + } +} ``` ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ for each function call. -* Space complexity: $O(1000000)$ since the key is in the range $[0, 1000000]$. +- Time complexity: $O(1)$ for each function call. +- Space complexity: $O(1000000)$ since the key is in the range $[0, 1000000]$. --- @@ -121,7 +145,7 @@ class MyHashMap: def __init__(self): self.map = [ListNode() for _ in range(1000)] - + def hash(self, key: int) -> int: return key % len(self.map) @@ -281,8 +305,8 @@ public: ```javascript class ListNode { - /** - * @param {number} key + /** + * @param {number} key * @param {number} val * @param {ListNode} next */ @@ -298,16 +322,16 @@ class MyHashMap { this.map = Array.from({ length: 1000 }, () => new ListNode()); } - /** - * @param {number} key + /** + * @param {number} key * @return {number} */ hash(key) { return key % this.map.length; } - /** - * @param {number} key + /** + * @param {number} key * @param {number} value * @return {void} */ @@ -323,8 +347,8 @@ class MyHashMap { cur.next = new ListNode(key, value); } - /** - * @param {number} key + /** + * @param {number} key * @return {number} */ get(key) { @@ -338,8 +362,8 @@ class MyHashMap { return -1; } - /** - * @param {number} key + /** + * @param {number} key * @return {void} */ remove(key) { @@ -355,11 +379,74 @@ class MyHashMap { } ``` +```csharp +public class ListNode { + public int key; + public int val; + public ListNode next; + + public ListNode(int key = -1, int val = -1, ListNode next = null) { + this.key = key; + this.val = val; + this.next = next; + } +} + +public class MyHashMap { + private ListNode[] map; + + public MyHashMap() { + map = new ListNode[1000]; + for (int i = 0; i < map.Length; i++) { + map[i] = new ListNode(); + } + } + + private int Hash(int key) { + return key % map.Length; + } + + public void Put(int key, int value) { + ListNode cur = map[Hash(key)]; + while (cur.next != null) { + if (cur.next.key == key) { + cur.next.val = value; + return; + } + cur = cur.next; + } + cur.next = new ListNode(key, value); + } + + public int Get(int key) { + ListNode cur = map[Hash(key)].next; + while (cur != null) { + if (cur.key == key) { + return cur.val; + } + cur = cur.next; + } + return -1; + } + + public void Remove(int key) { + ListNode cur = map[Hash(key)]; + while (cur.next != null) { + if (cur.next.key == key) { + cur.next = cur.next.next; + return; + } + cur = cur.next; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\frac{n}{k})$ for each function call. -* Space complexity: $O(k + m)$ +- Time complexity: $O(\frac{n}{k})$ for each function call. +- Space complexity: $O(k + m)$ -> Where $n$ is the number of keys, $k$ is the size of the map ($1000$) and $m$ is the number of unique keys. \ No newline at end of file +> Where $n$ is the number of keys, $k$ is the size of the map ($1000$) and $m$ is the number of unique keys. diff --git a/articles/design-hashset.md b/articles/design-hashset.md index 9ee3f0884..79c4e8e33 100644 --- a/articles/design-hashset.md +++ b/articles/design-hashset.md @@ -76,7 +76,7 @@ class MyHashSet { this.data = []; } - /** + /** * @param {number} key * @return {void} */ @@ -86,7 +86,7 @@ class MyHashSet { } } - /** + /** * @param {number} key * @return {void} */ @@ -97,7 +97,7 @@ class MyHashSet { } } - /** + /** * @param {number} key * @return {boolean} */ @@ -107,12 +107,38 @@ class MyHashSet { } ``` +```csharp +public class MyHashSet { + private List data; + + public MyHashSet() { + data = new List(); + } + + public void Add(int key) { + if (!data.Contains(key)) { + data.Add(key); + } + } + + public void Remove(int key) { + if (data.Contains(key)) { + data.Remove(key); + } + } + + public bool Contains(int key) { + return data.Contains(key); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ for each function call. -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ for each function call. +- Space complexity: $O(n)$ --- @@ -185,7 +211,7 @@ class MyHashSet { this.data = new Array(1000001).fill(false); } - /** + /** * @param {number} key * @return {void} */ @@ -193,7 +219,7 @@ class MyHashSet { this.data[key] = true; } - /** + /** * @param {number} key * @return {void} */ @@ -201,7 +227,7 @@ class MyHashSet { this.data[key] = false; } - /** + /** * @param {number} key * @return {boolean} */ @@ -211,12 +237,34 @@ class MyHashSet { } ``` +```csharp +public class MyHashSet { + private bool[] data; + + public MyHashSet() { + data = new bool[1000001]; + } + + public void Add(int key) { + data[key] = true; + } + + public void Remove(int key) { + data[key] = false; + } + + public bool Contains(int key) { + return data[key]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ for each function call. -* Space complexity: $O(1000000)$ since the key is in the range $[0, 1000000]$. +- Time complexity: $O(1)$ for each function call. +- Space complexity: $O(1000000)$ since the key is in the range $[0, 1000000]$. --- @@ -447,12 +495,64 @@ class MyHashSet { } ``` +```csharp +public class ListNode { + public int Key; + public ListNode Next; + + public ListNode(int key) { + Key = key; + Next = null; + } +} + +public class MyHashSet { + private ListNode[] set; + + public MyHashSet() { + set = new ListNode[10000]; + for (int i = 0; i < set.Length; i++) { + set[i] = new ListNode(0); // Dummy head + } + } + + public void Add(int key) { + ListNode cur = set[key % set.Length]; + while (cur.Next != null) { + if (cur.Next.Key == key) return; + cur = cur.Next; + } + cur.Next = new ListNode(key); + } + + public void Remove(int key) { + ListNode cur = set[key % set.Length]; + while (cur.Next != null) { + if (cur.Next.Key == key) { + cur.Next = cur.Next.Next; + return; + } + cur = cur.Next; + } + } + + public bool Contains(int key) { + ListNode cur = set[key % set.Length]; + while (cur.Next != null) { + if (cur.Next.Key == key) return true; + cur = cur.Next; + } + return false; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\frac{n}{k})$ for each function call. -* Space complexity: $O(k + m)$ +- Time complexity: $O(\frac{n}{k})$ for each function call. +- Space complexity: $O(k + m)$ > Where $n$ is the number of keys, $k$ is the size of the set ($10000$) and $m$ is the number of unique keys. @@ -813,7 +913,7 @@ class BST { return node; } - /** + /** * @param {number} key * @return {boolean} */ @@ -821,7 +921,7 @@ class BST { return this._search(this.root, key); } - /** + /** * @param {TreeNode} node * @param {number} key * @return {boolean} @@ -844,7 +944,7 @@ class MyHashSet { return key % this.size; } - /** + /** * @param {number} key * @return {void} */ @@ -855,7 +955,7 @@ class MyHashSet { } } - /** + /** * @param {number} key * @return {void} */ @@ -864,7 +964,7 @@ class MyHashSet { this.buckets[idx].remove(key); } - /** + /** * @param {number} key * @return {boolean} */ @@ -875,12 +975,113 @@ class MyHashSet { } ``` +```csharp +public class TreeNode { + public int Key; + public TreeNode Left; + public TreeNode Right; + + public TreeNode(int key) { + Key = key; + Left = null; + Right = null; + } +} + +public class BST { + public TreeNode Root; + + public TreeNode Insert(TreeNode root, int key) { + if (root == null) return new TreeNode(key); + if (key < root.Key) + root.Left = Insert(root.Left, key); + else if (key > root.Key) + root.Right = Insert(root.Right, key); + return root; + } + + public TreeNode Delete(TreeNode root, int key) { + if (root == null) return null; + if (key < root.Key) + root.Left = Delete(root.Left, key); + else if (key > root.Key) + root.Right = Delete(root.Right, key); + else { + if (root.Left == null) return root.Right; + if (root.Right == null) return root.Left; + TreeNode temp = MinValueNode(root.Right); + root.Key = temp.Key; + root.Right = Delete(root.Right, temp.Key); + } + return root; + } + + private TreeNode MinValueNode(TreeNode root) { + while (root.Left != null) + root = root.Left; + return root; + } + + public bool Search(TreeNode root, int key) { + if (root == null) return false; + if (key == root.Key) return true; + if (key < root.Key) return Search(root.Left, key); + return Search(root.Right, key); + } + + public void Add(int key) { + Root = Insert(Root, key); + } + + public void Remove(int key) { + Root = Delete(Root, key); + } + + public bool Contains(int key) { + return Search(Root, key); + } +} + +public class MyHashSet { + private const int Size = 10000; + private BST[] buckets; + + public MyHashSet() { + buckets = new BST[Size]; + for (int i = 0; i < Size; i++) { + buckets[i] = new BST(); + } + } + + private int Hash(int key) { + return key % Size; + } + + public void Add(int key) { + int idx = Hash(key); + if (!Contains(key)) { + buckets[idx].Add(key); + } + } + + public void Remove(int key) { + int idx = Hash(key); + buckets[idx].Remove(key); + } + + public bool Contains(int key) { + int idx = Hash(key); + return buckets[idx].Contains(key); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log (\frac{n}{k}))$ in average case, $O(\frac{n}{k})$ in worst case for each function call. -* Space complexity: $O(k + m)$ +- Time complexity: $O(\log (\frac{n}{k}))$ in average case, $O(\frac{n}{k})$ in worst case for each function call. +- Space complexity: $O(k + m)$ > Where $n$ is the number of keys, $k$ is the size of the set ($10000$) and $m$ is the number of unique keys. @@ -982,7 +1183,7 @@ class MyHashSet { this.set = new Array(31251).fill(0); } - /** + /** * @param {number} key * @return {void} */ @@ -990,7 +1191,7 @@ class MyHashSet { this.set[Math.floor(key / 32)] |= this.getMask(key); } - /** + /** * @param {number} key * @return {void} */ @@ -1000,7 +1201,7 @@ class MyHashSet { } } - /** + /** * @param {number} key * @return {boolean} */ @@ -1008,11 +1209,41 @@ class MyHashSet { return (this.set[Math.floor(key / 32)] & this.getMask(key)) !== 0; } - /** + /** * @param {number} key * @return {number} */ getMask(key) { + return 1 << key % 32; + } +} +``` + +```csharp +public class MyHashSet { + private int[] set; + + public MyHashSet() { + // key is in the range [1, 1000000] + // 31251 * 32 = 1000032 + set = new int[31251]; + } + + public void Add(int key) { + set[key / 32] |= GetMask(key); + } + + public void Remove(int key) { + if (Contains(key)) { + set[key / 32] ^= GetMask(key); + } + } + + public bool Contains(int key) { + return (set[key / 32] & GetMask(key)) != 0; + } + + private int GetMask(int key) { return 1 << (key % 32); } } @@ -1022,7 +1253,7 @@ class MyHashSet { ### Time & Space Complexity -* Time complexity: $O(1)$ for each function call. -* Space complexity: $O(k)$ +- Time complexity: $O(1)$ for each function call. +- Space complexity: $O(k)$ -> Where $k$ is the size of the set $(31251)$. \ No newline at end of file +> Where $k$ is the size of the set $(31251)$. diff --git a/articles/design-linked-list.md b/articles/design-linked-list.md new file mode 100644 index 000000000..c0e5df04b --- /dev/null +++ b/articles/design-linked-list.md @@ -0,0 +1,1262 @@ +## 1. Singly Linked List + +::tabs-start + +```python +class ListNode: + def __init__(self, val: int): + self.val = val + self.next = None + +class MyLinkedList: + def __init__(self): + self.head = ListNode(0) + self.size = 0 + + def get(self, index: int) -> int: + if index >= self.size: + return -1 + cur = self.head.next + for _ in range(index): + cur = cur.next + return cur.val + + def addAtHead(self, val: int) -> None: + node = ListNode(val) + node.next = self.head.next + self.head.next = node + self.size += 1 + + def addAtTail(self, val: int) -> None: + node = ListNode(val) + cur = self.head + while cur.next: + cur = cur.next + cur.next = node + self.size += 1 + + def addAtIndex(self, index: int, val: int) -> None: + if index > self.size: + return + cur = self.head + for _ in range(index): + cur = cur.next + node = ListNode(val) + node.next = cur.next + cur.next = node + self.size += 1 + + def deleteAtIndex(self, index: int) -> None: + if index >= self.size: + return + cur = self.head + for _ in range(index): + cur = cur.next + cur.next = cur.next.next + self.size -= 1 +``` + +```java +class ListNode { + int val; + ListNode next; + ListNode(int val) { + this.val = val; + this.next = null; + } +} + +public class MyLinkedList { + private ListNode head; + private int size; + MyLinkedList() { + head = new ListNode(0); + size = 0; + } + public int get(int index) { + if (index >= size) return -1; + ListNode cur = head.next; + for (int i = 0; i < index; i++) { + cur = cur.next; + } + return cur.val; + } + public void addAtHead(int val) { + ListNode node = new ListNode(val); + node.next = head.next; + head.next = node; + size++; + } + public void addAtTail(int val) { + ListNode node = new ListNode(val); + ListNode cur = head; + while (cur.next != null) { + cur = cur.next; + } + cur.next = node; + size++; + } + public void addAtIndex(int index, int val) { + if (index > size) return; + ListNode cur = head; + for (int i = 0; i < index; i++) { + cur = cur.next; + } + ListNode node = new ListNode(val); + node.next = cur.next; + cur.next = node; + size++; + } + public void deleteAtIndex(int index) { + if (index >= size) return; + ListNode cur = head; + for (int i = 0; i < index; i++) { + cur = cur.next; + } + cur.next = cur.next.next; + size--; + } +} +``` + +```cpp +class MyLinkedList { + struct ListNode { + int val; + ListNode* next; + ListNode(int val) : val(val), next(nullptr) {} + }; + +public: + ListNode* head; + int size; + MyLinkedList() { + head = new ListNode(0); + size = 0; + } + int get(int index) { + if (index >= size) return -1; + ListNode* cur = head->next; + for (int i = 0; i < index; i++) { + cur = cur->next; + } + return cur->val; + } + void addAtHead(int val) { + ListNode* node = new ListNode(val); + node->next = head->next; + head->next = node; + size++; + } + void addAtTail(int val) { + ListNode* node = new ListNode(val); + ListNode* cur = head; + while (cur->next != nullptr) { + cur = cur->next; + } + cur->next = node; + size++; + } + void addAtIndex(int index, int val) { + if (index > size) return; + ListNode* cur = head; + for (int i = 0; i < index; i++) { + cur = cur->next; + } + ListNode* node = new ListNode(val); + node->next = cur->next; + cur->next = node; + size++; + } + void deleteAtIndex(int index) { + if (index >= size) return; + ListNode* cur = head; + for (int i = 0; i < index; i++) { + cur = cur->next; + } + ListNode* temp = cur->next; + cur->next = cur->next->next; + delete temp; + size--; + } +}; +``` + +```javascript +class ListNode { + /** + * @constructor + * @param {number} val + */ + constructor(val) { + this.val = val; + this.next = null; + } +} + +class MyLinkedList { + constructor() { + this.head = new ListNode(0); + this.size = 0; + } + + /** + * @param {number} index + * @return {number} + */ + get(index) { + if (index >= this.size) return -1; + let cur = this.head.next; + for (let i = 0; i < index; i++) { + cur = cur.next; + } + return cur.val; + } + + /** + * @param {number} val + * @return {void} + */ + addAtHead(val) { + const node = new ListNode(val); + node.next = this.head.next; + this.head.next = node; + this.size++; + } + + /** + * @param {number} val + * @return {void} + */ + addAtTail(val) { + const node = new ListNode(val); + let cur = this.head; + while (cur.next !== null) { + cur = cur.next; + } + cur.next = node; + this.size++; + } + + /** + * @param {number} index + * @param {number} val + * @return {void} + */ + addAtIndex(index, val) { + if (index > this.size) return; + let cur = this.head; + for (let i = 0; i < index; i++) { + cur = cur.next; + } + const node = new ListNode(val); + node.next = cur.next; + cur.next = node; + this.size++; + } + + /** + * @param {number} index + * @return {void} + */ + deleteAtIndex(index) { + if (index >= this.size) return; + let cur = this.head; + for (let i = 0; i < index; i++) { + cur = cur.next; + } + cur.next = cur.next.next; + this.size--; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for $addAtHead()$. + - $O(n)$ time for $get()$, $addAtTail()$, $addAtIndex()$, $deleteAtIndex()$. +- Space complexity: $O(n)$ + +--- + +## 2. Singly Linked List (Optimal) + +::tabs-start + +```python +class ListNode: + def __init__(self, val=0, next=None): + self.val = val + self.next = next + +class MyLinkedList: + def __init__(self): + self.head = ListNode(0) + self.size = 0 + + def getPrev(self, index: int) -> ListNode: + cur = self.head + for _ in range(index): + cur = cur.next + return cur + + def get(self, index: int) -> int: + if index >= self.size: + return -1 + return self.getPrev(index).next.val + + def addAtHead(self, val: int) -> None: + self.addAtIndex(0, val) + + def addAtTail(self, val: int) -> None: + self.addAtIndex(self.size, val) + + def addAtIndex(self, index: int, val: int) -> None: + if index > self.size: + return + prev = self.getPrev(index) + node = ListNode(val, prev.next) + prev.next = node + self.size += 1 + + def deleteAtIndex(self, index: int) -> None: + if index >= self.size: + return + prev = self.getPrev(index) + prev.next = prev.next.next + self.size -= 1 +``` + +```java +class ListNode { + int val; + ListNode next; + ListNode(int val, ListNode next) { + this.val = val; + this.next = next; + } + ListNode(int val) { + this(val, null); + } +} + +public class MyLinkedList { + ListNode head; + int size; + + public MyLinkedList() { + head = new ListNode(0, null); + size = 0; + } + + private ListNode getPrev(int index) { + ListNode cur = head; + for (int i = 0; i < index; i++) { + cur = cur.next; + } + return cur; + } + + public int get(int index) { + if (index >= size) { + return -1; + } + return getPrev(index).next.val; + } + + public void addAtHead(int val) { + addAtIndex(0, val); + } + + public void addAtTail(int val) { + addAtIndex(size, val); + } + + public void addAtIndex(int index, int val) { + if (index > size) { + return; + } + ListNode prev = getPrev(index); + ListNode node = new ListNode(val, prev.next); + prev.next = node; + size++; + } + + public void deleteAtIndex(int index) { + if (index >= size) { + return; + } + ListNode prev = getPrev(index); + prev.next = prev.next.next; + size--; + } +} +``` + +```cpp + +class MyLinkedList { + struct ListNode { + int val; + ListNode* next; + ListNode(int val, ListNode* next) : val(val), next(next) {} + ListNode(int val) : val(val), next(nullptr) {} + }; + +public: + MyLinkedList() { + head = new ListNode(0, nullptr); + size = 0; + } + + int get(int index) { + if (index >= size) return -1; + return getPrev(index)->next->val; + } + + void addAtHead(int val) { + addAtIndex(0, val); + } + + void addAtTail(int val) { + addAtIndex(size, val); + } + + void addAtIndex(int index, int val) { + if (index > size) return; + ListNode* prev = getPrev(index); + ListNode* node = new ListNode(val, prev->next); + prev->next = node; + size++; + } + + void deleteAtIndex(int index) { + if (index >= size) return; + ListNode* prev = getPrev(index); + ListNode* toDelete = prev->next; + prev->next = prev->next->next; + delete toDelete; + size--; + } + +private: + ListNode* head; + int size; + + ListNode* getPrev(int index) { + ListNode* cur = head; + for (int i = 0; i < index; i++) { + cur = cur->next; + } + return cur; + } +}; +``` + +```javascript +class ListNode { + /** + * @constructor + * @param {number} + * @param {ListNode|null} + */ + constructor(val = 0, next = null) { + this.val = val; + this.next = next; + } +} + +class MyLinkedList { + constructor() { + this.head = new ListNode(0); + this.size = 0; + } + + /** + * @param {number} index + * @return {ListNode} + */ + getPrev(index) { + let cur = this.head; + for (let i = 0; i < index; i++) { + cur = cur.next; + } + return cur; + } + + /** + * @param {number} index + * @return {number} + */ + get(index) { + if (index >= this.size) { + return -1; + } + return this.getPrev(index).next.val; + } + + /** + * @param {number} val + * @return {void} + */ + addAtHead(val) { + this.addAtIndex(0, val); + } + + /** + * @param {number} val + * @return {void} + */ + addAtTail(val) { + this.addAtIndex(this.size, val); + } + + /** + * @param {number} index + * @param {number} val + * @return {void} + */ + addAtIndex(index, val) { + if (index > this.size) { + return; + } + let prev = this.getPrev(index); + let node = new ListNode(val, prev.next); + prev.next = node; + this.size++; + } + + /** + * @param {number} index + * @return {void} + */ + deleteAtIndex(index) { + if (index >= this.size) { + return; + } + let prev = this.getPrev(index); + prev.next = prev.next.next; + this.size--; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for $addAtHead()$. + - $O(n)$ time for $get()$, $addAtTail()$, $addAtIndex()$, $deleteAtIndex()$. +- Space complexity: $O(n)$ + +--- + +## 3. Doubly Linked List + +::tabs-start + +```python +class ListNode: + def __init__(self, val): + self.val = val + self.prev = None + self.next = None + +class MyLinkedList: + + def __init__(self): + self.head = ListNode(0) + self.tail = ListNode(0) + self.head.next = self.tail + self.tail.prev = self.head + + def get(self, index: int) -> int: + cur = self.head.next + while cur and index > 0: + cur = cur.next + index -= 1 + if cur and cur != self.tail and index == 0: + return cur.val + return -1 + + def addAtHead(self, val: int) -> None: + node, next, prev = ListNode(val), self.head.next, self.head + prev.next = node + next.prev = node + node.next = next + node.prev = prev + + def addAtTail(self, val: int) -> None: + node, next, prev = ListNode(val), self.tail, self.tail.prev + prev.next = node + next.prev = node + node.next = next + node.prev = prev + + def addAtIndex(self, index: int, val: int) -> None: + cur = self.head.next + while cur and index > 0: + cur = cur.next + index -= 1 + if cur and index == 0: + node, next, prev = ListNode(val), cur, cur.prev + prev.next = node + next.prev = node + node.next = next + node.prev = prev + + + def deleteAtIndex(self, index: int) -> None: + cur = self.head.next + while cur and index > 0: + cur = cur.next + index -= 1 + if cur and cur != self.tail and index == 0: + next, prev = cur.next, cur.prev + next.prev = prev + prev.next = next +``` + +```java +class ListNode { + int val; + ListNode prev; + ListNode next; + + ListNode(int val) { + this.val = val; + this.prev = null; + this.next = null; + } +} + +public class MyLinkedList { + ListNode head; + ListNode tail; + + MyLinkedList() { + head = new ListNode(0); + tail = new ListNode(0); + head.next = tail; + tail.prev = head; + } + + int get(int index) { + ListNode cur = head.next; + while (cur != null && index > 0) { + cur = cur.next; + index--; + } + if (cur != null && cur != tail && index == 0) { + return cur.val; + } + return -1; + } + + void addAtHead(int val) { + ListNode node = new ListNode(val); + ListNode next = head.next; + ListNode prev = head; + prev.next = node; + next.prev = node; + node.next = next; + node.prev = prev; + } + + void addAtTail(int val) { + ListNode node = new ListNode(val); + ListNode next = tail; + ListNode prev = tail.prev; + prev.next = node; + next.prev = node; + node.next = next; + node.prev = prev; + } + + void addAtIndex(int index, int val) { + ListNode cur = head.next; + while (cur != null && index > 0) { + cur = cur.next; + index--; + } + if (cur != null && index == 0) { + ListNode node = new ListNode(val); + ListNode next = cur; + ListNode prev = cur.prev; + prev.next = node; + next.prev = node; + node.next = next; + node.prev = prev; + } + } + + void deleteAtIndex(int index) { + ListNode cur = head.next; + while (cur != null && index > 0) { + cur = cur.next; + index--; + } + if (cur != null && cur != tail && index == 0) { + ListNode next = cur.next; + ListNode prev = cur.prev; + next.prev = prev; + prev.next = next; + } + } +} +``` + +```cpp +class MyLinkedList { + struct ListNode { + int val; + ListNode* prev; + ListNode* next; + ListNode(int val) : val(val), prev(nullptr), next(nullptr) {} + }; +public: + ListNode* head; + ListNode* tail; + + MyLinkedList() { + head = new ListNode(0); + tail = new ListNode(0); + head->next = tail; + tail->prev = head; + } + + int get(int index) { + ListNode* cur = head->next; + while (cur && index > 0) { + cur = cur->next; + index--; + } + if (cur && cur != tail && index == 0) { + return cur->val; + } + return -1; + } + + void addAtHead(int val) { + ListNode* node = new ListNode(val); + ListNode* next = head->next; + ListNode* prev = head; + prev->next = node; + next->prev = node; + node->next = next; + node->prev = prev; + } + + void addAtTail(int val) { + ListNode* node = new ListNode(val); + ListNode* next = tail; + ListNode* prev = tail->prev; + prev->next = node; + next->prev = node; + node->next = next; + node->prev = prev; + } + + void addAtIndex(int index, int val) { + ListNode* cur = head->next; + while (cur && index > 0) { + cur = cur->next; + index--; + } + if (cur && index == 0) { + ListNode* node = new ListNode(val); + ListNode* next = cur; + ListNode* prev = cur->prev; + prev->next = node; + next->prev = node; + node->next = next; + node->prev = prev; + } + } + + void deleteAtIndex(int index) { + ListNode* cur = head->next; + while (cur && index > 0) { + cur = cur->next; + index--; + } + if (cur && cur != tail && index == 0) { + ListNode* next = cur->next; + ListNode* prev = cur->prev; + next->prev = prev; + prev->next = next; + delete cur; + } + } +}; +``` + +```javascript +class ListNode { + /** + * @constructor + * @param {number} val + */ + constructor(val) { + this.val = val; + this.prev = null; + this.next = null; + } +} + +class MyLinkedList { + constructor() { + this.head = new ListNode(0); + this.tail = new ListNode(0); + this.head.next = this.tail; + this.tail.prev = this.head; + } + + /** + * @param {number} index + * @return {number} + */ + get(index) { + let cur = this.head.next; + while (cur && index > 0) { + cur = cur.next; + index--; + } + if (cur && cur !== this.tail && index === 0) { + return cur.val; + } + return -1; + } + + /** + * @param {number} val + * @return {void} + */ + addAtHead(val) { + const node = new ListNode(val); + const next = this.head.next; + const prev = this.head; + prev.next = node; + next.prev = node; + node.next = next; + node.prev = prev; + } + + /** + * @param {number} val + * @return {void} + */ + addAtTail(val) { + const node = new ListNode(val); + const next = this.tail; + const prev = this.tail.prev; + prev.next = node; + next.prev = node; + node.next = next; + node.prev = prev; + } + + /** + * @param {number} index + * @param {number} val + * @return {void} + */ + addAtIndex(index, val) { + let cur = this.head.next; + while (cur && index > 0) { + cur = cur.next; + index--; + } + if (cur && index === 0) { + const node = new ListNode(val); + const next = cur; + const prev = cur.prev; + prev.next = node; + next.prev = node; + node.next = next; + node.prev = prev; + } + } + + /** + * @param {number} index + * @return {void} + */ + deleteAtIndex(index) { + let cur = this.head.next; + while (cur && index > 0) { + cur = cur.next; + index--; + } + if (cur && cur !== this.tail && index === 0) { + const next = cur.next; + const prev = cur.prev; + next.prev = prev; + prev.next = next; + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for $addAtHead()$, $addAtTail()$. + - $O(n)$ time for $get()$, $addAtIndex()$, $deleteAtIndex()$. +- Space complexity: $O(n)$ + +--- + +## 4. Doubly Linked List (Optimal) + +::tabs-start + +```python +class ListNode: + def __init__(self, val=0, next=None, prev=None): + self.val = val + self.next = next + self.prev = prev + +class MyLinkedList: + def __init__(self): + self.head = ListNode(0) + self.tail = ListNode(0) + self.head.next = self.tail + self.tail.prev = self.head + self.size = 0 + + def getPrev(self, index: int) -> ListNode: + if index <= self.size // 2: + cur = self.head + for _ in range(index): + cur = cur.next + else: + cur = self.tail + for _ in range(self.size - index + 1): + cur = cur.prev + return cur + + def get(self, index: int) -> int: + if index >= self.size: + return -1 + return self.getPrev(index).next.val + + def addAtHead(self, val: int) -> None: + self.addAtIndex(0, val) + + def addAtTail(self, val: int) -> None: + self.addAtIndex(self.size, val) + + def addAtIndex(self, index: int, val: int) -> None: + if index > self.size: + return + node = ListNode(val) + prev = self.getPrev(index) + next = prev.next + prev.next = node + node.prev = prev + node.next = next + next.prev = node + self.size += 1 + + def deleteAtIndex(self, index: int) -> None: + if index >= self.size: + return + prev = self.getPrev(index) + cur = prev.next + next = cur.next + prev.next = next + next.prev = prev + self.size -= 1 +``` + +```java +class ListNode { + int val; + ListNode next; + ListNode prev; + + ListNode(int val) { + this(val, null, null); + } + + ListNode(int val, ListNode next, ListNode prev) { + this.val = val; + this.next = next; + this.prev = prev; + } +} + +public class MyLinkedList { + ListNode head; + ListNode tail; + int size; + + public MyLinkedList() { + head = new ListNode(0); + tail = new ListNode(0); + head.next = tail; + tail.prev = head; + size = 0; + } + + private ListNode getPrev(int index) { + if (index <= size / 2) { + ListNode cur = head; + for (int i = 0; i < index; i++) { + cur = cur.next; + } + return cur; + } else { + ListNode cur = tail; + for (int i = 0; i < size - index + 1; i++) { + cur = cur.prev; + } + return cur; + } + } + + public int get(int index) { + if (index >= size) return -1; + return getPrev(index).next.val; + } + + public void addAtHead(int val) { + addAtIndex(0, val); + } + + public void addAtTail(int val) { + addAtIndex(size, val); + } + + public void addAtIndex(int index, int val) { + if (index > size) return; + ListNode node = new ListNode(val); + ListNode prev = getPrev(index); + ListNode next = prev.next; + prev.next = node; + node.prev = prev; + node.next = next; + next.prev = node; + size++; + } + + public void deleteAtIndex(int index) { + if (index >= size) return; + ListNode prev = getPrev(index); + ListNode cur = prev.next; + ListNode next = cur.next; + prev.next = next; + next.prev = prev; + size--; + } +} +``` + +```cpp +class MyLinkedList { + struct ListNode { + int val; + ListNode* next; + ListNode* prev; + ListNode(int val = 0, ListNode* next = nullptr, ListNode* prev = nullptr) { + this->val = val; + this->next = next; + this->prev = prev; + } + }; + +public: + ListNode* head; + ListNode* tail; + int size; + + MyLinkedList() { + head = new ListNode(0); + tail = new ListNode(0); + head->next = tail; + tail->prev = head; + size = 0; + } + + ListNode* getPrev(int index) { + if (index <= size / 2) { + ListNode* cur = head; + for (int i = 0; i < index; i++) { + cur = cur->next; + } + return cur; + } else { + ListNode* cur = tail; + for (int i = 0; i < size - index + 1; i++) { + cur = cur->prev; + } + return cur; + } + } + + int get(int index) { + if (index >= size) return -1; + return getPrev(index)->next->val; + } + + void addAtHead(int val) { + addAtIndex(0, val); + } + + void addAtTail(int val) { + addAtIndex(size, val); + } + + void addAtIndex(int index, int val) { + if (index > size) return; + ListNode* node = new ListNode(val); + ListNode* prev = getPrev(index); + ListNode* next = prev->next; + prev->next = node; + node->prev = prev; + node->next = next; + next->prev = node; + size++; + } + + void deleteAtIndex(int index) { + if (index >= size) return; + ListNode* prev = getPrev(index); + ListNode* cur = prev->next; + ListNode* next = cur->next; + prev->next = next; + next->prev = prev; + delete cur; + size--; + } +}; +``` + +```javascript +class ListNode { + /** + * @constructor + * @param {number} + * @param {ListNode|null} + * @param {ListNode|null} + */ + constructor(val = 0, next = null, prev = null) { + this.val = val; + this.next = next; + this.prev = prev; + } +} + +class MyLinkedList { + constructor() { + this.head = new ListNode(0); + this.tail = new ListNode(0); + this.head.next = this.tail; + this.tail.prev = this.head; + this.size = 0; + } + + /** + * @param {number} index + * @return {ListNode} + */ + getPrev(index) { + let cur; + if (index <= this.size / 2) { + cur = this.head; + for (let i = 0; i < index; i++) { + cur = cur.next; + } + } else { + cur = this.tail; + for (let i = 0; i < this.size - index + 1; i++) { + cur = cur.prev; + } + } + return cur; + } + + /** + * @param {number} index + * @return {number} + */ + get(index) { + if (index >= this.size) { + return -1; + } + return this.getPrev(index).next.val; + } + + /** + * @param {number} val + * @return {void} + */ + addAtHead(val) { + this.addAtIndex(0, val); + } + + /** + * @param {number} val + * @return {void} + */ + addAtTail(val) { + this.addAtIndex(this.size, val); + } + + /** + * @param {number} index + * @param {number} val + * @return {void} + */ + addAtIndex(index, val) { + if (index > this.size) { + return; + } + const node = new ListNode(val); + const prev = this.getPrev(index); + const next = prev.next; + prev.next = node; + node.prev = prev; + node.next = next; + next.prev = node; + this.size++; + } + + /** + * @param {number} index + * @return {void} + */ + deleteAtIndex(index) { + if (index >= this.size) { + return; + } + const prev = this.getPrev(index); + const cur = prev.next; + const next = cur.next; + prev.next = next; + next.prev = prev; + this.size--; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for $addAtHead()$, $addAtTail()$. + - $O(n)$ time for $get()$, $addAtIndex()$, $deleteAtIndex()$. +- Space complexity: $O(n)$ diff --git a/articles/design-parking-system.md b/articles/design-parking-system.md new file mode 100644 index 000000000..907eee766 --- /dev/null +++ b/articles/design-parking-system.md @@ -0,0 +1,167 @@ +## 1. Array - I + +::tabs-start + +```python +class ParkingSystem: + + def __init__(self, big: int, medium: int, small: int): + self.spaces = [big, medium, small] + + def addCar(self, carType: int) -> bool: + if self.spaces[carType - 1] > 0: + self.spaces[carType - 1] -= 1 + return True + return False +``` + +```java +public class ParkingSystem { + private int[] spaces; + + public ParkingSystem(int big, int medium, int small) { + spaces = new int[]{big, medium, small}; + } + + public boolean addCar(int carType) { + if (spaces[carType - 1] > 0) { + spaces[carType - 1]--; + return true; + } + return false; + } +} +``` + +```cpp +class ParkingSystem { + int spaces[3]; + +public: + ParkingSystem(int big, int medium, int small) { + spaces[0] = big; + spaces[1] = medium; + spaces[2] = small; + } + + bool addCar(int carType) { + if (spaces[carType - 1] > 0) { + spaces[carType - 1]--; + return true; + } + return false; + } +}; +``` + +```javascript +class ParkingSystem { + /** + * @constructor + * @param {number} big + * @param {number} medium + * @param {number} small + */ + constructor(big, medium, small) { + this.spaces = [big, medium, small]; + } + + /** + * @param {number} carType + * @return {boolean} + */ + addCar(carType) { + if (this.spaces[carType - 1] > 0) { + this.spaces[carType - 1]--; + return true; + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $addCar()$ function call. +- Space complexity: $O(1)$ + +--- + +## 2. Array - II + +::tabs-start + +```python +class ParkingSystem: + + def __init__(self, big: int, medium: int, small: int): + self.spaces = [big, medium, small] + + def addCar(self, carType: int) -> bool: + self.spaces[carType - 1] -= 1 + return self.spaces[carType - 1] >= 0 +``` + +```java +public class ParkingSystem { + int[] spaces; + + public ParkingSystem(int big, int medium, int small) { + spaces = new int[]{big, medium, small}; + } + + public boolean addCar(int carType) { + return spaces[carType - 1]-- > 0; + } +} +``` + +```cpp +class ParkingSystem { + int spaces[3]; + +public: + ParkingSystem(int big, int medium, int small) { + spaces[0] = big, spaces[1] = medium, spaces[2] = small; + } + + bool addCar(int carType) { + return spaces[carType - 1]-- > 0; + } +}; +``` + +```javascript +class ParkingSystem { + /** + * @constructor + * @param {number} big + * @param {number} medium + * @param {number} small + */ + constructor(big, medium, small) { + this.spaces = [big, medium, small]; + } + + /** + * @param {number} carType + * @return {boolean} + */ + addCar(carType) { + return this.spaces[carType - 1]-- > 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $addCar()$ function call. +- Space complexity: $O(1)$ diff --git a/articles/design-twitter-feed.md b/articles/design-twitter-feed.md index 2c53e29a8..cfc516627 100644 --- a/articles/design-twitter-feed.md +++ b/articles/design-twitter-feed.md @@ -19,7 +19,7 @@ class Twitter: for followeeId in self.followMap[userId]: feed.extend(self.tweetMap[followeeId]) - feed.sort(key=lambda x: -x[0]) + feed.sort(key=lambda x: -x[0]) return [tweetId for _, tweetId in feed[:10]] def follow(self, followerId: int, followeeId: int) -> None: @@ -88,7 +88,7 @@ public: vector getNewsFeed(int userId) { vector> feed = tweetMap[userId]; for (int followeeId : followMap[userId]) { - feed.insert(feed.end(), tweetMap[followeeId].begin(), + feed.insert(feed.end(), tweetMap[followeeId].begin(), tweetMap[followeeId].end()); } sort(feed.begin(), feed.end(), [](auto &a, auto &b) { @@ -137,11 +137,11 @@ class Twitter { */ getNewsFeed(userId) { let feed = [...(this.tweetMap.get(userId) || [])]; - (this.followMap.get(userId) || new Set()).forEach(followeeId => { + (this.followMap.get(userId) || new Set()).forEach((followeeId) => { feed.push(...(this.tweetMap.get(followeeId) || [])); }); feed.sort((a, b) => b[0] - a[0]); - return feed.slice(0, 10).map(x => x[1]); + return feed.slice(0, 10).map((x) => x[1]); } /** @@ -151,7 +151,8 @@ class Twitter { */ follow(followerId, followeeId) { if (followerId !== followeeId) { - if (!this.followMap.has(followerId)) this.followMap.set(followerId, new Set()); + if (!this.followMap.has(followerId)) + this.followMap.set(followerId, new Set()); this.followMap.get(followerId).add(followeeId); } } @@ -246,17 +247,17 @@ func (this *Twitter) PostTweet(userId int, tweetId int) { func (this *Twitter) GetNewsFeed(userId int) []int { feed := make([]Tweet, 0) feed = append(feed, this.tweetMap[userId]...) - + if follows, ok := this.followMap[userId]; ok { for followeeId := range follows { feed = append(feed, this.tweetMap[followeeId]...) } } - + sort.Slice(feed, func(i, j int) bool { return feed[i].time > feed[j].time }) - + result := make([]int, 0) for i := 0; i < len(feed) && i < 10; i++ { result = append(result, feed[i].tweetId) @@ -285,7 +286,7 @@ class Twitter { private var time = 0 private val followMap = HashMap>() private val tweetMap = HashMap>>() - + fun postTweet(userId: Int, tweetId: Int) { if (!tweetMap.containsKey(userId)) { tweetMap[userId] = mutableListOf() @@ -293,19 +294,19 @@ class Twitter { tweetMap[userId]?.add(Pair(time, tweetId)) time++ } - + fun getNewsFeed(userId: Int): List { val feed = mutableListOf>() tweetMap[userId]?.let { feed.addAll(it) } followMap[userId]?.forEach { followeeId -> tweetMap[followeeId]?.let { feed.addAll(it) } } - + return feed.sortedByDescending { it.first } .take(10) .map { it.second } } - + fun follow(followerId: Int, followeeId: Int) { if (followerId != followeeId) { if (!followMap.containsKey(followerId)) { @@ -314,19 +315,64 @@ class Twitter { followMap[followerId]?.add(followeeId) } } - + fun unfollow(followerId: Int, followeeId: Int) { followMap[followerId]?.remove(followeeId) } } ``` +```swift +class Twitter { + private var time: Int + private var followMap: [Int: Set] + private var tweetMap: [Int: [(Int, Int)]] + + init() { + self.time = 0 + self.followMap = [:] + self.tweetMap = [:] + } + + func postTweet(_ userId: Int, _ tweetId: Int) { + if tweetMap[userId] == nil { + tweetMap[userId] = [] + } + tweetMap[userId]!.append((time, tweetId)) + time += 1 + } + + func getNewsFeed(_ userId: Int) -> [Int] { + var feed = tweetMap[userId] ?? [] + if let followees = followMap[userId] { + for followeeId in followees { + if let tweets = tweetMap[followeeId] { + feed.append(contentsOf: tweets) + } + } + } + feed.sort { $0.0 > $1.0 } + return feed.prefix(10).map { $0.1 } + } + + func follow(_ followerId: Int, _ followeeId: Int) { + if followerId != followeeId { + followMap[followerId, default: Set()].insert(followeeId) + } + } + + func unfollow(_ followerId: Int, _ followeeId: Int) { + followMap[followerId]?.remove(followeeId) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m + t\log t)$ for each $getNewsFeed()$ call and $O(1)$ for remaining methods. -* Space complexity: $O(N * m + N * M)$ +- Time complexity: $O(n * m + t\log t)$ for each $getNewsFeed()$ call and $O(1)$ for remaining methods. +- Space complexity: $O(N * m + N * M)$ > Where $n$ is the total number of $followeeIds$ associated with the $userId$, $m$ is the maximum number of tweets by any user, $t$ is the total number of tweets associated with the $userId$ and its $followeeIds$, $N$ is the total number of $userIds$ and $M$ is the maximum number of followees for any user. @@ -376,7 +422,7 @@ class Twitter: ```java public class Twitter { - + private int count; private Map> tweetMap; private Map> followMap; @@ -486,13 +532,14 @@ public: ```javascript /** - * const { MaxPriorityQueue } = require('@datastructures-js/priority-queue'); + * const { PriorityQueue } = require('@datastructures-js/priority-queue'); */ class Twitter { constructor() { - this.users = new Map(); - this.timestamp = 0; + this.count = 0; + this.tweetMap = new Map(); // userId -> array of [count, tweetId] + this.followMap = new Map(); // userId -> set of followeeIds } /** @@ -501,13 +548,11 @@ class Twitter { * @return {void} */ postTweet(userId, tweetId) { - if (!this.users.has(userId)) { - this.users.set(userId, { tweets: [], following: new Set() }); + if (!this.tweetMap.has(userId)) { + this.tweetMap.set(userId, []); } - this.users - .get(userId) - .tweets.push({ timestamp: this.timestamp, tweetId }); - this.timestamp += 1; + this.tweetMap.get(userId).push([this.count, tweetId]); + this.count -= 1; } /** @@ -515,38 +560,38 @@ class Twitter { * @return {number[]} */ getNewsFeed(userId) { - if (!this.users.has(userId)) { - return []; + const res = []; + if (!this.followMap.has(userId)) { + this.followMap.set(userId, new Set()); } - - const maxPQ = new MaxPriorityQueue(tweet => tweet.timestamp); - const seenTweets = new Set(); - - const user = this.users.get(userId); - user.tweets.forEach(tweet => { - if (!seenTweets.has(tweet.tweetId)) { - maxPQ.enqueue(tweet); - seenTweets.add(tweet.tweetId); + this.followMap.get(userId).add(userId); + const minHeap = new PriorityQueue((a, b) => a[0] - b[0]); + + for (const followeeId of this.followMap.get(userId)) { + if (this.tweetMap.has(followeeId)) { + const tweets = this.tweetMap.get(followeeId); + const index = tweets.length - 1; + const [count, tweetId] = tweets[index]; + minHeap.enqueue([count, tweetId, followeeId, index - 1]); } - }); + } - user.following.forEach(followeeId => { - if (this.users.has(followeeId)) { - this.users.get(followeeId).tweets.forEach(tweet => { - if (!seenTweets.has(tweet.tweetId)) { - maxPQ.enqueue(tweet); - seenTweets.add(tweet.tweetId); - } - }); + while (!minHeap.isEmpty() && res.length < 10) { + const [count, tweetId, followeeId, nextIndex] = minHeap.dequeue(); + res.push(tweetId); + if (nextIndex >= 0) { + const [olderCount, olderTweetId] = + this.tweetMap.get(followeeId)[nextIndex]; + minHeap.enqueue([ + olderCount, + olderTweetId, + followeeId, + nextIndex - 1, + ]); } - }); - - const newsFeed = []; - for (let i = 0; i < 10 && !maxPQ.isEmpty(); i++) { - newsFeed.push(maxPQ.dequeue().tweetId); } - return newsFeed; + return res; } /** @@ -555,10 +600,10 @@ class Twitter { * @return {void} */ follow(followerId, followeeId) { - if (!this.users.has(followerId)) { - this.users.set(followerId, { tweets: [], following: new Set() }); + if (!this.followMap.has(followerId)) { + this.followMap.set(followerId, new Set()); } - this.users.get(followerId).following.add(followeeId); + this.followMap.get(followerId).add(followeeId); } /** @@ -567,8 +612,8 @@ class Twitter { * @return {void} */ unfollow(followerId, followeeId) { - if (this.users.has(followerId)) { - this.users.get(followerId).following.delete(followeeId); + if (this.followMap.has(followerId)) { + this.followMap.get(followerId).delete(followeeId); } } } @@ -664,16 +709,16 @@ func (this *Twitter) PostTweet(userId int, tweetId int) { func (this *Twitter) GetNewsFeed(userId int) []int { res := make([]int, 0) - + minHeap := priorityqueue.NewWith(func(a, b interface{}) int { return a.([]int)[0] - b.([]int)[0] }) - + if this.followMap[userId] == nil { this.followMap[userId] = make(map[int]bool) } this.followMap[userId][userId] = true - + for followeeId := range this.followMap[userId] { tweets := this.tweetMap[followeeId] if len(tweets) > 0 { @@ -682,21 +727,21 @@ func (this *Twitter) GetNewsFeed(userId int) []int { minHeap.Enqueue([]int{count, tweetId, followeeId, index - 1}) } } - + for minHeap.Size() > 0 && len(res) < 10 { item, _ := minHeap.Dequeue() curr := item.([]int) count, tweetId, followeeId, index := curr[0], curr[1], curr[2], curr[3] - + res = append(res, tweetId) - + if index >= 0 { tweets := this.tweetMap[followeeId] count, tweetId = tweets[index][0], tweets[index][1] minHeap.Enqueue([]int{count, tweetId, followeeId, index - 1}) } } - + return res } @@ -719,7 +764,7 @@ class Twitter { private var count = 0 private val tweetMap = HashMap>() // userId -> list of [count, tweetId] private val followMap = HashMap>() // userId -> set of followeeId - + fun postTweet(userId: Int, tweetId: Int) { if (!tweetMap.containsKey(userId)) { tweetMap[userId] = mutableListOf() @@ -727,16 +772,16 @@ class Twitter { tweetMap[userId]?.add(intArrayOf(count, tweetId)) count-- } - + fun getNewsFeed(userId: Int): List { val res = mutableListOf() val minHeap = PriorityQueue(compareBy { it[0] }) - + if (!followMap.containsKey(userId)) { followMap[userId] = HashSet() } followMap[userId]?.add(userId) - + followMap[userId]?.forEach { followeeId -> tweetMap[followeeId]?.let { tweets -> if (tweets.isNotEmpty()) { @@ -746,39 +791,878 @@ class Twitter { } } } - + while (minHeap.isNotEmpty() && res.size < 10) { val (count, tweetId, followeeId, index) = minHeap.poll() res.add(tweetId) - + if (index >= 0) { val tweets = tweetMap[followeeId]!! val (nextCount, nextTweetId) = tweets[index] minHeap.add(intArrayOf(nextCount, nextTweetId, followeeId, index - 1)) } } - + return res } - + fun follow(followerId: Int, followeeId: Int) { if (!followMap.containsKey(followerId)) { followMap[followerId] = HashSet() } followMap[followerId]?.add(followeeId) } - + fun unfollow(followerId: Int, followeeId: Int) { followMap[followerId]?.remove(followeeId) } } ``` +```swift +class Twitter { + private var count: Int + private var tweetMap: [Int: [(Int, Int)]] // userId -> list of (count, tweetId) + private var followMap: [Int: Set] // userId -> set of followeeId + + init() { + self.count = 0 + self.tweetMap = [:] + self.followMap = [:] + } + + func postTweet(_ userId: Int, _ tweetId: Int) { + tweetMap[userId, default: []].append((count, tweetId)) + count -= 1 + } + + func getNewsFeed(_ userId: Int) -> [Int] { + var res = [Int]() + var minHeap = Heap() + + followMap[userId, default: Set()].insert(userId) + if let followees = followMap[userId] { + for followee in followees { + if let tweets = tweetMap[followee], !tweets.isEmpty { + let index = tweets.count - 1 + let (cnt, tweetId) = tweets[index] + minHeap.insert( + Item( + count: cnt, tweetId: tweetId, + followeeId: followee, index: index - 1 + ) + ) + } + } + } + + while !minHeap.isEmpty && res.count < 10 { + let entry = minHeap.popMin()! + res.append(entry.tweetId) + if entry.index >= 0, let tweets = tweetMap[entry.followeeId] { + let (cnt, tweetId) = tweets[entry.index] + minHeap.insert( + Item( + count: cnt, tweetId: tweetId, + followeeId: entry.followeeId, index: entry.index - 1 + ) + ) + } + } + return res + } + + func follow(_ followerId: Int, _ followeeId: Int) { + followMap[followerId, default: Set()].insert(followeeId) + } + + func unfollow(_ followerId: Int, _ followeeId: Int) { + followMap[followerId]?.remove(followeeId) + } +} + +struct Item: Comparable { + let count: Int + let tweetId: Int + let followeeId: Int + let index: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.count < rhs.count + } + + static func == (lhs: Item, rhs: Item) -> Bool { + return lhs.count == rhs.count + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ for each $getNewsFeed()$ call and $O(1)$ for remaining methods. +- Space complexity: $O(N * m + N * M + n)$ + +> Where $n$ is the total number of $followeeIds$ associated with the $userId$, $m$ is the maximum number of tweets by any user, $N$ is the total number of $userIds$ and $M$ is the maximum number of followees for any user. + +--- + +## 3. Heap (Optimal) + +::tabs-start + +```python +class Twitter: + + def __init__(self): + self.count = 0 + self.tweetMap = defaultdict(list) # userId -> list of [count, tweetIds] + self.followMap = defaultdict(set) # userId -> set of followeeId + + def postTweet(self, userId: int, tweetId: int) -> None: + self.tweetMap[userId].append([self.count, tweetId]) + if len(self.tweetMap[userId]) > 10: + self.tweetMap[userId].pop(0) + self.count -= 1 + + def getNewsFeed(self, userId: int) -> List[int]: + res = [] + minHeap = [] + self.followMap[userId].add(userId) + if len(self.followMap[userId]) >= 10: + maxHeap = [] + for followeeId in self.followMap[userId]: + if followeeId in self.tweetMap: + index = len(self.tweetMap[followeeId]) - 1 + count, tweetId = self.tweetMap[followeeId][index] + heapq.heappush(maxHeap, [-count, tweetId, followeeId, index - 1]) + if len(maxHeap) > 10: + heapq.heappop(maxHeap) + while maxHeap: + count, tweetId, followeeId, index = heapq.heappop(maxHeap) + heapq.heappush(minHeap, [-count, tweetId, followeeId, index]) + else: + for followeeId in self.followMap[userId]: + if followeeId in self.tweetMap: + index = len(self.tweetMap[followeeId]) - 1 + count, tweetId = self.tweetMap[followeeId][index] + heapq.heappush(minHeap, [count, tweetId, followeeId, index - 1]) + + while minHeap and len(res) < 10: + count, tweetId, followeeId, index = heapq.heappop(minHeap) + res.append(tweetId) + if index >= 0: + count, tweetId = self.tweetMap[followeeId][index] + heapq.heappush(minHeap, [count, tweetId, followeeId, index - 1]) + + return res + + def follow(self, followerId: int, followeeId: int) -> None: + self.followMap[followerId].add(followeeId) + + def unfollow(self, followerId: int, followeeId: int) -> None: + if followeeId in self.followMap[followerId]: + self.followMap[followerId].remove(followeeId) +``` + +```java +public class Twitter { + + private int count; + private Map> tweetMap; + private Map> followMap; + + public Twitter() { + this.count = 0; + this.tweetMap = new HashMap<>(); + this.followMap = new HashMap<>(); + } + + public void postTweet(int userId, int tweetId) { + tweetMap.computeIfAbsent(userId, k -> new ArrayList<>()) + .add(new int[]{count, tweetId}); + if (tweetMap.get(userId).size() > 10) { + tweetMap.get(userId).remove(0); + } + count--; + } + + public List getNewsFeed(int userId) { + List res = new ArrayList<>(); + PriorityQueue minHeap = new PriorityQueue<>( + (a, b) -> Integer.compare(a[0], b[0]) + ); + followMap.computeIfAbsent(userId, k -> new HashSet<>()).add(userId); + if (followMap.get(userId).size() >= 10) { + PriorityQueue maxHeap = new PriorityQueue<>( + (a, b) -> Integer.compare(a[0], b[0]) + ); + for (int followeeId : followMap.get(userId)) { + if (!tweetMap.containsKey(followeeId)) continue; + List tweets = tweetMap.get(followeeId); + int index = tweets.size() - 1; + int[] tweet = tweets.get(index); + maxHeap.offer(new int[]{-tweet[0], tweet[1], followeeId, index - 1}); + if (maxHeap.size() > 10) { + maxHeap.poll(); + } + } + while (!maxHeap.isEmpty()) { + int[] top = maxHeap.poll(); + minHeap.offer(new int[]{-top[0], top[1], top[2], top[3]}); + } + } else { + for (int followeeId : followMap.get(userId)) { + if (!tweetMap.containsKey(followeeId)) continue; + List tweets = tweetMap.get(followeeId); + int index = tweets.size() - 1; + int[] tweet = tweets.get(index); + minHeap.offer(new int[]{tweet[0], tweet[1], followeeId, index - 1}); + } + } + + while (!minHeap.isEmpty() && res.size() < 10) { + int[] top = minHeap.poll(); + res.add(top[1]); + int nextIndex = top[3]; + if (nextIndex >= 0) { + List tweets = tweetMap.get(top[2]); + int[] nextTweet = tweets.get(nextIndex); + minHeap.offer(new int[]{nextTweet[0], nextTweet[1], top[2], nextIndex - 1}); + } + } + return res; + } + + public void follow(int followerId, int followeeId) { + followMap.computeIfAbsent(followerId, k -> new HashSet<>()).add(followeeId); + } + + public void unfollow(int followerId, int followeeId) { + if (followMap.containsKey(followerId)) { + followMap.get(followerId).remove(followeeId); + } + } +} +``` + +```cpp +class Twitter { +public: + int count; + unordered_map>> tweetMap; + unordered_map> followMap; + + Twitter() { + count = 0; + } + + void postTweet(int userId, int tweetId) { + tweetMap[userId].push_back({count, tweetId}); + if (tweetMap[userId].size() > 10) { + tweetMap[userId].erase(tweetMap[userId].begin()); + } + count--; + } + + vector getNewsFeed(int userId) { + vector res; + followMap[userId].insert(userId); + priority_queue, vector>, greater>> minHeap; + if (followMap[userId].size() >= 10) { + priority_queue> maxHeap; + for (auto f : followMap[userId]) { + if (!tweetMap.count(f)) continue; + int idx = tweetMap[f].size() - 1; + auto &p = tweetMap[f][idx]; + maxHeap.push({-p.first, p.second, f, idx - 1}); + if (maxHeap.size() > 10) maxHeap.pop(); + } + while (!maxHeap.empty()) { + auto t = maxHeap.top(); + maxHeap.pop(); + minHeap.push({-t[0], t[1], t[2], t[3]}); + } + } else { + for (auto f : followMap[userId]) { + if (!tweetMap.count(f)) continue; + int idx = tweetMap[f].size() - 1; + auto &p = tweetMap[f][idx]; + minHeap.push({p.first, p.second, f, idx - 1}); + } + } + while (!minHeap.empty() && res.size() < 10) { + auto t = minHeap.top(); + minHeap.pop(); + res.push_back(t[1]); + int idx = t[3]; + if (idx >= 0) { + auto &p = tweetMap[t[2]][idx]; + minHeap.push({p.first, p.second, t[2], idx - 1}); + } + } + return res; + } + + void follow(int followerId, int followeeId) { + followMap[followerId].insert(followeeId); + } + + void unfollow(int followerId, int followeeId) { + if (followMap[followerId].count(followeeId)) { + followMap[followerId].erase(followeeId); + } + } +}; +``` + +```javascript +/** + * const { PriorityQueue } = require('@datastructures-js/priority-queue'); + */ +class Twitter { + constructor() { + this.count = 0; + this.tweetMap = new Map(); + this.followMap = new Map(); + } + + /** + * @param {number} userId + * @param {number} tweetId + * @return {void} + */ + postTweet(userId, tweetId) { + if (!this.tweetMap.has(userId)) { + this.tweetMap.set(userId, []); + } + const tweets = this.tweetMap.get(userId); + tweets.push([this.count, tweetId]); + if (tweets.length > 10) { + tweets.shift(); + } + this.count--; + } + + /** + * @param {number} userId + * @return {number[]} + */ + getNewsFeed(userId) { + const res = []; + if (!this.followMap.has(userId)) { + this.followMap.set(userId, new Set()); + } + this.followMap.get(userId).add(userId); + const minHeap = new PriorityQueue((a, b) => a[0] - b[0]); + + if (this.followMap.get(userId).size >= 10) { + const maxHeap = new PriorityQueue((a, b) => a[0] - b[0]); + for (const followeeId of this.followMap.get(userId)) { + if (!this.tweetMap.has(followeeId)) continue; + const tweets = this.tweetMap.get(followeeId); + const idx = tweets.length - 1; + const [cnt, tId] = tweets[idx]; + maxHeap.enqueue([-cnt, tId, followeeId, idx - 1]); + if (maxHeap.size() > 10) { + maxHeap.dequeue(); + } + } + while (maxHeap.size() > 0) { + const [negCount, tId, fId, idx] = maxHeap.dequeue(); + minHeap.enqueue([-negCount, tId, fId, idx]); + } + } else { + for (const followeeId of this.followMap.get(userId)) { + if (!this.tweetMap.has(followeeId)) continue; + const tweets = this.tweetMap.get(followeeId); + const idx = tweets.length - 1; + const [cnt, tId] = tweets[idx]; + minHeap.enqueue([cnt, tId, followeeId, idx - 1]); + } + } + + while (minHeap.size() > 0 && res.length < 10) { + const [cnt, tId, fId, idx] = minHeap.dequeue(); + res.push(tId); + if (idx >= 0) { + const [olderCount, olderTId] = this.tweetMap.get(fId)[idx]; + minHeap.enqueue([olderCount, olderTId, fId, idx - 1]); + } + } + return res; + } + + /** + * @param {number} followerId + * @param {number} followeeId + * @return {void} + */ + follow(followerId, followeeId) { + if (!this.followMap.has(followerId)) { + this.followMap.set(followerId, new Set()); + } + this.followMap.get(followerId).add(followeeId); + } + + /** + * @param {number} followerId + * @param {number} followeeId + * @return {void} + */ + unfollow(followerId, followeeId) { + if (this.followMap.has(followerId)) { + this.followMap.get(followerId).delete(followeeId); + } + } +} +``` + +```csharp +public class Twitter +{ + private int count; + private Dictionary> tweetMap; // userId -> list of (count, tweetId) + private Dictionary> followMap; // userId -> set of followeeId + + public Twitter() + { + count = 0; + tweetMap = new Dictionary>(); + followMap = new Dictionary>(); + } + + public void PostTweet(int userId, int tweetId) + { + if (!tweetMap.ContainsKey(userId)) + { + tweetMap[userId] = new List<(int, int)>(); + } + tweetMap[userId].Add((count, tweetId)); + if (tweetMap[userId].Count > 10) + { + tweetMap[userId].RemoveAt(0); + } + count--; + } + + public List GetNewsFeed(int userId) + { + var res = new List(); + if (!followMap.ContainsKey(userId)) + { + followMap[userId] = new HashSet(); + } + followMap[userId].Add(userId); + var minHeap = new PriorityQueue<(int, int, int, int), int>(); + if (followMap[userId].Count >= 10) + { + var maxHeap = new PriorityQueue<(int, int, int, int), int>(); + foreach (var fId in followMap[userId]) + { + if (tweetMap.ContainsKey(fId)) + { + var tweets = tweetMap[fId]; + int idx = tweets.Count - 1; + var (c, tId) = tweets[idx]; + maxHeap.Enqueue( + ( -c, tId, fId, idx - 1 ), + -c + ); + if (maxHeap.Count > 10) + { + maxHeap.Dequeue(); + } + } + } + + while (maxHeap.Count > 0) + { + var item = maxHeap.Dequeue(); + var negCount = item.Item1; + var tId = item.Item2; + var fId = item.Item3; + var idx = item.Item4; + + int originalCount = -negCount; + minHeap.Enqueue( + ( originalCount, tId, fId, idx ), + originalCount + ); + } + } + else + { + foreach (var fId in followMap[userId]) + { + if (tweetMap.ContainsKey(fId)) + { + var tweets = tweetMap[fId]; + int idx = tweets.Count - 1; + var (c, tId) = tweets[idx]; + minHeap.Enqueue( + ( c, tId, fId, idx - 1 ), + c + ); + } + } + } + + while (minHeap.Count > 0 && res.Count < 10) + { + var (c, tId, fId, idx) = minHeap.Dequeue(); + res.Add(tId); + if (idx >= 0) + { + var (olderCount, olderTid) = tweetMap[fId][idx]; + minHeap.Enqueue( + ( olderCount, olderTid, fId, idx - 1 ), + olderCount + ); + } + } + + return res; + } + + public void Follow(int followerId, int followeeId) + { + if (!followMap.ContainsKey(followerId)) + { + followMap[followerId] = new HashSet(); + } + followMap[followerId].Add(followeeId); + } + + public void Unfollow(int followerId, int followeeId) + { + if (followMap.ContainsKey(followerId)) + { + followMap[followerId].Remove(followeeId); + } + } +} +``` + +```go +type Twitter struct { + count int + tweetMap map[int][][2]int // userId -> [count, tweetId] + followMap map[int]map[int]bool // userId -> set of followeeIds +} + +func Constructor() Twitter { + return Twitter{ + count: 0, + tweetMap: make(map[int][][2]int), + followMap: make(map[int]map[int]bool), + } +} + +func (t *Twitter) PostTweet(userId int, tweetId int) { + if _, exists := t.tweetMap[userId]; !exists { + t.tweetMap[userId] = make([][2]int, 0, 10) + } + t.tweetMap[userId] = append(t.tweetMap[userId], [2]int{t.count, tweetId}) + if len(t.tweetMap[userId]) > 10 { + t.tweetMap[userId] = t.tweetMap[userId][1:] + } + t.count-- +} + +func maxHeapComparator(a, b interface{}) int { + A := a.([]int) + B := b.([]int) + switch { + case A[0] < B[0]: + return -1 + case A[0] > B[0]: + return 1 + default: + return 0 + } +} + +func minHeapComparator(a, b interface{}) int { + A := a.([]int) + B := b.([]int) + switch { + case A[0] < B[0]: + return -1 + case A[0] > B[0]: + return 1 + default: + return 0 + } +} + +func (t *Twitter) GetNewsFeed(userId int) []int { + res := []int{} + if _, ok := t.followMap[userId]; !ok { + t.followMap[userId] = make(map[int]bool) + } + t.followMap[userId][userId] = true + minHeap := priorityqueue.NewWith(minHeapComparator) + + if len(t.followMap[userId]) >= 10 { + maxHeap := priorityqueue.NewWith(maxHeapComparator) + for fId := range t.followMap[userId] { + if tweets, exists := t.tweetMap[fId]; exists && len(tweets) > 0 { + idx := len(tweets) - 1 + c := tweets[idx][0] + tId := tweets[idx][1] + maxHeap.Enqueue([]int{-c, tId, fId, idx - 1}) + if maxHeap.Size() > 10 { + maxHeap.Dequeue() + } + } + } + + for !maxHeap.Empty() { + item, _ := maxHeap.Dequeue() + arr := item.([]int) + negCount := arr[0] + tId := arr[1] + fId := arr[2] + nextIdx := arr[3] + realCount := -negCount + minHeap.Enqueue([]int{realCount, tId, fId, nextIdx}) + } + } else { + for fId := range t.followMap[userId] { + if tweets, exists := t.tweetMap[fId]; exists && len(tweets) > 0 { + idx := len(tweets) - 1 + c := tweets[idx][0] + tId := tweets[idx][1] + minHeap.Enqueue([]int{c, tId, fId, idx - 1}) + } + } + } + + for !minHeap.Empty() && len(res) < 10 { + top, _ := minHeap.Dequeue() + arr := top.([]int) + tId := arr[1] + fId := arr[2] + nextIdx := arr[3] + + res = append(res, tId) + if nextIdx >= 0 { + older := t.tweetMap[fId][nextIdx] + minHeap.Enqueue([]int{older[0], older[1], fId, nextIdx - 1}) + } + } + + return res +} + +func (t *Twitter) Follow(followerId, followeeId int) { + if _, ok := t.followMap[followerId]; !ok { + t.followMap[followerId] = make(map[int]bool) + } + t.followMap[followerId][followeeId] = true +} + +func (t *Twitter) Unfollow(followerId, followeeId int) { + if _, ok := t.followMap[followerId]; ok { + delete(t.followMap[followerId], followeeId) + } +} +``` + +```kotlin +class Twitter { + private var count = 0 + private val tweetMap = mutableMapOf>>() + private val followMap = mutableMapOf>() + + fun postTweet(userId: Int, tweetId: Int) { + if (!tweetMap.containsKey(userId)) { + tweetMap[userId] = mutableListOf() + } + val tweets = tweetMap[userId]!! + tweets.add(Pair(count, tweetId)) + if (tweets.size > 10) { + tweets.removeAt(0) + } + count-- + } + + fun getNewsFeed(userId: Int): List { + val res = mutableListOf() + if (!followMap.containsKey(userId)) { + followMap[userId] = mutableSetOf() + } + followMap[userId]!!.add(userId) + val minHeap = PriorityQueue> { a, b -> a[0].compareTo(b[0]) } + if (followMap[userId]!!.size >= 10) { + val maxHeap = PriorityQueue> { a, b -> a[0].compareTo(b[0]) } + for (fId in followMap[userId]!!) { + if (!tweetMap.containsKey(fId)) continue + val tweets = tweetMap[fId]!! + if (tweets.isEmpty()) continue + val idx = tweets.size - 1 + val (c, tId) = tweets[idx] + maxHeap.offer(listOf(-c, tId, fId, idx - 1)) + if (maxHeap.size > 10) { + maxHeap.poll() + } + } + while (maxHeap.isNotEmpty()) { + val (negCount, tId, fId, nextIdx) = maxHeap.poll() + val realCount = -negCount + minHeap.offer(listOf(realCount, tId, fId, nextIdx)) + } + } else { + for (fId in followMap[userId]!!) { + if (!tweetMap.containsKey(fId)) continue + val tweets = tweetMap[fId]!! + if (tweets.isEmpty()) continue + val idx = tweets.size - 1 + val (c, tId) = tweets[idx] + minHeap.offer(listOf(c, tId, fId, idx - 1)) + } + } + + while (minHeap.isNotEmpty() && res.size < 10) { + val (c, tId, fId, idx) = minHeap.poll() + res.add(tId) + if (idx >= 0) { + val (olderCount, olderTid) = tweetMap[fId]!![idx] + minHeap.offer(listOf(olderCount, olderTid, fId, idx - 1)) + } + } + + return res + } + + fun follow(followerId: Int, followeeId: Int) { + if (!followMap.containsKey(followerId)) { + followMap[followerId] = mutableSetOf() + } + followMap[followerId]!!.add(followeeId) + } + + fun unfollow(followerId: Int, followeeId: Int) { + if (followMap.containsKey(followerId)) { + followMap[followerId]!!.remove(followeeId) + } + } +} +``` + +```swift +struct Item: Comparable { + let count: Int + let tweetId: Int + let followeeId: Int + let index: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.count < rhs.count + } + + static func == (lhs: Item, rhs: Item) -> Bool { + return lhs.count == rhs.count && + lhs.tweetId == rhs.tweetId && + lhs.followeeId == rhs.followeeId && + lhs.index == rhs.index + } +} + +class Twitter { + private var count: Int + private var tweetMap: [Int: [(Int, Int)]] // userId -> list of (count, tweetId) + private var followMap: [Int: Set] // userId -> set of followeeId + + init() { + self.count = 0 + self.tweetMap = [:] + self.followMap = [:] + } + + func postTweet(_ userId: Int, _ tweetId: Int) { + tweetMap[userId, default: []].append((count, tweetId)) + if tweetMap[userId]!.count > 10 { + tweetMap[userId]!.removeFirst() + } + count -= 1 + } + + func getNewsFeed(_ userId: Int) -> [Int] { + var res = [Int]() + var minHeap = Heap() + followMap[userId, default: Set()].insert(userId) + + if followMap[userId]!.count >= 10 { + var maxHeap = Heap() + for followeeId in followMap[userId]! { + if let tweets = tweetMap[followeeId], !tweets.isEmpty { + let index = tweets.count - 1 + let (cnt, tweetId) = tweets[index] + maxHeap.insert( + Item( + count: cnt, tweetId: tweetId, + followeeId: followeeId, index: index - 1 + ) + ) + if maxHeap.count > 10 { + maxHeap.removeMax() + } + } + } + while !maxHeap.isEmpty { + let item = maxHeap.popMax()! + minHeap.insert(item) + } + } else { + for followeeId in followMap[userId]! { + if let tweets = tweetMap[followeeId], !tweets.isEmpty { + let index = tweets.count - 1 + let (cnt, tweetId) = tweets[index] + minHeap.insert( + Item( + count: cnt, tweetId: tweetId, + followeeId: followeeId, index: index - 1 + ) + ) + } + } + } + + while !minHeap.isEmpty && res.count < 10 { + let item = minHeap.popMin()! + res.append(item.tweetId) + if item.index >= 0, let tweets = tweetMap[item.followeeId] { + let (cnt, tweetId) = tweets[item.index] + minHeap.insert( + Item( + count: cnt, tweetId: tweetId, + followeeId: item.followeeId, index: item.index - 1 + ) + ) + } + } + + return res + } + + func follow(_ followerId: Int, _ followeeId: Int) { + followMap[followerId, default: Set()].insert(followeeId) + } + + func unfollow(_ followerId: Int, _ followeeId: Int) { + followMap[followerId]?.remove(followeeId) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ for each $getNewsFeed()$ call and $O(1)$ for remaining methods. -* Space complexity: $O(N * m + N * M + n)$ +- Time complexity: $O(n)$ for each $getNewsFeed()$ call and $O(1)$ for remaining methods. +- Space complexity: $O(N * m + N * M + n)$ -> Where $n$ is the total number of $followeeIds$ associated with the $userId$, $m$ is the maximum number of tweets by any user, $N$ is the total number of $userIds$ and $M$ is the maximum number of followees for any user. \ No newline at end of file +> Where $n$ is the total number of $followeeIds$ associated with the $userId$, $m$ is the maximum number of tweets by any user ($m$ can be at most $10$), $N$ is the total number of $userIds$ and $M$ is the maximum number of followees for any user. diff --git a/articles/design-underground-system.md b/articles/design-underground-system.md new file mode 100644 index 000000000..1a3f93bae --- /dev/null +++ b/articles/design-underground-system.md @@ -0,0 +1,362 @@ +## 1. Two HashMaps + +::tabs-start + +```python +class UndergroundSystem: + + def __init__(self): + self.checkInMap = {} # id -> (startStation, time) + self.routeMap = {} # (start, end) -> [totalTime, count] + + def checkIn(self, id: int, startStation: str, t: int) -> None: + self.checkInMap[id] = (startStation, t) + + def checkOut(self, id: int, endStation: str, t: int) -> None: + startStation, time = self.checkInMap[id] + route = (startStation, endStation) + if route not in self.routeMap: + self.routeMap[route] = [0, 0] + self.routeMap[route][0] += t - time + self.routeMap[route][1] += 1 + + def getAverageTime(self, startStation: str, endStation: str) -> float: + totalTime, count = self.routeMap[(startStation, endStation)] + return totalTime / count +``` + +```java +public class UndergroundSystem { + private Map> checkInMap; + private Map routeMap; + + public UndergroundSystem() { + checkInMap = new HashMap<>(); + routeMap = new HashMap<>(); + } + + public void checkIn(int id, String startStation, int t) { + checkInMap.put(id, new Pair<>(startStation, t)); + } + + public void checkOut(int id, String endStation, int t) { + Pair entry = checkInMap.get(id); + String route = entry.getKey() + "," + endStation; + routeMap.putIfAbsent(route, new int[]{0, 0}); + routeMap.get(route)[0] += t - entry.getValue(); + routeMap.get(route)[1] += 1; + } + + public double getAverageTime(String startStation, String endStation) { + int[] data = routeMap.get(startStation + "," + endStation); + return (double) data[0] / data[1]; + } +} +``` + +```cpp +class UndergroundSystem { + unordered_map> checkInMap; + unordered_map> routeMap; + +public: + UndergroundSystem() {} + + void checkIn(int id, string startStation, int t) { + checkInMap[id] = {startStation, t}; + } + + void checkOut(int id, string endStation, int t) { + auto [startStation, time] = checkInMap[id]; + string route = startStation + "," + endStation; + if (!routeMap.count(route)) + routeMap[route] = {0, 0}; + routeMap[route].first += t - time; + routeMap[route].second += 1; + } + + double getAverageTime(string startStation, string endStation) { + string route = startStation + "," + endStation; + auto [totalTime, count] = routeMap[route]; + return (double) totalTime / count; + } +}; +``` + +```javascript +class UndergroundSystem { + /** + * @constructor + */ + constructor() { + this.checkInMap = new Map(); + this.routeMap = new Map(); + } + + /** + * @param {number} id + * @param {string} startStation + * @param {number} t + * @return {void} + */ + checkIn(id, startStation, t) { + this.checkInMap.set(id, [startStation, t]); + } + + /** + * @param {number} id + * @param {string} endStation + * @param {number} t + * @return {void} + */ + checkOut(id, endStation, t) { + const [startStation, time] = this.checkInMap.get(id); + const route = `${startStation},${endStation}`; + if (!this.routeMap.has(route)) this.routeMap.set(route, [0, 0]); + this.routeMap.get(route)[0] += t - time; + this.routeMap.get(route)[1] += 1; + } + + /** + * @param {string} startStation + * @param {string} endStation + * @return {number} + */ + getAverageTime(startStation, endStation) { + const [totalTime, count] = this.routeMap.get( + `${startStation},${endStation}`, + ); + return totalTime / count; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $checkIn()$ function call. + - $O(m)$ time for each $checkOut()$ and $getAverageTime()$ function calls. +- Space complexity: $O(n + N ^ 2)$ + +> Where $n$ is the number of passengers, $N$ is the total number of stations, and $m$ is the average length of station name. + +--- + +## 2. Two HashMaps + Hashing + +::tabs-start + +```python +class UndergroundSystem: + MOD1, MOD2 = 768258391, 685683731 + BASE1, BASE2 = 37, 31 + + def __init__(self): + self.checkInMap = {} # id -> (startStation, time) + self.routeMap = {} # hash(route) -> (totalTime, count) + + def getHash(self, s1: str, s2: str) -> int: + h1, h2, p1, p2 = 0, 0, 1, 1 + for c in s1 + ',' + s2: + h1 = (h1 + (ord(c) - 96) * p1) % self.MOD1 + h2 = (h2 + (ord(c) - 96) * p2) % self.MOD2 + p1 = (p1 * self.BASE1) % self.MOD1 + p2 = (p2 * self.BASE2) % self.MOD2 + return (h1 << 32) | h2 + + def checkIn(self, id: int, startStation: str, t: int) -> None: + self.checkInMap[id] = (startStation, t) + + def checkOut(self, id: int, endStation: str, t: int) -> None: + startStation, time = self.checkInMap[id] + routeHash = self.getHash(startStation, endStation) + if routeHash not in self.routeMap: + self.routeMap[routeHash] = [0, 0] + self.routeMap[routeHash][0] += t - time + self.routeMap[routeHash][1] += 1 + + def getAverageTime(self, startStation: str, endStation: str) -> float: + routeHash = self.getHash(startStation, endStation) + totalTime, count = self.routeMap[routeHash] + return totalTime / count +``` + +```java +public class UndergroundSystem { + private static final int MOD1 = 768258391, MOD2 = 685683731; + private static final int BASE1 = 37, BASE2 = 31; + private Map> checkInMap; + private Map routeMap; + + public UndergroundSystem() { + checkInMap = new HashMap<>(); + routeMap = new HashMap<>(); + } + + private long getHash(String s1, String s2) { + long h1 = 0, h2 = 0, p1 = 1, p2 = 1; + String combined = s1 + "," + s2; + + for (char c : combined.toCharArray()) { + h1 = (h1 + (c - 96) * p1) % MOD1; + h2 = (h2 + (c - 96) * p2) % MOD2; + p1 = (p1 * BASE1) % MOD1; + p2 = (p2 * BASE2) % MOD2; + } + return (h1 << 32) | h2; + } + + public void checkIn(int id, String startStation, int t) { + checkInMap.put(id, new Pair<>(startStation, t)); + } + + public void checkOut(int id, String endStation, int t) { + Pair checkInData = checkInMap.get(id); + long routeHash = getHash(checkInData.getKey(), endStation); + routeMap.putIfAbsent(routeHash, new int[]{0, 0}); + int[] data = routeMap.get(routeHash); + data[0] += (t - checkInData.getValue()); + data[1]++; + } + + public double getAverageTime(String startStation, String endStation) { + long routeHash = getHash(startStation, endStation); + int[] data = routeMap.get(routeHash); + return (double) data[0] / data[1]; + } +} +``` + +```cpp +class UndergroundSystem { +private: + static constexpr int MOD1 = 768258391, MOD2 = 685683731; + static constexpr int BASE1 = 37, BASE2 = 31; + unordered_map> checkInMap; + unordered_map> routeMap; + + unsigned long long getHash(const string& s1, const string& s2) { + long long h1 = 0, h2 = 0, p1 = 1, p2 = 1; + string combined = s1 + "," + s2; + + for (char c : combined) { + h1 = (h1 + (c - 96) * p1) % MOD1; + h2 = (h2 + (c - 96) * p2) % MOD2; + p1 = (p1 * BASE1) % MOD1; + p2 = (p2 * BASE2) % MOD2; + } + return (h1 << 32) | h2; + } + +public: + UndergroundSystem() {} + + void checkIn(int id, string startStation, int t) { + checkInMap[id] = {startStation, t}; + } + + void checkOut(int id, string endStation, int t) { + auto [startStation, time] = checkInMap[id]; + unsigned long long routeHash = getHash(startStation, endStation); + routeMap[routeHash].first += (t - time); + routeMap[routeHash].second++; + } + + double getAverageTime(string startStation, string endStation) { + unsigned long long routeHash = getHash(startStation, endStation); + auto [totalTime, count] = routeMap[routeHash]; + return (double) totalTime / count; + } +}; +``` + +```javascript +class UndergroundSystem { + /** + * @constructor + */ + constructor() { + this.MOD1 = 768258391; + this.MOD2 = 685683731; + this.BASE1 = 37; + this.BASE2 = 31; + this.checkInMap = new Map(); + this.routeMap = new Map(); + } + + /** + * @param {string} s1 + * @param {string} s2 + * @return {number} + */ + getHash(s1, s2) { + let h1 = 0, + h2 = 0, + p1 = 1, + p2 = 1; + let combined = s1 + ',' + s2; + + for (let i = 0; i < combined.length; i++) { + let c = combined.charCodeAt(i) - 96; + h1 = (h1 + c * p1) % this.MOD1; + h2 = (h2 + c * p2) % this.MOD2; + p1 = (p1 * this.BASE1) % this.MOD1; + p2 = (p2 * this.BASE2) % this.MOD2; + } + return (BigInt(h1) << BigInt(32)) | BigInt(h2); + } + + /** + * @param {number} id + * @param {string} startStation + * @param {number} t + * @return {void} + */ + checkIn(id, startStation, t) { + this.checkInMap.set(id, [startStation, t]); + } + + /** + * @param {number} id + * @param {string} endStation + * @param {number} t + * @return {void} + */ + checkOut(id, endStation, t) { + let [startStation, time] = this.checkInMap.get(id); + let routeHash = this.getHash(startStation, endStation); + if (!this.routeMap.has(routeHash)) { + this.routeMap.set(routeHash, [0, 0]); + } + let data = this.routeMap.get(routeHash); + data[0] += t - time; + data[1]++; + } + + /** + * @param {string} startStation + * @param {string} endStation + * @return {number} + */ + getAverageTime(startStation, endStation) { + let routeHash = this.getHash(startStation, endStation); + let [totalTime, count] = this.routeMap.get(routeHash); + return totalTime / count; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $checkIn()$ function call. + - $O(m)$ time for each $checkOut()$ and $getAverageTime()$ function calls. +- Space complexity: $O(n + N ^ 2)$ + +> Where $n$ is the number of passengers, $N$ is the total number of stations, and $m$ is the average length of station name. diff --git a/articles/design-word-search-data-structure.md b/articles/design-word-search-data-structure.md index 501e42785..b6e433175 100644 --- a/articles/design-word-search-data-structure.md +++ b/articles/design-word-search-data-structure.md @@ -44,7 +44,7 @@ public class WordDictionary { if (w.length() != word.length()) continue; int i = 0; while (i < w.length()) { - if (w.charAt(i) == word.charAt(i) || + if (w.charAt(i) == word.charAt(i) || word.charAt(i) == '.') { i++; } else { @@ -104,7 +104,7 @@ class WordDictionary { addWord(word) { this.store.push(word); } - + /** * @param {string} word * @return {boolean} @@ -114,8 +114,7 @@ class WordDictionary { if (w.length !== word.length) continue; let i = 0; while (i < w.length) { - if (w[i] === word[i] || - word[i] === '.') { + if (w[i] === word[i] || word[i] === '.') { i++; } else { break; @@ -222,12 +221,48 @@ class WordDictionary { } ``` +```swift +class WordDictionary { + private var store: [String] + + init() { + self.store = [] + } + + func addWord(_ word: String) { + store.append(word) + } + + func search(_ word: String) -> Bool { + for w in store { + if w.count != word.count { + continue + } + var i = 0 + let wArray = Array(w) + let wordArray = Array(word) + while i < wArray.count { + if wArray[i] == wordArray[i] || wordArray[i] == "." { + i += 1 + } else { + break + } + } + if i == wArray.count { + return true + } + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ for $addWord()$, $O(m * n)$ for $search()$. -* Space complexity: $O(m * n)$ +- Time complexity: $O(1)$ for $addWord()$, $O(m * n)$ for $search()$. +- Space complexity: $O(m * n)$ > Where $m$ is the number of words added and $n$ is the length of the string. @@ -278,10 +313,10 @@ class WordDictionary: ```java public class TrieNode { - + TrieNode[] children; boolean word; - + public TrieNode() { children = new TrieNode[26]; word = false; @@ -289,7 +324,7 @@ public class TrieNode { } public class WordDictionary { - + private TrieNode root; public WordDictionary() { @@ -402,7 +437,7 @@ class WordDictionary { constructor() { this.root = new TrieNode(); } - + /** * @param {string} c * @return {number} @@ -418,7 +453,7 @@ class WordDictionary { addWord(word) { let cur = this.root; for (const c of word) { - const idx = this.getIndex(c); + const idx = this.getIndex(c); if (cur.children[idx] === null) { cur.children[idx] = new TrieNode(); } @@ -426,8 +461,8 @@ class WordDictionary { } cur.word = true; } - - /** + + /** * @param {string} word * @return {boolean} */ @@ -448,14 +483,13 @@ class WordDictionary { const c = word[i]; if (c === '.') { for (const child of cur.children) { - if (child !== null && - this.dfs(word, i + 1, child)) { + if (child !== null && this.dfs(word, i + 1, child)) { return true; } } return false; } else { - const idx = this.getIndex(c); + const idx = this.getIndex(c); if (cur.children[idx] === null) { return false; } @@ -474,7 +508,7 @@ public class TrieNode { } public class WordDictionary { - + private TrieNode root; public WordDictionary() { @@ -627,11 +661,69 @@ class WordDictionary { } ``` +```swift +class TrieNode { + var children: [Character: TrieNode] + var word: Bool + + init() { + self.children = [:] + self.word = false + } +} + +class WordDictionary { + private let root: TrieNode + + init() { + self.root = TrieNode() + } + + func addWord(_ word: String) { + var cur = root + for c in word { + if cur.children[c] == nil { + cur.children[c] = TrieNode() + } + cur = cur.children[c]! + } + cur.word = true + } + + func search(_ word: String) -> Bool { + func dfs(_ j: Int, _ root: TrieNode) -> Bool { + var cur = root + let wordArray = Array(word) + + for i in j.. Where $n$ is the length of the string and $t$ is the total number of TrieNodes created in the Trie. \ No newline at end of file +> Where $n$ is the length of the string and $t$ is the total number of TrieNodes created in the Trie. diff --git a/articles/destination-city.md b/articles/destination-city.md index 0dc585b2b..9cd307442 100644 --- a/articles/destination-city.md +++ b/articles/destination-city.md @@ -76,7 +76,7 @@ class Solution { return paths[i][1]; } } - return ""; + return ''; } } ``` @@ -85,8 +85,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -160,7 +160,7 @@ class Solution { return p[1]; } } - return ""; + return ''; } } ``` @@ -169,8 +169,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -182,7 +182,7 @@ class Solution { class Solution: def destCity(self, paths: List[List[str]]) -> str: mp = {p[0]: p[1] for p in paths} - + start = paths[0][0] while start in mp: start = mp[start] @@ -249,5 +249,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/detonate-the-maximum-bombs.md b/articles/detonate-the-maximum-bombs.md new file mode 100644 index 000000000..529a40d0c --- /dev/null +++ b/articles/detonate-the-maximum-bombs.md @@ -0,0 +1,522 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def maximumDetonation(self, bombs: list[list[int]]) -> int: + adj = [[] for _ in range(len(bombs))] + + for i in range(len(bombs)): + x1, y1, r1 = bombs[i] + for j in range(i + 1, len(bombs)): + x2, y2, r2 = bombs[j] + d = (x1 - x2) ** 2 + (y1 - y2) ** 2 + + if d <= r1 ** 2: + adj[i].append(j) + if d <= r2 ** 2: + adj[j].append(i) + + def dfs(i, visit): + if i in visit: + return 0 + visit.add(i) + for nei in adj[i]: + dfs(nei, visit) + return len(visit) + + res = 0 + for i in range(len(bombs)): + res = max(res, dfs(i, set())) + return res +``` + +```java +public class Solution { + public int maximumDetonation(int[][] bombs) { + int n = bombs.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2]; + int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2]; + long d = (long) (x1 - x2) * (x1 - x2) + (long) (y1 - y2) * (y1 - y2); + + if (d <= (long) r1 * r1) { + adj[i].add(j); + } + if (d <= (long) r2 * r2) { + adj[j].add(i); + } + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + res = Math.max(res, dfs(i, new HashSet<>(), adj)); + } + return res; + } + + private int dfs(int i, Set visit, List[] adj) { + if (!visit.add(i)) return 0; + for (int nei : adj[i]) { + dfs(nei, visit, adj); + } + return visit.size(); + } +} +``` + +```cpp +class Solution { +public: + int maximumDetonation(vector>& bombs) { + int n = bombs.size(); + vector> adj(n); + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + long long x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2]; + long long x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2]; + long long d = (x1 - x2) * (x1 - x2) + (y1 - y2) * (y1 - y2); + + if (d <= r1 * r1) { + adj[i].push_back(j); + } + if (d <= r2 * r2) { + adj[j].push_back(i); + } + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + unordered_set visit; + res = max(res, dfs(i, visit, adj)); + } + return res; + } + +private: + int dfs(int i, unordered_set& visit, vector>& adj) { + if (!visit.insert(i).second) return 0; + for (int nei : adj[i]) { + dfs(nei, visit, adj); + } + return visit.size(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} bombs + * @return {number} + */ + maximumDetonation(bombs) { + let n = bombs.length; + let adj = Array.from({ length: n }, () => []); + + for (let i = 0; i < n; i++) { + for (let j = i + 1; j < n; j++) { + let [x1, y1, r1] = bombs[i]; + let [x2, y2, r2] = bombs[j]; + let d = (x1 - x2) ** 2 + (y1 - y2) ** 2; + + if (d <= r1 ** 2) adj[i].push(j); + if (d <= r2 ** 2) adj[j].push(i); + } + } + + const dfs = (i, visit) => { + if (visit.has(i)) return 0; + visit.add(i); + for (let nei of adj[i]) { + dfs(nei, visit); + } + return visit.size; + }; + + let res = 0; + for (let i = 0; i < n; i++) { + res = Math.max(res, dfs(i, new Set())); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class Solution: + def maximumDetonation(self, bombs: list[list[int]]) -> int: + n = len(bombs) + adj = [[] for _ in range(n)] + + for i in range(n): + x1, y1, r1 = bombs[i] + for j in range(i + 1, n): + x2, y2, r2 = bombs[j] + d = (x1 - x2) ** 2 + (y1 - y2) ** 2 + + if d <= r1 ** 2: + adj[i].append(j) + if d <= r2 ** 2: + adj[j].append(i) + + res = 0 + for i in range(n): + q = deque([i]) + visit = [False] * n + visit[i] = True + count = 1 + while q: + node = q.popleft() + for nei in adj[node]: + if not visit[nei]: + visit[nei] = True + count += 1 + q.append(nei) + res = max(res, count) + return res +``` + +```java +public class Solution { + public int maximumDetonation(int[][] bombs) { + int n = bombs.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + + for (int i = 0; i < n; i++) { + int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2]; + for (int j = i + 1; j < n; j++) { + int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2]; + long d = (long) (x1 - x2) * (x1 - x2) + (long) (y1 - y2) * (y1 - y2); + + if (d <= (long) r1 * r1) adj[i].add(j); + if (d <= (long) r2 * r2) adj[j].add(i); + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + Queue q = new LinkedList<>(); + boolean[] visit = new boolean[n]; + q.offer(i); + visit[i] = true; + int count = 1; + + while (!q.isEmpty()) { + int node = q.poll(); + for (int nei : adj[node]) { + if (!visit[nei]) { + visit[nei] = true; + count++; + q.offer(nei); + } + } + } + res = Math.max(res, count); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximumDetonation(vector>& bombs) { + int n = bombs.size(); + vector> adj(n); + + for (int i = 0; i < n; i++) { + int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2]; + for (int j = i + 1; j < n; j++) { + int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2]; + long long d = (x1 - x2) * 1LL * (x1 - x2) + (y1 - y2) * 1LL * (y1 - y2); + + if (d <= (long long) r1 * r1) adj[i].push_back(j); + if (d <= (long long) r2 * r2) adj[j].push_back(i); + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + queue q; + vector visit(n, false); + q.push(i); + visit[i] = true; + int count = 1; + + while (!q.empty()) { + int node = q.front();q.pop(); + for (int& nei : adj[node]) { + if (!visit[nei]) { + visit[nei] = true; + count++; + q.push(nei); + } + } + } + res = max(res, count); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} bombs + * @return {number} + */ + maximumDetonation(bombs) { + let n = bombs.length; + let adj = Array.from({ length: n }, () => []); + + for (let i = 0; i < n; i++) { + let [x1, y1, r1] = bombs[i]; + for (let j = i + 1; j < n; j++) { + let [x2, y2, r2] = bombs[j]; + let d = (x1 - x2) ** 2 + (y1 - y2) ** 2; + + if (d <= r1 ** 2) adj[i].push(j); + if (d <= r2 ** 2) adj[j].push(i); + } + } + + let res = 0; + for (let i = 0; i < n; i++) { + let q = new Queue([i]); + let visit = new Array(n).fill(false); + visit[i] = true; + let count = 1; + + while (!q.isEmpty()) { + let node = q.pop(); + for (let nei of adj[node]) { + if (!visit[nei]) { + visit[nei] = true; + count++; + q.push(nei); + } + } + } + res = Math.max(res, count); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +class Solution: + def maximumDetonation(self, bombs: list[list[int]]) -> int: + n = len(bombs) + adj = [[] for _ in range(n)] + + for i in range(n): + x1, y1, r1 = bombs[i] + for j in range(i + 1, n): + x2, y2, r2 = bombs[j] + d = (x1 - x2) ** 2 + (y1 - y2) ** 2 + + if d <= r1 ** 2: + adj[i].append(j) + if d <= r2 ** 2: + adj[j].append(i) + + res = 0 + for i in range(n): + stack = [i] + visit = [False] * n + visit[i] = True + count = 1 + + while stack: + node = stack.pop() + for nei in adj[node]: + if not visit[nei]: + visit[nei] = True + count += 1 + stack.append(nei) + res = max(res, count) + return res +``` + +```java +public class Solution { + public int maximumDetonation(int[][] bombs) { + int n = bombs.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + + for (int i = 0; i < n; i++) { + int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2]; + for (int j = i + 1; j < n; j++) { + int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2]; + long d = (long) (x1 - x2) * (x1 - x2) + (long) (y1 - y2) * (y1 - y2); + + if (d <= (long) r1 * r1) adj[i].add(j); + if (d <= (long) r2 * r2) adj[j].add(i); + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + Stack stack = new Stack<>(); + boolean[] visit = new boolean[n]; + stack.push(i); + visit[i] = true; + int count = 1; + + while (!stack.isEmpty()) { + int node = stack.pop(); + for (int nei : adj[node]) { + if (!visit[nei]) { + visit[nei] = true; + count++; + stack.push(nei); + } + } + } + res = Math.max(res, count); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximumDetonation(vector>& bombs) { + int n = bombs.size(); + vector> adj(n); + + for (int i = 0; i < n; i++) { + int x1 = bombs[i][0], y1 = bombs[i][1], r1 = bombs[i][2]; + for (int j = i + 1; j < n; j++) { + int x2 = bombs[j][0], y2 = bombs[j][1], r2 = bombs[j][2]; + long long d = (long long)(x1 - x2) * (x1 - x2) + (long long)(y1 - y2) * (y1 - y2); + + if (d <= (long long) r1 * r1) adj[i].push_back(j); + if (d <= (long long) r2 * r2) adj[j].push_back(i); + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + stack stk; + vector visit(n, false); + stk.push(i); + visit[i] = true; + int count = 1; + + while (!stk.empty()) { + int node = stk.top();stk.pop(); + for (int& nei : adj[node]) { + if (!visit[nei]) { + visit[nei] = true; + count++; + stk.push(nei); + } + } + } + res = max(res, count); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} bombs + * @return {number} + */ + maximumDetonation(bombs) { + let n = bombs.length; + let adj = Array.from({ length: n }, () => []); + + for (let i = 0; i < n; i++) { + let [x1, y1, r1] = bombs[i]; + for (let j = i + 1; j < n; j++) { + let [x2, y2, r2] = bombs[j]; + let d = (x1 - x2) ** 2 + (y1 - y2) ** 2; + + if (d <= r1 ** 2) adj[i].push(j); + if (d <= r2 ** 2) adj[j].push(i); + } + } + + let res = 0; + for (let i = 0; i < n; i++) { + let stack = [i]; + let visit = new Array(n).fill(false); + visit[i] = true; + let count = 1; + + while (stack.length) { + let node = stack.pop(); + for (let nei of adj[node]) { + if (!visit[nei]) { + visit[nei] = true; + count++; + stack.push(nei); + } + } + } + res = Math.max(res, count); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n ^ 2)$ diff --git a/articles/distribute-candies-among-children-ii.md b/articles/distribute-candies-among-children-ii.md new file mode 100644 index 000000000..15096031a --- /dev/null +++ b/articles/distribute-candies-among-children-ii.md @@ -0,0 +1,505 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def distributeCandies(self, n: int, limit: int) -> int: + res = 0 + for a in range(limit + 1): + for b in range(limit + 1): + for c in range(limit + 1): + if a + b + c == n: + res += 1 + return res +``` + +```java +public class Solution { + public long distributeCandies(int n, int limit) { + long res = 0; + for (int a = 0; a <= limit; a++) { + for (int b = 0; b <= limit; b++) { + for (int c = 0; c <= limit; c++) { + if (a + b + c == n) { + res++; + } + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + long long distributeCandies(int n, int limit) { + long long res = 0; + for (int a = 0; a <= limit; a++) { + for (int b = 0; b <= limit; b++) { + for (int c = 0; c <= limit; c++) { + if (a + b + c == n) { + res++; + } + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} limit + * @return {number} + */ + distributeCandies(n, limit) { + let res = 0; + for (let a = 0; a <= limit; a++) { + for (let b = 0; b <= limit; b++) { + for (let c = 0; c <= limit; c++) { + if (a + b + c === n) { + res++; + } + } + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public long DistributeCandies(int n, int limit) { + long res = 0; + for (int a = 0; a <= limit; a++) { + for (int b = 0; b <= limit; b++) { + for (int c = 0; c <= limit; c++) { + if (a + b + c == n) { + res++; + } + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(l ^ 3)$ +- Space complexity: $O(1)$ + +> Where $l$ is the given limit. + +--- + +## 2. Better Approach + +::tabs-start + +```python +class Solution: + def distributeCandies(self, n: int, limit: int) -> int: + res = 0 + for a in range(min(n, limit) + 1): + for b in range(min(n - a, limit) + 1): + if n - a - b <= limit: + res += 1 + return res +``` + +```java +public class Solution { + public long distributeCandies(int n, int limit) { + long res = 0; + int maxA = Math.min(n, limit); + for (int a = 0; a <= maxA; a++) { + int maxB = Math.min(n - a, limit); + for (int b = 0; b <= maxB; b++) { + if (n - a - b <= limit) { + res++; + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + long long distributeCandies(int n, int limit) { + long long res = 0; + int maxA = min(n, limit); + for (int a = 0; a <= maxA; a++) { + int maxB = min(n - a, limit); + for (int b = 0; b <= maxB; b++) { + if (n - a - b <= limit) { + res++; + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} limit + * @return {number} + */ + distributeCandies(n, limit) { + let res = 0; + const maxA = Math.min(n, limit); + for (let a = 0; a <= maxA; a++) { + const maxB = Math.min(n - a, limit); + for (let b = 0; b <= maxB; b++) { + if (n - a - b <= limit) { + res++; + } + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public long DistributeCandies(int n, int limit) { + long res = 0; + int maxA = Math.Min(n, limit); + for (int a = 0; a <= maxA; a++) { + int maxB = Math.Min(n - a, limit); + for (int b = 0; b <= maxB; b++) { + if (n - a - b <= limit) { + res++; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(min(n, limit) ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 3. Enumeration - I + +::tabs-start + +```python +class Solution: + def distributeCandies(self, n: int, limit: int) -> int: + res = 0 + for a in range(min(n, limit) + 1): + b_max = min(n - a, limit) + b_min = max(0, n - a - limit) + if b_max >= b_min: + res += b_max - b_min + 1 + return res +``` + +```java +public class Solution { + public long distributeCandies(int n, int limit) { + long res = 0; + for (int a = 0, aMax = Math.min(n, limit); a <= aMax; a++) { + int bMax = Math.min(n - a, limit); + int bMin = Math.max(0, n - a - limit); + if (bMax >= bMin) { + res += (long)(bMax - bMin + 1); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + long long distributeCandies(int n, int limit) { + long long res = 0; + int aMax = min(n, limit); + for (int a = 0; a <= aMax; ++a) { + int bMax = min(n - a, limit); + int bMin = max(0, n - a - limit); + if (bMax >= bMin) { + res += (long long)(bMax - bMin + 1); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} limit + * @return {number} + */ + distributeCandies(n, limit) { + let res = 0; + const aMax = Math.min(n, limit); + for (let a = 0; a <= aMax; a++) { + const bMax = Math.min(n - a, limit); + const bMin = Math.max(0, n - a - limit); + if (bMax >= bMin) { + res += bMax - bMin + 1; + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public long DistributeCandies(int n, int limit) { + long res = 0; + int aMax = Math.Min(n, limit); + for (int a = 0; a <= aMax; a++) { + int bMax = Math.Min(n - a, limit); + int bMin = Math.Max(0, n - a - limit); + if (bMax >= bMin) { + res += (long)(bMax - bMin + 1); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(min(n, limit))$ +- Space complexity: $O(1)$ + +--- + +## 4. Enumeration - II + +::tabs-start + +```python +class Solution: + def distributeCandies(self, n: int, limit: int) -> int: + res = 0 + for a in range(min(n, limit) + 1): + if n - a <= 2 * limit: + res += min(n - a, limit) - max(0, n - a - limit) + 1 + return res +``` + +```java +public class Solution { + public long distributeCandies(int n, int limit) { + long res = 0; + int maxA = Math.min(n, limit); + for (int a = 0; a <= maxA; a++) { + int rem = n - a; + if (rem <= 2L * limit) { + int hi = Math.min(rem, limit); + int lo = Math.max(0, rem - limit); + res += (hi - lo + 1); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + long long distributeCandies(int n, int limit) { + long long res = 0; + int maxA = min(n, limit); + for (int a = 0; a <= maxA; ++a) { + int rem = n - a; + if (rem <= 2 * limit) { + int hi = min(rem, limit); + int lo = max(0, rem - limit); + res += (long long)(hi - lo + 1); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} limit + * @return {number} + */ + distributeCandies(n, limit) { + let res = 0; + const maxA = Math.min(n, limit); + for (let a = 0; a <= maxA; a++) { + const rem = n - a; + if (rem <= 2 * limit) { + const hi = Math.min(rem, limit); + const lo = Math.max(0, rem - limit); + res += hi - lo + 1; + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public long DistributeCandies(int n, int limit) { + long res = 0; + int maxA = Math.Min(n, limit); + for (int a = 0; a <= maxA; a++) { + int rem = n - a; + if (rem <= 2 * limit) { + int hi = Math.Min(rem, limit); + int lo = Math.Max(0, rem - limit); + res += (hi - lo + 1); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(min(n, limit))$ +- Space complexity: $O(1)$ + +--- + +## 5. Inclusion-Exclusion Principle + +::tabs-start + +```python +class Solution: + def distributeCandies(self, n: int, limit: int) -> int: + C3 = [1, 3, 3, 1] + res = 0 + for j in range(4): + m = n - j * (limit + 1) + if m < 0: + continue + ways = (m + 2) * (m + 1) // 2 + sign = -1 if j % 2 else 1 + res += sign * C3[j] * ways + return res +``` + +```java +public class Solution { + public long distributeCandies(int n, int limit) { + int[] C3 = {1, 3, 3, 1}; + long res = 0; + for (int j = 0; j < 4; j++) { + long m = n - j * (limit + 1); + if (m < 0) continue; + long ways = (m + 2) * (m + 1) / 2; + int sign = (j % 2 == 0) ? 1 : -1; + res += sign * C3[j] * ways; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + long long distributeCandies(int n, int limit) { + int C3[4] = {1, 3, 3, 1}; + long long res = 0; + for (int j = 0; j < 4; j++) { + long long m = n - j * (limit + 1); + if (m < 0) continue; + long long ways = (m + 2) * (m + 1) / 2; + int sign = (j % 2 == 0 ? 1 : -1); + res += sign * C3[j] * ways; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} limit + * @return {number} + */ + distributeCandies(n, limit) { + const C3 = [1, 3, 3, 1]; + let res = 0; + for (let j = 0; j < 4; j++) { + const m = n - j * (limit + 1); + if (m < 0) continue; + const ways = ((m + 2) * (m + 1)) / 2; + const sign = j % 2 === 0 ? 1 : -1; + res += sign * C3[j] * ways; + } + return res; + } +} +``` + +```csharp +public class Solution { + public long DistributeCandies(int n, int limit) { + int[] C3 = {1, 3, 3, 1}; + long res = 0; + for (int j = 0; j < 4; j++) { + long m = n - j * (limit + 1); + if (m < 0) continue; + long ways = (m + 2) * (m + 1) / 2; + int sign = (j % 2 == 0 ? 1 : -1); + res += sign * C3[j] * ways; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ diff --git a/articles/distribute-coins-in-binary-tree.md b/articles/distribute-coins-in-binary-tree.md new file mode 100644 index 000000000..fd39506bb --- /dev/null +++ b/articles/distribute-coins-in-binary-tree.md @@ -0,0 +1,723 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def distributeCoins(self, root: Optional[TreeNode]) -> int: + self.res = 0 + + def dfs(cur): + if not cur: + return [0, 0] # [size, coins] + + l_size, l_coins = dfs(cur.left) + r_size, r_coins = dfs(cur.right) + + size = 1 + l_size + r_size + coins = cur.val + l_coins + r_coins + self.res += abs(size - coins) + + return [size, coins] + + dfs(root) + return self.res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private int res; + + public int distributeCoins(TreeNode root) { + res = 0; + dfs(root); + return res; + } + + private int[] dfs(TreeNode cur) { + if (cur == null) { + return new int[]{0, 0}; // [size, coins] + } + + int[] left = dfs(cur.left); + int[] right = dfs(cur.right); + + int size = 1 + left[0] + right[0]; + int coins = cur.val + left[1] + right[1]; + res += Math.abs(size - coins); + + return new int[]{size, coins}; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +private: + int res; + + vector dfs(TreeNode* cur) { + if (!cur) { + return {0, 0}; // [size, coins] + } + + vector left = dfs(cur->left); + vector right = dfs(cur->right); + + int size = 1 + left[0] + right[0]; + int coins = cur->val + left[1] + right[1]; + res += abs(size - coins); + + return {size, coins}; + } + +public: + int distributeCoins(TreeNode* root) { + res = 0; + dfs(root); + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + distributeCoins(root) { + let res = 0; + + const dfs = (cur) => { + if (!cur) { + return [0, 0]; // [size, coins] + } + + let [lSize, lCoins] = dfs(cur.left); + let [rSize, rCoins] = dfs(cur.right); + + let size = 1 + lSize + rSize; + let coins = cur.val + lCoins + rCoins; + res += Math.abs(size - coins); + + return [size, coins]; + }; + + dfs(root); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Depth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def distributeCoins(self, root: Optional[TreeNode]) -> int: + self.res = 0 + + def dfs(cur): + if not cur: + return 0 # extra_coins + + l_extra = dfs(cur.left) + r_extra = dfs(cur.right) + + extra_coins = cur.val - 1 + l_extra + r_extra + self.res += abs(extra_coins) + return extra_coins + + dfs(root) + return self.res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private int res; + + public int distributeCoins(TreeNode root) { + res = 0; + dfs(root); + return res; + } + + private int dfs(TreeNode cur) { + if (cur == null) { + return 0; // extra_coins + } + + int lExtra = dfs(cur.left); + int rExtra = dfs(cur.right); + + int extraCoins = cur.val - 1 + lExtra + rExtra; + res += Math.abs(extraCoins); + return extraCoins; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +private: + int res; + + int dfs(TreeNode* cur) { + if (!cur) { + return 0; // extra_coins + } + + int lExtra = dfs(cur->left); + int rExtra = dfs(cur->right); + + int extraCoins = cur->val - 1 + lExtra + rExtra; + res += abs(extraCoins); + return extraCoins; + } + +public: + int distributeCoins(TreeNode* root) { + res = 0; + dfs(root); + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + distributeCoins(root) { + let res = 0; + + const dfs = (cur) => { + if (!cur) { + return 0; // extra_coins + } + + let lExtra = dfs(cur.left); + let rExtra = dfs(cur.right); + + let extraCoins = cur.val - 1 + lExtra + rExtra; + res += Math.abs(extraCoins); + return extraCoins; + }; + + dfs(root); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ fo recursion stack. + +--- + +## 3. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def distributeCoins(self, root: Optional[TreeNode]) -> int: + res = 0 + q = deque([root]) + parent_map = {} + + nodes = [] + while q: + node = q.popleft() + nodes.append(node) + if node.left: + parent_map[node.left] = node + q.append(node.left) + if node.right: + parent_map[node.right] = node + q.append(node.right) + + while nodes: + node = nodes.pop() + if node in parent_map: + parent = parent_map[node] + parent.val += node.val - 1 + res += abs(node.val - 1) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int distributeCoins(TreeNode root) { + int res = 0; + Queue q = new LinkedList<>(); + Map parentMap = new HashMap<>(); + List nodes = new ArrayList<>(); + + q.offer(root); + while (!q.isEmpty()) { + TreeNode node = q.poll(); + nodes.add(node); + if (node.left != null) { + parentMap.put(node.left, node); + q.offer(node.left); + } + if (node.right != null) { + parentMap.put(node.right, node); + q.offer(node.right); + } + } + + for (int i = nodes.size() - 1; i >= 0; i--) { + TreeNode node = nodes.get(i); + if (parentMap.containsKey(node)) { + TreeNode parent = parentMap.get(node); + parent.val += node.val - 1; + res += Math.abs(node.val - 1); + } + } + + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int distributeCoins(TreeNode* root) { + int res = 0; + queue q; + unordered_map parentMap; + vector nodes; + + q.push(root); + while (!q.empty()) { + TreeNode* node = q.front(); + q.pop(); + nodes.push_back(node); + if (node->left) { + parentMap[node->left] = node; + q.push(node->left); + } + if (node->right) { + parentMap[node->right] = node; + q.push(node->right); + } + } + + for (int i = nodes.size() - 1; i >= 0; i--) { + TreeNode* node = nodes[i]; + if (parentMap.count(node)) { + TreeNode* parent = parentMap[node]; + parent->val += node->val - 1; + res += abs(node->val - 1); + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + distributeCoins(root) { + let res = 0; + let q = new Queue(); + let parentMap = new Map(); + let nodes = []; + + q.push(root); + while (!q.isEmpty()) { + let node = q.pop(); + nodes.push(node); + if (node.left) { + parentMap.set(node.left, node); + q.push(node.left); + } + if (node.right) { + parentMap.set(node.right, node); + q.push(node.right); + } + } + + for (let i = nodes.length - 1; i >= 0; i--) { + let node = nodes[i]; + if (parentMap.has(node)) { + let parent = parentMap.get(node); + parent.val += node.val - 1; + res += Math.abs(node.val - 1); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def distributeCoins(self, root: Optional[TreeNode]) -> int: + stack = [root] + res = 0 + visit = set() + + while stack: + node = stack.pop() + + if node not in visit: + stack.append(node) + visit.add(node) + + if node.right: + stack.append(node.right) + if node.left: + stack.append(node.left) + else: + if node.left: + node.val += node.left.val + if node.right: + node.val += node.right.val + + node.val -= 1 + res += abs(node.val) + visit.remove(node) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int distributeCoins(TreeNode root) { + Stack stack = new Stack<>(); + Set visit = new HashSet<>(); + stack.push(root); + int res = 0; + + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + + if (!visit.contains(node)) { + stack.push(node); + visit.add(node); + + if (node.right != null) { + stack.push(node.right); + } + if (node.left != null) { + stack.push(node.left); + } + } else { + if (node.left != null) { + node.val += node.left.val; + } + if (node.right != null) { + node.val += node.right.val; + } + + node.val -= 1; + res += Math.abs(node.val); + visit.remove(node); + } + } + + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int distributeCoins(TreeNode* root) { + stack stack; + unordered_set visit; + stack.push(root); + int res = 0; + + while (!stack.empty()) { + TreeNode* node = stack.top(); + stack.pop(); + + if (visit.find(node) == visit.end()) { + stack.push(node); + visit.insert(node); + + if (node->right) { + stack.push(node->right); + } + if (node->left) { + stack.push(node->left); + } + } else { + if (node->left) { + node->val += node->left->val; + } + if (node->right) { + node->val += node->right->val; + } + + visit.erase(node); + node->val -= 1; + res += abs(node->val); + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + distributeCoins(root) { + let stack = [root]; + let visit = new Set(); + let res = 0; + + while (stack.length) { + let node = stack.pop(); + + if (!visit.has(node)) { + stack.push(node); + visit.add(node); + + if (node.right) { + stack.push(node.right); + } + if (node.left) { + stack.push(node.left); + } + } else { + if (node.left) { + node.val += node.left.val; + } + if (node.right) { + node.val += node.right.val; + } + + visit.delete(node); + node.val -= 1; + res += Math.abs(node.val); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/divide-array-into-arrays-with-max-difference.md b/articles/divide-array-into-arrays-with-max-difference.md index d969ca851..13a241fd4 100644 --- a/articles/divide-array-into-arrays-with-max-difference.md +++ b/articles/divide-array-into-arrays-with-max-difference.md @@ -12,7 +12,7 @@ class Solution: if nums[i + 2] - nums[i] > k: return [] res.append(nums[i: i + 3]) - + return res ``` @@ -82,8 +82,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ for the output array. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ for the output array. --- @@ -232,7 +232,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ -> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in $nums$. \ No newline at end of file +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in $nums$. diff --git a/articles/divide-array-into-equal-pairs.md b/articles/divide-array-into-equal-pairs.md new file mode 100644 index 000000000..d6a394aec --- /dev/null +++ b/articles/divide-array-into-equal-pairs.md @@ -0,0 +1,290 @@ +## 1. Sorting + +::tabs-start + +```python +class Solution: + def divideArray(self, nums: List[int]) -> bool: + N = len(nums) + nums.sort() + + i = 0 + while i < N: + j = i + while j < N and nums[i] == nums[j]: + j += 1 + + if (j - i) % 2 != 0: + return False + + i = j + + return True +``` + +```java +public class Solution { + public boolean divideArray(int[] nums) { + int N = nums.length; + Arrays.sort(nums); + + int i = 0; + while (i < N) { + int j = i; + while (j < N && nums[i] == nums[j]) { + j++; + } + + if ((j - i) % 2 != 0) { + return false; + } + + i = j; + } + + return true; + } +} +``` + +```cpp +class Solution { +public: + bool divideArray(vector& nums) { + int N = nums.size(); + sort(nums.begin(), nums.end()); + + int i = 0; + while (i < N) { + int j = i; + while (j < N && nums[i] == nums[j]) { + j++; + } + + if ((j - i) % 2 != 0) { + return false; + } + + i = j; + } + + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + divideArray(nums) { + const N = nums.length; + nums.sort((a, b) => a - b); + + let i = 0; + while (i < N) { + let j = i; + while (j < N && nums[i] === nums[j]) { + j++; + } + + if ((j - i) % 2 !== 0) { + return false; + } + + i = j; + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 2. Hash Map + +::tabs-start + +```python +class Solution: + def divideArray(self, nums: List[int]) -> bool: + count = {} + for num in nums: + if num not in count: + count[num] = 0 + count[num] += 1 + + for cnt in count.values(): + if cnt % 2 == 1: + return False + + return True +``` + +```java +public class Solution { + public boolean divideArray(int[] nums) { + Map count = new HashMap<>(); + for (int num : nums) { + count.put(num, count.getOrDefault(num, 0) + 1); + } + + for (int cnt : count.values()) { + if (cnt % 2 == 1) { + return false; + } + } + + return true; + } +} +``` + +```cpp +class Solution { +public: + bool divideArray(vector& nums) { + unordered_map count; + for (int num : nums) { + count[num]++; + } + + for (auto& [key, cnt] : count) { + if (cnt % 2 == 1) { + return false; + } + } + + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + divideArray(nums) { + const count = {}; + for (let num of nums) { + if (!(num in count)) { + count[num] = 0; + } + count[num]++; + } + + for (let key in count) { + if (count[key] % 2 === 1) { + return false; + } + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Hash Set + +::tabs-start + +```python +class Solution: + def divideArray(self, nums: List[int]) -> bool: + odd_set = set() + + for num in nums: + if num not in odd_set: + odd_set.add(num) + else: + odd_set.remove(num) + + return not len(odd_set) +``` + +```java +public class Solution { + public boolean divideArray(int[] nums) { + Set oddSet = new HashSet<>(); + + for (int num : nums) { + if (!oddSet.contains(num)) { + oddSet.add(num); + } else { + oddSet.remove(num); + } + } + + return oddSet.isEmpty(); + } +} +``` + +```cpp +class Solution { +public: + bool divideArray(vector& nums) { + unordered_set oddSet; + + for (int num : nums) { + if (oddSet.count(num)) { + oddSet.erase(num); + } else { + oddSet.insert(num); + } + } + + return oddSet.empty(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + divideArray(nums) { + const oddSet = new Set(); + + for (let num of nums) { + if (oddSet.has(num)) { + oddSet.delete(num); + } else { + oddSet.add(num); + } + } + + return oddSet.size === 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/dota2-senate.md b/articles/dota2-senate.md index 4e30f1d55..e330b7755 100644 --- a/articles/dota2-senate.md +++ b/articles/dota2-senate.md @@ -7,13 +7,12 @@ class Solution: def predictPartyVictory(self, senate: str) -> str: s = list(senate) while True: - if 'R' not in s: - return "Dire" - if 'D' not in s: - return "Radiant" - i = 0 while i < len(s): + if 'R' not in s: + return "Dire" + if 'D' not in s: + return "Radiant" if s[i] == 'R': j = (i + 1) % len(s) while s[j] == 'R': @@ -38,17 +37,16 @@ public class Solution { for (char c : senate.toCharArray()) { s.add(c); } - - while (true) { - if (!s.contains('R')) { - return "Dire"; - } - if (!s.contains('D')) { - return "Radiant"; - } + while (true) { int i = 0; while (i < s.size()) { + if (!s.contains('R')) { + return "Dire"; + } + if (!s.contains('D')) { + return "Radiant"; + } if (s.get(i) == 'R') { int j = (i + 1) % s.size(); while (s.get(j) == 'R') { @@ -80,17 +78,16 @@ class Solution { public: string predictPartyVictory(string senate) { vector s(senate.begin(), senate.end()); - - while (true) { - if (find(s.begin(), s.end(), 'R') == s.end()) { - return "Dire"; - } - if (find(s.begin(), s.end(), 'D') == s.end()) { - return "Radiant"; - } + while (true) { int i = 0; while (i < s.size()) { + if (find(s.begin(), s.end(), 'R') == s.end()) { + return "Dire"; + } + if (find(s.begin(), s.end(), 'D') == s.end()) { + return "Radiant"; + } if (s[i] == 'R') { int j = (i + 1) % s.size(); while (s[j] == 'R') { @@ -124,21 +121,20 @@ class Solution { * @return {string} */ predictPartyVictory(senate) { - const s = senate.split(""); - + const s = senate.split(''); + while (true) { - if (!s.includes("R")) { - return "Dire"; - } - if (!s.includes("D")) { - return "Radiant"; - } - let i = 0; while (i < s.length) { - if (s[i] === "R") { + if (!s.includes('R')) { + return 'Dire'; + } + if (!s.includes('D')) { + return 'Radiant'; + } + if (s[i] === 'R') { let j = (i + 1) % s.length; - while (s[j] === "R") { + while (s[j] === 'R') { j = (j + 1) % s.length; } s.splice(j, 1); @@ -147,7 +143,7 @@ class Solution { } } else { let j = (i + 1) % s.length; - while (s[j] === "D") { + while (s[j] === 'D') { j = (j + 1) % s.length; } s.splice(j, 1); @@ -162,12 +158,44 @@ class Solution { } ``` +```csharp +public class Solution { + public string PredictPartyVictory(string senate) { + List s = senate.ToList(); + + while (true) { + int i = 0; + while (i < s.Count) { + if (!s.Contains('R')) return "Dire"; + if (!s.Contains('D')) return "Radiant"; + if (s[i] == 'R') { + int j = (i + 1) % s.Count; + while (s[j] == 'R') { + j = (j + 1) % s.Count; + } + s.RemoveAt(j); + if (j < i) i--; + } else { + int j = (i + 1) % s.Count; + while (s[j] == 'D') { + j = (j + 1) % s.Count; + } + s.RemoveAt(j); + if (j < i) i--; + } + i++; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -273,7 +301,7 @@ class Solution { const n = senate.length; for (let i = 0; i < n; i++) { - if (senate[i] === "R") { + if (senate[i] === 'R') { R.push(i); } else { D.push(i); @@ -291,7 +319,38 @@ class Solution { } } - return !R.isEmpty() ? "Radiant" : "Dire"; + return !R.isEmpty() ? 'Radiant' : 'Dire'; + } +} +``` + +```csharp +public class Solution { + public string PredictPartyVictory(string senate) { + Queue D = new Queue(); + Queue R = new Queue(); + int n = senate.Length; + + for (int i = 0; i < n; i++) { + if (senate[i] == 'R') { + R.Enqueue(i); + } else { + D.Enqueue(i); + } + } + + while (D.Count > 0 && R.Count > 0) { + int dTurn = D.Dequeue(); + int rTurn = R.Dequeue(); + + if (rTurn < dTurn) { + R.Enqueue(rTurn + n); + } else { + D.Enqueue(dTurn + n); + } + } + + return R.Count > 0 ? "Radiant" : "Dire"; } } ``` @@ -300,8 +359,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -326,7 +385,7 @@ class Solution: senate.append('R') cnt -= 1 i += 1 - + return "Radiant" if cnt > 0 else "Dire" ``` @@ -392,7 +451,8 @@ class Solution { */ predictPartyVictory(senate) { let s = senate.split(''); - let cnt = 0, i = 0; + let cnt = 0, + i = 0; while (i < s.length) { const c = s[i]; @@ -410,6 +470,33 @@ class Solution { i++; } + return cnt > 0 ? 'Radiant' : 'Dire'; + } +} +``` + +```csharp +public class Solution { + public string PredictPartyVictory(string senate) { + List list = new List(senate); + int cnt = 0, i = 0; + + while (i < list.Count) { + char c = list[i]; + if (c == 'R') { + if (cnt < 0) { + list.Add('D'); + } + cnt++; + } else { // c == 'D' + if (cnt > 0) { + list.Add('R'); + } + cnt--; + } + i++; + } + return cnt > 0 ? "Radiant" : "Dire"; } } @@ -419,5 +506,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/duplicate-integer.md b/articles/duplicate-integer.md index c7b5e21f2..828d15e2e 100644 --- a/articles/duplicate-integer.md +++ b/articles/duplicate-integer.md @@ -40,7 +40,7 @@ public: } return false; } -}; +}; ``` ```javascript @@ -64,7 +64,7 @@ class Solution { ```csharp public class Solution { - public bool HasDuplicate(int[] nums) { + public bool hasDuplicate(int[] nums) { for (int i = 0; i < nums.Length; i++) { for (int j = i + 1; j < nums.Length; j++) { if (nums[i] == nums[j]) { @@ -105,12 +105,27 @@ class Solution { } ``` +```swift +class Solution { + func hasDuplicate(_ nums: [Int]) -> Bool { + for i in 0.. Bool { + var nums = nums.sorted() + for i in 1.. seen = new HashSet(); foreach (int num in nums) { if (seen.Contains(num)) { @@ -332,12 +361,27 @@ class Solution { } ``` +```swift +class Solution { + func hasDuplicate(_ nums: [Int]) -> Bool { + var seen = Set() + for num in nums { + if seen.contains(num) { + return true + } + seen.insert(num) + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -382,7 +426,7 @@ class Solution { ```csharp public class Solution { - public bool HasDuplicate(int[] nums) { + public bool hasDuplicate(int[] nums) { return new HashSet(nums).Count < nums.Length; } } @@ -406,9 +450,17 @@ class Solution { } ``` +```swift +class Solution { + func hasDuplicate(_ nums: [Int]) -> Bool { + return Set(nums).count < nums.count + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/eating-bananas.md b/articles/eating-bananas.md index bf00f6c04..938d7b892 100644 --- a/articles/eating-bananas.md +++ b/articles/eating-bananas.md @@ -10,7 +10,7 @@ class Solution: totalTime = 0 for pile in piles: totalTime += math.ceil(pile / speed) - + if totalTime <= h: return speed speed += 1 @@ -44,7 +44,7 @@ public: while (true) { long long totalTime = 0; for (int pile : piles) { - totalTime += (pile + speed - 1) / speed; + totalTime += (pile + speed - 1) / speed; } if (totalTime <= h) { @@ -107,7 +107,7 @@ func minEatingSpeed(piles []int, h int) int { for _, pile := range piles { totalTime += int(math.Ceil(float64(pile) / float64(speed))) } - + if totalTime <= h { return speed } @@ -126,7 +126,7 @@ class Solution { for (pile in piles) { totalTime += Math.ceil(pile.toDouble() / speed).toLong() } - + if (totalTime <= h) { return speed } @@ -137,12 +137,33 @@ class Solution { } ``` +```swift +class Solution { + func minEatingSpeed(_ piles: [Int], _ h: Int) -> Int { + var speed = 1 + + while true { + var totalTime = 0 + for pile in piles { + totalTime += Int(ceil(Double(pile) / Double(speed))) + } + + if totalTime <= h { + return speed + } + speed += 1 + } + return speed + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(1)$ > Where $n$ is the length of the input array $piles$ and $m$ is the maximum number of bananas in a pile. @@ -291,15 +312,15 @@ func minEatingSpeed(piles []int, h int) int { } } res := r - + for l <= r { k := (l + r) / 2 totalTime := 0 - + for _, p := range piles { totalTime += int(math.Ceil(float64(p) / float64(k))) } - + if totalTime <= h { res = k r = k - 1 @@ -317,15 +338,15 @@ class Solution { var l = 1 var r = piles.max()!! var res = r - + while (l <= r) { val k = (l + r) / 2 var totalTime = 0L - + for (p in piles) { totalTime += Math.ceil(p.toDouble() / k).toLong() } - + if (totalTime <= h) { res = k r = k - 1 @@ -338,11 +359,37 @@ class Solution { } ``` +```swift +class Solution { + func minEatingSpeed(_ piles: [Int], _ h: Int) -> Int { + var l = 1, r = piles.max()! + var res = r + + while l <= r { + let k = (l + r) / 2 + + var totalTime = 0 + for p in piles { + totalTime += Int(ceil(Double(p) / Double(k))) + } + + if totalTime <= h { + res = k + r = k - 1 + } else { + l = k + 1 + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * \log m)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n * \log m)$ +- Space complexity: $O(1)$ -> Where $n$ is the length of the input array $piles$ and $m$ is the maximum number of bananas in a pile. \ No newline at end of file +> Where $n$ is the length of the input array $piles$ and $m$ is the maximum number of bananas in a pile. diff --git a/articles/edit-distance.md b/articles/edit-distance.md index a116df5c7..64e70d7de 100644 --- a/articles/edit-distance.md +++ b/articles/edit-distance.md @@ -17,7 +17,7 @@ class Solution: res = min(dfs(i + 1, j), dfs(i, j + 1)) res = min(res, dfs(i + 1, j + 1)) return res + 1 - + return dfs(0, 0) ``` @@ -37,7 +37,7 @@ public class Solution { return dfs(i + 1, j + 1, word1, word2, m, n); } - int res = Math.min(dfs(i + 1, j, word1, word2, m, n), + int res = Math.min(dfs(i + 1, j, word1, word2, m, n), dfs(i, j + 1, word1, word2, m, n)); res = Math.min(res, dfs(i + 1, j + 1, word1, word2, m, n)); return res + 1; @@ -52,15 +52,15 @@ public: int m = word1.size(), n = word2.size(); return dfs(0, 0, word1, word2, m, n); } - + int dfs(int i, int j, string& word1, string& word2, int m, int n) { if (i == m) return n - j; if (j == n) return m - i; if (word1[i] == word2[j]){ return dfs(i + 1, j + 1, word1, word2, m, n); - } + } - int res = min(dfs(i + 1, j, word1, word2, m, n), + int res = min(dfs(i + 1, j, word1, word2, m, n), dfs(i, j + 1, word1, word2, m, n)); res = min(res, dfs(i + 1, j + 1, word1, word2, m, n)); return res + 1; @@ -76,7 +76,8 @@ class Solution { * @return {number} */ minDistance(word1, word2) { - const m = word1.length, n = word2.length; + const m = word1.length, + n = word2.length; const dfs = (i, j) => { if (i === m) return n - j; @@ -109,7 +110,7 @@ public class Solution { return Dfs(i + 1, j + 1, word1, word2, m, n); } - int res = Math.Min(Dfs(i + 1, j, word1, word2, m, n), + int res = Math.Min(Dfs(i + 1, j, word1, word2, m, n), Dfs(i, j + 1, word1, word2, m, n)); res = Math.Min(res, Dfs(i + 1, j + 1, word1, word2, m, n)); return res + 1; @@ -169,12 +170,33 @@ class Solution { } ``` +```swift +class Solution { + func minDistance(_ word1: String, _ word2: String) -> Int { + let m = word1.count, n = word2.count + let word1Array = Array(word1), word2Array = Array(word2) + + func dfs(_ i: Int, _ j: Int) -> Int { + if i == m { return n - j } + if j == n { return m - i } + if word1Array[i] == word2Array[j] { + return dfs(i + 1, j + 1) + } + let res = min(dfs(i + 1, j), dfs(i, j + 1)) + return min(res, dfs(i + 1, j + 1)) + 1 + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(3 ^ {m + n})$ -* Space complexity: $O(m + n)$ +- Time complexity: $O(3 ^ {m + n})$ +- Space complexity: $O(m + n)$ > Where $m$ is the length of $word1$ and $n$ is the length of $word2$. @@ -197,7 +219,7 @@ class Solution: return m - i if (i, j) in dp: return dp[(i, j)] - + if word1[i] == word2[j]: dp[(i, j)] = dfs(i + 1, j + 1) else: @@ -205,7 +227,7 @@ class Solution: res = min(res, dfs(i + 1, j + 1)) dp[(i, j)] = res + 1 return dp[(i, j)] - + return dfs(0, 0) ``` @@ -231,7 +253,7 @@ public class Solution { if (word1.charAt(i) == word2.charAt(j)) { dp[i][j] = dfs(i + 1, j + 1, word1, word2, m, n); } else { - int res = Math.min(dfs(i + 1, j, word1, word2, m, n), + int res = Math.min(dfs(i + 1, j, word1, word2, m, n), dfs(i, j + 1, word1, word2, m, n)); res = Math.min(res, dfs(i + 1, j + 1, word1, word2, m, n)); dp[i][j] = res + 1; @@ -250,7 +272,7 @@ public: dp = vector>(m, vector(n, -1)); return dfs(0, 0, word1, word2, m, n); } - + int dfs(int i, int j, string& word1, string& word2, int m, int n) { if (i == m) return n - j; if (j == n) return m - i; @@ -258,7 +280,7 @@ public: if (word1[i] == word2[j]){ dp[i][j] = dfs(i + 1, j + 1, word1, word2, m, n); } else { - int res = min(dfs(i + 1, j, word1, word2, m, n), + int res = min(dfs(i + 1, j, word1, word2, m, n), dfs(i, j + 1, word1, word2, m, n)); res = min(res, dfs(i + 1, j + 1, word1, word2, m, n)); dp[i][j] = res + 1; @@ -276,9 +298,9 @@ class Solution { * @return {number} */ minDistance(word1, word2) { - const m = word1.length, n = word2.length; - let dp = Array.from({ length: m + 1 }, () => - Array(n + 1).fill(-1)); + const m = word1.length, + n = word2.length; + let dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(-1)); const dfs = (i, j) => { if (i === m) return n - j; if (j === n) return m - i; @@ -301,31 +323,31 @@ class Solution { ```csharp public class Solution { - private int?[,] dp; + private int?[,] dp; public int MinDistance(string word1, string word2) { int m = word1.Length, n = word2.Length; - dp = new int?[m + 1, n + 1]; + dp = new int?[m + 1, n + 1]; return Dfs(0, 0, word1, word2, m, n); } private int Dfs(int i, int j, string word1, string word2, int m, int n) { - if (i == m) return n - j; - if (j == n) return m - i; + if (i == m) return n - j; + if (j == n) return m - i; - if (dp[i, j].HasValue) { + if (dp[i, j].HasValue) { return dp[i, j].Value; } if (word1[i] == word2[j]) { - dp[i, j] = Dfs(i + 1, j + 1, word1, word2, m, n); + dp[i, j] = Dfs(i + 1, j + 1, word1, word2, m, n); } else { - int res = Math.Min(Dfs(i + 1, j, word1, word2, m, n), + int res = Math.Min(Dfs(i + 1, j, word1, word2, m, n), Dfs(i, j + 1, word1, word2, m, n)); - res = Math.Min(res, Dfs(i + 1, j + 1, word1, word2, m, n)); - dp[i, j] = res + 1; + res = Math.Min(res, Dfs(i + 1, j + 1, word1, word2, m, n)); + dp[i, j] = res + 1; } - return dp[i, j].Value; + return dp[i, j].Value; } } ``` @@ -337,7 +359,7 @@ func minDistance(word1 string, word2 string) int { for i := range dp { dp[i] = make([]int, n+1) for j := range dp[i] { - dp[i][j] = -1 + dp[i][j] = -1 } } @@ -403,12 +425,38 @@ class Solution { } ``` +```swift +class Solution { + func minDistance(_ word1: String, _ word2: String) -> Int { + let m = word1.count, n = word2.count + let word1Array = Array(word1), word2Array = Array(word2) + var dp = [[Int?]](repeating: [Int?](repeating: nil, count: n + 1), count: m + 1) + + func dfs(_ i: Int, _ j: Int) -> Int { + if i == m { return n - j } + if j == n { return m - i } + if let val = dp[i][j] { return val } + + if word1Array[i] == word2Array[j] { + dp[i][j] = dfs(i + 1, j + 1) + } else { + let res = min(dfs(i + 1, j), dfs(i, j + 1), dfs(i + 1, j + 1)) + 1 + dp[i][j] = res + } + return dp[i][j]! + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the length of $word1$ and $n$ is the length of $word2$. @@ -454,7 +502,7 @@ public class Solution { if (word1.charAt(i) == word2.charAt(j)) { dp[i][j] = dp[i + 1][j + 1]; } else { - dp[i][j] = 1 + Math.min(dp[i + 1][j], + dp[i][j] = 1 + Math.min(dp[i + 1][j], Math.min(dp[i][j + 1], dp[i + 1][j + 1])); } } @@ -468,7 +516,7 @@ public class Solution { class Solution { public: int minDistance(string word1, string word2) { - vector> dp(word1.length() + 1, + vector> dp(word1.length() + 1, vector(word2.length() + 1, 0)); for (int j = 0; j <= word2.length(); j++) { @@ -483,7 +531,7 @@ public: if (word1[i] == word2[j]) { dp[i][j] = dp[i + 1][j + 1]; } else { - dp[i][j] = 1 + min(dp[i + 1][j], + dp[i][j] = 1 + min(dp[i + 1][j], min(dp[i][j + 1], dp[i + 1][j + 1])); } } @@ -548,7 +596,7 @@ public class Solution { if (word1[i] == word2[j]) { dp[i, j] = dp[i + 1, j + 1]; } else { - dp[i, j] = 1 + Math.Min(dp[i + 1, j], + dp[i, j] = 1 + Math.Min(dp[i + 1, j], Math.Min(dp[i, j + 1], dp[i + 1, j + 1])); } } @@ -578,7 +626,7 @@ func minDistance(word1, word2 string) int { if word1[i] == word2[j] { dp[i][j] = dp[i+1][j+1] } else { - dp[i][j] = 1 + min(dp[i+1][j], + dp[i][j] = 1 + min(dp[i+1][j], min(dp[i][j+1], dp[i+1][j+1])) } } @@ -614,7 +662,7 @@ class Solution { if (word1[i] == word2[j]) { dp[i][j] = dp[i + 1][j + 1] } else { - dp[i][j] = 1 + minOf(dp[i + 1][j], + dp[i][j] = 1 + minOf(dp[i + 1][j], minOf(dp[i][j + 1], dp[i + 1][j + 1])) } } @@ -624,12 +672,40 @@ class Solution { } ``` +```swift +class Solution { + func minDistance(_ word1: String, _ word2: String) -> Int { + let m = word1.count, n = word2.count + let word1Array = Array(word1), word2Array = Array(word2) + var dp = [[Int]](repeating: [Int](repeating: Int.max, count: n + 1), count: m + 1) + + for j in 0...n { + dp[m][j] = n - j + } + for i in 0...m { + dp[i][n] = m - i + } + + for i in stride(from: m - 1, through: 0, by: -1) { + for j in stride(from: n - 1, through: 0, by: -1) { + if word1Array[i] == word2Array[j] { + dp[i][j] = dp[i + 1][j + 1] + } else { + dp[i][j] = 1 + min(dp[i + 1][j], dp[i][j + 1], dp[i + 1][j + 1]) + } + } + } + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the length of $word1$ and $n$ is the length of $word2$. @@ -661,7 +737,7 @@ class Solution: else: nextDp[j] = 1 + min(dp[j], nextDp[j + 1], dp[j + 1]) dp = nextDp[:] - + return dp[0] ``` @@ -680,7 +756,7 @@ class Solution { int[] dp = new int[n + 1]; int[] nextDp = new int[n + 1]; - + for (int j = 0; j <= n; j++) { dp[j] = n - j; } @@ -691,13 +767,13 @@ class Solution { if (word1.charAt(i) == word2.charAt(j)) { nextDp[j] = dp[j + 1]; } else { - nextDp[j] = 1 + Math.min(dp[j], + nextDp[j] = 1 + Math.min(dp[j], Math.min(nextDp[j + 1], dp[j + 1])); } } System.arraycopy(nextDp, 0, dp, 0, n + 1); } - + return dp[0]; } } @@ -714,7 +790,7 @@ public: } vector dp(n + 1), nextDp(n + 1); - + for (int j = 0; j <= n; ++j) { dp[j] = n - j; } @@ -743,7 +819,8 @@ class Solution { * @return {number} */ minDistance(word1, word2) { - let m = word1.length, n = word2.length; + let m = word1.length, + n = word2.length; if (m < n) { [m, n] = [n, m]; [word1, word2] = [word2, word1]; @@ -762,8 +839,8 @@ class Solution { if (word1[i] === word2[j]) { nextDp[j] = dp[j + 1]; } else { - nextDp[j] = 1 + Math.min(dp[j], - Math.min(nextDp[j + 1], dp[j + 1])); + nextDp[j] = + 1 + Math.min(dp[j], Math.min(nextDp[j + 1], dp[j + 1])); } } dp = [...nextDp]; @@ -800,7 +877,7 @@ public class Solution { if (word1[i] == word2[j]) { nextDp[j] = dp[j + 1]; } else { - nextDp[j] = 1 + Math.Min(dp[j], + nextDp[j] = 1 + Math.Min(dp[j], Math.Min(nextDp[j + 1], dp[j + 1])); } } @@ -833,13 +910,13 @@ func minDistance(word1, word2 string) int { if word1[i] == word2[j] { nextDp[j] = dp[j+1] } else { - nextDp[j] = 1 + min(dp[j], + nextDp[j] = 1 + min(dp[j], min(nextDp[j+1], dp[j+1])) } } dp, nextDp = nextDp, dp } - + return dp[0] } @@ -890,12 +967,47 @@ class Solution { } ``` +```swift +class Solution { + func minDistance(_ word1: String, _ word2: String) -> Int { + var m = word1.count, n = word2.count + var word1Array = Array(word1), word2Array = Array(word2) + + if m < n { + swap(&m, &n) + swap(&word1Array, &word2Array) + } + + var dp = [Int](repeating: 0, count: n + 1) + var nextDp = [Int](repeating: 0, count: n + 1) + + for j in 0...n { + dp[j] = n - j + } + + for i in stride(from: m - 1, through: 0, by: -1) { + nextDp[n] = m - i + for j in stride(from: n - 1, through: 0, by: -1) { + if word1Array[i] == word2Array[j] { + nextDp[j] = dp[j + 1] + } else { + nextDp[j] = 1 + min(dp[j], nextDp[j + 1], dp[j + 1]) + } + } + dp = nextDp + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(min(m, n))$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(min(m, n))$ > Where $m$ is the length of $word1$ and $n$ is the length of $word2$. @@ -912,7 +1024,7 @@ class Solution: if m < n: m, n = n, m word1, word2 = word2, word1 - + dp = [n - i for i in range(n + 1)] for i in range(m - 1, -1, -1): @@ -948,7 +1060,7 @@ public class Solution { if (word1.charAt(i) == word2.charAt(j)) { dp[j] = nextDp; } else { - dp[j] = 1 + Math.min(dp[j], + dp[j] = 1 + Math.min(dp[j], Math.min(dp[j + 1], nextDp)); } nextDp = temp; @@ -998,7 +1110,8 @@ class Solution { * @return {number} */ minDistance(word1, word2) { - let m = word1.length, n = word2.length; + let m = word1.length, + n = word2.length; if (m < n) { [m, n] = [n, m]; [word1, word2] = [word2, word1]; @@ -1048,7 +1161,7 @@ public class Solution { if (word1[i] == word2[j]) { dp[j] = nextDp; } else { - dp[j] = 1 + Math.Min(dp[j], + dp[j] = 1 + Math.Min(dp[j], Math.Min(dp[j + 1], nextDp)); } nextDp = temp; @@ -1080,7 +1193,7 @@ func minDistance(word1, word2 string) int { if word1[i] == word2[j] { dp[j] = nextDp } else { - dp[j] = 1 + min(dp[j], + dp[j] = 1 + min(dp[j], min(dp[j+1], nextDp)) } nextDp = temp @@ -1134,11 +1247,42 @@ class Solution { } ``` +```swift +class Solution { + func minDistance(_ word1: String, _ word2: String) -> Int { + var m = word1.count, n = word2.count + var word1Array = Array(word1), word2Array = Array(word2) + + if m < n { + swap(&m, &n) + swap(&word1Array, &word2Array) + } + + var dp = (0...n).map { n - $0 } + + for i in stride(from: m - 1, through: 0, by: -1) { + var nextDp = dp[n] + dp[n] = m - i + for j in stride(from: n - 1, through: 0, by: -1) { + let temp = dp[j] + if word1Array[i] == word2Array[j] { + dp[j] = nextDp + } else { + dp[j] = 1 + min(dp[j], dp[j + 1], nextDp) + } + nextDp = temp + } + } + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(min(m, n))$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(min(m, n))$ -> Where $m$ is the length of $word1$ and $n$ is the length of $word2$. \ No newline at end of file +> Where $m$ is the length of $word1$ and $n$ is the length of $word2$. diff --git a/articles/eliminate-maximum-number-of-monsters.md b/articles/eliminate-maximum-number-of-monsters.md new file mode 100644 index 000000000..a3f9acc21 --- /dev/null +++ b/articles/eliminate-maximum-number-of-monsters.md @@ -0,0 +1,298 @@ +## 1. Sorting + +::tabs-start + +```python +class Solution: + def eliminateMaximum(self, dist: List[int], speed: List[int]) -> int: + minReach = [math.ceil(d / s) for d, s in zip(dist, speed)] + minReach.sort() + + res = 0 + for minute in range(len(minReach)): + if minute >= minReach[minute]: + return res + res += 1 + + return res +``` + +```java +public class Solution { + public int eliminateMaximum(int[] dist, int[] speed) { + int n = dist.length; + int[] minReach = new int[n]; + + for (int i = 0; i < n; i++) { + minReach[i] = (int) Math.ceil((double) dist[i] / speed[i]); + } + + Arrays.sort(minReach); + + int res = 0; + for (int minute = 0; minute < n; minute++) { + if (minute >= minReach[minute]) { + return res; + } + res++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int eliminateMaximum(vector& dist, vector& speed) { + int n = dist.size(); + vector minReach(n); + + for (int i = 0; i < n; i++) { + minReach[i] = ceil((double)dist[i] / speed[i]); + } + + sort(minReach.begin(), minReach.end()); + + int res = 0; + for (int minute = 0; minute < n; minute++) { + if (minute >= minReach[minute]) { + return res; + } + res++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} dist + * @param {number[]} speed + * @return {number} + */ + eliminateMaximum(dist, speed) { + let n = dist.length; + let minReach = new Array(n); + + for (let i = 0; i < n; i++) { + minReach[i] = Math.ceil(dist[i] / speed[i]); + } + + minReach.sort((a, b) => a - b); + + let res = 0; + for (let minute = 0; minute < n; minute++) { + if (minute >= minReach[minute]) { + return res; + } + res++; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Sorting (Overwrting Input Array) + +::tabs-start + +```python +class Solution: + def eliminateMaximum(self, dist: List[int], speed: List[int]) -> int: + for i in range(len(dist)): + dist[i] = math.ceil(dist[i] / speed[i]) + + dist.sort() + for minute in range(len(dist)): + if minute >= dist[minute]: + return minute + + return len(dist) +``` + +```java +public class Solution { + public int eliminateMaximum(int[] dist, int[] speed) { + int n = dist.length; + for (int i = 0; i < n; i++) { + dist[i] = (int) Math.ceil((double) dist[i] / speed[i]); + } + + Arrays.sort(dist); + for (int minute = 0; minute < n; minute++) { + if (minute >= dist[minute]) { + return minute; + } + } + + return n; + } +} +``` + +```cpp +class Solution { +public: + int eliminateMaximum(vector& dist, vector& speed) { + int n = dist.size(); + for (int i = 0; i < n; i++) { + dist[i] = ceil((double)dist[i] / speed[i]); + } + + sort(dist.begin(), dist.end()); + for (int minute = 0; minute < n; minute++) { + if (minute >= dist[minute]) { + return minute; + } + } + + return n; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} dist + * @param {number[]} speed + * @return {number} + */ + eliminateMaximum(dist, speed) { + let n = dist.length; + for (let i = 0; i < n; i++) { + dist[i] = Math.ceil(dist[i] / speed[i]); + } + + dist.sort((a, b) => a - b); + for (let minute = 0; minute < n; minute++) { + if (minute >= dist[minute]) { + return minute; + } + } + + return n; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 3. Min-Heap + +::tabs-start + +```python +class Solution: + def eliminateMaximum(self, dist: List[int], speed: List[int]) -> int: + minHeap = [] + for i in range(len(dist)): + heapq.heappush(minHeap, dist[i] / speed[i]) + + res = 0 + while minHeap: + if res >= heapq.heappop(minHeap): + return res + res += 1 + + return res +``` + +```java +public class Solution { + public int eliminateMaximum(int[] dist, int[] speed) { + PriorityQueue minHeap = new PriorityQueue<>(); + for (int i = 0; i < dist.length; i++) { + minHeap.add((double) dist[i] / speed[i]); + } + + int res = 0; + while (!minHeap.isEmpty()) { + if (res >= minHeap.poll()) { + return res; + } + res++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int eliminateMaximum(vector& dist, vector& speed) { + priority_queue, greater> minHeap; + for (int i = 0; i < dist.size(); i++) { + minHeap.push((double)dist[i] / speed[i]); + } + + int res = 0; + while (!minHeap.empty()) { + if (res >= minHeap.top()) { + return res; + } + minHeap.pop(); + res++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} dist + * @param {number[]} speed + * @return {number} + */ + eliminateMaximum(dist, speed) { + const minHeap = new MinPriorityQueue(); + for (let i = 0; i < dist.length; i++) { + minHeap.enqueue(dist[i] / speed[i]); + } + + let res = 0; + while (!minHeap.isEmpty()) { + if (res >= minHeap.dequeue().element) { + return res; + } + res++; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/encode-and-decode-tinyurl.md b/articles/encode-and-decode-tinyurl.md index 0da60014f..06ca58c8e 100644 --- a/articles/encode-and-decode-tinyurl.md +++ b/articles/encode-and-decode-tinyurl.md @@ -87,8 +87,8 @@ class Codec { ### Time & Space Complexity -* Time complexity: $O(1)$ for $encode()$ and $decode()$. -* Space complexity: $O(n * m)$ +- Time complexity: $O(1)$ for $encode()$ and $decode()$. +- Space complexity: $O(n * m)$ > Where $n$ is the number of $longUrls$, $m$ is the average length of the URLs. @@ -193,8 +193,8 @@ class Codec { ### Time & Space Complexity -* Time complexity: $O(1)$ for $encode()$ and $decode()$. -* Space complexity: $O(n * m)$ +- Time complexity: $O(1)$ for $encode()$ and $decode()$. +- Space complexity: $O(n * m)$ > Where $n$ is the number of $longUrls$, $m$ is the average length of the URLs. @@ -206,7 +206,7 @@ class Codec { ```python class Codec: - + def __init__(self): self.encodeMap = {} self.decodeMap = {} @@ -272,7 +272,7 @@ class Codec { constructor() { this.encodeMap = new Map(); this.decodeMap = new Map(); - this.base = "http://tinyurl.com/"; + this.base = 'http://tinyurl.com/'; } /** @@ -306,7 +306,7 @@ class Codec { ### Time & Space Complexity -* Time complexity: $O(1)$ for $encode()$ and $decode()$. -* Space complexity: $O(n * m)$ +- Time complexity: $O(1)$ for $encode()$ and $decode()$. +- Space complexity: $O(n * m)$ -> Where $n$ is the number of $longUrls$, $m$ is the average length of the URLs. \ No newline at end of file +> Where $n$ is the number of $longUrls$, $m$ is the average length of the URLs. diff --git a/articles/evaluate-boolean-binary-tree.md b/articles/evaluate-boolean-binary-tree.md new file mode 100644 index 000000000..96c0e9ada --- /dev/null +++ b/articles/evaluate-boolean-binary-tree.md @@ -0,0 +1,313 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def evaluateTree(self, root: Optional[TreeNode]) -> bool: + if not root.left: + return root.val == 1 + + if root.val == 2: + return self.evaluateTree(root.left) or self.evaluateTree(root.right) + + if root.val == 3: + return self.evaluateTree(root.left) and self.evaluateTree(root.right) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean evaluateTree(TreeNode root) { + if (root.left == null) { + return root.val == 1; + } + + if (root.val == 2) { + return evaluateTree(root.left) || evaluateTree(root.right); + } + + if (root.val == 3) { + return evaluateTree(root.left) && evaluateTree(root.right); + } + + return false; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool evaluateTree(TreeNode* root) { + if (!root->left) { + return root->val == 1; + } + + if (root->val == 2) { + return evaluateTree(root->left) || evaluateTree(root->right); + } + + if (root->val == 3) { + return evaluateTree(root->left) && evaluateTree(root->right); + } + + return false; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {boolean} + */ + evaluateTree(root) { + if (!root.left) { + return root.val === 1; + } + + if (root.val === 2) { + return ( + this.evaluateTree(root.left) || this.evaluateTree(root.right) + ); + } + + if (root.val === 3) { + return ( + this.evaluateTree(root.left) && this.evaluateTree(root.right) + ); + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def evaluateTree(self, root: Optional[TreeNode]) -> bool: + stack = [root] + value = {} # map (node -> value) + + while stack: + node = stack.pop() + + if not node.left: + value[node] = node.val == 1 + elif node.left in value: + if node.val == 2: + value[node] = value[node.left] or value[node.right] + if node.val == 3: + value[node] = value[node.left] and value[node.right] + else: + stack.extend([node, node.left, node.right]) + + return value[root] +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean evaluateTree(TreeNode root) { + Stack stack = new Stack<>(); + Map value = new HashMap<>(); + stack.push(root); + + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + + if (node.left == null) { + value.put(node, node.val == 1); + } else if (value.containsKey(node.left)) { + boolean leftValue = value.get(node.left); + boolean rightValue = value.get(node.right); + + if (node.val == 2) { + value.put(node, leftValue || rightValue); + } else if (node.val == 3) { + value.put(node, leftValue && rightValue); + } + } else { + stack.push(node); + stack.push(node.right); + stack.push(node.left); + } + } + + return value.get(root); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool evaluateTree(TreeNode* root) { + stack stk; + unordered_map value; + stk.push(root); + + while (!stk.empty()) { + TreeNode* node = stk.top(); + stk.pop(); + + if (!node->left) { + value[node] = node->val == 1; + } else if (value.count(node->left)) { + bool leftValue = value[node->left]; + bool rightValue = value[node->right]; + + if (node->val == 2) { + value[node] = leftValue || rightValue; + } else if (node->val == 3) { + value[node] = leftValue && rightValue; + } + } else { + stk.push(node); + stk.push(node->right); + stk.push(node->left); + } + } + + return value[root]; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {boolean} + */ + evaluateTree(root) { + const stack = [root]; + const value = new Map(); + + while (stack.length) { + const node = stack.pop(); + + if (!node.left) { + value.set(node, node.val === 1); + } else if (value.has(node.left)) { + const leftValue = value.get(node.left); + const rightValue = value.get(node.right); + + if (node.val === 2) { + value.set(node, leftValue || rightValue); + } else if (node.val === 3) { + value.set(node, leftValue && rightValue); + } + } else { + stack.push(node, node.right, node.left); + } + } + + return value.get(root); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/evaluate-division.md b/articles/evaluate-division.md index 647a8002b..b5a942f01 100644 --- a/articles/evaluate-division.md +++ b/articles/evaluate-division.md @@ -199,12 +199,62 @@ class Solution { } ``` +```csharp +public class Solution { + public double[] CalcEquation(List> equations, double[] values, List> queries) { + var adj = new Dictionary>(); + + for (int i = 0; i < equations.Count; i++) { + string a = equations[i][0]; + string b = equations[i][1]; + double val = values[i]; + + if (!adj.ContainsKey(a)) adj[a] = new List<(string, double)>(); + if (!adj.ContainsKey(b)) adj[b] = new List<(string, double)>(); + + adj[a].Add((b, val)); + adj[b].Add((a, 1.0 / val)); + } + + double Bfs(string src, string target) { + if (!adj.ContainsKey(src) || !adj.ContainsKey(target)) return -1.0; + var queue = new Queue<(string, double)>(); + var visited = new HashSet(); + + queue.Enqueue((src, 1.0)); + visited.Add(src); + + while (queue.Count > 0) { + var (node, weight) = queue.Dequeue(); + if (node == target) return weight; + + foreach (var (nei, w) in adj[node]) { + if (!visited.Contains(nei)) { + visited.Add(nei); + queue.Enqueue((nei, weight * w)); + } + } + } + + return -1.0; + } + + double[] res = new double[queries.Count]; + for (int i = 0; i < queries.Count; i++) { + res[i] = Bfs(queries[i][0], queries[i][1]); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(n + m)$ > Where $n$ is the number of unique strings and $m$ is the number of queries. @@ -391,12 +441,57 @@ class Solution { } ``` +```csharp +public class Solution { + public double[] CalcEquation(List> equations, double[] values, List> queries) { + var adj = new Dictionary>(); + + for (int i = 0; i < equations.Count; i++) { + string a = equations[i][0], b = equations[i][1]; + double val = values[i]; + + if (!adj.ContainsKey(a)) adj[a] = new List<(string, double)>(); + if (!adj.ContainsKey(b)) adj[b] = new List<(string, double)>(); + + adj[a].Add((b, val)); + adj[b].Add((a, 1.0 / val)); + } + + double Dfs(string src, string target, HashSet visited) { + if (!adj.ContainsKey(src) || !adj.ContainsKey(target)) return -1.0; + if (src == target) return 1.0; + + visited.Add(src); + + foreach (var (nei, weight) in adj[src]) { + if (!visited.Contains(nei)) { + double result = Dfs(nei, target, visited); + if (result != -1.0) { + return weight * result; + } + } + } + + return -1.0; + } + + double[] res = new double[queries.Count]; + for (int i = 0; i < queries.Count; i++) { + var visited = new HashSet(); + res[i] = Dfs(queries[i][0], queries[i][1], visited); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(n + m)$ > Where $n$ is the number of unique strings and $m$ is the number of queries. @@ -411,29 +506,29 @@ class UnionFind: def __init__(self): self.parent = {} self.weight = {} - + def add(self, x): if x not in self.parent: self.parent[x] = x self.weight[x] = 1.0 - + def find(self, x): if x != self.parent[x]: orig_parent = self.parent[x] self.parent[x] = self.find(self.parent[x]) self.weight[x] *= self.weight[orig_parent] return self.parent[x] - + def union(self, x, y, value): self.add(x) self.add(y) root_x = self.find(x) root_y = self.find(y) - + if root_x != root_y: self.parent[root_x] = root_y self.weight[root_x] = value * self.weight[y] / self.weight[x] - + def get_ratio(self, x, y): if x not in self.parent or y not in self.parent or self.find(x) != self.find(y): return -1.0 @@ -442,10 +537,10 @@ class UnionFind: class Solution: def calcEquation(self, equations: List[List[str]], values: List[float], queries: List[List[str]]) -> List[float]: uf = UnionFind() - + for (a, b), value in zip(equations, values): uf.union(a, b, value) - + return [uf.get_ratio(a, b) for a, b in queries] ``` @@ -610,7 +705,10 @@ class UnionFind { if (x !== this.parent.get(x)) { const origParent = this.parent.get(x); this.parent.set(x, this.find(origParent)); - this.weight.set(x, this.weight.get(x) * this.weight.get(origParent)); + this.weight.set( + x, + this.weight.get(x) * this.weight.get(origParent), + ); } return this.parent.get(x); } @@ -629,17 +727,24 @@ class UnionFind { if (rootX !== rootY) { this.parent.set(rootX, rootY); - this.weight.set(rootX, (value * this.weight.get(y)) / this.weight.get(x)); + this.weight.set( + rootX, + (value * this.weight.get(y)) / this.weight.get(x), + ); } } - + /** * @param {string} x * @param {string} y * @return {number} */ getRatio(x, y) { - if (!this.parent.has(x) || !this.parent.has(y) || this.find(x) !== this.find(y)) { + if ( + !this.parent.has(x) || + !this.parent.has(y) || + this.find(x) !== this.find(y) + ) { return -1.0; } return this.weight.get(x) / this.weight.get(y); @@ -666,12 +771,75 @@ class Solution { } ``` +```csharp +public class UnionFind { + private Dictionary parent = new Dictionary(); + private Dictionary weight = new Dictionary(); + + public void Add(string x) { + if (!parent.ContainsKey(x)) { + parent[x] = x; + weight[x] = 1.0; + } + } + + public string Find(string x) { + if (parent[x] != x) { + string origParent = parent[x]; + parent[x] = Find(origParent); + weight[x] *= weight[origParent]; + } + return parent[x]; + } + + public void Union(string x, string y, double value) { + Add(x); + Add(y); + string rootX = Find(x); + string rootY = Find(y); + + if (rootX != rootY) { + parent[rootX] = rootY; + weight[rootX] = value * weight[y] / weight[x]; + } + } + + public double GetRatio(string x, string y) { + if (!parent.ContainsKey(x) || !parent.ContainsKey(y) || Find(x) != Find(y)) { + return -1.0; + } + return weight[x] / weight[y]; + } +} + +public class Solution { + public double[] CalcEquation(List> equations, double[] values, List> queries) { + var uf = new UnionFind(); + + for (int i = 0; i < equations.Count; i++) { + string a = equations[i][0]; + string b = equations[i][1]; + uf.Union(a, b, values[i]); + } + + double[] res = new double[queries.Count]; + for (int i = 0; i < queries.Count; i++) { + string a = queries[i][0]; + string b = queries[i][1]; + res[i] = uf.GetRatio(a, b); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O((m + n)\log n)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O((m + n)\log n)$ +- Space complexity: $O(n + m)$ > Where $n$ is the number of unique strings and $m$ is the number of queries. @@ -809,7 +977,9 @@ class Solution { for (const i of graph.get(k).keys()) { for (const j of graph.get(k).keys()) { if (!graph.get(i).has(j)) { - graph.get(i).set(j, graph.get(i).get(k) * graph.get(k).get(j)); + graph + .get(i) + .set(j, graph.get(i).get(k) * graph.get(k).get(j)); } } } @@ -826,11 +996,54 @@ class Solution { } ``` +```csharp +public class Solution { + public double[] CalcEquation(List> equations, double[] values, List> queries) { + var graph = new Dictionary>(); + + for (int i = 0; i < equations.Count; i++) { + string a = equations[i][0]; + string b = equations[i][1]; + double val = values[i]; + + if (!graph.ContainsKey(a)) graph[a] = new Dictionary(); + if (!graph.ContainsKey(b)) graph[b] = new Dictionary(); + + graph[a][b] = val; + graph[b][a] = 1.0 / val; + } + + foreach (var k in graph.Keys.ToList()) { + foreach (var i in graph[k].Keys.ToList()) { + foreach (var j in graph[k].Keys.ToList()) { + if (!graph[i].ContainsKey(j)) { + graph[i][j] = graph[i][k] * graph[k][j]; + } + } + } + } + + double[] result = new double[queries.Count]; + for (int i = 0; i < queries.Count; i++) { + string a = queries[i][0]; + string b = queries[i][1]; + if (graph.ContainsKey(a) && graph[a].ContainsKey(b)) { + result[i] = graph[a][b]; + } else { + result[i] = -1.0; + } + } + + return result; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n ^ 3)$ -* Space complexity: $O(n ^ 2 + m)$ +- Time complexity: $O(m + n ^ 3)$ +- Space complexity: $O(n ^ 2 + m)$ -> Where $n$ is the number of unique strings and $m$ is the number of queries. \ No newline at end of file +> Where $n$ is the number of unique strings and $m$ is the number of queries. diff --git a/articles/evaluate-reverse-polish-notation.md b/articles/evaluate-reverse-polish-notation.md index 9c3520b02..f08beec96 100644 --- a/articles/evaluate-reverse-polish-notation.md +++ b/articles/evaluate-reverse-polish-notation.md @@ -27,16 +27,16 @@ class Solution: public class Solution { public int evalRPN(String[] tokens) { List tokenList = new ArrayList<>(Arrays.asList(tokens)); - + while (tokenList.size() > 1) { for (int i = 0; i < tokenList.size(); i++) { String token = tokenList.get(i); - + if ("+-*/".contains(token)) { int a = Integer.parseInt(tokenList.get(i - 2)); int b = Integer.parseInt(tokenList.get(i - 1)); int result = 0; - + if (token.equals("+")) { result = a + b; } else if (token.equals("-")) { @@ -46,10 +46,10 @@ public class Solution { } else if (token.equals("/")) { result = a / b; } - + tokenList.set(i - 2, String.valueOf(result)); - tokenList.remove(i); - tokenList.remove(i - 1); + tokenList.remove(i); + tokenList.remove(i - 1); break; } } @@ -65,10 +65,10 @@ public: int evalRPN(vector& tokens) { while (tokens.size() > 1) { for (int i = 0; i < tokens.size(); i++) { - if (tokens[i] == "+" - || tokens[i] == "-" - || tokens[i] == "*" - || tokens[i] == "/") + if (tokens[i] == "+" + || tokens[i] == "-" + || tokens[i] == "*" + || tokens[i] == "/") { int a = stoi(tokens[i - 2]); int b = stoi(tokens[i - 1]); @@ -77,7 +77,7 @@ public: else if (tokens[i] == "-") result = a - b; else if (tokens[i] == "*") result = a * b; else if (tokens[i] == "/") result = a / b; - + tokens.erase(tokens.begin() + i - 2, tokens.begin() + i + 1); tokens.insert(tokens.begin() + i - 2, to_string(result)); break; @@ -94,15 +94,15 @@ class Solution { evalRPN(tokens) { while (tokens.length > 1) { for (let i = 0; i < tokens.length; i++) { - if ("+-*/".includes(tokens[i])) { + if ('+-*/'.includes(tokens[i])) { const a = parseInt(tokens[i - 2]); const b = parseInt(tokens[i - 1]); let result; - if (tokens[i] === "+") result = a + b; - else if (tokens[i] === "-") result = a - b; - else if (tokens[i] === "*") result = a * b; - else if (tokens[i] === "/") result = Math.trunc(a / b); - + if (tokens[i] === '+') result = a + b; + else if (tokens[i] === '-') result = a - b; + else if (tokens[i] === '*') result = a * b; + else if (tokens[i] === '/') result = Math.trunc(a / b); + tokens.splice(i - 2, 3, result.toString()); break; } @@ -117,7 +117,7 @@ class Solution { public class Solution { public int EvalRPN(string[] tokens) { List tokenList = new List(tokens); - + while (tokenList.Count > 1) { for (int i = 0; i < tokenList.Count; i++) { if ("+-*/".Contains(tokenList[i])) { @@ -157,12 +157,12 @@ func evalRPN(tokens []string) int { a, _ := strconv.Atoi(tokens[i-2]) b, _ := strconv.Atoi(tokens[i-1]) var result int - + switch tokens[i] { case "+": result = a + b case "-": - result = a - b + result = a - b case "*": result = a * b case "/": @@ -178,7 +178,7 @@ func evalRPN(tokens []string) int { } } } - + result, _ := strconv.Atoi(tokens[0]) return result } @@ -188,7 +188,7 @@ func evalRPN(tokens []string) int { class Solution { fun evalRPN(tokens: Array): Int { val A = tokens.toMutableList() - + while (A.size > 1) { for (i in A.indices) { if (A[i] in setOf("+", "-", "*", "/")) { @@ -200,9 +200,9 @@ class Solution { "*" -> a * b else -> a / b } - - val temp = A.slice(0..i-3) + - result.toString() + + + val temp = A.slice(0..i-3) + + result.toString() + A.slice(i+1..A.lastIndex) A.clear() A.addAll(temp) @@ -210,18 +210,51 @@ class Solution { } } } - + return A[0].toInt() } } ``` +```swift +class Solution { + func evalRPN(_ tokens: [String]) -> Int { + var tokens = tokens + + while tokens.count > 1 { + for i in 0..val = val; this->next = next; @@ -353,9 +386,9 @@ public: int ans = 0; while (head != nullptr) { if (head->val == "+" || - head->val == "-" || - head->val == "*" || - head->val == "/") + head->val == "-" || + head->val == "*" || + head->val == "/") { int l = stoi(head->prev->prev->val); int r = stoi(head->prev->val); @@ -411,15 +444,15 @@ class Solution { let ans = 0; while (head !== null) { - if ("+-*/".includes(head.val)) { + if ('+-*/'.includes(head.val)) { let l = parseInt(head.prev.prev.val); let r = parseInt(head.prev.val); let res = 0; - if (head.val === "+") { + if (head.val === '+') { res = l + r; - } else if (head.val === "-") { + } else if (head.val === '-') { res = l - r; - } else if (head.val === "*") { + } else if (head.val === '*') { res = l * r; } else { res = Math.trunc(l / r); @@ -447,7 +480,7 @@ public class DoublyLinkedList { public DoublyLinkedList next; public DoublyLinkedList prev; - public DoublyLinkedList(string val, DoublyLinkedList next = null, + public DoublyLinkedList(string val, DoublyLinkedList next = null, DoublyLinkedList prev = null) { this.val = val; this.next = next; @@ -507,18 +540,18 @@ type DoublyLinkedList struct { func evalRPN(tokens []string) int { head := &DoublyLinkedList{val: tokens[0]} curr := head - + for i := 1; i < len(tokens); i++ { newNode := &DoublyLinkedList{val: tokens[i], prev: curr} curr.next = newNode curr = curr.next } - + for head != nil { if head.val == "+" || head.val == "-" || head.val == "*" || head.val == "/" { l, _ := strconv.Atoi(head.prev.prev.val) r, _ := strconv.Atoi(head.prev.val) - + var res int switch head.val { case "+": @@ -530,17 +563,17 @@ func evalRPN(tokens []string) int { case "/": res = l / r } - + head.val = strconv.Itoa(res) head.prev = head.prev.prev.prev if head.prev != nil { head.prev.next = head } } - + head = head.next } - + ans, _ := strconv.Atoi(curr.val) return ans } @@ -557,45 +590,103 @@ class Solution { fun evalRPN(tokens: Array): Int { val head = DoublyLinkedList(tokens[0]) var curr = head - + for (i in 1 until tokens.size) { val newNode = DoublyLinkedList(tokens[i], prev = curr) curr.next = newNode curr = newNode } - + var ptr: DoublyLinkedList? = head while (ptr != null) { if (ptr.value in setOf("+", "-", "*", "/")) { val l = ptr.prev!!.prev!!.value.toInt() val r = ptr.prev!!.value.toInt() - + val res = when (ptr.value) { "+" -> l + r "-" -> l - r "*" -> l * r else -> l / r } - + ptr.value = res.toString() ptr.prev = ptr.prev!!.prev!!.prev ptr.prev?.next = ptr } - + ptr = ptr.next } - + return curr.value.toInt() } } ``` +```swift +class DoublyLinkedList { + var val: String + var next: DoublyLinkedList? + var prev: DoublyLinkedList? + + init(val: String, next: DoublyLinkedList? = nil, prev: DoublyLinkedList? = nil) { + self.val = val + self.next = next + self.prev = prev + } +} + +class Solution { + func evalRPN(_ tokens: [String]) -> Int { + var head: DoublyLinkedList? = DoublyLinkedList(val: tokens[0]) + var curr = head + + for i in 1.. tokens) { String token = tokens.remove(tokens.size() - 1); - + if (!"+-*/".contains(token)) { return Integer.parseInt(token); } @@ -665,16 +756,16 @@ public: int dfs(vector& tokens) { string token = tokens.back(); tokens.pop_back(); - + if (token != "+" && token != "-" && - token != "*" && token != "/") + token != "*" && token != "/") { return stoi(token); } int right = dfs(tokens); int left = dfs(tokens); - + if (token == "+") { return left + right; } else if (token == "-") { @@ -699,13 +790,12 @@ class Solution { * @return {number} */ evalRPN(tokens) { - /** * @return {number} */ const dfs = () => { const token = tokens.pop(); - if (!"+-*/".includes(token)) { + if (!'+-*/'.includes(token)) { return parseInt(token); } @@ -763,20 +853,20 @@ public class Solution { ```go func evalRPN(tokens []string) int { index := len(tokens) - 1 - + var dfs func() int dfs = func() int { token := tokens[index] index-- - + if token != "+" && token != "-" && token != "*" && token != "/" { val, _ := strconv.Atoi(token) return val } - + right := dfs() left := dfs() - + switch token { case "+": return left + right @@ -788,7 +878,7 @@ func evalRPN(tokens []string) int { return left / right } } - + return dfs() } ``` @@ -796,21 +886,21 @@ func evalRPN(tokens []string) int { ```kotlin class Solution { private var index = 0 - + fun evalRPN(tokens: Array): Int { index = tokens.size - 1 - + fun dfs(): Int { val token = tokens[index] index-- - + if (token !in setOf("+", "-", "*", "/")) { return token.toInt() } - + val right = dfs() val left = dfs() - + return when (token) { "+" -> left + right "-" -> left - right @@ -818,7 +908,35 @@ class Solution { else -> left / right } } - + + return dfs() + } +} +``` + +```swift +class Solution { + func evalRPN(_ tokens: [String]) -> Int { + var tokens = tokens + + func dfs() -> Int { + let token = tokens.removeLast() + if let num = Int(token) { + return num + } + + let right = dfs() + let left = dfs() + + switch token { + case "+": return left + right + case "-": return left - right + case "*": return left * right + case "/": return left / right + default: return 0 + } + } + return dfs() } } @@ -828,8 +946,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -973,12 +1091,12 @@ public class Solution { ```go func evalRPN(tokens []string) int { stack := make([]int, 0) - + for _, token := range tokens { switch token { case "+": a := stack[len(stack)-1] - b := stack[len(stack)-2] + b := stack[len(stack)-2] stack = stack[:len(stack)-2] stack = append(stack, b+a) case "-": @@ -1001,7 +1119,7 @@ func evalRPN(tokens []string) int { stack = append(stack, num) } } - + return stack[0] } ``` @@ -1010,7 +1128,7 @@ func evalRPN(tokens []string) int { class Solution { fun evalRPN(tokens: Array): Int { val stack = ArrayDeque() - + for (token in tokens) { when (token) { "+" -> { @@ -1036,15 +1154,43 @@ class Solution { else -> stack.addLast(token.toInt()) } } - + return stack.last() } } ``` +```swift +class Solution { + func evalRPN(_ tokens: [String]) -> Int { + var stack = [Int]() + + for c in tokens { + switch c { + case "+": + stack.append(stack.removeLast() + stack.removeLast()) + case "-": + let a = stack.removeLast() + let b = stack.removeLast() + stack.append(b - a) + case "*": + stack.append(stack.removeLast() * stack.removeLast()) + case "/": + let a = stack.removeLast() + let b = stack.removeLast() + stack.append(b / a) + default: + stack.append(Int(c)!) + } + } + return stack[0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/even-odd-tree.md b/articles/even-odd-tree.md new file mode 100644 index 000000000..823730263 --- /dev/null +++ b/articles/even-odd-tree.md @@ -0,0 +1,547 @@ +## 1. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def isEvenOddTree(self, root: Optional[TreeNode]) -> bool: + even = True + q = deque([root]) + + while q: + prev = float("-inf") if even else float("inf") + for _ in range(len(q)): + node = q.popleft() + + if even and (node.val % 2 == 0 or node.val <= prev): + return False + elif not even and (node.val % 2 == 1 or node.val >= prev): + return False + + if node.left: + q.append(node.left) + if node.right: + q.append(node.right) + + prev = node.val + + even = not even + + return True +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean isEvenOddTree(TreeNode root) { + boolean even = true; + Queue q = new LinkedList<>(); + q.offer(root); + + while (!q.isEmpty()) { + int prev = even ? Integer.MIN_VALUE : Integer.MAX_VALUE; + for (int i = q.size(); i > 0; i--) { + TreeNode node = q.poll(); + + if (even && (node.val % 2 == 0 || node.val <= prev)) return false; + if (!even && (node.val % 2 == 1 || node.val >= prev)) return false; + + if (node.left != null) q.offer(node.left); + if (node.right != null) q.offer(node.right); + + prev = node.val; + } + even = !even; + } + return true; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool isEvenOddTree(TreeNode* root) { + bool even = true; + queue q; + q.push(root); + + while (!q.empty()) { + int prev = even ? INT_MIN : INT_MAX; + for (int i = q.size(); i > 0; i--) { + TreeNode* node = q.front();q.pop(); + + if (even && (node->val % 2 == 0 || node->val <= prev)) return false; + if (!even && (node->val % 2 == 1 || node->val >= prev)) return false; + + if (node->left) q.push(node->left); + if (node->right) q.push(node->right); + + prev = node->val; + } + even = !even; + } + return true; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {boolean} + */ + isEvenOddTree(root) { + let even = true; + const q = new Queue([root]); + + while (!q.isEmpty()) { + let prev = even ? -Infinity : Infinity; + for (let i = q.size(); i > 0; i--) { + let node = q.pop(); + + if (even && (node.val % 2 === 0 || node.val <= prev)) + return false; + if (!even && (node.val % 2 === 1 || node.val >= prev)) + return false; + + if (node.left) q.push(node.left); + if (node.right) q.push(node.right); + + prev = node.val; + } + even = !even; + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def isEvenOddTree(self, root: Optional[TreeNode]) -> bool: + levels = [] + + def dfs(node, level): + if not node: + return True + + even = level % 2 == 0 + if ((even and node.val % 2 == 0) or + (not even and (node.val % 2 == 1)) + ): + return False + + if len(levels) == level: + levels.append(node.val) + else: + if ((even and node.val <= levels[level]) or + (not even and node.val >= levels[level]) + ): + return False + levels[level] = node.val + + return dfs(node.left, level + 1) and dfs(node.right, level + 1) + + return dfs(root, 0) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + List levels = new ArrayList<>(); + + private boolean dfs(TreeNode node, int level) { + if (node == null) return true; + + boolean even = level % 2 == 0; + if ((even && node.val % 2 == 0) || + (!even && node.val % 2 == 1)) { + return false; + } + + if (levels.size() == level) { + levels.add(node.val); + } else { + if ((even && node.val <= levels.get(level)) || + (!even && node.val >= levels.get(level))) { + return false; + } + levels.set(level, node.val); + } + + return dfs(node.left, level + 1) && dfs(node.right, level + 1); + } + + public boolean isEvenOddTree(TreeNode root) { + return dfs(root, 0); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector levels; + + bool dfs(TreeNode* node, int level) { + if (!node) return true; + + bool even = level % 2 == 0; + if ((even && node->val % 2 == 0) || + (!even && node->val % 2 == 1)) { + return false; + } + + if (levels.size() == level) { + levels.push_back(node->val); + } else { + if ((even && node->val <= levels[level]) || + (!even && node->val >= levels[level])) { + return false; + } + levels[level] = node->val; + } + + return dfs(node->left, level + 1) && dfs(node->right, level + 1); + } + + bool isEvenOddTree(TreeNode* root) { + return dfs(root, 0); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {boolean} + */ + isEvenOddTree(root) { + const levels = []; + + const dfs = (node, level) => { + if (!node) return true; + + const even = level % 2 === 0; + if ((even && node.val % 2 === 0) || (!even && node.val % 2 === 1)) { + return false; + } + + if (levels.length === level) { + levels.push(node.val); + } else { + if ( + (even && node.val <= levels[level]) || + (!even && node.val >= levels[level]) + ) { + return false; + } + levels[level] = node.val; + } + + return dfs(node.left, level + 1) && dfs(node.right, level + 1); + }; + + return dfs(root, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def isEvenOddTree(self, root: Optional[TreeNode]) -> bool: + stack = [(root, 0)] + levels = [] + + while stack: + node, level = stack.pop() + + even = level % 2 == 0 + if ((even and node.val % 2 == 0) or + (not even and node.val % 2 == 1) + ): + return False + + if len(levels) == level: + levels.append(node.val) + else: + if ((even and node.val <= levels[level]) or + (not even and node.val >= levels[level]) + ): + return False + levels[level] = node.val + + if node.right: + stack.append((node.right, level + 1)) + if node.left: + stack.append((node.left, level + 1)) + + return True +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean isEvenOddTree(TreeNode root) { + Stack> stack = new Stack<>(); + stack.push(new Pair<>(root, 0)); + List levels = new ArrayList<>(); + + while (!stack.isEmpty()) { + Pair pair = stack.pop(); + TreeNode node = pair.getKey(); + int level = pair.getValue(); + + boolean even = level % 2 == 0; + if ((even && node.val % 2 == 0) || + (!even && node.val % 2 == 1)) + return false; + + if (levels.size() == level) { + levels.add(node.val); + } else { + if ((even && node.val <= levels.get(level)) || + (!even && node.val >= levels.get(level))) + return false; + levels.set(level, node.val); + } + + if (node.right != null) stack.push(new Pair<>(node.right, level + 1)); + if (node.left != null) stack.push(new Pair<>(node.left, level + 1)); + } + + return true; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool isEvenOddTree(TreeNode* root) { + stack> stack; + stack.push({root, 0}); + vector levels; + + while (!stack.empty()) { + auto [node, level] = stack.top(); + stack.pop(); + + bool even = level % 2 == 0; + if ((even && node->val % 2 == 0) || + (!even && node->val % 2 == 1)) + return false; + + if (levels.size() == level) { + levels.push_back(node->val); + } else { + if ((even && node->val <= levels[level]) || + (!even && node->val >= levels[level])) + return false; + levels[level] = node->val; + } + + if (node->right) stack.push({node->right, level + 1}); + if (node->left) stack.push({node->left, level + 1}); + } + + return true; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {boolean} + */ + isEvenOddTree(root) { + const stack = [[root, 0]]; + const levels = []; + + while (stack.length) { + const [node, level] = stack.pop(); + + const even = level % 2 === 0; + if ((even && node.val % 2 === 0) || (!even && node.val % 2 === 1)) + return false; + + if (levels.length === level) { + levels.push(node.val); + } else { + if ( + (even && node.val <= levels[level]) || + (!even && node.val >= levels[level]) + ) + return false; + levels[level] = node.val; + } + + if (node.right) stack.push([node.right, level + 1]); + if (node.left) stack.push([node.left, level + 1]); + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/excel-sheet-column-title.md b/articles/excel-sheet-column-title.md index 98ae4f249..c6380ce02 100644 --- a/articles/excel-sheet-column-title.md +++ b/articles/excel-sheet-column-title.md @@ -45,10 +45,26 @@ class Solution { */ convertToTitle(columnNumber) { if (columnNumber === 0) { - return ""; + return ''; } const n = columnNumber - 1; - return this.convertToTitle(Math.floor(n / 26)) + String.fromCharCode('A'.charCodeAt(0) + n % 26); + return ( + this.convertToTitle(Math.floor(n / 26)) + + String.fromCharCode('A'.charCodeAt(0) + (n % 26)) + ); + } +} +``` + +```csharp +public class Solution { + public string ConvertToTitle(int columnNumber) { + if (columnNumber == 0) { + return ""; + } + + columnNumber--; + return ConvertToTitle(columnNumber / 26) + (char)('A' + columnNumber % 26); } } ``` @@ -57,8 +73,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(\log n)$ for recursion stack. +- Time complexity: $O(\log n)$ +- Space complexity: $O(\log n)$ for recursion stack. > Where $n$ is the given column number. @@ -77,7 +93,7 @@ class Solution: offset = columnNumber % 26 res += chr(ord('A') + offset) columnNumber //= 26 - + return ''.join(reversed(res)) ``` @@ -132,11 +148,27 @@ class Solution { } ``` +```csharp +public class Solution { + public string ConvertToTitle(int columnNumber) { + var res = new List(); + while (columnNumber > 0) { + columnNumber--; + int offset = columnNumber % 26; + res.Add((char)('A' + offset)); + columnNumber /= 26; + } + res.Reverse(); + return new string(res.ToArray()); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ extra space. -> Where $n$ is the given column number. \ No newline at end of file +> Where $n$ is the given column number. diff --git a/articles/extra-characters-in-a-string.md b/articles/extra-characters-in-a-string.md index b41af1f45..ca7227405 100644 --- a/articles/extra-characters-in-a-string.md +++ b/articles/extra-characters-in-a-string.md @@ -104,12 +104,36 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinExtraChar(string s, string[] dictionary) { + HashSet words = new HashSet(dictionary); + return Dfs(0, s, words); + } + + private int Dfs(int i, string s, HashSet words) { + if (i == s.Length) { + return 0; + } + + int res = 1 + Dfs(i + 1, s, words); + for (int j = i; j < s.Length; j++) { + if (words.Contains(s.Substring(i, j - i + 1))) { + res = Math.Min(res, Dfs(j + 1, s, words)); + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n + m * k)$ -* Space complexity: $O(n + m * k)$ +- Time complexity: $O(n * 2 ^ n + m * k)$ +- Space complexity: $O(n + m * k)$ > Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. @@ -220,12 +244,40 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinExtraChar(string s, string[] dictionary) { + HashSet words = new HashSet(dictionary); + int n = s.Length; + int[] dp = new int[n + 1]; + Array.Fill(dp, -1); + dp[n] = 0; + + return Dfs(0, s, words, dp); + } + + private int Dfs(int i, string s, HashSet words, int[] dp) { + if (dp[i] != -1) return dp[i]; + + int res = 1 + Dfs(i + 1, s, words, dp); + for (int j = i; j < s.Length; j++) { + if (words.Contains(s.Substring(i, j - i + 1))) { + res = Math.Min(res, Dfs(j + 1, s, words, dp)); + } + } + + dp[i] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 3 + m * k)$ -* Space complexity: $O(n + m * k)$ +- Time complexity: $O(n ^ 3 + m * k)$ +- Space complexity: $O(n + m * k)$ > Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. @@ -316,12 +368,33 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinExtraChar(string s, string[] dictionary) { + HashSet words = new HashSet(dictionary); + int n = s.Length; + int[] dp = new int[n + 1]; + + for (int i = n - 1; i >= 0; i--) { + dp[i] = 1 + dp[i + 1]; + for (int j = i; j < n; j++) { + if (words.Contains(s.Substring(i, j - i + 1))) { + dp[i] = Math.Min(dp[i], dp[j + 1]); + } + } + } + + return dp[0]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 3 + m * k)$ -* Space complexity: $O(n + m * k)$ +- Time complexity: $O(n ^ 3 + m * k)$ +- Space complexity: $O(n + m * k)$ > Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. @@ -339,7 +412,7 @@ class Solution: def dfs(i): if i in dp: return dp[i] - + res = 1 + dfs(i + 1) for word in dictionary: if i + len(word) > len(s): @@ -352,11 +425,11 @@ class Solution: break if flag: res = min(res, dfs(i + len(word))) - + dp[i] = res return res - return dfs(0) + return dfs(0) ``` ```java @@ -467,12 +540,49 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinExtraChar(string s, string[] dictionary) { + Dictionary dp = new Dictionary(); + dp[s.Length] = 0; + return Dfs(0, s, dictionary, dp); + } + + private int Dfs(int i, string s, string[] dictionary, Dictionary dp) { + if (dp.ContainsKey(i)) { + return dp[i]; + } + + int res = 1 + Dfs(i + 1, s, dictionary, dp); + + foreach (string word in dictionary) { + if (i + word.Length > s.Length) continue; + + bool flag = true; + for (int j = 0; j < word.Length; j++) { + if (s[i + j] != word[j]) { + flag = false; + break; + } + } + + if (flag) { + res = Math.Min(res, Dfs(i + word.Length, s, dictionary, dp)); + } + } + + dp[i] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m * k)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * m * k)$ +- Space complexity: $O(n)$ > Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. @@ -487,13 +597,13 @@ class Solution: def minExtraChar(self, s: str, dictionary: List[str]) -> int: n = len(s) dp = [0] * (n + 1) - + for i in range(n - 1, -1, -1): dp[i] = 1 + dp[i + 1] for word in dictionary: if i + len(word) <= n and s[i:i + len(word)] == word: dp[i] = min(dp[i], dp[i + len(word)]) - + return dp[0] ``` @@ -552,7 +662,10 @@ class Solution { for (let i = n - 1; i >= 0; i--) { dp[i] = 1 + dp[i + 1]; for (const word of dictionary) { - if (i + word.length <= n && s.slice(i, i + word.length) === word) { + if ( + i + word.length <= n && + s.slice(i, i + word.length) === word + ) { dp[i] = Math.min(dp[i], dp[i + word.length]); } } @@ -563,12 +676,32 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinExtraChar(string s, string[] dictionary) { + int n = s.Length; + int[] dp = new int[n + 1]; + + for (int i = n - 1; i >= 0; i--) { + dp[i] = 1 + dp[i + 1]; + foreach (string word in dictionary) { + if (i + word.Length <= n && s.Substring(i, word.Length) == word) { + dp[i] = Math.Min(dp[i], dp[i + word.Length]); + } + } + } + + return dp[0]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m * k)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * m * k)$ +- Space complexity: $O(n)$ > Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. @@ -587,7 +720,7 @@ class TrieNode: class Trie: def __init__(self): self.root = TrieNode() - + def addWord(self, word): curr = self.root for c in word: @@ -768,7 +901,7 @@ class Trie { /** * @param {string} word * @return {void} - */ + */ addWord(word) { let curr = this.root; for (const c of word) { @@ -819,12 +952,69 @@ class Solution { } ``` +```csharp +public class TrieNode { + public TrieNode[] Children = new TrieNode[26]; + public bool IsWord = false; +} + +public class Trie { + public TrieNode Root = new TrieNode(); + + public void AddWord(string word) { + TrieNode curr = Root; + foreach (char c in word) { + int idx = c - 'a'; + if (curr.Children[idx] == null) { + curr.Children[idx] = new TrieNode(); + } + curr = curr.Children[idx]; + } + curr.IsWord = true; + } +} + +public class Solution { + public int MinExtraChar(string s, string[] dictionary) { + Trie trie = new Trie(); + foreach (string word in dictionary) { + trie.AddWord(word); + } + + int[] dp = new int[s.Length + 1]; + Array.Fill(dp, -1); + + return Dfs(0, s, trie, dp); + } + + private int Dfs(int i, string s, Trie trie, int[] dp) { + if (i == s.Length) return 0; + if (dp[i] != -1) return dp[i]; + + int res = 1 + Dfs(i + 1, s, trie, dp); + TrieNode curr = trie.Root; + + for (int j = i; j < s.Length; j++) { + int idx = s[j] - 'a'; + if (curr.Children[idx] == null) break; + curr = curr.Children[idx]; + if (curr.IsWord) { + res = Math.Min(res, Dfs(j + 1, s, trie, dp)); + } + } + + dp[i] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2 + m * k)$ -* Space complexity: $O(n + m * k)$ +- Time complexity: $O(n ^ 2 + m * k)$ +- Space complexity: $O(n + m * k)$ > Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. @@ -843,7 +1033,7 @@ class TrieNode: class Trie: def __init__(self): self.root = TrieNode() - + def addWord(self, word): curr = self.root for c in word: @@ -1007,7 +1197,7 @@ class Trie { /** * @param {string} word * @return {void} - */ + */ addWord(word) { let curr = this.root; for (const c of word) { @@ -1052,11 +1242,62 @@ class Solution { } ``` +```csharp +public class TrieNode { + public TrieNode[] Children = new TrieNode[26]; + public bool IsWord = false; +} + +public class Trie { + public TrieNode Root = new TrieNode(); + + public void AddWord(string word) { + TrieNode curr = Root; + foreach (char c in word) { + int idx = c - 'a'; + if (curr.Children[idx] == null) { + curr.Children[idx] = new TrieNode(); + } + curr = curr.Children[idx]; + } + curr.IsWord = true; + } +} + +public class Solution { + public int MinExtraChar(string s, string[] dictionary) { + Trie trie = new Trie(); + foreach (string word in dictionary) { + trie.AddWord(word); + } + + int n = s.Length; + int[] dp = new int[n + 1]; + + for (int i = n - 1; i >= 0; i--) { + dp[i] = 1 + dp[i + 1]; + TrieNode curr = trie.Root; + + for (int j = i; j < n; j++) { + int idx = s[j] - 'a'; + if (curr.Children[idx] == null) break; + curr = curr.Children[idx]; + if (curr.IsWord) { + dp[i] = Math.Min(dp[i], dp[j + 1]); + } + } + } + + return dp[0]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2 + m * k)$ -* Space complexity: $O(n + m * k)$ +- Time complexity: $O(n ^ 2 + m * k)$ +- Space complexity: $O(n + m * k)$ -> Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. \ No newline at end of file +> Where $n$ is the length of the string $s$, $m$ is the number of words in the dictionary, and $k$ is the average length of a word in the dictionary. diff --git a/articles/final-array-state-after-k-multiplication-operations-i.md b/articles/final-array-state-after-k-multiplication-operations-i.md new file mode 100644 index 000000000..1a5350dae --- /dev/null +++ b/articles/final-array-state-after-k-multiplication-operations-i.md @@ -0,0 +1,249 @@ +## 1. Simulation + +::tabs-start + +```python +class Solution: + def getFinalState(self, nums: List[int], k: int, multiplier: int) -> List[int]: + n = len(nums) + for _ in range(k): + minIdx = 0 + for i in range(1, n): + if nums[i] < nums[minIdx]: + minIdx = i + nums[minIdx] *= multiplier + return nums +``` + +```java +public class Solution { + public int[] getFinalState(int[] nums, int k, int multiplier) { + int n = nums.length; + for (int j = 0; j < k; j++) { + int minIdx = 0; + for (int i = 1; i < n; i++) { + if (nums[i] < nums[minIdx]) { + minIdx = i; + } + } + nums[minIdx] *= multiplier; + } + return nums; + } +} +``` + +```cpp +class Solution { +public: + vector getFinalState(vector& nums, int k, int multiplier) { + int n = nums.size(); + for (int _ = 0; _ < k; _++) { + int minIdx = 0; + for (int i = 1; i < n; i++) { + if (nums[i] < nums[minIdx]) { + minIdx = i; + } + } + nums[minIdx] *= multiplier; + } + return nums; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @param {number} multiplier + * @return {number[]} + */ + getFinalState(nums, k, multiplier) { + let n = nums.length; + for (let _ = 0; _ < k; _++) { + let minIdx = 0; + for (let i = 1; i < n; i++) { + if (nums[i] < nums[minIdx]) { + minIdx = i; + } + } + nums[minIdx] *= multiplier; + } + return nums; + } +} +``` + +```csharp +public class Solution { + public int[] GetFinalState(int[] nums, int k, int multiplier) { + int n = nums.Length; + for (int _ = 0; _ < k; _++) { + int minIdx = 0; + for (int i = 1; i < n; i++) { + if (nums[i] < nums[minIdx]) { + minIdx = i; + } + } + nums[minIdx] *= multiplier; + } + return nums; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * k)$ +* Space complexity: $O(1)$ extra space. + +> Where $n$ is the size of the input array, and $k$ is the number of operations. + +--- + +## 2. Min-Heap + +::tabs-start + +```python +class Solution: + def getFinalState(self, nums: List[int], k: int, multiplier: int) -> List[int]: + res = nums[:] + + min_heap = [(num, i) for i, num in enumerate(nums)] + heapq.heapify(min_heap) + + for _ in range(k): + num, i = heapq.heappop(min_heap) + res[i] *= multiplier + heapq.heappush(min_heap, (res[i], i)) + + return res +``` + +```java +public class Solution { + public int[] getFinalState(int[] nums, int k, int multiplier) { + int n = nums.length; + int[] res = Arrays.copyOf(nums, n); + + PriorityQueue minHeap = new PriorityQueue<>((a, b) -> { + if (res[a] != res[b]) return Integer.compare(res[a], res[b]); + return Integer.compare(a, b); + }); + + for (int i = 0; i < n; i++) { + minHeap.add(i); + } + + for (int i = 0; i < k; i++) { + int idx = minHeap.poll(); + res[idx] *= multiplier; + minHeap.add(idx); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector getFinalState(vector& nums, int k, int multiplier) { + int n = nums.size(); + vector res = nums; + + auto cmp = [&](int a, int b) { + if (res[a] != res[b]) return res[a] > res[b]; + return a > b; + }; + priority_queue, decltype(cmp)> minHeap(cmp); + + for (int i = 0; i < n; i++) { + minHeap.push(i); + } + + for (int _ = 0; _ < k; _++) { + int i = minHeap.top(); + minHeap.pop(); + res[i] *= multiplier; + minHeap.push(i); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @param {number} multiplier + * @return {number[]} + */ + getFinalState(nums, k, multiplier) { + let res = nums.slice(); + let n = res.length; + let minHeap = new PriorityQueue((a, b) => { + if (res[a] !== res[b]) { + return res[a] - res[b]; + } + return a - b; + }); + + for (let i = 0; i < n; i++) { + minHeap.enqueue(i); + } + + for (let _ = 0; _ < k; _++) { + let i = minHeap.dequeue(); + res[i] *= multiplier; + minHeap.enqueue(i); + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int[] GetFinalState(int[] nums, int k, int multiplier) { + int n = nums.Length; + int[] res = new int[n]; + Array.Copy(nums, res, n); + + var minHeap = new PriorityQueue(); + for (int i = 0; i < n; i++) { + minHeap.Enqueue(i, (res[i], i)); + } + + for (int _ = 0; _ < k; _++) { + int i = minHeap.Dequeue(); + res[i] *= multiplier; + minHeap.Enqueue(i, (res[i], i)); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + - $O(n + k \log n)$ in Python. + - $O(n \log n + k \log n)$ in other languages. + +* Space complexity: $O(n)$ + +> Where $n$ is the size of the input array, and $k$ is the number of operations. \ No newline at end of file diff --git a/articles/find-all-anagrams-in-a-string.md b/articles/find-all-anagrams-in-a-string.md index 4201b94ed..8d7411507 100644 --- a/articles/find-all-anagrams-in-a-string.md +++ b/articles/find-all-anagrams-in-a-string.md @@ -64,12 +64,17 @@ class Solution { * @return {number[]} */ findAnagrams(s, p) { - const n = s.length, m = p.length; + const n = s.length, + m = p.length; const res = []; const sortedP = p.split('').sort().join(''); for (let i = 0; i <= n - m; i++) { - const sub = s.substring(i, i + m).split('').sort().join(''); + const sub = s + .substring(i, i + m) + .split('') + .sort() + .join(''); if (sub === sortedP) { res.push(i); } @@ -83,8 +88,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m \log m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n * m \log m)$ +- Space complexity: $O(m)$ > Where $n$ is the length of the string $s$ and $m$ is the length of the string $p$. @@ -207,7 +212,8 @@ class Solution { * @return {number[]} */ findAnagrams(s, p) { - const n = s.length, m = p.length; + const n = s.length, + m = p.length; if (m > n) return []; const pCount = Array(26).fill(0); @@ -224,7 +230,8 @@ class Solution { } const res = []; - let i = 0, j = m - 1; + let i = 0, + j = m - 1; while (j < n) { let isValid = true; for (let c = 0; c < 26; c++) { @@ -247,8 +254,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n)$ > Where $n$ is the length of the string $s$ and $m$ is the length of the string $p$. @@ -285,20 +292,20 @@ class Solution: public class Solution { public List findAnagrams(String s, String p) { if (p.length() > s.length()) return new ArrayList<>(); - + int[] pCount = new int[26]; int[] sCount = new int[26]; - + for (char c : p.toCharArray()) { pCount[c - 'a']++; } for (int i = 0; i < p.length(); i++) { sCount[s.charAt(i) - 'a']++; } - + List res = new ArrayList<>(); if (Arrays.equals(pCount, sCount)) res.add(0); - + int l = 0; for (int r = p.length(); r < s.length(); r++) { sCount[s.charAt(r) - 'a']++; @@ -308,7 +315,7 @@ public class Solution { res.add(l); } } - + return res; } } @@ -358,7 +365,7 @@ class Solution { const pCount = new Array(26).fill(0); const sCount = new Array(26).fill(0); - + for (const char of p) { pCount[char.charCodeAt(0) - 97]++; } @@ -388,8 +395,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(n + m)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. > Where $n$ is the length of the string $s$ and $m$ is the length of the string $p$. @@ -531,7 +538,8 @@ class Solution { * @return {number[]} */ findAnagrams(s, p) { - const n = s.length, m = p.length; + const n = s.length, + m = p.length; if (m > n) return []; const pCount = new Array(26).fill(0); @@ -575,7 +583,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(n + m)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. -> Where $n$ is the length of the string $s$ and $m$ is the length of the string $p$. \ No newline at end of file +> Where $n$ is the length of the string $s$ and $m$ is the length of the string $p$. diff --git a/articles/find-all-duplicates-in-an-array.md b/articles/find-all-duplicates-in-an-array.md new file mode 100644 index 000000000..0e7982b24 --- /dev/null +++ b/articles/find-all-duplicates-in-an-array.md @@ -0,0 +1,440 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def findDuplicates(self, nums: List[int]) -> List[int]: + n = len(nums) + res = [] + + for i in range(n): + for j in range(i + 1, n): + if nums[i] == nums[j]: + res.append(nums[i]) + break + + return res +``` + +```java +public class Solution { + public List findDuplicates(int[] nums) { + int n = nums.length; + List res = new ArrayList<>(); + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + if (nums[i] == nums[j]) { + res.add(nums[i]); + break; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findDuplicates(vector& nums) { + int n = nums.size(); + vector res; + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + if (nums[i] == nums[j]) { + res.push_back(nums[i]); + break; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + findDuplicates(nums) { + const n = nums.length; + const res = []; + + for (let i = 0; i < n; i++) { + for (let j = i + 1; j < n; j++) { + if (nums[i] === nums[j]) { + res.push(nums[i]); + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 2. Sorting + +::tabs-start + +```python +class Solution: + def findDuplicates(self, nums: List[int]) -> List[int]: + nums.sort() + res = [] + + for i in range(len(nums) - 1): + if nums[i] == nums[i + 1]: + res.append(nums[i]) + + return res +``` + +```java +public class Solution { + public List findDuplicates(int[] nums) { + Arrays.sort(nums); + List res = new ArrayList<>(); + + for (int i = 0; i < nums.length - 1; i++) { + if (nums[i] == nums[i + 1]) { + res.add(nums[i]); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findDuplicates(vector& nums) { + sort(nums.begin(), nums.end()); + vector res; + + for (int i = 0; i < nums.size() - 1; i++) { + if (nums[i] == nums[i + 1]) { + res.push_back(nums[i]); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + findDuplicates(nums) { + nums.sort((a, b) => a - b); + const res = []; + + for (let i = 0; i < nums.length - 1; i++) { + if (nums[i] === nums[i + 1]) { + res.push(nums[i]); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 3. Hash Set + +::tabs-start + +```python +class Solution: + def findDuplicates(self, nums: List[int]) -> List[int]: + seen = set() + res = [] + for num in nums: + if num in seen: + res.append(num) + else: + seen.add(num) + return res +``` + +```java +public class Solution { + public List findDuplicates(int[] nums) { + Set seen = new HashSet<>(); + List res = new ArrayList<>(); + + for (int num : nums) { + if (seen.contains(num)) { + res.add(num); + } else { + seen.add(num); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findDuplicates(vector& nums) { + unordered_set seen; + vector res; + + for (int num : nums) { + if (seen.count(num)) { + res.push_back(num); + } else { + seen.insert(num); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + findDuplicates(nums) { + const seen = new Set(); + const res = []; + + for (const num of nums) { + if (seen.has(num)) { + res.push(num); + } else { + seen.add(num); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Hash Map + +::tabs-start + +```python +class Solution: + def findDuplicates(self, nums: List[int]) -> List[int]: + count = Counter(nums) + res = [] + + for num in count: + if count[num] == 2: + res.append(num) + + return res +``` + +```java +public class Solution { + public List findDuplicates(int[] nums) { + Map count = new HashMap<>(); + List res = new ArrayList<>(); + + for (int num : nums) { + count.put(num, count.getOrDefault(num, 0) + 1); + } + + for (int num : count.keySet()) { + if (count.get(num) == 2) { + res.add(num); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findDuplicates(vector& nums) { + unordered_map count; + vector res; + + for (int num : nums) { + count[num]++; + } + + for (auto& [num, freq] : count) { + if (freq == 2) { + res.push_back(num); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + findDuplicates(nums) { + const count = new Map(); + const res = []; + + for (const num of nums) { + count.set(num, (count.get(num) || 0) + 1); + } + + for (const [num, freq] of count.entries()) { + if (freq === 2) { + res.push(num); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 5. Negative Marking + +::tabs-start + +```python +class Solution: + def findDuplicates(self, nums: List[int]) -> List[int]: + res = [] + + for num in nums: + idx = abs(num) - 1 + if nums[idx] < 0: + res.append(abs(num)) + nums[idx] = -nums[idx] + + return res +``` + +```java +public class Solution { + public List findDuplicates(int[] nums) { + List res = new ArrayList<>(); + + for (int num : nums) { + int idx = Math.abs(num) - 1; + if (nums[idx] < 0) { + res.add(Math.abs(num)); + } + nums[idx] = -nums[idx]; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findDuplicates(vector& nums) { + vector res; + + for (int num : nums) { + int idx = abs(num) - 1; + if (nums[idx] < 0) { + res.push_back(abs(num)); + } + nums[idx] = -nums[idx]; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + findDuplicates(nums) { + const res = []; + + for (let num of nums) { + const idx = Math.abs(num) - 1; + if (nums[idx] < 0) { + res.push(Math.abs(num)); + } + nums[idx] = -nums[idx]; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/find-all-numbers-disappeared-in-an-array.md b/articles/find-all-numbers-disappeared-in-an-array.md index f0462dc4f..4ae4b6150 100644 --- a/articles/find-all-numbers-disappeared-in-an-array.md +++ b/articles/find-all-numbers-disappeared-in-an-array.md @@ -7,10 +7,10 @@ class Solution: def findDisappearedNumbers(self, nums: List[int]) -> List[int]: n = len(nums) store = set(range(1, n + 1)) - + for num in nums: store.discard(num) - + return list(store) ``` @@ -20,11 +20,11 @@ public class Solution { int n = nums.length; Set store = new HashSet<>(); for (int i = 1; i <= n; i++) store.add(i); - + for (int num : nums) { store.remove(num); } - + return new ArrayList<>(store); } } @@ -37,11 +37,11 @@ public: int n = nums.size(); unordered_set store; for (int i = 1; i <= n; i++) store.insert(i); - + for (int num : nums) { store.erase(num); } - + vector result(store.begin(), store.end()); return result; } @@ -58,11 +58,11 @@ class Solution { const n = nums.length; const store = new Set(); for (let i = 1; i <= n; i++) store.add(i); - + for (let num of nums) { store.delete(num); } - + return Array.from(store); } } @@ -72,8 +72,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -86,10 +86,10 @@ class Solution: def findDisappearedNumbers(self, nums: List[int]) -> List[int]: n = len(nums) mark = [False] * n - + for num in nums: mark[num - 1] = True - + res = [] for i in range(1, n + 1): if not mark[i - 1]: @@ -102,11 +102,11 @@ public class Solution { public List findDisappearedNumbers(int[] nums) { int n = nums.length; boolean[] mark = new boolean[n]; - + for (int num : nums) { mark[num - 1] = true; } - + List res = new ArrayList<>(); for (int i = 1; i <= n; i++) { if (!mark[i - 1]) { @@ -124,11 +124,11 @@ public: vector findDisappearedNumbers(vector& nums) { int n = nums.size(); vector mark(n, false); - + for (int num : nums) { mark[num - 1] = true; } - + vector res; for (int i = 1; i <= n; i++) { if (!mark[i - 1]) { @@ -149,11 +149,11 @@ class Solution { findDisappearedNumbers(nums) { const n = nums.length; const mark = new Array(n).fill(false); - + for (let num of nums) { mark[num - 1] = true; } - + const res = []; for (let i = 1; i <= n; i++) { if (!mark[i - 1]) { @@ -169,8 +169,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -183,7 +183,7 @@ class Solution: def findDisappearedNumbers(self, nums: List[int]) -> List[int]: n = len(nums) nums.sort() - + res = [] idx = 0 for num in range(1, n + 1): @@ -199,7 +199,7 @@ public class Solution { public List findDisappearedNumbers(int[] nums) { int n = nums.length; Arrays.sort(nums); - + List res = new ArrayList<>(); int idx = 0; for (int num = 1; num <= n; num++) { @@ -221,7 +221,7 @@ public: vector findDisappearedNumbers(vector& nums) { int n = nums.size(); sort(nums.begin(), nums.end()); - + vector res; int idx = 0; for (int num = 1; num <= n; num++) { @@ -245,7 +245,7 @@ class Solution { */ findDisappearedNumbers(nums) { nums.sort((a, b) => a - b); - + const res = []; let idx = 0; for (let num = 1; num <= nums.length; num++) { @@ -265,8 +265,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -279,13 +279,13 @@ class Solution: def findDisappearedNumbers(self, nums: List[int]) -> List[int]: for num in nums: i = abs(num) - 1 - nums[i] = -1 * abs(nums[i]) + nums[i] = -1 * abs(nums[i]) res = [] for i, num in enumerate(nums): if num > 0: res.append(i + 1) - return res + return res ``` ```java @@ -295,7 +295,7 @@ public class Solution { int i = Math.abs(num) - 1; nums[i] = -Math.abs(nums[i]); } - + List res = new ArrayList<>(); for (int i = 0; i < nums.length; i++) { if (nums[i] > 0) { @@ -315,7 +315,7 @@ public: int i = abs(num) - 1; nums[i] = -abs(nums[i]); } - + vector res; for (int i = 0; i < nums.size(); i++) { if (nums[i] > 0) { @@ -338,7 +338,7 @@ class Solution { let i = Math.abs(num) - 1; nums[i] = -Math.abs(nums[i]); } - + const res = []; for (let i = 0; i < nums.length; i++) { if (nums[i] > 0) { @@ -354,5 +354,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since we modified the input array without using extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we modified the input array without using extra space. diff --git a/articles/find-all-people-with-secret.md b/articles/find-all-people-with-secret.md new file mode 100644 index 000000000..7158d9b53 --- /dev/null +++ b/articles/find-all-people-with-secret.md @@ -0,0 +1,835 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def findAllPeople(self, n: int, meetings: list[list[int]], firstPerson: int) -> list[int]: + secrets = set([0, firstPerson]) # People with secret + time_map = {} # time -> adjacency list meetings + + for src, dst, t in meetings: + if t not in time_map: + time_map[t] = defaultdict(list) + time_map[t][src].append(dst) + time_map[t][dst].append(src) + + def dfs(src, adj): + if src in visit: + return + visit.add(src) + secrets.add(src) + for nei in adj[src]: + dfs(nei, adj) + + for t in sorted(time_map.keys()): + visit = set() + for src in time_map[t]: + if src in secrets: + dfs(src, time_map[t]) + + return list(secrets) +``` + +```java +public class Solution { + private Set secrets, visit; + + public List findAllPeople(int n, int[][] meetings, int firstPerson) { + secrets = new HashSet<>(); + visit = new HashSet<>(); + secrets.add(0); + secrets.add(firstPerson); + Map>> time_map = new HashMap<>(); + + for (int[] meet : meetings) { + int src = meet[0], dst = meet[1], t = meet[2]; + time_map.putIfAbsent(t, new HashMap<>()); + time_map.get(t).putIfAbsent(src, new ArrayList<>()); + time_map.get(t).putIfAbsent(dst, new ArrayList<>()); + time_map.get(t).get(src).add(dst); + time_map.get(t).get(dst).add(src); + } + + List timeKeys = new ArrayList<>(time_map.keySet()); + Collections.sort(timeKeys); + for (int t : timeKeys) { + visit = new HashSet<>(); + for (int src : time_map.get(t).keySet()) { + if (secrets.contains(src)) { + dfs(src, time_map.get(t)); + } + } + } + return new ArrayList<>(secrets); + } + + private void dfs(int src, Map> adj) { + if (!visit.add(src)) return; + secrets.add(src); + for (int nei : adj.getOrDefault(src, new ArrayList<>())) { + dfs(nei, adj); + } + } +} +``` + +```cpp +class Solution { +public: + unordered_set secrets, visit; + + vector findAllPeople(int n, vector>& meetings, int firstPerson) { + secrets = {0, firstPerson}; + unordered_map>> time_map; + + for (auto& meet : meetings) { + int src = meet[0], dst = meet[1], t = meet[2]; + time_map[t][src].push_back(dst); + time_map[t][dst].push_back(src); + } + + vector timeKeys; + for (auto& [t, _] : time_map) { + timeKeys.push_back(t); + } + sort(timeKeys.begin(), timeKeys.end()); + + for (int& t : timeKeys) { + visit.clear(); + for (auto& [src, _] : time_map[t]) { + if (secrets.count(src)) { + dfs(src, time_map[t]); + } + } + } + + return vector(secrets.begin(), secrets.end()); + } + +private: + void dfs(int src, unordered_map>& adj) { + if (!visit.insert(src).second) return; + secrets.insert(src); + for (int& nei : adj[src]) { + dfs(nei, adj); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} meetings + * @param {number} firstPerson + * @return {number[]} + */ + findAllPeople(n, meetings, firstPerson) { + const secrets = new Set([0, firstPerson]); + let visit = new Set(); + let time_map = new Map(); + + for (let [src, dst, t] of meetings) { + if (!time_map.has(t)) time_map.set(t, new Map()); + if (!time_map.get(t).has(src)) time_map.get(t).set(src, []); + if (!time_map.get(t).has(dst)) time_map.get(t).set(dst, []); + time_map.get(t).get(src).push(dst); + time_map.get(t).get(dst).push(src); + } + const dfs = (src, adj) => { + if (visit.has(src)) return; + visit.add(src); + secrets.add(src); + for (let nei of adj.get(src) || []) { + dfs(nei, adj); + } + }; + + let timeKeys = [...time_map.keys()].sort((a, b) => a - b); + for (let t of timeKeys) { + visit.clear(); + for (let src of time_map.get(t).keys()) { + if (secrets.has(src)) { + dfs(src, time_map.get(t)); + } + } + } + + return [...secrets]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m \log m + n)$ +- Space complexity: $O(m + n)$ + +> Where $m$ is the number of meetings and $n$ is the number of people. + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class Solution: + def findAllPeople(self, n: int, meetings: list[list[int]], firstPerson: int) -> list[int]: + secrets = set([0, firstPerson]) # People with secret + time_map = {} # time -> adjacency list meetings + + for src, dst, t in meetings: + if t not in time_map: + time_map[t] = defaultdict(list) + time_map[t][src].append(dst) + time_map[t][dst].append(src) + + for t in sorted(time_map.keys()): + visit = set() + q = deque() + + for src in time_map[t]: + if src in secrets: + q.append(src) + visit.add(src) + + while q: + node = q.popleft() + secrets.add(node) + for nei in time_map[t][node]: + if nei not in visit: + visit.add(nei) + q.append(nei) + + return list(secrets) +``` + +```java +public class Solution { + public List findAllPeople(int n, int[][] meetings, int firstPerson) { + Set secrets = new HashSet<>(); + secrets.add(0); + secrets.add(firstPerson); + TreeMap>> time_map = new TreeMap<>(); + + for (int[] meet : meetings) { + int src = meet[0], dst = meet[1], t = meet[2]; + time_map.putIfAbsent(t, new HashMap<>()); + time_map.get(t).putIfAbsent(src, new ArrayList<>()); + time_map.get(t).putIfAbsent(dst, new ArrayList<>()); + time_map.get(t).get(src).add(dst); + time_map.get(t).get(dst).add(src); + } + + for (int t : time_map.keySet()) { + Set visit = new HashSet<>(); + Queue q = new LinkedList<>(); + + for (int src : time_map.get(t).keySet()) { + if (secrets.contains(src)) { + q.offer(src); + visit.add(src); + } + } + + while (!q.isEmpty()) { + int node = q.poll(); + secrets.add(node); + for (int nei : time_map.get(t).get(node)) { + if (!visit.contains(nei)) { + visit.add(nei); + q.offer(nei); + } + } + } + } + + return new ArrayList<>(secrets); + } +} +``` + +```cpp +class Solution { +public: + vector findAllPeople(int n, vector>& meetings, int firstPerson) { + unordered_set secrets = {0, firstPerson}; + map>> time_map; + + for (auto& meet : meetings) { + int src = meet[0], dst = meet[1], t = meet[2]; + time_map[t][src].push_back(dst); + time_map[t][dst].push_back(src); + } + + for (auto& [t, adj] : time_map) { + unordered_set visit; + queue q; + + for (auto& [src, _] : adj) { + if (secrets.count(src)) { + q.push(src); + visit.insert(src); + } + } + + while (!q.empty()) { + int node = q.front(); + q.pop(); + secrets.insert(node); + for (int nei : adj[node]) { + if (!visit.count(nei)) { + visit.insert(nei); + q.push(nei); + } + } + } + } + + return vector(secrets.begin(), secrets.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} meetings + * @param {number} firstPerson + * @return {number[]} + */ + findAllPeople(n, meetings, firstPerson) { + const secrets = new Set([0, firstPerson]); + const time_map = new Map(); + + for (let [src, dst, t] of meetings) { + if (!time_map.has(t)) time_map.set(t, new Map()); + if (!time_map.get(t).has(src)) time_map.get(t).set(src, []); + if (!time_map.get(t).has(dst)) time_map.get(t).set(dst, []); + time_map.get(t).get(src).push(dst); + time_map.get(t).get(dst).push(src); + } + + for (let t of [...time_map.keys()].sort((a, b) => a - b)) { + let visit = new Set(); + const q = new Queue(); + + for (let src of time_map.get(t).keys()) { + if (secrets.has(src)) { + q.push(src); + visit.add(src); + } + } + + while (!q.isEmpty()) { + let node = q.pop(); + secrets.add(node); + for (let nei of time_map.get(t).get(node)) { + if (!visit.has(nei)) { + visit.add(nei); + q.push(nei); + } + } + } + } + + return [...secrets]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m \log m + n)$ +- Space complexity: $O(m + n)$ + +> Where $m$ is the number of meetings and $n$ is the number of people. + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +class Solution: + def findAllPeople(self, n: int, meetings: list[list[int]], firstPerson: int) -> list[int]: + meetings.sort(key=lambda x: x[2]) # Sort by time + secrets = [False] * n + secrets[0] = secrets[firstPerson] = True + + for _, group in groupby(meetings, key=lambda x: x[2]): + adj = defaultdict(list) + visited = set() + + for u, v, _ in group: + adj[u].append(v) + adj[v].append(u) + if secrets[u]: + visited.add(u) + if secrets[v]: + visited.add(v) + + stack = list(visited) + while stack: + node = stack.pop() + for nei in adj[node]: + if nei not in visited: + visited.add(nei) + stack.append(nei) + secrets[nei] = True + + return [i for i in range(n) if secrets[i]] +``` + +```java +public class Solution { + public List findAllPeople(int n, int[][] meetings, int firstPerson) { + Arrays.sort(meetings, Comparator.comparingInt(a -> a[2])); + boolean[] secrets = new boolean[n]; + secrets[0] = secrets[firstPerson] = true; + + int i = 0, m = meetings.length; + while (i < m) { + int time = meetings[i][2]; + Map> adj = new HashMap<>(); + Set visited = new HashSet<>(); + + while (i < m && meetings[i][2] == time) { + int u = meetings[i][0], v = meetings[i][1]; + adj.computeIfAbsent(u, k -> new ArrayList<>()).add(v); + adj.computeIfAbsent(v, k -> new ArrayList<>()).add(u); + if (secrets[u]) visited.add(u); + if (secrets[v]) visited.add(v); + i++; + } + + Stack stack = new Stack<>(); + stack.addAll(visited); + while (!stack.isEmpty()) { + int node = stack.pop(); + for (int nei : adj.getOrDefault(node, Collections.emptyList())) { + if (!visited.contains(nei)) { + visited.add(nei); + stack.push(nei); + secrets[nei] = true; + } + } + } + } + + List res = new ArrayList<>(); + for (int j = 0; j < n; j++) { + if (secrets[j]) res.add(j); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findAllPeople(int n, vector>& meetings, int firstPerson) { + sort(meetings.begin(), meetings.end(), [](auto& a, auto& b) { + return a[2] < b[2]; + }); + + vector secrets(n, false); + secrets[0] = secrets[firstPerson] = true; + + int i = 0, m = meetings.size(); + while (i < m) { + int time = meetings[i][2]; + unordered_map> adj; + unordered_set visited; + + while (i < m && meetings[i][2] == time) { + int u = meetings[i][0], v = meetings[i][1]; + adj[u].push_back(v); + adj[v].push_back(u); + if (secrets[u]) visited.insert(u); + if (secrets[v]) visited.insert(v); + i++; + } + + stack stack(visited.begin(), visited.end()); + while (!stack.empty()) { + int node = stack.top(); stack.pop(); + for (int& nei : adj[node]) { + if (!visited.count(nei)) { + visited.insert(nei); + stack.push(nei); + secrets[nei] = true; + } + } + } + } + + vector res; + for (int j = 0; j < n; j++) { + if (secrets[j]) res.push_back(j); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} meetings + * @param {number} firstPerson + * @return {number[]} + */ + findAllPeople(n, meetings, firstPerson) { + meetings.sort((a, b) => a[2] - b[2]); + const secrets = new Array(n).fill(false); + secrets[0] = secrets[firstPerson] = true; + + let i = 0, + m = meetings.length; + while (i < m) { + const time = meetings[i][2]; + const adj = new Map(); + const visited = new Set(); + + while (i < m && meetings[i][2] === time) { + const [u, v] = meetings[i]; + if (!adj.has(u)) adj.set(u, []); + if (!adj.has(v)) adj.set(v, []); + adj.get(u).push(v); + adj.get(v).push(u); + if (secrets[u]) visited.add(u); + if (secrets[v]) visited.add(v); + i++; + } + + const stack = [...visited]; + while (stack.length) { + const node = stack.pop(); + for (const nei of adj.get(node) || []) { + if (!visited.has(nei)) { + visited.add(nei); + stack.push(nei); + secrets[nei] = true; + } + } + } + } + + let res = []; + for (let i = 0; i < n; i++) { + if (secrets[i]) res.push(i); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m \log m + n)$ +- Space complexity: $O(m + n)$ + +> Where $m$ is the number of meetings and $n$ is the number of people. + +--- + +## 4. Disjoint Set Union + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.Parent = list(range(n + 1)) + self.Size = [1] * (n + 1) + + def find(self, node): + if self.Parent[node] != node: + self.Parent[node] = self.find(self.Parent[node]) + return self.Parent[node] + + def union(self, u, v): + pu, pv = self.find(u), self.find(v) + if pu == pv: + return False + if self.Size[pu] < self.Size[pv]: + pu, pv = pv, pu + self.Size[pu] += self.Size[pv] + self.Parent[pv] = pu + return True + + def reset(self, node): + self.Parent[node] = node + self.Size[node] = 1 + +class Solution: + def findAllPeople(self, n: int, meetings: list[list[int]], firstPerson: int) -> list[int]: + meetings.sort(key=lambda x: x[2]) # Sort by time + dsu = DSU(n) + dsu.union(0, firstPerson) + + for _, group in groupby(meetings, key=lambda x: x[2]): + group_nodes = set() + for u, v, _ in group: + dsu.union(u, v) + group_nodes.add(u) + group_nodes.add(v) + + for node in group_nodes: + if dsu.find(node) != dsu.find(0): + dsu.reset(node) + + return [i for i in range(n) if dsu.find(i) == dsu.find(0)] +``` + +```java +class DSU { + int[] Parent, Size; + + DSU(int n) { + Parent = new int[n + 1]; + Size = new int[n + 1]; + for (int i = 0; i <= n; i++) { + Parent[i] = i; + Size[i] = 1; + } + } + + int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + void union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return; + if (Size[pu] < Size[pv]) { + int temp = pu; + pu = pv; + pv = temp; + } + Size[pu] += Size[pv]; + Parent[pv] = pu; + } + + void reset(int node) { + Parent[node] = node; + Size[node] = 1; + } +} + +public class Solution { + public List findAllPeople(int n, int[][] meetings, int firstPerson) { + Arrays.sort(meetings, Comparator.comparingInt(a -> a[2])); + DSU dsu = new DSU(n); + dsu.union(0, firstPerson); + + for (int i = 0; i < meetings.length; ) { + int time = meetings[i][2]; + Set group = new HashSet<>(); + + for (; i < meetings.length && meetings[i][2] == time; i++) { + int u = meetings[i][0], v = meetings[i][1]; + dsu.union(u, v); + group.add(u); + group.add(v); + } + + for (int node : group) { + if (dsu.find(node) != dsu.find(0)) { + dsu.reset(node); + } + } + } + + List result = new ArrayList<>(); + for (int i = 0; i < n; i++) { + if (dsu.find(i) == dsu.find(0)) result.add(i); + } + return result; + } +} +``` + +```cpp +class DSU { +public: + vector Parent, Size; + + DSU(int n) { + Parent.resize(n + 1); + Size.resize(n + 1, 1); + for (int i = 0; i <= n; i++) { + Parent[i] = i; + } + } + + int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + void unionSets(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return; + if (Size[pu] < Size[pv]) swap(pu, pv); + Size[pu] += Size[pv]; + Parent[pv] = pu; + } + + void reset(int node) { + Parent[node] = node; + Size[node] = 1; + } +}; + +class Solution { +public: + vector findAllPeople(int n, vector>& meetings, int firstPerson) { + sort(meetings.begin(), meetings.end(), [](auto &a, auto &b) { + return a[2] < b[2]; + }); + DSU dsu(n); + dsu.unionSets(0, firstPerson); + + for (int i = 0; i < meetings.size(); ) { + int time = meetings[i][2]; + unordered_set group; + + for (; i < meetings.size() && meetings[i][2] == time; i++) { + int u = meetings[i][0], v = meetings[i][1]; + dsu.unionSets(u, v); + group.insert(u); + group.insert(v); + } + + for (int node : group) { + if (dsu.find(node) != dsu.find(0)) { + dsu.reset(node); + } + } + } + + vector result; + for (int i = 0; i < n; i++) { + if (dsu.find(i) == dsu.find(0)) result.push_back(i); + } + return result; + } +}; +``` + +```javascript +class DSU { + /** + * @constructor + * @param {number} n + */ + constructor(n) { + this.Parent = Array.from({ length: n + 1 }, (_, i) => i); + this.Size = Array(n + 1).fill(1); + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.Parent[node] !== node) { + this.Parent[node] = this.find(this.Parent[node]); + } + return this.Parent[node]; + } + + /** + * @param {number} u + * @param {number} v + * @return {boolean} + */ + union(u, v) { + let pu = this.find(u); + let pv = this.find(v); + if (pu === pv) return false; + if (this.Size[pu] >= this.Size[pv]) { + this.Size[pu] += this.Size[pv]; + this.Parent[pv] = pu; + } else { + this.Size[pv] += this.Size[pu]; + this.Parent[pu] = pv; + } + return true; + } + + /** + * @param {number} node + * @return {void} + */ + reset(node) { + this.Parent[node] = node; + this.Size[node] = 1; + } +} + +class Solution { + /** + * @param {number} n + * @param {number[][]} meetings + * @param {number} firstPerson + * @return {number[]} + */ + findAllPeople(n, meetings, firstPerson) { + meetings.sort((a, b) => a[2] - b[2]); + let dsu = new DSU(n); + dsu.union(0, firstPerson); + + for (let i = 0; i < meetings.length; ) { + let time = meetings[i][2]; + let group = new Set(); + + for (; i < meetings.length && meetings[i][2] === time; i++) { + let [u, v] = meetings[i]; + dsu.union(u, v); + group.add(u); + group.add(v); + } + + group.forEach((node) => { + if (dsu.find(node) !== dsu.find(0)) { + dsu.reset(node); + } + }); + } + + return [...Array(n).keys()].filter((i) => dsu.find(i) === dsu.find(0)); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m \log m + (m * α(n)))$ +- Space complexity: + - $O(n)$ extra space. + - $O(m)$ space depending on the sorting algorithm. + +> Where $m$ is the number of meetings and $n$ is the number of people. diff --git a/articles/find-bottom-left-tree-value.md b/articles/find-bottom-left-tree-value.md new file mode 100644 index 000000000..a39ec9ed1 --- /dev/null +++ b/articles/find-bottom-left-tree-value.md @@ -0,0 +1,638 @@ +## 1. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def findBottomLeftValue(self, root: Optional[TreeNode]) -> int: + q = deque([root]) + + while q: + node = q.popleft() + if node.right: + q.append(node.right) + if node.left: + q.append(node.left) + + return node.val +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int findBottomLeftValue(TreeNode root) { + Queue q = new LinkedList<>(); + q.offer(root); + TreeNode node = null; + + while (!q.isEmpty()) { + node = q.poll(); + if (node.right != null) q.offer(node.right); + if (node.left != null) q.offer(node.left); + } + return node.val; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int findBottomLeftValue(TreeNode* root) { + queue q; + q.push(root); + TreeNode* node = nullptr; + + while (!q.empty()) { + node = q.front(); + q.pop(); + if (node->right) q.push(node->right); + if (node->left) q.push(node->left); + } + return node->val; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + findBottomLeftValue(root) { + const q = new Queue([root]); + let node = null; + + while (!q.isEmpty()) { + node = q.pop(); + if (node.right) q.push(node.right); + if (node.left) q.push(node.left); + } + return node.val; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def findBottomLeftValue(self, root: Optional[TreeNode]) -> int: + self.maxDepth, self.res = -1, root.val + + def dfs(node, depth): + if not node: + return + if depth > self.maxDepth: + self.maxDepth, self.res = depth, node.val + + dfs(node.left, depth + 1) + dfs(node.right, depth + 1) + + dfs(root, 0) + return self.res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private int maxDepth = -1; + private int res; + + public int findBottomLeftValue(TreeNode root) { + res = root.val; + dfs(root, 0); + return res; + } + + private void dfs(TreeNode node, int depth) { + if (node == null) return; + if (depth > maxDepth) { + maxDepth = depth; + res = node.val; + } + + dfs(node.left, depth + 1); + dfs(node.right, depth + 1); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int maxDepth = -1, res; + + int findBottomLeftValue(TreeNode* root) { + res = root->val; + dfs(root, 0); + return res; + } + +private: + void dfs(TreeNode* node, int depth) { + if (!node) return; + if (depth > maxDepth) { + maxDepth = depth; + res = node->val; + } + + dfs(node->left, depth + 1); + dfs(node->right, depth + 1); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + findBottomLeftValue(root) { + let maxDepth = -1, + res = root.val; + + const dfs = (node, depth) => { + if (!node) return; + if (depth > maxDepth) { + maxDepth = depth; + res = node.val; + } + + dfs(node.left, depth + 1); + dfs(node.right, depth + 1); + }; + + dfs(root, 0); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def findBottomLeftValue(self, root: Optional[TreeNode]) -> int: + res, maxDepth = root.val, -1 + stack = [(root, 0)] + + while stack: + node, depth = stack.pop() + if depth > maxDepth: + maxDepth = depth + res = node.val + + if node.right: + stack.append((node.right, depth + 1)) + if node.left: + stack.append((node.left, depth + 1)) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int findBottomLeftValue(TreeNode root) { + int res = root.val, maxDepth = -1; + Stack> stack = new Stack<>(); + stack.push(new Pair<>(root, 0)); + + while (!stack.isEmpty()) { + Pair p = stack.pop(); + TreeNode node = p.getKey(); + int depth = p.getValue(); + if (depth > maxDepth) { + maxDepth = depth; + res = node.val; + } + + if (node.right != null) { + stack.push(new Pair<>(node.right, depth + 1)); + } + if (node.left != null) { + stack.push(new Pair<>(node.left, depth + 1)); + } + } + + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int findBottomLeftValue(TreeNode* root) { + int res = root->val, maxDepth = -1; + stack> stack; + stack.push({root, 0}); + + while (!stack.empty()) { + auto [node, depth] = stack.top();stack.pop(); + if (depth > maxDepth) { + maxDepth = depth; + res = node->val; + } + + if (node->right) { + stack.push({node->right, depth + 1}); + } + if (node->left) { + stack.push({node->left, depth + 1}); + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + findBottomLeftValue(root) { + let res = root.val, + maxDepth = -1; + const stack = [[root, 0]]; + + while (stack.length) { + const [node, depth] = stack.pop(); + if (depth > maxDepth) { + maxDepth = depth; + res = node.val; + } + + if (node.right) stack.push([node.right, depth + 1]); + if (node.left) stack.push([node.left, depth + 1]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Morris Traversal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def findBottomLeftValue(self, root: Optional[TreeNode]) -> int: + res, maxDepth, curDepth = root.val, -1, 0 + cur = root + + while cur: + if not cur.left: + if curDepth > maxDepth: + maxDepth, res = curDepth, cur.val + cur = cur.right + curDepth += 1 + else: + prev = cur.left + steps = 1 + while prev.right and prev.right != cur: + prev = prev.right + steps += 1 + + if not prev.right: + prev.right = cur + cur = cur.left + curDepth += 1 + else: + prev.right = None + curDepth -= steps + cur = cur.right + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int findBottomLeftValue(TreeNode root) { + int res = root.val, maxDepth = -1, curDepth = 0; + TreeNode cur = root; + + while (cur != null) { + if (cur.left == null) { + if (curDepth > maxDepth) { + maxDepth = curDepth; + res = cur.val; + } + cur = cur.right; + curDepth++; + } else { + TreeNode prev = cur.left; + int steps = 1; + while (prev.right != null && prev.right != cur) { + prev = prev.right; + steps++; + } + + if (prev.right == null) { + prev.right = cur; + cur = cur.left; + curDepth++; + } else { + prev.right = null; + curDepth -= steps; + cur = cur.right; + } + } + } + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int findBottomLeftValue(TreeNode* root) { + int res = root->val, maxDepth = -1, curDepth = 0; + TreeNode* cur = root; + + while (cur) { + if (!cur->left) { + if (curDepth > maxDepth) { + maxDepth = curDepth; + res = cur->val; + } + cur = cur->right; + curDepth++; + } else { + TreeNode* prev = cur->left; + int steps = 1; + while (prev->right && prev->right != cur) { + prev = prev->right; + steps++; + } + + if (!prev->right) { + prev->right = cur; + cur = cur->left; + curDepth++; + } else { + prev->right = nullptr; + curDepth -= steps; + cur = cur->right; + } + } + } + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + findBottomLeftValue(root) { + let res = root.val, + maxDepth = -1, + curDepth = 0; + let cur = root; + + while (cur) { + if (!cur.left) { + if (curDepth > maxDepth) { + maxDepth = curDepth; + res = cur.val; + } + cur = cur.right; + curDepth++; + } else { + let prev = cur.left, + steps = 1; + while (prev.right && prev.right !== cur) { + prev = prev.right; + steps++; + } + + if (!prev.right) { + prev.right = cur; + cur = cur.left; + curDepth++; + } else { + prev.right = null; + curDepth -= steps; + cur = cur.right; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/find-closest-node-to-given-two-nodes.md b/articles/find-closest-node-to-given-two-nodes.md new file mode 100644 index 000000000..73f74bcdc --- /dev/null +++ b/articles/find-closest-node-to-given-two-nodes.md @@ -0,0 +1,673 @@ +## 1. Breadth First Search + +::tabs-start + +```python +class Solution: + def closestMeetingNode(self, edges: list[int], node1: int, node2: int) -> int: + adj = defaultdict(list) + for i, nei in enumerate(edges): + adj[i].append(nei) + + def bfs(src, distMap): + q = deque([(src, 0)]) + distMap[src] = 0 + while q: + node, dist = q.popleft() + for nei in adj[node]: + if nei not in distMap: + q.append((nei, dist + 1)) + distMap[nei] = dist + 1 + + node1Dist, node2Dist = {}, {} + bfs(node1, node1Dist) + bfs(node2, node2Dist) + + res, resDist = -1, float("inf") + for i in range(len(edges)): + if i in node1Dist and i in node2Dist: + dist = max(node1Dist[i], node2Dist[i]) + if dist < resDist: + resDist, res = dist, i + + return res +``` + +```java +public class Solution { + public int closestMeetingNode(int[] edges, int node1, int node2) { + int n = edges.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + for (int i = 0; i < n; i++) { + if (edges[i] != -1) adj[i].add(edges[i]); + } + + int[] node1Dist = bfs(node1, n, adj); + int[] node2Dist = bfs(node2, n, adj); + + int res = -1, resDist = Integer.MAX_VALUE; + for (int i = 0; i < n; i++) { + if (node1Dist[i] != -1 && node2Dist[i] != -1) { + int dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } + + private int[] bfs(int src, int n, List[] adj) { + int[] distMap = new int[n]; + Arrays.fill(distMap, -1); + Queue q = new LinkedList<>(); + q.offer(new int[]{src, 0}); + distMap[src] = 0; + + while (!q.isEmpty()) { + int[] cur = q.poll(); + int node = cur[0], dist = cur[1]; + + for (int nei : adj[node]) { + if (distMap[nei] == -1) { + q.offer(new int[]{nei, dist + 1}); + distMap[nei] = dist + 1; + } + } + } + return distMap; + } +} +``` + +```cpp +class Solution { +public: + int closestMeetingNode(vector& edges, int node1, int node2) { + int n = edges.size(); + vector> adj(n); + for (int i = 0; i < n; i++) { + if (edges[i] != -1) adj[i].push_back(edges[i]); + } + + vector node1Dist = bfs(node1, n, adj); + vector node2Dist = bfs(node2, n, adj); + + int res = -1, resDist = INT_MAX; + for (int i = 0; i < n; i++) { + if (node1Dist[i] != -1 && node2Dist[i] != -1) { + int dist = max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } + +private: + vector bfs(int src, int n, vector>& adj) { + vector distMap(n, -1); + queue> q; + q.push({src, 0}); + distMap[src] = 0; + + while (!q.empty()) { + auto [node, dist] = q.front(); + q.pop(); + + for (int nei : adj[node]) { + if (distMap[nei] == -1) { + q.push({nei, dist + 1}); + distMap[nei] = dist + 1; + } + } + } + return distMap; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} edges + * @param {number} node1 + * @param {number} node2 + * @return {number} + */ + closestMeetingNode(edges, node1, node2) { + const n = edges.length; + const adj = Array.from({ length: n }, () => []); + for (let i = 0; i < n; i++) { + if (edges[i] !== -1) adj[i].push(edges[i]); + } + + const bfs = (src) => { + const distMap = Array(n).fill(-1); + const q = new Queue([[src, 0]]); + distMap[src] = 0; + + while (!q.isEmpty()) { + const [node, dist] = q.pop(); + for (const nei of adj[node]) { + if (distMap[nei] === -1) { + q.push([nei, dist + 1]); + distMap[nei] = dist + 1; + } + } + } + return distMap; + }; + + const node1Dist = bfs(node1); + const node2Dist = bfs(node2); + + let res = -1, + resDist = Infinity; + for (let i = 0; i < n; i++) { + if (node1Dist[i] !== -1 && node2Dist[i] !== -1) { + let dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Breadth First Search (Optimal) + +::tabs-start + +```python +class Solution: + def closestMeetingNode(self, edges: list[int], node1: int, node2: int) -> int: + n = len(edges) + + def bfs(src): + dist = [-1] * n + q = deque([src]) + dist[src] = 0 + + while q: + node = q.popleft() + nei = edges[node] + if nei == -1 or dist[nei] >= 0: + continue + q.append(nei) + dist[nei] = dist[node] + 1 + return dist + + node1Dist, node2Dist = bfs(node1), bfs(node2) + + res, resDist = -1, float("inf") + for i in range(n): + if node1Dist[i] != -1 and node2Dist[i] != -1: + dist = max(node1Dist[i], node2Dist[i]) + if dist < resDist: + resDist, res = dist, i + + return res +``` + +```java +public class Solution { + public int closestMeetingNode(int[] edges, int node1, int node2) { + int n = edges.length; + int[] node1Dist = bfs(node1, edges, n); + int[] node2Dist = bfs(node2, edges, n); + + int res = -1, resDist = Integer.MAX_VALUE; + for (int i = 0; i < n; i++) { + if (node1Dist[i] != -1 && node2Dist[i] != -1) { + int dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + + return res; + } + + private int[] bfs(int src, int[] edges, int n) { + int[] dist = new int[n]; + Arrays.fill(dist, -1); + Queue q = new LinkedList<>(); + q.offer(src); + dist[src] = 0; + + while (!q.isEmpty()) { + int node = q.poll(); + int nei = edges[node]; + if (nei == -1 || dist[nei] != -1) { + continue; + } + + q.offer(nei); + dist[nei] = dist[node] + 1; + } + return dist; + } +} +``` + +```cpp +class Solution { +public: + int closestMeetingNode(vector& edges, int node1, int node2) { + int n = edges.size(); + vector node1Dist = bfs(node1, edges, n); + vector node2Dist = bfs(node2, edges, n); + + int res = -1, resDist = INT_MAX; + for (int i = 0; i < n; i++) { + if (node1Dist[i] != -1 && node2Dist[i] != -1) { + int dist = max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } + +private: + vector bfs(int src, vector& edges, int n) { + vector dist(n, -1); + queue q; + q.push(src); + dist[src] = 0; + + while (!q.empty()) { + int node = q.front(); + q.pop(); + int nei = edges[node]; + if (nei == -1 || dist[nei] != -1) { + continue; + } + + q.push(nei); + dist[nei] = dist[node] + 1; + } + return dist; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} edges + * @param {number} node1 + * @param {number} node2 + * @return {number} + */ + closestMeetingNode(edges, node1, node2) { + const n = edges.length; + + const bfs = (src) => { + const dist = Array(n).fill(-1); + const q = new Queue([src]); + dist[src] = 0; + + while (!q.isEmpty()) { + const node = q.pop(); + const nei = edges[node]; + if (nei === -1 || dist[nei] !== -1) { + continue; + } + + q.push(nei); + dist[nei] = dist[node] + 1; + } + return dist; + }; + + const node1Dist = bfs(node1); + const node2Dist = bfs(node2); + + let res = -1, + resDist = Infinity; + for (let i = 0; i < n; i++) { + if (node1Dist[i] !== -1 && node2Dist[i] !== -1) { + let dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Depth First Search + +::tabs-start + +```python +class Solution: + def closestMeetingNode(self, edges: List[int], node1: int, node2: int) -> int: + n = len(edges) + + def dfs(node, dist): + nei = edges[node] + if nei != -1 and dist[nei] == -1: + dist[nei] = dist[node] + 1 + dfs(nei, dist) + + node1Dist = [-1] * n + node2Dist = [-1] * n + node1Dist[node1] = node2Dist[node2] = 0 + + dfs(node1, node1Dist) + dfs(node2, node2Dist) + + res, resDist = -1, float("inf") + for i in range(n): + if min(node1Dist[i], node2Dist[i]) != -1: + dist = max(node1Dist[i], node2Dist[i]) + if dist < resDist: + resDist, res = dist, i + + return res +``` + +```java +public class Solution { + public int closestMeetingNode(int[] edges, int node1, int node2) { + int n = edges.length; + int[] node1Dist = new int[n]; + int[] node2Dist = new int[n]; + Arrays.fill(node1Dist, -1); + Arrays.fill(node2Dist, -1); + node1Dist[node1] = 0; + node2Dist[node2] = 0; + + dfs(node1, edges, node1Dist); + dfs(node2, edges, node2Dist); + + int res = -1, resDist = Integer.MAX_VALUE; + for (int i = 0; i < n; i++) { + if (Math.min(node1Dist[i], node2Dist[i]) != -1) { + int dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } + + private void dfs(int node, int[] edges, int[] dist) { + int nei = edges[node]; + if (nei != -1 && dist[nei] == -1) { + dist[nei] = dist[node] + 1; + dfs(nei, edges, dist); + } + } +} +``` + +```cpp +class Solution { +public: + int closestMeetingNode(vector& edges, int node1, int node2) { + int n = edges.size(); + vector node1Dist(n, -1), node2Dist(n, -1); + node1Dist[node1] = node2Dist[node2] = 0; + + dfs(node1, edges, node1Dist); + dfs(node2, edges, node2Dist); + + int res = -1, resDist = INT_MAX; + for (int i = 0; i < n; i++) { + if (min(node1Dist[i], node2Dist[i]) != -1) { + int dist = max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } + +private: + void dfs(int node, vector& edges, vector& dist) { + int nei = edges[node]; + if (nei != -1 && dist[nei] == -1) { + dist[nei] = dist[node] + 1; + dfs(nei, edges, dist); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} edges + * @param {number} node1 + * @param {number} node2 + * @return {number} + */ + closestMeetingNode(edges, node1, node2) { + const n = edges.length; + + const dfs = (node, dist) => { + const nei = edges[node]; + if (nei !== -1 && dist[nei] === -1) { + dist[nei] = dist[node] + 1; + dfs(nei, dist); + } + }; + + const node1Dist = Array(n).fill(-1); + const node2Dist = Array(n).fill(-1); + node1Dist[node1] = 0; + node2Dist[node2] = 0; + + dfs(node1, node1Dist); + dfs(node2, node2Dist); + + let res = -1, + resDist = Infinity; + for (let i = 0; i < n; i++) { + if (Math.min(node1Dist[i], node2Dist[i]) !== -1) { + const dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Iterative Depth First Search + +::tabs-start + +```python +class Solution: + def closestMeetingNode(self, edges: list[int], node1: int, node2: int) -> int: + n = len(edges) + + def dfs(node): + dist = [-1] * n + dist[node] = 0 + while edges[node] != -1 and dist[edges[node]] == -1: + nei = edges[node] + dist[nei] = dist[node] + 1 + node = nei + return dist + + + node1Dist, node2Dist = dfs(node1), dfs(node2) + res, resDist = -1, float("inf") + for i in range(n): + if min(node1Dist[i], node2Dist[i]) != -1: + dist = max(node1Dist[i], node2Dist[i]) + if dist < resDist: + resDist, res = dist, i + return res +``` + +```java +public class Solution { + public int closestMeetingNode(int[] edges, int node1, int node2) { + int n = edges.length; + int[] node1Dist = dfs(node1, edges, n); + int[] node2Dist = dfs(node2, edges, n); + + int res = -1, resDist = Integer.MAX_VALUE; + for (int i = 0; i < n; i++) { + if (Math.min(node1Dist[i], node2Dist[i]) != -1) { + int dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } + + private int[] dfs(int node, int[] edges, int n) { + int[] dist = new int[n]; + Arrays.fill(dist, -1); + dist[node] = 0; + while (edges[node] != -1 && dist[edges[node]] == -1) { + int nei = edges[node]; + dist[nei] = dist[node] + 1; + node = nei; + } + return dist; + } +} +``` + +```cpp +class Solution { +public: + int closestMeetingNode(vector& edges, int node1, int node2) { + int n = edges.size(); + vector node1Dist = dfs(node1, edges, n); + vector node2Dist = dfs(node2, edges, n); + + int res = -1, resDist = INT_MAX; + for (int i = 0; i < n; i++) { + if (min(node1Dist[i], node2Dist[i]) != -1) { + int dist = max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } + +private: + vector dfs(int node, vector& edges, int n) { + vector dist(n, -1); + dist[node] = 0; + while (edges[node] != -1 && dist[edges[node]] == -1) { + int nei = edges[node]; + dist[nei] = dist[node] + 1; + node = nei; + } + return dist; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} edges + * @param {number} node1 + * @param {number} node2 + * @return {number} + */ + closestMeetingNode(edges, node1, node2) { + const n = edges.length; + + const dfs = (node) => { + const dist = Array(n).fill(-1); + dist[node] = 0; + while (edges[node] !== -1 && dist[edges[node]] === -1) { + const nei = edges[node]; + dist[nei] = dist[node] + 1; + node = nei; + } + return dist; + }; + + const node1Dist = dfs(node1); + const node2Dist = dfs(node2); + + let res = -1, + resDist = Infinity; + for (let i = 0; i < n; i++) { + if (Math.min(node1Dist[i], node2Dist[i]) !== -1) { + const dist = Math.max(node1Dist[i], node2Dist[i]); + if (dist < resDist) { + resDist = dist; + res = i; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/find-common-characters.md b/articles/find-common-characters.md new file mode 100644 index 000000000..1408e1712 --- /dev/null +++ b/articles/find-common-characters.md @@ -0,0 +1,122 @@ +## 1. Frequency Count + +::tabs-start + +```python +class Solution: + def commonChars(self, words: List[str]) -> List[str]: + cnt = Counter(words[0]) + + for w in words: + cur_cnt = Counter(w) + for c in cnt: + cnt[c] = min(cnt[c], cur_cnt[c]) + + res = [] + for c in cnt: + for i in range(cnt[c]): + res.append(c) + + return res +``` + +```java +public class Solution { + public List commonChars(String[] words) { + int[] cnt = new int[26]; + Arrays.fill(cnt, Integer.MAX_VALUE); + + for (String word : words) { + int[] curCnt = new int[26]; + for (char c : word.toCharArray()) { + curCnt[c - 'a']++; + } + + for (int i = 0; i < 26; i++) { + cnt[i] = Math.min(cnt[i], curCnt[i]); + } + } + + List res = new ArrayList<>(); + for (int i = 0; i < 26; i++) { + for (int j = 0; j < cnt[i]; j++) { + res.add(String.valueOf((char) (i + 'a'))); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector commonChars(vector& words) { + vector cnt(26, INT_MAX); + + for (string& word : words) { + vector curCnt(26, 0); + for (char c : word) { + curCnt[c - 'a']++; + } + + for (int i = 0; i < 26; i++) { + cnt[i] = min(cnt[i], curCnt[i]); + } + } + + vector res; + for (int i = 0; i < 26; i++) { + for (int j = 0; j < cnt[i]; j++) { + res.push_back(string(1, i + 'a')); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + commonChars(words) { + const cnt = new Array(26).fill(Infinity); + + for (let word of words) { + const curCnt = new Array(26).fill(0); + for (let c of word) { + curCnt[c.charCodeAt(0) - 97]++; + } + + for (let i = 0; i < 26; i++) { + cnt[i] = Math.min(cnt[i], curCnt[i]); + } + } + + const res = []; + for (let i = 0; i < 26; i++) { + for (let j = 0; j < cnt[i]; j++) { + res.push(String.fromCharCode(i + 97)); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m)$ +- Space complexity: + - $O(1)$ extra space, since we have at most $26$ different characters. + - $O(n * m)$ space for the output list. + +> Where $n$ is the number of words and $m$ is the length of the longest word. diff --git a/articles/find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree.md b/articles/find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree.md index b20fb8a09..e113e35cf 100644 --- a/articles/find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree.md +++ b/articles/find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree.md @@ -263,7 +263,8 @@ class UnionFind { * @return {boolean} */ union(v1, v2) { - const p1 = this.find(v1), p2 = this.find(v2); + const p1 = this.find(v1), + p2 = this.find(v2); if (p1 === p2) return false; if (this.rank[p1] > this.rank[p2]) { this.par[p2] = p1; @@ -306,7 +307,10 @@ class Solution { weightWithout += w; } } - if (Math.max(...ufWithout.rank) !== n || weightWithout > mstWeight) { + if ( + Math.max(...ufWithout.rank) !== n || + weightWithout > mstWeight + ) { critical.push(i); continue; } @@ -330,12 +334,105 @@ class Solution { } ``` +```csharp +public class UnionFind { + private int[] parent, rank; + + public UnionFind(int n) { + parent = new int[n]; + rank = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + rank[i] = 1; + } + } + + public int Find(int x) { + if (parent[x] != x) { + parent[x] = Find(parent[x]); + } + return parent[x]; + } + + public bool Union(int x, int y) { + int px = Find(x), py = Find(y); + if (px == py) return false; + + if (rank[px] > rank[py]) { + parent[py] = px; + rank[px] += rank[py]; + } else { + parent[px] = py; + rank[py] += rank[px]; + } + + return true; + } + + public int[] GetRanks() { + return rank; + } +} + +public class Solution { + public List> FindCriticalAndPseudoCriticalEdges(int n, int[][] edges) { + var edgeList = new List(); + for (int i = 0; i < edges.Length; i++) { + edgeList.Add(new int[] { edges[i][0], edges[i][1], edges[i][2], i }); + } + + edgeList.Sort((a, b) => a[2].CompareTo(b[2])); + + int mstWeight = 0; + var uf = new UnionFind(n); + foreach (var edge in edgeList) { + if (uf.Union(edge[0], edge[1])) { + mstWeight += edge[2]; + } + } + + var critical = new List(); + var pseudo = new List(); + + foreach (var edge in edgeList) { + var ufWithout = new UnionFind(n); + int weight = 0; + foreach (var other in edgeList) { + if (other[3] != edge[3] && ufWithout.Union(other[0], other[1])) { + weight += other[2]; + } + } + + if (ufWithout.GetRanks().Max() != n || weight > mstWeight) { + critical.Add(edge[3]); + continue; + } + + var ufWith = new UnionFind(n); + ufWith.Union(edge[0], edge[1]); + weight = edge[2]; + foreach (var other in edgeList) { + if (other[3] != edge[3] && ufWith.Union(other[0], other[1])) { + weight += other[2]; + } + } + + if (weight == mstWeight) { + pseudo.Add(edge[3]); + } + } + + return new List> { critical, pseudo }; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(E ^ 2)$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(E ^ 2)$ +- Space complexity: $O(V + E)$ > Where $V$ is the number of vertices and $E$ is the number of edges. @@ -368,7 +465,7 @@ class UnionFind: self.Size[pu] += self.Size[pv] self.Parent[pv] = pu return True - + def isConnected(self): return self.n == 1 @@ -384,14 +481,14 @@ class Solution: if include: wgt += edges[index][2] uf.union(edges[index][0], edges[index][1]) - + for i, e in enumerate(edges): if i == index: continue if uf.union(e[0], e[1]): wgt += e[2] return wgt if uf.isConnected() else float("inf") - + mst_wgt = findMST(-1, False) critical, pseudo = [], [] for i, e in enumerate(edges): @@ -399,7 +496,7 @@ class Solution: critical.append(e[3]) elif mst_wgt == findMST(i, True): pseudo.append(e[3]) - + return [critical, pseudo] ``` @@ -663,12 +760,100 @@ class Solution { } ``` +```csharp +public class UnionFind { + private int count; + private int[] parent, size; + + public UnionFind(int n) { + count = n; + parent = new int[n]; + size = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + size[i] = 1; + } + } + + public int Find(int node) { + if (parent[node] != node) { + parent[node] = Find(parent[node]); + } + return parent[node]; + } + + public bool Union(int u, int v) { + int pu = Find(u), pv = Find(v); + if (pu == pv) return false; + count--; + if (size[pu] < size[pv]) { + int temp = pu; + pu = pv; + pv = temp; + } + size[pu] += size[pv]; + parent[pv] = pu; + return true; + } + + public bool IsConnected() { + return count == 1; + } +} + +public class Solution { + public List> FindCriticalAndPseudoCriticalEdges(int n, int[][] edges) { + var indexedEdges = new List(); + for (int i = 0; i < edges.Length; i++) { + var edge = new int[] { edges[i][0], edges[i][1], edges[i][2], i }; + indexedEdges.Add(edge); + } + + indexedEdges.Sort((a, b) => a[2].CompareTo(b[2])); + int[][] sortedEdges = indexedEdges.ToArray(); + + int mstWeight = FindMST(n, sortedEdges, -1, false); + var critical = new List(); + var pseudo = new List(); + + for (int i = 0; i < sortedEdges.Length; i++) { + if (FindMST(n, sortedEdges, i, false) > mstWeight) { + critical.Add(sortedEdges[i][3]); + } else if (FindMST(n, sortedEdges, i, true) == mstWeight) { + pseudo.Add(sortedEdges[i][3]); + } + } + + return new List> { critical, pseudo }; + } + + private int FindMST(int n, int[][] edges, int skipIndex, bool includeEdge) { + var uf = new UnionFind(n); + int weight = 0; + + if (includeEdge) { + weight += edges[skipIndex][2]; + uf.Union(edges[skipIndex][0], edges[skipIndex][1]); + } + + for (int i = 0; i < edges.Length; i++) { + if (i == skipIndex) continue; + if (uf.Union(edges[i][0], edges[i][1])) { + weight += edges[i][2]; + } + } + + return uf.IsConnected() ? weight : int.MaxValue; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(E ^ 2)$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(E ^ 2)$ +- Space complexity: $O(V + E)$ > Where $V$ is the number of vertices and $E$ is the number of edges. @@ -856,7 +1041,7 @@ class Solution { const dist = Array(n).fill(Infinity); dist[src] = 0; - const pq = new MinPriorityQueue({ compare: (a, b) => a[0] - b[0] }); + const pq = new PriorityQueue((a, b) => a[0] - b[0]); pq.enqueue([0, src]); while (!pq.isEmpty()) { @@ -891,12 +1076,74 @@ class Solution { } ``` +```csharp +public class Solution { + private List[] adj; + + public List> FindCriticalAndPseudoCriticalEdges(int n, int[][] edges) { + for (int i = 0; i < edges.Length; i++) { + Array.Resize(ref edges[i], edges[i].Length + 1); + edges[i][3] = i; + } + + adj = new List[n]; + for (int i = 0; i < n; i++) { + adj[i] = new List(); + } + foreach (var edge in edges) { + adj[edge[0]].Add(new int[] { edge[1], edge[2], edge[3] }); + adj[edge[1]].Add(new int[] { edge[0], edge[2], edge[3] }); + } + + var critical = new List(); + var pseudo = new List(); + + foreach (var edge in edges) { + int u = edge[0], v = edge[1], w = edge[2], idx = edge[3]; + if (w < Minimax(n, u, v, idx)) { + critical.Add(idx); + } else if (w == Minimax(n, u, v, -1)) { + pseudo.Add(idx); + } + } + + return new List> { critical, pseudo }; + } + + private int Minimax(int n, int src, int dst, int excludeIdx) { + int[] dist = new int[n]; + Array.Fill(dist, int.MaxValue); + dist[src] = 0; + + var pq = new PriorityQueue<(int weight, int node), int>(); + pq.Enqueue((0, src), 0); + + while (pq.Count > 0) { + var (maxW, u) = pq.Dequeue(); + if (u == dst) return maxW; + + foreach (var neighbor in adj[u]) { + int v = neighbor[0], weight = neighbor[1], edgeIdx = neighbor[2]; + if (edgeIdx == excludeIdx) continue; + int newW = Math.Max(maxW, weight); + if (newW < dist[v]) { + dist[v] = newW; + pq.Enqueue((newW, v), newW); + } + } + } + + return int.MaxValue; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(E ^ 2 \log V)$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(E ^ 2 \log V)$ +- Space complexity: $O(V + E)$ > Where $V$ is the number of vertices and $E$ is the number of edges. @@ -911,12 +1158,12 @@ class UnionFind: def __init__(self, n): self.Parent = list(range(n + 1)) self.Size = [1] * (n + 1) - + def find(self, node): if self.Parent[node] != node: self.Parent[node] = self.find(self.Parent[node]) return self.Parent[node] - + def union(self, u, v): pu = self.find(u) pv = self.find(v) @@ -932,17 +1179,17 @@ class Solution: def findCriticalAndPseudoCriticalEdges(self, n: int, edges: List[List[int]]) -> List[List[int]]: mst = [[] for _ in range(n)] mstEdge = [] - + edge_list = [(w, u, v, i) for i, (u, v, w) in enumerate(edges)] edge_list.sort() - + uf = UnionFind(n) for w, u, v, i in edge_list: if uf.union(u, v): mst[u].append((v, i)) mst[v].append((u, i)) mstEdge.append(i) - + def dfs(node): for next, ind in mst[node]: if path and ind == path[-1]: @@ -952,7 +1199,7 @@ class Solution: return True path.pop() return False - + pseudo, mstEdge = set(), set(mstEdge) for ind in range(len(edges)): if ind in mstEdge: @@ -963,7 +1210,7 @@ class Solution: if edges[i][2] == edges[ind][2]: pseudo.add(i) pseudo.add(ind) - + return [list(mstEdge - pseudo), list(pseudo)] ``` @@ -1223,7 +1470,9 @@ class Solution { const mst = Array.from({ length: n }, () => []); const mstEdges = new Set(); const pseudoCriticalEdges = new Set(); - const edgeList = edges.map((e, i) => [...e, i]).sort((a, b) => a[2] - b[2]); + const edgeList = edges + .map((e, i) => [...e, i]) + .sort((a, b) => a[2] - b[2]); const uf = new UnionFind(n); @@ -1264,7 +1513,9 @@ class Solution { } } - const critical = [...mstEdges].filter(edgeIdx => !pseudoCriticalEdges.has(edgeIdx)); + const critical = [...mstEdges].filter( + (edgeIdx) => !pseudoCriticalEdges.has(edgeIdx), + ); const pseudo = [...pseudoCriticalEdges]; return [critical, pseudo]; @@ -1272,11 +1523,117 @@ class Solution { } ``` +```csharp +public class UnionFind { + private int[] parent; + private int[] size; + + public UnionFind(int n) { + parent = new int[n]; + size = new int[n]; + for (int i = 0; i < n; i++) { + parent[i] = i; + size[i] = 1; + } + } + + public int Find(int node) { + if (parent[node] != node) { + parent[node] = Find(parent[node]); + } + return parent[node]; + } + + public bool Union(int u, int v) { + int pu = Find(u); + int pv = Find(v); + if (pu == pv) return false; + if (size[pu] < size[pv]) { + int temp = pu; + pu = pv; + pv = temp; + } + size[pu] += size[pv]; + parent[pv] = pu; + return true; + } +} + +public class Solution { + private List> mst; + private HashSet mstEdges; + private HashSet pseudoCriticalEdges; + private int destination; + private List path; + + public List> FindCriticalAndPseudoCriticalEdges(int n, int[][] edges) { + mst = new List>(); + mstEdges = new HashSet(); + pseudoCriticalEdges = new HashSet(); + + for (int i = 0; i < n; i++) { + mst.Add(new List()); + } + + var edgeList = new List(); + for (int i = 0; i < edges.Length; i++) { + edgeList.Add(new int[] { edges[i][2], edges[i][0], edges[i][1], i }); + } + edgeList.Sort((a, b) => a[0].CompareTo(b[0])); + + UnionFind uf = new UnionFind(n); + foreach (var edge in edgeList) { + int weight = edge[0], u = edge[1], v = edge[2], index = edge[3]; + if (uf.Union(u, v)) { + mst[u].Add(index); + mst[v].Add(index); + mstEdges.Add(index); + } + } + + for (int i = 0; i < edges.Length; i++) { + if (mstEdges.Contains(i)) continue; + path = new List(); + destination = edges[i][1]; + if (DFS(edges[i][0], -1, edges)) { + foreach (int p in path) { + if (edges[p][2] == edges[i][2]) { + pseudoCriticalEdges.Add(i); + pseudoCriticalEdges.Add(p); + } + } + } + } + + var critical = new List(); + foreach (int edge in mstEdges) { + if (!pseudoCriticalEdges.Contains(edge)) { + critical.Add(edge); + } + } + + return new List>() { critical, new List(pseudoCriticalEdges) }; + } + + private bool DFS(int node, int parent, int[][] edges) { + if (node == destination) return true; + foreach (int edgeIndex in mst[node]) { + if (edgeIndex == parent) continue; + path.Add(edgeIndex); + int nextNode = edges[edgeIndex][0] == node ? edges[edgeIndex][1] : edges[edgeIndex][0]; + if (DFS(nextNode, edgeIndex, edges)) return true; + path.RemoveAt(path.Count - 1); + } + return false; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(E ^ 2)$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(E ^ 2)$ +- Space complexity: $O(V + E)$ -> Where $V$ is the number of vertices and $E$ is the number of edges. \ No newline at end of file +> Where $V$ is the number of vertices and $E$ is the number of edges. diff --git a/articles/find-duplicate-integer.md b/articles/find-duplicate-integer.md index 46542d9b6..f6a4db4e0 100644 --- a/articles/find-duplicate-integer.md +++ b/articles/find-duplicate-integer.md @@ -99,12 +99,26 @@ class Solution { } ``` +```swift +class Solution { + func findDuplicate(_ nums: [Int]) -> Int { + var nums = nums.sorted() + for i in 0.. Int { + var seen = Set() + for num in nums { + if seen.contains(num) { + return num + } + seen.insert(num) + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -333,12 +362,27 @@ class Solution { } ``` +```swift +class Solution { + func findDuplicate(_ nums: [Int]) -> Int { + var seen = [Int](repeating: 0, count: nums.count) + for num in nums { + if seen[num - 1] == 1 { + return num + } + seen[num - 1] = 1 + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -350,7 +394,7 @@ class Solution { class Solution: def findDuplicate(self, nums: List[int]) -> int: for num in nums : - idx = abs(num) - 1 + idx = abs(num) - 1 if nums[idx] < 0 : return abs(num) nums[idx] *= -1 @@ -457,12 +501,28 @@ class Solution { } ``` +```swift +class Solution { + func findDuplicate(_ nums: [Int]) -> Int { + var nums = nums + for num in nums { + let idx = abs(num) - 1 + if nums[idx] < 0 { + return abs(num) + } + nums[idx] *= -1 + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -549,7 +609,8 @@ class Solution { */ findDuplicate(nums) { let n = nums.length; - let low = 1, high = n - 1; + let low = 1, + high = n - 1; while (low < high) { let mid = Math.floor(low + (high - low) / 2); @@ -656,12 +717,33 @@ class Solution { } ``` +```swift +class Solution { + func findDuplicate(_ nums: [Int]) -> Int { + let n = nums.count + var low = 1, high = n - 1 + + while low < high { + let mid = low + (high - low) / 2 + let lessOrEqual = nums.filter { $0 <= mid }.count + + if lessOrEqual <= mid { + low = mid + 1 + } else { + high = mid + } + } + return low + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ --- @@ -680,11 +762,11 @@ class Solution: for num in nums: if num & mask: x += 1 - + for num in range(1, n): if num & mask: y += 1 - + if x > y: res |= mask return res @@ -755,7 +837,8 @@ class Solution { let n = nums.length; let res = 0; for (let b = 0; b < 32; b++) { - let x = 0, y = 0; + let x = 0, + y = 0; let mask = 1 << b; for (let num of nums) { if (num & mask) { @@ -866,12 +949,43 @@ class Solution { } ``` +```swift +class Solution { + func findDuplicate(_ nums: [Int]) -> Int { + let n = nums.count + var res = 0 + + for b in 0..<32 { + var x = 0, y = 0 + let mask = 1 << b + + for num in nums { + if num & mask != 0 { + x += 1 + } + } + + for num in 1.. y { + res |= mask + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(32 * n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(32 * n)$ +- Space complexity: $O(1)$ --- @@ -1052,9 +1166,34 @@ class Solution { } ``` +```swift +class Solution { + func findDuplicate(_ nums: [Int]) -> Int { + var slow = 0, fast = 0 + + while true { + slow = nums[slow] + fast = nums[nums[fast]] + if slow == fast { + break + } + } + + var slow2 = 0 + while true { + slow = nums[slow] + slow2 = nums[slow2] + if slow == slow2 { + return slow + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/find-duplicate-subtrees.md b/articles/find-duplicate-subtrees.md new file mode 100644 index 000000000..655ad8ce0 --- /dev/null +++ b/articles/find-duplicate-subtrees.md @@ -0,0 +1,551 @@ +## 1. Brute Force (DFS) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def findDuplicateSubtrees(self, root: Optional[TreeNode]) -> List[Optional[TreeNode]]: + def same(node1, node2): + if not node1 and not node2: + return True + if not node1 or not node2: + return False + return (node1.val == node2.val and + same(node1.left, node2.left) and + same(node1.right, node2.right)) + + subTree = [] + def dfs(root): + if not root: + return + subTree.append(root) + dfs(root.left) + dfs(root.right) + + dfs(root) + res = [] + seen = set() + + for i in range(len(subTree)): + if subTree[i] in seen: + continue + for j in range(i + 1, len(subTree)): + if subTree[j] in seen: + continue + + if same(subTree[i], subTree[j]): + if subTree[i] not in seen: + res.append(subTree[i]) + seen.add(subTree[i]) + seen.add(subTree[j]) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List findDuplicateSubtrees(TreeNode root) { + List res = new ArrayList<>(); + Set seen = new HashSet<>(); + List subTree = new ArrayList<>(); + dfs(root, subTree); + + for (int i = 0; i < subTree.size(); i++) { + if (seen.contains(subTree.get(i))) continue; + for (int j = i + 1; j < subTree.size(); j++) { + if (seen.contains(subTree.get(j))) continue; + + if (same(subTree.get(i), subTree.get(j))) { + if (!seen.contains(subTree.get(i))) { + res.add(subTree.get(i)); + seen.add(subTree.get(i)); + } + seen.add(subTree.get(j)); + } + } + } + return res; + } + + private boolean same(TreeNode node1, TreeNode node2) { + if (node1 == null && node2 == null) return true; + if (node1 == null || node2 == null) return false; + return node1.val == node2.val && + same(node1.left, node2.left) && + same(node1.right, node2.right); + } + + private void dfs(TreeNode root, List subTree) { + if (root == null) return; + subTree.add(root); + dfs(root.left, subTree); + dfs(root.right, subTree); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector findDuplicateSubtrees(TreeNode* root) { + vector res; + unordered_set seen; + vector subTree; + dfs(root, subTree); + + for (int i = 0; i < subTree.size(); i++) { + if (seen.count(subTree[i])) continue; + for (int j = i + 1; j < subTree.size(); j++) { + if (seen.count(subTree[j])) continue; + + if (same(subTree[i], subTree[j])) { + if (!seen.count(subTree[i])) { + res.push_back(subTree[i]); + seen.insert(subTree[i]); + } + seen.insert(subTree[j]); + } + } + } + return res; + } + +private: + bool same(TreeNode* node1, TreeNode* node2) { + if (!node1 && !node2) return true; + if (!node1 || !node2) return false; + return node1->val == node2->val && + same(node1->left, node2->left) && + same(node1->right, node2->right); + } + + void dfs(TreeNode* root, vector& subTree) { + if (!root) return; + subTree.push_back(root); + dfs(root->left, subTree); + dfs(root->right, subTree); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {TreeNode[]} + */ + findDuplicateSubtrees(root) { + const res = []; + const seen = new Set(); + + const subTree = []; + const dfs = (root) => { + if (!root) return; + subTree.push(root); + dfs(root.left); + dfs(root.right); + }; + dfs(root); + + const same = (node1, node2) => { + if (!node1 && !node2) return true; + if (!node1 || !node2) return false; + return ( + node1.val === node2.val && + same(node1.left, node2.left) && + same(node1.right, node2.right) + ); + }; + + for (let i = 0; i < subTree.length; i++) { + if (seen.has(subTree[i])) continue; + for (let j = i + 1; j < subTree.length; j++) { + if (seen.has(subTree[j])) continue; + + if (same(subTree[i], subTree[j])) { + if (!seen.has(subTree[i])) { + res.push(subTree[i]); + seen.add(subTree[i]); + } + seen.add(subTree[j]); + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n)$ + +--- + +## 2. DFS + Serialization + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def findDuplicateSubtrees(self, root: Optional[TreeNode]) -> List[Optional[TreeNode]]: + subtrees = defaultdict(list) + res = [] + + def dfs(node): + if not node: + return "null" + s = ",".join([str(node.val), dfs(node.left), dfs(node.right)]) + if len(subtrees[s]) == 1: + res.append(node) + subtrees[s].append(node) + return s + + dfs(root) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private Map> subtrees; + private List res; + + public List findDuplicateSubtrees(TreeNode root) { + subtrees = new HashMap<>(); + res = new ArrayList<>(); + dfs(root); + return res; + } + + private String dfs(TreeNode node) { + if (node == null) return "null"; + String s = node.val + "," + dfs(node.left) + "," + dfs(node.right); + subtrees.putIfAbsent(s, new ArrayList<>()); + if (subtrees.get(s).size() == 1) { + res.add(node); + } + subtrees.get(s).add(node); + return s; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { + unordered_map> subtrees; + vector res; + +public: + vector findDuplicateSubtrees(TreeNode* root) { + dfs(root); + return res; + } + +private: + string dfs(TreeNode* node) { + if (!node) return "null"; + string s = to_string(node->val) + "," + dfs(node->left) + "," + dfs(node->right); + if (subtrees[s].size() == 1) { + res.push_back(node); + } + subtrees[s].push_back(node); + return s; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {TreeNode[]} + */ + findDuplicateSubtrees(root) { + const subtrees = new Map(); + const res = []; + + const dfs = (node) => { + if (!node) return 'null'; + const s = `${node.val},${dfs(node.left)},${dfs(node.right)}`; + if (!subtrees.has(s)) { + subtrees.set(s, []); + } + if (subtrees.get(s).length === 1) { + res.push(node); + } + subtrees.get(s).push(node); + return s; + }; + + dfs(root); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 3. Depth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def findDuplicateSubtrees(self, root: Optional[TreeNode]) -> List[Optional[TreeNode]]: + id_map = {} + count = defaultdict(int) + res = [] + + def dfs(node): + if not node: + return -1 + cur = (dfs(node.left), node.val, dfs(node.right)) + if cur not in id_map: + id_map[cur] = len(id_map) + 1 + + curId = id_map[cur] + if count[curId] == 1: + res.append(node) + count[curId] += 1 + return curId + + dfs(root) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private Map idMap; + private Map count; + private List res; + + public List findDuplicateSubtrees(TreeNode root) { + idMap = new HashMap<>(); + count = new HashMap<>(); + res = new ArrayList<>(); + + dfs(root); + return res; + } + + private int dfs(TreeNode node) { + if (node == null) return -1; + String cur = dfs(node.left) + "," + node.val + "," + dfs(node.right); + idMap.putIfAbsent(cur, idMap.size()); + int curId = idMap.get(cur); + count.put(curId, count.getOrDefault(curId, 0) + 1); + if (count.get(curId) == 2) { + res.add(node); + } + return curId; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { + unordered_map idMap; + unordered_map count; + vector res; + +public: + vector findDuplicateSubtrees(TreeNode* root) { + dfs(root); + return res; + } + +private: + int dfs(TreeNode* node) { + if (!node) return -1; + string cur = to_string(dfs(node->left)) + "," + + to_string(node->val) + "," + + to_string(dfs(node->right)); + if (idMap.find(cur) == idMap.end()) { + idMap[cur] = idMap.size(); + } + int curId = idMap[cur]; + count[curId]++; + if (count[curId] == 2) { + res.push_back(node); + } + return curId; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {TreeNode[]} + */ + findDuplicateSubtrees(root) { + const idMap = new Map(); + const count = new Map(); + const res = []; + + const dfs = (node) => { + if (!node) return -1; + + const cur = `${dfs(node.left)},${node.val},${dfs(node.right)}`; + if (!idMap.has(cur)) { + idMap.set(cur, idMap.size + 1); + } + + const curId = idMap.get(cur); + count.set(curId, (count.get(curId) || 0) + 1); + if (count.get(curId) === 2) { + res.push(node); + } + + return curId; + }; + + dfs(root); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/find-eventual-safe-states.md b/articles/find-eventual-safe-states.md index df245c8a2..205c80bde 100644 --- a/articles/find-eventual-safe-states.md +++ b/articles/find-eventual-safe-states.md @@ -28,7 +28,7 @@ class Solution: ```java public class Solution { private Boolean[] safe; - + public List eventualSafeNodes(int[][] graph) { int n = graph.length; safe = new Boolean[n]; @@ -45,7 +45,7 @@ public class Solution { if (safe[node] != null) { return safe[node]; } - + safe[node] = false; for (int nei : graph[node]) { if (!dfs(graph, nei)) { @@ -131,8 +131,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(V + E)$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ > Where $V$ is the number of vertices and $E$ is the number of edges in the given graph. @@ -178,11 +178,11 @@ public class Solution { int[] outdegree = new int[n]; List[] parents = new ArrayList[n]; Queue queue = new LinkedList<>(); - + for (int i = 0; i < n; i++) { parents[i] = new ArrayList<>(); } - + for (int node = 0; node < n; node++) { outdegree[node] = graph[node].length; if (outdegree[node] == 0) { @@ -192,7 +192,7 @@ public class Solution { parents[nei].add(node); } } - + while (!queue.isEmpty()) { int node = queue.poll(); for (int parent : parents[node]) { @@ -202,7 +202,7 @@ public class Solution { } } } - + List res = new ArrayList<>(); for (int node = 0; node < n; node++) { if (outdegree[node] <= 0) { @@ -266,7 +266,7 @@ class Solution { const outdegree = Array(n).fill(0); const parents = Array.from({ length: n }, () => []); const queue = new Queue(); - + for (let node = 0; node < n; node++) { outdegree[node] = graph[node].length; if (outdegree[node] === 0) { @@ -276,7 +276,7 @@ class Solution { parents[nei].push(node); } } - + while (!queue.isEmpty()) { const node = queue.pop(); for (let parent of parents[node]) { @@ -286,7 +286,7 @@ class Solution { } } } - + const res = []; for (let node = 0; node < n; node++) { if (outdegree[node] <= 0) { @@ -302,7 +302,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(V + E)$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ -> Where $V$ is the number of vertices and $E$ is the number of edges in the given graph. \ No newline at end of file +> Where $V$ is the number of vertices and $E$ is the number of edges in the given graph. diff --git a/articles/find-first-and-last-position-of-element-in-sorted-array.md b/articles/find-first-and-last-position-of-element-in-sorted-array.md new file mode 100644 index 000000000..c4477cc63 --- /dev/null +++ b/articles/find-first-and-last-position-of-element-in-sorted-array.md @@ -0,0 +1,553 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def searchRange(self, nums: List[int], target: int) -> List[int]: + res = [-1, -1] + + for i, num in enumerate(nums): + if num == target: + if res[0] == -1: + res[0] = res[1] = i + else: + res[1] = i + + return res +``` + +```java +public class Solution { + public int[] searchRange(int[] nums, int target) { + int[] res = {-1, -1}; + + for (int i = 0; i < nums.length; i++) { + if (nums[i] == target) { + if (res[0] == -1) { + res[0] = res[1] = i; + } else { + res[1] = i; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector searchRange(vector& nums, int target) { + vector res = {-1, -1}; + + for (int i = 0; i < nums.size(); i++) { + if (nums[i] == target) { + if (res[0] == -1) { + res[0] = res[1] = i; + } else { + res[1] = i; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ + searchRange(nums, target) { + let res = [-1, -1]; + + for (let i = 0; i < nums.length; i++) { + if (nums[i] === target) { + if (res[0] === -1) { + res[0] = res[1] = i; + } else { + res[1] = i; + } + } + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int[] SearchRange(int[] nums, int target) { + int[] res = new int[] { -1, -1 }; + for (int i = 0; i < nums.Length; i++) { + if (nums[i] == target) { + if (res[0] == -1) { + res[0] = i; + res[1] = i; + } else { + res[1] = i; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 2. Binary Search - I + +::tabs-start + +```python +class Solution: + def searchRange(self, nums: List[int], target: int) -> List[int]: + left = self.binarySearch(nums, target, True) + right = self.binarySearch(nums, target, False) + return [left, right] + + def binarySearch(self, nums, target, leftBias): + l, r = 0, len(nums) - 1 + i = -1 + while l <= r: + m = (l + r) // 2 + if target > nums[m]: + l = m + 1 + elif target < nums[m]: + r = m - 1 + else: + i = m + if leftBias: + r = m - 1 + else: + l = m + 1 + return i +``` + +```java +public class Solution { + public int[] searchRange(int[] nums, int target) { + int left = binarySearch(nums, target, true); + int right = binarySearch(nums, target, false); + return new int[]{left, right}; + } + + private int binarySearch(int[] nums, int target, boolean leftBias) { + int l = 0, r = nums.length - 1, i = -1; + while (l <= r) { + int m = (l + r) / 2; + if (target > nums[m]) { + l = m + 1; + } else if (target < nums[m]) { + r = m - 1; + } else { + i = m; + if (leftBias) { + r = m - 1; + } else { + l = m + 1; + } + } + } + return i; + } +} +``` + +```cpp +class Solution { +public: + vector searchRange(vector& nums, int target) { + int left = binarySearch(nums, target, true); + int right = binarySearch(nums, target, false); + return {left, right}; + } + +private: + int binarySearch(vector& nums, int target, bool leftBias) { + int l = 0, r = nums.size() - 1, i = -1; + while (l <= r) { + int m = (l + r) / 2; + if (target > nums[m]) { + l = m + 1; + } else if (target < nums[m]) { + r = m - 1; + } else { + i = m; + if (leftBias) { + r = m - 1; + } else { + l = m + 1; + } + } + } + return i; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ + searchRange(nums, target) { + let left = this.binarySearch(nums, target, true); + let right = this.binarySearch(nums, target, false); + return [left, right]; + } + + /** + * @param {number[]} nums + * @param {number} target + * @param {boolean} leftBias + * @return {number} + */ + binarySearch(nums, target, leftBias) { + let l = 0, + r = nums.length - 1, + i = -1; + while (l <= r) { + let m = Math.floor((l + r) / 2); + if (target > nums[m]) { + l = m + 1; + } else if (target < nums[m]) { + r = m - 1; + } else { + i = m; + if (leftBias) { + r = m - 1; + } else { + l = m + 1; + } + } + } + return i; + } +} +``` + +```csharp +public class Solution { + public int[] SearchRange(int[] nums, int target) { + int left = BinarySearch(nums, target, true); + int right = BinarySearch(nums, target, false); + return new int[] { left, right }; + } + + private int BinarySearch(int[] nums, int target, bool leftBias) { + int l = 0, r = nums.Length - 1, i = -1; + while (l <= r) { + int m = l + (r - l) / 2; + if (target > nums[m]) { + l = m + 1; + } else if (target < nums[m]) { + r = m - 1; + } else { + i = m; + if (leftBias) { + r = m - 1; + } else { + l = m + 1; + } + } + } + return i; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ + +--- + +## 3. Binary Search - II + +::tabs-start + +```python +class Solution: + def searchRange(self, nums: List[int], target: int) -> List[int]: + n = len(nums) + + def binarySearch(target): + l, r = 0, n + while l < r: + m = l + (r - l) // 2 + if nums[m] >= target: + r = m + else: + l = m + 1 + return l + + start = binarySearch(target) + if start == n or nums[start] != target: + return [-1, -1] + + return [start, binarySearch(target + 1) - 1] +``` + +```java +public class Solution { + public int[] searchRange(int[] nums, int target) { + int n = nums.length; + + int start = binarySearch(nums, target, n); + if (start == n || nums[start] != target) { + return new int[]{-1, -1}; + } + + return new int[]{start, binarySearch(nums, target + 1, n) - 1}; + } + + private int binarySearch(int[] nums, int target, int n) { + int l = 0, r = n; + while (l < r) { + int m = l + (r - l) / 2; + if (nums[m] >= target) { + r = m; + } else { + l = m + 1; + } + } + return l; + } +} +``` + +```cpp +class Solution { +public: + vector searchRange(vector& nums, int target) { + int n = nums.size(); + + int start = binarySearch(nums, target, n); + if (start == n || nums[start] != target) { + return {-1, -1}; + } + + return {start, binarySearch(nums, target + 1, n) - 1}; + } + +private: + int binarySearch(vector& nums, int target, int n) { + int l = 0, r = n; + while (l < r) { + int m = l + (r - l) / 2; + if (nums[m] >= target) { + r = m; + } else { + l = m + 1; + } + } + return l; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ + searchRange(nums, target) { + const n = nums.length; + + const binarySearch = (target) => { + let l = 0, + r = n; + while (l < r) { + let m = Math.floor(l + (r - l) / 2); + if (nums[m] >= target) { + r = m; + } else { + l = m + 1; + } + } + return l; + }; + + let start = binarySearch(target); + if (start === n || nums[start] !== target) { + return [-1, -1]; + } + + return [start, binarySearch(target + 1) - 1]; + } +} +``` + +```csharp +public class Solution { + public int[] SearchRange(int[] nums, int target) { + int n = nums.Length; + + int BinarySearch(int t) { + int l = 0, r = n; + while (l < r) { + int m = l + (r - l) / 2; + if (nums[m] >= t) { + r = m; + } else { + l = m + 1; + } + } + return l; + } + + int start = BinarySearch(target); + if (start == n || nums[start] != target) { + return new int[] { -1, -1 }; + } + + int end = BinarySearch(target + 1) - 1; + return new int[] { start, end }; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ + +--- + +## 4. In-Built Function + +::tabs-start + +```python +class Solution: + def searchRange(self, nums: List[int], target: int) -> List[int]: + left = bisect.bisect_left(nums, target) + if left >= len(nums) or nums[left] != target: + return [-1, -1] + + right = bisect.bisect_right(nums, target) - 1 + return [left, right] +``` + +```java +public class Solution { + public int[] searchRange(int[] nums, int target) { + int left = findLeft(nums, target); + if (left == -1) { + return new int[]{-1, -1}; + } + + int right = findRight(nums, target); + return new int[]{left, right}; + } + + private int findLeft(int[] nums, int target) { + // O(n) time in worst case + int index = Arrays.binarySearch(nums, target); + if (index < 0) return -1; + + while (index > 0 && nums[index - 1] == target) { + index--; + } + return index; + } + + private int findRight(int[] nums, int target) { + // O(n) time in worst case + int index = Arrays.binarySearch(nums, target); + if (index < 0) return -1; + + while (index < nums.length - 1 && nums[index + 1] == target) { + index++; + } + return index; + } +} +``` + +```cpp +class Solution { +public: + vector searchRange(vector& nums, int target) { + int left = lower_bound(nums.begin(), nums.end(), target) - nums.begin(); + if (left == nums.size() || nums[left] != target) { + return {-1, -1}; + } + + int right = upper_bound(nums.begin(), nums.end(), target) - nums.begin() - 1; + return {left, right}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} target + * @return {number[]} + */ + searchRange(nums, target) { + let left = nums.indexOf(target); + let right = nums.lastIndexOf(target); + + return left === -1 ? [-1, -1] : [left, right]; + } +} +``` + +```csharp +public class Solution { + public int[] SearchRange(int[] nums, int target) { + int idx = Array.BinarySearch(nums, target); + if (idx < 0) { + return new int[] { -1, -1 }; + } + + int first = idx; + while (first > 0 && nums[first - 1] == target) { + first--; + } + + int last = idx; + while (last < nums.Length - 1 && nums[last + 1] == target) { + last++; + } + + return new int[] { first, last }; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/find-first-palindromic-string-in-the-array.md b/articles/find-first-palindromic-string-in-the-array.md index 03dd3683d..b0f3995ea 100644 --- a/articles/find-first-palindromic-string-in-the-array.md +++ b/articles/find-first-palindromic-string-in-the-array.md @@ -52,7 +52,7 @@ class Solution { return w; } } - return ""; + return ''; } } ``` @@ -61,8 +61,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(m)$ > Where $n$ is the size of the string array $words$ and $m$ is the average length of a word in the array. @@ -125,14 +125,15 @@ class Solution { */ firstPalindrome(words) { for (let w of words) { - let l = 0, r = w.length - 1; + let l = 0, + r = w.length - 1; while (w.charAt(l) === w.charAt(r)) { if (l >= r) return w; l++; r--; } } - return ""; + return ''; } } ``` @@ -141,7 +142,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n * m)$ +- Space complexity: $O(1)$ extra space. -> Where $n$ is the size of the string array $words$ and $m$ is the average length of a word in the array. \ No newline at end of file +> Where $n$ is the size of the string array $words$ and $m$ is the average length of a word in the array. diff --git a/articles/find-in-mountain-array.md b/articles/find-in-mountain-array.md index f687ba271..9a12f1c93 100644 --- a/articles/find-in-mountain-array.md +++ b/articles/find-in-mountain-array.md @@ -18,7 +18,7 @@ class Solution: for i in range(n): if mountainArr.get(i) == target: return i - + return -1 ``` @@ -31,7 +31,7 @@ class Solution: * public int length() {} * } */ - + public class Solution { public int findInMountainArray(int target, MountainArray mountainArr) { int n = mountainArr.length(); @@ -41,7 +41,7 @@ public class Solution { return i; } } - + return -1; } } @@ -68,7 +68,7 @@ public: return i; } } - + return -1; } }; @@ -78,18 +78,18 @@ public: /** * // This is the MountainArray's API interface. * // You should not implement it, or speculate about its implementation - * function MountainArray() { + * class MountainArray { * @param {number} index * @return {number} - * this.get = function(index) { + * get(index) { * ... - * }; + * } * * @return {number} - * this.length = function() { + * length() { * ... - * }; - * }; + * } + * } */ class Solution { @@ -106,7 +106,32 @@ class Solution { return i; } } - + + return -1; + } +} +``` + +```csharp +/** + * // This is MountainArray's API interface. + * // You should not implement it, or speculate about its implementation + * class MountainArray { + * public int Get(int index) {} + * public int Length() {} + * } + */ + +class Solution { + public int FindInMountainArray(int target, MountainArray mountainArr) { + int n = mountainArr.Length(); + + for (int i = 0; i < n; i++) { + if (mountainArr.Get(i) == target) { + return i; + } + } + return -1; } } @@ -116,8 +141,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -174,7 +199,7 @@ class Solution: r = m - 1 else: return m - + return -1 ``` @@ -187,7 +212,7 @@ class Solution: * public int length() {} * } */ - + public class Solution { public int findInMountainArray(int target, MountainArray mountainArr) { int length = mountainArr.length(); @@ -316,18 +341,18 @@ public: /** * // This is the MountainArray's API interface. * // You should not implement it, or speculate about its implementation - * function MountainArray() { + * class MountainArray { * @param {number} index * @return {number} - * this.get = function(index) { + * get(index) { * ... - * }; + * } * * @return {number} - * this.length = function() { + * length() { * ... - * }; - * }; + * } + * } */ class Solution { @@ -340,7 +365,9 @@ class Solution { const length = mountainArr.length(); // Find Peak - let l = 1, r = length - 2, peak = 0; + let l = 1, + r = length - 2, + peak = 0; while (l <= r) { const m = Math.floor((l + r) / 2); const left = mountainArr.get(m - 1); @@ -391,12 +418,78 @@ class Solution { } ``` +```csharp +/** + * // This is MountainArray's API interface. + * // You should not implement it, or speculate about its implementation + * class MountainArray { + * public int Get(int index) {} + * public int Length() {} + * } + */ + +class Solution { + public int FindInMountainArray(int target, MountainArray mountainArr) { + int length = mountainArr.Length(); + + // Find Peak + int l = 1, r = length - 2, peak = 0; + while (l <= r) { + int m = (l + r) / 2; + int left = mountainArr.Get(m - 1); + int mid = mountainArr.Get(m); + int right = mountainArr.Get(m + 1); + if (left < mid && mid < right) { + l = m + 1; + } else if (left > mid && mid > right) { + r = m - 1; + } else { + peak = m; + break; + } + } + + // Search left portion + l = 0; + r = peak - 1; + while (l <= r) { + int m = (l + r) / 2; + int val = mountainArr.Get(m); + if (val < target) { + l = m + 1; + } else if (val > target) { + r = m - 1; + } else { + return m; + } + } + + // Search right portion + l = peak; + r = length - 1; + while (l <= r) { + int m = (l + r) / 2; + int val = mountainArr.Get(m); + if (val > target) { + l = m + 1; + } else if (val < target) { + r = m - 1; + } else { + return m; + } + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ --- @@ -466,7 +559,7 @@ class Solution: * public int length() {} * } */ - + public class Solution { private Map cache = new HashMap<>(); @@ -600,18 +693,18 @@ public: /** * // This is the MountainArray's API interface. * // You should not implement it, or speculate about its implementation - * function MountainArray() { + * class MountainArray { * @param {number} index * @return {number} - * this.get = function(index) { + * get(index) { * ... - * }; + * } * * @return {number} - * this.length = function() { + * length() { * ... - * }; - * }; + * } + * } */ class Solution { @@ -636,7 +729,7 @@ class Solution { if (val === target) { return m; } - if (ascending === (val < target)) { + if (ascending === val < target) { l = m + 1; } else { r = m - 1; @@ -648,7 +741,9 @@ class Solution { const length = mountainArr.length(); // Find Peak - let l = 1, r = length - 2, peak = 0; + let l = 1, + r = length - 2, + peak = 0; while (l <= r) { const m = Math.floor((l + r) / 2); const left = get(m - 1); @@ -676,9 +771,76 @@ class Solution { } ``` +```csharp +/** + * // This is MountainArray's API interface. + * // You should not implement it, or speculate about its implementation + * class MountainArray { + * public int Get(int index) {} + * public int Length() {} + * } + */ + +class Solution { + private Dictionary cache = new Dictionary(); + + private int Get(int index, MountainArray mountainArr) { + if (!cache.ContainsKey(index)) { + cache[index] = mountainArr.Get(index); + } + return cache[index]; + } + + private int BinarySearch(int l, int r, bool ascending, MountainArray mountainArr, int target) { + while (l <= r) { + int m = (l + r) >> 1; + int val = Get(m, mountainArr); + if (val == target) { + return m; + } + if ((ascending && val < target) || (!ascending && val > target)) { + l = m + 1; + } else { + r = m - 1; + } + } + return -1; + } + + public int FindInMountainArray(int target, MountainArray mountainArr) { + int length = mountainArr.Length(); + + // Find Peak + int l = 1, r = length - 2, peak = 0; + while (l <= r) { + int m = (l + r) >> 1; + int left = Get(m - 1, mountainArr); + int mid = Get(m, mountainArr); + int right = Get(m + 1, mountainArr); + + if (left < mid && mid < right) { + l = m + 1; + } else if (left > mid && mid > right) { + r = m - 1; + } else { + peak = m; + break; + } + } + + // Search left portion + int res = BinarySearch(0, peak, true, mountainArr, target); + if (res != -1) return res; + + // Search right portion + return BinarySearch(peak, length - 1, false, mountainArr, target); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(\log n)$ \ No newline at end of file +- Time complexity: $O(\log n)$ +- Space complexity: $O(\log n)$ diff --git a/articles/find-k-closest-elements.md b/articles/find-k-closest-elements.md index d4a177c89..c48874fcf 100644 --- a/articles/find-k-closest-elements.md +++ b/articles/find-k-closest-elements.md @@ -16,12 +16,12 @@ public class Solution { for (int num : arr) { list.add(num); } - + list.sort((a, b) -> { int diff = Math.abs(a - x) - Math.abs(b - x); return diff == 0 ? Integer.compare(a, b) : diff; }); - + List result = list.subList(0, k); Collections.sort(result); return result; @@ -67,10 +67,10 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n + k \log k)$ -* Space complexity: - * $O(1)$ or $O(n)$ space depending on the sorting algorithm. - * $O(k)$ space for the output array. +- Time complexity: $O(n \log n + k \log k)$ +- Space complexity: + - $O(1)$ or $O(n)$ space depending on the sorting algorithm. + - $O(k)$ space for the output array. > Where $n$ is the size of the input array and $k$ is the number of closest elements to find. @@ -198,7 +198,8 @@ class Solution { } const res = [arr[idx]]; - let l = idx - 1, r = idx + 1; + let l = idx - 1, + r = idx + 1; while (res.length < k) { if (l >= 0 && r < n) { @@ -223,10 +224,10 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + k \log k)$ -* Space complexity: - * $O(1)$ or $O(k)$ space depending on the sorting algorithm. - * $O(k)$ space for the output array. +- Time complexity: $O(n + k \log k)$ +- Space complexity: + - $O(1)$ or $O(k)$ space depending on the sorting algorithm. + - $O(k)$ space for the output array. > Where $n$ is the size of the input array and $k$ is the number of closest elements to find. @@ -245,7 +246,7 @@ class Solution: r -= 1 else: l += 1 - + return arr[l: r + 1] ``` @@ -295,7 +296,8 @@ class Solution { * @return {number[]} */ findClosestElements(arr, k, x) { - let l = 0, r = arr.length - 1; + let l = 0, + r = arr.length - 1; while (r - l >= k) { if (Math.abs(x - arr[l]) <= Math.abs(x - arr[r])) { r--; @@ -312,8 +314,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n - k)$ -* Space complexity: $O(k)$ for the output array. +- Time complexity: $O(n - k)$ +- Space complexity: $O(k)$ for the output array. > Where $n$ is the size of the input array and $k$ is the number of closest elements to find. @@ -426,7 +428,8 @@ class Solution { * @return {number[]} */ findClosestElements(arr, k, x) { - let l = 0, r = arr.length - 1; + let l = 0, + r = arr.length - 1; while (l < r) { const mid = Math.floor((l + r) / 2); if (arr[mid] < x) { @@ -459,8 +462,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(\log n + k)$ -* Space complexity: $O(k)$ for the output array. +- Time complexity: $O(\log n + k)$ +- Space complexity: $O(k)$ for the output array. > Where $n$ is the size of the input array and $k$ is the number of closest elements to find. @@ -531,7 +534,8 @@ class Solution { * @return {number[]} */ findClosestElements(arr, k, x) { - let l = 0, r = arr.length - k; + let l = 0, + r = arr.length - k; while (l < r) { const m = Math.floor((l + r) / 2); if (x - arr[m] > arr[m + k] - x) { @@ -549,7 +553,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(\log (n - k) + k)$ -* Space complexity: $O(k)$ for the output array. +- Time complexity: $O(\log (n - k) + k)$ +- Space complexity: $O(k)$ for the output array. -> Where $n$ is the size of the input array and $k$ is the number of closest elements to find. \ No newline at end of file +> Where $n$ is the size of the input array and $k$ is the number of closest elements to find. diff --git a/articles/find-largest-value-in-each-tree-row.md b/articles/find-largest-value-in-each-tree-row.md new file mode 100644 index 000000000..0624297ef --- /dev/null +++ b/articles/find-largest-value-in-each-tree-row.md @@ -0,0 +1,462 @@ +## 1. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def largestValues(self, root: Optional[TreeNode]) -> List[int]: + if not root: + return [] + + res = [] + q = deque([root]) + while q: + row_max = q[0].val + for _ in range(len(q)): + node = q.popleft() + row_max = max(row_max, node.val) + if node.left: + q.append(node.left) + if node.right: + q.append(node.right) + res.append(row_max) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List largestValues(TreeNode root) { + if (root == null) return new ArrayList<>(); + + List res = new ArrayList<>(); + Queue q = new LinkedList<>(); + q.offer(root); + + while (!q.isEmpty()) { + int rowMax = q.peek().val; + for (int i = q.size(); i > 0; i--) { + TreeNode node = q.poll(); + rowMax = Math.max(rowMax, node.val); + if (node.left != null) q.offer(node.left); + if (node.right != null) q.offer(node.right); + } + res.add(rowMax); + } + + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector largestValues(TreeNode* root) { + if (!root) return {}; + + vector res; + queue q; + q.push(root); + + while (!q.empty()) { + int rowMax = q.front()->val; + for (int i = q.size(); i > 0; i--) { + TreeNode* node = q.front(); q.pop(); + rowMax = max(rowMax, node->val); + if (node->left) q.push(node->left); + if (node->right) q.push(node->right); + } + res.push_back(rowMax); + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[]} + */ + largestValues(root) { + if (!root) return []; + + const res = []; + const q = new Queue([root]); + + while (!q.isEmpty()) { + let rowMax = q.front().val; + for (let i = q.size(); i > 0; i--) { + const node = q.pop(); + rowMax = Math.max(rowMax, node.val); + if (node.left) q.push(node.left); + if (node.right) q.push(node.right); + } + res.push(rowMax); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def largestValues(self, root: Optional[TreeNode]) -> List[int]: + if not root: + return [] + + res = [] + def dfs(node, level): + if not node: + return + if level == len(res): + res.append(node.val) + else: + res[level] = max(res[level], node.val) + + dfs(node.left, level + 1) + dfs(node.right, level + 1) + + dfs(root, 0) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List largestValues(TreeNode root) { + List res = new ArrayList<>(); + dfs(root, 0, res); + return res; + } + + private void dfs(TreeNode node, int level, List res) { + if (node == null) return; + if (level == res.size()) { + res.add(node.val); + } else { + res.set(level, Math.max(res.get(level), node.val)); + } + + dfs(node.left, level + 1, res); + dfs(node.right, level + 1, res); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector largestValues(TreeNode* root) { + vector res; + dfs(root, 0, res); + return res; + } + +private: + void dfs(TreeNode* node, int level, vector& res) { + if (!node) return; + if (level == res.size()) { + res.push_back(node->val); + } else { + res[level] = max(res[level], node->val); + } + + dfs(node->left, level + 1, res); + dfs(node->right, level + 1, res); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[]} + */ + largestValues(root) { + if (!root) return []; + + const res = []; + const dfs = (node, level) => { + if (!node) return; + if (level === res.length) { + res.push(node.val); + } else { + res[level] = Math.max(res[level], node.val); + } + dfs(node.left, level + 1); + dfs(node.right, level + 1); + }; + + dfs(root, 0); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def largestValues(self, root: Optional[TreeNode]) -> List[int]: + if not root: + return [] + + res = [] + stack = [(root, 0)] + while stack: + node, level = stack.pop() + if level == len(res): + res.append(node.val) + else: + res[level] = max(res[level], node.val) + + if node.right: + stack.append((node.right, level + 1)) + if node.left: + stack.append((node.left, level + 1)) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List largestValues(TreeNode root) { + if (root == null) return new ArrayList<>(); + + List res = new ArrayList<>(); + Stack> stack = new Stack<>(); + stack.push(new Pair<>(root, 0)); + while (!stack.isEmpty()) { + Pair p = stack.pop(); + TreeNode node = p.getKey(); + int level = p.getValue(); + if (level == res.size()) { + res.add(node.val); + } else { + res.set(level, Math.max(res.get(level), node.val)); + } + + if (node.right != null) stack.push(new Pair<>(node.right, level + 1)); + if (node.left != null) stack.push(new Pair<>(node.left, level + 1)); + } + + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector largestValues(TreeNode* root) { + if (!root) return {}; + + vector res; + stack> stk; + stk.push({root, 0}); + while (!stk.empty()) { + auto [node, level] = stk.top();stk.pop(); + if (level == res.size()) { + res.push_back(node->val); + } else { + res[level] = max(res[level], node->val); + } + + if (node->right) stk.push({node->right, level + 1}); + if (node->left) stk.push({node->left, level + 1}); + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number[]} + */ + largestValues(root) { + if (!root) return []; + + const res = []; + const stack = [[root, 0]]; + while (stack.length) { + const [node, level] = stack.pop(); + if (level === res.length) { + res.push(node.val); + } else { + res[level] = Math.max(res[level], node.val); + } + + if (node.right) stack.push([node.right, level + 1]); + if (node.left) stack.push([node.left, level + 1]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/find-lucky-integer-in-an-array.md b/articles/find-lucky-integer-in-an-array.md new file mode 100644 index 000000000..02ffa2cea --- /dev/null +++ b/articles/find-lucky-integer-in-an-array.md @@ -0,0 +1,581 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def findLucky(self, arr: List[int]) -> int: + res = -1 + + for num in arr: + cnt = 0 + for a in arr: + if num == a: + cnt += 1 + if cnt == num: + res = max(res, num) + + return res +``` + +```java +public class Solution { + public int findLucky(int[] arr) { + int res = -1; + + for (int num : arr) { + int cnt = 0; + for (int a : arr) { + if (num == a) { + cnt++; + } + } + if (cnt == num) { + res = Math.max(res, num); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int findLucky(vector& arr) { + int res = -1; + + for (int num : arr) { + int cnt = 0; + for (int a : arr) { + if (num == a) { + cnt++; + } + } + if (cnt == num) { + res = max(res, num); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + findLucky(arr) { + let res = -1; + + for (let num of arr) { + let cnt = 0; + for (let a of arr) { + if (num === a) { + cnt++; + } + } + if (cnt === num) { + res = Math.max(res, num); + } + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int FindLucky(int[] arr) { + int res = -1; + + foreach (int num in arr) { + int cnt = 0; + foreach (int a in arr) { + if (num == a) { + cnt++; + } + } + if (cnt == num) { + res = Math.Max(res, num); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Sorting + +::tabs-start + +```python +class Solution: + def findLucky(self, arr: List[int]) -> int: + arr.sort() + streak = 0 + for i in range(len(arr) - 1, -1, -1): + streak += 1 + if i == 0 or (arr[i] != arr[i - 1]): + if arr[i] == streak: + return arr[i] + streak = 0 + return -1 +``` + +```java +public class Solution { + public int findLucky(int[] arr) { + Arrays.sort(arr); + int streak = 0; + + for (int i = arr.length - 1; i >= 0; i--) { + streak++; + if (i == 0 || arr[i] != arr[i - 1]) { + if (arr[i] == streak) { + return arr[i]; + } + streak = 0; + } + } + return -1; + } +} +``` + +```cpp +class Solution { +public: + int findLucky(vector& arr) { + sort(arr.begin(), arr.end()); + int streak = 0; + + for (int i = arr.size() - 1; i >= 0; i--) { + streak++; + if (i == 0 || arr[i] != arr[i - 1]) { + if (arr[i] == streak) { + return arr[i]; + } + streak = 0; + } + } + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + findLucky(arr) { + arr.sort((a, b) => a - b); + let streak = 0; + + for (let i = arr.length - 1; i >= 0; i--) { + streak++; + if (i === 0 || arr[i] !== arr[i - 1]) { + if (arr[i] === streak) { + return arr[i]; + } + streak = 0; + } + } + return -1; + } +} +``` + +```csharp +public class Solution { + public int FindLucky(int[] arr) { + Array.Sort(arr); + int streak = 0; + + for (int i = arr.Length - 1; i >= 0; i--) { + streak++; + if (i == 0 || arr[i] != arr[i - 1]) { + if (arr[i] == streak) { + return arr[i]; + } + streak = 0; + } + } + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 3. Hash Map + +::tabs-start + +```python +class Solution: + def findLucky(self, arr: List[int]) -> int: + cnt = Counter(arr) + res = -1 + + for num in cnt: + if num == cnt[num]: + res = max(num, res) + + return res +``` + +```java +public class Solution { + public int findLucky(int[] arr) { + Map count = new HashMap<>(); + for (int num : arr) { + count.put(num, count.getOrDefault(num, 0) + 1); + } + + int res = -1; + for (int num : count.keySet()) { + if (num == count.get(num)) { + res = Math.max(res, num); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int findLucky(vector& arr) { + unordered_map count; + for (int num : arr) { + count[num]++; + } + + int res = -1; + for (auto& [num, freq] : count) { + if (num == freq) { + res = max(res, num); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + findLucky(arr) { + const count = new Map(); + for (const num of arr) { + count.set(num, (count.get(num) || 0) + 1); + } + + let res = -1; + for (const [num, freq] of count.entries()) { + if (num === freq) { + res = Math.max(res, num); + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public int FindLucky(int[] arr) { + Dictionary count = new Dictionary(); + foreach (int num in arr) { + if (!count.ContainsKey(num)) { + count[num] = 0; + } + count[num]++; + } + + int res = -1; + foreach (var kvp in count) { + if (kvp.Key == kvp.Value) { + res = Math.Max(res, kvp.Key); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Negative Marking + +::tabs-start + +```python +class Solution: + def findLucky(self, arr: List[int]) -> int: + n = len(arr) + for i in range(n): + prev, num = i, arr[i] + while 0 < num <= n: + nxt = arr[num - 1] + arr[num - 1] = min(0, arr[num - 1]) - 1 + if num - 1 <= i or num - 1 == prev: + break + prev = num - 1 + num = nxt + + for i in range(n - 1, -1, -1): + if -arr[i] == i + 1: + return i + 1 + + return -1 +``` + +```java +public class Solution { + public int findLucky(int[] arr) { + int n = arr.length; + for (int i = 0; i < n; i++) { + int prev = i, num = arr[i]; + while (0 < num && num <= n) { + int nxt = arr[num - 1]; + arr[num - 1] = Math.min(0, arr[num - 1]) - 1; + if (num - 1 <= i || num - 1 == prev) break; + prev = num - 1; + num = nxt; + } + } + + for (int i = n - 1; i >= 0; i--) { + if (-arr[i] == i + 1) return i + 1; + } + return -1; + } +} +``` + +```cpp +class Solution { +public: + int findLucky(vector& arr) { + int n = arr.size(); + for (int i = 0; i < n; i++) { + int prev = i, num = arr[i]; + while (0 < num && num <= n) { + int nxt = arr[num - 1]; + arr[num - 1] = min(0, arr[num - 1]) - 1; + if (num - 1 <= i || num - 1 == prev) break; + prev = num - 1; + num = nxt; + } + } + + for (int i = n - 1; i >= 0; i--) { + if (-arr[i] == i + 1) return i + 1; + } + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + findLucky(arr) { + const n = arr.length; + for (let i = 0; i < n; i++) { + let prev = i, num = arr[i]; + while (0 < num && num <= n) { + let nxt = arr[num - 1]; + arr[num - 1] = Math.min(0, arr[num - 1]) - 1; + if (num - 1 <= i || num - 1 === prev) break; + prev = num - 1; + num = nxt; + } + } + + for (let i = n - 1; i >= 0; i--) { + if (-arr[i] === i + 1) return i + 1; + } + return -1; + } +} +``` + +```csharp +public class Solution { + public int FindLucky(int[] arr) { + int n = arr.Length; + for (int i = 0; i < n; i++) { + int prev = i, num = arr[i]; + while (0 < num && num <= n) { + int nxt = arr[num - 1]; + arr[num - 1] = Math.Min(0, arr[num - 1]) - 1; + if (num - 1 <= i || num - 1 == prev) break; + prev = num - 1; + num = nxt; + } + } + + for (int i = n - 1; i >= 0; i--) { + if (-arr[i] == i + 1) return i + 1; + } + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 5. Bit Manipulation + +::tabs-start + +```python +class Solution: + def findLucky(self, arr: List[int]) -> int: + for num in arr: + idx = num & ((1 << 10) - 1) + if idx <= len(arr): + arr[idx - 1] += (1 << 10) + + for i in range(len(arr) - 1, -1, -1): + cnt = arr[i] >> 10 + if cnt == i + 1: + return i + 1 + return -1 +``` + +```java +public class Solution { + public int findLucky(int[] arr) { + for (int num : arr) { + int idx = num & ((1 << 10) - 1); + if (idx <= arr.length) { + arr[idx - 1] += (1 << 10); + } + } + + for (int i = arr.length - 1; i >= 0; i--) { + int cnt = arr[i] >> 10; + if (cnt == i + 1) return i + 1; + } + return -1; + } +} +``` + +```cpp +class Solution { +public: + int findLucky(vector& arr) { + for (int num : arr) { + int idx = num & ((1 << 10) - 1); + if (idx <= arr.size()) { + arr[idx - 1] += (1 << 10); + } + } + + for (int i = arr.size() - 1; i >= 0; i--) { + int cnt = arr[i] >> 10; + if (cnt == i + 1) return i + 1; + } + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + findLucky(arr) { + for (let num of arr) { + const idx = num & ((1 << 10) - 1); + if (idx <= arr.length) { + arr[idx - 1] += (1 << 10); + } + } + + for (let i = arr.length - 1; i >= 0; i--) { + const cnt = arr[i] >> 10; + if (cnt === i + 1) return i + 1; + } + return -1; + } +} +``` + +```csharp +public class Solution { + public int FindLucky(int[] arr) { + foreach (int num in arr) { + int idx = num & ((1 << 10) - 1); + if (idx <= arr.Length) { + arr[idx - 1] += (1 << 10); + } + } + + for (int i = arr.Length - 1; i >= 0; i--) { + int cnt = arr[i] >> 10; + if (cnt == i + 1) return i + 1; + } + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/find-median-in-a-data-stream.md b/articles/find-median-in-a-data-stream.md index ab246b370..6d9ae64bc 100644 --- a/articles/find-median-in-a-data-stream.md +++ b/articles/find-median-in-a-data-stream.md @@ -14,7 +14,7 @@ class MedianFinder: def findMedian(self) -> float: self.data.sort() n = len(self.data) - return (self.data[n // 2] if (n & 1) else + return (self.data[n // 2] if (n & 1) else (self.data[n // 2] + self.data[n // 2 - 1]) / 2) ``` @@ -162,12 +162,36 @@ class MedianFinder() { } ``` +```swift +class MedianFinder { + private var data: [Int] + + init() { + self.data = [] + } + + func addNum(_ num: Int) { + data.append(num) + } + + func findMedian() -> Double { + data.sort() + let n = data.count + if n % 2 == 1 { + return Double(data[n / 2]) + } else { + return (Double(data[n / 2]) + Double(data[n / 2 - 1])) / 2.0 + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m)$ for $addNum()$, $O(m * n \log n)$ for $findMedian()$. -* Space complexity: $O(n)$ +- Time complexity: $O(m)$ for $addNum()$, $O(m * n \log n)$ for $findMedian()$. +- Space complexity: $O(n)$ > Where $m$ is the number of function calls and $n$ is the length of the array. @@ -182,7 +206,7 @@ class MedianFinder: def __init__(self): # two heaps, large, small, minheap, maxheap # heaps should be equal size - self.small, self.large = [], [] + self.small, self.large = [], [] def addNum(self, num: int) -> None: if self.large and num > self.large[0]: @@ -244,7 +268,7 @@ public class MedianFinder { ```cpp class MedianFinder { - priority_queue, less> smallHeap; + priority_queue, less> smallHeap; priority_queue, greater> largeHeap; public: @@ -331,7 +355,7 @@ public class MedianFinder { small = new PriorityQueue(Comparer.Create((a, b) => b.CompareTo(a))); large = new PriorityQueue(); } - + public void AddNum(int num) { if (large.Count != 0 && num > large.Peek()) { large.Enqueue(num, num); @@ -347,14 +371,14 @@ public class MedianFinder { small.Enqueue(val, val); } } - + public double FindMedian() { if (small.Count > large.Count) { return small.Peek(); } else if (large.Count > small.Count) { return large.Peek(); } - + int smallTop = small.Peek(); return (smallTop + large.Peek()) / 2.0; } @@ -388,7 +412,7 @@ func (this *MedianFinder) AddNum(num int) { } else { this.small.Enqueue(num) } - + // Rebalance if this.small.Size() > this.large.Size()+1 { val, _ := this.small.Dequeue() @@ -420,14 +444,14 @@ class MedianFinder() { // small is maxHeap, large is minHeap private val small = PriorityQueue(compareByDescending { it }) private val large = PriorityQueue() - + fun addNum(num: Int) { if (large.isNotEmpty() && num > large.peek()) { large.add(num) } else { small.add(num) } - + // Rebalance if (small.size > large.size + 1) { large.add(small.poll()) @@ -436,7 +460,7 @@ class MedianFinder() { small.add(large.poll()) } } - + fun findMedian(): Double { return when { small.size > large.size -> small.peek().toDouble() @@ -447,11 +471,52 @@ class MedianFinder() { } ``` +```swift +class MedianFinder { + // two heaps, large, small, minheap, maxheap + // heaps should be equal size + private var small: Heap + private var large: Heap + + init() { + self.small = Heap() + self.large = Heap() + } + + func addNum(_ num: Int) { + if let top = large.min, num > top { + large.insert(num) + } else { + small.insert(num) + } + if small.count > large.count + 1 { + if let val = small.popMax() { + large.insert(val) + } + } + if large.count > small.count + 1 { + if let val = large.popMin() { + small.insert(val) + } + } + } + + func findMedian() -> Double { + if small.count > large.count { + return Double(small.max!) + } else if large.count > small.count { + return Double(large.min!) + } + return (Double(small.max!) + Double(large.min!)) / 2.0 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * \log n)$ for $addNum()$, $O(m)$ for $findMedian()$. -* Space complexity: $O(n)$ +- Time complexity: $O(m * \log n)$ for $addNum()$, $O(m)$ for $findMedian()$. +- Space complexity: $O(n)$ -> Where $m$ is the number of function calls and $n$ is the length of the array. \ No newline at end of file +> Where $m$ is the number of function calls and $n$ is the length of the array. diff --git a/articles/find-minimum-in-rotated-sorted-array.md b/articles/find-minimum-in-rotated-sorted-array.md index 3c4c59be9..21dafa7eb 100644 --- a/articles/find-minimum-in-rotated-sorted-array.md +++ b/articles/find-minimum-in-rotated-sorted-array.md @@ -65,12 +65,20 @@ class Solution { } ``` +```swift +class Solution { + func findMin(_ nums: [Int]) -> Int { + return nums.min()! + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -88,7 +96,7 @@ class Solution: if nums[l] < nums[r]: res = min(res, nums[l]) break - + m = (l + r) // 2 res = min(res, nums[m]) if nums[m] >= nums[l]: @@ -141,7 +149,7 @@ public: res = min(res, nums[m]); if (nums[m] >= nums[l]) { - l = m + 1; + l = m + 1; } else { r = m - 1; } @@ -261,12 +269,38 @@ class Solution { } ``` +```swift +class Solution { + func findMin(_ nums: [Int]) -> Int { + var res = nums[0] + var l = 0, r = nums.count - 1 + + while l <= r { + if nums[l] < nums[r] { + res = min(res, nums[l]) + break + } + + let m = (l + r) / 2 + res = min(res, nums[m]) + + if nums[m] >= nums[l] { + l = m + 1 + } else { + r = m - 1 + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ --- @@ -331,7 +365,8 @@ class Solution { * @return {number} */ findMin(nums) { - let l = 0, r = nums.length - 1; + let l = 0, + r = nums.length - 1; while (l < r) { let m = l + Math.floor((r - l) / 2); if (nums[m] < nums[r]) { @@ -396,9 +431,26 @@ class Solution { } ``` +```swift +class Solution { + func findMin(_ nums: [Int]) -> Int { + var l = 0, r = nums.count - 1 + while l < r { + let m = l + (r - l) / 2 + if nums[m] < nums[r] { + r = m + } else { + l = m + 1 + } + } + return nums[l] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/find-missing-and-repeated-values.md b/articles/find-missing-and-repeated-values.md new file mode 100644 index 000000000..6ed3c9841 --- /dev/null +++ b/articles/find-missing-and-repeated-values.md @@ -0,0 +1,495 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def findMissingAndRepeatedValues(self, grid: List[List[int]]) -> List[int]: + n = len(grid) + double = missing = 0 + + for num in range(1, n * n + 1): + cnt = 0 + for i in range(n): + for j in range(n): + if num == grid[i][j]: + cnt += 1 + + if cnt == 2: + double = num + elif cnt == 0: + missing = num + + return [double, missing] +``` + +```java +public class Solution { + public int[] findMissingAndRepeatedValues(int[][] grid) { + int n = grid.length; + int doubleVal = 0, missing = 0; + + for (int num = 1; num <= n * n; num++) { + int cnt = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == num) { + cnt++; + } + } + } + + if (cnt == 2) { + doubleVal = num; + } else if (cnt == 0) { + missing = num; + } + } + + return new int[]{doubleVal, missing}; + } +} +``` + +```cpp +class Solution { +public: + vector findMissingAndRepeatedValues(vector>& grid) { + int n = grid.size(); + int doubleVal = 0, missing = 0; + + for (int num = 1; num <= n * n; num++) { + int cnt = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == num) { + cnt++; + } + } + } + + if (cnt == 2) { + doubleVal = num; + } else if (cnt == 0) { + missing = num; + } + } + + return {doubleVal, missing}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number[]} + */ + findMissingAndRepeatedValues(grid) { + const n = grid.length; + let doubleVal = 0, + missing = 0; + + for (let num = 1; num <= n * n; num++) { + let cnt = 0; + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if (grid[i][j] === num) { + cnt++; + } + } + } + + if (cnt === 2) { + doubleVal = num; + } else if (cnt === 0) { + missing = num; + } + } + + return [doubleVal, missing]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 4)$ +- Space complexity: $O(1)$ + +--- + +## 2. Hash Map + +::tabs-start + +```python +class Solution: + def findMissingAndRepeatedValues(self, grid: List[List[int]]) -> List[int]: + N = len(grid) + count = defaultdict(int) + + for i in range(N): + for j in range(N): + count[grid[i][j]] += 1 + + double = missing = 0 + + for num in range(1, N * N + 1): + if count[num] == 0: + missing = num + if count[num] == 2: + double = num + + return [double, missing] +``` + +```java +public class Solution { + public int[] findMissingAndRepeatedValues(int[][] grid) { + int N = grid.length; + Map count = new HashMap<>(); + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + count.put(grid[i][j], count.getOrDefault(grid[i][j], 0) + 1); + } + } + + int doubleVal = 0, missing = 0; + + for (int num = 1; num <= N * N; num++) { + int freq = count.getOrDefault(num, 0); + if (freq == 0) missing = num; + if (freq == 2) doubleVal = num; + } + + return new int[]{doubleVal, missing}; + } +} +``` + +```cpp +class Solution { +public: + vector findMissingAndRepeatedValues(vector>& grid) { + int N = grid.size(); + unordered_map count; + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + count[grid[i][j]]++; + } + } + + int doubleVal = 0, missing = 0; + + for (int num = 1; num <= N * N; num++) { + int freq = count[num]; + if (freq == 0) missing = num; + if (freq == 2) doubleVal = num; + } + + return {doubleVal, missing}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number[]} + */ + findMissingAndRepeatedValues(grid) { + const N = grid.length; + const count = {}; + + for (let i = 0; i < N; i++) { + for (let j = 0; j < N; j++) { + let val = grid[i][j]; + count[val] = (count[val] || 0) + 1; + } + } + + let doubleVal = 0, + missing = 0; + + for (let num = 1; num <= N * N; num++) { + let freq = count[num] || 0; + if (freq === 0) missing = num; + if (freq === 2) doubleVal = num; + } + + return [doubleVal, missing]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 3. Hash Set + +::tabs-start + +```python +class Solution: + def findMissingAndRepeatedValues(self, grid: List[List[int]]) -> List[int]: + N = len(grid) + seen = set() + double = missing = 0 + + for i in range(N): + for j in range(N): + if grid[i][j] in seen: + double = grid[i][j] + seen.add(grid[i][j]) + + for num in range(1, N * N + 1): + if num not in seen: + missing = num + break + + return [double, missing] +``` + +```java +public class Solution { + public int[] findMissingAndRepeatedValues(int[][] grid) { + int N = grid.length; + Set seen = new HashSet<>(); + int doubleVal = 0, missing = 0; + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + if (seen.contains(grid[i][j])) { + doubleVal = grid[i][j]; + } + seen.add(grid[i][j]); + } + } + + for (int num = 1; num <= N * N; num++) { + if (!seen.contains(num)) { + missing = num; + break; + } + } + + return new int[]{doubleVal, missing}; + } +} +``` + +```cpp +class Solution { +public: + vector findMissingAndRepeatedValues(vector>& grid) { + int N = grid.size(); + unordered_set seen; + int doubleVal = 0, missing = 0; + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + if (seen.count(grid[i][j])) { + doubleVal = grid[i][j]; + } + seen.insert(grid[i][j]); + } + } + + for (int num = 1; num <= N * N; num++) { + if (!seen.count(num)) { + missing = num; + break; + } + } + + return {doubleVal, missing}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number[]} + */ + findMissingAndRepeatedValues(grid) { + const N = grid.length; + const seen = new Set(); + let doubleVal = 0, + missing = 0; + + for (let i = 0; i < N; i++) { + for (let j = 0; j < N; j++) { + const val = grid[i][j]; + if (seen.has(val)) { + doubleVal = val; + } + seen.add(val); + } + } + + for (let num = 1; num <= N * N; num++) { + if (!seen.has(num)) { + missing = num; + break; + } + } + + return [doubleVal, missing]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 4. Math + +::tabs-start + +```python +class Solution: + def findMissingAndRepeatedValues(self, grid: List[List[int]]) -> List[int]: + N = len(grid) + gridSum = 0 + gridSqSum = 0 + + for i in range(N): + for j in range(N): + gridSum += grid[i][j] + gridSqSum += grid[i][j] * grid[i][j] + + totSum = (N * N * (N * N + 1)) // 2 + diff = gridSum - totSum # a - b + + totSqSum = (N * N * (N * N + 1) * (2 * N * N + 1)) // 6 + sqDiff = gridSqSum - totSqSum # (a^2) - (b^2) + + sum = sqDiff // diff # a + b + + a = (sum + diff) // 2 + b = sum - a + return [a, b] +``` + +```java +public class Solution { + public int[] findMissingAndRepeatedValues(int[][] grid) { + int N = grid.length; + long gridSum = 0; + long gridSqSum = 0; + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + gridSum += grid[i][j]; + gridSqSum += 1L * grid[i][j] * grid[i][j]; + } + } + + long totSum = (long) N * N * (N * N + 1) / 2; + long diff = gridSum - totSum; // a - b + + long totSqSum = (long) N * N * (N * N + 1) * (2L * N * N + 1) / 6; + long sqDiff = gridSqSum - totSqSum; // (a^2) - (b^2) + + long sum = sqDiff / diff; // a + b + + long a = (sum + diff) / 2; + long b = sum - a; + + return new int[]{(int) a, (int) b}; + } +} +``` + +```cpp +class Solution { +public: + vector findMissingAndRepeatedValues(vector>& grid) { + int N = grid.size(); + long long gridSum = 0; + long long gridSqSum = 0; + + for (int i = 0; i < N; i++) { + for (int j = 0; j < N; j++) { + gridSum += grid[i][j]; + gridSqSum += 1LL * grid[i][j] * grid[i][j]; + } + } + + long long totSum = 1LL * N * N * (N * N + 1) / 2; + long long diff = gridSum - totSum; // a - b + + long long totSqSum = 1LL * N * N * (N * N + 1) * (2 * N * N + 1) / 6; + long long sqDiff = gridSqSum - totSqSum; // (a^2) - (b^2) + + long long sum = sqDiff / diff; // a + b + + int a = (sum + diff) / 2; + int b = sum - a; + + return {a, b}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number[]} + */ + findMissingAndRepeatedValues(grid) { + const N = grid.length; + let gridSum = 0; + let gridSqSum = 0; + + for (let i = 0; i < N; i++) { + for (let j = 0; j < N; j++) { + gridSum += grid[i][j]; + gridSqSum += grid[i][j] * grid[i][j]; + } + } + + let totSum = (N * N * (N * N + 1)) / 2; + let diff = gridSum - totSum; // a - b + + let totSqSum = (N * N * (N * N + 1) * (2 * N * N + 1)) / 6; + let sqDiff = gridSqSum - totSqSum; // (a^2) - (b^2) + + let sum = sqDiff / diff; // a + b + + let a = (sum + diff) / 2; + let b = sum - a; + + return [a, b]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ diff --git a/articles/find-missing-observations.md b/articles/find-missing-observations.md new file mode 100644 index 000000000..4c2ccba24 --- /dev/null +++ b/articles/find-missing-observations.md @@ -0,0 +1,214 @@ +## 1. Math - I + +::tabs-start + +```python +class Solution: + def missingRolls(self, rolls: List[int], mean: int, n: int) -> List[int]: + m = len(rolls) + nTotal = (mean * (n + m)) - sum(rolls) + + if nTotal < n or nTotal > n * 6: + return [] + + res = [] + while nTotal: + dice = min(nTotal - n + 1, 6) + res.append(dice) + nTotal -= dice + n -= 1 + return res +``` + +```java +public class Solution { + public int[] missingRolls(int[] rolls, int mean, int n) { + int m = rolls.length; + int nTotal = (mean * (n + m)) - Arrays.stream(rolls).sum(); + + if (nTotal < n || nTotal > n * 6) { + return new int[0]; + } + + int[] res = new int[n]; + for (int i = 0; i < n; i++) { + int dice = Math.min(nTotal - (n - i - 1), 6); + res[i] = dice; + nTotal -= dice; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector missingRolls(vector& rolls, int mean, int n) { + int m = rolls.size(); + int nTotal = (mean * (n + m)) - accumulate(rolls.begin(), rolls.end(), 0); + + if (nTotal < n || nTotal > n * 6) { + return {}; + } + + vector res; + for (int i = 0; i < n; ++i) { + int dice = min(nTotal - (n - i - 1), 6); + res.push_back(dice); + nTotal -= dice; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} rolls + * @param {number} mean + * @param {number} n + * @return {number[]} + */ + missingRolls(rolls, mean, n) { + const m = rolls.length; + let nTotal = + mean * (n + m) - rolls.reduce((sum, roll) => sum + roll, 0); + + if (nTotal < n || nTotal > n * 6) { + return []; + } + + const res = []; + while (nTotal > 0) { + const dice = Math.min(nTotal - n + 1, 6); + res.push(dice); + nTotal -= dice; + n--; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m + n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output array. + +> Where $m$ is the size of the array $rolls$ and $n$ is the number of missing observations. + +--- + +## 2. Math - II + +::tabs-start + +```python +class Solution: + def missingRolls(self, rolls: List[int], mean: int, n: int) -> List[int]: + m = len(rolls) + nTotal = (mean * (n + m)) - sum(rolls) + + if nTotal < n or nTotal > n * 6: + return [] + + avg = nTotal // n + rem = nTotal - (avg * n) + return [avg] * (n - rem) + [avg + 1] * rem +``` + +```java +public class Solution { + public int[] missingRolls(int[] rolls, int mean, int n) { + int m = rolls.length; + int nTotal = (mean * (n + m)) - Arrays.stream(rolls).sum(); + + if (nTotal < n || nTotal > n * 6) { + return new int[0]; + } + + int avg = nTotal / n; + int rem = nTotal - (avg * n); + int[] res = new int[n]; + + for (int i = 0; i < n - rem; i++) { + res[i] = avg; + } + for (int i = n - rem; i < n; i++) { + res[i] = avg + 1; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector missingRolls(vector& rolls, int mean, int n) { + int m = rolls.size(); + int nTotal = (mean * (n + m)) - accumulate(rolls.begin(), rolls.end(), 0); + + if (nTotal < n || nTotal > n * 6) { + return {}; + } + + int avg = nTotal / n; + int rem = nTotal - (avg * n); + vector res; + + for (int i = 0; i < n - rem; ++i) { + res.push_back(avg); + } + for (int i = 0; i < rem; ++i) { + res.push_back(avg + 1); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} rolls + * @param {number} mean + * @param {number} n + * @return {number[]} + */ + missingRolls(rolls, mean, n) { + const m = rolls.length; + const nTotal = + mean * (n + m) - rolls.reduce((sum, roll) => sum + roll, 0); + + if (nTotal < n || nTotal > n * 6) { + return []; + } + + const avg = Math.floor(nTotal / n); + const rem = nTotal - avg * n; + return Array(n - rem) + .fill(avg) + .concat(Array(rem).fill(avg + 1)); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m + n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output array. + +> Where $m$ is the size of the array $rolls$ and $n$ is the number of missing observations. diff --git a/articles/find-peak-element.md b/articles/find-peak-element.md new file mode 100644 index 000000000..4ab856d0b --- /dev/null +++ b/articles/find-peak-element.md @@ -0,0 +1,411 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def findPeakElement(self, nums: List[int]) -> int: + for i in range(len(nums) - 1): + if nums[i] > nums[i + 1]: + return i + + return len(nums) - 1 +``` + +```java +public class Solution { + public int findPeakElement(int[] nums) { + for (int i = 0; i < nums.length - 1; i++) { + if (nums[i] > nums[i + 1]) { + return i; + } + } + return nums.length - 1; + } +} +``` + +```cpp +class Solution { +public: + int findPeakElement(vector& nums) { + for (int i = 0; i < nums.size() - 1; i++) { + if (nums[i] > nums[i + 1]) { + return i; + } + } + return nums.size() - 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findPeakElement(nums) { + for (let i = 0; i < nums.length - 1; i++) { + if (nums[i] > nums[i + 1]) { + return i; + } + } + return nums.length - 1; + } +} +``` + +```csharp +public class Solution { + public int FindPeakElement(int[] nums) { + for (int i = 0; i < nums.Length - 1; i++) { + if (nums[i] > nums[i + 1]) { + return i; + } + } + return nums.Length - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 2. Binary Search + +::tabs-start + +```python +class Solution: + def findPeakElement(self, nums: List[int]) -> int: + l, r = 0, len(nums) - 1 + + while l <= r: + m = l + (r - l) // 2 + if m > 0 and nums[m] < nums[m - 1]: + r = m - 1 + elif m < len(nums) - 1 and nums[m] < nums[m + 1]: + l = m + 1 + else: + return m +``` + +```java +public class Solution { + public int findPeakElement(int[] nums) { + int l = 0, r = nums.length - 1; + + while (l <= r) { + int m = l + (r - l) / 2; + if (m > 0 && nums[m] < nums[m - 1]) { + r = m - 1; + } else if (m < nums.length - 1 && nums[m] < nums[m + 1]) { + l = m + 1; + } else { + return m; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int findPeakElement(vector& nums) { + int l = 0, r = nums.size() - 1; + + while (l <= r) { + int m = l + (r - l) / 2; + if (m > 0 && nums[m] < nums[m - 1]) { + r = m - 1; + } else if (m < nums.size() - 1 && nums[m] < nums[m + 1]) { + l = m + 1; + } else { + return m; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findPeakElement(nums) { + let l = 0, + r = nums.length - 1; + + while (l <= r) { + let m = Math.floor(l + (r - l) / 2); + if (m > 0 && nums[m] < nums[m - 1]) { + r = m - 1; + } else if (m < nums.length - 1 && nums[m] < nums[m + 1]) { + l = m + 1; + } else { + return m; + } + } + + return -1; + } +} +``` + +```csharp +public class Solution { + public int FindPeakElement(int[] nums) { + int l = 0, r = nums.Length - 1; + while (l <= r) { + int m = l + (r - l) / 2; + if (m > 0 && nums[m] < nums[m - 1]) { + r = m - 1; + } else if (m < nums.Length - 1 && nums[m] < nums[m + 1]) { + l = m + 1; + } else { + return m; + } + } + return l; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ + +--- + +## 3. Recursive Binary Search + +::tabs-start + +```python +class Solution: + def findPeakElement(self, nums: List[int]) -> int: + def binary_search(l, r): + if l == r: + return l + m = l + (r - l) // 2 + if nums[m] > nums[m + 1]: + return binary_search(l, m) + return binary_search(m + 1, r) + + return binary_search(0, len(nums) - 1) +``` + +```java +public class Solution { + public int findPeakElement(int[] nums) { + return binarySearch(nums, 0, nums.length - 1); + } + + private int binarySearch(int[] nums, int l, int r) { + if (l == r) { + return l; + } + int m = l + (r - l) / 2; + if (nums[m] > nums[m + 1]) { + return binarySearch(nums, l, m); + } + return binarySearch(nums, m + 1, r); + } +} +``` + +```cpp +class Solution { +public: + int findPeakElement(vector& nums) { + return binarySearch(nums, 0, nums.size() - 1); + } + +private: + int binarySearch(vector& nums, int l, int r) { + if (l == r) { + return l; + } + int m = l + (r - l) / 2; + if (nums[m] > nums[m + 1]) { + return binarySearch(nums, l, m); + } + return binarySearch(nums, m + 1, r); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findPeakElement(nums) { + const binarySearch = (l, r) => { + if (l === r) { + return l; + } + let m = Math.floor((l + r) / 2); + if (nums[m] > nums[m + 1]) { + return binarySearch(l, m); + } else { + return binarySearch(m + 1, r); + } + }; + + return binarySearch(0, nums.length - 1); + } +} +``` + +```csharp +public class Solution { + public int FindPeakElement(int[] nums) { + return BinarySearch(nums, 0, nums.Length - 1); + } + + private int BinarySearch(int[] nums, int l, int r) { + if (l == r) { + return l; + } + int m = l + (r - l) / 2; + if (nums[m] > nums[m + 1]) { + return BinarySearch(nums, l, m); + } + return BinarySearch(nums, m + 1, r); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(\log n)$ for recursion stack. + +--- + +## 4. Binary Search (Optimal) + +::tabs-start + +```python +class Solution: + def findPeakElement(self, nums: List[int]) -> int: + l, r = 0, len(nums) - 1 + + while l < r: + m = (l + r) >> 1 + if nums[m] > nums[m + 1]: + r = m + else: + l = m + 1 + + return l +``` + +```java +public class Solution { + public int findPeakElement(int[] nums) { + int l = 0, r = nums.length - 1; + + while (l < r) { + int m = (l + r) >> 1; + if (nums[m] > nums[m + 1]) { + r = m; + } else { + l = m + 1; + } + } + + return l; + } +} +``` + +```cpp +class Solution { +public: + int findPeakElement(vector& nums) { + int l = 0, r = nums.size() - 1; + + while (l < r) { + int m = (l + r) >> 1; + if (nums[m] > nums[m + 1]) { + r = m; + } else { + l = m + 1; + } + } + + return l; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findPeakElement(nums) { + let l = 0, + r = nums.length - 1; + + while (l < r) { + let m = (l + r) >> 1; + if (nums[m] > nums[m + 1]) { + r = m; + } else { + l = m + 1; + } + } + + return l; + } +} +``` + +```csharp +public class Solution { + public int FindPeakElement(int[] nums) { + int l = 0, r = nums.Length - 1; + while (l < r) { + int m = (l + r) >> 1; + if (nums[m] > nums[m + 1]) { + r = m; + } else { + l = m + 1; + } + } + return l; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/find-pivot-index.md b/articles/find-pivot-index.md index 7e8568d02..0354d06e4 100644 --- a/articles/find-pivot-index.md +++ b/articles/find-pivot-index.md @@ -69,7 +69,8 @@ class Solution { pivotIndex(nums) { const n = nums.length; for (let i = 0; i < n; i++) { - let leftSum = 0, rightSum = 0; + let leftSum = 0, + rightSum = 0; for (let l = 0; l < i; l++) { leftSum += nums[l]; } @@ -89,8 +90,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -105,7 +106,7 @@ class Solution: prefixSum = [0] * (n + 1) for i in range(n): prefixSum[i + 1] = prefixSum[i] + nums[i] - + for i in range(n): leftSum = prefixSum[i] rightSum = prefixSum[n] - prefixSum[i + 1] @@ -117,7 +118,7 @@ class Solution: ```java public class Solution { public int pivotIndex(int[] nums) { - int n = nums.length; + int n = nums.length; int[] prefixSum = new int[n + 1]; for (int i = 0; i < n; i++) { prefixSum[i + 1] = prefixSum[i] + nums[i]; @@ -129,7 +130,7 @@ public class Solution { if (leftSum == rightSum) { return i; } - } + } return -1; } } @@ -139,7 +140,7 @@ public class Solution { class Solution { public: int pivotIndex(vector& nums) { - int n = nums.size(); + int n = nums.size(); vector prefixSum(n + 1, 0); for (int i = 0; i < n; i++) { prefixSum[i + 1] = prefixSum[i] + nums[i]; @@ -151,7 +152,7 @@ public: if (leftSum == rightSum) { return i; } - } + } return -1; } }; @@ -186,8 +187,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -280,5 +281,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/find-polygon-with-the-largest-perimeter.md b/articles/find-polygon-with-the-largest-perimeter.md new file mode 100644 index 000000000..f05143240 --- /dev/null +++ b/articles/find-polygon-with-the-largest-perimeter.md @@ -0,0 +1,295 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def largestPerimeter(self, nums: List[int]) -> int: + n = len(nums) + res = -1 + + for i, large in enumerate(nums): + cur = 0 + for j, side in enumerate(nums): + if i != j and side <= large: + cur += side + if cur > large: + res = max(res, cur + large) + + return res +``` + +```java +public class Solution { + public long largestPerimeter(int[] nums) { + int n = nums.length; + long res = -1; + + for (int i = 0; i < n; i++) { + int large = nums[i]; + long cur = 0; + + for (int j = 0; j < n; j++) { + if (i != j && nums[j] <= large) { + cur += nums[j]; + } + } + + if (cur > large) { + res = Math.max(res, cur + large); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long largestPerimeter(vector& nums) { + int n = nums.size(); + long long res = -1; + + for (int i = 0; i < n; i++) { + long long large = nums[i]; + long long cur = 0; + + for (int j = 0; j < n; j++) { + if (i != j && nums[j] <= large) { + cur += nums[j]; + } + } + + if (cur > large) { + res = max(res, cur + large); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + largestPerimeter(nums) { + const n = nums.length; + let res = -1; + + for (let i = 0; i < n; i++) { + const large = nums[i]; + let cur = 0; + + for (let j = 0; j < n; j++) { + if (i !== j && nums[j] <= large) { + cur += nums[j]; + } + } + + if (cur > large) { + res = Math.max(res, cur + large); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 2. Sorting + +::tabs-start + +```python +class Solution: + def largestPerimeter(self, nums: List[int]) -> int: + nums.sort() + res = -1 + total = 0 + for num in nums: + if total > num: + res = total + num + total += num + return res +``` + +```java +public class Solution { + public long largestPerimeter(int[] nums) { + Arrays.sort(nums); + long res = -1; + long total = 0; + + for (int num : nums) { + if (total > num) { + res = total + num; + } + total += num; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long largestPerimeter(vector& nums) { + sort(nums.begin(), nums.end()); + long long res = -1; + long long total = 0; + + for (int& num : nums) { + if (total > num) { + res = total + num; + } + total += num; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + largestPerimeter(nums) { + nums.sort((a, b) => a - b); + let res = -1; + let total = 0; + + for (let num of nums) { + if (total > num) { + res = total + num; + } + total += num; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 3. Max Heap + +::tabs-start + +```python +class Solution: + def largestPerimeter(self, nums: List[int]) -> int: + nums = [-num for num in nums] + heapq.heapify(nums) + total = -sum(nums) + + while len(nums) > 2: + largest = -heapq.heappop(nums) + total -= largest + if largest < total: + return total + largest + return -1 +``` + +```java +public class Solution { + public long largestPerimeter(int[] nums) { + PriorityQueue maxHeap = new PriorityQueue<>((a, b) -> b - a); + long total = 0; + for (int num : nums) { + maxHeap.add(num); + total += num; + } + + while (maxHeap.size() > 2) { + int largest = maxHeap.poll(); + total -= largest; + if (largest < total) { + return total + largest; + } + } + return -1; + } +} +``` + +```cpp +class Solution { +public: + long long largestPerimeter(vector& nums) { + priority_queue maxHeap(nums.begin(), nums.end()); + long long total = accumulate(nums.begin(), nums.end(), 0LL); + + while (maxHeap.size() > 2) { + int largest = maxHeap.top(); + maxHeap.pop(); + total -= largest; + if (largest < total) { + return total + largest; + } + } + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + largestPerimeter(nums) { + const maxHeap = new MaxPriorityQueue(); + let total = 0; + + nums.forEach((num) => { + total += num; + maxHeap.enqueue(num); + }); + + while (maxHeap.size() > 2) { + const largest = maxHeap.dequeue().element; + total -= largest; + if (largest < total) return total + largest; + } + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(n + (30\log n))$ in Python, C++, JS. + - $O(n \log n)$ in Java. +- Space complexity: $O(n)$ diff --git a/articles/find-target-in-rotated-sorted-array.md b/articles/find-target-in-rotated-sorted-array.md index 2e6dd37e5..41f7e56bb 100644 --- a/articles/find-target-in-rotated-sorted-array.md +++ b/articles/find-target-in-rotated-sorted-array.md @@ -93,12 +93,25 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + for i in 0.. int: while left <= right: mid = (left + right) // 2 @@ -134,7 +147,7 @@ class Solution: result = binary_search(0, pivot - 1) if result != -1: return result - + return binary_search(pivot, len(nums) - 1) ``` @@ -392,12 +405,53 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + var l = 0, r = nums.count - 1 + + while l < r { + let m = (l + r) / 2 + if nums[m] > nums[r] { + l = m + 1 + } else { + r = m + } + } + + let pivot = l + + func binarySearch(_ left: Int, _ right: Int) -> Int { + var l = left, r = right + while l <= r { + let mid = (l + r) / 2 + if nums[mid] == target { + return mid + } else if nums[mid] < target { + l = mid + 1 + } else { + r = mid - 1 + } + } + return -1 + } + + let result = binarySearch(0, pivot - 1) + if result != -1 { + return result + } + + return binarySearch(pivot, nums.count - 1) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ --- @@ -526,7 +580,8 @@ class Solution { * @return {number} */ search(nums, target) { - let l = 0, r = nums.length - 1; + let l = 0, + r = nums.length - 1; while (l < r) { let m = Math.floor((l + r) / 2); @@ -681,12 +736,52 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + var l = 0, r = nums.count - 1 + + while l < r { + let m = (l + r) / 2 + if nums[m] > nums[r] { + l = m + 1 + } else { + r = m + } + } + + let pivot = l + l = 0 + r = nums.count - 1 + + if target >= nums[pivot] && target <= nums[r] { + l = pivot + } else { + r = pivot - 1 + } + + while l <= r { + let m = (l + r) / 2 + if nums[m] == target { + return m + } else if nums[m] < target { + l = m + 1 + } else { + r = m - 1 + } + } + + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ --- @@ -709,7 +804,7 @@ class Solution: l = mid + 1 else: r = mid - 1 - + else: if target < nums[mid] or target > nums[r]: r = mid - 1 @@ -792,7 +887,8 @@ class Solution { * @return {number} */ search(nums, target) { - let l = 0, r = nums.length - 1; + let l = 0, + r = nums.length - 1; while (l <= r) { const mid = Math.floor((l + r) / 2); @@ -908,9 +1004,39 @@ class Solution { } ``` +```swift +class Solution { + func search(_ nums: [Int], _ target: Int) -> Int { + var l = 0, r = nums.count - 1 + + while l <= r { + let mid = (l + r) / 2 + if target == nums[mid] { + return mid + } + + if nums[l] <= nums[mid] { + if target > nums[mid] || target < nums[l] { + l = mid + 1 + } else { + r = mid - 1 + } + } else { + if target < nums[mid] || target > nums[r] { + r = mid - 1 + } else { + l = mid + 1 + } + } + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/find-the-difference-of-two-arrays.md b/articles/find-the-difference-of-two-arrays.md index 853638267..08f994bbc 100644 --- a/articles/find-the-difference-of-two-arrays.md +++ b/articles/find-the-difference-of-two-arrays.md @@ -100,7 +100,7 @@ public: } } - return {vector(res1.begin(), res1.end()), + return {vector(res1.begin(), res1.end()), vector(res2.begin(), res2.end())}; } }; @@ -152,8 +152,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n + m)$ > Where $n$ is the size of the array $nums1$ and $m$ is the size of the array $nums2$. @@ -283,8 +283,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n + m \log m)$ -* Space complexity: $O(1)$ or $O(n + m)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n + m \log m)$ +- Space complexity: $O(1)$ or $O(n + m)$ depending on the sorting algorithm. > Where $n$ is the size of the array $nums1$ and $m$ is the size of the array $nums2$. @@ -386,8 +386,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ > Where $n$ is the size of the array $nums1$ and $m$ is the size of the array $nums2$. @@ -429,10 +429,10 @@ public: vector> findDifference(vector& nums1, vector& nums2) { vector res1, res2; set numSet1(begin(nums1), end(nums1)), numSet2(begin(nums2), end(nums2)); - + set_difference(begin(numSet1), end(numSet1), begin(numSet2), end(numSet2), back_inserter(res1)); set_difference(begin(numSet2), end(numSet2), begin(numSet1), end(numSet1), back_inserter(res2)); - + return {res1, res2}; } }; @@ -449,8 +449,8 @@ class Solution { const numSet1 = new Set(nums1); const numSet2 = new Set(nums2); - const res1 = Array.from(numSet1).filter(num => !numSet2.has(num)); - const res2 = Array.from(numSet2).filter(num => !numSet1.has(num)); + const res1 = Array.from(numSet1).filter((num) => !numSet2.has(num)); + const res2 = Array.from(numSet2).filter((num) => !numSet1.has(num)); return [res1, res2]; } @@ -461,7 +461,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ -> Where $n$ is the size of the array $nums1$ and $m$ is the size of the array $nums2$. \ No newline at end of file +> Where $n$ is the size of the array $nums1$ and $m$ is the size of the array $nums2$. diff --git a/articles/find-the-difference.md b/articles/find-the-difference.md new file mode 100644 index 000000000..1b3f9f9da --- /dev/null +++ b/articles/find-the-difference.md @@ -0,0 +1,467 @@ +## 1. Two Hash Maps + +::tabs-start + +```python +class Solution: + def findTheDifference(self, s: str, t: str) -> str: + count_s, count_t = Counter(s), Counter(t) + for c in count_t: + if c not in count_s or count_s[c] < count_t[c]: + return c +``` + +```java +public class Solution { + public char findTheDifference(String s, String t) { + int[] countS = new int[26]; + int[] countT = new int[26]; + + for (char c : s.toCharArray()) countS[c - 'a']++; + for (char c : t.toCharArray()) countT[c - 'a']++; + + for (int i = 0; i < 26; i++) { + if (countT[i] > countS[i]) { + return (char) (i + 'a'); + } + } + return ' '; + } +} +``` + +```cpp +class Solution { +public: + char findTheDifference(string s, string t) { + vector countS(26, 0), countT(26, 0); + + for (char c : s) countS[c - 'a']++; + for (char c : t) countT[c - 'a']++; + + for (int i = 0; i < 26; i++) { + if (countT[i] > countS[i]) { + return i + 'a'; + } + } + return ' '; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} t + * @return {character} + */ + findTheDifference(s, t) { + let countS = Array(26).fill(0); + let countT = Array(26).fill(0); + + for (let char of s) countS[char.charCodeAt(0) - 'a'.charCodeAt(0)]++; + for (let char of t) countT[char.charCodeAt(0) - 'a'.charCodeAt(0)]++; + + for (let i = 0; i < 26; i++) { + if (countT[i] > countS[i]) { + return String.fromCharCode(i + 'a'.charCodeAt(0)); + } + } + return ''; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. + +--- + +## 2. One Hash Map + +::tabs-start + +```python +class Solution: + def findTheDifference(self, s: str, t: str) -> str: + count = Counter(t) + for c in s: + count[c] -= 1 + for c in count: + if count[c] == 1: + return c +``` + +```java +public class Solution { + public char findTheDifference(String s, String t) { + int[] count = new int[26]; + + for (char c : t.toCharArray()) count[c - 'a']++; + for (char c : s.toCharArray()) count[c - 'a']--; + + for (int i = 0; i < 26; i++) { + if (count[i] == 1) { + return (char) (i + 'a'); + } + } + return ' '; + } +} +``` + +```cpp +class Solution { +public: + char findTheDifference(string s, string t) { + vector count(26); + + for (char c : t) count[c - 'a']++; + for (char c : s) count[c - 'a']--; + + for (int i = 0; i < 26; i++) { + if (count[i] == 1) { + return i + 'a'; + } + } + return ' '; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} t + * @return {character} + */ + findTheDifference(s, t) { + let count = Array(26).fill(0); + + for (let char of t) count[char.charCodeAt(0) - 'a'.charCodeAt(0)]++; + for (let char of s) count[char.charCodeAt(0) - 'a'.charCodeAt(0)]--; + + for (let i = 0; i < 26; i++) { + if (count[i] === 1) { + return String.fromCharCode(i + 'a'.charCodeAt(0)); + } + } + return ''; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. + +--- + +## 3. Sorting + +::tabs-start + +```python +class Solution: + def findTheDifference(self, s: str, t: str) -> str: + s, t = sorted(s), sorted(t) + for c1, c2 in zip(s, t): + if c1 != c2: + return c2 + return t[-1] +``` + +```java +public class Solution { + public char findTheDifference(String s, String t) { + char[] sArr = s.toCharArray(); + char[] tArr = t.toCharArray(); + Arrays.sort(sArr); + Arrays.sort(tArr); + for (int i = 0; i < sArr.length; i++) { + if (sArr[i] != tArr[i]) { + return tArr[i]; + } + } + return tArr[tArr.length - 1]; + } +} +``` + +```cpp +class Solution { +public: + char findTheDifference(string s, string t) { + sort(s.begin(), s.end()); + sort(t.begin(), t.end()); + for (int i = 0; i < s.size(); i++) { + if (s[i] != t[i]) { + return t[i]; + } + } + return t[t.size() - 1]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} t + * @return {character} + */ + findTheDifference(s, t) { + s = s.split('').sort(); + t = t.split('').sort(); + for (let i = 0; i < s.length; i++) { + if (s[i] !== t[i]) { + return t[i]; + } + } + return t[t.length - 1]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 4. Difference Between ASCII Values + +::tabs-start + +```python +class Solution: + def findTheDifference(self, s: str, t: str) -> str: + sum_s, sum_t = 0, 0 + for c in s: + sum_s += ord(c) + for c in t: + sum_t += ord(c) + return chr(sum_t - sum_s) +``` + +```java +public class Solution { + public char findTheDifference(String s, String t) { + int sumS = 0, sumT = 0; + for (int i = 0; i < s.length(); i++) { + sumS += s.charAt(i); + } + for (int i = 0; i < t.length(); i++) { + sumT += t.charAt(i); + } + return (char) (sumT - sumS); + } +} +``` + +```cpp +class Solution { +public: + char findTheDifference(string s, string t) { + int sumS = 0, sumT = 0; + for (char c : s) { + sumS += c; + } + for (char c : t) { + sumT += c; + } + return (char) (sumT - sumS); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} t + * @return {character} + */ + findTheDifference(s, t) { + let sumS = 0, + sumT = 0; + for (let char of s) { + sumS += char.charCodeAt(0); + } + for (let char of t) { + sumT += char.charCodeAt(0); + } + return String.fromCharCode(sumT - sumS); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 5. Difference Between ASCII Values (Optimal) + +::tabs-start + +```python +class Solution: + def findTheDifference(self, s: str, t: str) -> str: + res = 0 + for c in s: + res -= ord(c) + for c in t: + res += ord(c) + return chr(res) +``` + +```java +public class Solution { + public char findTheDifference(String s, String t) { + int res = 0; + for (int i = 0; i < s.length(); i++) { + res -= s.charAt(i); + } + for (int i = 0; i < t.length(); i++) { + res += t.charAt(i); + } + return (char) (res); + } +} +``` + +```cpp +class Solution { +public: + char findTheDifference(string s, string t) { + int res = 0; + for (char c : s) { + res -= c; + } + for (char c : t) { + res += c; + } + return (char) (res); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} t + * @return {character} + */ + findTheDifference(s, t) { + let res = 0; + for (let char of s) { + res -= char.charCodeAt(0); + } + for (let char of t) { + res += char.charCodeAt(0); + } + return String.fromCharCode(res); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 6. Bitwise XOR + +::tabs-start + +```python +class Solution: + def findTheDifference(self, s: str, t: str) -> str: + res = 0 + for c in s: + res ^= ord(c) + for c in t: + res ^= ord(c) + return chr(res) +``` + +```java +public class Solution { + public char findTheDifference(String s, String t) { + int res = 0; + for (int i = 0; i < s.length(); i++) { + res ^= s.charAt(i); + } + for (int i = 0; i < t.length(); i++) { + res ^= t.charAt(i); + } + return (char) (res); + } +} +``` + +```cpp +class Solution { +public: + char findTheDifference(string s, string t) { + int res = 0; + for (char c : s) { + res ^= c; + } + for (char c : t) { + res ^= c; + } + return (char) (res); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} t + * @return {character} + */ + findTheDifference(s, t) { + let res = 0; + for (let char of s) { + res ^= char.charCodeAt(0); + } + for (let char of t) { + res ^= char.charCodeAt(0); + } + return String.fromCharCode(res); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/find-the-index-of-the-first-occurrence-in-a-string.md b/articles/find-the-index-of-the-first-occurrence-in-a-string.md index beb5b5893..ed564661a 100644 --- a/articles/find-the-index-of-the-first-occurrence-in-a-string.md +++ b/articles/find-the-index-of-the-first-occurrence-in-a-string.md @@ -64,7 +64,8 @@ class Solution { * @return {number} */ strStr(haystack, needle) { - let n = haystack.length, m = needle.length; + let n = haystack.length, + m = needle.length; for (let i = 0; i < n - m + 1; i++) { let j = 0; while (j < m) { @@ -80,12 +81,33 @@ class Solution { } ``` +```csharp +public class Solution { + public int StrStr(string haystack, string needle) { + int n = haystack.Length, m = needle.Length; + for (int i = 0; i <= n - m; i++) { + int j = 0; + while (j < m) { + if (haystack[i + j] != needle[j]) { + break; + } + j++; + } + if (j == m) { + return i; + } + } + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(1)$ > Where $n$ is the length of the string $heystack$ and $m$ is the length of the string $needle$. @@ -112,7 +134,7 @@ class Solution: i += 1 else: prevLPS = lps[prevLPS - 1] - + i = 0 # ptr for haystack j = 0 # ptr for needle while i < len(haystack): @@ -123,10 +145,10 @@ class Solution: i += 1 else: j = lps[j - 1] - + if j == len(needle): return i - len(needle) - + return -1 ``` @@ -231,12 +253,13 @@ class Solution { * @return {number} */ strStr(haystack, needle) { - if (needle === "") return 0; + if (needle === '') return 0; const m = needle.length; const lps = new Array(m).fill(0); - let prevLPS = 0, i = 1; + let prevLPS = 0, + i = 1; while (i < m) { if (needle[i] === needle[prevLPS]) { lps[i] = prevLPS + 1; @@ -250,8 +273,8 @@ class Solution { } } - i = 0; // ptr for haystack - let j = 0; // ptr for needle + i = 0; // ptr for haystack + let j = 0; // ptr for needle while (i < haystack.length) { if (haystack[i] === needle[j]) { i++; @@ -274,12 +297,58 @@ class Solution { } ``` +```csharp +public class Solution { + public int StrStr(string haystack, string needle) { + if (needle == "") return 0; + + int[] lps = new int[needle.Length]; + int prevLPS = 0, i = 1; + + while (i < needle.Length) { + if (needle[i] == needle[prevLPS]) { + lps[i] = prevLPS + 1; + prevLPS++; + i++; + } else if (prevLPS == 0) { + lps[i] = 0; + i++; + } else { + prevLPS = lps[prevLPS - 1]; + } + } + + i = 0; + int j = 0; + + while (i < haystack.Length) { + if (haystack[i] == needle[j]) { + i++; + j++; + } else { + if (j == 0) { + i++; + } else { + j = lps[j - 1]; + } + } + + if (j == needle.Length) { + return i - needle.Length; + } + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(m)$ > Where $n$ is the length of the string $heystack$ and $m$ is the length of the string $needle$. @@ -294,12 +363,12 @@ class Solution: def strStr(self, haystack: str, needle: str) -> int: if not needle: return 0 - + s = needle + "$" + haystack n = len(s) z = [0] * n l, r = 0, 0 - + for i in range(1, n): if i <= r: z[i] = min(r - i + 1, z[i - l]) @@ -307,11 +376,11 @@ class Solution: z[i] += 1 if i + z[i] - 1 > r: l, r = i, i + z[i] - 1 - + for i in range(len(needle) + 1, n): if z[i] == len(needle): return i - len(needle) - 1 - + return -1 ``` @@ -392,12 +461,13 @@ class Solution { * @return {number} */ strStr(haystack, needle) { - if (needle === "") return 0; + if (needle === '') return 0; - const s = needle + "$" + haystack; + const s = needle + '$' + haystack; const n = s.length; const z = new Array(n).fill(0); - let l = 0, r = 0; + let l = 0, + r = 0; for (let i = 1; i < n; i++) { if (i <= r) { @@ -423,12 +493,47 @@ class Solution { } ``` +```csharp +public class Solution { + public int StrStr(string haystack, string needle) { + if (string.IsNullOrEmpty(needle)) return 0; + + string s = needle + "$" + haystack; + int n = s.Length; + int[] z = new int[n]; + int l = 0, r = 0; + + for (int i = 1; i < n; i++) { + if (i <= r) { + z[i] = Math.Min(r - i + 1, z[i - l]); + } + while (i + z[i] < n && s[z[i]] == s[i + z[i]]) { + z[i]++; + } + if (i + z[i] - 1 > r) { + l = i; + r = i + z[i] - 1; + } + } + + int m = needle.Length; + for (int i = m + 1; i < n; i++) { + if (z[i] == m) { + return i - m - 1; + } + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ > Where $n$ is the length of the string $heystack$ and $m$ is the length of the string $needle$. @@ -443,10 +548,10 @@ class Solution: def strStr(self, haystack: str, needle: str) -> int: if not needle: return 0 - + base1, mod1 = 31, 768258391 base2, mod2 = 37, 685683731 - + n, m = len(haystack), len(needle) if m > n: return -1 @@ -468,7 +573,7 @@ class Solution: for i in range(n - m + 1): if haystack_hash1 == needle_hash1 and haystack_hash2 == needle_hash2: return i - + if i + m < n: haystack_hash1 = (haystack_hash1 * base1 - ord(haystack[i]) * power1 + ord(haystack[i + m])) % mod1 haystack_hash2 = (haystack_hash2 * base2 - ord(haystack[i]) * power2 + ord(haystack[i + m])) % mod2 @@ -580,38 +685,103 @@ class Solution { * @return {number} */ strStr(haystack, needle) { - if (needle === "") return 0; + if (needle === '') return 0; - const base1 = 31, mod1 = 768258391; - const base2 = 37, mod2 = 685683731; + const base1 = 31, + mod1 = 768258391; + const base2 = 37, + mod2 = 685683731; - const n = haystack.length, m = needle.length; + const n = haystack.length, + m = needle.length; if (m > n) return -1; - let power1 = 1, power2 = 1; + let power1 = 1, + power2 = 1; for (let i = 0; i < m; i++) { power1 = (power1 * base1) % mod1; power2 = (power2 * base2) % mod2; } - let needleHash1 = 0, needleHash2 = 0; - let haystackHash1 = 0, haystackHash2 = 0; + let needleHash1 = 0, + needleHash2 = 0; + let haystackHash1 = 0, + haystackHash2 = 0; for (let i = 0; i < m; i++) { needleHash1 = (needleHash1 * base1 + needle.charCodeAt(i)) % mod1; needleHash2 = (needleHash2 * base2 + needle.charCodeAt(i)) % mod2; - haystackHash1 = (haystackHash1 * base1 + haystack.charCodeAt(i)) % mod1; - haystackHash2 = (haystackHash2 * base2 + haystack.charCodeAt(i)) % mod2; + haystackHash1 = + (haystackHash1 * base1 + haystack.charCodeAt(i)) % mod1; + haystackHash2 = + (haystackHash2 * base2 + haystack.charCodeAt(i)) % mod2; } for (let i = 0; i <= n - m; i++) { - if (haystackHash1 === needleHash1 && haystackHash2 === needleHash2) { + if ( + haystackHash1 === needleHash1 && + haystackHash2 === needleHash2 + ) { return i; } if (i + m < n) { - haystackHash1 = (haystackHash1 * base1 - haystack.charCodeAt(i) * power1 + haystack.charCodeAt(i + m)) % mod1; - haystackHash2 = (haystackHash2 * base2 - haystack.charCodeAt(i) * power2 + haystack.charCodeAt(i + m)) % mod2; + haystackHash1 = + (haystackHash1 * base1 - + haystack.charCodeAt(i) * power1 + + haystack.charCodeAt(i + m)) % + mod1; + haystackHash2 = + (haystackHash2 * base2 - + haystack.charCodeAt(i) * power2 + + haystack.charCodeAt(i + m)) % + mod2; + + if (haystackHash1 < 0) haystackHash1 += mod1; + if (haystackHash2 < 0) haystackHash2 += mod2; + } + } + + return -1; + } +} +``` + +```csharp +public class Solution { + public int StrStr(string haystack, string needle) { + if (string.IsNullOrEmpty(needle)) return 0; + + int base1 = 31, mod1 = 768258391; + int base2 = 37, mod2 = 685683731; + + int n = haystack.Length, m = needle.Length; + if (m > n) return -1; + + long power1 = 1, power2 = 1; + for (int i = 0; i < m; i++) { + power1 = (power1 * base1) % mod1; + power2 = (power2 * base2) % mod2; + } + + long needleHash1 = 0, needleHash2 = 0; + long haystackHash1 = 0, haystackHash2 = 0; + + for (int i = 0; i < m; i++) { + needleHash1 = (needleHash1 * base1 + needle[i]) % mod1; + needleHash2 = (needleHash2 * base2 + needle[i]) % mod2; + haystackHash1 = (haystackHash1 * base1 + haystack[i]) % mod1; + haystackHash2 = (haystackHash2 * base2 + haystack[i]) % mod2; + } + + for (int i = 0; i <= n - m; i++) { + if (haystackHash1 == needleHash1 && haystackHash2 == needleHash2) { + return i; + } + + if (i + m < n) { + haystackHash1 = (haystackHash1 * base1 - haystack[i] * power1 + haystack[i + m]) % mod1; + haystackHash2 = (haystackHash2 * base2 - haystack[i] * power2 + haystack[i + m]) % mod2; if (haystackHash1 < 0) haystackHash1 += mod1; if (haystackHash2 < 0) haystackHash2 += mod2; @@ -627,7 +797,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(1)$ -> Where $n$ is the length of the string $heystack$ and $m$ is the length of the string $needle$. \ No newline at end of file +> Where $n$ is the length of the string $heystack$ and $m$ is the length of the string $needle$. diff --git a/articles/find-the-kth-largest-integer-in-the-array.md b/articles/find-the-kth-largest-integer-in-the-array.md new file mode 100644 index 000000000..9c46cfcf2 --- /dev/null +++ b/articles/find-the-kth-largest-integer-in-the-array.md @@ -0,0 +1,550 @@ +## 1. Sorting + +::tabs-start + +```python +class Solution: + def kthLargestNumber(self, nums: List[str], k: int) -> str: + return sorted(nums, key=lambda x: (len(x), x), reverse=True)[k - 1] +``` + +```java +public class Solution { + public String kthLargestNumber(String[] nums, int k) { + Arrays.sort(nums, + (a, b) -> a.length() == b.length() ? b.compareTo(a) : b.length() - a.length() + ); + return nums[k - 1]; + } +} +``` + +```cpp +class Solution { +public: + string kthLargestNumber(vector& nums, int k) { + sort(nums.begin(), nums.end(), [](const string& a, const string& b) { + return a.size() == b.size() ? a > b : a.size() > b.size(); + }); + return nums[k - 1]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @param {number} k + * @return {string} + */ + kthLargestNumber(nums, k) { + nums.sort((a, b) => + a.length === b.length ? b.localeCompare(a) : b.length - a.length, + ); + return nums[k - 1]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +> Where $n$ is the number of strings and $m$ is the average length of a string. + +--- + +## 2. Max-Heap + +::tabs-start + +```python +class Num: + def __init__(self, s: str): + self.s = s + + def __lt__(self, other: "Num") -> bool: + if len(self.s) != len(other.s): + return len(self.s) > len(other.s) + return self.s > other.s + +class Solution: + def kthLargestNumber(self, nums: List[str], k: int) -> str: + maxHeap = [Num(s) for s in nums] + heapq.heapify(maxHeap) + + for _ in range(k - 1): + heapq.heappop(maxHeap) + + return heapq.heappop(maxHeap).s +``` + +```java +public class Solution { + public String kthLargestNumber(String[] nums, int k) { + PriorityQueue maxHeap = new PriorityQueue<>((a, b) -> + a.length() == b.length() ? b.compareTo(a) : Integer.compare(b.length(), a.length()) + ); + + for (String num : nums) { + maxHeap.offer(num); + } + + while (--k > 0) { + maxHeap.poll(); + } + + return maxHeap.poll(); + } +} +``` + +```cpp +class Solution { +public: + string kthLargestNumber(vector& nums, int k) { + auto cmp = [](const string& a, const string& b) { + return a.size() == b.size() ? a < b : a.size() < b.size(); + }; + + priority_queue, decltype(cmp)> maxHeap(cmp); + + for (const string& num : nums) { + maxHeap.push(num); + } + + while (--k > 0) { + maxHeap.pop(); + } + + return maxHeap.top(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @param {number} k + * @return {string} + */ + kthLargestNumber(nums, k) { + const maxHeap = new PriorityQueue((a, b) => + a.length === b.length ? b.localeCompare(a) : b.length - a.length, + ); + + for (const num of nums) { + maxHeap.enqueue(num); + } + + while (--k > 0) { + maxHeap.dequeue(); + } + + return maxHeap.dequeue(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * (n + k) * \log n)$ +- Space complexity: $O(n)$ + +> Where $n$ is the number of strings and $m$ is the average length of a string. + +--- + +## 3. Min-Heap + +::tabs-start + +```python +class Num: + def __init__(self, s: str): + self.s = s + + def __lt__(self, other: "Num") -> bool: + if len(self.s) != len(other.s): + return len(self.s) < len(other.s) + return self.s < other.s + +class Solution: + def kthLargestNumber(self, nums: List[str], k: int) -> str: + minHeap = [] + for num in nums: + heapq.heappush(minHeap, Num(num)) + if len(minHeap) > k: + heapq.heappop(minHeap) + return minHeap[0].s +``` + +```java +public class Solution { + public String kthLargestNumber(String[] nums, int k) { + PriorityQueue minHeap = new PriorityQueue<>((a, b) -> + a.length() == b.length() ? a.compareTo(b) : Integer.compare(a.length(), b.length()) + ); + + for (String num : nums) { + minHeap.offer(num); + if (minHeap.size() > k) { + minHeap.poll(); + } + } + + return minHeap.peek(); + } +} +``` + +```cpp +class Solution { +public: + string kthLargestNumber(vector& nums, int k) { + auto cmp = [](const string& a, const string& b) { + return a.size() == b.size() ? a > b : a.size() > b.size(); + }; + + priority_queue, decltype(cmp)> minHeap(cmp); + + for (const string& num : nums) { + minHeap.push(num); + if (minHeap.size() > k) { + minHeap.pop(); + } + } + + return minHeap.top(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @param {number} k + * @return {string} + */ + kthLargestNumber(nums, k) { + const minHeap = new PriorityQueue((a, b) => + a.length === b.length ? a.localeCompare(b) : a.length - b.length, + ); + + for (const num of nums) { + minHeap.enqueue(num); + if (minHeap.size() > k) { + minHeap.dequeue(); + } + } + + return minHeap.front(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n * \log k)$ +- Space complexity: $O(k)$ + +> Where $n$ is the number of strings and $m$ is the average length of a string. + +--- + +## 4. Quick Select + +::tabs-start + +```python +class Solution: + def greater(self, x: str, y: str) -> bool: + if len(x) != len(y): + return len(x) > len(y) + return x > y + + def less(self, x: str, y: str) -> bool: + if len(x) != len(y): + return len(x) < len(y) + return x < y + + def partition(self, nums: List[str], left: int, right: int) -> int: + mid = (left + right) >> 1 + nums[mid], nums[left + 1] = nums[left + 1], nums[mid] + + if self.less(nums[left], nums[right]): + nums[left], nums[right] = nums[right], nums[left] + if self.less(nums[left + 1], nums[right]): + nums[left + 1], nums[right] = nums[right], nums[left + 1] + if self.less(nums[left], nums[left + 1]): + nums[left], nums[left + 1] = nums[left + 1], nums[left] + + pivot = nums[left + 1] + i = left + 1 + j = right + + while True: + while True: + i += 1 + if not self.greater(nums[i], pivot): + break + while True: + j -= 1 + if not self.less(nums[j], pivot): + break + if i > j: + break + nums[i], nums[j] = nums[j], nums[i] + + nums[left + 1], nums[j] = nums[j], nums[left + 1] + return j + + def quickSelect(self, nums: List[str], k: int) -> str: + left = 0 + right = len(nums) - 1 + + while True: + if right <= left + 1: + if right == left + 1 and self.greater(nums[right], nums[left]): + nums[left], nums[right] = nums[right], nums[left] + return nums[k] + + j = self.partition(nums, left, right) + if j >= k: + right = j - 1 + if j <= k: + left = j + 1 + + def kthLargestNumber(self, nums: List[str], k: int) -> str: + return self.quickSelect(nums, k - 1) +``` + +```java +public class Solution { + public String kthLargestNumber(String[] nums, int k) { + return quickSelect(nums, k - 1); + } + + private boolean greater(String x, String y) { + if (x.length() != y.length()) { + return x.length() > y.length(); + } + return x.compareTo(y) > 0; + } + + private boolean less(String x, String y) { + if (x.length() != y.length()) { + return x.length() < y.length(); + } + return x.compareTo(y) < 0; + } + + private int partition(String[] nums, int left, int right) { + int mid = (left + right) >> 1; + swap(nums, mid, left + 1); + + if (less(nums[left], nums[right])) { + swap(nums, left, right); + } + if (less(nums[left + 1], nums[right])) { + swap(nums, left + 1, right); + } + if (less(nums[left], nums[left + 1])) { + swap(nums, left, left + 1); + } + + String pivot = nums[left + 1]; + int i = left + 1, j = right; + + while (true) { + while (greater(nums[++i], pivot)); + while (less(nums[--j], pivot)); + if (i > j) break; + swap(nums, i, j); + } + + swap(nums, left + 1, j); + return j; + } + + private String quickSelect(String[] nums, int k) { + int left = 0, right = nums.length - 1; + + while (true) { + if (right <= left + 1) { + if (right == left + 1 && greater(nums[right], nums[left])) { + swap(nums, left, right); + } + return nums[k]; + } + + int j = partition(nums, left, right); + if (j >= k) { + right = j - 1; + } + if (j <= k) { + left = j + 1; + } + } + } + + private void swap(String[] nums, int i, int j) { + String temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } +} +``` + +```cpp +class Solution { +public: + string kthLargestNumber(vector& nums, int k) { + return quickSelect(nums, k - 1); + } + +private: + bool greater(const string& x, const string& y) { + if (x.size() != y.size()) { + return x.size() > y.size(); + } + return x > y; + } + + bool less(const string& x, const string& y) { + if (x.size() != y.size()) { + return x.size() < y.size(); + } + return x < y; + } + + int partition(vector& nums, int left, int right) { + int mid = (left + right) >> 1; + swap(nums[mid], nums[left + 1]); + + if (less(nums[left], nums[right])) { + swap(nums[left], nums[right]); + } + if (less(nums[left + 1], nums[right])) { + swap(nums[left + 1], nums[right]); + } + if (less(nums[left], nums[left + 1])) { + swap(nums[left], nums[left + 1]); + } + + string pivot = nums[left + 1]; + int i = left + 1, j = right; + + while (true) { + while (greater(nums[++i], pivot)); + while (less(nums[--j], pivot)); + if (i > j) break; + swap(nums[i], nums[j]); + } + + swap(nums[left + 1], nums[j]); + return j; + } + + string quickSelect(vector& nums, int k) { + int left = 0, right = nums.size() - 1; + + while (true) { + if (right <= left + 1) { + if (right == left + 1 && greater(nums[right], nums[left])) { + swap(nums[left], nums[right]); + } + return nums[k]; + } + + int j = partition(nums, left, right); + if (j >= k) { + right = j - 1; + } + if (j <= k) { + left = j + 1; + } + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @param {number} k + * @return {string} + */ + kthLargestNumber(nums, k) { + const greater = (x, y) => + x.length !== y.length ? x.length > y.length : x > y; + const less = (x, y) => + x.length !== y.length ? x.length < y.length : x < y; + const swap = (arr, i, j) => ([arr[i], arr[j]] = [arr[j], arr[i]]); + + const partition = (nums, left, right) => { + const mid = Math.floor((left + right) / 2); + swap(nums, mid, left + 1); + + if (less(nums[left], nums[right])) swap(nums, left, right); + if (less(nums[left + 1], nums[right])) swap(nums, left + 1, right); + if (less(nums[left], nums[left + 1])) swap(nums, left, left + 1); + + const pivot = nums[left + 1]; + let i = left + 1, + j = right; + + while (true) { + while (greater(nums[++i], pivot)); + while (less(nums[--j], pivot)); + if (i > j) break; + swap(nums, i, j); + } + + swap(nums, left + 1, j); + return j; + }; + + const quickSelect = (nums, k) => { + let left = 0, + right = nums.length - 1; + + while (true) { + if (right <= left + 1) { + if ( + right === left + 1 && + greater(nums[right], nums[left]) + ) { + swap(nums, left, right); + } + return nums[k]; + } + + const j = partition(nums, left, right); + if (j >= k) right = j - 1; + if (j <= k) left = j + 1; + } + }; + + return quickSelect(nums, k - 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ in average case, $O(m * n ^ 2)$ in worst case. +- Space complexity: $O(1)$ diff --git a/articles/find-the-longest-valid-obstacle-course-at-each-position.md b/articles/find-the-longest-valid-obstacle-course-at-each-position.md new file mode 100644 index 000000000..e4660f452 --- /dev/null +++ b/articles/find-the-longest-valid-obstacle-course-at-each-position.md @@ -0,0 +1,389 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def longestObstacleCourseAtEachPosition(self, obstacles: List[int]) -> List[int]: + n = len(obstacles) + dp = [[-1] * (n + 1) for _ in range(n)] + + def dfs(i, prev): + if i < 0: + return 0 + if dp[i][prev] != -1: + return dp[i][prev] + + res = dfs(i - 1, prev) + if prev == n or obstacles[prev] >= obstacles[i]: + res = max(res, 1 + dfs(i - 1, i)) + dp[i][prev] = res + return res + + dfs(n - 1, n) + return [1] + [1 + dp[i - 1][i] for i in range(1, n)] +``` + +```java +public class Solution { + private int[][] dp; + + public int[] longestObstacleCourseAtEachPosition(int[] obstacles) { + int n = obstacles.length; + this.dp = new int[n][n + 1]; + for (int[] row : dp) { + Arrays.fill(row, -1); + } + + dfs(n - 1, n, obstacles); + + int[] res = new int[n]; + res[0] = 1; + for (int i = 1; i < n; i++) { + res[i] = 1 + dp[i - 1][i]; + } + return res; + } + + private int dfs(int i, int prev, int[] obstacles) { + if (i < 0) { + return 0; + } + if (dp[i][prev] != -1) { + return dp[i][prev]; + } + + int res = dfs(i - 1, prev, obstacles); + if (prev == obstacles.length || obstacles[prev] >= obstacles[i]) { + res = Math.max(res, 1 + dfs(i - 1, i, obstacles)); + } + return dp[i][prev] = res; + } +} +``` + +```cpp +class Solution { +public: + vector> dp; + + vector longestObstacleCourseAtEachPosition(vector& obstacles) { + int n = obstacles.size(); + this->dp = vector>(n, vector(n + 1, -1)); + + dfs(n - 1, n, obstacles); + + vector res(n, 1); + for (int i = 1; i < n; i++) { + res[i] = 1 + dp[i - 1][i]; + } + return res; + } + +private: + int dfs(int i, int prev, vector& obstacles) { + if (i < 0) { + return 0; + } + if (dp[i][prev] != -1) { + return dp[i][prev]; + } + + int res = dfs(i - 1, prev, obstacles); + if (prev == obstacles.size() || obstacles[prev] >= obstacles[i]) { + res = max(res, 1 + dfs(i - 1, i, obstacles)); + } + return dp[i][prev] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} obstacles + * @return {number[]} + */ + longestObstacleCourseAtEachPosition(obstacles) { + const n = obstacles.length; + const dp = Array.from({ length: n }, () => new Array(n + 1).fill(-1)); + + const dfs = (i, prev) => { + if (i < 0) { + return 0; + } + if (dp[i][prev] !== -1) { + return dp[i][prev]; + } + + let res = dfs(i - 1, prev); + if (prev === n || obstacles[prev] >= obstacles[i]) { + res = Math.max(res, 1 + dfs(i - 1, i)); + } + dp[i][prev] = res; + return res; + }; + + dfs(n - 1, n); + + const res = new Array(n).fill(1); + for (let i = 1; i < n; i++) { + res[i] = 1 + dp[i - 1][i]; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 2. Dynamic Programming (Binary Search) - I + +::tabs-start + +```python +class Solution: + def longestObstacleCourseAtEachPosition(self, obstacles: List[int]) -> List[int]: + res = [] + dp = [10**8] * (len(obstacles) + 1) + + for num in obstacles: + index = bisect.bisect(dp, num) + res.append(index + 1) + dp[index] = num + + return res +``` + +```java +public class Solution { + public int[] longestObstacleCourseAtEachPosition(int[] obstacles) { + int n = obstacles.length; + int[] res = new int[n]; + int[] dp = new int[n + 1]; + Arrays.fill(dp, (int) 1e8); + + for (int i = 0; i < n; i++) { + int index = upperBound(dp, obstacles[i]); + res[i] = index + 1; + dp[index] = obstacles[i]; + } + + return res; + } + + private int upperBound(int[] dp, int target) { + int left = 0, right = dp.length; + while (left < right) { + int mid = left + (right - left) / 2; + if (dp[mid] > target) { + right = mid; + } else { + left = mid + 1; + } + } + return left; + } +} +``` + +```cpp +class Solution { +public: + vector longestObstacleCourseAtEachPosition(vector& obstacles) { + int n = obstacles.size(); + vector res(n); + vector dp(n + 1, 1e8); + + for (int i = 0; i < n; i++) { + int index = upper_bound(dp.begin(), dp.end(), obstacles[i]) - dp.begin(); + res[i] = index + 1; + dp[index] = obstacles[i]; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} obstacles + * @return {number[]} + */ + longestObstacleCourseAtEachPosition(obstacles) { + let n = obstacles.length; + let res = new Array(n).fill(0); + let dp = new Array(n + 1).fill(1e8); + + const upperBound = (dp, target) => { + let left = 0, + right = dp.length; + while (left < right) { + let mid = Math.floor((left + right) / 2); + if (dp[mid] > target) { + right = mid; + } else { + left = mid + 1; + } + } + return left; + }; + + for (let i = 0; i < n; i++) { + let index = upperBound(dp, obstacles[i]); + res[i] = index + 1; + dp[index] = obstacles[i]; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Binary Search) - II + +::tabs-start + +```python +class Solution: + def longestObstacleCourseAtEachPosition(self, obstacles: List[int]) -> List[int]: + res = [] + dp = [] + + for num in obstacles: + index = bisect.bisect_right(dp, num) + res.append(index + 1) + + if index == len(dp): + dp.append(num) + else: + dp[index] = num + + return res +``` + +```java +public class Solution { + public int[] longestObstacleCourseAtEachPosition(int[] obstacles) { + int n = obstacles.length; + int[] res = new int[n]; + List dp = new ArrayList<>(); + + for (int i = 0; i < n; i++) { + int index = upperBound(dp, obstacles[i]); + res[i] = index + 1; + + if (index == dp.size()) { + dp.add(obstacles[i]); + } else { + dp.set(index, obstacles[i]); + } + } + + return res; + } + + private int upperBound(List dp, int target) { + int left = 0, right = dp.size(); + while (left < right) { + int mid = left + (right - left) / 2; + if (dp.get(mid) > target) { + right = mid; + } else { + left = mid + 1; + } + } + return left; + } +} +``` + +```cpp +class Solution { +public: + vector longestObstacleCourseAtEachPosition(vector& obstacles) { + int n = obstacles.size(); + vector res(n); + vector dp; + + for (int i = 0; i < n; i++) { + int index = upper_bound(dp.begin(), dp.end(), obstacles[i]) - dp.begin(); + res[i] = index + 1; + + if (index == dp.size()) { + dp.push_back(obstacles[i]); + } else { + dp[index] = obstacles[i]; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} obstacles + * @return {number[]} + */ + longestObstacleCourseAtEachPosition(obstacles) { + let n = obstacles.length; + let res = new Array(n).fill(0); + let dp = []; + + const upperBound = (dp, target) => { + let left = 0, + right = dp.length; + while (left < right) { + let mid = Math.floor((left + right) / 2); + if (dp[mid] > target) { + right = mid; + } else { + left = mid + 1; + } + } + return left; + }; + + for (let i = 0; i < n; i++) { + let index = upperBound(dp, obstacles[i]); + res[i] = index + 1; + + if (index === dp.length) { + dp.push(obstacles[i]); + } else { + dp[index] = obstacles[i]; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/find-the-maximum-sum-of-node-values.md b/articles/find-the-maximum-sum-of-node-values.md new file mode 100644 index 000000000..d37f1846c --- /dev/null +++ b/articles/find-the-maximum-sum-of-node-values.md @@ -0,0 +1,645 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int: + adj = [[] for _ in range(len(nums))] + for u, v in edges: + adj[u].append(v) + adj[v].append(u) + + def dfs(node, par): + res = [nums[node], nums[node] ^ k] + for child in adj[node]: + if child == par: + continue + + cur = dfs(child, node) + tmp = [] + tmp.append(max(res[0] + cur[0], res[1] + cur[1])) + tmp.append(max(res[1] + cur[0], res[0] + cur[1])) + res = tmp + + return res + + return dfs(0, -1)[0] +``` + +```java +public class Solution { + public long maximumValueSum(int[] nums, int k, int[][] edges) { + int n = nums.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + adj[edge[1]].add(edge[0]); + } + + return dfs(0, -1, nums, k, adj)[0]; + } + + private long[] dfs(int node, int parent, int[] nums, int k, List[] adj) { + long[] res = { nums[node], nums[node] ^ k }; + for (int child : adj[node]) { + if (child == parent) continue; + + long[] cur = dfs(child, node, nums, k, adj); + long[] tmp = new long[2]; + tmp[0] = Math.max(res[0] + cur[0], res[1] + cur[1]); + tmp[1] = Math.max(res[1] + cur[0], res[0] + cur[1]); + res = tmp; + } + return res; + } +} +``` + +```cpp +class Solution { + vector> adj; + +public: + long long maximumValueSum(vector& nums, int k, vector>& edges) { + int n = nums.size(); + adj.resize(n); + for (const auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + adj[edge[1]].push_back(edge[0]); + } + + return dfs(0, -1, nums, k)[0]; + } + +private: + vector dfs(int node, int parent, vector& nums, int k) { + vector res = { nums[node], nums[node] ^ k }; + for (int child : adj[node]) { + if (child == parent) continue; + + vector cur = dfs(child, node, nums, k); + vector tmp(2); + tmp[0] = max(res[0] + cur[0], res[1] + cur[1]); + tmp[1] = max(res[1] + cur[0], res[0] + cur[1]); + res = tmp; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @param {number[][]} edges + * @return {number} + */ + maximumValueSum(nums, k, edges) { + const n = nums.length; + const adj = Array.from({ length: n }, () => []); + + for (const [u, v] of edges) { + adj[u].push(v); + adj[v].push(u); + } + + const dfs = (node, parent) => { + let res = [nums[node], nums[node] ^ k]; + + for (const child of adj[node]) { + if (child === parent) continue; + + const cur = dfs(child, node); + const tmp = []; + tmp[0] = Math.max(res[0] + cur[0], res[1] + cur[1]); + tmp[1] = Math.max(res[1] + cur[0], res[0] + cur[1]); + res = tmp; + } + + return res; + }; + + return dfs(0, -1)[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int: + dp = [[None] * 2 for _ in range(len(nums))] + [[0, float("-inf")]] + + def dfs(i, xorCnt): + if dp[i][xorCnt] is not None: + return dp[i][xorCnt] + + res = nums[i] + dfs(i + 1, xorCnt) + res = max(res, (nums[i] ^ k) + dfs(i + 1, xorCnt ^ 1)) + dp[i][xorCnt] = res + return res + + return dfs(0, 0) +``` + +```java +public class Solution { + private long[][] dp; + + public long maximumValueSum(int[] nums, int k, int[][] edges) { + int n = nums.length; + dp = new long[n + 1][2]; + for (long[] row : dp) Arrays.fill(row, Long.MIN_VALUE); + dp[n][0] = 0; + dp[n][1] = Integer.MIN_VALUE; + + return dfs(0, 0, nums, k); + } + + private long dfs(int i, int xorCnt, int[] nums, int k) { + if (dp[i][xorCnt] != Long.MIN_VALUE) { + return dp[i][xorCnt]; + } + + long res = nums[i] + dfs(i + 1, xorCnt, nums, k); + res = Math.max(res, (nums[i] ^ k) + dfs(i + 1, xorCnt ^ 1, nums, k)); + + return dp[i][xorCnt] = res; + } +} +``` + +```cpp +class Solution { + vector> dp; + +public: + long long maximumValueSum(vector& nums, int k, vector>& edges) { + int n = nums.size(); + dp.assign(n + 1, vector(2, LLONG_MIN)); + dp[n][0] = 0; + dp[n][1] = INT_MIN; + + return dfs(0, 0, nums, k); + } + +private: + long long dfs(int i, int xorCnt, vector& nums, int k) { + if (dp[i][xorCnt] != LLONG_MIN) { + return dp[i][xorCnt]; + } + + long long res = nums[i] + dfs(i + 1, xorCnt, nums, k); + res = max(res, (nums[i] ^ k) + dfs(i + 1, xorCnt ^ 1, nums, k)); + return dp[i][xorCnt] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @param {number[][]} edges + * @return {number} + */ + maximumValueSum(nums, k, edges) { + const n = nums.length; + const dp = Array.from({ length: n + 1 }, () => [null, null]); + dp[n][0] = 0; + dp[n][1] = -Infinity; + + const dfs = (i, xorCnt) => { + if (dp[i][xorCnt] !== null) return dp[i][xorCnt]; + + let res = nums[i] + dfs(i + 1, xorCnt); + res = Math.max(res, (nums[i] ^ k) + dfs(i + 1, xorCnt ^ 1)); + return (dp[i][xorCnt] = res); + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int: + n = len(nums) + dp = [[0, 0] for _ in range(n + 1)] + dp[n][1] = float("-inf") + + for i in range(n - 1, -1, -1): + dp[i][0] = max(nums[i] + dp[i + 1][0], (nums[i] ^ k) + dp[i + 1][1]) + dp[i][1] = max(nums[i] + dp[i + 1][1], (nums[i] ^ k) + dp[i + 1][0]) + + return dp[0][0] +``` + +```java +public class Solution { + public long maximumValueSum(int[] nums, int k, int[][] edges) { + int n = nums.length; + long[][] dp = new long[n + 1][2]; + dp[n][1] = Integer.MIN_VALUE; + + for (int i = n - 1; i >= 0; i--) { + dp[i][0] = Math.max(nums[i] + dp[i + 1][0], (nums[i] ^ k) + dp[i + 1][1]); + dp[i][1] = Math.max(nums[i] + dp[i + 1][1], (nums[i] ^ k) + dp[i + 1][0]); + } + + return dp[0][0]; + } +} +``` + +```cpp +class Solution { +public: + long long maximumValueSum(vector& nums, int k, vector>& edges) { + int n = nums.size(); + vector> dp(n + 1, vector(2)); + dp[n][1] = INT_MIN; + + for (int i = n - 1; i >= 0; i--) { + dp[i][0] = max(nums[i] + dp[i + 1][0], (nums[i] ^ k) + dp[i + 1][1]); + dp[i][1] = max(nums[i] + dp[i + 1][1], (nums[i] ^ k) + dp[i + 1][0]); + } + + return dp[0][0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @param {number[][]} edges + * @return {number} + */ + maximumValueSum(nums, k, edges) { + const n = nums.length; + const dp = Array.from({ length: n + 1 }, () => [0, 0]); + dp[n][1] = -Infinity; + + for (let i = n - 1; i >= 0; i--) { + dp[i][0] = Math.max( + nums[i] + dp[i + 1][0], + (nums[i] ^ k) + dp[i + 1][1], + ); + dp[i][1] = Math.max( + nums[i] + dp[i + 1][1], + (nums[i] ^ k) + dp[i + 1][0], + ); + } + + return dp[0][0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int: + dp = [0, float("-inf")] + + for i in range(len(nums) - 1, -1, -1): + next_dp = [0, 0] + next_dp[0] = max(nums[i] + dp[0], (nums[i] ^ k) + dp[1]) + next_dp[1] = max(nums[i] + dp[1], (nums[i] ^ k) + dp[0]) + dp = next_dp + + return dp[0] +``` + +```java +public class Solution { + public long maximumValueSum(int[] nums, int k, int[][] edges) { + int n = nums.length; + long[] dp = {0, Long.MIN_VALUE}; + + for (int i = n - 1; i >= 0; i--) { + long[] nextDp = new long[2]; + nextDp[0] = Math.max(nums[i] + dp[0], (nums[i] ^ k) + dp[1]); + nextDp[1] = Math.max(nums[i] + dp[1], (nums[i] ^ k) + dp[0]); + dp = nextDp; + } + + return dp[0]; + } +} +``` + +```cpp +class Solution { +public: + long long maximumValueSum(vector& nums, int k, vector>& edges) { + int n = nums.size(); + vector dp = {0, LLONG_MIN}; + + for (int i = n - 1; i >= 0; i--) { + vector nextDp(2); + nextDp[0] = max(nums[i] + dp[0], (nums[i] ^ k) + dp[1]); + nextDp[1] = max(nums[i] + dp[1], (nums[i] ^ k) + dp[0]); + dp = nextDp; + } + + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @param {number[][]} edges + * @return {number} + */ + maximumValueSum(nums, k, edges) { + const n = nums.length; + let dp = [0, -Infinity]; + + for (let i = n - 1; i >= 0; i--) { + let nextDp = [0, 0]; + nextDp[0] = Math.max(nums[i] + dp[0], (nums[i] ^ k) + dp[1]); + nextDp[1] = Math.max(nums[i] + dp[1], (nums[i] ^ k) + dp[0]); + dp = nextDp; + } + + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 5. Greedy + +::tabs-start + +```python +class Solution: + def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int: + delta = [(num ^ k) - num for num in nums] + delta.sort(reverse=True) + res = sum(nums) + + for i in range(0, len(nums), 2): + if i == len(nums) - 1: + break + path_delta = delta[i] + delta[i + 1] + if path_delta <= 0: + break + res += path_delta + + return res +``` + +```java +public class Solution { + public long maximumValueSum(int[] nums, int k, int[][] edges) { + int n = nums.length; + int[] delta = new int[n]; + long res = 0; + for (int i = 0; i < n; i++) { + res += nums[i]; + delta[i] = (nums[i] ^ k) - nums[i]; + } + + Arrays.sort(delta); + for (int i = n - 1; i > 0; i -= 2) { + int pathDelta = delta[i] + delta[i - 1]; + if (pathDelta <= 0) { + break; + } + res += pathDelta; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long maximumValueSum(vector& nums, int k, vector>& edges) { + int n = nums.size(); + vector delta(n); + long long res = 0; + for (int i = 0; i < n; i++) { + res += nums[i]; + delta[i] = (nums[i] ^ k) - nums[i]; + } + + sort(delta.rbegin(), delta.rend()); + + for (int i = 0; i + 1 < n; i += 2) { + int pathDelta = delta[i] + delta[i + 1]; + if (pathDelta <= 0) { + break; + } + res += pathDelta; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @param {number[][]} edges + * @return {number} + */ + maximumValueSum(nums, k, edges) { + const n = nums.length; + let res = 0; + let delta = []; + for (let i = 0; i < n; i++) { + res += nums[i]; + delta.push((nums[i] ^ k) - nums[i]); + } + + delta.sort((a, b) => b - a); + for (let i = 0; i + 1 < n; i += 2) { + let pathDelta = delta[i] + delta[i + 1]; + if (pathDelta <= 0) { + break; + } + res += pathDelta; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 6. Greedy (Optimal) + +::tabs-start + +```python +class Solution: + def maximumValueSum(self, nums: List[int], k: int, edges: List[List[int]]) -> int: + xorCnt = res = 0 + minDiff = 1 << 30 + + for num in nums: + xorNum = num ^ k + if xorNum > num: + res += xorNum + xorCnt ^= 1 + else: + res += num + minDiff = min(minDiff, abs(xorNum - num)) + + return res - xorCnt * minDiff +``` + +```java +public class Solution { + public long maximumValueSum(int[] nums, int k, int[][] edges) { + int xorCnt = 0, minDiff = 1 << 30; + long res = 0; + + for (int num : nums) { + int xorNum = num ^ k; + if (xorNum > num) { + res += xorNum; + xorCnt ^= 1; + } else { + res += num; + } + minDiff = Math.min(minDiff, Math.abs(xorNum - num)); + } + + return res - xorCnt * minDiff; + } +} +``` + +```cpp +class Solution { +public: + long long maximumValueSum(vector& nums, int k, vector>& edges) { + int xorCnt = 0, minDiff = 1 << 30; + long long res = 0; + + for (int& num : nums) { + int xorNum = num ^ k; + if (xorNum > num) { + res += xorNum; + xorCnt ^= 1; + } else { + res += num; + } + minDiff = min(minDiff, abs(xorNum - num)); + } + + return res - (xorCnt * minDiff); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @param {number[][]} edges + * @return {number} + */ + maximumValueSum(nums, k, edges) { + let xorCnt = 0, + res = 0, + minDiff = 1 << 30; + + for (let num of nums) { + let xorNum = num ^ k; + if (xorNum > num) { + res += xorNum; + xorCnt ^= 1; + } else { + res += num; + } + minDiff = Math.min(minDiff, Math.abs(xorNum - num)); + } + + return res - xorCnt * minDiff; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/find-the-safest-path-in-a-grid.md b/articles/find-the-safest-path-in-a-grid.md new file mode 100644 index 000000000..a6a4bb7dc --- /dev/null +++ b/articles/find-the-safest-path-in-a-grid.md @@ -0,0 +1,1113 @@ +## 1. Multi Source BFS + Dijkstra's Algorithm + +::tabs-start + +```python +class Solution: + def maximumSafenessFactor(self, grid: List[List[int]]) -> int: + N = len(grid) + + def in_bounds(r, c): + return min(r, c) >= 0 and max(r, c) < N + + def precompute(): + q = deque() + min_dist = {} + for r in range(N): + for c in range(N): + if grid[r][c]: + q.append([r, c, 0]) + min_dist[(r, c)] = 0 + while q: + r, c, dist = q.popleft() + nei = [[r+1, c], [r-1, c], [r, c+1], [r, c-1]] + for r2, c2 in nei: + if in_bounds(r2, c2) and (r2, c2) not in min_dist: + min_dist[(r2, c2)] = dist + 1 + q.append([r2, c2, dist + 1]) + return min_dist + + min_dist = precompute() + maxHeap = [(-min_dist[(0, 0)], 0, 0)] # (dist, r, c) + visit = set() + visit.add((0, 0)) + + while maxHeap: + dist, r, c = heapq.heappop(maxHeap) + dist = -dist + if (r, c) == (N-1, N-1): + return dist + nei = [[r+1, c], [r-1, c], [r, c+1], [r, c-1]] + for r2, c2 in nei: + if in_bounds(r2, c2) and (r2, c2) not in visit: + visit.add((r2, c2)) + dist2 = min(dist, min_dist[(r2, c2)]) + heapq.heappush(maxHeap, (-dist2, r2, c2)) +``` + +```java +public class Solution { + public int maximumSafenessFactor(List> grid) { + int N = grid.size(); + int[][] minDist = precompute(grid, N); + PriorityQueue maxHeap = new PriorityQueue<>((a, b) -> b[0] - a[0]); + boolean[][] visit = new boolean[N][N]; + + maxHeap.offer(new int[]{minDist[0][0], 0, 0}); + visit[0][0] = true; + + while (!maxHeap.isEmpty()) { + int[] curr = maxHeap.poll(); + int dist = curr[0], r = curr[1], c = curr[2]; + + if (r == N - 1 && c == N - 1) { + return dist; + } + + for (int[] dir : new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}) { + int r2 = r + dir[0], c2 = c + dir[1]; + if (inBounds(r2, c2, N) && !visit[r2][c2]) { + visit[r2][c2] = true; + int dist2 = Math.min(dist, minDist[r2][c2]); + maxHeap.offer(new int[]{dist2, r2, c2}); + } + } + } + return 0; + } + + private int[][] precompute(List> grid, int N) { + int[][] minDist = new int[N][N]; + for (int[] row : minDist) Arrays.fill(row, -1); + Queue q = new LinkedList<>(); + + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid.get(r).get(c) == 1) { + q.offer(new int[]{r, c, 0}); + minDist[r][c] = 0; + } + } + } + + while (!q.isEmpty()) { + int[] curr = q.poll(); + int r = curr[0], c = curr[1], dist = curr[2]; + + for (int[] dir : new int[][]{{1, 0}, {-1, 0}, {0, 1}, {0, -1}}) { + int r2 = r + dir[0], c2 = c + dir[1]; + if (inBounds(r2, c2, N) && minDist[r2][c2] == -1) { + minDist[r2][c2] = dist + 1; + q.offer(new int[]{r2, c2, dist + 1}); + } + } + } + return minDist; + } + + private boolean inBounds(int r, int c, int N) { + return r >= 0 && c >= 0 && r < N && c < N; + } +} +``` + +```cpp +class Solution { + static constexpr int directions[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + +public: + int maximumSafenessFactor(vector>& grid) { + int N = grid.size(); + vector> minDist = precompute(grid, N); + priority_queue> maxHeap; + vector> visit(N, vector(N, false)); + + maxHeap.push({minDist[0][0], 0, 0}); + visit[0][0] = true; + + while (!maxHeap.empty()) { + vector cur = maxHeap.top(); maxHeap.pop(); + int dist = cur[0], r = cur[1], c = cur[2]; + + if (r == N - 1 && c == N - 1) { + return dist; + } + + for (const auto& dir : directions) { + int r2 = r + dir[0], c2 = c + dir[1]; + if (inBounds(r2, c2, N) && !visit[r2][c2]) { + visit[r2][c2] = true; + int dist2 = min(dist, minDist[r2][c2]); + maxHeap.push({dist2, r2, c2}); + } + } + } + return 0; + } + +private: + vector> precompute(vector>& grid, int N) { + vector> minDist(N, vector(N, -1)); + queue> q; + + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + q.push({r, c, 0}); + minDist[r][c] = 0; + } + } + } + + while (!q.empty()) { + vector cur = q.front(); + q.pop(); + int r = cur[0], c = cur[1], dist = cur[2]; + + for (const auto& dir : directions) { + int r2 = r + dir[0], c2 = c + dir[1]; + if (inBounds(r2, c2, N) && minDist[r2][c2] == -1) { + minDist[r2][c2] = dist + 1; + q.push({r2, c2, dist + 1}); + } + } + } + return minDist; + } + + bool inBounds(int r, int c, int N) { + return r >= 0 && c >= 0 && r < N && c < N; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + maximumSafenessFactor(grid) { + const N = grid.length; + const directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; + + const inBounds = (r, c) => { + return r >= 0 && c >= 0 && r < N && c < N; + }; + + const precompute = () => { + const q = new Queue(); + const minDist = Array.from({ length: N }, () => Array(N).fill(-1)); + + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + q.push([r, c, 0]); + minDist[r][c] = 0; + } + } + } + + while (!q.isEmpty()) { + let [r, c, dist] = q.pop(); + + for (let [dr, dc] of directions) { + let r2 = r + dr, + c2 = c + dc; + if (inBounds(r2, c2) && minDist[r2][c2] === -1) { + minDist[r2][c2] = dist + 1; + q.push([r2, c2, dist + 1]); + } + } + } + return minDist; + }; + + const minDist = precompute(); + const maxHeap = new MaxPriorityQueue({ priority: (x) => x[0] }); + const visit = Array.from({ length: N }, () => Array(N).fill(false)); + + maxHeap.enqueue([minDist[0][0], 0, 0]); + visit[0][0] = true; + + while (!maxHeap.isEmpty()) { + let [dist, r, c] = maxHeap.dequeue().element; + + if (r === N - 1 && c === N - 1) { + return dist; + } + + for (let [dr, dc] of directions) { + let r2 = r + dr, + c2 = c + dc; + if (inBounds(r2, c2) && !visit[r2][c2]) { + visit[r2][c2] = true; + let dist2 = Math.min(dist, minDist[r2][c2]); + maxHeap.enqueue([dist2, r2, c2]); + } + } + } + return 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2 \log n)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 2. Multi Source BFS + Dijkstra's Algorithm (Overwriting the Input) + +::tabs-start + +```python +class Solution: + def maximumSafenessFactor(self, grid): + N = len(grid) + minDist = grid + directions = [0, 1, 0, -1, 0] + + q = deque() + for r in range(N): + for c in range(N): + if grid[r][c] == 1: + q.append(r * N + c) + minDist[r][c] = 0 + else: + minDist[r][c] = -1 + + while q: + node = q.popleft() + r, c = divmod(node, N) + for i in range(4): + r2, c2 = r + directions[i], c + directions[i + 1] + if 0 <= r2 < N and 0 <= c2 < N and minDist[r2][c2] == -1: + minDist[r2][c2] = minDist[r][c] + 1 + q.append(r2 * N + c2) + + maxHeap = [(-minDist[0][0], 0)] + safeFactor = [0] * (N * N) + safeFactor[0] = minDist[0][0] + + while maxHeap: + dist, node = heapq.heappop(maxHeap) + dist = -dist + r, c = divmod(node, N) + if r == N - 1 and c == N - 1: + return dist + if safeFactor[node] > dist: + continue + + for i in range(4): + r2, c2 = r + directions[i], c + directions[i + 1] + node2 = r2 * N + c2 + if 0 <= r2 < N and 0 <= c2 < N: + dist2 = min(dist, minDist[r2][c2]) + if dist2 > safeFactor[node2]: + safeFactor[node2] = dist2 + heapq.heappush(maxHeap, (-dist2, node2)) + + return 0 +``` + +```java +public class Solution { + public int maximumSafenessFactor(List> grid) { + int N = grid.size(); + int[][] minDist = new int[N][N]; + int[] directions = {0, 1, 0, -1, 0}; + + Queue q = new LinkedList<>(); + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid.get(r).get(c) == 1) { + q.offer(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.isEmpty()) { + int node = q.poll(); + int r = node / N, c = node % N; + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.offer(r2 * N + c2); + } + } + } + + PriorityQueue maxHeap = new PriorityQueue<>((a, b) -> Integer.compare(b[0], a[0])); + int[] safeFactor = new int[N * N]; + Arrays.fill(safeFactor, -1); + safeFactor[0] = minDist[0][0]; + maxHeap.offer(new int[]{safeFactor[0], 0}); + + while (!maxHeap.isEmpty()) { + int[] top = maxHeap.poll(); + int dist = top[0], node = top[1]; + int r = node / N, c = node % N; + if (r == N - 1 && c == N - 1) { + return dist; + } + if (safeFactor[node] > dist) { + continue; + } + + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + int node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N) { + int dist2 = Math.min(dist, minDist[r2][c2]); + if (dist2 > safeFactor[node2]) { + safeFactor[node2] = dist2; + maxHeap.offer(new int[]{dist2, node2}); + } + } + } + } + return 0; + } +} +``` + +```cpp +class Solution { +public: + int maximumSafenessFactor(vector>& grid) { + int N = grid.size(); + vector directions = {0, 1, 0, -1, 0}; + vector>& minDist = grid; + + queue q; + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + q.push(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.empty()) { + int node = q.front(); q.pop(); + int r = node / N, c = node % N; + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.push(r2 * N + c2); + } + } + } + + priority_queue> maxHeap; + vector safeFactor(N * N, 0); + safeFactor[0] = minDist[0][0]; + maxHeap.push({safeFactor[0], 0}); + + while (!maxHeap.empty()) { + auto [dist, node] = maxHeap.top(); maxHeap.pop(); + int r = node / N, c = node % N; + if (r == N - 1 && c == N - 1) { + return dist; + } + if (safeFactor[node] > dist) { + continue; + } + + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N) { + int dist2 = min(dist, minDist[r2][c2]); + if (dist2 > safeFactor[node2]) { + safeFactor[node2] = dist2; + maxHeap.push({dist2, node2}); + } + } + } + } + return 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + maximumSafenessFactor(grid) { + const N = grid.length; + const directions = [0, 1, 0, -1, 0]; + const minDist = grid; + + const q = new Queue(); + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + q.push(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.isEmpty()) { + let node = q.pop(); + let r = Math.floor(node / N), + c = node % N; + for (let i = 0; i < 4; i++) { + let r2 = r + directions[i], + c2 = c + directions[i + 1]; + if ( + r2 >= 0 && + c2 >= 0 && + r2 < N && + c2 < N && + minDist[r2][c2] === -1 + ) { + minDist[r2][c2] = minDist[r][c] + 1; + q.push(r2 * N + c2); + } + } + } + + let maxHeap = new MaxPriorityQueue({ priority: (x) => x[0] }); + let safeFactor = new Array(N * N).fill(0); + safeFactor[0] = minDist[0][0]; + maxHeap.enqueue([safeFactor[0], 0]); + + while (!maxHeap.isEmpty()) { + let [dist, node] = maxHeap.dequeue().element; + let r = Math.floor(node / N), + c = node % N; + if (r === N - 1 && c === N - 1) { + return dist; + } + if (safeFactor[node] > dist) { + continue; + } + + for (let i = 0; i < 4; i++) { + let r2 = r + directions[i], + c2 = c + directions[i + 1], + node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N) { + let dist2 = Math.min(dist, minDist[r2][c2]); + if (dist2 > safeFactor[node2]) { + safeFactor[node2] = dist2; + maxHeap.enqueue([dist2, node2]); + } + } + } + } + return 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2 \log n)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 3. Multi Source BFS + Binary Search + +::tabs-start + +```python +class Solution: + def maximumSafenessFactor(self, grid): + N = len(grid) + minDist = grid + directions = [0, 1, 0, -1, 0] + + q = deque() + for r in range(N): + for c in range(N): + if grid[r][c] == 1: + q.append(r * N + c) + minDist[r][c] = 0 + else: + minDist[r][c] = -1 + + while q: + node = q.popleft() + r, c = divmod(node, N) + for i in range(4): + r2, c2 = r + directions[i], c + directions[i + 1] + if 0 <= r2 < N and 0 <= c2 < N and minDist[r2][c2] == -1: + minDist[r2][c2] = minDist[r][c] + 1 + q.append(r2 * N + c2) + + def canReach(threshold): + q = deque([0]) + visited = [False] * (N * N) + visited[0] = True + + while q: + node = q.popleft() + r, c = divmod(node, N) + if r == N - 1 and c == N - 1: + return True + + for i in range(4): + r2, c2 = r + directions[i], c + directions[i + 1] + node2 = r2 * N + c2 + if (0 <= r2 < N and 0 <= c2 < N and not visited[node2] and + minDist[r2][c2] >= threshold + ): + visited[node2] = True + q.append(node2) + + return False + + l, r = 0, min(minDist[0][0], minDist[N - 1][N - 1]) + while l <= r: + mid = (l + r) // 2 + if canReach(mid): + l = mid + 1 + else: + r = mid - 1 + + return l - 1 +``` + +```java +public class Solution { + private static int[] directions = {0, 1, 0, -1, 0}; + + public int maximumSafenessFactor(List> grid) { + int N = grid.size(); + int[][] minDist = new int[N][N]; + + Queue q = new LinkedList<>(); + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid.get(r).get(c) == 1) { + q.offer(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.isEmpty()) { + int node = q.poll(); + int r = node / N, c = node % N; + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.offer(r2 * N + c2); + } + } + } + + int l = 0, r = Math.min(minDist[0][0], minDist[N - 1][N - 1]); + while (l <= r) { + int mid = (l + r) / 2; + if (canReach(minDist, N, mid)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + return l - 1; + } + + private boolean canReach(int[][] minDist, int N, int threshold) { + Queue q = new LinkedList<>(); + boolean[] visited = new boolean[N * N]; + q.offer(0); + visited[0] = true; + + while (!q.isEmpty()) { + int node = q.poll(); + int r = node / N, c = node % N; + if (r == N - 1 && c == N - 1) { + return true; + } + + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + int node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && !visited[node2] && + minDist[r2][c2] >= threshold) { + visited[node2] = true; + q.offer(node2); + } + } + } + return false; + } +} +``` + +```cpp +class Solution { + static constexpr int directions[5] = {0, 1, 0, -1, 0}; + +public: + int maximumSafenessFactor(vector>& grid) { + int N = grid.size(); + vector>& minDist = grid; + + queue q; + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + q.push(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.empty()) { + int node = q.front(); q.pop(); + int r = node / N, c = node % N; + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.push(r2 * N + c2); + } + } + } + + int l = 0, r = min(minDist[0][0], minDist[N - 1][N - 1]); + while (l <= r) { + int mid = (l + r) / 2; + if (canReach(minDist, N, mid)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + return l - 1; + } + +private: + bool canReach(vector>& minDist, int N, int threshold) { + queue q; + vector visited(N * N, false); + q.push(0); + visited[0] = true; + + while (!q.empty()) { + int node = q.front(); q.pop(); + int r = node / N, c = node % N; + if (r == N - 1 && c == N - 1) { + return true; + } + + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && !visited[node2] && + minDist[r2][c2] >= threshold) { + visited[node2] = true; + q.push(node2); + } + } + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + maximumSafenessFactor(grid) { + const N = grid.length; + const minDist = grid; + const directions = [0, 1, 0, -1, 0]; + + let q = new Queue(); + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + q.push(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.isEmpty()) { + let node = q.pop(); + let r = Math.floor(node / N), + c = node % N; + for (let i = 0; i < 4; i++) { + let r2 = r + directions[i], + c2 = c + directions[i + 1]; + if ( + r2 >= 0 && + c2 >= 0 && + r2 < N && + c2 < N && + minDist[r2][c2] === -1 + ) { + minDist[r2][c2] = minDist[r][c] + 1; + q.push(r2 * N + c2); + } + } + } + + const canReach = (threshold) => { + q = new Queue([0]); + let visited = new Array(N * N).fill(false); + visited[0] = true; + + while (!q.isEmpty()) { + let node = q.pop(); + let r = Math.floor(node / N), + c = node % N; + if (r === N - 1 && c === N - 1) return true; + + for (let i = 0; i < 4; i++) { + let r2 = r + directions[i], + c2 = c + directions[i + 1], + node2 = r2 * N + c2; + if ( + r2 >= 0 && + c2 >= 0 && + r2 < N && + c2 < N && + !visited[node2] && + minDist[r2][c2] >= threshold + ) { + visited[node2] = true; + q.push(node2); + } + } + } + return false; + }; + + let l = 0, + r = Math.min(minDist[0][0], minDist[N - 1][N - 1]); + while (l <= r) { + let mid = Math.floor((l + r) / 2); + if (canReach(mid)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + return l - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2 \log n)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 4. Breadth First Search (0-1 BFS) + +::tabs-start + +```python +class Solution: + def maximumSafenessFactor(self, grid): + N = len(grid) + minDist = grid + directions = [0, 1, 0, -1, 0] + + q = deque() + for r in range(N): + for c in range(N): + if grid[r][c] == 1: + q.append(r * N + c) + minDist[r][c] = 0 + else: + minDist[r][c] = -1 + + while q: + node = q.popleft() + r, c = divmod(node, N) + for i in range(4): + r2, c2 = r + directions[i], c + directions[i + 1] + if 0 <= r2 < N and 0 <= c2 < N and minDist[r2][c2] == -1: + minDist[r2][c2] = minDist[r][c] + 1 + q.append(r2 * N + c2) + + safeFactor = [-1] * (N * N) + res = safeFactor[0] = min(minDist[N - 1][N - 1], minDist[0][0]) + q.append(0) + + while q: + node = q.popleft() + r, c = divmod(node, N) + res = min(res, safeFactor[node]) + if r == N - 1 and c == N - 1: + break + + for i in range(4): + r2, c2 = r + directions[i], c + directions[i + 1] + node2 = r2 * N + c2 + if 0 <= r2 < N and 0 <= c2 < N and safeFactor[node2] == -1: + safeFactor[node2] = min(safeFactor[node], minDist[r2][c2]) + if safeFactor[node2] < res: + q.append(node2) + else: + q.appendleft(node2) + + return res +``` + +```java +public class Solution { + private static final int[] directions = {0, 1, 0, -1, 0}; + + public int maximumSafenessFactor(List> grid) { + int N = grid.size(); + int[][] minDist = new int[N][N]; + + Deque q = new ArrayDeque<>(); + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid.get(r).get(c) == 1) { + q.offerLast(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.isEmpty()) { + int node = q.pollFirst(); + int r = node / N, c = node % N; + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.offerLast(r2 * N + c2); + } + } + } + + int[] safeFactor = new int[N * N]; + Arrays.fill(safeFactor, -1); + int res = safeFactor[0] = Math.min(minDist[N - 1][N - 1], minDist[0][0]); + q.offerLast(0); + + while (!q.isEmpty()) { + int node = q.pollFirst(); + int r = node / N, c = node % N; + res = Math.min(res, safeFactor[node]); + if (r == N - 1 && c == N - 1) { + break; + } + + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && safeFactor[node2] == -1) { + safeFactor[node2] = Math.min(safeFactor[node], minDist[r2][c2]); + if (safeFactor[node2] < res) { + q.offerLast(node2); + } else { + q.offerFirst(node2); + } + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximumSafenessFactor(vector>& grid) { + int N = grid.size(); + vector>& minDist = grid; + constexpr int directions[5] = {0, 1, 0, -1, 0}; + + deque q; + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + q.push_back(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.empty()) { + int node = q.front(); q.pop_front(); + int r = node / N, c = node % N; + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1]; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && minDist[r2][c2] == -1) { + minDist[r2][c2] = minDist[r][c] + 1; + q.push_back(r2 * N + c2); + } + } + } + + vector safeFactor(N * N, -1); + int res = safeFactor[0] = min(minDist[N - 1][N - 1], minDist[0][0]); + q.push_back(0); + + while (!q.empty()) { + int node = q.front(); q.pop_front(); + int r = node / N, c = node % N; + res = min(res, safeFactor[node]); + if (r == N - 1 && c == N - 1) { + break; + } + + for (int i = 0; i < 4; i++) { + int r2 = r + directions[i], c2 = c + directions[i + 1], node2 = r2 * N + c2; + if (r2 >= 0 && c2 >= 0 && r2 < N && c2 < N && safeFactor[node2] == -1) { + safeFactor[node2] = min(safeFactor[node], minDist[r2][c2]); + if (safeFactor[node2] < res) { + q.push_back(node2); + } else { + q.push_front(node2); + } + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + maximumSafenessFactor(grid) { + const N = grid.length; + const minDist = grid; + const directions = [0, 1, 0, -1, 0]; + + const q = new Deque(); + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + q.pushBack(r * N + c); + minDist[r][c] = 0; + } else { + minDist[r][c] = -1; + } + } + } + + while (!q.isEmpty()) { + let node = q.popFront(); + let r = Math.floor(node / N), + c = node % N; + for (let i = 0; i < 4; i++) { + let r2 = r + directions[i], + c2 = c + directions[i + 1]; + if ( + r2 >= 0 && + c2 >= 0 && + r2 < N && + c2 < N && + minDist[r2][c2] === -1 + ) { + minDist[r2][c2] = minDist[r][c] + 1; + q.pushBack(r2 * N + c2); + } + } + } + + let safeFactor = new Array(N * N).fill(-1); + let res = (safeFactor[0] = Math.min( + minDist[N - 1][N - 1], + minDist[0][0], + )); + q.pushBack(0); + + while (!q.isEmpty()) { + let node = q.popFront(); + let r = Math.floor(node / N), + c = node % N; + res = Math.min(res, safeFactor[node]); + if (r === N - 1 && c === N - 1) { + break; + } + + for (let i = 0; i < 4; i++) { + let r2 = r + directions[i], + c2 = c + directions[i + 1], + node2 = r2 * N + c2; + if ( + r2 >= 0 && + c2 >= 0 && + r2 < N && + c2 < N && + safeFactor[node2] === -1 + ) { + safeFactor[node2] = Math.min( + safeFactor[node], + minDist[r2][c2], + ); + if (safeFactor[node2] < res) { + q.pushBack(node2); + } else { + q.pushFront(node2); + } + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ diff --git a/articles/find-the-town-judge.md b/articles/find-the-town-judge.md index 393448cd8..092eed3dc 100644 --- a/articles/find-the-town-judge.md +++ b/articles/find-the-town-judge.md @@ -11,11 +11,11 @@ class Solution: for src, dst in trust: outgoing[src] += 1 incoming[dst] += 1 - + for i in range(1, n + 1): if outgoing[i] == 0 and incoming[i] == n - 1: return i - + return -1 ``` @@ -24,18 +24,18 @@ public class Solution { public int findJudge(int n, int[][] trust) { int[] incoming = new int[n + 1]; int[] outgoing = new int[n + 1]; - + for (int[] t : trust) { outgoing[t[0]]++; incoming[t[1]]++; } - + for (int i = 1; i <= n; i++) { if (outgoing[i] == 0 && incoming[i] == n - 1) { return i; } } - + return -1; } } @@ -46,17 +46,17 @@ class Solution { public: int findJudge(int n, vector>& trust) { vector incoming(n + 1, 0), outgoing(n + 1, 0); - + for (auto& t : trust) { outgoing[t[0]]++; incoming[t[1]]++; } - + for (int i = 1; i <= n; i++) { if (outgoing[i] == 0 && incoming[i] == n - 1) return i; } - + return -1; } }; @@ -72,18 +72,42 @@ class Solution { findJudge(n, trust) { let incoming = new Array(n + 1).fill(0); let outgoing = new Array(n + 1).fill(0); - + for (let [src, dst] of trust) { outgoing[src]++; incoming[dst]++; } - + for (let i = 1; i <= n; i++) { if (outgoing[i] === 0 && incoming[i] === n - 1) { return i; } } - + + return -1; + } +} +``` + +```csharp +public class Solution { + public int FindJudge(int n, int[][] trust) { + int[] incoming = new int[n + 1]; + int[] outgoing = new int[n + 1]; + + foreach (int[] t in trust) { + int a = t[0]; + int b = t[1]; + outgoing[a]++; + incoming[b]++; + } + + for (int i = 1; i <= n; i++) { + if (outgoing[i] == 0 && incoming[i] == n - 1) { + return i; + } + } + return -1; } } @@ -93,8 +117,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(V + E)$ -* Space complexity: $O(V)$ +- Time complexity: $O(V + E)$ +- Space complexity: $O(V)$ > Where $V$ is the number of vertices and $E$ is the number of edges. @@ -112,11 +136,11 @@ class Solution: for src, dst in trust: delta[src] -= 1 delta[dst] += 1 - + for i in range(1, n + 1): if delta[i] == n - 1: return i - + return -1 ``` @@ -129,13 +153,13 @@ public class Solution { delta[t[0]] -= 1; delta[t[1]] += 1; } - + for (int i = 1; i <= n; i++) { if (delta[i] == n - 1) { return i; } } - + return -1; } } @@ -146,18 +170,18 @@ class Solution { public: int findJudge(int n, vector>& trust) { vector delta(n + 1, 0); - + for (auto& t : trust) { delta[t[0]]--; delta[t[1]]++; } - + for (int i = 1; i <= n; i++) { if (delta[i] == n - 1) { return i; } } - + return -1; } }; @@ -172,18 +196,40 @@ class Solution { */ findJudge(n, trust) { let delta = new Array(n + 1).fill(0); - + for (let [src, dst] of trust) { delta[src]--; delta[dst]++; } - + for (let i = 1; i <= n; i++) { if (delta[i] === n - 1) { return i; } } - + + return -1; + } +} +``` + +```csharp +public class Solution { + public int FindJudge(int n, int[][] trust) { + int[] delta = new int[n + 1]; + + foreach (int[] t in trust) { + int a = t[0]; + int b = t[1]; + delta[a]--; + delta[b]++; + } + + for (int i = 1; i <= n; i++) { + if (delta[i] == n - 1) { + return i; + } + } return -1; } } @@ -193,7 +239,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(V + E)$ -* Space complexity: $O(V)$ +- Time complexity: $O(V + E)$ +- Space complexity: $O(V)$ -> Where $V$ is the number of vertices and $E$ is the number of edges. \ No newline at end of file +> Where $V$ is the number of vertices and $E$ is the number of edges. diff --git a/articles/find-unique-binary-string.md b/articles/find-unique-binary-string.md new file mode 100644 index 000000000..33c9097f0 --- /dev/null +++ b/articles/find-unique-binary-string.md @@ -0,0 +1,686 @@ +## 1. Backtracking (Recursion) + +::tabs-start + +```python +class Solution: + def findDifferentBinaryString(self, nums: List[str]) -> str: + strSet = {s for s in nums} + + def backtrack(i, cur): + if i == len(nums): + res = "".join(cur) + return None if res in strSet else res + + res = backtrack(i + 1, cur) + if res: return res + + cur[i] = "1" + return backtrack(i + 1, cur) + + return backtrack(0, ["0" for _ in nums]) +``` + +```java +public class Solution { + public String findDifferentBinaryString(String[] nums) { + Set strSet = new HashSet<>(); + for (String s : nums) { + strSet.add(s); + } + return backtrack(0, new char[nums.length], strSet, nums.length); + } + + private String backtrack(int i, char[] cur, Set strSet, int n) { + if (i == n) { + String res = new String(cur); + return strSet.contains(res) ? null : res; + } + + cur[i] = '0'; + String res = backtrack(i + 1, cur, strSet, n); + if (res != null) return res; + + cur[i] = '1'; + return backtrack(i + 1, cur, strSet, n); + } +} +``` + +```cpp +class Solution { +public: + string findDifferentBinaryString(vector& nums) { + unordered_set strSet(nums.begin(), nums.end()); + string cur(nums.size(), '0'); + return backtrack(0, cur, strSet, nums.size()); + } + +private: + string backtrack(int i, string& cur, unordered_set& strSet, int n) { + if (i == n) { + return strSet.count(cur) ? "" : cur; + } + + string res = backtrack(i + 1, cur, strSet, n); + if (!res.empty()) return res; + + cur[i] = '1'; + return backtrack(i + 1, cur, strSet, n); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @return {string} + */ + findDifferentBinaryString(nums) { + const strSet = new Set(nums); + const n = nums.length; + + const backtrack = (i, cur) => { + if (i === n) { + const res = cur.join(''); + return strSet.has(res) ? null : res; + } + + let res = backtrack(i + 1, cur); + if (res) return res; + + cur[i] = '1'; + return backtrack(i + 1, cur); + }; + + return backtrack(0, Array(n).fill('0')); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 2. Backtracking (Iteration) + +::tabs-start + +```python +class Solution: + def findDifferentBinaryString(self, nums: List[str]) -> str: + strSet = set(nums) + n = len(nums) + + for num in range(1 << n): + res = bin(num)[2:].zfill(n) + if res not in strSet: + return res + + return "" +``` + +```java +public class Solution { + public String findDifferentBinaryString(String[] nums) { + Set strSet = new HashSet<>(); + for (String s : nums) { + strSet.add(s); + } + int n = nums.length; + + for (int num = 0; num < (n + 1); num++) { + String res = String.format("%" + n + "s", + Integer.toBinaryString(num)).replace(' ', '0'); + if (!strSet.contains(res)) { + return res; + } + } + + return ""; + } +} +``` + +```cpp +class Solution { +public: + string findDifferentBinaryString(vector& nums) { + unordered_set strSet(nums.begin(), nums.end()); + int n = nums.size(); + + for (int num = 0; num < (n + 1); num++) { + string res = toBinaryString(num, n); + if (strSet.find(res) == strSet.end()) { + return res; + } + } + + return ""; + } + +private: + string toBinaryString(int num, int length) { + string res = ""; + for (int i = length - 1; i >= 0; i--) { + res += (num & (1 << i)) ? '1' : '0'; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @return {string} + */ + findDifferentBinaryString(nums) { + const strSet = new Set(nums); + const n = nums.length; + + for (let num = 0; num < n + 1; num++) { + let res = num.toString(2).padStart(n, '0'); + if (!strSet.has(res)) { + return res; + } + } + + return ''; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 3. Cantor's Diagonal Argument + +::tabs-start + +```python +class Solution: + def findDifferentBinaryString(self, nums: List[str]) -> str: + res = [] + for i in range(len(nums)): + if nums[i][i] == '0': + res.append('1') + else: + res.append('0') + return "".join(res) +``` + +```java +public class Solution { + public String findDifferentBinaryString(String[] nums) { + StringBuilder res = new StringBuilder(); + for (int i = 0; i < nums.length; i++) { + res.append(nums[i].charAt(i) == '0' ? '1' : '0'); + } + return res.toString(); + } +} +``` + +```cpp +class Solution { +public: + string findDifferentBinaryString(vector& nums) { + string res; + for (int i = 0; i < nums.size(); i++) { + res += (nums[i][i] == '0') ? '1' : '0'; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @return {string} + */ + findDifferentBinaryString(nums) { + let res = []; + for (let i = 0; i < nums.length; i++) { + res.push(nums[i][i] === '0' ? '1' : '0'); + } + return res.join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output string. + +--- + +## 4. Randomization + +::tabs-start + +```python +class Solution: + def findDifferentBinaryString(self, nums: List[str]) -> str: + strSet = set(nums) + n = len(nums) + + while True: + res = "".join(random.choice("01") for _ in range(n)) + if res not in strSet: + return res +``` + +```java +public class Solution { + public String findDifferentBinaryString(String[] nums) { + Set strSet = new HashSet<>(); + for (String s : nums) { + strSet.add(s); + } + int n = nums.length; + Random random = new Random(); + + while (true) { + StringBuilder res = new StringBuilder(); + for (int i = 0; i < n; i++) { + res.append(random.nextBoolean() ? '1' : '0'); + } + String result = res.toString(); + if (!strSet.contains(result)) { + return result; + } + } + } +} +``` + +```cpp +class Solution { +public: + string findDifferentBinaryString(vector& nums) { + unordered_set strSet(nums.begin(), nums.end()); + int n = nums.size(); + + while (true) { + string res = ""; + for (int i = 0; i < n; i++) { + res += (rand() % 2) ? '1' : '0'; + } + if (strSet.find(res) == strSet.end()) { + return res; + } + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} nums + * @return {string} + */ + findDifferentBinaryString(nums) { + const strSet = new Set(nums); + const n = nums.length; + + while (true) { + let res = Array.from({ length: n }, () => + Math.random() < 0.5 ? '0' : '1', + ).join(''); + if (!strSet.has(res)) { + return res; + } + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(∞)$ in worst case. +- Space complexity: $O(n)$ + +--- + +## 5. Trie + +::tabs-start + +```python +class Node: + def __init__(self): + self.children = [None, None] + + def contains_bit(self, bit: int) -> bool: + return self.children[bit] is not None + + def put(self, bit: int): + self.children[bit] = Node() + + def get(self, bit: int): + return self.children[bit] + +class Trie: + def __init__(self): + self.root = Node() + + def insert(self, s: str): + curr = self.root + for c in s: + bit = int(c) + if not curr.contains_bit(bit): + curr.put(bit) + curr = curr.get(bit) + + def search(self, res: str, curr) -> bool: + while curr.contains_bit(0) or curr.contains_bit(1): + if not curr.contains_bit(0): + res.append('0') + return True + if not curr.contains_bit(1): + res.append('1') + return True + + res.append('1') + curr = curr.get(1) + + return False + +class Solution: + def findDifferentBinaryString(self, nums: List[str]) -> str: + trie = Trie() + for s in nums: + trie.insert(s) + + res = [] + trie.search(res, trie.root) + + while len(res) < len(nums): + res.append('1') + + return ''.join(res) +``` + +```java +class Node { + Node[] children; + + Node() { + this.children = new Node[2]; + } + + boolean containsBit(int bit) { + return this.children[bit] != null; + } + + void put(int bit) { + this.children[bit] = new Node(); + } + + Node get(int bit) { + return this.children[bit]; + } +} + +class Trie { + Node root; + + Trie() { + this.root = new Node(); + } + + void insert(String s) { + Node curr = root; + for (char c : s.toCharArray()) { + int bit = c - '0'; + if (!curr.containsBit(bit)) { + curr.put(bit); + } + curr = curr.get(bit); + } + } + + boolean search(StringBuilder res, Node curr) { + while (curr.containsBit(0) || curr.containsBit(1)) { + if (!curr.containsBit(0)) { + res.append('0'); + return true; + } + if (!curr.containsBit(1)) { + res.append('1'); + return true; + } + + res.append('1'); + curr = curr.get(1); + } + + return false; + } +} + +public class Solution { + public String findDifferentBinaryString(String[] nums) { + Trie trie = new Trie(); + for (String s : nums) { + trie.insert(s); + } + + StringBuilder res = new StringBuilder(); + trie.search(res, trie.root); + + while (res.length() < nums.length) { + res.append('1'); + } + + return res.toString(); + } +} +``` + +```cpp +class Node { +public: + Node *children[2]; + + Node() { + this->children[0] = nullptr; + this->children[1] = nullptr; + } + + bool containsBit(int bit) { + return this->children[bit] != nullptr; + } + + void put(int bit) { + this->children[bit] = new Node(); + } + + Node* get(int bit) { + return this->children[bit]; + } +}; + +class Trie { +public: + Node* root; + + Trie() { + this->root = new Node(); + } + + void insert(const string& s) { + Node* curr = root; + for (char c : s) { + int bit = c - '0'; + if (!curr->containsBit(bit)) { + curr->put(bit); + } + curr = curr->get(bit); + } + } + + bool search(string& res, Node* curr) { + while (curr->containsBit(0) || curr->containsBit(1)) { + if (!curr->containsBit(0)) { + res += '0'; + return true; + } + if (!curr->containsBit(1)) { + res += '1'; + return true; + } + + res += '1'; + curr = curr->get(1); + } + + return false; + } +}; + +class Solution { +public: + string findDifferentBinaryString(vector& nums) { + Trie trie; + for (const string& s : nums) { + trie.insert(s); + } + + string res; + trie.search(res, trie.root); + + while (res.length() < nums.size()) { + res += '1'; + } + + return res; + } +}; +``` + +```javascript +class Node { + constructor() { + this.children = [null, null]; + } + + /** + * @param {number} bit + * @return {boolean} + */ + containsBit(bit) { + return this.children[bit] !== null; + } + + /** + * @param {number} bit + */ + put(bit) { + this.children[bit] = new Node(); + } + + /** + * @param {number} bit + * @return {Node} + */ + get(bit) { + return this.children[bit]; + } +} + +class Trie { + constructor() { + this.root = new Node(); + } + + /** + * @param {string} s + */ + insert(s) { + let curr = this.root; + for (const c of s) { + let bit = c === '1' ? 1 : 0; + if (!curr.containsBit(bit)) { + curr.put(bit); + } + curr = curr.get(bit); + } + } + + /** + * @param {string[]} res + * @param {Node} curr + * @return {boolean} + */ + search(res, curr) { + while (curr.containsBit(0) || curr.containsBit(1)) { + if (!curr.containsBit(0)) { + res.push('0'); + return true; + } + if (!curr.containsBit(1)) { + res.push('1'); + return true; + } + + res.push('1'); + curr = curr.get(1); + } + return false; + } +} + +class Solution { + /** + * @param {string[]} nums + * @return {string} + */ + findDifferentBinaryString(nums) { + let trie = new Trie(); + for (const s of nums) { + trie.insert(s); + } + + let res = []; + trie.search(res, trie.root); + + while (res.length < nums.length) { + res.push('1'); + } + + return res.join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ diff --git a/articles/find-words-that-can-be-formed-by-characters.md b/articles/find-words-that-can-be-formed-by-characters.md index 4dfdf7b44..b343dac24 100644 --- a/articles/find-words-that-can-be-formed-by-characters.md +++ b/articles/find-words-that-can-be-formed-by-characters.md @@ -7,7 +7,7 @@ class Solution: def countCharacters(self, words: List[str], chars: str) -> int: count = Counter(chars) res = 0 - + for w in words: cur_word = Counter(w) good = True @@ -117,8 +117,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + (m * k))$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(n + (m * k))$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. > Where $n$ is the length of $chars$, $m$ is the number of words and $k$ is the average length of each word. @@ -133,7 +133,7 @@ class Solution: def countCharacters(self, words: List[str], chars: str) -> int: count = Counter(chars) res = 0 - + for w in words: cur_word = defaultdict(int) good = True @@ -238,8 +238,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + (m * k))$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(n + (m * k))$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. > Where $n$ is the length of $chars$, $m$ is the number of words and $k$ is the average length of each word. @@ -255,10 +255,10 @@ class Solution: count = [0] * 26 for c in chars: count[ord(c) - ord('a')] += 1 - + org = count[:] res = 0 - + for w in words: good = True for c in w: @@ -282,10 +282,10 @@ public class Solution { for (char c : chars.toCharArray()) { count[c - 'a']++; } - + int[] org = count.clone(); int res = 0; - + for (String w : words) { boolean good = true; for (int i = 0; i < w.length(); i++) { @@ -316,10 +316,10 @@ public: for (char c : chars) { count[c - 'a']++; } - + vector org = count; int res = 0; - + for (string& w : words) { bool good = true; for (char& c : w) { @@ -354,10 +354,10 @@ class Solution { for (let c of chars) { count[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; } - + const org = [...count]; let res = 0; - + for (let w of words) { let good = true; for (let c of w) { @@ -368,7 +368,7 @@ class Solution { break; } } - + if (good) { res += w.length; } @@ -385,7 +385,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + (m * k))$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(n + (m * k))$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. -> Where $n$ is the length of $chars$, $m$ is the number of words and $k$ is the average length of each word. \ No newline at end of file +> Where $n$ is the length of $chars$, $m$ is the number of words and $k$ is the average length of each word. diff --git a/articles/first-bad-version.md b/articles/first-bad-version.md new file mode 100644 index 000000000..40a7ff574 --- /dev/null +++ b/articles/first-bad-version.md @@ -0,0 +1,376 @@ +## 1. Brute Force (Linear Search) + +::tabs-start + +```python +# The isBadVersion API is already defined for you. +# def isBadVersion(version: int) -> bool: + +class Solution: + def firstBadVersion(self, n: int) -> int: + for i in range(1, n): + if isBadVersion(i): + return i + return n +``` + +```java +/* The isBadVersion API is defined in the parent class VersionControl. + boolean isBadVersion(int version); */ + +public class Solution extends VersionControl { + public int firstBadVersion(int n) { + for (int i = 1; i < n; i++) { + if (isBadVersion(i)) { + return i; + } + } + return n; + } +} +``` + +```cpp +// The API isBadVersion is defined for you. +// bool isBadVersion(int version); + +class Solution { +public: + int firstBadVersion(int n) { + for (int i = 1; i < n; i++) { + if (isBadVersion(i)) { + return i; + } + } + return n; + } +}; +``` + +```javascript +// The isBadVersion API is already defined in the VersionControl class. +// isBadVersion(version: number): boolean + +class Solution extends VersionControl { + /** + * @param {number} n Total versions + * @return {number} The first bad version + */ + firstBadVersion(n) { + for (let i = 1; i < n; i++) { + if (this.isBadVersion(i)) { + return i; + } + } + return n; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 2. Recursive Binary Search + +::tabs-start + +```python +# The isBadVersion API is already defined for you. +# def isBadVersion(version: int) -> bool: + +class Solution: + def firstBadVersion(self, n: int) -> int: + def helper(l, r): + if l > r: + return l + m = l + (r - l) // 2 + if isBadVersion(m): + return helper(l, m - 1) + else: + return helper(m + 1, r) + + return helper(1, n) +``` + +```java +/* The isBadVersion API is defined in the parent class VersionControl. + boolean isBadVersion(int version); */ + +public class Solution extends VersionControl { + public int firstBadVersion(int n) { + return helper(1, n); + } + + private int helper(int l, int r) { + if (l > r) { + return l; + } + int m = l + (r - l) / 2; + if (isBadVersion(m)) { + return helper(l, m - 1); + } else { + return helper(m + 1, r); + } + } +} +``` + +```cpp +// The API isBadVersion is defined for you. +// bool isBadVersion(int version); + +class Solution { +public: + int firstBadVersion(int n) { + return helper(1, n); + } + +private: + int helper(int l, int r) { + if (l > r) { + return l; + } + int m = l + (r - l) / 2; + if (isBadVersion(m)) { + return helper(l, m - 1); + } else { + return helper(m + 1, r); + } + } +}; +``` + +```javascript +// The isBadVersion API is already defined in the VersionControl class. +// isBadVersion(version: number): boolean + +class Solution extends VersionControl { + /** + * @param {number} n Total versions + * @return {number} The first bad version + */ + firstBadVersion(n) { + const helper = (l, r) => { + if (l > r) { + return l; + } + const m = Math.floor(l + (r - l) / 2); + if (this.isBadVersion(m)) { + return helper(l, m - 1); + } else { + return helper(m + 1, r); + } + }; + return helper(1, n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(\log n)$ for recursion stack. + +--- + +## 3. Iterative Binary Search + +::tabs-start + +```python +# The isBadVersion API is already defined for you. +# def isBadVersion(version: int) -> bool: + +class Solution: + def firstBadVersion(self, n: int) -> int: + l, r = 1, n + res = -1 + while l <= r: + m = l + (r - l) // 2 + if isBadVersion(m): + res = m + r = m - 1 + else: + l = m + 1 + return res +``` + +```java +/* The isBadVersion API is defined in the parent class VersionControl. + boolean isBadVersion(int version); */ + +public class Solution extends VersionControl { + public int firstBadVersion(int n) { + int l = 1, r = n, res = -1; + while (l <= r) { + int m = l + (r - l) / 2; + if (isBadVersion(m)) { + res = m; + r = m - 1; + } else { + l = m + 1; + } + } + return res; + } +} +``` + +```cpp +// The API isBadVersion is defined for you. +// bool isBadVersion(int version); + +class Solution { +public: + int firstBadVersion(int n) { + int l = 1, r = n, res = -1; + while (l <= r) { + int m = l + (r - l) / 2; + if (isBadVersion(m)) { + res = m; + r = m - 1; + } else { + l = m + 1; + } + } + return res; + } +}; +``` + +```javascript +// The isBadVersion API is already defined in the VersionControl class. +// isBadVersion(version: number): boolean + +class Solution extends VersionControl { + /** + * @param {number} n Total versions + * @return {number} The first bad version + */ + firstBadVersion(n) { + let l = 1, + r = n, + res = -1; + while (l <= r) { + const m = Math.floor(l + (r - l) / 2); + if (this.isBadVersion(m)) { + res = m; + r = m - 1; + } else { + l = m + 1; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ + +--- + +## 4. Iterative Binary Search (Lower Bound) + +::tabs-start + +```python +# The isBadVersion API is already defined for you. +# def isBadVersion(version: int) -> bool: + +class Solution: + def firstBadVersion(self, n: int) -> int: + l, r = 1, n + while l < r: + m = l + (r - l) // 2 + if isBadVersion(m): + r = m + else: + l = m + 1 + return l +``` + +```java +/* The isBadVersion API is defined in the parent class VersionControl. + boolean isBadVersion(int version); */ + +public class Solution extends VersionControl { + public int firstBadVersion(int n) { + int l = 1, r = n; + while (l < r) { + int m = l + (r - l) / 2; + if (isBadVersion(m)) { + r = m; + } else { + l = m + 1; + } + } + return r; + } +} +``` + +```cpp +// The API isBadVersion is defined for you. +// bool isBadVersion(int version); + +class Solution { +public: + int firstBadVersion(int n) { + int l = 1, r = n; + while (l < r) { + int m = l + (r - l) / 2; + if (isBadVersion(m)) { + r = m; + } else { + l = m + 1; + } + } + return r; + } +}; +``` + +```javascript +// The isBadVersion API is already defined in the VersionControl class. +// isBadVersion(version: number): boolean + +class Solution extends VersionControl { + /** + * @param {number} n Total versions + * @return {number} The first bad version + */ + firstBadVersion(n) { + let l = 1, + r = n; + while (l < r) { + const m = Math.floor(l + (r - l) / 2); + if (this.isBadVersion(m)) { + r = m; + } else { + l = m + 1; + } + } + return r; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/first-missing-positive.md b/articles/first-missing-positive.md index f0bef0643..d9b2c5fc2 100644 --- a/articles/first-missing-positive.md +++ b/articles/first-missing-positive.md @@ -15,7 +15,7 @@ class Solution: if flag: return missing - missing += 1 + missing += 1 ``` ```java @@ -80,12 +80,37 @@ class Solution { } ``` +```csharp +public class Solution { + public int FirstMissingPositive(int[] nums) { + int missing = 1; + + while (true) { + bool found = false; + + foreach (int num in nums) { + if (num == missing) { + found = true; + break; + } + } + + if (!found) { + return missing; + } + + missing++; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -101,11 +126,11 @@ class Solution: for num in nums: if num > 0 and num <= n: seen[num - 1] = True - + for num in range(1, n + 1): if not seen[num - 1]: return num - + return n + 1 ``` @@ -114,19 +139,19 @@ public class Solution { public int firstMissingPositive(int[] nums) { int n = nums.length; boolean[] seen = new boolean[n]; - + for (int num : nums) { if (num > 0 && num <= n) { seen[num - 1] = true; } } - + for (int i = 0; i < n; i++) { if (!seen[i]) { return i + 1; } } - + return n + 1; } } @@ -138,19 +163,19 @@ public: int firstMissingPositive(vector& nums) { int n = nums.size(); vector seen(n, false); - + for (int num : nums) { if (num > 0 && num <= n) { seen[num - 1] = true; } } - + for (int i = 0; i < n; i++) { if (!seen[i]) { return i + 1; } } - + return n + 1; } }; @@ -165,19 +190,42 @@ class Solution { firstMissingPositive(nums) { const n = nums.length; const seen = new Array(n).fill(false); - + for (const num of nums) { if (num > 0 && num <= n) { seen[num - 1] = true; } } - + for (let i = 0; i < n; i++) { if (!seen[i]) { return i + 1; } } - + + return n + 1; + } +} +``` + +```csharp +public class Solution { + public int FirstMissingPositive(int[] nums) { + int n = nums.Length; + bool[] seen = new bool[n]; + + foreach (int num in nums) { + if (num > 0 && num <= n) { + seen[num - 1] = true; + } + } + + for (int num = 1; num <= n; num++) { + if (!seen[num - 1]) { + return num; + } + } + return n + 1; } } @@ -187,8 +235,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -257,12 +305,29 @@ class Solution { } ``` +```csharp +public class Solution { + public int FirstMissingPositive(int[] nums) { + Array.Sort(nums); + int missing = 1; + + foreach (int num in nums) { + if (num > 0 && num == missing) { + missing++; + } + } + + return missing; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -396,12 +461,45 @@ class Solution { } ``` +```csharp +public class Solution { + public int FirstMissingPositive(int[] nums) { + int n = nums.Length; + + for (int i = 0; i < n; i++) { + if (nums[i] < 0) { + nums[i] = 0; + } + } + + for (int i = 0; i < n; i++) { + int val = Math.Abs(nums[i]); + if (val >= 1 && val <= n) { + if (nums[val - 1] > 0) { + nums[val - 1] *= -1; + } else if (nums[val - 1] == 0) { + nums[val - 1] = -(n + 1); + } + } + } + + for (int i = 0; i < n; i++) { + if (nums[i] >= 0) { + return i + 1; + } + } + + return n + 1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -418,7 +516,7 @@ class Solution: if nums[i] <= 0 or nums[i] > n: i += 1 continue - + index = nums[i] - 1 if nums[i] != nums[index]: nums[i], nums[index] = nums[index], nums[i] @@ -528,9 +626,42 @@ class Solution { } ``` +```csharp +public class Solution { + public int FirstMissingPositive(int[] nums) { + int n = nums.Length; + int i = 0; + + while (i < n) { + if (nums[i] <= 0 || nums[i] > n) { + i++; + continue; + } + + int index = nums[i] - 1; + if (nums[i] != nums[index]) { + int temp = nums[i]; + nums[i] = nums[index]; + nums[index] = temp; + } else { + i++; + } + } + + for (i = 0; i < n; i++) { + if (nums[i] != i + 1) { + return i + 1; + } + } + + return n + 1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/first-unique-character-in-a-string.md b/articles/first-unique-character-in-a-string.md index b60c2e4f6..7fbb67baa 100644 --- a/articles/first-unique-character-in-a-string.md +++ b/articles/first-unique-character-in-a-string.md @@ -84,8 +84,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -99,7 +99,7 @@ class Solution: count = defaultdict(int) for c in s: count[c] += 1 - + for i, c in enumerate(s): if count[c] == 1: return i @@ -132,7 +132,7 @@ public: for (char c : s) { count[c]++; } - + for (int i = 0; i < s.size(); i++) { if (count[s[i]] == 1) { return i; @@ -169,8 +169,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. --- @@ -188,7 +188,7 @@ class Solution: count[c] = i else: count[c] = n - + res = n for c in count: res = min(res, count[c]) @@ -201,7 +201,7 @@ public class Solution { public int firstUniqChar(String s) { int n = s.length(); Map count = new HashMap<>(); - + for (int i = 0; i < n; i++) { char c = s.charAt(i); if (!count.containsKey(c)) { @@ -210,12 +210,12 @@ public class Solution { count.put(c, n); } } - + int res = n; for (int index : count.values()) { res = Math.min(res, index); } - + return res == n ? -1 : res; } } @@ -235,12 +235,12 @@ public: count[s[i]] = n; } } - + int res = n; for (auto& [key, index] : count) { res = min(res, index); } - + return res == n ? -1 : res; } }; @@ -279,8 +279,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. --- @@ -361,5 +361,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(26 * n)$ since we have at most $26$ different characters. -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(26 * n)$ since we have at most $26$ different characters. +- Space complexity: $O(1)$ diff --git a/articles/flatten-nested-list-iterator.md b/articles/flatten-nested-list-iterator.md new file mode 100644 index 000000000..8a02655a7 --- /dev/null +++ b/articles/flatten-nested-list-iterator.md @@ -0,0 +1,579 @@ +## 1. Recursion (Flatten And Store Into Global List ) + +::tabs-start + +```python +class NestedIterator: + def __init__(self, nestedList): + self.arr = [] + self.ptr = 0 + self.dfs(nestedList) + + def next(self): + val = self.arr[self.ptr] + self.ptr += 1 + return val + + def hasNext(self): + return self.ptr < len(self.arr) + + def dfs(self, nestedArr): + for num in nestedArr: + if num.isInteger(): + self.arr.append(num.getInteger()) + else: + self.dfs(num.getList()) +``` + +```java +public class NestedIterator implements Iterator { + + private List arr; + private int ptr; + + public NestedIterator(List nestedList) { + arr = new ArrayList<>(); + ptr = 0; + dfs(nestedList); + } + + @Override + public Integer next() { + return arr.get(ptr++); + } + + @Override + public boolean hasNext() { + return ptr < arr.size(); + } + + private void dfs(List nestedArr) { + for (NestedInteger num : nestedArr) { + if (num.isInteger()) { + arr.add(num.getInteger()); + } else { + dfs(num.getList()); + } + } + } +} +``` + +```cpp +class NestedIterator { +private: + vector arr; + int ptr; + + void dfs(const vector &nestedArr) { + for (const auto &num : nestedArr) { + if (num.isInteger()) { + arr.push_back(num.getInteger()); + } else { + dfs(num.getList()); + } + } + } + +public: + NestedIterator(vector &nestedList) { + ptr = 0; + dfs(nestedList); + } + + int next() { + return arr[ptr++]; + } + + bool hasNext() { + return ptr < arr.size(); + } +}; +``` + +```javascript +class NestedIterator { + /** + * @constructor + * @param {NestedInteger[]} nestedList + */ + constructor(nestedList) { + this.arr = []; + this.ptr = 0; + this.dfs(nestedList); + } + + /** + * @param {NestedInteger[]} nestedArr + */ + dfs(nestedArr) { + for (let num of nestedArr) { + if (num.isInteger()) { + this.arr.push(num.getInteger()); + } else { + this.dfs(num.getList()); + } + } + } + + /** + * @this NestedIterator + * @returns {integer} + */ + next() { + return this.arr[this.ptr++]; + } + + /** + * @this NestedIterator + * @returns {boolean} + */ + hasNext() { + return this.ptr < this.arr.length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + d)$ +- Space complexity: $O(n + d)$ + +> Where $n$ is the number of integers and $d$ is the nesting depth. + +--- + +## 2. Recursion (Flatten And Return) + +::tabs-start + +```python +class NestedIterator: + def __init__(self, nestedList): + self.arr = self.dfs(nestedList) + self.ptr = 0 + + def dfs(self, nestedArr): + res = [] + for num in nestedArr: + if num.isInteger(): + res.append(num.getInteger()) + else: + res.extend(self.dfs(num.getList())) + return res + + def next(self): + val = self.arr[self.ptr] + self.ptr += 1 + return val + + def hasNext(self): + return self.ptr < len(self.arr) +``` + +```java +public class NestedIterator implements Iterator { + private List arr; + private int ptr; + + public NestedIterator(List nestedList) { + arr = dfs(nestedList); + ptr = 0; + } + + private List dfs(List nestedArr) { + List res = new ArrayList<>(); + for (NestedInteger num : nestedArr) { + if (num.isInteger()) { + res.add(num.getInteger()); + } else { + res.addAll(dfs(num.getList())); + } + } + return res; + } + + @Override + public Integer next() { + return arr.get(ptr++); + } + + @Override + public boolean hasNext() { + return ptr < arr.size(); + } +} +``` + +```cpp +class NestedIterator { +private: + vector arr; + int ptr; + + vector dfs(const vector &nestedArr) { + vector res; + for (const auto &num : nestedArr) { + if (num.isInteger()) { + res.push_back(num.getInteger()); + } else { + vector temp = dfs(num.getList()); + res.insert(res.end(), temp.begin(), temp.end()); + } + } + return res; + } + +public: + NestedIterator(vector &nestedList) { + arr = dfs(nestedList); + ptr = 0; + } + + int next() { + return arr[ptr++]; + } + + bool hasNext() { + return ptr < arr.size(); + } +}; +``` + +```javascript +class NestedIterator { + /** + * @constructor + * @param {NestedInteger[]} nestedList + */ + constructor(nestedList) { + this.arr = this.dfs(nestedList); + this.ptr = 0; + } + + /** + * @param {NestedInteger[]} nestedArr + */ + dfs(nestedArr) { + let res = []; + for (let num of nestedArr) { + if (num.isInteger()) { + res.push(num.getInteger()); + } else { + res.push(...this.dfs(num.getList())); + } + } + return res; + } + + /** + * @this NestedIterator + * @returns {integer} + */ + next() { + return this.arr[this.ptr++]; + } + + /** + * @this NestedIterator + * @returns {boolean} + */ + hasNext() { + return this.ptr < this.arr.length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + d)$ +- Space complexity: $O(n + d)$ + +> Where $n$ is the number of integers and $d$ is the nesting depth. + +--- + +## 3. Recursion + Stack + +::tabs-start + +```python +class NestedIterator: + def __init__(self, nestedList: [NestedInteger]): + self.stack = [] + self.dfs(nestedList) + self.stack.reverse() + + def next(self) -> int: + return self.stack.pop() + + def hasNext(self) -> bool: + return len(self.stack) > 0 + + def dfs(self, nested): + for num in nested: + if num.isInteger(): + self.stack.append(num.getInteger()) + else: + self.dfs(num.getList()) +``` + +```java +public class NestedIterator implements Iterator { + private Stack stack; + + public NestedIterator(List nestedList) { + stack = new Stack<>(); + dfs(nestedList); + Collections.reverse(stack); + } + + private void dfs(List nested) { + for (NestedInteger num : nested) { + if (num.isInteger()) { + stack.push(num.getInteger()); + } else { + dfs(num.getList()); + } + } + } + + @Override + public Integer next() { + return stack.pop(); + } + + @Override + public boolean hasNext() { + return !stack.isEmpty(); + } +} +``` + +```cpp +class NestedIterator { +private: + vector stack; + + void dfs(const vector &nested) { + for (const auto &num : nested) { + if (num.isInteger()) { + stack.push_back(num.getInteger()); + } else { + dfs(num.getList()); + } + } + } + +public: + NestedIterator(vector &nestedList) { + dfs(nestedList); + reverse(stack.begin(), stack.end()); + } + + int next() { + int val = stack.back(); + stack.pop_back(); + return val; + } + + bool hasNext() { + return !stack.empty(); + } +}; +``` + +```javascript +class NestedIterator { + /** + * @constructor + * @param {NestedInteger[]} nestedList + */ + constructor(nestedList) { + this.stack = []; + this.dfs(nestedList); + this.stack.reverse(); + } + + /** + * @param {NestedInteger[]} nested + */ + dfs(nested) { + for (let num of nested) { + if (num.isInteger()) { + this.stack.push(num.getInteger()); + } else { + this.dfs(num.getList()); + } + } + } + + /** + * @this NestedIterator + * @returns {number} + */ + next() { + return this.stack.pop(); + } + + /** + * @this NestedIterator + * @returns {boolean} + */ + hasNext() { + return this.stack.length > 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + d)$ +- Space complexity: $O(n + d)$ + +> Where $n$ is the number of integers and $d$ is the nesting depth. + +--- + +## 4. Stack + +::tabs-start + +```python +class NestedIterator: + def __init__(self, nestedList: [NestedInteger]): + self.stack = nestedList + self.stack.reverse() + + def next(self) -> int: + return self.stack.pop().getInteger() + + def hasNext(self) -> bool: + while self.stack: + top = self.stack[-1] + if top.isInteger(): + return True + + self.stack.pop() + self.stack.extend(reversed(top.getList())) + return False +``` + +```java +public class NestedIterator implements Iterator { + private List stack; + + public NestedIterator(List nestedList) { + stack = new ArrayList<>(nestedList); + Collections.reverse(stack); + } + + @Override + public Integer next() { + return stack.remove(stack.size() - 1).getInteger(); + } + + @Override + public boolean hasNext() { + while (!stack.isEmpty()) { + NestedInteger top = stack.get(stack.size() - 1); + if (top.isInteger()) { + return true; + } + stack.remove(stack.size() - 1); + List nestedList = top.getList(); + Collections.reverse(nestedList); + stack.addAll(nestedList); + } + return false; + } +} +``` + +```cpp +class NestedIterator { +private: + vector stack; + +public: + NestedIterator(vector &nestedList) { + stack = nestedList; + reverse(stack.begin(), stack.end()); + } + + int next() { + int val = stack.back().getInteger(); + stack.pop_back(); + return val; + } + + bool hasNext() { + while (!stack.empty()) { + NestedInteger top = stack.back(); + if (top.isInteger()) { + return true; + } + stack.pop_back(); + vector nestedList = top.getList(); + for (auto it = nestedList.rbegin(); it != nestedList.rend(); ++it) { + stack.push_back(*it); + } + } + return false; + } +}; +``` + +```javascript +class NestedIterator { + /** + * @constructor + * @param {NestedInteger[]} nestedList + */ + constructor(nestedList) { + this.stack = nestedList; + this.stack.reverse(); + } + + /** + * @this NestedIterator + * @returns {number} + */ + next() { + return this.stack.pop().getInteger(); + } + + /** + * @this NestedIterator + * @returns {boolean} + */ + hasNext() { + while (this.stack.length > 0) { + const top = this.stack[this.stack.length - 1]; + if (top.isInteger()) { + return true; + } + this.stack.pop(); + const nestedList = top.getList(); + nestedList.reverse(); + this.stack.push(...nestedList); + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + d)$ +- Space complexity: $O(n)$ + +> Where $n$ is the number of integers and $d$ is the nesting depth. diff --git a/articles/flip-equivalent-binary-trees.md b/articles/flip-equivalent-binary-trees.md new file mode 100644 index 000000000..39f315bc3 --- /dev/null +++ b/articles/flip-equivalent-binary-trees.md @@ -0,0 +1,498 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def flipEquiv(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool: + if not root1 or not root2: + return not root1 and not root2 + if root1.val != root2.val: + return False + + return ( + self.flipEquiv(root1.left, root2.left) and + self.flipEquiv(root1.right, root2.right) or + self.flipEquiv(root1.left, root2.right) and + self.flipEquiv(root1.right, root2.left) + ) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean flipEquiv(TreeNode root1, TreeNode root2) { + if (root1 == null || root2 == null) + return root1 == null && root2 == null; + if (root1.val != root2.val) + return false; + + return (flipEquiv(root1.left, root2.left) && + flipEquiv(root1.right, root2.right) || + flipEquiv(root1.left, root2.right) && + flipEquiv(root1.right, root2.left)); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool flipEquiv(TreeNode* root1, TreeNode* root2) { + if (!root1 || !root2) + return !root1 && !root2; + if (root1->val != root2->val) + return false; + + return (flipEquiv(root1->left, root2->left) && + flipEquiv(root1->right, root2->right) || + flipEquiv(root1->left, root2->right) && + flipEquiv(root1->right, root2->left)); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root1 + * @param {TreeNode} root2 + * @return {boolean} + */ + flipEquiv(root1, root2) { + if (!root1 || !root2) return !root1 && !root2; + if (root1.val !== root2.val) return false; + + return ( + (this.flipEquiv(root1.left, root2.left) && + this.flipEquiv(root1.right, root2.right)) || + (this.flipEquiv(root1.left, root2.right) && + this.flipEquiv(root1.right, root2.left)) + ); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def flipEquiv(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool: + q = deque([(root1, root2)]) + + while q: + node1, node2 = q.popleft() + if not node1 or not node2: + if node1 != node2: + return False + continue + + if node1.val != node2.val: + return False + + if ((node1.right and node2.right and + node1.right.val == node2.right.val) or + (not node1.right and not node2.right) + ): + q.append((node1.left, node2.left)) + q.append((node1.right, node2.right)) + else: + q.append((node1.left, node2.right)) + q.append((node1.right, node2.left)) + + return True +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean flipEquiv(TreeNode root1, TreeNode root2) { + Queue q = new LinkedList<>(); + q.offer(new TreeNode[]{root1, root2}); + + while (!q.isEmpty()) { + TreeNode[] pair = q.poll(); + TreeNode node1 = pair[0], node2 = pair[1]; + + if (node1 == null || node2 == null) { + if (node1 != node2) return false; + continue; + } + + if (node1.val != node2.val) return false; + + if ((node1.left != null && node2.left != null && + node1.left.val == node2.left.val) || + (node1.left == null && node2.left == null)) { + q.offer(new TreeNode[]{node1.left, node2.left}); + q.offer(new TreeNode[]{node1.right, node2.right}); + } else { + q.offer(new TreeNode[]{node1.left, node2.right}); + q.offer(new TreeNode[]{node1.right, node2.left}); + } + } + + return true; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool flipEquiv(TreeNode* root1, TreeNode* root2) { + queue> q; + q.push({root1, root2}); + + while (!q.empty()) { + auto [node1, node2] = q.front(); + q.pop(); + + if (!node1 || !node2) { + if (node1 != node2) return false; + continue; + } + + if (node1->val != node2->val) return false; + + if ((node1->left && node2->left && node1->left->val == node2->left->val) || + (!node1->left && !node2->left)) { + q.push({node1->left, node2->left}); + q.push({node1->right, node2->right}); + } else { + q.push({node1->left, node2->right}); + q.push({node1->right, node2->left}); + } + } + + return true; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root1 + * @param {TreeNode} root2 + * @return {boolean} + */ + flipEquiv(root1, root2) { + let q = new Queue([[root1, root2]]); + + while (!q.isEmpty()) { + let [node1, node2] = q.pop(); + + if (!node1 || !node2) { + if (node1 !== node2) return false; + continue; + } + + if (node1.val !== node2.val) return false; + + if ( + (node1.left && + node2.left && + node1.left.val === node2.left.val) || + (!node1.left && !node2.left) + ) { + q.push([node1.left, node2.left]); + q.push([node1.right, node2.right]); + } else { + q.push([node1.left, node2.right]); + q.push([node1.right, node2.left]); + } + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def flipEquiv(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool: + stack = [(root1, root2)] + + while stack: + node1, node2 = stack.pop() + + if not node1 or not node2: + if node1 != node2: + return False + continue + + if node1.val != node2.val: + return False + + if ((node1.left and node2.left and + node1.left.val == node2.left.val) or + (not node1.left and not node2.left) + ): + stack.append((node1.left, node2.left)) + stack.append((node1.right, node2.right)) + else: + stack.append((node1.left, node2.right)) + stack.append((node1.right, node2.left)) + + return True +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean flipEquiv(TreeNode root1, TreeNode root2) { + Stack stack = new Stack<>(); + stack.push(new TreeNode[]{root1, root2}); + + while (!stack.isEmpty()) { + TreeNode[] pair = stack.pop(); + TreeNode node1 = pair[0], node2 = pair[1]; + + if (node1 == null || node2 == null) { + if (node1 != node2) return false; + continue; + } + + if (node1.val != node2.val) return false; + + if ((node1.left != null && node2.left != null && + node1.left.val == node2.left.val) || + (node1.left == null && node2.left == null)) { + stack.push(new TreeNode[]{node1.left, node2.left}); + stack.push(new TreeNode[]{node1.right, node2.right}); + } else { + stack.push(new TreeNode[]{node1.left, node2.right}); + stack.push(new TreeNode[]{node1.right, node2.left}); + } + } + + return true; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool flipEquiv(TreeNode* root1, TreeNode* root2) { + stack> stk; + stk.push({root1, root2}); + + while (!stk.empty()) { + auto [node1, node2] = stk.top();stk.pop(); + + if (!node1 || !node2) { + if (node1 != node2) return false; + continue; + } + + if (node1->val != node2->val) return false; + + if ((node1->left && node2->left && node1->left->val == node2->left->val) || + (!node1->left && !node2->left)) { + stk.push({node1->left, node2->left}); + stk.push({node1->right, node2->right}); + } else { + stk.push({node1->left, node2->right}); + stk.push({node1->right, node2->left}); + } + } + + return true; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root1 + * @param {TreeNode} root2 + * @return {boolean} + */ + flipEquiv(root1, root2) { + let stack = [[root1, root2]]; + + while (stack.length > 0) { + let [node1, node2] = stack.pop(); + + if (!node1 || !node2) { + if (node1 !== node2) return false; + continue; + } + + if (node1.val !== node2.val) return false; + + if ( + (node1.left && + node2.left && + node1.left.val === node2.left.val) || + (!node1.left && !node2.left) + ) { + stack.push([node1.left, node2.left]); + stack.push([node1.right, node2.right]); + } else { + stack.push([node1.left, node2.right]); + stack.push([node1.right, node2.left]); + } + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/flip-string-to-monotone-increasing.md b/articles/flip-string-to-monotone-increasing.md index 74c357f57..255bc354e 100644 --- a/articles/flip-string-to-monotone-increasing.md +++ b/articles/flip-string-to-monotone-increasing.md @@ -12,7 +12,7 @@ class Solution: return dp[(i, mono)] if i == len(s): return 0 - + if mono and s[i] == "0": dp[(i, mono)] = min(1 + dfs(i + 1, False), dfs(i + 1, mono)) elif mono and s[i] == "1": @@ -21,7 +21,7 @@ class Solution: dp[(i, mono)] = dfs(i + 1, mono) else: dp[(i, mono)] = 1 + dfs(i + 1, mono) - + return dp[(i, mono)] return dfs(0, True) @@ -121,8 +121,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -204,7 +204,8 @@ class Solution { if (s[i] === '0') { dp[i][1] = Math.min(1 + dp[i + 1][0], dp[i + 1][1]); dp[i][0] = 1 + dp[i + 1][0]; - } else { // s[i] === '1' + } else { + // s[i] === '1' dp[i][1] = Math.min(1 + dp[i + 1][1], dp[i + 1][0]); dp[i][0] = dp[i + 1][0]; } @@ -219,8 +220,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -241,7 +242,7 @@ class Solution: else: # s[i] == '1' new_dp_1 = min(dp[1] + 1, dp[0]) new_dp_0 = dp[0] - + dp[1] = new_dp_1 dp[0] = new_dp_0 @@ -311,7 +312,8 @@ class Solution { if (s[i] === '0') { newDp1 = Math.min(1 + dp[0], dp[1]); newDp0 = dp[0] + 1; - } else { // s[i] === '1' + } else { + // s[i] === '1' newDp1 = Math.min(1 + dp[1], dp[0]); newDp0 = dp[0]; } @@ -329,8 +331,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -347,10 +349,10 @@ class Solution: for i in range(n): left_ones[i + 1] = left_ones[i] + (1 if s[i] == '1' else 0) - + for i in range(n - 1, -1, -1): right_zeros[i] = right_zeros[i + 1] + (1 if s[i] == '0' else 0) - + res = float('inf') for i in range(n + 1): res = min(res, left_ones[i] + right_zeros[i]) @@ -441,8 +443,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -502,7 +504,8 @@ class Solution { * @return {number} */ minFlipsMonoIncr(s) { - let res = 0, cntOne = 0; + let res = 0, + cntOne = 0; for (let c of s) { if (c === '1') { cntOne++; @@ -519,5 +522,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/flood-fill.md b/articles/flood-fill.md new file mode 100644 index 000000000..825e87525 --- /dev/null +++ b/articles/flood-fill.md @@ -0,0 +1,276 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]: + if image[sr][sc] == color: + return image + + m, n = len(image), len(image[0]) + dirs = [1,0,-1,0,1] + + def dfs(r, c, org): + if not (0 <= r < m) or not (0 <= c < n) or image[r][c] != org: + return + + image[r][c] = color + for d in range(4): + dfs(r + dirs[d], c + dirs[d + 1], org) + + dfs(sr, sc, image[sr][sc]) + return image +``` + +```java +public class Solution { + public int[][] floodFill(int[][] image, int sr, int sc, int color) { + int orig = image[sr][sc]; + if (orig == color) return image; + int m = image.length, n = image[0].length; + dfs(image, sr, sc, orig, color, m, n); + return image; + } + + private void dfs(int[][] image, int r, int c, int orig, int color, int m, int n) { + if (r < 0 || r >= m || c < 0 || c >= n || image[r][c] != orig) return; + image[r][c] = color; + dfs(image, r + 1, c, orig, color, m, n); + dfs(image, r - 1, c, orig, color, m, n); + dfs(image, r, c + 1, orig, color, m, n); + dfs(image, r, c - 1, orig, color, m, n); + } +} +``` + +```cpp +class Solution { +public: + vector> floodFill(vector>& image, int sr, int sc, int color) { + int orig = image[sr][sc]; + if (orig == color) return image; + m = image.size(); + n = image[0].size(); + dfs(image, sr, sc, orig, color); + return image; + } +private: + int m, n; + void dfs(vector>& image, int r, int c, int orig, int color) { + if (r < 0 || r >= m || c < 0 || c >= n || image[r][c] != orig) return; + image[r][c] = color; + dfs(image, r + 1, c, orig, color); + dfs(image, r - 1, c, orig, color); + dfs(image, r, c + 1, orig, color); + dfs(image, r, c - 1, orig, color); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} image + * @param {number} sr + * @param {number} sc + * @param {number} color + * @return {number[][]} + */ + floodFill(image, sr, sc, color) { + const orig = image[sr][sc]; + if (orig === color) return image; + const m = image.length, n = image[0].length; + const dfs = (r, c) => { + if (r < 0 || r >= m || c < 0 || c >= n || image[r][c] !== orig) return; + image[r][c] = color; + dfs(r + 1, c); + dfs(r - 1, c); + dfs(r, c + 1); + dfs(r, c - 1); + }; + dfs(sr, sc); + return image; + } +} +``` + +```csharp +public class Solution { + public int[][] FloodFill(int[][] image, int sr, int sc, int color) { + int orig = image[sr][sc]; + if (orig == color) return image; + int m = image.Length, n = image[0].Length; + DFS(image, sr, sc, orig, color, m, n); + return image; + } + + private void DFS(int[][] image, int r, int c, int orig, int color, int m, int n) { + if (r < 0 || r >= m || c < 0 || c >= n || image[r][c] != orig) return; + image[r][c] = color; + DFS(image, r + 1, c, orig, color, m, n); + DFS(image, r - 1, c, orig, color, m, n); + DFS(image, r, c + 1, orig, color, m, n); + DFS(image, r, c - 1, orig, color, m, n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns in the image. + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class Solution: + def floodFill(self, image: List[List[int]], sr: int, sc: int, color: int) -> List[List[int]]: + orig = image[sr][sc] + if orig == color: + return image + + m, n = len(image), len(image[0]) + q = deque([(sr, sc)]) + image[sr][sc] = color + dirs = [(1,0), (-1,0), (0,1), (0,-1)] + + while q: + r, c = q.popleft() + for dr, dc in dirs: + nr, nc = r + dr, c + dc + if 0 <= nr < m and 0 <= nc < n and image[nr][nc] == orig: + image[nr][nc] = color + q.append((nr, nc)) + + return image +``` + +```java +public class Solution { + public int[][] floodFill(int[][] image, int sr, int sc, int color) { + int orig = image[sr][sc]; + if (orig == color) return image; + int m = image.length, n = image[0].length; + Deque q = new ArrayDeque<>(); + q.add(new int[]{sr, sc}); + image[sr][sc] = color; + int[][] dirs = {{1,0},{-1,0},{0,1},{0,-1}}; + + while (!q.isEmpty()) { + int[] cell = q.remove(); + int r = cell[0], c = cell[1]; + for (int[] d : dirs) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nr < m && nc >= 0 && nc < n && image[nr][nc] == orig) { + image[nr][nc] = color; + q.add(new int[]{nr, nc}); + } + } + } + return image; + } +} +``` + +```cpp +class Solution { +public: + vector> floodFill(vector>& image, int sr, int sc, int color) { + int orig = image[sr][sc]; + if (orig == color) return image; + int m = image.size(), n = image[0].size(); + queue> q; + q.emplace(sr, sc); + image[sr][sc] = color; + int dirs[4][2] = {{1,0},{-1,0},{0,1},{0,-1}}; + + while (!q.empty()) { + auto [r, c] = q.front(); q.pop(); + for (auto &d : dirs) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nr < m && nc >= 0 && nc < n && image[nr][nc] == orig) { + image[nr][nc] = color; + q.emplace(nr, nc); + } + } + } + return image; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} image + * @param {number} sr + * @param {number} sc + * @param {number} color + * @return {number[][]} + */ + floodFill(image, sr, sc, color) { + const orig = image[sr][sc]; + if (orig === color) return image; + const m = image.length, n = image[0].length; + const q = new Queue([[sr, sc]]); + image[sr][sc] = color; + const dirs = [[1,0],[-1,0],[0,1],[0,-1]]; + + while (!q.isEmpty()) { + const [r, c] = q.pop(); + for (const [dr, dc] of dirs) { + const nr = r + dr, nc = c + dc; + if (nr >= 0 && nr < m && nc >= 0 && nc < n && image[nr][nc] === orig) { + image[nr][nc] = color; + q.push([nr, nc]); + } + } + } + return image; + } +} +``` + +```csharp +public class Solution { + public int[][] FloodFill(int[][] image, int sr, int sc, int color) { + int orig = image[sr][sc]; + if (orig == color) return image; + int m = image.Length, n = image[0].Length; + var q = new Queue<(int r, int c)>(); + q.Enqueue((sr, sc)); + image[sr][sc] = color; + var dirs = new (int dr, int dc)[] { (1,0), (-1,0), (0,1), (0,-1) }; + + while (q.Count > 0) { + var (r, c) = q.Dequeue(); + foreach (var (dr, dc) in dirs) { + int nr = r + dr, nc = c + dc; + if (nr >= 0 && nr < m && nc >= 0 && nc < n && image[nr][nc] == orig) { + image[nr][nc] = color; + q.Enqueue((nr, nc)); + } + } + } + return image; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns in the image. \ No newline at end of file diff --git a/articles/foreign-dictionary.md b/articles/foreign-dictionary.md index f1353b74a..89a4620fb 100644 --- a/articles/foreign-dictionary.md +++ b/articles/foreign-dictionary.md @@ -58,7 +58,7 @@ public class Solution { for (int i = 0; i < words.length - 1; i++) { String w1 = words[i], w2 = words[i + 1]; int minLen = Math.min(w1.length(), w2.length()); - if (w1.length() > w2.length() && + if (w1.length() > w2.length() && w1.substring(0, minLen).equals(w2.substring(0, minLen))) { return ""; } @@ -121,7 +121,7 @@ public: for (size_t i = 0; i < words.size() - 1; ++i) { const string& w1 = words[i], & w2 = words[i + 1]; size_t minLen = min(w1.length(), w2.length()); - if (w1.length() > w2.length() && + if (w1.length() > w2.length() && w1.substr(0, minLen) == w2.substr(0, minLen)) { return ""; } @@ -179,9 +179,11 @@ class Solution { const w1 = words[i]; const w2 = words[i + 1]; const minLen = Math.min(w1.length, w2.length); - if (w1.length > w2.length && - w1.slice(0, minLen) === w2.slice(0, minLen)) { - return ""; + if ( + w1.length > w2.length && + w1.slice(0, minLen) === w2.slice(0, minLen) + ) { + return ''; } for (let j = 0; j < minLen; j++) { if (w1[j] !== w2[j]) { @@ -208,11 +210,11 @@ class Solution { }; for (const char in adj) { - if (dfs(char)) return ""; + if (dfs(char)) return ''; } res.reverse(); - return res.join(""); + return res.join(''); } } ``` @@ -361,7 +363,7 @@ class Solution { val w1 = words[i] val w2 = words[i + 1] val minLen = minOf(w1.length, w2.length) - if (w1.length > w2.length && + if (w1.length > w2.length && w1.substring(0, minLen) == w2.substring(0, minLen)) { return "" } @@ -405,12 +407,71 @@ class Solution { } ``` +```swift +class Solution { + func foreignDictionary(_ words: [String]) -> String { + var adj = [Character: Set]() + for word in words { + for char in word { + if adj[char] == nil { + adj[char] = Set() + } + } + } + + for i in 0.. w2.count && String(w1.prefix(minLen)) == String(w2.prefix(minLen)) { + return "" + } + for j in 0.. Bool { + if let flag = visited[char] { + return flag + } + visited[char] = true + for neigh in adj[char]! { + if dfs(neigh) { + return true + } + } + visited[char] = false + res.append(char) + return false + } + + for char in adj.keys { + if dfs(char) { + return "" + } + } + + res.reverse() + return String(res) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(N + V + E)$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(N + V + E)$ +- Space complexity: $O(V + E)$ > Where $V$ is the number of unique characters, $E$ is the number of edges and $N$ is the sum of lengths of all the strings. @@ -425,7 +486,7 @@ class Solution: def foreignDictionary(self, words): adj = {c: set() for w in words for c in w} indegree = {c: 0 for c in adj} - + for i in range(len(words) - 1): w1, w2 = words[i], words[i + 1] minLen = min(len(w1), len(w2)) @@ -437,10 +498,10 @@ class Solution: adj[w1[j]].add(w2[j]) indegree[w2[j]] += 1 break - + q = deque([c for c in indegree if indegree[c] == 0]) res = [] - + while q: char = q.popleft() res.append(char) @@ -448,10 +509,10 @@ class Solution: indegree[neighbor] -= 1 if indegree[neighbor] == 0: q.append(neighbor) - + if len(res) != len(indegree): return "" - + return "".join(res) ``` @@ -460,7 +521,7 @@ public class Solution { public String foreignDictionary(String[] words) { Map> adj = new HashMap<>(); Map indegree = new HashMap<>(); - + for (String word : words) { for (char c : word.toCharArray()) { adj.putIfAbsent(c, new HashSet<>()); @@ -472,7 +533,7 @@ public class Solution { String w1 = words[i]; String w2 = words[i + 1]; int minLen = Math.min(w1.length(), w2.length()); - if (w1.length() > w2.length() && + if (w1.length() > w2.length() && w1.substring(0, minLen).equals(w2.substring(0, minLen))) { return ""; } @@ -480,7 +541,7 @@ public class Solution { if (w1.charAt(j) != w2.charAt(j)) { if (!adj.get(w1.charAt(j)).contains(w2.charAt(j))) { adj.get(w1.charAt(j)).add(w2.charAt(j)); - indegree.put(w2.charAt(j), + indegree.put(w2.charAt(j), indegree.get(w2.charAt(j)) + 1); } break; @@ -528,11 +589,11 @@ public: indegree[c] = 0; } } - + for (int i = 0; i < words.size() - 1; i++) { string w1 = words[i], w2 = words[i + 1]; int minLen = min(w1.size(), w2.size()); - if (w1.size() > w2.size() && + if (w1.size() > w2.size() && w1.substr(0, minLen) == w2.substr(0, minLen)) { return ""; } @@ -546,14 +607,14 @@ public: } } } - + queue q; for (auto &[c, deg] : indegree) { if (deg == 0) { q.push(c); } } - + string res; while (!q.empty()) { char char_ = q.front(); @@ -566,7 +627,7 @@ public: } } } - + return res.size() == indegree.size() ? res : ""; } }; @@ -587,13 +648,16 @@ class Solution { indegree[c] = 0; } } - + for (let i = 0; i < words.length - 1; i++) { - let w1 = words[i], w2 = words[i + 1]; + let w1 = words[i], + w2 = words[i + 1]; let minLen = Math.min(w1.length, w2.length); - if (w1.length > w2.length && - w1.slice(0, minLen) === w2.slice(0, minLen)) { - return ""; + if ( + w1.length > w2.length && + w1.slice(0, minLen) === w2.slice(0, minLen) + ) { + return ''; } for (let j = 0; j < minLen; j++) { if (w1[j] !== w2[j]) { @@ -605,14 +669,14 @@ class Solution { } } } - + let q = new Queue(); for (let c in indegree) { if (indegree[c] === 0) { q.push(c); } } - + let res = []; while (!q.isEmpty()) { let char = q.pop(); @@ -624,12 +688,12 @@ class Solution { } } } - + if (res.length !== Object.keys(indegree).length) { - return ""; + return ''; } - - return res.join(""); + + return res.join(''); } } ``` @@ -655,7 +719,7 @@ public class Solution { var w1 = words[i]; var w2 = words[i + 1]; int minLen = Math.Min(w1.Length, w2.Length); - if (w1.Length > w2.Length && + if (w1.Length > w2.Length && w1.Substring(0, minLen) == w2.Substring(0, minLen)) { return ""; } @@ -702,7 +766,7 @@ public class Solution { func foreignDictionary(words []string) string { adj := make(map[byte]map[byte]struct{}) indegree := make(map[byte]int) - + for _, word := range words { for i := 0; i < len(word); i++ { char := word[i] @@ -712,18 +776,18 @@ func foreignDictionary(words []string) string { indegree[char] = 0 } } - + for i := 0; i < len(words)-1; i++ { w1, w2 := words[i], words[i+1] minLen := len(w1) if len(w2) < minLen { minLen = len(w2) } - + if len(w1) > len(w2) && w1[:minLen] == w2[:minLen] { return "" } - + for j := 0; j < minLen; j++ { if w1[j] != w2[j] { if _, exists := adj[w1[j]][w2[j]]; !exists { @@ -734,20 +798,20 @@ func foreignDictionary(words []string) string { } } } - + q := []byte{} for char := range indegree { if indegree[char] == 0 { q = append(q, char) } } - + res := []byte{} for len(q) > 0 { char := q[0] q = q[1:] res = append(res, char) - + for neighbor := range adj[char] { indegree[neighbor]-- if indegree[neighbor] == 0 { @@ -755,11 +819,11 @@ func foreignDictionary(words []string) string { } } } - + if len(res) != len(indegree) { return "" } - + return string(res) } ``` @@ -769,24 +833,24 @@ class Solution { fun foreignDictionary(words: Array): String { val adj = HashMap>() val indegree = HashMap() - + for (word in words) { for (c in word) { adj.computeIfAbsent(c) { hashSetOf() } indegree[c] = 0 } } - + for (i in 0 until words.size - 1) { val w1 = words[i] val w2 = words[i + 1] val minLen = minOf(w1.length, w2.length) - - if (w1.length > w2.length && + + if (w1.length > w2.length && w1.substring(0, minLen) == w2.substring(0, minLen)) { return "" } - + for (j in 0 until minLen) { if (w1[j] != w2[j]) { if (w2[j] !in adj[w1[j]]!!) { @@ -797,19 +861,19 @@ class Solution { } } } - + val q: Queue = LinkedList() for ((char, degree) in indegree) { if (degree == 0) { q.add(char) } } - + val res = StringBuilder() while (q.isNotEmpty()) { val char = q.poll() res.append(char) - + for (neighbor in adj[char]!!) { indegree[neighbor] = indegree[neighbor]!! - 1 if (indegree[neighbor] == 0) { @@ -817,17 +881,80 @@ class Solution { } } } - + return if (res.length != indegree.size) "" else res.toString() } } ``` +```swift +class Solution { + func foreignDictionary(_ words: [String]) -> String { + var adj = [Character: Set]() + for word in words { + for char in word { + adj[char] = Set() + } + } + + var indegree = [Character: Int]() + for key in adj.keys { + indegree[key] = 0 + } + + for i in 0.. w2.count && String(w1.prefix(minLen)) == String(w2.prefix(minLen)) { + return "" + } + let w1Arr = Array(w1) + let w2Arr = Array(w2) + for j in 0..() + for (c, deg) in indegree { + if deg == 0 { + q.append(c) + } + } + + var res = [Character]() + while !q.isEmpty { + let char = q.removeFirst() + res.append(char) + for neighbor in adj[char]! { + indegree[neighbor]! -= 1 + if indegree[neighbor]! == 0 { + q.append(neighbor) + } + } + } + + if res.count != indegree.count { + return "" + } + + return String(res) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(N + V + E)$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(N + V + E)$ +- Space complexity: $O(V + E)$ -> Where $V$ is the number of unique characters, $E$ is the number of edges and $N$ is the sum of lengths of all the strings. \ No newline at end of file +> Where $V$ is the number of unique characters, $E$ is the number of edges and $N$ is the sum of lengths of all the strings. diff --git a/articles/freedom-trail.md b/articles/freedom-trail.md index 9c7ef1c89..e7803e7f9 100644 --- a/articles/freedom-trail.md +++ b/articles/freedom-trail.md @@ -79,7 +79,7 @@ class Solution { if (ring[i] === key[k]) { const minDist = Math.min( Math.abs(r - i), - ring.length - Math.abs(r - i) + ring.length - Math.abs(r - i), ); res = Math.min(res, minDist + 1 + dfs(i, k + 1)); } @@ -96,8 +96,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ m)$ -* Space complexity: $O(m)$ for recursion stack. +- Time complexity: $O(n ^ m)$ +- Space complexity: $O(m)$ for recursion stack. > Where $n$ is the length of the $ring$ and $m$ is the length of the $key$. @@ -215,7 +215,7 @@ class Solution { if (ring[i] === key[k]) { const minDist = Math.min( Math.abs(r - i), - ring.length - Math.abs(r - i) + ring.length - Math.abs(r - i), ); res = Math.min(res, minDist + 1 + dfs(i, k + 1)); } @@ -234,8 +234,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2 * m)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n ^ 2 * m)$ +- Space complexity: $O(n * m)$ > Where $n$ is the length of the $ring$ and $m$ is the length of the $key$. @@ -333,9 +333,7 @@ class Solution { findRotateSteps(ring, key) { const n = ring.length; const m = key.length; - const dp = Array.from({ length: m + 1 }, () => - Array(n).fill(Infinity) - ); + const dp = Array.from({ length: m + 1 }, () => Array(n).fill(Infinity)); for (let i = 0; i < n; i++) { dp[m][i] = 0; @@ -345,8 +343,14 @@ class Solution { for (let r = 0; r < n; r++) { for (let i = 0; i < n; i++) { if (ring[i] === key[k]) { - const minDist = Math.min(Math.abs(r - i), n - Math.abs(r - i)); - dp[k][r] = Math.min(dp[k][r], minDist + 1 + dp[k + 1][i]); + const minDist = Math.min( + Math.abs(r - i), + n - Math.abs(r - i), + ); + dp[k][r] = Math.min( + dp[k][r], + minDist + 1 + dp[k + 1][i], + ); } } } @@ -360,8 +364,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2 * m)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n ^ 2 * m)$ +- Space complexity: $O(n * m)$ > Where $n$ is the length of the $ring$ and $m$ is the length of the $key$. @@ -475,7 +479,10 @@ class Solution { const nextDp = new Array(n).fill(Infinity); for (let r = 0; r < n; r++) { for (const i of adj[key.charCodeAt(k) - 97]) { - const minDist = Math.min(Math.abs(r - i), n - Math.abs(r - i)); + const minDist = Math.min( + Math.abs(r - i), + n - Math.abs(r - i), + ); nextDp[r] = Math.min(nextDp[r], minDist + 1 + dp[i]); } } @@ -491,8 +498,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2 * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2 * m)$ +- Space complexity: $O(n)$ > Where $n$ is the length of the $ring$ and $m$ is the length of the $key$. @@ -550,7 +557,7 @@ public class Solution { for (int r : adj[key.charAt(k) - 'a']) { int minDist = Integer.MAX_VALUE; for (int i : adj[key.charAt(k - 1) - 'a']) { - minDist = Math.min(minDist, + minDist = Math.min(minDist, Math.min(Math.abs(r - i), n - Math.abs(r - i)) + dp[i] ); } @@ -614,7 +621,9 @@ class Solution { findRotateSteps(ring, key) { const n = ring.length; const m = key.length; - const dp = Array(n).fill(0).map((_, i) => Math.min(i, n - i)); + const dp = Array(n) + .fill(0) + .map((_, i) => Math.min(i, n - i)); const adj = Array.from({ length: 26 }, () => []); for (let i = 0; i < n; i++) { @@ -625,15 +634,18 @@ class Solution { for (let r of adj[key.charCodeAt(k) - 97]) { let minDist = Infinity; for (let i of adj[key.charCodeAt(k - 1) - 97]) { - minDist = Math.min(minDist, - Math.min(Math.abs(r - i), n - Math.abs(r - i)) + dp[i] + minDist = Math.min( + minDist, + Math.min(Math.abs(r - i), n - Math.abs(r - i)) + dp[i], ); } dp[r] = minDist; } } - return Math.min(...adj[key.charCodeAt(m - 1) - 97].map(i => dp[i])) + m; + return ( + Math.min(...adj[key.charCodeAt(m - 1) - 97].map((i) => dp[i])) + m + ); } } ``` @@ -642,8 +654,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2 * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2 * m)$ +- Space complexity: $O(n)$ > Where $n$ is the length of the $ring$ and $m$ is the length of the $key$. @@ -658,14 +670,14 @@ class Solution: def findRotateSteps(self, ring: str, key: str) -> int: n = len(ring) m = len(key) - + dp = [0] * n next_dp = [0] * n - + adj = [[] for _ in range(26)] for i, c in enumerate(ring): adj[ord(c) - ord('a')].append(i) - + for k in range(m - 1, -1, -1): c = ord(key[k]) - ord('a') it, N = 0, len(adj[c]) @@ -675,19 +687,19 @@ class Solution: next_dp[r] = float('inf') while it < N and adj[c][it] < r: it += 1 - + nextIdx = adj[c][it] if it < N else adj[c][0] prevIdx = adj[c][it - 1] if it > 0 else adj[c][-1] - + next_dp[r] = min( (r - prevIdx if r > prevIdx else n - (prevIdx - r)) + dp[prevIdx], (nextIdx - r if nextIdx > r else n - (r - nextIdx)) + dp[nextIdx] ) else: next_dp[r] = dp[r] - + dp, next_dp = next_dp, dp - + return dp[0] + m ``` @@ -696,32 +708,32 @@ public class Solution { public int findRotateSteps(String ring, String key) { int n = ring.length(); int m = key.length(); - + int[] dp = new int[n]; int[] nextDp = new int[n]; List[] adj = new ArrayList[26]; - + for (int i = 0; i < 26; i++) { adj[i] = new ArrayList<>(); } for (int i = 0; i < n; i++) { adj[ring.charAt(i) - 'a'].add(i); } - + for (int k = m - 1; k >= 0; k--) { int c = key.charAt(k) - 'a'; int it = 0, N = adj[c].size(); - + for (int r = 0; r < n; r++) { if (ring.charAt(r) - 'a' != c) { nextDp[r] = Integer.MAX_VALUE; while (it < N && adj[c].get(it) < r) { it++; } - + int nextIdx = it < N ? adj[c].get(it) : adj[c].get(0); int prevIdx = it > 0 ? adj[c].get(it - 1) : adj[c].get(N - 1); - + nextDp[r] = Math.min( (r > prevIdx ? r - prevIdx : n - (prevIdx - r)) + dp[prevIdx], (nextIdx > r ? nextIdx - r : n - (r - nextIdx)) + dp[nextIdx] @@ -730,12 +742,12 @@ public class Solution { nextDp[r] = dp[r]; } } - + int[] temp = dp; dp = nextDp; nextDp = temp; } - + return dp[0] + m; } } @@ -746,29 +758,29 @@ class Solution { public: int findRotateSteps(string ring, string key) { int n = ring.size(), m = key.size(); - + vector dp(n, 0); vector nextDp(n, 0); vector> adj(26); - + for (int i = 0; i < n; i++) { adj[ring[i] - 'a'].push_back(i); } - + for (int k = m - 1; k >= 0; k--) { int c = key[k] - 'a'; int it = 0, N = adj[c].size(); - + for (int r = 0; r < n; r++) { if (ring[r] - 'a' != c) { nextDp[r] = INT_MAX; while (it < N && adj[c][it] < r) { it++; } - + int nextIdx = it < N ? adj[c][it] : adj[c][0]; int prevIdx = it > 0 ? adj[c][it - 1] : adj[c][N - 1]; - + nextDp[r] = min( (r > prevIdx ? r - prevIdx : n - (prevIdx - r)) + dp[prevIdx], (nextIdx > r ? nextIdx - r : n - (r - nextIdx)) + dp[nextIdx] @@ -777,10 +789,10 @@ public: nextDp[r] = dp[r]; } } - + dp.swap(nextDp); } - + return dp[0] + m; } }; @@ -794,42 +806,46 @@ class Solution { * @return {number} */ findRotateSteps(ring, key) { - const n = ring.length, m = key.length; - + const n = ring.length, + m = key.length; + let dp = Array(n).fill(0); let nextDp = Array(n).fill(0); const adj = Array.from({ length: 26 }, () => []); - + for (let i = 0; i < n; i++) { adj[ring.charCodeAt(i) - 97].push(i); } - + for (let k = m - 1; k >= 0; k--) { const c = key.charCodeAt(k) - 97; - let it = 0, N = adj[c].length; - + let it = 0, + N = adj[c].length; + for (let r = 0; r < n; r++) { if (ring.charCodeAt(r) - 97 !== c) { nextDp[r] = Infinity; while (it < N && adj[c][it] < r) { it++; } - + const nextIdx = it < N ? adj[c][it] : adj[c][0]; const prevIdx = it > 0 ? adj[c][it - 1] : adj[c][N - 1]; - + nextDp[r] = Math.min( - (r > prevIdx ? r - prevIdx : n - (prevIdx - r)) + dp[prevIdx], - (nextIdx > r ? nextIdx - r : n - (r - nextIdx)) + dp[nextIdx] + (r > prevIdx ? r - prevIdx : n - (prevIdx - r)) + + dp[prevIdx], + (nextIdx > r ? nextIdx - r : n - (r - nextIdx)) + + dp[nextIdx], ); } else { nextDp[r] = dp[r]; } } - + [dp, nextDp] = [nextDp, dp]; } - + return dp[0] + m; } } @@ -839,7 +855,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n)$ -> Where $n$ is the length of the $ring$ and $m$ is the length of the $key$. \ No newline at end of file +> Where $n$ is the length of the $ring$ and $m$ is the length of the $key$. diff --git a/articles/frequency-of-the-most-frequent-element.md b/articles/frequency-of-the-most-frequent-element.md index 51c727d97..d1ca95a65 100644 --- a/articles/frequency-of-the-most-frequent-element.md +++ b/articles/frequency-of-the-most-frequent-element.md @@ -75,8 +75,8 @@ class Solution { let j = i - 1; let tmpK = k; - while (j >= 0 && (tmpK - (nums[i] - nums[j])) >= 0) { - tmpK -= (nums[i] - nums[j]); + while (j >= 0 && tmpK - (nums[i] - nums[j]) >= 0) { + tmpK -= nums[i] - nums[j]; j--; } res = Math.max(res, i - j); @@ -86,12 +86,33 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxFrequency(int[] nums, int k) { + Array.Sort(nums); + int res = 1; + + for (int i = 0; i < nums.Length; i++) { + int j = i - 1; + long tmpK = k; + + while (j >= 0 && tmpK - (nums[i] - nums[j]) >= 0) { + tmpK -= (nums[i] - nums[j]); + j--; + } + res = Math.Max(res, i - j); + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2 + n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n ^ 2 + n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -200,7 +221,8 @@ class Solution { let res = 1; for (let i = 0; i < nums.length; i++) { - let left = 0, right = i; + let left = 0, + right = i; while (left <= right) { const mid = Math.floor((left + right) / 2); const curSum = prefixSum[i + 1] - prefixSum[mid]; @@ -218,12 +240,42 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxFrequency(int[] nums, int k) { + Array.Sort(nums); + int n = nums.Length; + long[] prefixSum = new long[n + 1]; + for (int i = 0; i < n; i++) { + prefixSum[i + 1] = prefixSum[i] + nums[i]; + } + + int res = 1; + for (int i = 0; i < n; i++) { + int left = 0, right = i; + while (left <= right) { + int mid = (left + right) / 2; + long curSum = prefixSum[i + 1] - prefixSum[mid]; + long need = (long)(i - mid + 1) * nums[i] - curSum; + if (need <= k) { + res = Math.Max(res, i - mid + 1); + right = mid - 1; + } else { + left = mid + 1; + } + } + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -301,7 +353,9 @@ class Solution { */ maxFrequency(nums, k) { nums.sort((a, b) => a - b); - let total = 0, res = 0, l = 0; + let total = 0, + res = 0, + l = 0; for (let r = 0; r < nums.length; r++) { total += nums[r]; @@ -317,12 +371,33 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxFrequency(int[] nums, int k) { + Array.Sort(nums); + long total = 0; + int res = 0, l = 0; + + for (int r = 0; r < nums.Length; r++) { + total += nums[r]; + while ((long)nums[r] * (r - l + 1) > total + k) { + total -= nums[l]; + l++; + } + res = Math.Max(res, r - l + 1); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -336,10 +411,10 @@ class Solution: nums.sort() l = 0 total = 0 - + for r in range(len(nums)): total += nums[r] - + if (r - l + 1) * nums[r] > total + k: total -= nums[l] l += 1 @@ -397,7 +472,8 @@ class Solution { */ maxFrequency(nums, k) { nums.sort((a, b) => a - b); - let total = 0, l = 0; + let total = 0, + l = 0; for (let r = 0; r < nums.length; r++) { total += nums[r]; @@ -412,9 +488,29 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxFrequency(int[] nums, int k) { + Array.Sort(nums); + long total = 0; + int l = 0; + + for (int r = 0; r < nums.Length; r++) { + total += nums[r]; + if ((long)(r - l + 1) * nums[r] > total + k) { + total -= nums[l]; + l++; + } + } + + return nums.Length - l; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. \ No newline at end of file +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. diff --git a/articles/fruit-into-baskets.md b/articles/fruit-into-baskets.md index 7aa1b5bbe..9869c7d83 100644 --- a/articles/fruit-into-baskets.md +++ b/articles/fruit-into-baskets.md @@ -67,7 +67,8 @@ class Solution { * @return {number} */ totalFruit(fruits) { - let n = fruits.length, res = 0; + let n = fruits.length, + res = 0; for (let i = 0; i < n; i++) { let types = new Set(); @@ -89,8 +90,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -103,7 +104,7 @@ class Solution: def totalFruit(self, fruits: List[int]) -> int: count = defaultdict(int) l, total, res = 0, 0, 0 - + for r in range(len(fruits)): count[fruits[r]] += 1 total += 1 @@ -115,7 +116,7 @@ class Solution: l += 1 if not count[f]: count.pop(f) - + res = max(res, total) return res @@ -182,7 +183,9 @@ class Solution { */ totalFruit(fruits) { let count = new Map(); - let l = 0, total = 0, res = 0; + let l = 0, + total = 0, + res = 0; for (let r = 0; r < fruits.length; r++) { count.set(fruits[r], (count.get(fruits[r]) || 0) + 1); @@ -208,8 +211,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -231,7 +234,7 @@ class Solution: if count[fruits[l]] == 0: count.pop(fruits[l]) l += 1 - + return len(fruits) - l ``` @@ -313,8 +316,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -431,8 +434,13 @@ class Solution { * @return {number} */ totalFruit(fruits) { - let l = 0, fruit1_lastIdx = 0, fruit2_lastIdx = -1; - let fruit1 = fruits[0], fruit2 = -1, total = 1, res = 1; + let l = 0, + fruit1_lastIdx = 0, + fruit2_lastIdx = -1; + let fruit1 = fruits[0], + fruit2 = -1, + total = 1, + res = 1; for (let r = 0; r < fruits.length; r++) { let f = fruits[r]; @@ -444,11 +452,16 @@ class Solution { fruit2_lastIdx = r; fruit2 = f; } else { - if (fruit2_lastIdx === Math.min(fruit1_lastIdx, fruit2_lastIdx)) { - [fruit1_lastIdx, fruit2_lastIdx] = [fruit2_lastIdx, fruit1_lastIdx]; + if ( + fruit2_lastIdx === Math.min(fruit1_lastIdx, fruit2_lastIdx) + ) { + [fruit1_lastIdx, fruit2_lastIdx] = [ + fruit2_lastIdx, + fruit1_lastIdx, + ]; [fruit1, fruit2] = [fruit2, fruit1]; } - total -= (fruit1_lastIdx - l + 1); + total -= fruit1_lastIdx - l + 1; l = fruit1_lastIdx + 1; fruit1 = f; fruit1_lastIdx = r; @@ -464,5 +477,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/furthest-building-you-can-reach.md b/articles/furthest-building-you-can-reach.md new file mode 100644 index 000000000..fe46cae9f --- /dev/null +++ b/articles/furthest-building-you-can-reach.md @@ -0,0 +1,726 @@ +## 1. Brute Force (Greedy) + +::tabs-start + +```python +class Solution: + def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int: + n = len(heights) + + for i in range(1, n): + if ladders >= i: + continue + + diffs = [] + for j in range(i): + if heights[j + 1] > heights[j]: + diffs.append(heights[j + 1] - heights[j]) + + diffs.sort() + brickSum = 0 + for j in range(len(diffs) - ladders): + brickSum += diffs[j] + + if brickSum > bricks: + return i - 1 + + return n - 1 +``` + +```java +public class Solution { + public int furthestBuilding(int[] heights, int bricks, int ladders) { + int n = heights.length; + + for (int i = 1; i < n; i++) { + if (ladders >= i) { + continue; + } + + List diffs = new ArrayList<>(); + for (int j = 0; j < i; j++) { + if (heights[j + 1] > heights[j]) { + diffs.add(heights[j + 1] - heights[j]); + } + } + + Collections.sort(diffs); + long brickSum = 0; + for (int j = 0; j < diffs.size() - ladders; j++) { + brickSum += diffs.get(j); + } + + if (brickSum > bricks) { + return i - 1; + } + } + + return n - 1; + } +} +``` + +```cpp +class Solution { +public: + int furthestBuilding(vector& heights, int bricks, int ladders) { + int n = heights.size(); + + for (int i = 1; i < n; i++) { + if (ladders >= i) { + continue; + } + + vector diffs; + for (int j = 0; j < i; j++) { + if (heights[j + 1] > heights[j]) { + diffs.push_back(heights[j + 1] - heights[j]); + } + } + + sort(diffs.begin(), diffs.end()); + long long brickSum = 0; + for (int j = 0; j < int(diffs.size()) - ladders; j++) { + brickSum += diffs[j]; + } + + if (brickSum > bricks) { + return i - 1; + } + } + + return n - 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @param {number} bricks + * @param {number} ladders + * @return {number} + */ + furthestBuilding(heights, bricks, ladders) { + let n = heights.length; + + for (let i = 1; i < n; i++) { + if (ladders >= i) { + continue; + } + + let diffs = []; + for (let j = 0; j < i; j++) { + if (heights[j + 1] > heights[j]) { + diffs.push(heights[j + 1] - heights[j]); + } + } + + diffs.sort((a, b) => a - b); + let brickSum = 0; + for (let j = 0; j < diffs.length - ladders; j++) { + brickSum += diffs[j]; + } + + if (brickSum > bricks) { + return i - 1; + } + } + + return n - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2 \log n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Binary Search On Buildings + +::tabs-start + +```python +class Solution: + def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int: + def canReach(mid): + diffs = [] + for i in range(mid): + if heights[i + 1] > heights[i]: + diffs.append(heights[i + 1] - heights[i]) + + diffs.sort() + brickSum = 0 + for j in range(len(diffs) - ladders): + brickSum += diffs[j] + if brickSum > bricks: + return False + + return True + + l, r = ladders - 1, len(heights) - 1 + while l <= r: + mid = (l + r) // 2 + if canReach(mid): + l = mid + 1 + else: + r = mid - 1 + + return l - 1 +``` + +```java +public class Solution { + public int furthestBuilding(int[] heights, int bricks, int ladders) { + int l = ladders - 1, r = heights.length - 1; + + while (l <= r) { + int mid = (l + r) / 2; + if (canReach(heights, mid, bricks, ladders)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + return l - 1; + } + + private boolean canReach(int[] heights, int mid, int bricks, int ladders) { + List diffs = new ArrayList<>(); + + for (int i = 0; i < mid; i++) { + if (heights[i + 1] > heights[i]) { + diffs.add(heights[i + 1] - heights[i]); + } + } + + Collections.sort(diffs); + int brickSum = 0; + + for (int j = 0; j < diffs.size() - ladders; j++) { + brickSum += diffs.get(j); + if (brickSum > bricks) { + return false; + } + } + + return true; + } +} +``` + +```cpp +class Solution { +public: + int furthestBuilding(vector& heights, int bricks, int ladders) { + int l = ladders - 1, r = heights.size() - 1; + + while (l <= r) { + int mid = (l + r) / 2; + if (canReach(heights, mid, bricks, ladders)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + return l - 1; + } + +private: + bool canReach(vector& heights, int mid, int bricks, int ladders) { + vector diffs; + + for (int i = 0; i < mid; i++) { + if (heights[i + 1] > heights[i]) { + diffs.push_back(heights[i + 1] - heights[i]); + } + } + + sort(diffs.begin(), diffs.end()); + long long brickSum = 0; + + for (int j = 0; j < int(diffs.size()) - ladders; j++) { + brickSum += diffs[j]; + if (brickSum > bricks) { + return false; + } + } + + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @param {number} bricks + * @param {number} ladders + * @return {number} + */ + furthestBuilding(heights, bricks, ladders) { + let l = ladders - 1, + r = heights.length - 1; + + const canReach = (mid) => { + let diffs = []; + for (let i = 0; i < mid; i++) { + if (heights[i + 1] > heights[i]) { + diffs.push(heights[i + 1] - heights[i]); + } + } + + diffs.sort((a, b) => a - b); + let brickSum = 0; + + for (let j = 0; j < diffs.length - ladders; j++) { + brickSum += diffs[j]; + if (brickSum > bricks) { + return false; + } + } + + return true; + }; + + while (l <= r) { + let mid = Math.floor((l + r) / 2); + if (canReach(mid)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + return l - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log ^ 2 n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Binary Search On Buildings (Optimal) + +::tabs-start + +```python +class Solution: + def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int: + diffs = [] + for i in range(1, len(heights)): + if heights[i] > heights[i - 1]: + diffs.append((heights[i] - heights[i - 1], i)) + + diffs.sort(reverse=True) + + def canReach(index): + useLadders = useBricks = 0 + for diff, i in diffs: + if i > index: + continue + + if useLadders < ladders: + useLadders += 1 + else: + useBricks += diff + if useBricks > bricks: + return False + return True + + l, r = 1, len(heights) - 1 + while l <= r: + mid = (l + r) >> 1 + if canReach(mid): + l = mid + 1 + else: + r = mid - 1 + return l - 1 +``` + +```java +public class Solution { + public int furthestBuilding(int[] heights, int bricks, int ladders) { + List diffs = new ArrayList<>(); + for (int i = 1; i < heights.length; i++) { + if (heights[i] > heights[i - 1]) { + diffs.add(new int[]{heights[i] - heights[i - 1], i}); + } + } + + diffs.sort((a, b) -> Integer.compare(b[0], a[0])); + + int l = 1, r = heights.length - 1; + while (l <= r) { + int mid = (l + r) >> 1; + if (canReach(diffs, mid, bricks, ladders)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + return l - 1; + } + + private boolean canReach(List diffs, int index, int bricks, int ladders) { + int useLadders = 0; + long useBricks = 0; + for (int[] diff : diffs) { + int jump = diff[0], i = diff[1]; + + if (i > index) continue; + + if (useLadders < ladders) { + useLadders++; + } else { + useBricks += jump; + if (useBricks > bricks) { + return false; + } + } + } + return true; + } +} +``` + +```cpp +class Solution { +public: + int furthestBuilding(vector& heights, int bricks, int ladders) { + vector> diffs; + for (int i = 1; i < heights.size(); i++) { + if (heights[i] > heights[i - 1]) { + diffs.emplace_back(heights[i] - heights[i - 1], i); + } + } + + sort(diffs.rbegin(), diffs.rend()); // Sort in descending order + + int l = 1, r = heights.size() - 1; + while (l <= r) { + int mid = (l + r) >> 1; + if (canReach(diffs, mid, bricks, ladders)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + return l - 1; + } + +private: + bool canReach(vector>& diffs, int index, int bricks, int ladders) { + int useLadders = 0; + long long useBricks = 0; + for (auto& diff : diffs) { + int jump = diff.first, i = diff.second; + + if (i > index) continue; + + if (useLadders < ladders) { + useLadders++; + } else { + useBricks += jump; + if (useBricks > bricks) { + return false; + } + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @param {number} bricks + * @param {number} ladders + * @return {number} + */ + furthestBuilding(heights, bricks, ladders) { + let diffs = []; + for (let i = 1; i < heights.length; i++) { + if (heights[i] > heights[i - 1]) { + diffs.push([heights[i] - heights[i - 1], i]); + } + } + + diffs.sort((a, b) => b[0] - a[0]); + + const canReach = (index) => { + let useLadders = 0, + useBricks = 0; + for (let [diff, i] of diffs) { + if (i > index) continue; + + if (useLadders < ladders) { + useLadders++; + } else { + useBricks += diff; + if (useBricks > bricks) { + return false; + } + } + } + return true; + }; + + let l = 1, + r = heights.length - 1; + while (l <= r) { + let mid = (l + r) >> 1; + if (canReach(mid)) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + return l - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Max-Heap + +::tabs-start + +```python +class Solution: + def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int: + heap = [] # Max heap of bricks used + + for i in range(len(heights) - 1): + diff = heights[i + 1] - heights[i] + if diff <= 0: + continue + + bricks -= diff + heapq.heappush(heap, -diff) + + if bricks < 0: + if ladders == 0: + return i + ladders -= 1 + bricks += -heapq.heappop(heap) + + return len(heights) - 1 +``` + +```java +public class Solution { + public int furthestBuilding(int[] heights, int bricks, int ladders) { + PriorityQueue maxHeap = new PriorityQueue<>((a, b) -> b - a); + + for (int i = 0; i < heights.length - 1; i++) { + int diff = heights[i + 1] - heights[i]; + if (diff <= 0) continue; + + bricks -= diff; + maxHeap.offer(diff); + + if (bricks < 0) { + if (ladders == 0) return i; + ladders--; + bricks += maxHeap.poll(); + } + } + + return heights.length - 1; + } +} +``` + +```cpp +class Solution { +public: + int furthestBuilding(vector& heights, int bricks, int ladders) { + priority_queue maxHeap; + + for (int i = 0; i < heights.size() - 1; i++) { + int diff = heights[i + 1] - heights[i]; + if (diff <= 0) continue; + + bricks -= diff; + maxHeap.push(diff); + + if (bricks < 0) { + if (ladders == 0) return i; + ladders--; + bricks += maxHeap.top(); + maxHeap.pop(); + } + } + + return heights.size() - 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @param {number} bricks + * @param {number} ladders + * @return {number} + */ + furthestBuilding(heights, bricks, ladders) { + const maxHeap = new MaxPriorityQueue(); + + for (let i = 0; i < heights.length - 1; i++) { + let diff = heights[i + 1] - heights[i]; + if (diff <= 0) continue; + + bricks -= diff; + maxHeap.enqueue(diff); + + if (bricks < 0) { + if (ladders === 0) return i; + ladders--; + bricks += maxHeap.dequeue().element; + } + } + + return heights.length - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 5. Min-Heap + +::tabs-start + +```python +class Solution: + def furthestBuilding(self, heights: List[int], bricks: int, ladders: int) -> int: + minHeap = [] + + for i in range(len(heights) - 1): + diff = heights[i + 1] - heights[i] + if diff <= 0: + continue + + heapq.heappush(minHeap, diff) + if len(minHeap) > ladders: + bricks -= heapq.heappop(minHeap) + if bricks < 0: + return i + + return len(heights) - 1 +``` + +```java +public class Solution { + public int furthestBuilding(int[] heights, int bricks, int ladders) { + PriorityQueue minHeap = new PriorityQueue<>(); + + for (int i = 0; i < heights.length - 1; i++) { + int diff = heights[i + 1] - heights[i]; + if (diff <= 0) continue; + + minHeap.offer(diff); + if (minHeap.size() > ladders) { + bricks -= minHeap.poll(); + if (bricks < 0) return i; + } + } + + return heights.length - 1; + } +} +``` + +```cpp +class Solution { +public: + int furthestBuilding(vector& heights, int bricks, int ladders) { + priority_queue, greater> minHeap; + + for (int i = 0; i < int(heights.size()) - 1; i++) { + int diff = heights[i + 1] - heights[i]; + if (diff <= 0) continue; + + minHeap.push(diff); + if (minHeap.size() > ladders) { + bricks -= minHeap.top(); minHeap.pop(); + if (bricks < 0) return i; + } + } + + return int(heights.size()) - 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @param {number} bricks + * @param {number} ladders + * @return {number} + */ + furthestBuilding(heights, bricks, ladders) { + const minHeap = new MinPriorityQueue(); + + for (let i = 0; i < heights.length - 1; i++) { + let diff = heights[i + 1] - heights[i]; + if (diff <= 0) continue; + + minHeap.enqueue(diff); + if (minHeap.size() > ladders) { + bricks -= minHeap.dequeue().element; + if (bricks < 0) return i; + } + } + + return heights.length - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/gas-station.md b/articles/gas-station.md index cedbf31c2..9f49089c7 100644 --- a/articles/gas-station.md +++ b/articles/gas-station.md @@ -11,6 +11,7 @@ class Solution: tank = gas[i] - cost[i] if tank < 0: continue + j = (i + 1) % n while j != i: tank += gas[j] @@ -19,6 +20,7 @@ class Solution: break j += 1 j %= n + if j == i: return i return -1 @@ -32,12 +34,14 @@ public class Solution { for (int i = 0; i < n; i++) { int tank = gas[i] - cost[i]; if (tank < 0) continue; + int j = (i + 1) % n; while (j != i) { tank += gas[j] - cost[j]; if (tank < 0) break; j = (j + 1) % n; } + if (j == i) return i; } return -1; @@ -54,12 +58,14 @@ public: for (int i = 0; i < n; i++) { int tank = gas[i] - cost[i]; if (tank < 0) continue; + int j = (i + 1) % n; while (j != i) { tank += gas[j] - cost[j]; if (tank < 0) break; j = (j + 1) % n; } + if (j == i) return i; } return -1; @@ -80,12 +86,14 @@ class Solution { for (let i = 0; i < n; i++) { let tank = gas[i] - cost[i]; if (tank < 0) continue; + let j = (i + 1) % n; while (j !== i) { tank += gas[j] - cost[j]; if (tank < 0) break; j = (j + 1) % n; } + if (j === i) return i; } return -1; @@ -101,14 +109,17 @@ public class Solution { for (int i = 0; i < n; i++) { int tank = gas[i] - cost[i]; if (tank < 0) continue; + int j = (i + 1) % n; while (j != i) { tank += gas[j] - cost[j]; if (tank < 0) break; j = (j + 1) % n; } + if (j == i) return i; } + return -1; } } @@ -117,11 +128,13 @@ public class Solution { ```go func canCompleteCircuit(gas []int, cost []int) int { n := len(gas) + for i := 0; i < n; i++ { tank := gas[i] - cost[i] if tank < 0 { continue } + j := (i + 1) % n for j != i { tank += gas[j] @@ -131,10 +144,12 @@ func canCompleteCircuit(gas []int, cost []int) int { } j = (j + 1) % n } + if j == i { return i } } + return -1 } ``` @@ -166,12 +181,44 @@ class Solution { } ``` +```swift +class Solution { + func canCompleteCircuit(_ gas: [Int], _ cost: [Int]) -> Int { + let n = gas.count + + for i in 0.. end) { if (tank < 0) { @@ -327,12 +375,35 @@ class Solution { } ``` +```swift +class Solution { + func canCompleteCircuit(_ gas: [Int], _ cost: [Int]) -> Int { + let n = gas.count + var start = n - 1 + var end = 0 + var tank = gas[start] - cost[start] + + while start > end { + if tank < 0 { + start -= 1 + tank += gas[start] - cost[start] + } else { + tank += gas[end] - cost[end] + end += 1 + } + } + + return tank >= 0 ? start : -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -354,7 +425,7 @@ class Solution: if total < 0: total = 0 res = i + 1 - + return res ``` @@ -385,7 +456,7 @@ public class Solution { class Solution { public: int canCompleteCircuit(vector& gas, vector& cost) { - if (accumulate(gas.begin(), gas.end(), 0) < + if (accumulate(gas.begin(), gas.end(), 0) < accumulate(cost.begin(), cost.end(), 0)) { return -1; } @@ -414,8 +485,10 @@ class Solution { * @return {number} */ canCompleteCircuit(gas, cost) { - if (gas.reduce((acc, val) => acc + val, 0) < - cost.reduce((acc, val) => acc + val, 0)) { + if ( + gas.reduce((acc, val) => acc + val, 0) < + cost.reduce((acc, val) => acc + val, 0) + ) { return -1; } @@ -510,9 +583,32 @@ class Solution { } ``` +```swift +class Solution { + func canCompleteCircuit(_ gas: [Int], _ cost: [Int]) -> Int { + if gas.reduce(0, +) < cost.reduce(0, +) { + return -1 + } + + var total = 0 + var res = 0 + for i in 0.. { val res = mutableListOf() - + fun valid(s: String): Boolean { var open = 0 for (c in s) { @@ -205,7 +205,7 @@ class Solution { } return open == 0 } - + fun dfs(s: String) { if (s.length == n * 2) { if (valid(s)) { @@ -213,11 +213,44 @@ class Solution { } return } - + dfs(s + "(") dfs(s + ")") } - + + dfs("") + return res + } +} +``` + +```swift +class Solution { + func generateParenthesis(_ n: Int) -> [String] { + var res = [String]() + + func isValid(_ s: String) -> Bool { + var open = 0 + for c in s { + open += (c == "(") ? 1 : -1 + if open < 0 { + return false + } + } + return open == 0 + } + + func dfs(_ s: String) { + if s.count == n * 2 { + if isValid(s) { + res.append(s) + } + return + } + dfs(s + "(") + dfs(s + ")") + } + dfs("") return res } @@ -228,8 +261,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ {2n} * n)$ -* Space complexity: $O(2 ^ {2n} * n)$ +- Time complexity: $O(2 ^ {2n} * n)$ +- Space complexity: $O(2 ^ {2n} * n)$ --- @@ -374,9 +407,9 @@ public class Solution { public List GenerateParenthesis(int n) { List res = new List(); - string stack = ""; + string stack = ""; Backtrack(0, 0, n, res, stack); - return res; + return res; } } ``` @@ -385,27 +418,27 @@ public class Solution { func generateParenthesis(n int) []string { stack := make([]string, 0) res := make([]string, 0) - + var backtrack func(int, int) backtrack = func(openN, closedN int) { if openN == n && closedN == n { res = append(res, strings.Join(stack, "")) return } - + if openN < n { stack = append(stack, "(") backtrack(openN+1, closedN) stack = stack[:len(stack)-1] } - + if closedN < openN { stack = append(stack, ")") backtrack(openN, closedN+1) stack = stack[:len(stack)-1] } } - + backtrack(0, 0) return res } @@ -416,26 +449,57 @@ class Solution { fun generateParenthesis(n: Int): List { val stack = mutableListOf() val res = mutableListOf() - + fun backtrack(openN: Int, closedN: Int) { if (openN == n && closedN == n) { res.add(stack.joinToString("")) return } - + if (openN < n) { stack.add("(") backtrack(openN + 1, closedN) stack.removeAt(stack.lastIndex) } - + if (closedN < openN) { stack.add(")") backtrack(openN, closedN + 1) stack.removeAt(stack.lastIndex) } } - + + backtrack(0, 0) + return res + } +} +``` + +```swift +class Solution { + func generateParenthesis(_ n: Int) -> [String] { + var stack = [Character]() + var res = [String]() + + func backtrack(_ openN: Int, _ closedN: Int) { + if openN == n && closedN == n { + res.append(String(stack)) + return + } + + if openN < n { + stack.append("(") + backtrack(openN + 1, closedN) + stack.removeLast() + } + + if closedN < openN { + stack.append(")") + backtrack(openN, closedN + 1) + stack.removeLast() + } + } + backtrack(0, 0) return res } @@ -446,8 +510,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(\frac{4^n}{\sqrt{n}})$ -* Space complexity: $O(n)$ +- Time complexity: $O(\frac{4^n}{\sqrt{n}})$ +- Space complexity: $O(n)$ --- @@ -460,13 +524,13 @@ class Solution: def generateParenthesis(self, n): res = [[] for _ in range(n+1)] res[0] = [""] - + for k in range(n + 1): for i in range(k): for left in res[i]: for right in res[k-i-1]: res[k].append("(" + left + ")" + right) - + return res[-1] ``` @@ -524,13 +588,13 @@ class Solution { */ generateParenthesis(n) { const res = Array.from({ length: n + 1 }, () => []); - res[0] = [""]; + res[0] = ['']; for (let k = 0; k <= n; k++) { for (let i = 0; i < k; i++) { for (const left of res[i]) { for (const right of res[k - i - 1]) { - res[k].push("(" + left + ")" + right); + res[k].push('(' + left + ')' + right); } } } @@ -569,7 +633,7 @@ public class Solution { func generateParenthesis(n int) []string { res := make([][]string, n+1) res[0] = []string{""} - + for k := 1; k <= n; k++ { res[k] = make([]string, 0) for i := 0; i < k; i++ { @@ -580,7 +644,7 @@ func generateParenthesis(n int) []string { } } } - + return res[n] } ``` @@ -590,7 +654,7 @@ class Solution { fun generateParenthesis(n: Int): List { val res = Array(n + 1) { mutableListOf() } res[0] = mutableListOf("") - + for (k in 1..n) { for (i in 0 until k) { for (left in res[i]) { @@ -600,7 +664,28 @@ class Solution { } } } - + + return res[n] + } +} +``` + +```swift +class Solution { + func generateParenthesis(_ n: Int) -> [String] { + var res = [[String]](repeating: [], count: n + 1) + res[0] = [""] + + for k in 0...n { + for i in 0.. int: + n = len(s) + res = 0 + + for i in range(n): + cur_cost = 0 + for j in range(i, n): + cur_cost += abs(ord(t[j]) - ord(s[j])) + if cur_cost > maxCost: + break + res = max(res, j - i + 1) + + return res +``` + +```java +public class Solution { + public int equalSubstring(String s, String t, int maxCost) { + int n = s.length(); + int res = 0; + + for (int i = 0; i < n; i++) { + int curCost = 0; + for (int j = i; j < n; j++) { + curCost += Math.abs(t.charAt(j) - s.charAt(j)); + if (curCost > maxCost) { + break; + } + res = Math.max(res, j - i + 1); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int equalSubstring(string s, string t, int maxCost) { + int n = s.size(); + int res = 0; + + for (int i = 0; i < n; i++) { + int curCost = 0; + for (int j = i; j < n; j++) { + curCost += abs(t[j] - s[j]); + if (curCost > maxCost) { + break; + } + res = max(res, j - i + 1); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} t + * @param {number} maxCost + * @return {number} + */ + equalSubstring(s, t, maxCost) { + const n = s.length; + let res = 0; + + for (let i = 0; i < n; i++) { + let curCost = 0; + for (let j = i; j < n; j++) { + curCost += Math.abs(t.charCodeAt(j) - s.charCodeAt(j)); + if (curCost > maxCost) { + break; + } + res = Math.max(res, j - i + 1); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Sliding Window + +::tabs-start + +```python +class Solution: + def equalSubstring(self, s: str, t: str, maxCost: int) -> int: + curCost = 0 + l = 0 + res = 0 + + for r in range(len(s)): + curCost += abs(ord(s[r]) - ord(t[r])) + while curCost > maxCost: + curCost -= abs(ord(s[l]) - ord(t[l])) + l += 1 + res = max(res, r - l + 1) + + return res +``` + +```java +public class Solution { + public int equalSubstring(String s, String t, int maxCost) { + int curCost = 0, l = 0, res = 0; + + for (int r = 0; r < s.length(); r++) { + curCost += Math.abs(s.charAt(r) - t.charAt(r)); + while (curCost > maxCost) { + curCost -= Math.abs(s.charAt(l) - t.charAt(l)); + l++; + } + res = Math.max(res, r - l + 1); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int equalSubstring(string s, string t, int maxCost) { + int curCost = 0, l = 0, res = 0; + + for (int r = 0; r < s.length(); r++) { + curCost += abs(s[r] - t[r]); + while (curCost > maxCost) { + curCost -= abs(s[l] - t[l]); + l++; + } + res = max(res, r - l + 1); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} t + * @param {number} maxCost + * @return {number} + */ + equalSubstring(s, t, maxCost) { + let curCost = 0, + l = 0, + res = 0; + + for (let r = 0; r < s.length; r++) { + curCost += Math.abs(s.charCodeAt(r) - t.charCodeAt(r)); + while (curCost > maxCost) { + curCost -= Math.abs(s.charCodeAt(l) - t.charCodeAt(l)); + l++; + } + res = Math.max(res, r - l + 1); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 3. Sliding Window (Optimal) + +::tabs-start + +```python +class Solution: + def equalSubstring(self, s: str, t: str, maxCost: int) -> int: + l = 0 + for r in range(len(s)): + maxCost -= abs(ord(s[r]) - ord(t[r])) + if maxCost < 0: + maxCost += abs(ord(s[l]) - ord(t[l])) + l += 1 + return len(s) - l +``` + +```java +public class Solution { + public int equalSubstring(String s, String t, int maxCost) { + int l = 0; + for (int r = 0; r < s.length(); r++) { + maxCost -= Math.abs(s.charAt(r) - t.charAt(r)); + if (maxCost < 0) { + maxCost += Math.abs(s.charAt(l) - t.charAt(l)); + l++; + } + } + return s.length() - l; + } +} +``` + +```cpp +class Solution { +public: + int equalSubstring(string s, string t, int maxCost) { + int l = 0; + for (int r = 0; r < s.length(); r++) { + maxCost -= abs(s[r] - t[r]); + if (maxCost < 0) { + maxCost += abs(s[l] - t[l]); + l++; + } + } + return s.length() - l; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} t + * @param {number} maxCost + * @return {number} + */ + equalSubstring(s, t, maxCost) { + let l = 0; + for (let r = 0; r < s.length; r++) { + maxCost -= Math.abs(s.charCodeAt(r) - t.charCodeAt(r)); + if (maxCost < 0) { + maxCost += Math.abs(s.charCodeAt(l) - t.charCodeAt(l)); + l++; + } + } + return s.length - l; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/greatest-common-divisor-of-strings.md b/articles/greatest-common-divisor-of-strings.md index ae138e7d6..482894ee9 100644 --- a/articles/greatest-common-divisor-of-strings.md +++ b/articles/greatest-common-divisor-of-strings.md @@ -82,14 +82,16 @@ class Solution { * @return {string} */ gcdOfStrings(str1, str2) { - const len1 = str1.length, len2 = str2.length; + const len1 = str1.length, + len2 = str2.length; const isDivisor = (l) => { if (len1 % l !== 0 || len2 % l !== 0) { return false; } const sub = str1.slice(0, l); - const f1 = len1 / l, f2 = len2 / l; + const f1 = len1 / l, + f2 = len2 / l; return sub.repeat(f1) === str1 && sub.repeat(f2) === str2; }; @@ -99,6 +101,31 @@ class Solution { } } + return ''; + } +} +``` + +```csharp +public class Solution { + public string GcdOfStrings(string str1, string str2) { + int len1 = str1.Length, len2 = str2.Length; + + bool IsDivisor(int l) { + if (len1 % l != 0 || len2 % l != 0) return false; + + int f1 = len1 / l, f2 = len2 / l; + string baseStr = str1.Substring(0, l); + return new StringBuilder().Insert(0, baseStr, f1).ToString() == str1 && + new StringBuilder().Insert(0, baseStr, f2).ToString() == str2; + } + + for (int l = Math.Min(len1, len2); l >= 1; l--) { + if (IsDivisor(l)) { + return str1.Substring(0, l); + } + } + return ""; } } @@ -108,8 +135,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(min(m, n) * (m + n))$ -* Space complexity: $O(m + n)$ +- Time complexity: $O(min(m, n) * (m + n))$ +- Space complexity: $O(m + n)$ > Where $m$ and $n$ are the lengths of the strings $str1$ and $str2$ respectively. @@ -126,11 +153,11 @@ class Solution: if m < n: m, n = n, m str1, str2 = str2, str1 - + for l in range(n, 0, -1): if m % l != 0 or n % l != 0: continue - + valid = True for i in range(m): if str1[i] != str2[i % l]: @@ -238,7 +265,8 @@ class Solution { * @return {string} */ gcdOfStrings(str1, str2) { - let m = str1.length, n = str2.length; + let m = str1.length, + n = str2.length; if (m < n) { [m, n] = [n, m]; [str1, str2] = [str2, str1]; @@ -269,6 +297,42 @@ class Solution { } } + return ''; + } +} +``` + +```csharp +public class Solution { + public string GcdOfStrings(string str1, string str2) { + int m = str1.Length, n = str2.Length; + if (m < n) { + (str1, str2) = (str2, str1); + (m, n) = (n, m); + } + + for (int l = n; l >= 1; l--) { + if (m % l != 0 || n % l != 0) continue; + + bool valid = true; + for (int i = 0; i < m; i++) { + if (str1[i] != str2[i % l]) { + valid = false; + break; + } + } + if (!valid) continue; + + for (int i = l; i < n; i++) { + if (str2[i] != str2[i % l]) { + valid = false; + break; + } + } + + if (valid) return str2.Substring(0, l); + } + return ""; } } @@ -278,8 +342,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(min(m, n) * (m + n))$ -* Space complexity: $O(g)$ for the output string. +- Time complexity: $O(min(m, n) * (m + n))$ +- Space complexity: $O(g)$ for the output string. > Where $m$ is the length of the string $str1$, $n$ is the length of the string $str2$, and $g$ is the length of the output string. @@ -337,7 +401,7 @@ class Solution { */ gcdOfStrings(str1, str2) { if (str1 + str2 !== str2 + str1) { - return ""; + return ''; } const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b)); const g = gcd(str1.length, str2.length); @@ -346,12 +410,34 @@ class Solution { } ``` +```csharp +public class Solution { + public string GcdOfStrings(string str1, string str2) { + if (str1 + str2 != str2 + str1) { + return ""; + } + + int g = GCD(str1.Length, str2.Length); + return str1.Substring(0, g); + } + + private int GCD(int a, int b) { + while (b != 0) { + int temp = b; + b = a % b; + a = temp; + } + return a; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n)$ -* Space complexity: $O(m + n)$. +- Time complexity: $O(m + n)$ +- Space complexity: $O(m + n)$. > Where $m$ and $n$ are the lengths of the strings $str1$ and $str2$ respectively. @@ -365,7 +451,7 @@ class Solution { class Solution: def gcdOfStrings(self, str1: str, str2: str) -> str: g = gcd(len(str1), len(str2)) - + if all(str1[i] == str1[i % g] for i in range(len(str1))) and \ all(str2[i] == str1[i % g] for i in range(len(str2))): return str1[:g] @@ -434,13 +520,13 @@ class Solution { for (let i = 0; i < str1.length; i++) { if (str1[i] !== str1[i % g]) { - return ""; + return ''; } } for (let i = 0; i < str2.length; i++) { if (str2[i] !== str1[i % g]) { - return ""; + return ''; } } @@ -449,11 +535,42 @@ class Solution { } ``` +```csharp +public class Solution { + public string GcdOfStrings(string str1, string str2) { + int g = GCD(str1.Length, str2.Length); + + for (int i = 0; i < str1.Length; i++) { + if (str1[i] != str1[i % g]) { + return ""; + } + } + + for (int i = 0; i < str2.Length; i++) { + if (str2[i] != str1[i % g]) { + return ""; + } + } + + return str1.Substring(0, g); + } + + private int GCD(int a, int b) { + while (b != 0) { + int temp = b; + b = a % b; + a = temp; + } + return a; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n)$ -* Space complexity: $O(g)$ for the output string. +- Time complexity: $O(m + n)$ +- Space complexity: $O(g)$ for the output string. -> Where $m$ is the length of the string $str1$, $n$ is the length of the string $str2$, and $g$ is the GCD of $m$ and $n$. \ No newline at end of file +> Where $m$ is the length of the string $str1$, $n$ is the length of the string $str2$, and $g$ is the GCD of $m$ and $n$. diff --git a/articles/greatest-common-divisor-traversal.md b/articles/greatest-common-divisor-traversal.md index 79c11cf70..e68cd2095 100644 --- a/articles/greatest-common-divisor-traversal.md +++ b/articles/greatest-common-divisor-traversal.md @@ -13,13 +13,13 @@ class Solution: if gcd(nums[i], nums[j]) > 1: adj[i].append(j) adj[j].append(i) - + def dfs(node): visit[node] = True for nei in adj[node]: if not visit[nei]: dfs(nei) - + dfs(0) for node in visit: if not node: @@ -144,12 +144,59 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanTraverseAllPairs(int[] nums) { + int n = nums.Length; + bool[] visited = new bool[n]; + List[] adj = new List[n]; + for (int i = 0; i < n; i++) { + adj[i] = new List(); + } + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + if (GCD(nums[i], nums[j]) > 1) { + adj[i].Add(j); + adj[j].Add(i); + } + } + } + + void DFS(int node) { + visited[node] = true; + foreach (int neighbor in adj[node]) { + if (!visited[neighbor]) { + DFS(neighbor); + } + } + } + + DFS(0); + foreach (bool v in visited) { + if (!v) return false; + } + + return true; + } + + private int GCD(int a, int b) { + while (b != 0) { + int temp = b; + b = a % b; + a = temp; + } + return a; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2 \log n)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2 \log n)$ +- Space complexity: $O(n ^ 2)$ --- @@ -180,7 +227,7 @@ class UnionFind: self.Size[pu] += self.Size[pv] self.Parent[pv] = pu return True - + def isConnected(self): return self.n == 1 @@ -189,7 +236,7 @@ class Solution: uf = UnionFind(len(nums)) factor_index = {} # f -> index of value with factor f - for i, num in enumerate(nums): + for i, n in enumerate(nums): f = 2 while f * f <= n: if n % f == 0: @@ -205,8 +252,8 @@ class Solution: uf.union(i, factor_index[n]) else: factor_index[n] = i - - return uf.isConnected() + + return uf.isConnected() ``` ```java @@ -452,12 +499,93 @@ class Solution { } ``` +```csharp +public class Solution { + public class UnionFind { + public int Count; + private int[] Parent; + private int[] Size; + + public UnionFind(int n) { + Count = n; + Parent = new int[n]; + Size = new int[n]; + for (int i = 0; i < n; i++) { + Parent[i] = i; + Size[i] = 1; + } + } + + public int Find(int x) { + if (Parent[x] != x) { + Parent[x] = Find(Parent[x]); + } + return Parent[x]; + } + + public bool Union(int x, int y) { + int px = Find(x); + int py = Find(y); + if (px == py) return false; + Count--; + if (Size[px] < Size[py]) { + int temp = px; + px = py; + py = temp; + } + Size[px] += Size[py]; + Parent[py] = px; + return true; + } + + public bool IsConnected() { + return Count == 1; + } + } + + public bool CanTraverseAllPairs(int[] nums) { + int n = nums.Length; + if (n == 1) return true; + if (Array.Exists(nums, x => x == 1)) return false; + + UnionFind uf = new UnionFind(n); + Dictionary factorIndex = new Dictionary(); + + for (int i = 0; i < n; i++) { + int num = nums[i]; + int original = num; + for (int f = 2; f * f <= num; f++) { + if (num % f == 0) { + if (factorIndex.ContainsKey(f)) { + uf.Union(i, factorIndex[f]); + } else { + factorIndex[f] = i; + } + while (num % f == 0) { + num /= f; + } + } + } + if (num > 1) { + if (factorIndex.ContainsKey(num)) { + uf.Union(i, factorIndex[num]); + } else { + factorIndex[num] = i; + } + } + } + + return uf.IsConnected(); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n\sqrt {m})$ -* Space complexity: $O(n \log m)$ +- Time complexity: $O(m + n\sqrt {m})$ +- Space complexity: $O(n \log m)$ > Where $n$ is the size of the array $nums$ and $m$ is the maximum value in the array. @@ -765,7 +893,8 @@ class Solution { const uf = new UnionFind(N + MAX + 1); for (let i = 0; i < N; i++) { let num = nums[i]; - if (sieve[num] === 0) { // num is prime + if (sieve[num] === 0) { + // num is prime uf.union(i, N + num); continue; } @@ -790,12 +919,92 @@ class Solution { } ``` +```csharp +public class UnionFind { + public int[] Parent; + public int[] Size; + + public UnionFind(int n) { + Parent = new int[n]; + Size = new int[n]; + for (int i = 0; i < n; i++) { + Parent[i] = i; + Size[i] = 1; + } + } + + public int Find(int x) { + if (Parent[x] != x) { + Parent[x] = Find(Parent[x]); + } + return Parent[x]; + } + + public bool Union(int x, int y) { + int px = Find(x); + int py = Find(y); + if (px == py) return false; + if (Size[px] < Size[py]) { + int temp = px; + px = py; + py = temp; + } + Parent[py] = px; + Size[px] += Size[py]; + return true; + } +} + +public class Solution { + public bool CanTraverseAllPairs(int[] nums) { + int n = nums.Length; + if (n == 1) return true; + if (Array.Exists(nums, x => x == 1)) return false; + + int maxVal = nums.Max(); + int[] sieve = new int[maxVal + 1]; + for (int i = 2; i * i <= maxVal; i++) { + if (sieve[i] == 0) { + for (int j = i * i; j <= maxVal; j += i) { + if (sieve[j] == 0) sieve[j] = i; + } + } + } + + UnionFind uf = new UnionFind(n + maxVal + 1); + + for (int i = 0; i < n; i++) { + int num = nums[i]; + if (sieve[num] == 0) { + uf.Union(i, n + num); + continue; + } + + while (num > 1) { + int prime = sieve[num] != 0 ? sieve[num] : num; + uf.Union(i, n + prime); + while (num % prime == 0) { + num /= prime; + } + } + } + + int root = uf.Find(0); + for (int i = 1; i < n; i++) { + if (uf.Find(i) != root) return false; + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n \log m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(m + n \log m)$ +- Space complexity: $O(n + m)$ > Where $n$ is the size of the array $nums$ and $m$ is the maximum value in the array. @@ -822,7 +1031,7 @@ class Solution: for composite in range(p * p, MAX + 1, p): sieve[composite] = p p += 1 - + adj = defaultdict(list) for i in range(N): num = nums[i] @@ -1029,12 +1238,76 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanTraverseAllPairs(int[] nums) { + int N = nums.Length; + if (N == 1) return true; + if (Array.Exists(nums, num => num == 1)) return false; + + int MAX = nums.Max(); + int[] sieve = new int[MAX + 1]; + for (int p = 2; p * p <= MAX; p++) { + if (sieve[p] == 0) { + for (int mult = p * p; mult <= MAX; mult += p) { + if (sieve[mult] == 0) { + sieve[mult] = p; + } + } + } + } + + Dictionary> adj = new Dictionary>(); + for (int i = 0; i < N; i++) { + int num = nums[i]; + if (sieve[num] == 0) { + AddEdge(adj, i, N + num); + continue; + } + while (num > 1) { + int prime = sieve[num] != 0 ? sieve[num] : num; + AddEdge(adj, i, N + prime); + while (num % prime == 0) { + num /= prime; + } + } + } + + HashSet visited = new HashSet(); + DFS(0, adj, visited); + + for (int i = 0; i < N; i++) { + if (!visited.Contains(i)) return false; + } + + return true; + } + + private void AddEdge(Dictionary> adj, int u, int v) { + if (!adj.ContainsKey(u)) adj[u] = new List(); + if (!adj.ContainsKey(v)) adj[v] = new List(); + adj[u].Add(v); + adj[v].Add(u); + } + + private void DFS(int node, Dictionary> adj, HashSet visited) { + visited.Add(node); + if (!adj.ContainsKey(node)) return; + foreach (int nei in adj[node]) { + if (!visited.Contains(nei)) { + DFS(nei, adj, visited); + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n \log m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(m + n \log m)$ +- Space complexity: $O(n + m)$ > Where $n$ is the size of the array $nums$ and $m$ is the maximum value in the array. @@ -1249,7 +1522,8 @@ class Solution { const adj = new Map(); for (let i = 0; i < N; i++) { let num = nums[i]; - if (sieve[num] === 0) { // num is prime + if (sieve[num] === 0) { + // num is prime if (!adj.has(i)) adj.set(i, []); if (!adj.has(N + num)) adj.set(N + num, []); adj.get(i).push(N + num); @@ -1295,11 +1569,79 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanTraverseAllPairs(int[] nums) { + int N = nums.Length; + if (N == 1) return true; + if (nums.Contains(1)) return false; + + int MAX = nums.Max(); + int[] sieve = new int[MAX + 1]; + for (int p = 2; p * p <= MAX; p++) { + if (sieve[p] == 0) { + for (int composite = p * p; composite <= MAX; composite += p) { + if (sieve[composite] == 0) { + sieve[composite] = p; + } + } + } + } + + Dictionary> adj = new Dictionary>(); + for (int i = 0; i < N; i++) { + int num = nums[i]; + if (sieve[num] == 0) { + AddEdge(adj, i, N + num); + continue; + } + + while (num > 1) { + int prime = sieve[num] != 0 ? sieve[num] : num; + AddEdge(adj, i, N + prime); + while (num % prime == 0) { + num /= prime; + } + } + } + + HashSet visited = new HashSet(); + Queue queue = new Queue(); + queue.Enqueue(0); + visited.Add(0); + + while (queue.Count > 0) { + int node = queue.Dequeue(); + if (!adj.ContainsKey(node)) continue; + foreach (int nei in adj[node]) { + if (!visited.Contains(nei)) { + visited.Add(nei); + queue.Enqueue(nei); + } + } + } + + for (int i = 0; i < N; i++) { + if (!visited.Contains(i)) return false; + } + + return true; + } + + private void AddEdge(Dictionary> adj, int u, int v) { + if (!adj.ContainsKey(u)) adj[u] = new List(); + if (!adj.ContainsKey(v)) adj[v] = new List(); + adj[u].Add(v); + adj[v].Add(u); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n \log m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(m + n \log m)$ +- Space complexity: $O(n + m)$ -> Where $n$ is the size of the array $nums$ and $m$ is the maximum value in the array. \ No newline at end of file +> Where $n$ is the size of the array $nums$ and $m$ is the maximum value in the array. diff --git a/articles/grid-game.md b/articles/grid-game.md index 236f53012..fc232c649 100644 --- a/articles/grid-game.md +++ b/articles/grid-game.md @@ -14,7 +14,7 @@ class Solution: bottom1 = 0 for j in range(i, cols): bottom1 += grid[1][j] - + top2 = robot2 = 0 for j in range(cols): if j > i: @@ -24,9 +24,9 @@ class Solution: for k in range(j, i): bottom2 += grid[1][k] robot2 = max(robot2, top2 + bottom2) - + res = min(res, robot2) - + return res ``` @@ -43,20 +43,20 @@ public class Solution { for (int j = i; j < cols; j++) { bottom1 += grid[1][j]; } - + long top2 = 0, robot2 = 0; for (int j = 0; j < cols; j++) { if (j > i) { top2 += grid[0][j]; } - + long bottom2 = 0; for (int k = j; k < i; k++) { bottom2 += grid[1][k]; } robot2 = Math.max(robot2, top2 + bottom2); } - + res = Math.min(res, robot2); } @@ -119,7 +119,8 @@ class Solution { bottom1 += grid[1][j]; } - let top2 = 0, robot2 = 0; + let top2 = 0, + robot2 = 0; for (let j = 0; j < cols; j++) { if (j > i) { top2 += grid[0][j]; @@ -144,8 +145,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(1)$ --- @@ -260,8 +261,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -350,5 +351,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/grumpy-bookstore-owner.md b/articles/grumpy-bookstore-owner.md new file mode 100644 index 000000000..0f4b15d95 --- /dev/null +++ b/articles/grumpy-bookstore-owner.md @@ -0,0 +1,293 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maxSatisfied(self, customers: List[int], grumpy: List[int], minutes: int) -> int: + res, n = 0, len(customers) + for i in range(n): + if not grumpy[i]: + res += customers[i] + + satisfied = res + for i in range(n - minutes + 1): + cur = 0 + for j in range(i, i + minutes): + if grumpy[j]: + cur += customers[j] + res = max(res, satisfied + cur) + + return res +``` + +```java +public class Solution { + public int maxSatisfied(int[] customers, int[] grumpy, int minutes) { + int res = 0, n = customers.length; + for (int i = 0; i < n; i++) { + if (grumpy[i] == 0) { + res += customers[i]; + } + } + + int satisfied = res; + for (int i = 0; i <= n - minutes; i++) { + int cur = 0; + for (int j = i; j < i + minutes; j++) { + if (grumpy[j] == 1) { + cur += customers[j]; + } + } + res = Math.max(res, satisfied + cur); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxSatisfied(vector& customers, vector& grumpy, int minutes) { + int res = 0, n = customers.size(); + for (int i = 0; i < n; i++) { + if (grumpy[i] == 0) { + res += customers[i]; + } + } + + int satisfied = res; + for (int i = 0; i <= n - minutes; i++) { + int cur = 0; + for (int j = i; j < i + minutes; j++) { + if (grumpy[j] == 1) { + cur += customers[j]; + } + } + res = max(res, satisfied + cur); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} customers + * @param {number[]} grumpy + * @param {number} minutes + * @return {number} + */ + maxSatisfied(customers, grumpy, minutes) { + let res = 0, n = customers.length; + for (let i = 0; i < n; i++) { + if (grumpy[i] === 0) { + res += customers[i]; + } + } + + let satisfied = res; + for (let i = 0; i <= n - minutes; i++) { + let cur = 0; + for (let j = i; j < i + minutes; j++) { + if (grumpy[j] === 1) { + cur += customers[j]; + } + } + res = Math.max(res, satisfied + cur); + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int MaxSatisfied(int[] customers, int[] grumpy, int minutes) { + int res = 0, n = customers.Length; + for (int i = 0; i < n; i++) { + if (grumpy[i] == 0) { + res += customers[i]; + } + } + + int satisfied = res; + for (int i = 0; i <= n - minutes; i++) { + int cur = 0; + for (int j = i; j < i + minutes; j++) { + if (grumpy[j] == 1) { + cur += customers[j]; + } + } + res = Math.Max(res, satisfied + cur); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * m)$ +* Space complexity: $O(1)$ + +> Where $n$ is the size of the input array and $m$ is the number of minutes. + +--- + +## 2. Sliding Window + +::tabs-start + +```python +class Solution: + def maxSatisfied(self, customers: List[int], grumpy: List[int], minutes: int) -> int: + l = 0 + window = max_window = 0 + satisfied = 0 + + for r in range(len(customers)): + if grumpy[r]: + window += customers[r] + else: + satisfied += customers[r] + + if r - l + 1 > minutes: + if grumpy[l]: + window -= customers[l] + l += 1 + + max_window = max(window, max_window) + + return satisfied + max_window +``` + +```java +public class Solution { + public int maxSatisfied(int[] customers, int[] grumpy, int minutes) { + int l = 0, window = 0, maxWindow = 0, satisfied = 0; + + for (int r = 0; r < customers.length; r++) { + if (grumpy[r] == 1) { + window += customers[r]; + } else { + satisfied += customers[r]; + } + + if (r - l + 1 > minutes) { + if (grumpy[l] == 1) { + window -= customers[l]; + } + l++; + } + + maxWindow = Math.max(window, maxWindow); + } + + return satisfied + maxWindow; + } +} +``` + +```cpp +class Solution { +public: + int maxSatisfied(vector& customers, vector& grumpy, int minutes) { + int l = 0, window = 0, maxWindow = 0, satisfied = 0; + + for (int r = 0; r < customers.size(); r++) { + if (grumpy[r] == 1) { + window += customers[r]; + } else { + satisfied += customers[r]; + } + + if (r - l + 1 > minutes) { + if (grumpy[l] == 1) { + window -= customers[l]; + } + l++; + } + + maxWindow = max(window, maxWindow); + } + + return satisfied + maxWindow; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} customers + * @param {number[]} grumpy + * @param {number} minutes + * @return {number} + */ + maxSatisfied(customers, grumpy, minutes) { + let l = 0, window = 0, maxWindow = 0, satisfied = 0; + + for (let r = 0; r < customers.length; r++) { + if (grumpy[r] === 1) { + window += customers[r]; + } else { + satisfied += customers[r]; + } + + if (r - l + 1 > minutes) { + if (grumpy[l] === 1) { + window -= customers[l]; + } + l++; + } + + maxWindow = Math.max(window, maxWindow); + } + + return satisfied + maxWindow; + } +} +``` + +```csharp +public class Solution { + public int MaxSatisfied(int[] customers, int[] grumpy, int minutes) { + int l = 0, window = 0, maxWindow = 0, satisfied = 0; + + for (int r = 0; r < customers.Length; r++) { + if (grumpy[r] == 1) { + window += customers[r]; + } else { + satisfied += customers[r]; + } + + if (r - l + 1 > minutes) { + if (grumpy[l] == 1) { + window -= customers[l]; + } + l++; + } + + maxWindow = Math.Max(window, maxWindow); + } + + return satisfied + maxWindow; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/guess-number-higher-or-lower.md b/articles/guess-number-higher-or-lower.md index b6053e2e8..8651359e8 100644 --- a/articles/guess-number-higher-or-lower.md +++ b/articles/guess-number-higher-or-lower.md @@ -18,7 +18,7 @@ class Solution: ``` ```java -/** +/** * Forward declaration of guess API. * @param num your guess * @return -1 if num is higher than the picked number @@ -38,7 +38,7 @@ public class Solution extends GuessGame { ``` ```cpp -/** +/** * Forward declaration of guess API. * @param num your guess * @return -1 if num is higher than the picked number @@ -59,13 +59,13 @@ public: ``` ```javascript -/** +/** * Forward declaration of guess API. * @param {number} num your guess * @return -1 if num is higher than the picked number * 1 if num is lower than the picked number * otherwise return 0 - * var guess = function(num) {} + * function guess(num) {} */ class Solution { @@ -82,12 +82,32 @@ class Solution { } ``` +```csharp +/** + * Forward declaration of guess API. + * @param num your guess + * @return -1 if num is higher than the picked number + * 1 if num is lower than the picked number + * otherwise return 0 + * int guess(int num); + */ + +public class Solution : GuessGame { + public int GuessNumber(int n) { + for (int num = 1; num <= n; num++) { + if (guess(num) == 0) return num; + } + return n; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -118,7 +138,7 @@ class Solution: ``` ```java -/** +/** * Forward declaration of guess API. * @param num your guess * @return -1 if num is higher than the picked number @@ -146,7 +166,7 @@ public class Solution extends GuessGame { ``` ```cpp -/** +/** * Forward declaration of guess API. * @param num your guess * @return -1 if num is higher than the picked number @@ -175,13 +195,13 @@ public: ``` ```javascript -/** +/** * Forward declaration of guess API. * @param {number} num your guess * @return -1 if num is higher than the picked number * 1 if num is lower than the picked number * otherwise return 0 - * var guess = function(num) {} + * function guess(num) {} */ class Solution { @@ -190,7 +210,8 @@ class Solution { * @return {number} */ guessNumber(n) { - let l = 1, r = n; + let l = 1, + r = n; while (true) { let m = Math.floor((l + r) / 2); let res = guess(m); @@ -206,12 +227,42 @@ class Solution { } ``` +```csharp +/** + * Forward declaration of guess API. + * @param num your guess + * @return -1 if num is higher than the picked number + * 1 if num is lower than the picked number + * otherwise return 0 + * int guess(int num); + */ + +public class Solution : GuessGame { + public int GuessNumber(int n) { + int l = 1, r = n; + while (true) { + int m = l + (r - l) / 2; + int res = guess(m); + if (res > 0) { + l = m + 1; + } + else if (res < 0) { + r = m - 1; + } + else { + return m; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ --- @@ -247,7 +298,7 @@ class Solution: ``` ```java -/** +/** * Forward declaration of guess API. * @param num your guess * @return -1 if num is higher than the picked number @@ -278,7 +329,7 @@ public class Solution extends GuessGame { ``` ```cpp -/** +/** * Forward declaration of guess API. * @param num your guess * @return -1 if num is higher than the picked number @@ -310,13 +361,13 @@ public: ``` ```javascript -/** +/** * Forward declaration of guess API. * @param {number} num your guess * @return -1 if num is higher than the picked number * 1 if num is lower than the picked number * otherwise return 0 - * var guess = function(num) {} + * function guess(num) {} */ class Solution { @@ -325,7 +376,8 @@ class Solution { * @return {number} */ guessNumber(n) { - let l = 1, r = n; + let l = 1, + r = n; while (true) { let m1 = l + Math.floor((r - l) / 3); let m2 = r - Math.floor((r - l) / 3); @@ -344,9 +396,44 @@ class Solution { } ``` +```csharp +/** + * Forward declaration of guess API. + * @param num your guess + * @return -1 if num is higher than the picked number + * 1 if num is lower than the picked number + * otherwise return 0 + * int guess(int num); + */ + +public class Solution : GuessGame { + public int GuessNumber(int n) { + int l = 1, r = n; + while (true) { + int m1 = l + (r - l) / 3; + int m2 = r - (r - l) / 3; + + if (guess(m1) == 0) return m1; + if (guess(m2) == 0) return m2; + + if (guess(m1) + guess(m2) == 0) { + l = m1 + 1; + r = m2 - 1; + } + else if (guess(m1) == -1) { + r = m1 - 1; + } + else { + l = m2 + 1; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log_3 n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(\log_3 n)$ +- Space complexity: $O(1)$ diff --git a/articles/hand-of-straights.md b/articles/hand-of-straights.md index 728447cc2..b38a27e84 100644 --- a/articles/hand-of-straights.md +++ b/articles/hand-of-straights.md @@ -7,6 +7,7 @@ class Solution: def isNStraightHand(self, hand, groupSize): if len(hand) % groupSize: return False + count = Counter(hand) hand.sort() for num in hand: @@ -22,10 +23,12 @@ class Solution: public class Solution { public boolean isNStraightHand(int[] hand, int groupSize) { if (hand.length % groupSize != 0) return false; + Map count = new HashMap<>(); for (int num : hand) { count.put(num, count.getOrDefault(num, 0) + 1); } + Arrays.sort(hand); for (int num : hand) { if (count.get(num) > 0) { @@ -45,8 +48,10 @@ class Solution { public: bool isNStraightHand(vector& hand, int groupSize) { if (hand.size() % groupSize != 0) return false; + unordered_map count; for (int num : hand) count[num]++; + sort(hand.begin(), hand.end()); for (int num : hand) { if (count[num] > 0) { @@ -72,10 +77,12 @@ class Solution { if (hand.length % groupSize !== 0) { return false; } + const count = {}; for (const num of hand) { count[num] = (count[num] || 0) + 1; } + hand.sort((a, b) => a - b); for (const num of hand) { if (count[num] > 0) { @@ -94,10 +101,12 @@ class Solution { public class Solution { public bool IsNStraightHand(int[] hand, int groupSize) { if (hand.Length % groupSize != 0) return false; + var count = new Dictionary(); foreach (var num in hand) { count[num] = count.GetValueOrDefault(num, 0) + 1; } + Array.Sort(hand); foreach (var num in hand) { if (count[num] > 0) { @@ -148,7 +157,7 @@ class Solution { val count = HashMap() hand.forEach { count[it] = count.getOrDefault(it, 0) + 1 } hand.sort() - + for (num in hand) { if (count[num]!! > 0) { for (i in num until num + groupSize) { @@ -164,12 +173,42 @@ class Solution { } ``` +```swift +class Solution { + func isNStraightHand(_ hand: [Int], _ groupSize: Int) -> Bool { + if hand.count % groupSize != 0 { + return false + } + + var count = [Int: Int]() + for num in hand { + count[num, default: 0] += 1 + } + + let sortedHand = hand.sorted() + for num in sortedHand { + if let freq = count[num], freq > 0 { + for i in num..<(num + groupSize) { + if let f = count[i], f > 0 { + count[i] = f - 1 + } else { + return false + } + } + } + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -333,7 +372,7 @@ public class Solution { for (int i = first; i < first + groupSize; i++) { if (!count.ContainsKey(i) || count[i] == 0) return false; - + count[i]--; if (count[i] == 0) { if (i != minH.Peek()) @@ -410,12 +449,46 @@ class Solution { } ``` +```swift +class Solution { + func isNStraightHand(_ hand: [Int], _ groupSize: Int) -> Bool { + if hand.count % groupSize != 0 { + return false + } + + var count = [Int: Int]() + for n in hand { + count[n, default: 0] += 1 + } + + var minH = Heap(Array(count.keys)) + + while !minH.isEmpty { + guard let first = minH.min else { return false } + + for i in first..<(first + groupSize) { + guard let freq = count[i] else { return false } + count[i] = freq - 1 + if count[i] == 0 { + if i != minH.min { + return false + } + minH.removeMin() + } + } + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -434,7 +507,7 @@ class Solution: last_num, open_groups = -1, 0 for num in sorted(count): - if ((open_groups > 0 and num > last_num + 1) or + if ((open_groups > 0 and num > last_num + 1) or open_groups > count[num] ): return False @@ -463,7 +536,7 @@ public class Solution { int lastNum = -1, openGroups = 0; for (int num : count.keySet()) { - if ((openGroups > 0 && num > lastNum + 1) || + if ((openGroups > 0 && num > lastNum + 1) || openGroups > count.get(num)) { return false; } @@ -489,13 +562,13 @@ public: map count; for (int num : hand) count[num]++; - + queue q; int lastNum = -1, openGroups = 0; for (auto& entry : count) { int num = entry.first; - if ((openGroups > 0 && num > lastNum + 1) || + if ((openGroups > 0 && num > lastNum + 1) || openGroups > count[num]) { return false; } @@ -525,25 +598,30 @@ class Solution { if (hand.length % groupSize !== 0) return false; let count = new Map(); - hand.forEach(num => count.set(num, (count.get(num) || 0) + 1)); + hand.forEach((num) => count.set(num, (count.get(num) || 0) + 1)); let q = new Queue(); - let lastNum = -1, openGroups = 0; + let lastNum = -1, + openGroups = 0; + + Array.from(count.keys()) + .sort((a, b) => a - b) + .forEach((num) => { + if ( + (openGroups > 0 && num > lastNum + 1) || + openGroups > count.get(num) + ) { + return false; + } - Array.from(count.keys()).sort((a, b) => a - b).forEach(num => { - if ((openGroups > 0 && num > lastNum + 1) || - openGroups > count.get(num)) { - return false; - } + q.push(count.get(num) - openGroups); + lastNum = num; + openGroups = count.get(num); - q.push(count.get(num) - openGroups); - lastNum = num; - openGroups = count.get(num); - - if (q.size() === groupSize) { - openGroups -= q.pop(); - } - }); + if (q.size() === groupSize) { + openGroups -= q.pop(); + } + }); return openGroups === 0; } @@ -565,7 +643,7 @@ public class Solution { int lastNum = -1, openGroups = 0; foreach (int num in count.Keys) { - if ((openGroups > 0 && num > lastNum + 1) || + if ((openGroups > 0 && num > lastNum + 1) || openGroups > count[num]) { return false; } @@ -604,7 +682,7 @@ func isNStraightHand(hand []int, groupSize int) bool { lastNum, openGroups := -1, 0 for _, num := range keys { - if (openGroups > 0 && num > lastNum+1) || + if (openGroups > 0 && num > lastNum+1) || openGroups > count[num] { return false } @@ -637,7 +715,7 @@ class Solution { var openGroups = 0 for (num in count.keys) { - if ((openGroups > 0 && num > lastNum + 1) || + if ((openGroups > 0 && num > lastNum + 1) || openGroups > count[num]!!) { return false } @@ -655,12 +733,46 @@ class Solution { } ``` +```swift +class Solution { + func isNStraightHand(_ hand: [Int], _ groupSize: Int) -> Bool { + if hand.count % groupSize != 0 { + return false + } + + var count = [Int: Int]() + for num in hand { + count[num, default: 0] += 1 + } + + var queue = Deque() + var lastNum = -1 + var openGroups = 0 + + for (num, numCount) in count.sorted(by: { $0.key < $1.key }) { + if (openGroups > 0 && num > lastNum + 1) || openGroups > numCount { + return false + } + + queue.append(numCount - openGroups) + lastNum = num + openGroups = numCount + + if queue.count == groupSize { + openGroups -= queue.removeFirst() + } + } + return openGroups == 0 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -673,6 +785,7 @@ class Solution: def isNStraightHand(self, hand: List[int], groupSize: int) -> bool: if len(hand) % groupSize != 0: return False + count = Counter(hand) for num in hand: start = num @@ -692,11 +805,12 @@ class Solution: public class Solution { public boolean isNStraightHand(int[] hand, int groupSize) { if (hand.length % groupSize != 0) return false; + Map count = new HashMap<>(); for (int num : hand) { count.put(num, count.getOrDefault(num, 0) + 1); } - + for (int num : hand) { int start = num; while (count.getOrDefault(start - 1, 0) > 0) start--; @@ -720,9 +834,10 @@ class Solution { public: bool isNStraightHand(vector& hand, int groupSize) { if (hand.size() % groupSize != 0) return false; + unordered_map count; for (int num : hand) count[num]++; - + for (int num : hand) { int start = num; while (count[start - 1] > 0) start--; @@ -750,9 +865,10 @@ class Solution { */ isNStraightHand(hand, groupSize) { if (hand.length % groupSize !== 0) return false; + const count = new Map(); - hand.forEach(num => count.set(num, (count.get(num) || 0) + 1)); - + hand.forEach((num) => count.set(num, (count.get(num) || 0) + 1)); + for (const num of hand) { let start = num; while (count.get(start - 1) > 0) start--; @@ -775,6 +891,7 @@ class Solution { public class Solution { public bool IsNStraightHand(int[] hand, int groupSize) { if (hand.Length % groupSize != 0) return false; + Dictionary count = new Dictionary(); foreach (int num in hand) { if (!count.ContainsKey(num)) count[num] = 0; @@ -819,7 +936,7 @@ func isNStraightHand(hand []int, groupSize int) bool { for count[start-1] > 0 { start-- } - + for start <= num { for count[start] > 0 { for i := start; i < start+groupSize; i++ { @@ -867,9 +984,44 @@ class Solution { } ``` +```swift +class Solution { + func isNStraightHand(_ hand: [Int], _ groupSize: Int) -> Bool { + if hand.count % groupSize != 0 { + return false + } + + var count = [Int: Int]() + for num in hand { + count[num, default: 0] += 1 + } + + for num in hand { + var start = num + while (count[start - 1] ?? 0) > 0 { + start -= 1 + } + while start <= num { + while (count[start] ?? 0) > 0 { + for i in start..<(start + groupSize) { + if (count[i] ?? 0) == 0 { + return false + } + count[i]! -= 1 + } + } + start += 1 + } + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/height-checker.md b/articles/height-checker.md new file mode 100644 index 000000000..14b3e474b --- /dev/null +++ b/articles/height-checker.md @@ -0,0 +1,206 @@ +## 1. Sorting + +::tabs-start + +```python +class Solution: + def heightChecker(self, heights: List[int]) -> int: + expected = sorted(heights) + + res = 0 + for i in range(len(heights)): + if heights[i] != expected[i]: + res += 1 + + return res +``` + +```java +public class Solution { + public int heightChecker(int[] heights) { + int[] expected = Arrays.copyOf(heights, heights.length); + Arrays.sort(expected); + + int res = 0; + for (int i = 0; i < heights.length; i++) { + if (heights[i] != expected[i]) { + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int heightChecker(vector& heights) { + vector expected = heights; + sort(expected.begin(), expected.end()); + + int res = 0; + for (int i = 0; i < heights.size(); i++) { + if (heights[i] != expected[i]) { + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @return {number} + */ + heightChecker(heights) { + const expected = [...heights].sort((a, b) => a - b); + + let res = 0; + for (let i = 0; i < heights.length; i++) { + if (heights[i] !== expected[i]) { + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Counting Sort + +::tabs-start + +```python +class Solution: + def heightChecker(self, heights: List[int]) -> int: + count = [0] * 101 + for h in heights: + count[h] += 1 + + expected = [] + for h in range(1, 101): + c = count[h] + for _ in range(c): + expected.append(h) + + res = 0 + for i in range(len(heights)): + if heights[i] != expected[i]: + res += 1 + + return res +``` + +```java +public class Solution { + public int heightChecker(int[] heights) { + int[] count = new int[101]; + for (int h : heights) { + count[h]++; + } + + List expected = new ArrayList<>(); + for (int h = 1; h <= 100; h++) { + int c = count[h]; + for (int i = 0; i < c; i++) { + expected.add(h); + } + } + + int res = 0; + for (int i = 0; i < heights.length; i++) { + if (heights[i] != expected.get(i)) { + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int heightChecker(vector& heights) { + int count[101] = {}; + for (int h : heights) { + count[h]++; + } + + vector expected; + for (int h = 1; h <= 100; h++) { + int c = count[h]; + for (int i = 0; i < c; i++) { + expected.push_back(h); + } + } + + int res = 0; + for (int i = 0; i < heights.size(); i++) { + if (heights[i] != expected[i]) { + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @return {number} + */ + heightChecker(heights) { + const count = new Array(101).fill(0); + for (let h of heights) { + count[h]++; + } + + const expected = []; + for (let h = 1; h <= 100; h++) { + let c = count[h]; + for (let i = 0; i < c; i++) { + expected.push(h); + } + } + + let res = 0; + for (let i = 0; i < heights.length; i++) { + if (heights[i] !== expected[i]) { + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + k)$ +- Space complexity: $O(n + k)$ + +> Where $n$ is the size of the input array, and $k$ is the range of numbers. diff --git a/articles/house-robber-ii.md b/articles/house-robber-ii.md index 9157646c6..17cd92a3e 100644 --- a/articles/house-robber-ii.md +++ b/articles/house-robber-ii.md @@ -10,8 +10,8 @@ class Solution: def dfs(i, flag): if i >= len(nums) or (flag and i == len(nums) - 1): return 0 - - return max(dfs(i + 1, flag), + + return max(dfs(i + 1, flag), nums[i] + dfs(i + 2, flag or i == 0)) return max(dfs(0, True), dfs(1, False)) ``` @@ -22,12 +22,12 @@ public class Solution { if (nums.length == 1) return nums[0]; return Math.max(dfs(0, true, nums), dfs(1, false, nums)); } - + private int dfs(int i, boolean flag, int[] nums) { - if (i >= nums.length || (flag && i == nums.length - 1)) + if (i >= nums.length || (flag && i == nums.length - 1)) return 0; - return Math.max(dfs(i + 1, flag, nums), + return Math.max(dfs(i + 1, flag, nums), nums[i] + dfs(i + 2, flag || i == 0, nums)); } } @@ -43,10 +43,10 @@ public: private: int dfs(int i, bool flag, vector& nums) { - if (i >= nums.size() || (flag && i == nums.size() - 1)) + if (i >= nums.size() || (flag && i == nums.size() - 1)) return 0; - return max(dfs(i + 1, flag, nums), + return max(dfs(i + 1, flag, nums), nums[i] + dfs(i + 2, flag || i == 0, nums)); } }; @@ -62,13 +62,14 @@ class Solution { if (nums.length === 1) return nums[0]; const dfs = (i, flag) => { - if (i >= nums.length || (flag && i === nums.length - 1)) - return 0; + if (i >= nums.length || (flag && i === nums.length - 1)) return 0; + + return Math.max( + dfs(i + 1, flag), + nums[i] + dfs(i + 2, flag || i === 0), + ); + }; - return Math.max(dfs(i + 1, flag), - nums[i] + dfs(i + 2, flag || i === 0)); - } - return Math.max(dfs(0, true), dfs(1, false)); } } @@ -80,12 +81,12 @@ public class Solution { if (nums.Length == 1) return nums[0]; return Math.Max(Dfs(0, true, nums), Dfs(1, false, nums)); } - + private int Dfs(int i, bool flag, int[] nums) { - if (i >= nums.Length || (flag && i == nums.Length - 1)) + if (i >= nums.Length || (flag && i == nums.Length - 1)) return 0; - return Math.Max(Dfs(i + 1, flag, nums), + return Math.Max(Dfs(i + 1, flag, nums), nums[i] + Dfs(i + 2, flag || i == 0, nums)); } } @@ -123,7 +124,7 @@ class Solution { if (i >= nums.size || (flag && i == nums.size - 1)) { return 0 } - return maxOf(dfs(i + 1, flag), + return maxOf(dfs(i + 1, flag), nums[i] + dfs(i + 2, flag || i == 0)) } return maxOf(dfs(0, true), dfs(1, false)) @@ -131,12 +132,31 @@ class Solution { } ``` +```swift +class Solution { + func rob(_ nums: [Int]) -> Int { + if nums.count == 1 { + return nums[0] + } + + func dfs(_ i: Int, _ flag: Bool) -> Int { + if i >= nums.count || (flag && i == nums.count - 1) { + return 0 + } + return max(dfs(i + 1, flag), nums[i] + dfs(i + 2, flag || i == 0)) + } + + return max(dfs(0, true), dfs(1, false)) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -157,7 +177,7 @@ class Solution: return 0 if memo[i][flag] != -1: return memo[i][flag] - memo[i][flag] = max(dfs(i + 1, flag), + memo[i][flag] = max(dfs(i + 1, flag), nums[i] + dfs(i + 2, flag or (i == 0))) return memo[i][flag] @@ -167,25 +187,25 @@ class Solution: ```java public class Solution { private int[][] memo; - + public int rob(int[] nums) { if (nums.length == 1) return nums[0]; - + memo = new int[nums.length][2]; for (int i = 0; i < nums.length; i++) { memo[i][0] = -1; memo[i][1] = -1; } - + return Math.max(dfs(0, 1, nums), dfs(1, 0, nums)); } - + private int dfs(int i, int flag, int[] nums) { - if (i >= nums.length || (flag == 1 && i == nums.length - 1)) + if (i >= nums.length || (flag == 1 && i == nums.length - 1)) return 0; if (memo[i][flag] != -1) return memo[i][flag]; - memo[i][flag] = Math.max(dfs(i + 1, flag, nums), + memo[i][flag] = Math.max(dfs(i + 1, flag, nums), nums[i] + dfs(i + 2, flag | (i == 0 ? 1 : 0), nums)); return memo[i][flag]; } @@ -195,22 +215,22 @@ public class Solution { ```cpp class Solution { vector> memo; - + public: int rob(vector& nums) { if (nums.size() == 1) return nums[0]; - + memo.resize(nums.size(), vector(2, -1)); return max(dfs(0, 1, nums), dfs(1, 0, nums)); } private: int dfs(int i, int flag, vector& nums) { - if (i >= nums.size() || (flag == 1 && i == nums.size() - 1)) + if (i >= nums.size() || (flag == 1 && i == nums.size() - 1)) return 0; - if (memo[i][flag] != -1) + if (memo[i][flag] != -1) return memo[i][flag]; - memo[i][flag] = max(dfs(i + 1, flag, nums), + memo[i][flag] = max(dfs(i + 1, flag, nums), nums[i] + dfs(i + 2, flag | (i == 0 ? 1 : 0), nums)); return memo[i][flag]; } @@ -230,17 +250,15 @@ class Solution { const memo = Array.from({ length: n }, () => Array(2).fill(-1)); const dfs = (i, flag) => { - if (i >= n || (flag && (i === n - 1))) - return 0; - if (memo[i][flag] !== -1) - return memo[i][flag]; + if (i >= n || (flag && i === n - 1)) return 0; + if (memo[i][flag] !== -1) return memo[i][flag]; memo[i][flag] = Math.max( - dfs(i + 1, flag), - nums[i] + dfs(i + 2, flag | (i === 0)) + dfs(i + 1, flag), + nums[i] + dfs(i + 2, flag | (i === 0)), ); return memo[i][flag]; - } + }; return Math.max(dfs(0, 1), dfs(1, 0)); } @@ -253,21 +271,21 @@ public class Solution { public int Rob(int[] nums) { if (nums.Length == 1) return nums[0]; - + memo = new int[nums.Length][]; for (int i = 0; i < nums.Length; i++) { memo[i] = new int[] { -1, -1 }; } - + return Math.Max(Dfs(0, 1, nums), Dfs(1, 0, nums)); } private int Dfs(int i, int flag, int[] nums) { - if (i >= nums.Length || (flag == 1 && i == nums.Length - 1)) + if (i >= nums.Length || (flag == 1 && i == nums.Length - 1)) return 0; - if (memo[i][flag] != -1) + if (memo[i][flag] != -1) return memo[i][flag]; - memo[i][flag] = Math.Max(Dfs(i + 1, flag, nums), + memo[i][flag] = Math.Max(Dfs(i + 1, flag, nums), nums[i] + Dfs(i + 2, flag | (i == 0 ? 1 : 0), nums)); return memo[i][flag]; } @@ -326,7 +344,7 @@ class Solution { if (memo[i][flag] != -1) { return memo[i][flag] } - memo[i][flag] = maxOf(dfs(i + 1, flag), + memo[i][flag] = maxOf(dfs(i + 1, flag), nums[i] + dfs(i + 2, flag or if (i == 0) 1 else 0)) return memo[i][flag] } @@ -336,12 +354,41 @@ class Solution { } ``` +```swift +class Solution { + func rob(_ nums: [Int]) -> Int { + if nums.count == 1 { + return nums[0] + } + + var memo = Array(repeating: Array(repeating: -1, count: 2), count: nums.count) + + func dfs(_ i: Int, _ flag: Bool) -> Int { + if i >= nums.count || (flag && i == nums.count - 1) { + return 0 + } + if memo[i][flag ? 1 : 0] != -1 { + return memo[i][flag ? 1 : 0] + } + + memo[i][flag ? 1 : 0] = max( + dfs(i + 1, flag), nums[i] + dfs(i + 2, flag || i == 0) + ) + + return memo[i][flag ? 1 : 0] + } + + return max(dfs(0, true), dfs(1, false)) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -354,22 +401,22 @@ class Solution: def rob(self, nums: List[int]) -> int: if len(nums) == 1: return nums[0] - return max(self.helper(nums[1:]), + return max(self.helper(nums[1:]), self.helper(nums[:-1])) - + def helper(self, nums: List[int]) -> int: if not nums: return 0 if len(nums) == 1: return nums[0] - + dp = [0] * len(nums) dp[0] = nums[0] dp[1] = max(nums[0], nums[1]) - + for i in range(2, len(nums)): dp[i] = max(dp[i - 1], nums[i] + dp[i - 2]) - + return dp[-1] ``` @@ -436,8 +483,10 @@ class Solution { if (nums.length === 0) return 0; if (nums.length === 1) return nums[0]; - return Math.max(this.helper(nums.slice(1)), - this.helper(nums.slice(0, -1))); + return Math.max( + this.helper(nums.slice(1)), + this.helper(nums.slice(0, -1)), + ); } /** @@ -528,7 +577,7 @@ class Solution { if (nums.size == 1) { return nums[0] } - return max(helper(nums.copyOfRange(1, nums.size)), + return max(helper(nums.copyOfRange(1, nums.size)), helper(nums.copyOfRange(0, nums.size - 1))) } @@ -553,12 +602,42 @@ class Solution { } ``` +```swift +class Solution { + func rob(_ nums: [Int]) -> Int { + if nums.count == 1 { + return nums[0] + } + return max(helper(Array(nums[1...])), helper(Array(nums[..<(nums.count - 1)]))) + } + + func helper(_ nums: [Int]) -> Int { + if nums.isEmpty { + return 0 + } + if nums.count == 1 { + return nums[0] + } + + var dp = [Int](repeating: 0, count: nums.count) + dp[0] = nums[0] + dp[1] = max(nums[0], nums[1]) + + for i in 2.. int: - return max(nums[0], self.helper(nums[1:]), + return max(nums[0], self.helper(nums[1:]), self.helper(nums[:-1])) def helper(self, nums): @@ -585,10 +664,10 @@ class Solution: ```java public class Solution { - + public int rob(int[] nums) { - return Math.max(nums[0], - Math.max(helper(Arrays.copyOfRange(nums, 1, nums.length)), + return Math.max(nums[0], + Math.max(helper(Arrays.copyOfRange(nums, 1, nums.length)), helper(Arrays.copyOfRange(nums, 0, nums.length - 1)))); } @@ -663,12 +742,12 @@ class Solution { ```csharp public class Solution { - + public int Rob(int[] nums) { - if (nums.Length == 1) + if (nums.Length == 1) return nums[0]; - return Math.Max(Helper(nums[1..]), + return Math.Max(Helper(nums[1..]), Helper(nums[..^1])); } @@ -689,7 +768,7 @@ func rob(nums []int) int { if len(nums) == 0 { return 0 } - return max(nums[0], max(helper(nums[1:]), + return max(nums[0], max(helper(nums[1:]), helper(nums[:len(nums)-1]))) } @@ -715,8 +794,8 @@ func max(a, b int) int { ```kotlin class Solution { fun rob(nums: IntArray): Int { - return maxOf(nums[0], - maxOf(helper(nums.copyOfRange(1, nums.size)), + return maxOf(nums[0], + maxOf(helper(nums.copyOfRange(1, nums.size)), helper(nums.copyOfRange(0, nums.size - 1)))) } @@ -734,9 +813,41 @@ class Solution { } ``` +```swift +class Solution { + func rob(_ nums: [Int]) -> Int { + if nums.isEmpty { + return 0 + } + if nums.count == 1 { + return nums[0] + } + + let candidate1 = nums[0] + let candidate2 = helper(Array(nums[1.. Int { + var rob1 = 0 + var rob2 = 0 + + for num in nums { + let newRob = max(rob1 + num, rob2) + rob1 = rob2 + rob2 = newRob + } + + return rob2 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/house-robber-iii.md b/articles/house-robber-iii.md index 08d521c95..a0e24cb96 100644 --- a/articles/house-robber-iii.md +++ b/articles/house-robber-iii.md @@ -13,13 +13,13 @@ class Solution: def rob(self, root: Optional[TreeNode]) -> int: if not root: return 0 - + res = root.val if root.left: res += self.rob(root.left.left) + self.rob(root.left.right) if root.right: res += self.rob(root.right.left) + self.rob(root.right.right) - + res = max(res, self.rob(root.left) + self.rob(root.right)) return res ``` @@ -128,12 +128,44 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public int Rob(TreeNode root) { + if (root == null) return 0; + + int res = root.val; + if (root.left != null) { + res += Rob(root.left.left) + Rob(root.left.right); + } + if (root.right != null) { + res += Rob(root.right.left) + Rob(root.right.right); + } + + res = Math.Max(res, Rob(root.left) + Rob(root.right)); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -155,16 +187,16 @@ class Solution: def dfs(root): if root in cache: return cache[root] - + cache[root] = root.val if root.left: cache[root] += dfs(root.left.left) + dfs(root.left.right) if root.right: cache[root] += dfs(root.right.left) + dfs(root.right.right) - + cache[root] = max(cache[root], dfs(root.left) + dfs(root.right)) return cache[root] - + return dfs(root) ``` @@ -299,12 +331,52 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + private Dictionary cache = new(); + + public int Rob(TreeNode root) { + return Dfs(root); + } + + private int Dfs(TreeNode root) { + if (root == null) return 0; + if (cache.ContainsKey(root)) return cache[root]; + + int res = root.val; + if (root.left != null) { + res += Dfs(root.left.left) + Dfs(root.left.right); + } + if (root.right != null) { + res += Dfs(root.right.left) + Dfs(root.right.right); + } + + res = Math.Max(res, Dfs(root.left) + Dfs(root.right)); + cache[root] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -367,7 +439,7 @@ public class Solution { int[] rightPair = dfs(root.right); int withRoot = root.val + leftPair[1] + rightPair[1]; - int withoutRoot = Math.max(leftPair[0], leftPair[1]) + + int withoutRoot = Math.max(leftPair[0], leftPair[1]) + Math.max(rightPair[0], rightPair[1]); return new int[]{withRoot, withoutRoot}; @@ -404,7 +476,7 @@ private: auto rightPair = dfs(root->right); int withRoot = root->val + leftPair.second + rightPair.second; - int withoutRoot = max(leftPair.first, leftPair.second) + + int withoutRoot = max(leftPair.first, leftPair.second) + max(rightPair.first, rightPair.second); return {withRoot, withoutRoot}; @@ -449,9 +521,43 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public int Rob(TreeNode root) { + var result = Dfs(root); + return Math.Max(result.withRoot, result.withoutRoot); + } + + private (int withRoot, int withoutRoot) Dfs(TreeNode root) { + if (root == null) return (0, 0); + + var left = Dfs(root.left); + var right = Dfs(root.right); + + int withRoot = root.val + left.withoutRoot + right.withoutRoot; + int withoutRoot = Math.Max(left.withRoot, left.withoutRoot) + Math.Max(right.withRoot, right.withoutRoot); + + return (withRoot, withoutRoot); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for recursion stack. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. diff --git a/articles/house-robber.md b/articles/house-robber.md index 6122135cb..e8d9ca34e 100644 --- a/articles/house-robber.md +++ b/articles/house-robber.md @@ -5,13 +5,13 @@ ```python class Solution: def rob(self, nums: List[int]) -> int: - + def dfs(i): if i >= len(nums): return 0 return max(dfs(i + 1), nums[i] + dfs(i + 2)) - + return dfs(0) ``` @@ -55,14 +55,12 @@ class Solution { * @return {number} */ rob(nums) { - const dfs = (i) => { if (i >= nums.length) { return 0; } - return Math.max(dfs(i + 1), - nums[i] + dfs(i + 2)); - } + return Math.max(dfs(i + 1), nums[i] + dfs(i + 2)); + }; return dfs(0); } } @@ -118,12 +116,27 @@ class Solution { } ``` +```swift +class Solution { + func rob(_ nums: [Int]) -> Int { + func dfs(_ i: Int) -> Int { + if i >= nums.count { + return 0 + } + return max(dfs(i + 1), nums[i] + dfs(i + 2)) + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -143,7 +156,7 @@ class Solution: return memo[i] memo[i] = max(dfs(i + 1), nums[i] + dfs(i + 2)) return memo[i] - + return dfs(0) ``` @@ -164,7 +177,7 @@ public class Solution { if (memo[i] != -1) { return memo[i]; } - memo[i] = Math.max(dfs(nums, i + 1), + memo[i] = Math.max(dfs(nums, i + 1), nums[i] + dfs(nums, i + 2)); return memo[i]; } @@ -175,7 +188,7 @@ public class Solution { class Solution { public: vector memo; - + int rob(vector& nums) { memo.resize(nums.size(), -1); return dfs(nums, 0); @@ -210,9 +223,8 @@ class Solution { if (memo[i] !== -1) { return memo[i]; } - return memo[i] = Math.max(dfs(i + 1), - nums[i] + dfs(i + 2)); - } + return (memo[i] = Math.max(dfs(i + 1), nums[i] + dfs(i + 2))); + }; return dfs(0); } } @@ -291,12 +303,33 @@ class Solution { } ``` +```swift +class Solution { + func rob(_ nums: [Int]) -> Int { + var memo = Array(repeating: -1, count: nums.count) + + func dfs(_ i: Int) -> Int { + if i >= nums.count { + return 0 + } + if memo[i] != -1 { + return memo[i] + } + memo[i] = max(dfs(i + 1), nums[i] + dfs(i + 2)) + return memo[i] + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -311,14 +344,14 @@ class Solution: return 0 if len(nums) == 1: return nums[0] - + dp = [0] * len(nums) dp[0] = nums[0] dp[1] = max(nums[0], nums[1]) - + for i in range(2, len(nums)): dp[i] = max(dp[i - 1], nums[i] + dp[i - 2]) - + return dp[-1] ``` @@ -455,12 +488,35 @@ class Solution { } ``` +```swift +class Solution { + func rob(_ nums: [Int]) -> Int { + if nums.isEmpty { + return 0 + } + if nums.count == 1 { + return nums[0] + } + + var dp = Array(repeating: 0, count: nums.count) + dp[0] = nums[0] + dp[1] = max(nums[0], nums[1]) + + for i in 2.. Int { + var rob1 = 0, rob2 = 0 + + for num in nums { + let temp = max(num + rob1, rob2) + rob1 = rob2 + rob2 = temp + } + + return rob2 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/image-smoother.md b/articles/image-smoother.md new file mode 100644 index 000000000..00b007e79 --- /dev/null +++ b/articles/image-smoother.md @@ -0,0 +1,554 @@ +## 1. Iteration (Using Extra Matrix) + +::tabs-start + +```python +class Solution: + def imageSmoother(self, img: List[List[int]]) -> List[List[int]]: + ROWS, COLS = len(img), len(img[0]) + res = [[0] * COLS for _ in range(ROWS)] + + for r in range(ROWS): + for c in range(COLS): + total, cnt = 0, 0 + for i in range(r - 1, r + 2): + for j in range(c - 1, c + 2): + if 0 <= i < ROWS and 0 <= j < COLS: + total += img[i][j] + cnt += 1 + res[r][c] = total // cnt + + return res +``` + +```java +public class Solution { + public int[][] imageSmoother(int[][] img) { + int ROWS = img.length, COLS = img[0].length; + int[][] res = new int[ROWS][COLS]; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int total = 0, count = 0; + for (int i = r - 1; i <= r + 1; i++) { + for (int j = c - 1; j <= c + 1; j++) { + if (i >= 0 && i < ROWS && j >= 0 && j < COLS) { + total += img[i][j]; + count++; + } + } + } + res[r][c] = total / count; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> imageSmoother(vector>& img) { + int ROWS = img.size(), COLS = img[0].size(); + vector> res(ROWS, vector(COLS, 0)); + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int total = 0, count = 0; + for (int i = r - 1; i <= r + 1; i++) { + for (int j = c - 1; j <= c + 1; j++) { + if (i >= 0 && i < ROWS && j >= 0 && j < COLS) { + total += img[i][j]; + count++; + } + } + } + res[r][c] = total / count; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} img + * @return {number[][]} + */ + imageSmoother(img) { + const ROWS = img.length, + COLS = img[0].length; + const res = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + let total = 0, + count = 0; + for (let i = r - 1; i <= r + 1; i++) { + for (let j = c - 1; j <= c + 1; j++) { + if (i >= 0 && i < ROWS && j >= 0 && j < COLS) { + total += img[i][j]; + count++; + } + } + } + res[r][c] = Math.floor(total / count); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ + +> Where $n$ is the number of rows and $m$ is the number of columns of the matrix. + +--- + +## 2. Iteration (Using Extra Row) + +::tabs-start + +```python +class Solution: + def imageSmoother(self, img: List[List[int]]) -> List[List[int]]: + ROWS, COLS = len(img), len(img[0]) + prev_row = img[0][:] + + for r in range(ROWS): + curr_row = img[r][:] + + for c in range(COLS): + total, cnt = 0, 0 + for i in range(max(0, r - 1), min(ROWS, r + 2)): + for j in range(max(0, c - 1), min(COLS, c + 2)): + if i == r: + total += curr_row[j] + elif i == r - 1: + total += prev_row[j] + else: + total += img[i][j] + cnt += 1 + img[r][c] = total // cnt + + prev_row = curr_row + + return img +``` + +```java +public class Solution { + public int[][] imageSmoother(int[][] img) { + int ROWS = img.length, COLS = img[0].length; + int[] prevRow = img[0].clone(); + + for (int r = 0; r < ROWS; r++) { + int[] currRow = img[r].clone(); + + for (int c = 0; c < COLS; c++) { + int total = 0, count = 0; + for (int i = Math.max(0, r - 1); i < Math.min(ROWS, r + 2); i++) { + for (int j = Math.max(0, c - 1); j < Math.min(COLS, c + 2); j++) { + if (i == r) { + total += currRow[j]; + } else if (i == r - 1) { + total += prevRow[j]; + } else { + total += img[i][j]; + } + count++; + } + } + img[r][c] = total / count; + } + + prevRow = currRow; + } + + return img; + } +} +``` + +```cpp +class Solution { +public: + vector> imageSmoother(vector>& img) { + int ROWS = img.size(), COLS = img[0].size(); + vector prevRow = img[0]; + + for (int r = 0; r < ROWS; r++) { + vector currRow = img[r]; + + for (int c = 0; c < COLS; c++) { + int total = 0, count = 0; + for (int i = max(0, r - 1); i < min(ROWS, r + 2); i++) { + for (int j = max(0, c - 1); j < min(COLS, c + 2); j++) { + if (i == r) { + total += currRow[j]; + } else if (i == r - 1) { + total += prevRow[j]; + } else { + total += img[i][j]; + } + count++; + } + } + img[r][c] = total / count; + } + + prevRow = currRow; + } + + return img; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} img + * @return {number[][]} + */ + imageSmoother(img) { + const ROWS = img.length, + COLS = img[0].length; + let prevRow = [...img[0]]; + + for (let r = 0; r < ROWS; r++) { + let currRow = [...img[r]]; + + for (let c = 0; c < COLS; c++) { + let total = 0, + count = 0; + for ( + let i = Math.max(0, r - 1); + i < Math.min(ROWS, r + 2); + i++ + ) { + for ( + let j = Math.max(0, c - 1); + j < Math.min(COLS, c + 2); + j++ + ) { + if (i === r) { + total += currRow[j]; + } else if (i === r - 1) { + total += prevRow[j]; + } else { + total += img[i][j]; + } + count++; + } + } + img[r][c] = Math.floor(total / count); + } + + prevRow = currRow; + } + + return img; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m)$ +- Space complexity: $O(n)$ extra space. + +> Where $n$ is the number of rows and $m$ is the number of columns of the matrix. + +--- + +## 3. Iteration (Without Extra Space) + +::tabs-start + +```python +class Solution: + def imageSmoother(self, img: List[List[int]]) -> List[List[int]]: + ROWS, COLS = len(img), len(img[0]) + LIMIT = 256 + + for r in range(ROWS): + for c in range(COLS): + total, cnt = 0, 0 + for i in range(max(0, r - 1), min(ROWS, r + 2)): + for j in range(max(0, c - 1), min(COLS, c + 2)): + total += img[i][j] % LIMIT + cnt += 1 + img[r][c] += (total // cnt) * LIMIT + + for r in range(ROWS): + for c in range(COLS): + img[r][c] //= LIMIT + + return img +``` + +```java +public class Solution { + public int[][] imageSmoother(int[][] img) { + int ROWS = img.length, COLS = img[0].length; + int LIMIT = 256; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int total = 0, count = 0; + for (int i = Math.max(0, r - 1); i < Math.min(ROWS, r + 2); i++) { + for (int j = Math.max(0, c - 1); j < Math.min(COLS, c + 2); j++) { + total += img[i][j] % LIMIT; + count++; + } + } + img[r][c] += (total / count) * LIMIT; + } + } + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + img[r][c] /= LIMIT; + } + } + + return img; + } +} +``` + +```cpp +class Solution { +public: + vector> imageSmoother(vector>& img) { + int ROWS = img.size(), COLS = img[0].size(); + int LIMIT = 256; + + for (int r = 0; r < ROWS; ++r) { + for (int c = 0; c < COLS; ++c) { + int total = 0, count = 0; + for (int i = max(0, r - 1); i < min(ROWS, r + 2); ++i) { + for (int j = max(0, c - 1); j < min(COLS, c + 2); ++j) { + total += img[i][j] % LIMIT; + count++; + } + } + img[r][c] += (total / count) * LIMIT; + } + } + + for (int r = 0; r < ROWS; ++r) { + for (int c = 0; c < COLS; ++c) { + img[r][c] /= LIMIT; + } + } + + return img; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} img + * @return {number[][]} + */ + imageSmoother(img) { + const ROWS = img.length, + COLS = img[0].length; + const LIMIT = 256; + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + let total = 0, + count = 0; + for ( + let i = Math.max(0, r - 1); + i < Math.min(ROWS, r + 2); + i++ + ) { + for ( + let j = Math.max(0, c - 1); + j < Math.min(COLS, c + 2); + j++ + ) { + total += img[i][j] % LIMIT; + count++; + } + } + img[r][c] += Math.floor(total / count) * LIMIT; + } + } + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + img[r][c] = Math.floor(img[r][c] / LIMIT); + } + } + + return img; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m)$ +- Space complexity: $O(1)$ extra space. + +> Where $n$ is the number of rows and $m$ is the number of columns of the matrix. + +--- + +## 4. Bit Mask + +::tabs-start + +```python +class Solution: + def imageSmoother(self, img: List[List[int]]) -> List[List[int]]: + ROWS, COLS = len(img), len(img[0]) + + for r in range(ROWS): + for c in range(COLS): + total, cnt = 0, 0 + for i in range(r - 1, r + 2): + for j in range(c - 1, c + 2): + if i < 0 or i == ROWS or j < 0 or j == COLS: + continue + total += img[i][j] % 256 + cnt += 1 + img[r][c] ^= ((total // cnt) << 8) + + for r in range(ROWS): + for c in range(COLS): + img[r][c] >>= 8 + return img +``` + +```java +public class Solution { + public int[][] imageSmoother(int[][] img) { + int ROWS = img.length, COLS = img[0].length; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int total = 0, cnt = 0; + for (int i = r - 1; i <= r + 1; i++) { + for (int j = c - 1; j <= c + 1; j++) { + if (i < 0 || i >= ROWS || j < 0 || j >= COLS) { + continue; + } + total += img[i][j] % 256; + cnt++; + } + } + img[r][c] ^= ((total / cnt) << 8); + } + } + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + img[r][c] >>= 8; + } + } + return img; + } +} +``` + +```cpp +class Solution { +public: + vector> imageSmoother(vector>& img) { + int ROWS = img.size(), COLS = img[0].size(); + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int total = 0, cnt = 0; + for (int i = r - 1; i <= r + 1; i++) { + for (int j = c - 1; j <= c + 1; j++) { + if (i < 0 || i >= ROWS || j < 0 || j >= COLS) { + continue; + } + total += img[i][j] % 256; + cnt++; + } + } + img[r][c] ^= ((total / cnt) << 8); + } + } + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + img[r][c] >>= 8; + } + } + return img; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} img + * @return {number[][]} + */ + imageSmoother(img) { + const ROWS = img.length, + COLS = img[0].length; + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + let total = 0, + cnt = 0; + for (let i = r - 1; i <= r + 1; i++) { + for (let j = c - 1; j <= c + 1; j++) { + if (i < 0 || i >= ROWS || j < 0 || j >= COLS) { + continue; + } + total += img[i][j] % 256; + cnt++; + } + } + img[r][c] ^= (total / cnt) << 8; + } + } + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + img[r][c] >>= 8; + } + } + return img; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m)$ +- Space complexity: $O(1)$ extra space. + +> Where $n$ is the number of rows and $m$ is the number of columns of the matrix. diff --git a/articles/implement-prefix-tree.md b/articles/implement-prefix-tree.md index 493258c7b..cbfc89383 100644 --- a/articles/implement-prefix-tree.md +++ b/articles/implement-prefix-tree.md @@ -96,18 +96,18 @@ class TrieNode { public: TrieNode* children[26]; bool endOfWord; - + TrieNode() { for (int i = 0; i < 26; i++) { children[i] = nullptr; - } + } endOfWord = false; } }; class PrefixTree { TrieNode* root; - + public: PrefixTree() { root = new TrieNode(); @@ -363,12 +363,68 @@ class PrefixTree { } ``` +```swift +class TrieNode { + var children: [TrieNode?] + var endOfWord: Bool + + init() { + self.children = Array(repeating: nil, count: 26) + self.endOfWord = false + } +} + +class PrefixTree { + private let root: TrieNode + + init() { + self.root = TrieNode() + } + + func insert(_ word: String) { + var cur = root + for c in word { + let i = Int(c.asciiValue! - Character("a").asciiValue!) + if cur.children[i] == nil { + cur.children[i] = TrieNode() + } + cur = cur.children[i]! + } + cur.endOfWord = true + } + + func search(_ word: String) -> Bool { + var cur = root + for c in word { + let i = Int(c.asciiValue! - Character("a").asciiValue!) + if cur.children[i] == nil { + return false + } + cur = cur.children[i]! + } + return cur.endOfWord + } + + func startsWith(_ prefix: String) -> Bool { + var cur = root + for c in prefix { + let i = Int(c.asciiValue! - Character("a").asciiValue!) + if cur.children[i] == nil { + return false + } + cur = cur.children[i]! + } + return true + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ for each function call. -* Space complexity: $O(t)$ +- Time complexity: $O(n)$ for each function call. +- Space complexity: $O(t)$ > Where $n$ is the length of the string and $t$ is the total number of TrieNodes created in the Trie. @@ -521,7 +577,7 @@ class PrefixTree { constructor() { this.root = new TrieNode(); } - + /** * @param {string} word * @return {void} @@ -571,7 +627,7 @@ class PrefixTree { ```csharp public class TrieNode { - public Dictionary children = + public Dictionary children = new Dictionary(); public bool endOfWord = false; } @@ -708,11 +764,64 @@ class PrefixTree { } ``` +```swift +class TrieNode { + var children: [Character: TrieNode] + var endOfWord: Bool + + init() { + self.children = [:] + self.endOfWord = false + } +} + +class PrefixTree { + private let root: TrieNode + + init() { + self.root = TrieNode() + } + + func insert(_ word: String) { + var cur = root + for c in word { + if cur.children[c] == nil { + cur.children[c] = TrieNode() + } + cur = cur.children[c]! + } + cur.endOfWord = true + } + + func search(_ word: String) -> Bool { + var cur = root + for c in word { + if cur.children[c] == nil { + return false + } + cur = cur.children[c]! + } + return cur.endOfWord + } + + func startsWith(_ prefix: String) -> Bool { + var cur = root + for c in prefix { + if cur.children[c] == nil { + return false + } + cur = cur.children[c]! + } + return true + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ for each function call. -* Space complexity: $O(t)$ +- Time complexity: $O(n)$ for each function call. +- Space complexity: $O(t)$ -> Where $n$ is the length of the string and $t$ is the total number of TrieNodes created in the Trie. \ No newline at end of file +> Where $n$ is the length of the string and $t$ is the total number of TrieNodes created in the Trie. diff --git a/articles/implement-queue-using-stacks.md b/articles/implement-queue-using-stacks.md index 9d51b2ad4..770f0cb0a 100644 --- a/articles/implement-queue-using-stacks.md +++ b/articles/implement-queue-using-stacks.md @@ -127,7 +127,7 @@ class MyQueue { this.stack2 = []; } - /** + /** * @param {number} x * @return {void} */ @@ -172,15 +172,57 @@ class MyQueue { } ``` +```csharp +public class MyQueue { + private Stack stack1; + private Stack stack2; + + public MyQueue() { + stack1 = new Stack(); + stack2 = new Stack(); + } + + public void Push(int x) { + stack1.Push(x); + } + + public int Pop() { + while (stack1.Count > 1) { + stack2.Push(stack1.Pop()); + } + int res = stack1.Pop(); + while (stack2.Count > 0) { + stack1.Push(stack2.Pop()); + } + return res; + } + + public int Peek() { + while (stack1.Count > 1) { + stack2.Push(stack1.Pop()); + } + int res = stack1.Peek(); + while (stack2.Count > 0) { + stack1.Push(stack2.Pop()); + } + return res; + } + + public bool Empty() { + return stack1.Count == 0; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(1)$ time for initialization. - * $O(1)$ time for each $push()$ and $empty()$ function calls. - * $O(n)$ time for each $pop()$ and $peek()$ function calls. -* Space complexity: $O(n)$ +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $push()$ and $empty()$ function calls. + - $O(n)$ time for each $pop()$ and $peek()$ function calls. +- Space complexity: $O(n)$ --- @@ -190,7 +232,7 @@ class MyQueue { ```python class MyQueue: - + def __init__(self): self.s1 = [] self.s2 = [] @@ -299,7 +341,7 @@ class MyQueue { this.s2 = []; } - /** + /** * @param {number} x * @return {void} */ @@ -340,12 +382,50 @@ class MyQueue { } ``` +```csharp +public class MyQueue { + private Stack s1; + private Stack s2; + + public MyQueue() { + s1 = new Stack(); + s2 = new Stack(); + } + + public void Push(int x) { + s1.Push(x); + } + + public int Pop() { + if (s2.Count == 0) { + while (s1.Count > 0) { + s2.Push(s1.Pop()); + } + } + return s2.Pop(); + } + + public int Peek() { + if (s2.Count == 0) { + while (s1.Count > 0) { + s2.Push(s1.Pop()); + } + } + return s2.Peek(); + } + + public bool Empty() { + return s1.Count == 0 && s2.Count == 0; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(1)$ time for initialization. - * $O(1)$ time for each $push()$ and $empty()$ function calls. - * $O(1)$ amortized time for each $pop()$ and $peek()$ function calls. -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $push()$ and $empty()$ function calls. + - $O(1)$ amortized time for each $pop()$ and $peek()$ function calls. +- Space complexity: $O(n)$ diff --git a/articles/implement-stack-using-queues.md b/articles/implement-stack-using-queues.md index ee6199220..6d1114f6e 100644 --- a/articles/implement-stack-using-queues.md +++ b/articles/implement-stack-using-queues.md @@ -13,7 +13,7 @@ class MyStack: self.q2.append(x) while self.q1: self.q2.append(self.q1.popleft()) - + self.q1, self.q2 = self.q2, self.q1 def pop(self) -> int: @@ -107,11 +107,11 @@ class MyStack { */ push(x) { this.q2.push(x); - + while (!this.q1.isEmpty()) { this.q2.push(this.q1.pop()); } - + [this.q1, this.q2] = [this.q2, this.q1]; } @@ -138,15 +138,49 @@ class MyStack { } ``` +```csharp +public class MyStack { + private Queue q1; + private Queue q2; + + public MyStack() { + q1 = new Queue(); + q2 = new Queue(); + } + + public void Push(int x) { + q2.Enqueue(x); + while (q1.Count > 0) { + q2.Enqueue(q1.Dequeue()); + } + var temp = q1; + q1 = q2; + q2 = temp; + } + + public int Pop() { + return q1.Dequeue(); + } + + public int Top() { + return q1.Peek(); + } + + public bool Empty() { + return q1.Count == 0; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(1)$ time for initialization. - * $O(n)$ time for each $push()$ function call. - * $O(1)$ time for each $pop()$ function call. -* Space complexity: $O(n)$ +- Time complexity: + - $O(1)$ time for initialization. + - $O(n)$ time for each $push()$ function call. + - $O(1)$ time for each $pop()$ function call. +- Space complexity: $O(n)$ --- @@ -247,7 +281,7 @@ class MyStack { */ push(x) { this.q.push(x); - + for (let i = this.q.size() - 1; i > 0; i--) { this.q.push(this.q.pop()); } @@ -276,15 +310,44 @@ class MyStack { } ``` +```csharp +public class MyStack { + private Queue q; + + public MyStack() { + q = new Queue(); + } + + public void Push(int x) { + q.Enqueue(x); + for (int i = q.Count - 1; i > 0; i--) { + q.Enqueue(q.Dequeue()); + } + } + + public int Pop() { + return q.Dequeue(); + } + + public int Top() { + return q.Peek(); + } + + public bool Empty() { + return q.Count == 0; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(1)$ time for initialization. - * $O(n)$ time for each $push()$ function call. - * $O(1)$ time for each $pop()$ function call. -* Space complexity: $O(n)$ +- Time complexity: + - $O(1)$ time for initialization. + - $O(n)$ time for each $push()$ function call. + - $O(1)$ time for each $pop()$ function call. +- Space complexity: $O(n)$ --- @@ -427,12 +490,46 @@ class MyStack { } ``` +```csharp +public class MyStack { + private Queue q; + + public MyStack() { + q = null; + } + + public void Push(int x) { + Queue newQueue = new Queue(); + newQueue.Enqueue(x); + newQueue.Enqueue(q); + q = newQueue; + } + + public int Pop() { + if (q == null) return -1; + + int top = (int)q.Dequeue(); + q = (Queue)q.Dequeue(); + return top; + } + + public int Top() { + if (q == null) return -1; + return (int)q.Peek(); + } + + public bool Empty() { + return q == null; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(1)$ time for initialization. - * $O(1)$ time for each $push()$ function call. - * $O(1)$ time for each $pop()$ function call. -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $push()$ function call. + - $O(1)$ time for each $pop()$ function call. +- Space complexity: $O(n)$ diff --git a/articles/insert-delete-getrandom-o1.md b/articles/insert-delete-getrandom-o1.md index 000979641..caa9b8f0c 100644 --- a/articles/insert-delete-getrandom-o1.md +++ b/articles/insert-delete-getrandom-o1.md @@ -4,7 +4,7 @@ ```python class RandomizedSet: - + def __init__(self): self.numMap = {} self.size = 0 @@ -106,7 +106,7 @@ class RandomizedSet { this.size = 0; } - /** + /** * @param {number} val * @return {boolean} */ @@ -117,7 +117,7 @@ class RandomizedSet { return true; } - /** + /** * @param {number} val * @return {boolean} */ @@ -143,8 +143,8 @@ class RandomizedSet { ### Time & Space Complexity -* Time complexity: $O(n)$ for $getRandom()$, $O(1)$ for other function calls. -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ for $getRandom()$, $O(1)$ for other function calls. +- Space complexity: $O(n)$ --- @@ -154,7 +154,7 @@ class RandomizedSet { ```python class RandomizedSet: - + def __init__(self): self.numMap = {} self.nums = [] @@ -257,7 +257,7 @@ class RandomizedSet { this.nums = []; } - /** + /** * @param {number} val * @return {boolean} */ @@ -268,7 +268,7 @@ class RandomizedSet { return true; } - /** + /** * @param {number} val * @return {boolean} */ @@ -296,5 +296,5 @@ class RandomizedSet { ### Time & Space Complexity -* Time complexity: $O(1)$ for each function call. -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(1)$ for each function call. +- Space complexity: $O(n)$ diff --git a/articles/insert-greatest-common-divisors-in-linked-list.md b/articles/insert-greatest-common-divisors-in-linked-list.md index ffa61c7ce..05fa7c7e5 100644 --- a/articles/insert-greatest-common-divisors-in-linked-list.md +++ b/articles/insert-greatest-common-divisors-in-linked-list.md @@ -131,7 +131,8 @@ class Solution { let cur = head; while (cur.next) { - const n1 = cur.val, n2 = cur.next.val; + const n1 = cur.val, + n2 = cur.next.val; const gcdValue = gcd(n1, n2); const newNode = new ListNode(gcdValue, cur.next); cur.next = newNode; @@ -143,13 +144,50 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val=0, ListNode next=null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + public ListNode InsertGreatestCommonDivisors(ListNode head) { + ListNode cur = head; + + while (cur.next != null) { + int gcdVal = GCD(cur.val, cur.next.val); + ListNode newNode = new ListNode(gcdVal, cur.next); + cur.next = newNode; + cur = newNode.next; + } + + return head; + } + + private int GCD(int a, int b) { + while (b > 0) { + int temp = b; + b = a % b; + a = temp; + } + return a; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * \log (min(a, b)))$ -* Space complexity: - * $O(n)$ space for the gcd ListNodes. - * $O(1)$ extra space. +- Time complexity: $O(n * \log (min(a, b)))$ +- Space complexity: + - $O(n)$ space for the gcd ListNodes. + - $O(1)$ extra space. -> Where $n$ is the length of the given list, and $a$ and $b$ are two numbers passed to the $gcd()$ function. \ No newline at end of file +> Where $n$ is the length of the given list, and $a$ and $b$ are two numbers passed to the $gcd()$ function. diff --git a/articles/insert-into-a-binary-search-tree.md b/articles/insert-into-a-binary-search-tree.md index d8597610b..b74eb1d2b 100644 --- a/articles/insert-into-a-binary-search-tree.md +++ b/articles/insert-into-a-binary-search-tree.md @@ -118,12 +118,43 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public TreeNode InsertIntoBST(TreeNode root, int val) { + if (root == null) { + return new TreeNode(val); + } + + if (val > root.val) { + root.right = InsertIntoBST(root.right, val); + } else { + root.left = InsertIntoBST(root.left, val); + } + + return root; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(h)$ -* Space complexity: $O(h)$ for the recursion stack. +- Time complexity: $O(h)$ +- Space complexity: $O(h)$ for the recursion stack. > Where $h$ is the height of the given binary search tree. @@ -282,11 +313,51 @@ class Solution { } ``` +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public TreeNode InsertIntoBST(TreeNode root, int val) { + if (root == null) { + return new TreeNode(val); + } + + TreeNode cur = root; + while (true) { + if (val > cur.val) { + if (cur.right == null) { + cur.right = new TreeNode(val); + return root; + } + cur = cur.right; + } else { + if (cur.left == null) { + cur.left = new TreeNode(val); + return root; + } + cur = cur.left; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(h)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(h)$ +- Space complexity: $O(1)$ extra space. -> Where $h$ is the height of the given binary search tree. \ No newline at end of file +> Where $h$ is the height of the given binary search tree. diff --git a/articles/insert-new-interval.md b/articles/insert-new-interval.md index e35159e6e..b06111133 100644 --- a/articles/insert-new-interval.md +++ b/articles/insert-new-interval.md @@ -91,8 +91,8 @@ class Solution { */ insert(intervals, newInterval) { let n = intervals.length, - i = 0, - res = []; + i = 0, + res = []; while (i < n && intervals[i][1] < newInterval[0]) { res.push(intervals[i]); @@ -120,13 +120,13 @@ class Solution { public class Solution { public int[][] Insert(int[][] intervals, int[] newInterval) { var result = new List(); - + for(var i = 0; i < intervals.Length; i++) { if(newInterval[1] < intervals[i][0]) { result.Add(newInterval); result.AddRange( intervals.AsEnumerable().Skip(i).ToArray()); - + return result.ToArray(); } else if(newInterval[0] > intervals[i][1]) { @@ -136,9 +136,9 @@ public class Solution { newInterval[1] = Math.Max(intervals[i][1], newInterval[1]); } } - + result.Add(newInterval); - + return result.ToArray(); } } @@ -216,12 +216,45 @@ class Solution { } ``` +```swift +class Solution { + func insert(_ intervals: [[Int]], _ newInterval: [Int]) -> [[Int]] { + var intervals = intervals + var newInterval = newInterval + var res: [[Int]] = [] + var i = 0 + let n = intervals.count + + while i < n && intervals[i][1] < newInterval[0] { + res.append(intervals[i]) + i += 1 + } + + while i < n && newInterval[1] >= intervals[i][0] { + newInterval[0] = min(newInterval[0], intervals[i][0]) + newInterval[1] = max(newInterval[1], intervals[i][1]) + i += 1 + } + res.append(newInterval) + + while i < n { + res.append(intervals[i]) + i += 1 + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output list. --- @@ -371,8 +404,7 @@ class Solution { let res = []; for (let interval of intervals) { - if (res.length === 0 || - res[res.length - 1][1] < interval[0]) { + if (res.length === 0 || res[res.length - 1][1] < interval[0]) { res.push(interval); } else { res[res.length - 1][1] = Math.max( @@ -510,12 +542,49 @@ class Solution { } ``` +```swift +class Solution { + func insert(_ intervals: [[Int]], _ newInterval: [Int]) -> [[Int]] { + if intervals.isEmpty { + return [newInterval] + } + + var intervals = intervals + let target = newInterval[0] + var left = 0, right = intervals.count - 1 + + while left <= right { + let mid = (left + right) / 2 + if intervals[mid][0] < target { + left = mid + 1 + } else { + right = mid - 1 + } + } + + intervals.insert(newInterval, at: left) + + var res: [[Int]] = [] + for interval in intervals { + if res.isEmpty || res.last![1] < interval[0] { + res.append(interval) + } else { + res[res.count - 1][1] = max(res.last![1], interval[1]) + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output list. --- @@ -576,8 +645,8 @@ public: for (int i = 0; i < n; i++) { if (intervals[i][0] > newEnd) { res.push_back(newInterval); - copy(intervals.begin() + i, intervals.end(), back_inserter(ans)); - return ans; + copy(intervals.begin() + i, intervals.end(), back_inserter(res)); + return res; } else if (intervals[i][1] < newStart) { res.push_back(intervals[i]); } else { @@ -622,7 +691,7 @@ class Solution { public class Solution { public int[][] Insert(int[][] intervals, int[] newInterval) { var result = new List(); - + for(var i = 0; i < intervals.Length; i++) { if(newInterval[1] < intervals[i][0]) { result.Add(newInterval); @@ -635,7 +704,7 @@ public class Solution { newInterval[1] = Math.Max(intervals[i][1], newInterval[1]); } } - + result.Add(newInterval); return result.ToArray(); } @@ -686,7 +755,7 @@ class Solution { for (interval in intervals) { if (newInterval[1] < interval[0]) { res.add(newInterval) - return (res + + return (res + intervals.sliceArray( intervals.indexOf(interval) until intervals.size )).toTypedArray() @@ -703,9 +772,36 @@ class Solution { } ``` +```swift +class Solution { + func insert(_ intervals: [[Int]], _ newInterval: [Int]) -> [[Int]] { + var res = [[Int]]() + var newInterval = newInterval + + for i in 0.. intervals[i][1] { + res.append(intervals[i]) + } else { + newInterval[0] = min(newInterval[0], intervals[i][0]) + newInterval[1] = max(newInterval[1], intervals[i][1]) + } + } + + res.append(newInterval) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output list. diff --git a/articles/insertion-sort-list.md b/articles/insertion-sort-list.md new file mode 100644 index 000000000..d729a6b95 --- /dev/null +++ b/articles/insertion-sort-list.md @@ -0,0 +1,412 @@ +## 1. Convert To Array + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def insertionSortList(self, head: Optional[ListNode]) -> Optional[ListNode]: + arr = [] + cur = head + while cur: + arr.append(cur.val) + cur = cur.next + + arr.sort() + cur = head + for val in arr: + cur.val = val + cur = cur.next + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode insertionSortList(ListNode head) { + List arr = new ArrayList<>(); + ListNode cur = head; + + while (cur != null) { + arr.add(cur.val); + cur = cur.next; + } + + Collections.sort(arr); + cur = head; + + for (int val : arr) { + cur.val = val; + cur = cur.next; + } + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* insertionSortList(ListNode* head) { + vector arr; + ListNode* cur = head; + + while (cur) { + arr.push_back(cur->val); + cur = cur->next; + } + + sort(arr.begin(), arr.end()); + cur = head; + + for (int val : arr) { + cur->val = val; + cur = cur->next; + } + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + insertionSortList(head) { + let arr = []; + let cur = head; + + while (cur) { + arr.push(cur.val); + cur = cur.next; + } + + arr.sort((a, b) => a - b); + cur = head; + + for (let val of arr) { + cur.val = val; + cur = cur.next; + } + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Swapping Values + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def insertionSortList(self, head: Optional[ListNode]) -> Optional[ListNode]: + cur = head.next + while cur: + tmp = head + while tmp != cur: + if tmp.val > cur.val: + tmp.val, cur.val = cur.val, tmp.val + tmp = tmp.next + cur = cur.next + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode insertionSortList(ListNode head) { + for (ListNode cur = head.next; cur != null; cur = cur.next) { + for (ListNode tmp = head; tmp != cur; tmp = tmp.next) { + if (tmp.val > cur.val) { + int swap = tmp.val; + tmp.val = cur.val; + cur.val = swap; + } + } + } + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* insertionSortList(ListNode* head) { + for (ListNode* cur = head->next; cur; cur = cur->next) { + for (ListNode* tmp = head; tmp != cur; tmp = tmp->next) { + if (tmp->val > cur->val) { + swap(tmp->val, cur->val); + } + } + } + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + insertionSortList(head) { + for (let cur = head.next; cur; cur = cur.next) { + for (let tmp = head; tmp !== cur; tmp = tmp.next) { + if (tmp.val > cur.val) { + [tmp.val, cur.val] = [cur.val, tmp.val]; + } + } + } + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 3. Swapping Nodes + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def insertionSortList(self, head: Optional[ListNode]) -> Optional[ListNode]: + dummy = ListNode(0, head) + prev, cur = head, head.next + + while cur: + if cur.val >= prev.val: + prev, cur = cur, cur.next + continue + + tmp = dummy + while cur.val > tmp.next.val: + tmp = tmp.next + + prev.next = cur.next + cur.next = tmp.next + tmp.next = cur + cur = prev.next + + return dummy.next +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode insertionSortList(ListNode head) { + ListNode dummy = new ListNode(0, head); + ListNode prev = head, cur = head.next; + + while (cur != null) { + if (cur.val >= prev.val) { + prev = cur; + cur = cur.next; + continue; + } + + ListNode tmp = dummy; + while (tmp.next.val < cur.val) { + tmp = tmp.next; + } + + prev.next = cur.next; + cur.next = tmp.next; + tmp.next = cur; + cur = prev.next; + } + + return dummy.next; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* insertionSortList(ListNode* head) { + ListNode* dummy = new ListNode(0, head); + ListNode* prev = head; + ListNode* cur = head->next; + + while (cur) { + if (cur->val >= prev->val) { + prev = cur; + cur = cur->next; + continue; + } + + ListNode* tmp = dummy; + while (tmp->next->val < cur->val) { + tmp = tmp->next; + } + + prev->next = cur->next; + cur->next = tmp->next; + tmp->next = cur; + cur = prev->next; + } + + return dummy->next; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + insertionSortList(head) { + let dummy = new ListNode(0, head); + let prev = head, + cur = head.next; + + while (cur) { + if (cur.val >= prev.val) { + prev = cur; + cur = cur.next; + continue; + } + + let tmp = dummy; + while (tmp.next.val < cur.val) { + tmp = tmp.next; + } + + prev.next = cur.next; + cur.next = tmp.next; + tmp.next = cur; + cur = prev.next; + } + + return dummy.next; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/integer-break.md b/articles/integer-break.md index eadd8856d..2ef7a83a2 100644 --- a/articles/integer-break.md +++ b/articles/integer-break.md @@ -66,7 +66,7 @@ class Solution { const dfs = (num) => { if (num === 1) return 1; - let res = (num === n) ? 0 : num; + let res = num === n ? 0 : num; for (let i = 1; i < num; i++) { const val = dfs(i) * dfs(num - i); res = Math.max(res, val); @@ -79,12 +79,34 @@ class Solution { } ``` +```csharp +public class Solution { + private int n; + + public int IntegerBreak(int n) { + this.n = n; + + int Dfs(int num) { + if (num == 1) return 1; + int res = num == n ? 0 : num; + for (int i = 1; i < num; i++) { + int val = Dfs(i) * Dfs(num - i); + res = Math.Max(res, val); + } + return res; + } + + return Dfs(n); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -98,12 +120,12 @@ class Solution: def dfs(num, i): if min(num, i) == 0: return 1 - + if i > num: return dfs(num, num) - + return max(i * dfs(num - i, i), dfs(num, i - 1)) - + return dfs(n, n - 1) ``` @@ -117,11 +139,11 @@ public class Solution { if (Math.min(num, i) == 0) { return 1; } - + if (i > num) { return dfs(num, num); } - + return Math.max(i * dfs(num - i, i), dfs(num, i - 1)); } } @@ -139,11 +161,11 @@ private: if (min(num, i) == 0) { return 1; } - + if (i > num) { return dfs(num, num); } - + return max(i * dfs(num - i, i), dfs(num, i - 1)); } }; @@ -160,11 +182,11 @@ class Solution { if (Math.min(num, i) === 0) { return 1; } - + if (i > num) { return dfs(num, num); } - + return Math.max(i * dfs(num - i, i), dfs(num, i - 1)); }; @@ -173,12 +195,32 @@ class Solution { } ``` +```csharp +public class Solution { + public int IntegerBreak(int n) { + int Dfs(int num, int i) { + if (Math.Min(num, i) == 0) { + return 1; + } + + if (i > num) { + return Dfs(num, num); + } + + return Math.Max(i * Dfs(num - i, i), Dfs(num, i - 1)); + } + + return Dfs(n, n - 1); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -200,7 +242,7 @@ class Solution: val = dfs(i) * dfs(num - i) dp[num] = max(dp[num], val) return dp[num] - + return dfs(n) ``` @@ -274,7 +316,7 @@ class Solution { return dp.get(num); } - let res = (num === n) ? 0 : num; + let res = num === n ? 0 : num; for (let i = 1; i < num; i++) { const val = dfs(i) * dfs(num - i); res = Math.max(res, val); @@ -289,12 +331,37 @@ class Solution { } ``` +```csharp +public class Solution { + public int IntegerBreak(int n) { + Dictionary dp = new Dictionary(); + dp[1] = 1; + + int Dfs(int num) { + if (dp.ContainsKey(num)) { + return dp[num]; + } + + dp[num] = (num == n) ? 0 : num; + for (int i = 1; i < num; i++) { + int val = Dfs(i) * Dfs(num - i); + dp[num] = Math.Max(dp[num], val); + } + + return dp[num]; + } + + return Dfs(n); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -314,10 +381,10 @@ class Solution: if i > num: dp[(num, i)] = dfs(num, num) return dp[(num, i)] - + dp[(num, i)] = max(i * dfs(num - i, i), dfs(num, i - 1)) return dp[(num, i)] - + return dfs(n, n - 1) ``` @@ -409,12 +476,36 @@ class Solution { } ``` +```csharp +public class Solution { + public int IntegerBreak(int n) { + Dictionary<(int, int), int> dp = new Dictionary<(int, int), int>(); + + int Dfs(int num, int i) { + if (Math.Min(num, i) == 0) return 1; + + if (dp.ContainsKey((num, i))) return dp[(num, i)]; + + if (i > num) { + dp[(num, i)] = Dfs(num, num); + return dp[(num, i)]; + } + + dp[(num, i)] = Math.Max(i * Dfs(num - i, i), Dfs(num, i - 1)); + return dp[(num, i)]; + } + + return Dfs(n, n - 1); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -484,7 +575,7 @@ class Solution { dp[1] = 1; for (let num = 2; num <= n; num++) { - dp[num] = (num === n) ? 0 : num; + dp[num] = num === n ? 0 : num; for (let i = 1; i < num; i++) { dp[num] = Math.max(dp[num], dp[i] * dp[num - i]); } @@ -495,12 +586,30 @@ class Solution { } ``` +```csharp +public class Solution { + public int IntegerBreak(int n) { + int[] dp = new int[n + 1]; + dp[1] = 1; + + for (int num = 2; num <= n; num++) { + dp[num] = num == n ? 0 : num; + for (int i = 1; i < num; i++) { + dp[num] = Math.Max(dp[num], dp[i] * dp[num - i]); + } + } + + return dp[n]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -513,7 +622,7 @@ class Solution: def integerBreak(self, n: int) -> int: if n <= 3: return n - 1 - + res = 1 while n > 4: res *= 3 @@ -571,12 +680,30 @@ class Solution { } ``` +```csharp +public class Solution { + public int IntegerBreak(int n) { + if (n <= 3) { + return n - 1; + } + + int res = 1; + while (n > 4) { + res *= 3; + n -= 3; + } + + return res * n; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -653,9 +780,27 @@ class Solution { } ``` +```csharp +public class Solution { + public int IntegerBreak(int n) { + if (n <= 3) { + return n - 1; + } + + int res = (int)Math.Pow(3, n / 3); + + if (n % 3 == 1) { + return (res / 3) * 4; + } + + return res * Math.Max(1, n % 3); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/integer-to-roman.md b/articles/integer-to-roman.md new file mode 100644 index 000000000..2a8a85dc1 --- /dev/null +++ b/articles/integer-to-roman.md @@ -0,0 +1,284 @@ +## 1. Math - I + +::tabs-start + +```python +class Solution: + def intToRoman(self, num: int) -> str: + symList = [ + ["I", 1], ["IV", 4], ["V", 5], ["IX", 9], + ["X", 10], ["XL", 40], ["L", 50], ["XC", 90], + ["C", 100], ["CD", 400], ["D", 500], ["CM", 900], + ["M", 1000] + ] + + res = "" + for sym, val in reversed(symList): + count = num // val + if count: + res += sym * count + num %= val + + return res +``` + +```java +public class Solution { + public String intToRoman(int num) { + String[][] symList = { + {"I", "1"}, {"IV", "4"}, {"V", "5"}, {"IX", "9"}, + {"X", "10"}, {"XL", "40"}, {"L", "50"}, {"XC", "90"}, + {"C", "100"}, {"CD", "400"}, {"D", "500"}, {"CM", "900"}, + {"M", "1000"} + }; + + StringBuilder res = new StringBuilder(); + for (int i = symList.length - 1; i >= 0; i--) { + String sym = symList[i][0]; + int val = Integer.parseInt(symList[i][1]); + int count = num / val; + if (count > 0) { + res.append(sym.repeat(count)); + num %= val; + } + } + + return res.toString(); + } +} +``` + +```cpp +class Solution { +public: + string intToRoman(int num) { + vector> symList = { + {"I", 1}, {"IV", 4}, {"V", 5}, {"IX", 9}, + {"X", 10}, {"XL", 40}, {"L", 50}, {"XC", 90}, + {"C", 100}, {"CD", 400}, {"D", 500}, {"CM", 900}, + {"M", 1000} + }; + + string res = ""; + for (int i = symList.size() - 1; i >= 0; i--) { + string sym = symList[i].first; + int val = symList[i].second; + int count = num / val; + if (count > 0) { + res.append(count, sym[0]); + if (sym.size() == 2) res.append(1, sym[1]); + num %= val; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {string} + */ + intToRoman(num) { + const symList = [ + ['I', 1], + ['IV', 4], + ['V', 5], + ['IX', 9], + ['X', 10], + ['XL', 40], + ['L', 50], + ['XC', 90], + ['C', 100], + ['CD', 400], + ['D', 500], + ['CM', 900], + ['M', 1000], + ]; + + let res = ''; + for (let i = symList.length - 1; i >= 0; i--) { + const [sym, val] = symList[i]; + let count = Math.floor(num / val); + if (count > 0) { + res += sym.repeat(count); + num %= val; + } + } + + return res; + } +} +``` + +```csharp +public class Solution { + public string IntToRoman(int num) { + string[][] symList = new string[][] { + new[] {"I", "1"}, new[] {"IV", "4"}, + new[] {"V", "5"}, new[] {"IX", "9"}, + new[] {"X", "10"}, new[] {"XL", "40"}, + new[] {"L", "50"}, new[] {"XC", "90"}, + new[] {"C", "100"}, new[] {"CD", "400"}, + new[] {"D", "500"}, new[] {"CM", "900"}, + new[] {"M", "1000"} + }; + + var res = new StringBuilder(); + for (int i = symList.Length - 1; i >= 0; i--) { + string sym = symList[i][0]; + int val = int.Parse(symList[i][1]); + int count = num / val; + for (int k = 0; k < count; k++) { + res.Append(sym); + } + num %= val; + } + + return res.ToString(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +--- + +## 2. Math - II + +::tabs-start + +```python +class Solution: + def intToRoman(self, num: int) -> str: + thousands = ["", "M", "MM", "MMM"] + hundreds = ["", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"] + tens = ["", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"] + ones = ["", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"] + + return ( + thousands[num // 1000] + + hundreds[(num % 1000) // 100] + + tens[(num % 100) // 10] + + ones[num % 10] + ) +``` + +```java +public class Solution { + public String intToRoman(int num) { + String[] thousands = {"", "M", "MM", "MMM"}; + String[] hundreds = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}; + String[] tens = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}; + String[] ones = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}; + + return thousands[num / 1000] + + hundreds[(num % 1000) / 100] + + tens[(num % 100) / 10] + + ones[num % 10]; + } +} +``` + +```cpp +class Solution { +public: + string intToRoman(int num) { + string thousands[] = {"", "M", "MM", "MMM"}; + string hundreds[] = {"", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM"}; + string tens[] = {"", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC"}; + string ones[] = {"", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX"}; + + return thousands[num / 1000] + + hundreds[(num % 1000) / 100] + + tens[(num % 100) / 10] + + ones[num % 10]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {string} + */ + intToRoman(num) { + const thousands = ['', 'M', 'MM', 'MMM']; + const hundreds = [ + '', + 'C', + 'CC', + 'CCC', + 'CD', + 'D', + 'DC', + 'DCC', + 'DCCC', + 'CM', + ]; + const tens = [ + '', + 'X', + 'XX', + 'XXX', + 'XL', + 'L', + 'LX', + 'LXX', + 'LXXX', + 'XC', + ]; + const ones = [ + '', + 'I', + 'II', + 'III', + 'IV', + 'V', + 'VI', + 'VII', + 'VIII', + 'IX', + ]; + + return ( + thousands[Math.floor(num / 1000)] + + hundreds[Math.floor((num % 1000) / 100)] + + tens[Math.floor((num % 100) / 10)] + + ones[num % 10] + ); + } +} +``` + +```csharp +public class Solution { + public string IntToRoman(int num) { + string[] thousands = { "", "M", "MM", "MMM" }; + string[] hundreds = { "", "C", "CC", "CCC", "CD", "D", "DC", "DCC", "DCCC", "CM" }; + string[] tens = { "", "X", "XX", "XXX", "XL", "L", "LX", "LXX", "LXXX", "XC" }; + string[] ones = { "", "I", "II", "III", "IV", "V", "VI", "VII", "VIII", "IX" }; + + return thousands[num / 1000] + + hundreds[(num % 1000) / 100] + + tens[(num % 100) / 10] + + ones[num % 10]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ diff --git a/articles/interleaving-string.md b/articles/interleaving-string.md index c5e0566de..e33107de7 100644 --- a/articles/interleaving-string.md +++ b/articles/interleaving-string.md @@ -5,48 +5,48 @@ ```python class Solution: def isInterleave(self, s1: str, s2: str, s3: str) -> bool: - + def dfs(i, j, k): if k == len(s3): return (i == len(s1)) and (j == len(s2)) - + if i < len(s1) and s1[i] == s3[k]: if dfs(i + 1, j, k + 1): return True - + if j < len(s2) and s2[j] == s3[k]: if dfs(i, j + 1, k + 1): return True - + return False - + return dfs(0, 0, 0) ``` ```java public class Solution { public boolean isInterleave(String s1, String s2, String s3) { - + return dfs(0, 0, 0, s1, s2, s3); } - + private boolean dfs(int i, int j, int k, String s1, String s2, String s3) { if (k == s3.length()) { return (i == s1.length()) && (j == s2.length()); } - + if (i < s1.length() && s1.charAt(i) == s3.charAt(k)) { if (dfs(i + 1, j, k + 1, s1, s2, s3)) { return true; } } - + if (j < s2.length() && s2.charAt(j) == s3.charAt(k)) { if (dfs(i, j + 1, k + 1, s1, s2, s3)) { return true; } } - + return false; } } @@ -58,24 +58,24 @@ public: bool isInterleave(string s1, string s2, string s3) { return dfs(0, 0, 0, s1, s2, s3); } - + bool dfs(int i, int j, int k, string& s1, string& s2, string& s3) { if (k == s3.length()) { return (i == s1.length()) && (j == s2.length()); } - + if (i < s1.length() && s1[i] == s3[k]) { if (dfs(i + 1, j, k + 1, s1, s2, s3)) { return true; } } - + if (j < s2.length() && s2[j] == s3[k]) { if (dfs(i, j + 1, k + 1, s1, s2, s3)) { return true; } } - + return false; } }; @@ -90,26 +90,25 @@ class Solution { * @return {boolean} */ isInterleave(s1, s2, s3) { - const dfs = (i, j, k) => { if (k === s3.length) { - return (i === s1.length) && (j === s2.length); + return i === s1.length && j === s2.length; } - + if (i < s1.length && s1[i] === s3[k]) { if (dfs(i + 1, j, k + 1)) { return true; } } - + if (j < s2.length && s2[j] === s3[k]) { if (dfs(i, j + 1, k + 1)) { return true; } } - + return false; - } + }; return dfs(0, 0, 0); } @@ -121,24 +120,24 @@ public class Solution { public bool IsInterleave(string s1, string s2, string s3) { return dfs(0, 0, 0, s1, s2, s3); } - + private bool dfs(int i, int j, int k, string s1, string s2, string s3) { if (k == s3.Length) { return (i == s1.Length) && (j == s2.Length); } - + if (i < s1.Length && s1[i] == s3[k]) { if (dfs(i + 1, j, k + 1, s1, s2, s3)) { return true; } } - + if (j < s2.Length && s2[j] == s3[k]) { if (dfs(i, j + 1, k + 1, s1, s2, s3)) { return true; } } - + return false; } } @@ -199,12 +198,45 @@ class Solution { } ``` +```swift +class Solution { + func isInterleave(_ s1: String, _ s2: String, _ s3: String) -> Bool { + let n1 = s1.count, n2 = s2.count, n3 = s3.count + if n1 + n2 != n3 { return false } + + let s1 = Array(s1), s2 = Array(s2), s3 = Array(s3) + + func dfs(_ i: Int, _ j: Int, _ k: Int) -> Bool { + if k == n3 { + return i == n1 && j == n2 + } + + if i < n1 && s1[i] == s3[k] { + if dfs(i + 1, j, k + 1) { + return true + } + } + + if j < n2 && s2[j] == s3[k] { + if dfs(i, j + 1, k + 1) { + return true + } + } + + return false + } + + return dfs(0, 0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ {m + n})$ -* Space complexity: $O(m + n)$ +- Time complexity: $O(2 ^ {m + n})$ +- Space complexity: $O(m + n)$ > Where $m$ is the length of the string $s1$ and $n$ is the length of the string $s2$. @@ -226,16 +258,16 @@ class Solution: return (i == len(s1)) and (j == len(s2)) if (i, j) in dp: return dp[(i, j)] - + res = False if i < len(s1) and s1[i] == s3[k]: res = dfs(i + 1, j, k + 1) if not res and j < len(s2) and s2[j] == s3[k]: res = dfs(i, j + 1, k + 1) - + dp[(i, j)] = res return res - + return dfs(0, 0, 0) ``` @@ -249,7 +281,7 @@ public class Solution { dp = new Boolean[m + 1][n + 1]; return dfs(0, 0, 0, s1, s2, s3); } - + private boolean dfs(int i, int j, int k, String s1, String s2, String s3) { if (k == s3.length()) { return (i == s1.length()) && (j == s2.length()); @@ -283,7 +315,7 @@ public: dp = vector>(m + 1, vector(n + 1, -1)); return dfs(0, 0, 0, s1, s2, s3); } - + bool dfs(int i, int j, int k, string& s1, string& s2, string& s3) { if (k == s3.length()) { return (i == s1.length()) && (j == s2.length()); @@ -315,14 +347,14 @@ class Solution { * @return {boolean} */ isInterleave(s1, s2, s3) { - const m = s1.length, n = s2.length; + const m = s1.length, + n = s2.length; if (m + n !== s3.length) return false; - - const dp = Array.from({ length: m + 1 }, () => - Array(n + 1).fill(-1)); + + const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(-1)); const dfs = (i, j, k) => { if (k === s3.length) { - return (i === s1.length) && (j === s2.length); + return i === s1.length && j === s2.length; } if (dp[i][j] !== -1) { return dp[i][j]; @@ -332,13 +364,13 @@ class Solution { if (i < s1.length && s1[i] === s3[k]) { res = dfs(i + 1, j, k + 1); } - + if (!res && j < s2.length && s2[j] === s3[k]) { res = dfs(i, j + 1, k + 1); } dp[i][j] = res; return res; - } + }; return dfs(0, 0, 0); } @@ -355,7 +387,7 @@ public class Solution { dp = new bool?[m + 1, n + 1]; return dfs(0, 0, 0, s1, s2, s3); } - + private bool dfs(int i, int j, int k, string s1, string s2, string s3) { if (k == s3.Length) { return (i == s1.Length) && (j == s2.Length); @@ -412,9 +444,9 @@ func isInterleave(s1, s2, s3 string) bool { } if res { - dp[i][j] = 1 + dp[i][j] = 1 } else { - dp[i][j] = 0 + dp[i][j] = 0 } return res @@ -452,8 +484,42 @@ class Solution { res = dfs(i, j + 1, k + 1) } - dp[i][j] = if (res) 1 else 0 + dp[i][j] = if (res) 1 else 0 + + return res + } + + return dfs(0, 0, 0) + } +} +``` + +```swift +class Solution { + func isInterleave(_ s1: String, _ s2: String, _ s3: String) -> Bool { + let m = s1.count, n = s2.count, l = s3.count + if m + n != l { return false } + + let s1 = Array(s1), s2 = Array(s2), s3 = Array(s3) + var dp = Array(repeating: Array(repeating: nil as Bool?, count: n + 1), count: m + 1) + + func dfs(_ i: Int, _ j: Int, _ k: Int) -> Bool { + if k == l { + return i == m && j == n + } + if let cached = dp[i][j] { + return cached + } + + var res = false + if i < m && s1[i] == s3[k] { + res = dfs(i + 1, j, k + 1) + } + if !res && j < n && s2[j] == s3[k] { + res = dfs(i, j + 1, k + 1) + } + dp[i][j] = res return res } @@ -466,8 +532,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the length of the string $s1$ and $n$ is the length of the string $s2$. @@ -557,13 +623,15 @@ class Solution { * @return {boolean} */ isInterleave(s1, s2, s3) { - let m = s1.length, n = s2.length; + let m = s1.length, + n = s2.length; if (m + n !== s3.length) { return false; } const dp = Array.from({ length: m + 1 }, () => - Array(n + 1).fill(false)); + Array(n + 1).fill(false), + ); dp[m][n] = true; for (let i = m; i >= 0; i--) { @@ -660,12 +728,37 @@ class Solution { } ``` +```swift +class Solution { + func isInterleave(_ s1: String, _ s2: String, _ s3: String) -> Bool { + let m = s1.count, n = s2.count, l = s3.count + if m + n != l { return false } + + let s1 = Array(s1), s2 = Array(s2), s3 = Array(s3) + var dp = Array(repeating: Array(repeating: false, count: n + 1), count: m + 1) + dp[m][n] = true + + for i in stride(from: m, through: 0, by: -1) { + for j in stride(from: n, through: 0, by: -1) { + if i < m && s1[i] == s3[i + j] && dp[i + 1][j] { + dp[i][j] = true + } + if j < n && s2[j] == s3[i + j] && dp[i][j + 1] { + dp[i][j] = true + } + } + } + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the length of the string $s1$ and $n$ is the length of the string $s2$. @@ -684,12 +777,13 @@ class Solution: if n < m: s1, s2 = s2, s1 m, n = n, m - + dp = [False for _ in range(n + 1)] dp[n] = True for i in range(m, -1, -1): nextDp = [False for _ in range(n + 1)] - nextDp[n] = True + if i == m: + nextDp[n] = True for j in range(n, -1, -1): if i < m and s1[i] == s3[i + j] and dp[j]: nextDp[j] = True @@ -712,12 +806,12 @@ public class Solution { m = n; n = tempLength; } - + boolean[] dp = new boolean[n + 1]; dp[n] = true; for (int i = m; i >= 0; i--) { boolean[] nextDp = new boolean[n + 1]; - nextDp[n] = true; + if (i == m) nextDp[n] = true; for (int j = n; j >= 0; j--) { if (i < m && s1.charAt(i) == s3.charAt(i + j) && dp[j]) { nextDp[j] = true; @@ -743,12 +837,12 @@ public: swap(s1, s2); swap(m, n); } - + vector dp(n + 1); dp[n] = true; for (int i = m; i >= 0; --i) { vector nextDp(n + 1); - nextDp[n] = true; + if (i == m) nextDp[n] = true; for (int j = n; j >= 0; --j) { if (i < m && s1[i] == s3[i + j] && dp[j]) { nextDp[j] = true; @@ -773,18 +867,19 @@ class Solution { * @return {boolean} */ isInterleave(s1, s2, s3) { - let m = s1.length, n = s2.length; + let m = s1.length, + n = s2.length; if (m + n !== s3.length) return false; if (n < m) { [s1, s2] = [s2, s1]; [m, n] = [n, m]; } - + let dp = Array(n + 1).fill(false); dp[n] = true; for (let i = m; i >= 0; i--) { let nextDp = Array(n + 1).fill(false); - nextDp[n] = true; + if (i === m) nextDp[n] = true; for (let j = n; j >= 0; j--) { if (i < m && s1[i] === s3[i + j] && dp[j]) { nextDp[j] = true; @@ -813,12 +908,12 @@ public class Solution { m = n; n = tempLength; } - + bool[] dp = new bool[n + 1]; dp[n] = true; for (int i = m; i >= 0; i--) { bool[] nextDp = new bool[n + 1]; - nextDp[n] = true; + if (i == m) nextDp[n] = true; for (int j = n; j >= 0; j--) { if (i < m && s1[i] == s3[i + j] && dp[j]) { nextDp[j] = true; @@ -849,7 +944,9 @@ func isInterleave(s1 string, s2 string, s3 string) bool { dp[n] = true for i := m; i >= 0; i-- { nextDp := make([]bool, n+1) - nextDp[n] = true + if i == m { + nextDp[n] = true + } for j := n; j >= 0; j-- { if i < m && s1[i] == s3[i+j] && dp[j] { nextDp[j] = true @@ -888,7 +985,7 @@ class Solution { dp[n] = true for (i in m downTo 0) { val nextDp = BooleanArray(n + 1) - nextDp[n] = true + if (i == m) nextDp[n] = true for (j in n downTo 0) { if (i < m && s1[i] == s3[i + j] && dp[j]) { nextDp[j] = true @@ -904,12 +1001,46 @@ class Solution { } ``` +```swift +class Solution { + func isInterleave(_ s1: String, _ s2: String, _ s3: String) -> Bool { + var s1 = Array(s1), s2 = Array(s2), s3 = Array(s3) + var m = s1.count, n = s2.count + if m + n != s3.count { return false } + if n < m { + swap(&s1, &s2) + swap(&m, &n) + } + + var dp = Array(repeating: false, count: n + 1) + dp[n] = true + + for i in stride(from: m, through: 0, by: -1) { + var nextDp = Array(repeating: false, count: n + 1) + if i == m { + nextDp[n] = true + } + for j in stride(from: n, through: 0, by: -1) { + if i < m && s1[i] == s3[i + j] && dp[j] { + nextDp[j] = true + } + if j < n && s2[j] == s3[i + j] && nextDp[j + 1] { + nextDp[j] = true + } + } + dp = nextDp + } + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(min(m, n))$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(min(m, n))$ > Where $m$ is the length of the string $s1$ and $n$ is the length of the string $s2$. @@ -928,13 +1059,13 @@ class Solution: if n < m: s1, s2 = s2, s1 m, n = n, m - + dp = [False for _ in range(n + 1)] dp[n] = True for i in range(m, -1, -1): - nextDp = True - for j in range(n - 1, -1, -1): - res = False + nextDp = True if i == m else False + for j in range(n, -1, -1): + res = False if j < n else nextDp if i < m and s1[i] == s3[i + j] and dp[j]: res = True if j < n and s2[j] == s3[i + j] and nextDp: @@ -961,9 +1092,9 @@ public class Solution { boolean[] dp = new boolean[n + 1]; dp[n] = true; for (int i = m; i >= 0; i--) { - boolean nextDp = true; - for (int j = n - 1; j >= 0; j--) { - boolean res = false; + boolean nextDp = (i == m ? true : false); + for (int j = n; j >= 0; j--) { + boolean res = (j < n ? false : nextDp); if (i < m && s1.charAt(i) == s3.charAt(i + j) && dp[j]) { res = true; } @@ -993,9 +1124,9 @@ public: vector dp(n + 1, false); dp[n] = true; for (int i = m; i >= 0; i--) { - bool nextDp = true; - for (int j = n - 1; j >= 0; j--) { - bool res = false; + bool nextDp = (i == m ? true : false); + for (int j = n; j >= 0; j--) { + bool res = (j < n ? false : nextDp); if (i < m && s1[i] == s3[i + j] && dp[j]) { res = true; } @@ -1020,7 +1151,8 @@ class Solution { * @return {boolean} */ isInterleave(s1, s2, s3) { - let m = s1.length, n = s2.length; + let m = s1.length, + n = s2.length; if (m + n !== s3.length) return false; if (n < m) { [s1, s2] = [s2, s1]; @@ -1030,9 +1162,9 @@ class Solution { let dp = Array(n + 1).fill(false); dp[n] = true; for (let i = m; i >= 0; i--) { - let nextDp = true; - for (let j = n - 1; j >= 0; j--) { - let res = false; + let nextDp = (i === m ? true : false); + for (let j = n; j >= 0; j--) { + let res = (j < n ? false : nextDp); if (i < m && s1[i] === s3[i + j] && dp[j]) { res = true; } @@ -1065,9 +1197,9 @@ public class Solution { bool[] dp = new bool[n + 1]; dp[n] = true; for (int i = m; i >= 0; i--) { - bool nextDp = true; - for (int j = n - 1; j >= 0; j--) { - bool res = false; + bool nextDp = (i == m ? true : false); + for (int j = n; j >= 0; j--) { + bool res = (j < n ? false : nextDp); if (i < m && s1[i] == s3[i + j] && dp[j]) { res = true; } @@ -1097,9 +1229,12 @@ func isInterleave(s1, s2, s3 string) bool { dp := make([]bool, n+1) dp[n] = true for i := m; i >= 0; i-- { - nextDp := true - for j := n - 1; j >= 0; j-- { - res := false + nextDp := (i == m) + for j := n; j >= 0; j-- { + res := nextDp + if j < n { + res = false + } if i < m && s1[i] == s3[i+j] && dp[j] { res = true } @@ -1137,9 +1272,10 @@ class Solution { val dp = BooleanArray(n + 1) dp[n] = true for (i in m downTo 0) { - var nextDp = true - for (j in n - 1 downTo 0) { - var res = false + var nextDp = (i == m) + for (j in n downTo 0) { + var res = nextDp + if (j < n) res = false if (i < m && s1[i] == s3[i + j] && dp[j]) { res = true } @@ -1155,11 +1291,47 @@ class Solution { } ``` +```swift +class Solution { + func isInterleave(_ s1: String, _ s2: String, _ s3: String) -> Bool { + var s1 = Array(s1), s2 = Array(s2), s3 = Array(s3) + var m = s1.count, n = s2.count + if m + n != s3.count { return false } + if n < m { + swap(&s1, &s2) + swap(&m, &n) + } + + var dp = Array(repeating: false, count: n + 1) + dp[n] = true + + for i in stride(from: m, through: 0, by: -1) { + var nextDp = (i == m) + for j in stride(from: n, through: 0, by: -1) { + var res = nextDp + if j < n { + res = false + } + if i < m && s1[i] == s3[i + j] && dp[j] { + res = true + } + if j < n && s2[j] == s3[i + j] && nextDp { + res = true + } + dp[j] = res + nextDp = dp[j] + } + } + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(min(m, n))$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(min(m, n))$ -> Where $m$ is the length of the string $s1$ and $n$ is the length of the string $s2$. \ No newline at end of file +> Where $m$ is the length of the string $s1$ and $n$ is the length of the string $s2$. diff --git a/articles/intersection-of-two-arrays.md b/articles/intersection-of-two-arrays.md index 5892704ec..33326dadb 100644 --- a/articles/intersection-of-two-arrays.md +++ b/articles/intersection-of-two-arrays.md @@ -80,8 +80,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n)$ > Where $n$ is the size of the array $nums1$ and $m$ is the size of the array $nums2$. @@ -109,7 +109,7 @@ class Solution: i += 1 while i < n and nums1[i] == nums1[i - 1]: i += 1 - + return res ``` @@ -184,7 +184,8 @@ class Solution { nums2.sort((a, b) => a - b); const res = []; - let i = 0, j = 0; + let i = 0, + j = 0; while (i < nums1.length && j < nums2.length) { while (j < nums2.length && nums2[j] < nums1[i]) { @@ -210,8 +211,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n + m \log m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n + m \log m)$ +- Space complexity: $O(n)$ > Where $n$ is the size of the array $nums1$ and $m$ is the size of the array $nums2$. @@ -303,8 +304,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ > Where $n$ is the size of the array $nums1$ and $m$ is the size of the array $nums2$. @@ -320,7 +321,7 @@ class Solution: seen = defaultdict(int) for num in nums1: seen[num] = 1 - + res = [] for num in nums2: if seen[num] == 1: @@ -400,8 +401,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n)$ > Where $n$ is the size of the array $nums1$ and $m$ is the size of the array $nums2$. @@ -489,8 +490,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n)$ > Where $n$ is the size of the array $nums1$ and $m$ is the size of the array $nums2$. @@ -518,7 +519,7 @@ public class Solution { for (Integer n : nums2) { set2.add(n); } - + set1.retainAll(set2); int[] res= new int[set1.size()]; int idx = 0; @@ -551,7 +552,7 @@ class Solution { */ intersection(nums1, nums2) { const set2 = new Set(nums2); - return [...new Set(nums1)].filter(num => set2.has(num)); + return [...new Set(nums1)].filter((num) => set2.has(num)); } } ``` @@ -560,7 +561,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ in average case, $O(n * m)$ in worst case. -* Space complexity: $O(n + m)$ +- Time complexity: $O(n + m)$ in average case, $O(n * m)$ in worst case. +- Space complexity: $O(n + m)$ -> Where $n$ is the size of the array $nums1$ and $m$ is the size of the array $nums2$. \ No newline at end of file +> Where $n$ is the size of the array $nums1$ and $m$ is the size of the array $nums2$. diff --git a/articles/intersection-of-two-linked-lists.md b/articles/intersection-of-two-linked-lists.md index 855f2a43f..98d0cc72c 100644 --- a/articles/intersection-of-two-linked-lists.md +++ b/articles/intersection-of-two-linked-lists.md @@ -108,12 +108,38 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int x) { val = x; } + * } + */ +public class Solution { + public ListNode GetIntersectionNode(ListNode headA, ListNode headB) { + while (headA != null) { + ListNode cur = headB; + while (cur != null) { + if (headA == cur) { + return headA; + } + cur = cur.next; + } + headA = headA.next; + } + return null; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(m * n)$ +- Space complexity: $O(1)$ extra space. > Where $m$ is the length of the first list and $n$ is the length of the second list. @@ -136,13 +162,13 @@ class Solution: while cur: nodeSet.add(cur) cur = cur.next - + cur = headB while cur: if cur in nodeSet: return cur cur = cur.next - + return None ``` @@ -161,13 +187,13 @@ class Solution: public class Solution { public ListNode getIntersectionNode(ListNode headA, ListNode headB) { HashSet nodeSet = new HashSet<>(); - + ListNode cur = headA; while (cur != null) { nodeSet.add(cur); cur = cur.next; } - + cur = headB; while (cur != null) { if (nodeSet.contains(cur)) { @@ -175,7 +201,7 @@ public class Solution { } cur = cur.next; } - + return null; } } @@ -194,13 +220,13 @@ class Solution { public: ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) { unordered_set nodeSet; - + ListNode* cur = headA; while (cur) { nodeSet.insert(cur); cur = cur->next; } - + cur = headB; while (cur) { if (nodeSet.find(cur) != nodeSet.end()) { @@ -208,7 +234,7 @@ public: } cur = cur->next; } - + return nullptr; } }; @@ -232,13 +258,13 @@ class Solution { */ getIntersectionNode(headA, headB) { const nodeSet = new Set(); - + let cur = headA; while (cur) { nodeSet.add(cur); cur = cur.next; } - + cur = headB; while (cur) { if (nodeSet.has(cur)) { @@ -246,7 +272,38 @@ class Solution { } cur = cur.next; } - + + return null; + } +} +``` + +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int x) { val = x; } + * } + */ +public class Solution { + public ListNode GetIntersectionNode(ListNode headA, ListNode headB) { + var nodeSet = new HashSet(); + var cur = headA; + while (cur != null) { + nodeSet.Add(cur); + cur = cur.next; + } + + cur = headB; + while (cur != null) { + if (nodeSet.Contains(cur)) { + return cur; + } + cur = cur.next; + } + return null; } } @@ -256,8 +313,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m + n)$ -* Space complexity: $O(m)$ +- Time complexity: $O(m + n)$ +- Space complexity: $O(m)$ > Where $m$ is the length of the first list and $n$ is the length of the second list. @@ -281,7 +338,7 @@ class Solution: length += 1 cur = cur.next return length - + m = getLength(headA) n = getLength(headB) l1, l2 = headA, headB @@ -289,15 +346,15 @@ class Solution: if m < n: m, n = n, m l1, l2 = headB, headA - + while m - n: m -= 1 l1 = l1.next - + while l1 != l2: l1 = l1.next l2 = l2.next - + return l1 ``` @@ -322,7 +379,7 @@ public class Solution { } return length; } - + public ListNode getIntersectionNode(ListNode headA, ListNode headB) { int m = getLength(headA); int n = getLength(headB); @@ -366,26 +423,26 @@ class Solution { } return length; } - + public: ListNode* getIntersectionNode(ListNode* headA, ListNode* headB) { int m = getLength(headA), n = getLength(headB); ListNode* l1 = headA, *l2 = headB; - + if (m < n) { swap(m, n); swap(l1, l2); } - + while (m-- > n) { l1 = l1->next; } - + while (l1 && l1 != l2) { l1 = l1->next; l2 = l2->next; } - + return l1; } }; @@ -409,7 +466,8 @@ class Solution { */ getIntersectionNode(headA, headB) { const getLength = (head) => { - let length = 0, cur = head; + let length = 0, + cur = head; while (cur) { length++; cur = cur.next; @@ -419,7 +477,8 @@ class Solution { let m = getLength(headA); let n = getLength(headB); - let l1 = headA, l2 = headB; + let l1 = headA, + l2 = headB; if (m < n) { [m, n] = [n, m]; @@ -440,12 +499,56 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int x) { val = x; } + * } + */ +public class Solution { + public ListNode GetIntersectionNode(ListNode headA, ListNode headB) { + int GetLength(ListNode head) { + int length = 0; + while (head != null) { + length++; + head = head.next; + } + return length; + } + + int m = GetLength(headA); + int n = GetLength(headB); + ListNode l1 = headA, l2 = headB; + + if (m < n) { + int temp = m; m = n; n = temp; + l1 = headB; + l2 = headA; + } + + for (int i = 0; i < m - n; i++) { + l1 = l1.next; + } + + while (l1 != l2) { + l1 = l1.next; + l2 = l2.next; + } + + return l1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(m + n)$ +- Space complexity: $O(1)$ extra space. > Where $m$ is the length of the first list and $n$ is the length of the second list. @@ -534,7 +637,8 @@ class Solution { * @return {ListNode} */ getIntersectionNode(headA, headB) { - let l1 = headA, l2 = headB; + let l1 = headA, + l2 = headB; while (l1 !== l2) { l1 = l1 ? l1.next : headB; l2 = l2 ? l2.next : headA; @@ -544,11 +648,34 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int x) { val = x; } + * } + */ +public class Solution { + public ListNode GetIntersectionNode(ListNode headA, ListNode headB) { + ListNode l1 = headA, l2 = headB; + + while (l1 != l2) { + l1 = (l1 != null) ? l1.next : headB; + l2 = (l2 != null) ? l2.next : headA; + } + + return l1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(m + n)$ +- Space complexity: $O(1)$ extra space. -> Where $m$ is the length of the first list and $n$ is the length of the second list. \ No newline at end of file +> Where $m$ is the length of the first list and $n$ is the length of the second list. diff --git a/articles/interval-list-intersections.md b/articles/interval-list-intersections.md new file mode 100644 index 000000000..4e923ac83 --- /dev/null +++ b/articles/interval-list-intersections.md @@ -0,0 +1,425 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def intervalIntersection(self, firstList: List[List[int]], secondList: List[List[int]]) -> List[List[int]]: + res = [] + for i in range(len(firstList)): + startA, endA = firstList[i][0], firstList[i][1] + for j in range(len(secondList)): + startB, endB = secondList[j][0], secondList[j][1] + if (startA <= startB <= endA) or (startB <= startA <= endB): + res.append([max(startA, startB), min(endA, endB)]) + return res +``` + +```java +public class Solution { + public int[][] intervalIntersection(int[][] firstList, int[][] secondList) { + List res = new ArrayList<>(); + for (int i = 0; i < firstList.length; i++) { + int startA = firstList[i][0], endA = firstList[i][1]; + for (int j = 0; j < secondList.length; j++) { + int startB = secondList[j][0], endB = secondList[j][1]; + if ((startA <= startB && startB <= endA) || (startB <= startA && startA <= endB)) { + res.add(new int[]{Math.max(startA, startB), Math.min(endA, endB)}); + } + } + } + return res.toArray(new int[res.size()][]); + } +} +``` + +```cpp +class Solution { +public: + vector> intervalIntersection(vector>& firstList, vector>& secondList) { + vector> res; + for (int i = 0; i < firstList.size(); i++) { + int startA = firstList[i][0], endA = firstList[i][1]; + for (int j = 0; j < secondList.size(); j++) { + int startB = secondList[j][0], endB = secondList[j][1]; + if ((startA <= startB && startB <= endA) || (startB <= startA && startA <= endB)) { + res.push_back({max(startA, startB), min(endA, endB)}); + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} firstList + * @param {number[][]} secondList + * @return {number[][]} + */ + intervalIntersection(firstList, secondList) { + const res = []; + for (let i = 0; i < firstList.length; i++) { + const [startA, endA] = firstList[i]; + for (let j = 0; j < secondList.length; j++) { + const [startB, endB] = secondList[j]; + if ((startA <= startB && startB <= endA) || (startB <= startA && startA <= endB)) { + res.push([Math.max(startA, startB), Math.min(endA, endB)]); + } + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public int[][] IntervalIntersection(int[][] firstList, int[][] secondList) { + var res = new List(); + for (int i = 0; i < firstList.Length; i++) { + int startA = firstList[i][0], endA = firstList[i][1]; + for (int j = 0; j < secondList.Length; j++) { + int startB = secondList[j][0], endB = secondList[j][1]; + if ((startA <= startB && startB <= endA) || (startB <= startA && startA <= endB)) { + res.Add(new int[] { Math.Max(startA, startB), Math.Min(endA, endB) }); + } + } + } + return res.ToArray(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: + * $O(1)$ extra space. + * $O(m + n)$ for the output list. + +> Where $m$ and $n$ are the sizes of the arrays $firstList$ and $secondList$, respectively. + +--- + +## 2. Line Sweep + +::tabs-start + +```python +class Solution: + def intervalIntersection(self, firstList: List[List[int]], secondList: List[List[int]]) -> List[List[int]]: + mp = defaultdict(int) + for s, e in firstList: + mp[s] += 1 + mp[e + 1] -= 1 + for s, e in secondList: + mp[s] += 1 + mp[e + 1] -= 1 + + res = [] + active = 0 + prev = None + for x in sorted(mp): + if active == 2: + res.append([prev, x - 1]) + active += mp[x] + prev = x + return res +``` + +```java +class Solution { + public int[][] intervalIntersection(int[][] firstList, int[][] secondList) { + TreeMap mp = new TreeMap<>(); + for (int[] f : firstList) { + mp.put(f[0], mp.getOrDefault(f[0], 0) + 1); + mp.put(f[1] + 1, mp.getOrDefault(f[1] + 1, 0) - 1); + } + for (int[] s : secondList) { + mp.put(s[0], mp.getOrDefault(s[0], 0) + 1); + mp.put(s[1] + 1, mp.getOrDefault(s[1] + 1, 0) - 1); + } + + List res = new ArrayList<>(); + int active = 0, prev = 0; + boolean started = false; + for (int x : mp.keySet()) { + if (active == 2) { + res.add(new int[]{prev, x - 1}); + } + active += mp.get(x); + prev = x; + } + return res.toArray(new int[res.size()][]); + } +} +``` + +```cpp +class Solution { +public: + vector> intervalIntersection(vector>& firstList, vector>& secondList) { + map mp; + for (auto& f : firstList) { + mp[f[0]] += 1; + mp[f[1] + 1] -= 1; + } + for (auto& s : secondList) { + mp[s[0]] += 1; + mp[s[1] + 1] -= 1; + } + + vector> res; + int active = 0, prev = 0; + bool started = false; + for (auto& [x, v] : mp) { + if (active == 2) { + res.push_back({prev, x - 1}); + } + active += v; + prev = x; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} firstList + * @param {number[][]} secondList + * @return {number[][]} + */ + intervalIntersection(firstList, secondList) { + let mp = new Map(); + for (let [s, e] of firstList) { + mp.set(s, (mp.get(s) || 0) + 1); + mp.set(e + 1, (mp.get(e + 1) || 0) - 1); + } + for (let [s, e] of secondList) { + mp.set(s, (mp.get(s) || 0) + 1); + mp.set(e + 1, (mp.get(e + 1) || 0) - 1); + } + + let keys = Array.from(mp.keys()).sort((a, b) => a - b); + let res = [], active = 0, prev = 0; + for (let x of keys) { + if (active === 2) { + res.push([prev, x - 1]); + } + active += mp.get(x); + prev = x; + } + return res; + } +} +``` + +```csharp +public class Solution { + public int[][] IntervalIntersection(int[][] firstList, int[][] secondList) { + var mp = new SortedDictionary(); + foreach (var f in firstList) { + if (!mp.ContainsKey(f[0])) mp[f[0]] = 0; + mp[f[0]] += 1; + if (!mp.ContainsKey(f[1] + 1)) mp[f[1] + 1] = 0; + mp[f[1] + 1] -= 1; + } + foreach (var s in secondList) { + if (!mp.ContainsKey(s[0])) mp[s[0]] = 0; + mp[s[0]] += 1; + if (!mp.ContainsKey(s[1] + 1)) mp[s[1] + 1] = 0; + mp[s[1] + 1] -= 1; + } + + var res = new List(); + int active = 0, prev = 0; + foreach (var kvp in mp) { + int x = kvp.Key; + if (active == 2) { + res.Add(new int[] { prev, x - 1 }); + } + active += kvp.Value; + prev = x; + } + return res.ToArray(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O((m + n) \log (m + n))$ +* Space complexity: $O(m + n)$ + +> Where $m$ and $n$ are the sizes of the arrays $firstList$ and $secondList$, respectively. + +--- + +## 3. Two Pointers + +::tabs-start + +```python +class Solution: + def intervalIntersection(self, firstList: List[List[int]], secondList: List[List[int]]) -> List[List[int]]: + res = [] + i = j = 0 + while i < len(firstList) and j < len(secondList): + startA, endA = firstList[i] + startB, endB = secondList[j] + + start = max(startA, startB) + end = min(endA, endB) + + if start <= end: + res.append([start, end]) + + if endA < endB: + i += 1 + else: + j += 1 + + return res +``` + +```java +public class Solution { + public int[][] intervalIntersection(int[][] firstList, int[][] secondList) { + List res = new ArrayList<>(); + int i = 0, j = 0; + + while (i < firstList.length && j < secondList.length) { + int startA = firstList[i][0], endA = firstList[i][1]; + int startB = secondList[j][0], endB = secondList[j][1]; + + int start = Math.max(startA, startB); + int end = Math.min(endA, endB); + + if (start <= end) { + res.add(new int[]{start, end}); + } + + if (endA < endB) { + i++; + } else { + j++; + } + } + + return res.toArray(new int[res.size()][]); + } +} +``` + +```cpp +class Solution { +public: + vector> intervalIntersection(vector>& firstList, vector>& secondList) { + vector> res; + int i = 0, j = 0; + + while (i < firstList.size() && j < secondList.size()) { + int startA = firstList[i][0], endA = firstList[i][1]; + int startB = secondList[j][0], endB = secondList[j][1]; + + int start = max(startA, startB); + int end = min(endA, endB); + + if (start <= end) { + res.push_back({start, end}); + } + + if (endA < endB) { + i++; + } else { + j++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} firstList + * @param {number[][]} secondList + * @return {number[][]} + */ + intervalIntersection(firstList, secondList) { + const res = []; + let i = 0, j = 0; + + while (i < firstList.length && j < secondList.length) { + const [startA, endA] = firstList[i]; + const [startB, endB] = secondList[j]; + + const start = Math.max(startA, startB); + const end = Math.min(endA, endB); + + if (start <= end) { + res.push([start, end]); + } + + if (endA < endB) { + i++; + } else { + j++; + } + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int[][] IntervalIntersection(int[][] firstList, int[][] secondList) { + var res = new List(); + int i = 0, j = 0; + + while (i < firstList.Length && j < secondList.Length) { + int startA = firstList[i][0], endA = firstList[i][1]; + int startB = secondList[j][0], endB = secondList[j][1]; + + int start = Math.Max(startA, startB); + int end = Math.Min(endA, endB); + + if (start <= end) { + res.Add(new int[] { start, end }); + } + + if (endA < endB) { + i++; + } else { + j++; + } + } + + return res.ToArray(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m + n)$ +* Space complexity: + * $O(1)$ extra space. + * $O(m + n)$ for the output list. + +> Where $m$ and $n$ are the sizes of the arrays $firstList$ and $secondList$, respectively. \ No newline at end of file diff --git a/articles/invert-a-binary-tree.md b/articles/invert-a-binary-tree.md index ed6a548cc..25a529652 100644 --- a/articles/invert-a-binary-tree.md +++ b/articles/invert-a-binary-tree.md @@ -227,16 +227,54 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func invertTree(_ root: TreeNode?) -> TreeNode? { + guard let root = root else { return nil } + var queue = Deque() + queue.append(root) + + while !queue.isEmpty { + let node = queue.removeFirst() + (node.left, node.right) = (node.right, node.left) + + if let left = node.left { + queue.append(left) + } + if let right = node.right { + queue.append(right) + } + } + return root + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- -## 2. Depth First Search +## 2. Depth First Search ::tabs-start @@ -253,10 +291,10 @@ class Solution: if not root: return None root.left, root.right = root.right, root.left - + self.invertTree(root.left) self.invertTree(root.right) - + return root ``` @@ -277,16 +315,18 @@ class Solution: * } */ -class Solution { +public class Solution { public TreeNode invertTree(TreeNode root) { if (root == null) return null; - - TreeNode node = new TreeNode(root.val); - node.right = invertTree(root.left); - node.left = invertTree(root.right); - - return node; + TreeNode temp = root.left; + root.left = root.right; + root.right = temp; + + invertTree(root.left); + invertTree(root.right); + + return root; } } ``` @@ -307,14 +347,13 @@ class Solution { class Solution { public: TreeNode* invertTree(TreeNode* root) { - if (root == nullptr) return nullptr; + if (!root) return nullptr; - TreeNode* node = new TreeNode(root->val); - - node->right = invertTree(root->left); - node->left = invertTree(root->right); + swap(root->left, root->right); + invertTree(root->left); + invertTree(root->right); - return node; + return root; } }; ``` @@ -337,14 +376,13 @@ class Solution { * @return {TreeNode} */ invertTree(root) { - if (root === null) return null; - - const node = new TreeNode(root.val); + if (!root) return null; - node.right = this.invertTree(root.left); - node.left = this.invertTree(root.right); + [root.left, root.right] = [root.right, root.left]; + this.invertTree(root.left); + this.invertTree(root.right); - return node; + return root; } } ``` @@ -368,12 +406,95 @@ public class Solution { public TreeNode InvertTree(TreeNode root) { if (root == null) return null; - TreeNode node = new TreeNode(root.val); - - node.right = InvertTree(root.left); - node.left = InvertTree(root.right); + TreeNode temp = root.left; + root.left = root.right; + root.right = temp; - return node; + InvertTree(root.left); + InvertTree(root.right); + + return root; + } +} +``` + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ + +func invertTree(root *TreeNode) *TreeNode { + if root == nil { + return nil + } + + root.Left, root.Right = root.Right, root.Left + invertTree(root.Left) + invertTree(root.Right) + + return root +} +``` + +```kotlin +/** + * Example: + * var ti = TreeNode(5) + * var v = ti.`val` + * Definition for a binary tree node. + * class TreeNode(var `val`: Int) { + * var left: TreeNode? = null + * var right: TreeNode? = null + * } + */ + +class Solution { + fun invertTree(root: TreeNode?): TreeNode? { + if (root == null) return null + + val temp = root.left + root.left = root.right + root.right = temp + + invertTree(root.left) + invertTree(root.right) + + return root + } +} +``` + +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func invertTree(_ root: TreeNode?) -> TreeNode? { + guard let root = root else { return nil } + + (root.left, root.right) = (root.right, root.left) + + invertTree(root.left) + invertTree(root.right) + + return root } } ``` @@ -382,12 +503,12 @@ public class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. --- -## 3. Depth First Search (Stack) +## 3. Iterative DFS ::tabs-start @@ -592,9 +713,46 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func invertTree(_ root: TreeNode?) -> TreeNode? { + guard let root = root else { return nil } + var stack: [TreeNode] = [root] + + while !stack.isEmpty { + let node = stack.removeLast() + (node.left, node.right) = (node.right, node.left) + + if let left = node.left { + stack.append(left) + } + if let right = node.right { + stack.append(right) + } + } + return root + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/ipo.md b/articles/ipo.md index e71ba4c34..63fc51b1a 100644 --- a/articles/ipo.md +++ b/articles/ipo.md @@ -13,10 +13,10 @@ class Solution: while minCapital and minCapital[0][0] <= w: c, p = heapq.heappop(minCapital) heapq.heappush(maxProfit, -p) - + if not maxProfit: break - + w += -heapq.heappop(maxProfit) return w @@ -27,21 +27,21 @@ public class Solution { public int findMaximizedCapital(int k, int w, int[] profits, int[] capital) { PriorityQueue minCapital = new PriorityQueue<>((a, b) -> a[0] - b[0]); // Min heap PriorityQueue maxProfit = new PriorityQueue<>((a, b) -> b - a); // Max heap - + for (int i = 0; i < capital.length; i++) { minCapital.offer(new int[]{capital[i], profits[i]}); } - + for (int i = 0; i < k; i++) { while (!minCapital.isEmpty() && minCapital.peek()[0] <= w) { maxProfit.offer(minCapital.poll()[1]); } if (maxProfit.isEmpty()) { break; - } + } w += maxProfit.poll(); } - + return w; } } @@ -53,11 +53,11 @@ public: int findMaximizedCapital(int k, int w, vector& profits, vector& capital) { priority_queue maxProfit; // Max heap priority_queue, vector>, greater<>> minCapital; // Min heap - + for (int i = 0; i < capital.size(); i++) { minCapital.emplace(capital[i], profits[i]); } - + for (int i = 0; i < k; i++) { while (!minCapital.empty() && minCapital.top().first <= w) { maxProfit.push(minCapital.top().second); @@ -69,7 +69,7 @@ public: w += maxProfit.top(); maxProfit.pop(); } - + return w; } }; @@ -85,13 +85,13 @@ class Solution { * @return {number} */ findMaximizedCapital(k, w, profits, capital) { - const minCapital = new MinPriorityQueue({ compare: (a, b) => a[0] - b[0] }); // Min heap - const maxProfit = new MaxPriorityQueue({ compare: (a, b) => b - a }); // Max heap - + const minCapital = new PriorityQueue((a, b) => a[0] - b[0]); // Min heap + const maxProfit = new PriorityQueue((a, b) => b - a); // Max heap + for (let i = 0; i < capital.length; i++) { minCapital.enqueue([capital[i], profits[i]]); } - + for (let i = 0; i < k; i++) { while (!minCapital.isEmpty() && minCapital.front()[0] <= w) { maxProfit.enqueue(minCapital.dequeue()[1]); @@ -101,7 +101,40 @@ class Solution { } w += maxProfit.dequeue(); } - + + return w; + } +} +``` + +```csharp +public class Solution { + public int FindMaximizedCapital(int k, int w, int[] profits, int[] capital) { + var minCapital = new List<(int c, int p)>(); + for (int i = 0; i < capital.Length; i++) { + minCapital.Add((capital[i], profits[i])); + } + + // Min-heap by capital + minCapital.Sort((a, b) => a.c.CompareTo(b.c)); + + // Max-heap by profit + var maxProfit = new PriorityQueue(Comparer.Create((a, b) => b.CompareTo(a))); + int iPtr = 0; + + for (int i = 0; i < k; i++) { + while (iPtr < minCapital.Count && minCapital[iPtr].c <= w) { + maxProfit.Enqueue(minCapital[iPtr].p, minCapital[iPtr].p); + iPtr++; + } + + if (maxProfit.Count == 0) { + break; + } + + w += maxProfit.Dequeue(); + } + return w; } } @@ -111,8 +144,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -126,7 +159,7 @@ class Solution: class Node: def __init__(self, idx): self.idx = idx - + def __lt__(self, other): if capital[self.idx] != capital[other.idx]: return capital[self.idx] < capital[other.idx] @@ -141,7 +174,7 @@ class Solution: while minCapital and capital[minCapital[0].idx] <= w: idx = heapq.heappop(minCapital).idx heapq.heappush(maxProfit, -profits[idx]) - + if not maxProfit: break w += -heapq.heappop(maxProfit) @@ -215,12 +248,8 @@ class Solution { * @return {number} */ findMaximizedCapital(k, w, profits, capital) { - const minCapital = new MinPriorityQueue({ - compare: (a, b) => capital[a] - capital[b], - }); - const maxProfit = new MaxPriorityQueue({ - compare: (a, b) => profits[b] - profits[a], - }); + const minCapital = new PriorityQueue((a, b) => capital[a] - capital[b]); + const maxProfit = new PriorityQueue((a, b) => profits[b] - profits[a]); for (let i = 0; i < capital.length; i++) { minCapital.enqueue(i); @@ -241,12 +270,40 @@ class Solution { } ``` +```csharp +public class Solution { + public int FindMaximizedCapital(int k, int w, int[] profits, int[] capital) { + var minCapital = new PriorityQueue(); // index with capital as priority + var maxProfit = new PriorityQueue(Comparer.Create((a, b) => b.CompareTo(a))); // max heap by profit + + for (int i = 0; i < capital.Length; i++) { + minCapital.Enqueue(i, capital[i]); + } + + for (int i = 0; i < k; i++) { + while (minCapital.Count > 0 && capital[minCapital.Peek()] <= w) { + int idx = minCapital.Dequeue(); + maxProfit.Enqueue(profits[idx], profits[idx]); + } + + if (maxProfit.Count == 0) { + break; + } + + w += maxProfit.Dequeue(); + } + + return w; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -260,17 +317,17 @@ class Solution: n = len(profits) indices = list(range(n)) indices.sort(key=lambda i: capital[i]) - + maxProfit, idx = [], 0 for _ in range(k): while idx < n and capital[indices[idx]] <= w: heapq.heappush(maxProfit, -profits[indices[idx]]) idx += 1 - + if not maxProfit: break w += -heapq.heappop(maxProfit) - + return w ``` @@ -283,20 +340,20 @@ public class Solution { indices[i] = i; } Arrays.sort(indices, (a, b) -> Integer.compare(capital[a], capital[b])); - + PriorityQueue maxProfit = new PriorityQueue<>(Collections.reverseOrder()); int idx = 0; for (int i = 0; i < k; i++) { while (idx < n && capital[indices[idx]] <= w) { maxProfit.add(profits[indices[idx]]); idx++; - } + } if (maxProfit.isEmpty()) { break; } w += maxProfit.poll(); } - + return w; } } @@ -314,7 +371,7 @@ public: sort(indices.begin(), indices.end(), [&](int a, int b) { return capital[a] < capital[b]; }); - + priority_queue maxProfit; int idx = 0; for (int i = 0; i < k; i++) { @@ -324,7 +381,7 @@ public: } if (maxProfit.empty()) { break; - } + } w += maxProfit.top(); maxProfit.pop(); } @@ -347,7 +404,7 @@ class Solution { const n = profits.length; const indices = Array.from({ length: n }, (_, i) => i); indices.sort((a, b) => capital[a] - capital[b]); - + const maxProfit = new MaxPriorityQueue(); let idx = 0; for (let i = 0; i < k; i++) { @@ -358,9 +415,41 @@ class Solution { if (maxProfit.isEmpty()) { break; } - w += maxProfit.dequeue().element; + w += maxProfit.dequeue(); + } + + return w; + } +} +``` + +```csharp +public class Solution { + public int FindMaximizedCapital(int k, int w, int[] profits, int[] capital) { + int n = profits.Length; + int[] indices = new int[n]; + for (int i = 0; i < n; i++) { + indices[i] = i; + } + + Array.Sort(indices, (a, b) => capital[a].CompareTo(capital[b])); + + var maxProfit = new PriorityQueue(Comparer.Create((a, b) => b.CompareTo(a))); + int idx = 0; + + for (int i = 0; i < k; i++) { + while (idx < n && capital[indices[idx]] <= w) { + maxProfit.Enqueue(profits[indices[idx]], profits[indices[idx]]); + idx++; + } + + if (maxProfit.Count == 0) { + break; + } + + w += maxProfit.Dequeue(); } - + return w; } } @@ -370,5 +459,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/is-anagram.md b/articles/is-anagram.md index ae3a44534..9cef09353 100644 --- a/articles/is-anagram.md +++ b/articles/is-anagram.md @@ -7,7 +7,7 @@ class Solution: def isAnagram(self, s: str, t: str) -> bool: if len(s) != len(t): return False - + return sorted(s) == sorted(t) ``` @@ -54,9 +54,9 @@ class Solution { return false; } - let sSort = s.split("").sort().join(); - let tSort = t.split("").sort().join(); - return sSort == tSort + let sSort = s.split('').sort().join(); + let tSort = t.split('').sort().join(); + return sSort == tSort; } } ``` @@ -82,15 +82,15 @@ func isAnagram(s string, t string) bool { if len(s) != len(t) { return false } - + sRunes, tRunes := []rune(s), []rune(t) - sort.Slice(sRunes, func(i, j int) bool { - return sRunes[i] < sRunes[j] + sort.Slice(sRunes, func(i, j int) bool { + return sRunes[i] < sRunes[j] }) - sort.Slice(tRunes, func(i, j int) bool { - return tRunes[i] < tRunes[j] + sort.Slice(tRunes, func(i, j int) bool { + return tRunes[i] < tRunes[j] }) - + for i := range sRunes { if sRunes[i] != tRunes[i] { return false @@ -106,24 +106,32 @@ class Solution { if (s.length != t.length) { return false } - + return s.toCharArray().sorted() == t.toCharArray().sorted() } } ``` +```swift +class Solution { + func isAnagram(_ s: String, _ t: String) -> Bool { + return s.count == t.count && s.sorted() == t.sorted() + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n + m \log m)$ -* Space complexity: $O(1)$ or $O(n + m)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n + m \log m)$ +- Space complexity: $O(1)$ or $O(n + m)$ depending on the sorting algorithm. -> Where $n$ is the length of string $s$ and $m$ is the length of string $t$. +> Where $n$ is the length of string $s$ and $m$ is the length of string $t$. --- -## 2. Hash Table +## 2. Hash Map ::tabs-start @@ -266,18 +274,41 @@ class Solution { } ``` +```swift +class Solution { + func isAnagram(_ s: String, _ t: String) -> Bool { + if s.count != t.count { + return false + } + + var countS = [Character: Int]() + var countT = [Character: Int]() + + let sArray = Array(s) + let tArray = Array(t) + + for i in 0.. Where $n$ is the length of string $s$ and $m$ is the length of string $t$. +> Where $n$ is the length of string $s$ and $m$ is the length of string $t$. --- -## 3. Hash Table (Optimal) +## 3. Hash Table (Using Array) ::tabs-start @@ -362,7 +393,7 @@ class Solution { count[s.charCodeAt(i) - 'a'.charCodeAt(0)]++; count[t.charCodeAt(i) - 'a'.charCodeAt(0)]--; } - return count.every(val => val === 0); + return count.every((val) => val === 0); } } ``` @@ -434,11 +465,37 @@ class Solution { } ``` +```swift +class Solution { + func isAnagram(_ s: String, _ t: String) -> Bool { + if s.count != t.count { + return false + } + + var count = [Int](repeating: 0, count: 26) + let sArray = Array(s) + let tArray = Array(t) + + for i in 0.. Where $n$ is the length of string $s$ and $m$ is the length of string $t$. diff --git a/articles/is-graph-bipartite.md b/articles/is-graph-bipartite.md new file mode 100644 index 000000000..1a441c806 --- /dev/null +++ b/articles/is-graph-bipartite.md @@ -0,0 +1,612 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def isBipartite(self, graph: List[List[int]]) -> bool: + color = [0] * len(graph) # Map node i -> odd=1, even=-1 + + def dfs(i, c): + color[i] = c + for nei in graph[i]: + if color[nei] == c: + return False + if color[nei] == 0 and not dfs(nei, -c): + return False + return True + + for i in range(len(graph)): + if color[i] == 0 and not dfs(i, 1): + return False + return True +``` + +```java +public class Solution { + private int[] color; + + public boolean isBipartite(int[][] graph) { + int n = graph.length; + color = new int[n]; // Map node i -> odd=1, even=-1 + + for (int i = 0; i < n; i++) { + if (color[i] == 0 && !dfs(graph, i, 1)) { + return false; + } + } + return true; + } + + private boolean dfs(int[][] graph, int i, int c) { + color[i] = c; + for (int nei : graph[i]) { + if (color[nei] == c) { + return false; + } + if (color[nei] == 0 && !dfs(graph, nei, -c)) { + return false; + } + } + return true; + } +} +``` + +```cpp +class Solution { +private: + vector color; + + bool dfs(vector>& graph, int i, int c) { + color[i] = c; + for (int nei : graph[i]) { + if (color[nei] == c) { + return false; + } + if (color[nei] == 0 && !dfs(graph, nei, -c)) { + return false; + } + } + return true; + } + +public: + bool isBipartite(vector>& graph) { + int n = graph.size(); + color.assign(n, 0); // Map node i -> odd=1, even=-1 + + for (int i = 0; i < n; i++) { + if (color[i] == 0 && !dfs(graph, i, 1)) { + return false; + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} graph + * @return {boolean} + */ + isBipartite(graph) { + let n = graph.length; + let color = new Array(n).fill(0); // Map node i -> odd=1, even=-1 + + const dfs = (i, c) => { + color[i] = c; + for (let nei of graph[i]) { + if (color[nei] === c) { + return false; + } + if (color[nei] === 0 && !dfs(nei, -c)) { + return false; + } + } + return true; + }; + + for (let i = 0; i < n; i++) { + if (color[i] === 0 && !dfs(i, 1)) { + return false; + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class Solution: + def isBipartite(self, graph: List[List[int]]) -> bool: + color = [0] * len(graph) # Map node i -> odd=1, even=-1 + + def bfs(i): + if color[i]: + return True + q = deque([i]) + color[i] = -1 + while q: + i = q.popleft() + for nei in graph[i]: + if color[i] == color[nei]: + return False + elif not color[nei]: + q.append(nei) + color[nei] = -1 * color[i] + return True + + for i in range(len(graph)): + if not bfs(i): + return False + return True +``` + +```java +public class Solution { + public boolean isBipartite(int[][] graph) { + int n = graph.length; + int[] color = new int[n]; // Map node i -> odd=1, even=-1 + + for (int i = 0; i < n; i++) { + if (color[i] != 0) continue; + Queue q = new LinkedList<>(); + q.offer(i); + color[i] = -1; + + while (!q.isEmpty()) { + int node = q.poll(); + for (int nei : graph[node]) { + if (color[nei] == color[node]) { + return false; + } else if (color[nei] == 0) { + q.offer(nei); + color[nei] = -color[node]; + } + } + } + } + return true; + } +} +``` + +```cpp +class Solution { +public: + bool isBipartite(vector>& graph) { + int n = graph.size(); + vector color(n, 0); // Map node i -> odd=1, even=-1 + + for (int i = 0; i < n; i++) { + if (color[i] != 0) continue; + queue q; + q.push(i); + color[i] = -1; + + while (!q.empty()) { + int node = q.front(); + q.pop(); + for (int nei : graph[node]) { + if (color[nei] == color[node]) { + return false; + } else if (color[nei] == 0) { + q.push(nei); + color[nei] = -color[node]; + } + } + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} graph + * @return {boolean} + */ + isBipartite(graph) { + let n = graph.length; + let color = new Array(n).fill(0); // Map node i -> odd=1, even=-1 + + for (let i = 0; i < n; i++) { + if (color[i] !== 0) continue; + let q = new Queue([i]); + color[i] = -1; + + while (!q.isEmpty()) { + let node = q.pop(); + for (let nei of graph[node]) { + if (color[nei] === color[node]) { + return false; + } else if (color[nei] === 0) { + q.push(nei); + color[nei] = -color[node]; + } + } + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +class Solution: + def isBipartite(self, graph: List[List[int]]) -> bool: + color = [0] * len(graph) # Map node i -> odd=1, even=-1 + stack = [] + + for i in range(len(graph)): + if color[i] != 0: + continue + color[i] = -1 + stack.append(i) + while stack: + node = stack.pop() + for nei in graph[node]: + if color[node] == color[nei]: + return False + elif not color[nei]: + stack.append(nei) + color[nei] = -1 * color[node] + + return True +``` + +```java +public class Solution { + public boolean isBipartite(int[][] graph) { + int n = graph.length; + int[] color = new int[n]; // Map node i -> odd=1, even=-1 + Stack stack = new Stack<>(); + + for (int i = 0; i < n; i++) { + if (color[i] != 0) continue; + color[i] = -1; + stack.push(i); + while (!stack.isEmpty()) { + int node = stack.pop(); + for (int nei : graph[node]) { + if (color[node] == color[nei]) return false; + if (color[nei] == 0) { + stack.push(nei); + color[nei] = -color[node]; + } + } + } + } + return true; + } +} +``` + +```cpp +class Solution { +public: + bool isBipartite(vector>& graph) { + int n = graph.size(); + vector color(n); // Map node i -> odd=1, even=-1 + stack stack; + + for (int i = 0; i < n; i++) { + if (color[i] != 0) continue; + color[i] = -1; + stack.push(i); + while (!stack.empty()) { + int node = stack.top(); + stack.pop(); + for (int nei : graph[node]) { + if (color[node] == color[nei]) return false; + if (color[nei] == 0) { + stack.push(nei); + color[nei] = -color[node]; + } + } + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} graph + * @return {boolean} + */ + isBipartite(graph) { + let n = graph.length; + let color = new Array(n).fill(0); // Map node i -> odd=1, even=-1 + let stack = []; + + for (let i = 0; i < n; i++) { + if (color[i] !== 0) continue; + color[i] = -1; + stack.push(i); + while (stack.length > 0) { + let node = stack.pop(); + for (let nei of graph[node]) { + if (color[node] === color[nei]) return false; + if (color[nei] === 0) { + stack.push(nei); + color[nei] = -color[node]; + } + } + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 4. Disjoint Set Union + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.Parent = list(range(n)) + self.Size = [0] * n + + def find(self, node): + if self.Parent[node] != node: + self.Parent[node] = self.find(self.Parent[node]) + return self.Parent[node] + + def union(self, u, v): + pu, pv = self.find(u), self.find(v) + if pu == pv: + return False + if self.Size[pu] > self.Size[pv]: + self.Parent[pv] = pu + elif self.Size[pu] < self.Size[pv]: + self.Parent[pu] = pv + else: + self.Parent[pv] = pu + self.Size[pu] += 1 + return True + +class Solution: + def isBipartite(self, graph: List[List[int]]) -> bool: + n = len(graph) + dsu = DSU(n) + + for node in range(n): + for nei in graph[node]: + if dsu.find(node) == dsu.find(nei): + return False + dsu.union(graph[node][0], nei) + + return True +``` + +```java +public class DSU { + private int[] Parent, Size; + + public DSU(int n) { + Parent = new int[n]; + Size = new int[n]; + for (int i = 0; i < n; i++) { + Parent[i] = i; + Size[i] = 0; + } + } + + public int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + public boolean union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (Size[pu] > Size[pv]) { + Parent[pv] = pu; + } else if (Size[pu] < Size[pv]) { + Parent[pu] = pv; + } else { + Parent[pv] = pu; + Size[pu]++; + } + return true; + } +} + +class Solution { + public boolean isBipartite(int[][] graph) { + int n = graph.length; + DSU dsu = new DSU(n); + + for (int node = 0; node < n; node++) { + for (int nei : graph[node]) { + if (dsu.find(node) == dsu.find(nei)) { + return false; + } + dsu.union(graph[node][0], nei); + } + } + return true; + } +} +``` + +```cpp +class DSU { +private: + vector Parent, Size; + +public: + DSU(int n) { + Parent.resize(n); + Size.resize(n, 0); + for (int i = 0; i < n; i++) { + Parent[i] = i; + } + } + + int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + bool unionSet(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (Size[pu] > Size[pv]) { + Parent[pv] = pu; + } else if (Size[pu] < Size[pv]) { + Parent[pu] = pv; + } else { + Parent[pv] = pu; + Size[pu]++; + } + return true; + } +}; + +class Solution { +public: + bool isBipartite(vector>& graph) { + int n = graph.size(); + DSU dsu(n); + + for (int node = 0; node < n; node++) { + for (int& nei : graph[node]) { + if (dsu.find(node) == dsu.find(nei)) { + return false; + } + dsu.unionSet(graph[node][0], nei); + } + } + return true; + } +}; +``` + +```javascript +class DSU { + /** + * @constructor + * @param {number} n + */ + constructor(n) { + this.parent = Array.from({ length: n + 1 }, (_, i) => i); + this.size = new Array(n + 1).fill(1); + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.parent[node] !== node) { + this.parent[node] = this.find(this.parent[node]); + } + return this.parent[node]; + } + + /** + * @param {number} u + * @param {number} u=v + * @return {boolean} + */ + union(u, v) { + let pu = this.find(u), + pv = this.find(v); + if (pu === pv) return false; + if (this.size[pu] >= this.size[pv]) { + this.size[pu] += this.size[pv]; + this.parent[pv] = pu; + } else { + this.size[pv] += this.size[pu]; + this.parent[pu] = pv; + } + return true; + } +} + +class Solution { + /** + * @param {number[][]} graph + * @return {boolean} + */ + isBipartite(graph) { + let n = graph.length; + let dsu = new DSU(n); + + for (let node = 0; node < n; node++) { + for (let nei of graph[node]) { + if (dsu.find(node) === dsu.find(nei)) { + return false; + } + dsu.union(graph[node][0], nei); + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + (E * α(V)))$ +- Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. $α()$ is used for amortized complexity. diff --git a/articles/is-palindrome.md b/articles/is-palindrome.md index e7675ceb9..76910a13a 100644 --- a/articles/is-palindrome.md +++ b/articles/is-palindrome.md @@ -49,9 +49,11 @@ class Solution { * @return {boolean} */ isAlphanumeric(char) { - return (char >= 'a' && char <= 'z') || - (char >= 'A' && char <= 'Z') || - (char >= '0' && char <= '9'); + return ( + (char >= 'a' && char <= 'z') || + (char >= 'A' && char <= 'Z') || + (char >= '0' && char <= '9') + ); } /** @@ -61,7 +63,7 @@ class Solution { isPalindrome(s) { let newStr = ''; for (let c of s) { - if (this.isAlphanumeric(c)) { + if (this.isAlphanumeric(c)) { newStr += c.toLowerCase(); } } @@ -123,12 +125,28 @@ class Solution { } ``` +```swift +class Solution { + func isPalindrome(_ s: String) -> Bool { + var newStr = "" + + for c in s { + if c.isLetter || c.isNumber { + newStr.append(c.lowercased()) + } + } + + return newStr == String(newStr.reversed()) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -150,10 +168,10 @@ class Solution: return False l, r = l + 1, r - 1 return True - + def alphaNum(self, c): - return (ord('A') <= ord(c) <= ord('Z') or - ord('a') <= ord(c) <= ord('z') or + return (ord('A') <= ord(c) <= ord('Z') or + ord('a') <= ord(c) <= ord('z') or ord('0') <= ord(c) <= ord('9')) ``` @@ -178,8 +196,8 @@ public class Solution { } public boolean alphaNum(char c) { - return (c >= 'A' && c <= 'Z' || - c >= 'a' && c <= 'z' || + return (c >= 'A' && c <= 'Z' || + c >= 'a' && c <= 'z' || c >= '0' && c <= '9'); } } @@ -207,8 +225,8 @@ public: } bool alphaNum(char c) { - return (c >= 'A' && c <= 'Z' || - c >= 'a' && c <= 'z' || + return (c >= 'A' && c <= 'Z' || + c >= 'a' && c <= 'z' || c >= '0' && c <= '9'); } }; @@ -221,7 +239,8 @@ class Solution { * @return {boolean} */ isPalindrome(s) { - let l = 0, r = s.length - 1; + let l = 0, + r = s.length - 1; while (l < r) { while (l < r && !this.alphaNum(s[l])) { @@ -233,7 +252,8 @@ class Solution { if (s[l].toLowerCase() !== s[r].toLowerCase()) { return false; } - l++; r--; + l++; + r--; } return true; } @@ -243,9 +263,11 @@ class Solution { * @return {boolean} */ alphaNum(c) { - return (c >= 'A' && c <= 'Z' || - c >= 'a' && c <= 'z' || - c >= '0' && c <= '9'); + return ( + (c >= 'A' && c <= 'Z') || + (c >= 'a' && c <= 'z') || + (c >= '0' && c <= '9') + ); } } ``` @@ -271,8 +293,8 @@ public class Solution { } public bool AlphaNum(char c) { - return (c >= 'A' && c <= 'Z' || - c >= 'a' && c <= 'z' || + return (c >= 'A' && c <= 'Z' || + c >= 'a' && c <= 'z' || c >= '0' && c <= '9'); } } @@ -327,9 +349,37 @@ class Solution { } ``` +```swift +class Solution { + func isPalindrome(_ s: String) -> Bool { + let chars = Array(s) + var l = 0, r = chars.count - 1 + + while l < r { + while l < r && !isAlphaNum(chars[l]) { + l += 1 + } + while r > l && !isAlphaNum(chars[r]) { + r -= 1 + } + if chars[l].lowercased() != chars[r].lowercased() { + return false + } + l += 1 + r -= 1 + } + return true + } + + private func isAlphaNum(_ c: Character) -> Bool { + return c.isLetter || c.isNumber + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/is-subsequence.md b/articles/is-subsequence.md index fde7628a6..2d725e239 100644 --- a/articles/is-subsequence.md +++ b/articles/is-subsequence.md @@ -10,7 +10,7 @@ class Solution: return True if j == len(t): return False - + if s[i] == t[j]: return rec(i + 1, j + 1) return rec(i, j + 1) @@ -72,12 +72,30 @@ class Solution { } ``` +```csharp +public class Solution { + public bool IsSubsequence(string s, string t) { + return Rec(0, 0, s, t); + } + + private bool Rec(int i, int j, string s, string t) { + if (i == s.Length) return true; + if (j == t.Length) return false; + + if (s[i] == t[j]) { + return Rec(i + 1, j + 1, s, t); + } + return Rec(i, j + 1, s, t); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n)$ > Where $n$ is the length of the string $s$ and $m$ is the length of the string $t$. @@ -166,7 +184,8 @@ class Solution { * @return {boolean} */ isSubsequence(s, t) { - const n = s.length, m = t.length; + const n = s.length, + m = t.length; const memo = Array.from({ length: n }, () => Array(m).fill(-1)); const rec = (i, j) => { @@ -186,12 +205,39 @@ class Solution { } ``` +```csharp +public class Solution { + public bool IsSubsequence(string s, string t) { + int n = s.Length, m = t.Length; + int[,] memo = new int[n, m]; + for (int i = 0; i < n; i++) + for (int j = 0; j < m; j++) + memo[i, j] = -1; + + bool Rec(int i, int j) { + if (i == n) return true; + if (j == m) return false; + if (memo[i, j] != -1) return memo[i, j] == 1; + + if (s[i] == t[j]) { + memo[i, j] = Rec(i + 1, j + 1) ? 1 : 0; + } else { + memo[i, j] = Rec(i, j + 1) ? 1 : 0; + } + return memo[i, j] == 1; + } + + return Rec(0, 0); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ > Where $n$ is the length of the string $s$ and $m$ is the length of the string $t$. @@ -206,17 +252,17 @@ class Solution: def isSubsequence(self, s: str, t: str) -> bool: n, m = len(s), len(t) dp = [[False] * (m + 1) for _ in range(n + 1)] - + for j in range(m + 1): dp[n][j] = True - + for i in range(n - 1, -1, -1): for j in range(m - 1, -1, -1): if s[i] == t[j]: dp[i][j] = dp[i + 1][j + 1] else: dp[i][j] = dp[i][j + 1] - + return dp[0][0] ``` @@ -225,11 +271,11 @@ public class Solution { public boolean isSubsequence(String s, String t) { int n = s.length(), m = t.length(); boolean[][] dp = new boolean[n + 1][m + 1]; - + for (int j = 0; j <= m; j++) { dp[n][j] = true; } - + for (int i = n - 1; i >= 0; i--) { for (int j = m - 1; j >= 0; j--) { if (s.charAt(i) == t.charAt(j)) { @@ -239,7 +285,7 @@ public class Solution { } } } - + return dp[0][0]; } } @@ -251,11 +297,11 @@ public: bool isSubsequence(string s, string t) { int n = s.size(), m = t.size(); vector> dp(n + 1, vector(m + 1, false)); - + for (int j = 0; j <= m; ++j) { dp[n][j] = true; } - + for (int i = n - 1; i >= 0; --i) { for (int j = m - 1; j >= 0; --j) { if (s[i] == t[j]) { @@ -265,7 +311,7 @@ public: } } } - + return dp[0][0]; } }; @@ -279,13 +325,16 @@ class Solution { * @return {boolean} */ isSubsequence(s, t) { - const n = s.length, m = t.length; - const dp = Array.from({ length: n + 1 }, () => Array(m + 1).fill(false)); - + const n = s.length, + m = t.length; + const dp = Array.from({ length: n + 1 }, () => + Array(m + 1).fill(false), + ); + for (let j = 0; j <= m; j++) { dp[n][j] = true; } - + for (let i = n - 1; i >= 0; i--) { for (let j = m - 1; j >= 0; j--) { if (s[i] === t[j]) { @@ -295,18 +344,43 @@ class Solution { } } } - + return dp[0][0]; } } ``` +```csharp +public class Solution { + public bool IsSubsequence(string s, string t) { + int n = s.Length, m = t.Length; + bool[,] dp = new bool[n + 1, m + 1]; + + for (int j = 0; j <= m; j++) { + dp[n, j] = true; + } + + for (int i = n - 1; i >= 0; i--) { + for (int j = m - 1; j >= 0; j--) { + if (s[i] == t[j]) { + dp[i, j] = dp[i + 1, j + 1]; + } else { + dp[i, j] = dp[i, j + 1]; + } + } + } + + return dp[0, 0]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ > Where $n$ is the length of the string $s$ and $m$ is the length of the string $t$. @@ -366,7 +440,8 @@ class Solution { * @return {boolean} */ isSubsequence(s, t) { - let i = 0, j = 0; + let i = 0, + j = 0; while (i < s.length && j < t.length) { if (s.charAt(i) == t.charAt(j)) { i++; @@ -378,12 +453,27 @@ class Solution { } ``` +```csharp +public class Solution { + public bool IsSubsequence(string s, string t) { + int i = 0, j = 0; + while (i < s.Length && j < t.Length) { + if (s[i] == t[j]) { + i++; + } + j++; + } + return i == s.Length; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(1)$ > Where $n$ is the length of the string $s$ and $m$ is the length of the string $t$. @@ -397,21 +487,21 @@ class Solution: n, m = len(s), len(t) if m == 0: return n == 0 - + store = [[m + 1] * 26 for _ in range(m)] store[m - 1][ord(t[m - 1]) - ord('a')] = m - 1 - + for i in range(m - 2, -1, -1): store[i] = store[i + 1][:] store[i][ord(t[i]) - ord('a')] = i - + i, j = 0, 0 while i < n and j < m: j = store[j][ord(s[i]) - ord('a')] + 1 if j > m: return False i += 1 - + return i == n ``` @@ -439,7 +529,7 @@ public class Solution { if (j > m) return false; i++; } - + return i == n; } } @@ -454,7 +544,7 @@ public: vector> store(m, vector(26, m + 1)); store[m - 1][t[m - 1] - 'a'] = m - 1; - + for (int i = m - 2; i >= 0; i--) { store[i] = store[i + 1]; store[i][t[i] - 'a'] = i; @@ -480,7 +570,8 @@ class Solution { * @return {boolean} */ isSubsequence(s, t) { - const n = s.length, m = t.length; + const n = s.length, + m = t.length; if (m === 0) return n === 0; const store = Array.from({ length: m }, () => Array(26).fill(m + 1)); @@ -491,7 +582,8 @@ class Solution { store[i][t.charCodeAt(i) - 'a'.charCodeAt(0)] = i; } - let i = 0, j = 0; + let i = 0, + j = 0; while (i < n && j < m) { j = store[j][s.charCodeAt(i) - 'a'.charCodeAt(0)] + 1; if (j > m) return false; @@ -503,11 +595,45 @@ class Solution { } ``` +```csharp +public class Solution { + public bool IsSubsequence(string s, string t) { + int n = s.Length, m = t.Length; + if (m == 0) return n == 0; + + int[,] store = new int[m, 26]; + for (int i = 0; i < 26; i++) { + for (int j = 0; j < m; j++) { + store[j, i] = m + 1; + } + } + + store[m - 1, t[m - 1] - 'a'] = m - 1; + + for (int i = m - 2; i >= 0; i--) { + for (int c = 0; c < 26; c++) { + store[i, c] = store[i + 1, c]; + } + store[i, t[i] - 'a'] = i; + } + + int iPtr = 0, jPtr = 0; + while (iPtr < n && jPtr < m) { + jPtr = store[jPtr, s[iPtr] - 'a'] + 1; + if (jPtr > m) return false; + iPtr++; + } + + return iPtr == n; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(m)$ -> Where $n$ is the length of the string $s$ and $m$ is the length of the string $t$. \ No newline at end of file +> Where $n$ is the length of the string $s$ and $m$ is the length of the string $t$. diff --git a/articles/island-perimeter.md b/articles/island-perimeter.md index c4bb78ca5..5a29dba4a 100644 --- a/articles/island-perimeter.md +++ b/articles/island-perimeter.md @@ -13,11 +13,11 @@ class Solution: return 1 if (i, j) in visit: return 0 - + visit.add((i, j)) perim = dfs(i, j + 1) + dfs(i + 1, j) + dfs(i, j - 1) + dfs(i - 1, j) return perim - + for i in range(rows): for j in range(cols): if grid[i][j]: @@ -48,7 +48,7 @@ public class Solution { } private int dfs(int i, int j) { - if (i < 0 || j < 0 || i >= rows || + if (i < 0 || j < 0 || i >= rows || j >= cols || grid[i][j] == 0) { return 1; } @@ -57,7 +57,7 @@ public class Solution { } visited[i][j] = true; - return dfs(i, j + 1) + dfs(i + 1, j) + + return dfs(i, j + 1) + dfs(i + 1, j) + dfs(i, j - 1) + dfs(i - 1, j); } } @@ -71,7 +71,7 @@ private: int rows, cols; int dfs(int i, int j) { - if (i < 0 || j < 0 || i >= rows || + if (i < 0 || j < 0 || i >= rows || j >= cols || grid[i][j] == 0) { return 1; } @@ -80,7 +80,7 @@ private: } visited[i][j] = true; - return dfs(i, j + 1) + dfs(i + 1, j) + + return dfs(i, j + 1) + dfs(i + 1, j) + dfs(i, j - 1) + dfs(i - 1, j); } @@ -110,8 +110,11 @@ class Solution { * @return {number} */ islandPerimeter(grid) { - const rows = grid.length, cols = grid[0].length; - const visited = Array.from({ length: rows }, () => Array(cols).fill(false)); + const rows = grid.length, + cols = grid[0].length; + const visited = Array.from({ length: rows }, () => + Array(cols).fill(false), + ); const dfs = (i, j) => { if (i < 0 || j < 0 || i >= rows || j >= cols || grid[i][j] === 0) { @@ -122,8 +125,9 @@ class Solution { } visited[i][j] = true; - return dfs(i, j + 1) + dfs(i + 1, j) + - dfs(i, j - 1) + dfs(i - 1, j); + return ( + dfs(i, j + 1) + dfs(i + 1, j) + dfs(i, j - 1) + dfs(i - 1, j) + ); }; for (let i = 0; i < rows; i++) { @@ -138,12 +142,48 @@ class Solution { } ``` +```csharp +public class Solution { + private int rows, cols; + private HashSet<(int, int)> visit; + + public int IslandPerimeter(int[][] grid) { + rows = grid.Length; + cols = grid[0].Length; + visit = new HashSet<(int, int)>(); + + int Dfs(int i, int j) { + if (i < 0 || j < 0 || i >= rows || j >= cols || grid[i][j] == 0) { + return 1; + } + if (visit.Contains((i, j))) { + return 0; + } + + visit.Add((i, j)); + int perim = Dfs(i, j + 1) + Dfs(i + 1, j) + Dfs(i, j - 1) + Dfs(i - 1, j); + return perim; + } + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (grid[i][j] == 1) { + return Dfs(i, j); + } + } + } + + return 0; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns in the grid. @@ -159,17 +199,17 @@ class Solution: rows, cols = len(grid), len(grid[0]) visited = set() directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] - + def bfs(r, c): queue = deque([(r, c)]) visited.add((r, c)) perimeter = 0 - + while queue: x, y = queue.popleft() for dx, dy in directions: nx, ny = x + dx, y + dy - if (nx < 0 or ny < 0 or nx >= rows or + if (nx < 0 or ny < 0 or nx >= rows or ny >= cols or grid[nx][ny] == 0 ): perimeter += 1 @@ -177,7 +217,7 @@ class Solution: visited.add((nx, ny)) queue.append((nx, ny)) return perimeter - + for i in range(rows): for j in range(cols): if grid[i][j] == 1: @@ -191,7 +231,7 @@ public class Solution { int rows = grid.length, cols = grid[0].length; boolean[][] visited = new boolean[rows][cols]; int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; - + for (int i = 0; i < rows; i++) { for (int j = 0; j < cols; j++) { if (grid[i][j] == 1) { @@ -199,14 +239,14 @@ public class Solution { queue.offer(new int[]{i, j}); visited[i][j] = true; int perimeter = 0; - + while (!queue.isEmpty()) { int[] cell = queue.poll(); int x = cell[0], y = cell[1]; - + for (int[] dir : directions) { int nx = x + dir[0], ny = y + dir[1]; - if (nx < 0 || ny < 0 || nx >= rows || + if (nx < 0 || ny < 0 || nx >= rows || ny >= cols || grid[nx][ny] == 0) { perimeter++; } else if (!visited[nx][ny]) { @@ -246,7 +286,7 @@ public: for (auto& dir : directions) { int nx = x + dir[0], ny = y + dir[1]; - if (nx < 0 || ny < 0 || nx >= rows || + if (nx < 0 || ny < 0 || nx >= rows || ny >= cols || grid[nx][ny] == 0) { perimeter++; } else if (!visited[nx][ny]) { @@ -271,10 +311,18 @@ class Solution { * @return {number} */ islandPerimeter(grid) { - const rows = grid.length, cols = grid[0].length; - const visited = Array.from({ length: rows }, () => Array(cols).fill(false)); - const directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]; - + const rows = grid.length, + cols = grid[0].length; + const visited = Array.from({ length: rows }, () => + Array(cols).fill(false), + ); + const directions = [ + [0, 1], + [1, 0], + [0, -1], + [-1, 0], + ]; + const bfs = (r, c) => { const queue = new Queue([[r, c]]); visited[r][c] = true; @@ -283,10 +331,16 @@ class Solution { const [x, y] = queue.pop(); for (const [dx, dy] of directions) { - const nx = x + dx, ny = y + dy; - - if (nx < 0 || ny < 0 || nx >= rows || - ny >= cols || grid[nx][ny] === 0) { + const nx = x + dx, + ny = y + dy; + + if ( + nx < 0 || + ny < 0 || + nx >= rows || + ny >= cols || + grid[nx][ny] === 0 + ) { perimeter++; } else if (!visited[nx][ny]) { visited[nx][ny] = true; @@ -309,12 +363,62 @@ class Solution { } ``` +```csharp +public class Solution { + public int IslandPerimeter(int[][] grid) { + int rows = grid.Length; + int cols = grid[0].Length; + var visited = new HashSet<(int, int)>(); + int[][] directions = new int[][] { + new int[] { 0, 1 }, + new int[] { 1, 0 }, + new int[] { 0, -1 }, + new int[] { -1, 0 } + }; + + int Bfs(int r, int c) { + var queue = new Queue<(int, int)>(); + queue.Enqueue((r, c)); + visited.Add((r, c)); + int perimeter = 0; + + while (queue.Count > 0) { + var (x, y) = queue.Dequeue(); + foreach (var dir in directions) { + int nx = x + dir[0]; + int ny = y + dir[1]; + + if (nx < 0 || ny < 0 || nx >= rows || ny >= cols || grid[nx][ny] == 0) { + perimeter++; + } else if (!visited.Contains((nx, ny))) { + visited.Add((nx, ny)); + queue.Enqueue((nx, ny)); + } + } + } + + return perimeter; + } + + for (int i = 0; i < rows; i++) { + for (int j = 0; j < cols; j++) { + if (grid[i][j] == 1) { + return Bfs(i, j); + } + } + } + + return 0; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns in the grid. @@ -384,18 +488,42 @@ class Solution { * @return {number} */ islandPerimeter(grid) { - const m = grid.length, n = grid[0].length; + const m = grid.length, + n = grid[0].length; let res = 0; for (let i = 0; i < m; i++) { for (let j = 0; j < n; j++) { if (grid[i][j] === 1) { - res += (i + 1 >= m || grid[i + 1][j] === 0) ? 1 : 0; - res += (j + 1 >= n || grid[i][j + 1] === 0) ? 1 : 0; - res += (i - 1 < 0 || grid[i - 1][j] === 0) ? 1 : 0; - res += (j - 1 < 0 || grid[i][j - 1] === 0) ? 1 : 0; + res += i + 1 >= m || grid[i + 1][j] === 0 ? 1 : 0; + res += j + 1 >= n || grid[i][j + 1] === 0 ? 1 : 0; + res += i - 1 < 0 || grid[i - 1][j] === 0 ? 1 : 0; + res += j - 1 < 0 || grid[i][j - 1] === 0 ? 1 : 0; + } + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public int IslandPerimeter(int[][] grid) { + int m = grid.Length; + int n = grid[0].Length; + int res = 0; + + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + if (grid[i][j] == 1) { + if (i + 1 >= m || grid[i + 1][j] == 0) res++; + if (j + 1 >= n || grid[i][j + 1] == 0) res++; + if (i - 1 < 0 || grid[i - 1][j] == 0) res++; + if (j - 1 < 0 || grid[i][j - 1] == 0) res++; } } } + return res; } } @@ -405,8 +533,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(m * n)$ +- Space complexity: $O(1)$ extra space. > Where $m$ is the number of rows and $n$ is the number of columns in the grid. @@ -486,7 +614,8 @@ class Solution { * @return {number} */ islandPerimeter(grid) { - const m = grid.length, n = grid[0].length; + const m = grid.length, + n = grid[0].length; let res = 0; for (let r = 0; r < m; r++) { for (let c = 0; c < n; c++) { @@ -506,11 +635,37 @@ class Solution { } ``` +```csharp +public class Solution { + public int IslandPerimeter(int[][] grid) { + int m = grid.Length; + int n = grid[0].Length; + int res = 0; + + for (int r = 0; r < m; r++) { + for (int c = 0; c < n; c++) { + if (grid[r][c] == 1) { + res += 4; + if (r > 0 && grid[r - 1][c] == 1) { + res -= 2; + } + if (c > 0 && grid[r][c - 1] == 1) { + res -= 2; + } + } + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(m * n)$ +- Space complexity: $O(1)$ extra space. -> Where $m$ is the number of rows and $n$ is the number of columns in the grid. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns in the grid. diff --git a/articles/islands-and-treasure.md b/articles/islands-and-treasure.md index ff99ef107..2e4ad2806 100644 --- a/articles/islands-and-treasure.md +++ b/articles/islands-and-treasure.md @@ -33,14 +33,14 @@ class Solution: ```java public class Solution { - private int[][] directions = {{1, 0}, {-1, 0}, + private int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; private int INF = 2147483647; private boolean[][] visit; private int ROWS, COLS; private int dfs(int[][] grid, int r, int c) { - if (r < 0 || c < 0 || r >= ROWS || + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == -1 || visit[r][c]) { return INF; } @@ -78,14 +78,14 @@ public class Solution { ```cpp class Solution { public: - vector> directions = {{1, 0}, {-1, 0}, + vector> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; int INF = 2147483647; vector> visit; int ROWS, COLS; int dfs(vector>& grid, int r, int c) { - if (r < 0 || c < 0 || r >= ROWS || + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == -1 || visit[r][c]) { return INF; } @@ -129,14 +129,24 @@ class Solution { islandsAndTreasure(grid) { let ROWS = grid.length; let COLS = grid[0].length; - const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; + const directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; const INF = 2147483647; - let visit = Array.from({ length: ROWS }, () => - Array(COLS).fill(false)); + let visit = Array.from({ length: ROWS }, () => Array(COLS).fill(false)); const dfs = (r, c) => { - if (r < 0 || c < 0 || r >= ROWS || - c >= COLS || grid[r][c] === -1 || visit[r][c]) { + if ( + r < 0 || + c < 0 || + r >= ROWS || + c >= COLS || + grid[r][c] === -1 || + visit[r][c] + ) { return INF; } if (grid[r][c] === 0) { @@ -165,7 +175,7 @@ class Solution { ```csharp public class Solution { private int[][] directions = new int[][] { - new int[] {1, 0}, new int[] {-1, 0}, + new int[] {1, 0}, new int[] {-1, 0}, new int[] {0, 1}, new int[] {0, -1} }; private int INF = 2147483647; @@ -173,7 +183,7 @@ public class Solution { private int ROWS, COLS; private int Dfs(int[][] grid, int r, int c) { - if (r < 0 || c < 0 || r >= ROWS || + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == -1 || visit[r, c]) { return INF; } @@ -220,7 +230,7 @@ func islandsAndTreasure(grid [][]int) { var dfs func(r, c int) int dfs = func(r, c int) int { - if r < 0 || c < 0 || r >= rows || c >= cols || + if r < 0 || c < 0 || r >= rows || c >= cols || grid[r][c] == -1 || visit[r][c] { return INF } @@ -267,7 +277,7 @@ class Solution { private var cols = 0 private fun dfs(grid: Array, r: Int, c: Int): Int { - if (r < 0 || c < 0 || r >= rows || c >= cols || + if (r < 0 || c < 0 || r >= rows || c >= cols || grid[r][c] == -1 || visit[r][c]) { return INF } @@ -302,12 +312,49 @@ class Solution { } ``` +```swift +class Solution { + func islandsAndTreasure(_ grid: inout [[Int]]) { + let ROWS = grid.count + let COLS = grid[0].count + let INF = 2147483647 + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + var visit = Array(repeating: Array(repeating: false, count: COLS), count: ROWS) + + func dfs(_ r: Int, _ c: Int) -> Int { + if r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == -1 || visit[r][c] { + return INF + } + if grid[r][c] == 0 { + return 0 + } + + visit[r][c] = true + var res = INF + for (dx, dy) in directions { + res = min(res, 1 + dfs(r + dx, c + dy)) + } + visit[r][c] = false + return res + } + + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. @@ -336,7 +383,7 @@ class Solution: return steps for dr, dc in directions: nr, nc = row + dr, col + dc - if (0 <= nr < ROWS and 0 <= nc < COLS and + if (0 <= nr < ROWS and 0 <= nc < COLS and not visit[nr][nc] and grid[nr][nc] != -1 ): visit[nr][nc] = True @@ -352,7 +399,7 @@ class Solution: ```java public class Solution { - private int[][] directions = {{1, 0}, {-1, 0}, + private int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; private int INF = 2147483647; private int ROWS, COLS; @@ -372,7 +419,7 @@ public class Solution { if (grid[row][col] == 0) return steps; for (int[] dir : directions) { int nr = row + dir[0], nc = col + dir[1]; - if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && !visit[nr][nc] && grid[nr][nc] != -1) { visit[nr][nc] = true; q.add(new int[]{nr, nc}); @@ -403,7 +450,7 @@ public class Solution { class Solution { public: int ROWS, COLS; - vector> directions = {{1, 0}, {-1, 0}, + vector> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; int INF = INT_MAX; @@ -422,7 +469,7 @@ public: if (grid[row][col] == 0) return steps; for (auto& dir : directions) { int nr = row + dir[0], nc = col + dir[1]; - if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && !visit[nr][nc] && grid[nr][nc] != -1) { visit[nr][nc] = true; q.push({nr, nc}); @@ -458,15 +505,20 @@ class Solution { islandsAndTreasure(grid) { let ROWS = grid.length; let COLS = grid[0].length; - const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; + const directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; const INF = 2147483647; - let visit = Array.from({ length: ROWS }, () => - Array(COLS).fill(false)); + let visit = Array.from({ length: ROWS }, () => Array(COLS).fill(false)); const bfs = (r, c) => { const q = new Queue([[r, c]]); - const visit = Array.from({ length: ROWS }, () => - Array(COLS).fill(false)); + const visit = Array.from({ length: ROWS }, () => + Array(COLS).fill(false), + ); visit[r][c] = true; let steps = 0; @@ -476,9 +528,16 @@ class Solution { const [row, col] = q.pop(); if (grid[row][col] === 0) return steps; for (let [dr, dc] of directions) { - const nr = row + dr, nc = col + dc; - if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && - !visit[nr][nc] && grid[nr][nc] !== -1) { + const nr = row + dr, + nc = col + dc; + if ( + nr >= 0 && + nr < ROWS && + nc >= 0 && + nc < COLS && + !visit[nr][nc] && + grid[nr][nc] !== -1 + ) { visit[nr][nc] = true; q.push([nr, nc]); } @@ -525,7 +584,7 @@ public class Solution { if (grid[row][col] == 0) return steps; foreach (var dir in directions) { int nr = row + dir[0], nc = col + dir[1]; - if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && !visit[nr][nc] && grid[nr][nc] != -1) { visit[nr][nc] = true; q.Enqueue(new int[] { nr, nc }); @@ -578,7 +637,7 @@ func islandsAndTreasure(grid [][]int) { } for _, dir := range directions { nr, nc := row+dir[0], col+dir[1] - if nr >= 0 && nc >= 0 && nr < rows && nc < cols && + if nr >= 0 && nc >= 0 && nr < rows && nc < cols && !visit[nr][nc] && grid[nr][nc] != -1 { visit[nr][nc] = true q = append(q, [2]int{nr, nc}) @@ -603,7 +662,7 @@ func islandsAndTreasure(grid [][]int) { ```kotlin class Solution { private val directions = arrayOf( - intArrayOf(1, 0), intArrayOf(-1, 0), + intArrayOf(1, 0), intArrayOf(-1, 0), intArrayOf(0, 1), intArrayOf(0, -1) ) private val INF = 2147483647 @@ -628,7 +687,7 @@ class Solution { for (dir in directions) { val nr = row + dir[0] val nc = col + dir[1] - if (nr in 0 until rows && nc in 0 until cols && + if (nr in 0 until rows && nc in 0 until cols && !visit[nr][nc] && grid[nr][nc] != -1) { visit[nr][nc] = true q.add(Pair(nr, nc)) @@ -651,12 +710,58 @@ class Solution { } ``` +```swift +class Solution { + func islandsAndTreasure(_ grid: inout [[Int]]) { + let ROWS = grid.count + let COLS = grid[0].count + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + let INF = 2147483647 + + func bfs(_ r: Int, _ c: Int) -> Int { + var q = Deque<(Int, Int)>() + q.append((r, c)) + var visit = Array(repeating: Array(repeating: false, count: COLS), count: ROWS) + visit[r][c] = true + var steps = 0 + while !q.isEmpty { + let levelCount = q.count + for _ in 0..= 0 && nr < ROWS && nc >= 0 && nc < COLS && + !visit[nr][nc] && grid[nr][nc] != -1) { + visit[nr][nc] = true + q.append((nr, nc)) + } + } + } + steps += 1 + } + return INF + } + + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. @@ -714,7 +819,7 @@ public class Solution { } if (q.size() == 0) return; - int[][] dirs = { { -1, 0 }, { 0, -1 }, + int[][] dirs = { { -1, 0 }, { 0, -1 }, { 1, 0 }, { 0, 1 } }; while (!q.isEmpty()) { int[] node = q.poll(); @@ -742,7 +847,7 @@ public: void islandsAndTreasure(vector>& grid) { int m = grid.size(); int n = grid[0].size(); - + queue> q; for (int i = 0; i < m; i++) { for (int j = 0; j < n; j++) { @@ -751,23 +856,23 @@ public: } } } - - vector> dirs = {{-1, 0}, {1, 0}, + + vector> dirs = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; while (!q.empty()) { int row = q.front().first; int col = q.front().second; q.pop(); - + for (int i = 0; i < 4; i++) { int r = row + dirs[i][0]; int c = col + dirs[i][1]; - - if (r < 0 || r >= m || c < 0 || + + if (r < 0 || r >= m || c < 0 || c >= n || grid[r][c] != INT_MAX) { continue; } - + grid[r][c] = grid[row][col] + 1; q.push({r, c}); } @@ -792,8 +897,12 @@ class Solution { * @param {number} c */ function addCell(r, c) { - if (Math.min(r, c) < 0 || r === ROWS || c === COLS || - visit.has(r + ',' + c) || grid[r][c] === -1 + if ( + Math.min(r, c) < 0 || + r === ROWS || + c === COLS || + visit.has(r + ',' + c) || + grid[r][c] === -1 ) { return; } @@ -839,10 +948,10 @@ public class Solution { } if (q.Count == 0) return; - - int[][] dirs = { - new int[] { -1, 0 }, new int[] { 0, -1 }, - new int[] { 1, 0 }, new int[] { 0, 1 } + + int[][] dirs = { + new int[] { -1, 0 }, new int[] { 0, -1 }, + new int[] { 1, 0 }, new int[] { 0, 1 } }; while (q.Count > 0) { int[] cur = q.Dequeue(); @@ -853,7 +962,7 @@ public class Solution { int c = col + dir[1]; if (r >= m || c >= n || r < 0 || c < 0 || grid[r][c] != int.MaxValue) { - continue; + continue; } q.Enqueue(new int[] { r, c }); @@ -889,7 +998,7 @@ func islandsAndTreasure(grid [][]int) { for _, dir := range dirs { r, c := row+dir[0], col+dir[1] - if r >= m || c >= n || r < 0 || c < 0 || + if r >= m || c >= n || r < 0 || c < 0 || grid[r][c] != 2147483647 { continue } @@ -917,7 +1026,7 @@ class Solution { if (q.isEmpty()) return val dirs = arrayOf( - intArrayOf(-1, 0), intArrayOf(0, -1), + intArrayOf(-1, 0), intArrayOf(0, -1), intArrayOf(1, 0), intArrayOf(0, 1) ) @@ -926,7 +1035,7 @@ class Solution { for (dir in dirs) { val r = row + dir[0] val c = col + dir[1] - if (r !in 0 until m || c !in 0 until n || + if (r !in 0 until m || c !in 0 until n || grid[r][c] != Int.MAX_VALUE) { continue } @@ -938,11 +1047,60 @@ class Solution { } ``` +```swift +struct Item: Hashable { + let r: Int + let c: Int +} + +class Solution { + func islandsAndTreasure(_ grid: inout [[Int]]) { + let ROWS = grid.count + let COLS = grid[0].count + var visit = Set() + var q = Deque() + + func addCell(_ r: Int, _ c: Int) { + if r < 0 || c < 0 || r >= ROWS || c >= COLS { return } + let item = Item(r: r, c: c) + if visit.contains(item) || grid[r][c] == -1 { return } + visit.insert(item) + q.append(item) + } + + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. diff --git a/articles/isomorphic-strings.md b/articles/isomorphic-strings.md index afbaa6c10..b65759396 100644 --- a/articles/isomorphic-strings.md +++ b/articles/isomorphic-strings.md @@ -91,8 +91,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n)$ +- Space complexity: $O(m)$ > Where $n$ is the length of the input string and $m$ is the number of unique characters in the strings. @@ -114,7 +114,7 @@ class Solution: return False mapST[c1] = c2 mapTS[c2] = c1 - + return True ``` @@ -135,7 +135,7 @@ public class Solution { mapST.put(c1, c2); mapTS.put(c2, c1); } - + return true; } } @@ -158,7 +158,7 @@ public: mapST[c1] = c2; mapTS[c2] = c1; } - + return true; } }; @@ -175,10 +175,13 @@ class Solution { const mapTS = new Map(); for (let i = 0; i < s.length; i++) { - const c1 = s[i], c2 = t[i]; + const c1 = s[i], + c2 = t[i]; - if ((mapST.has(c1) && mapST.get(c1) !== c2) || - (mapTS.has(c2) && mapTS.get(c2) !== c1)) { + if ( + (mapST.has(c1) && mapST.get(c1) !== c2) || + (mapTS.has(c2) && mapTS.get(c2) !== c1) + ) { return false; } @@ -195,7 +198,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n)$ +- Space complexity: $O(m)$ -> Where $n$ is the length of the input string and $m$ is the number of unique characters in the strings. \ No newline at end of file +> Where $n$ is the length of the input string and $m$ is the number of unique characters in the strings. diff --git a/articles/jump-game-ii.md b/articles/jump-game-ii.md index 44e309136..2a9738d34 100644 --- a/articles/jump-game-ii.md +++ b/articles/jump-game-ii.md @@ -55,12 +55,16 @@ private: if (i == nums.size() - 1) { return 0; } - if (nums[i] == 0) return 1000000; + if (nums[i] == 0) { + return 1000000; + } + int res = 1000000; int end = min((int)nums.size() - 1, i + nums[i]); for (int j = i + 1; j <= end; ++j) { res = min(res, 1 + dfs(nums, j)); } + return res; } }; @@ -84,7 +88,7 @@ class Solution { res = Math.min(res, 1 + dfs(j)); } return res; - } + }; return dfs(0); } @@ -162,12 +166,37 @@ class Solution { } ``` +```swift +class Solution { + func jump(_ nums: [Int]) -> Int { + func dfs(_ i: Int) -> Int { + if i == nums.count - 1 { + return 0 + } + if nums[i] == 0 { + return 1000000 + } + + let end = min(nums.count - 1, i + nums[i]) + var res = 1000000 + for j in i + 1..<(end + 1) { + res = min(res, 1 + dfs(j)) + } + + return res + } + + return dfs(0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n!)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n!)$ +- Space complexity: $O(n)$ --- @@ -187,7 +216,7 @@ class Solution: return 0 if nums[i] == 0: return 1000000 - + res = 1000000 end = min(len(nums), i + nums[i] + 1) for j in range(i + 1, end): @@ -215,7 +244,7 @@ public class Solution { if (nums[i] == 0) { return 1000000; } - + int res = 1000000; int end = Math.min(nums.length, i + nums[i] + 1); for (int j = i + 1; j < end; j++) { @@ -246,7 +275,7 @@ private: if (nums[i] == 0) { return 1000000; } - + int res = 1000000; int end = min((int)nums.size(), i + nums[i] + 1); for (int j = i + 1; j < end; j++) { @@ -283,7 +312,7 @@ class Solution { } memo.set(i, res); return res; - } + }; return dfs(0); } @@ -307,7 +336,7 @@ public class Solution { if (nums[i] == 0) { return 1000000; } - + int res = 1000000; int end = Math.Min(nums.Length, i + nums[i] + 1); for (int j = i + 1; j < end; j++) { @@ -382,12 +411,43 @@ class Solution { } ``` +```swift +class Solution { + var memo: [Int: Int] = [:] + + func jump(_ nums: [Int]) -> Int { + return dfs(nums, 0) + } + + private func dfs(_ nums: [Int], _ i: Int) -> Int { + if let cachedResult = memo[i] { + return cachedResult + } + if i == nums.count - 1 { + return 0 + } + if nums[i] == 0 { + return 1000000 + } + + var res = 1000000 + let end = min(nums.count, i + nums[i] + 1) + for j in i + 1.. Int { + let n = nums.count + var dp = Array(repeating: 1000000, count: n) + dp[n - 1] = 0 + + for i in stride(from: n - 2, through: 0, by: -1) { + let end = min(n, i + nums[i] + 1) + for j in i + 1.. Int { + var res = 0 + var l = 0 + var r = 0 + + while r < nums.count - 1 { + var farthest = 0 + for i in l...r { + farthest = max(farthest, i + nums[i]) + } + l = r + 1 + r = farthest + res += 1 + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/jump-game-vii.md b/articles/jump-game-vii.md index d2be241f9..b034aa727 100644 --- a/articles/jump-game-vii.md +++ b/articles/jump-game-vii.md @@ -64,12 +64,12 @@ public class Solution { class Solution { public: int n; - vector> dp; + vector dp; bool canReach(string s, int minJump, int maxJump) { this->n = s.size(); - dp.resize(n, nullopt); - dp[n - 1] = true; + dp.resize(n, -1); + dp[n - 1] = 1; if (s[n - 1] == '1') { return false; @@ -80,18 +80,18 @@ public: private: bool dfs(int i, string& s, int& minJump, int& maxJump) { - if (dp[i].has_value()) { - return dp[i].value(); + if (dp[i] != -1) { + return dp[i]; } - dp[i] = false; + dp[i] = 0; for (int j = i + minJump; j <= min(n - 1, i + maxJump); ++j) { if (s[j] == '0' && dfs(j, s, minJump, maxJump)) { - dp[i] = true; + dp[i] = 1; break; } } - return dp[i].value(); + return dp[i]; } }; ``` @@ -132,12 +132,44 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanReach(string s, int minJump, int maxJump) { + int n = s.Length; + bool?[] dp = new bool?[n]; + dp[n - 1] = true; + + bool Dfs(int i) { + if (dp[i].HasValue) { + return dp[i].Value; + } + + dp[i] = false; + for (int j = i + minJump; j <= Math.Min(n - 1, i + maxJump); j++) { + if (s[j] == '0' && Dfs(j)) { + dp[i] = true; + break; + } + } + + return dp[i].Value; + } + + if (s[n - 1] == '1') { + return false; + } + + return Dfs(0); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n)$ > Where $n$ is the length of the string $s$ and $m$ is the given range of the jump $(maxJump - minJump + 1)$. @@ -152,7 +184,7 @@ class Solution: def canReach(self, s: str, minJump: int, maxJump: int) -> bool: q = deque([0]) farthest = 0 - + while q: i = q.popleft() start = max(i + minJump, farthest + 1) @@ -162,7 +194,7 @@ class Solution: if j == len(s) - 1: return True farthest = i + maxJump - + return False ``` @@ -188,7 +220,7 @@ public class Solution { } farthest = i + maxJump; } - + return false; } } @@ -218,7 +250,7 @@ public: } farthest = i + maxJump; } - + return false; } }; @@ -257,12 +289,37 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanReach(string s, int minJump, int maxJump) { + int n = s.Length; + Queue q = new Queue(); + q.Enqueue(0); + int farthest = 0; + + while (q.Count > 0) { + int i = q.Dequeue(); + int start = Math.Max(i + minJump, farthest + 1); + for (int j = start; j <= Math.Min(i + maxJump, n - 1); j++) { + if (s[j] == '0') { + if (j == n - 1) return true; + q.Enqueue(j); + } + } + farthest = i + maxJump; + } + + return false; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -276,7 +333,7 @@ class Solution: n = len(s) if s[n - 1] == '1': return False - + dp = [False] * n dp[0] = True cnt = 0 @@ -287,7 +344,7 @@ class Solution: cnt -= 1 if cnt > 0 and s[i] == '0': dp[i] = True - + return dp[n - 1] ``` @@ -385,12 +442,41 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanReach(string s, int minJump, int maxJump) { + int n = s.Length; + if (s[n - 1] == '1') { + return false; + } + + bool[] dp = new bool[n]; + dp[0] = true; + int cnt = 0; + + for (int i = 1; i < n; i++) { + if (i >= minJump && dp[i - minJump]) { + cnt++; + } + if (i > maxJump && dp[i - maxJump - 1]) { + cnt--; + } + if (cnt > 0 && s[i] == '0') { + dp[i] = true; + } + } + + return dp[n - 1]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -404,7 +490,7 @@ class Solution: n = len(s) if s[n - 1] == '1': return False - + dp = [False] * n dp[0] = True j = 0 @@ -417,7 +503,7 @@ class Solution: if s[j] == '0': dp[j] = True j += 1 - + return dp[n - 1] ``` @@ -518,9 +604,38 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanReach(string s, int minJump, int maxJump) { + int n = s.Length; + if (s[n - 1] == '1') { + return false; + } + + bool[] dp = new bool[n]; + dp[0] = true; + int j = 0; + + for (int i = 0; i < n; i++) { + if (!dp[i]) continue; + + j = Math.Max(j, i + minJump); + while (j <= Math.Min(i + maxJump, n - 1)) { + if (s[j] == '0') { + dp[j] = true; + } + j++; + } + } + + return dp[n - 1]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/jump-game.md b/articles/jump-game.md index 850539bca..7ed6d6111 100644 --- a/articles/jump-game.md +++ b/articles/jump-game.md @@ -22,7 +22,7 @@ public class Solution { public boolean canJump(int[] nums) { return dfs(nums, 0); } - + private boolean dfs(int[] nums, int i) { if (i == nums.length - 1) { return true; @@ -79,7 +79,7 @@ class Solution { } } return false; - } + }; return dfs(0); } @@ -114,7 +114,7 @@ func canJump(nums []int) bool { if i == len(nums)-1 { return true } - + end := min(len(nums)-1, i+nums[i]) for j := i + 1; j <= end; j++ { if dfs(j) { @@ -123,7 +123,7 @@ func canJump(nums []int) bool { } return false } - + return dfs(0) } @@ -142,7 +142,7 @@ class Solution { if (i == nums.size - 1) { return true } - + val end = minOf(nums.size - 1, i + nums[i]) for (j in (i + 1)..end) { if (dfs(j)) { @@ -151,7 +151,30 @@ class Solution { } return false } - + + return dfs(0) + } +} +``` + +```swift +class Solution { + func canJump(_ nums: [Int]) -> Bool { + + func dfs(_ i: Int) -> Bool { + if i == nums.count - 1 { + return true + } + + let end = min(nums.count - 1, i + nums[i]) + for j in i + 1..<(end + 1) { + if dfs(j) { + return true + } + } + return false + } + return dfs(0) } } @@ -161,8 +184,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n!)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n!)$ +- Space complexity: $O(n)$ --- @@ -182,7 +205,7 @@ class Solution: return True if nums[i] == 0: return False - + end = min(len(nums), i + nums[i] + 1) for j in range(i + 1, end): if dfs(j): @@ -211,7 +234,7 @@ public class Solution { if (nums[i] == 0) { return false; } - + int end = Math.min(nums.length, i + nums[i] + 1); for (int j = i + 1; j < end; j++) { if (dfs(nums, j, memo)) { @@ -244,7 +267,7 @@ private: if (nums[i] == 0) { return false; } - + int end = min((int)nums.size(), i + nums[i] + 1); for (int j = i + 1; j < end; j++) { if (dfs(nums, j, memo)) { @@ -285,7 +308,7 @@ class Solution { } memo.set(i, false); return false; - } + }; return dfs(0); } @@ -309,7 +332,7 @@ public class Solution { if (nums[i] == 0) { return false; } - + int end = Math.Min(nums.Length, i + nums[i] + 1); for (int j = i + 1; j < end; j++) { if (Dfs(nums, j, memo)) { @@ -326,13 +349,13 @@ public class Solution { ```go func canJump(nums []int) bool { memo := make(map[int]bool) - + var dfs func(i int) bool dfs = func(i int) bool { if result, exists := memo[i]; exists { return result } - + if i == len(nums)-1 { return true } @@ -340,7 +363,7 @@ func canJump(nums []int) bool { memo[i] = false return false } - + end := min(len(nums), i+nums[i]+1) for j := i + 1; j < end; j++ { if dfs(j) { @@ -348,11 +371,11 @@ func canJump(nums []int) bool { return true } } - + memo[i] = false return false } - + return dfs(0) } @@ -368,10 +391,10 @@ func min(a, b int) int { class Solution { fun canJump(nums: IntArray): Boolean { val memo = HashMap() - + fun dfs(i: Int): Boolean { memo[i]?.let { return it } - + if (i == nums.size - 1) { return true } @@ -379,7 +402,7 @@ class Solution { memo[i] = false return false } - + val end = minOf(nums.size, i + nums[i] + 1) for (j in (i + 1) until end) { if (dfs(j)) { @@ -387,11 +410,44 @@ class Solution { return true } } - + memo[i] = false return false } - + + return dfs(0) + } +} +``` + +```swift +class Solution { + func canJump(_ nums: [Int]) -> Bool { + var memo: [Int: Bool] = [:] + + func dfs(_ i: Int) -> Bool { + if let cachedResult = memo[i] { + return cachedResult + } + if i == nums.count - 1 { + return true + } + if nums[i] == 0 { + return false + } + + let end = min(nums.count, i + nums[i] + 1) + for j in i + 1..= 0; i-- { end := min(n, i + nums[i] + 1) for j := i + 1; j < end; j++ { @@ -547,7 +603,7 @@ class Solution { val n = nums.size val dp = BooleanArray(n) dp[n - 1] = true - + for (i in n - 2 downTo 0) { val end = minOf(n, i + nums[i] + 1) for (j in i + 1 until end) { @@ -562,12 +618,33 @@ class Solution { } ``` +```swift +class Solution { + func canJump(_ nums: [Int]) -> Bool { + let n = nums.count + var dp = [Bool](repeating: false, count: n) + dp[n - 1] = true + + for i in (0..= 0; i-- { if i + nums[i] >= goal { goal = i @@ -672,7 +749,7 @@ func canJump(nums []int) bool { class Solution { fun canJump(nums: IntArray): Boolean { var goal = nums.size - 1 - + for (i in nums.size - 2 downTo 0) { if (i + nums[i] >= goal) { goal = i @@ -683,9 +760,25 @@ class Solution { } ``` +```swift +class Solution { + func canJump(_ nums: [Int]) -> Bool { + var goal = nums.count - 1 + + for i in stride(from: nums.count - 2, through: 0, by: -1) { + if i + nums[i] >= goal { + goal = i + } + } + + return goal == 0 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/k-closest-points-to-origin.md b/articles/k-closest-points-to-origin.md index 823a5a33f..950ee2098 100644 --- a/articles/k-closest-points-to-origin.md +++ b/articles/k-closest-points-to-origin.md @@ -12,7 +12,7 @@ class Solution: ```java public class Solution { public int[][] kClosest(int[][] points, int k) { - Arrays.sort(points, (a, b) -> (a[0] * a[0] + a[1] * a[1]) - + Arrays.sort(points, (a, b) -> (a[0] * a[0] + a[1] * a[1]) - (b[0] * b[0] + b[1] * b[1])); return Arrays.copyOfRange(points, 0, k); } @@ -39,8 +39,7 @@ class Solution { * @return {number[][]} */ kClosest(points, k) { - points.sort((a, b) => (a[0] ** 2 + a[1] ** 2) - - (b[0] ** 2 + b[1] ** 2)); + points.sort((a, b) => a[0] ** 2 + a[1] ** 2 - (b[0] ** 2 + b[1] ** 2)); return points.slice(0, k); } } @@ -49,7 +48,7 @@ class Solution { ```csharp public class Solution { public int[][] KClosest(int[][] points, int k) { - Array.Sort(points, (a, b) => + Array.Sort(points, (a, b) => (a[0] * a[0] + a[1] * a[1]).CompareTo(b[0] * b[0] + b[1] * b[1])); return points[..k]; } @@ -59,7 +58,7 @@ public class Solution { ```go func kClosest(points [][]int, k int) [][]int { sort.Slice(points, func(i, j int) bool { - return points[i][0]*points[i][0] + points[i][1]*points[i][1] < + return points[i][0]*points[i][0] + points[i][1]*points[i][1] < points[j][0]*points[j][0] + points[j][1]*points[j][1] }) return points[:k] @@ -75,16 +74,26 @@ class Solution { } ``` +```swift +class Solution { + func kClosest(_ points: [[Int]], _ k: Int) -> [[Int]] { + return points.sorted { ($0[0] * $0[0] + $0[1] * $0[1]) < ($1[0] * $1[0] + $1[1] * $1[1]) } + .prefix(k) + .map { $0 } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- -## 2. Min Heap +## 2. Min-Heap ::tabs-start @@ -95,14 +104,14 @@ class Solution: for x, y in points: dist = (x ** 2) + (y ** 2) minHeap.append([dist, x, y]) - + heapq.heapify(minHeap) res = [] while k > 0: dist, x, y = heapq.heappop(minHeap) res.append([x, y]) k -= 1 - + return res ``` @@ -132,7 +141,7 @@ public: auto comp = [](const vector& a, const vector& b) { return a[0]*a[0] + a[1]*a[1] > b[0]*b[0] + b[1]*b[1]; }; - + priority_queue, vector>, decltype(comp)> minHeap(comp); for (const auto& point : points) { @@ -161,7 +170,7 @@ class Solution { * @return {number[][]} */ kClosest(points, k) { - const minHeap = new MinPriorityQueue(point => point[0]); + const minHeap = new MinPriorityQueue((point) => point[0]); for (const [x, y] of points) { const dist = x ** 2 + y ** 2; @@ -242,12 +251,45 @@ class Solution { } ``` +```swift +struct Item: Comparable { + let dist: Int + let x: Int + let y: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.dist < rhs.dist + } +} + +class Solution { + func kClosest(_ points: [[Int]], _ k: Int) -> [[Int]] { + var minHeap = Heap() + + for point in points { + let x = point[0], y = point[1] + let dist = x * x + y * y + minHeap.insert(Item(dist: dist, x: x, y: y)) + } + + var res = [[Int]]() + for _ in 0.. Where $n$ is the length of the array $points$. @@ -266,7 +308,7 @@ class Solution: heapq.heappush(maxHeap, [dist, x, y]) if len(maxHeap) > k: heapq.heappop(maxHeap) - + res = [] while maxHeap: dist, x, y = heapq.heappop(maxHeap) @@ -278,7 +320,7 @@ class Solution: public class Solution { public int[][] kClosest(int[][] points, int k) { PriorityQueue maxHeap = new PriorityQueue<>( - (a, b) -> Integer.compare(b[0] * b[0] + b[1] * b[1], + (a, b) -> Integer.compare(b[0] * b[0] + b[1] * b[1], a[0] * a[0] + a[1] * a[1]) ); @@ -311,10 +353,10 @@ public: maxHeap.pop(); } } - + vector> res; while (!maxHeap.empty()) { - res.push_back({maxHeap.top().second.first, + res.push_back({maxHeap.top().second.first, maxHeap.top().second.second}); maxHeap.pop(); } @@ -359,7 +401,7 @@ class Solution { public class Solution { public int[][] KClosest(int[][] points, int K) { PriorityQueue maxHeap = new(); - + foreach (var point in points) { int dist = point[0] * point[0] + point[1] * point[1]; maxHeap.Enqueue(point, -dist); @@ -372,7 +414,7 @@ public class Solution { while (maxHeap.Count > 0) { res.Add(maxHeap.Dequeue()); } - + return res.ToArray(); } } @@ -390,7 +432,7 @@ func kClosest(points [][]int, k int) [][]int { } return 0 }) - + for _, point := range points { x, y := point[0], point[1] dist := x*x + y*y @@ -399,14 +441,14 @@ func kClosest(points [][]int, k int) [][]int { maxHeap.Dequeue() } } - + result := make([][]int, k) for i := k - 1; i >= 0; i-- { val, _ := maxHeap.Dequeue() point := val.([]int) result[i] = []int{point[0], point[1]} } - + return result } ``` @@ -430,12 +472,48 @@ class Solution { } ``` +```swift +struct Item: Comparable { + let dist: Int + let x: Int + let y: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.dist > rhs.dist + } +} + +class Solution { + func kClosest(_ points: [[Int]], _ k: Int) -> [[Int]] { + var maxHeap = Heap() + + for point in points { + let x = point[0], y = point[1] + let dist = x * x + y * y + maxHeap.insert(Item(dist: dist, x: x, y: y)) + if maxHeap.count > k { + _ = maxHeap.popMin() + } + } + + var res = [[Int]]() + while !maxHeap.isEmpty { + if let item = maxHeap.popMin() { + res.append([item.x, item.y]) + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * \log k)$ -* Space complexity: $O(k)$ +- Time complexity: $O(n * \log k)$ +- Space complexity: $O(k)$ > Where $n$ is the length of the array $points$. @@ -562,7 +640,9 @@ class Solution { * @return {number[][]} */ kClosest(points, k) { - let L = 0, R = points.length - 1, pivot = points.length; + let L = 0, + R = points.length - 1, + pivot = points.length; while (pivot !== k) { pivot = this.partition(points, L, R); @@ -721,9 +801,49 @@ class Solution { } ``` +```swift +class Solution { + func kClosest(_ points: [[Int]], _ k: Int) -> [[Int]] { + var points = points + + func euclidean(_ point: [Int]) -> Int { + return point[0] * point[0] + point[1] * point[1] + } + + func partition(_ l: Int, _ r: Int) -> Int { + let pivotIdx = r + let pivotDist = euclidean(points[pivotIdx]) + var i = l + for j in l.. Where $n$ is the size of the permutation and $k$ is the number of inverse pairs in the permutation. @@ -263,8 +263,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * k)$ -* Space complexity: $O(n * k)$ +- Time complexity: $O(n * k)$ +- Space complexity: $O(n * k)$ > Where $n$ is the size of the permutation and $k$ is the number of inverse pairs in the permutation. @@ -366,8 +366,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2 * k)$ -* Space complexity: $O(n * k)$ +- Time complexity: $O(n ^ 2 * k)$ +- Space complexity: $O(n * k)$ > Where $n$ is the size of the permutation and $k$ is the number of inverse pairs in the permutation. @@ -477,8 +477,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * k)$ -* Space complexity: $O(n * k)$ +- Time complexity: $O(n * k)$ +- Space complexity: $O(n * k)$ > Where $n$ is the size of the permutation and $k$ is the number of inverse pairs in the permutation. @@ -593,7 +593,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * k)$ -* Space complexity: $O(k)$ +- Time complexity: $O(n * k)$ +- Space complexity: $O(k)$ -> Where $n$ is the size of the permutation and $k$ is the number of inverse pairs in the permutation. \ No newline at end of file +> Where $n$ is the size of the permutation and $k$ is the number of inverse pairs in the permutation. diff --git a/articles/k-th-smallest-in-lexicographical-order.md b/articles/k-th-smallest-in-lexicographical-order.md new file mode 100644 index 000000000..27fff97d3 --- /dev/null +++ b/articles/k-th-smallest-in-lexicographical-order.md @@ -0,0 +1,250 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def findKthNumber(self, n: int, k: int) -> int: + nums = [] + for num in range(1, n + 1): + nums.append(str(num)) + + nums.sort() + return int(nums[k - 1]) +``` + +```java +public class Solution { + public int findKthNumber(int n, int k) { + List nums = new ArrayList<>(); + for (int num = 1; num <= n; num++) { + nums.add(Integer.toString(num)); + } + Collections.sort(nums); + return Integer.parseInt(nums.get(k - 1)); + } +} +``` + +```cpp +class Solution { +public: + int findKthNumber(int n, int k) { + vector nums; + for (int num = 1; num <= n; ++num) { + nums.push_back(to_string(num)); + } + sort(nums.begin(), nums.end()); + return stoi(nums[k - 1]); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @return {number} + */ + findKthNumber(n, k) { + const nums = []; + for (let num = 1; num <= n; num++) { + nums.push(num.toString()); + } + nums.sort(); + return parseInt(nums[k - 1], 10); + } +} +``` + +```csharp +public class Solution { + public int FindKthNumber(int n, int k) { + var nums = new List(); + for (int num = 1; num <= n; num++) { + nums.Add(num.ToString()); + } + nums.Sort(); + return int.Parse(nums[k - 1]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Prefix Count + +::tabs-start + +```python +class Solution: + def findKthNumber(self, n: int, k: int) -> int: + cur = 1 + i = 1 + + def count(cur): + res = 0 + nei = cur + 1 + while cur <= n: + res += min(nei, n + 1) - cur + cur *= 10 + nei *= 10 + return res + + while i < k: + steps = count(cur) + if i + steps <= k: + cur = cur + 1 + i += steps + else: + cur *= 10 + i += 1 + + return cur +``` + +```java +public class Solution { + public int findKthNumber(int n, int k) { + long cur = 1; + long i = 1; + while (i < k) { + long steps = count(cur, n); + if (i + steps <= k) { + cur++; + i += steps; + } else { + cur *= 10; + i++; + } + } + return (int) cur; + } + + private long count(long cur, int n) { + long res = 0; + long nei = cur + 1; + while (cur <= n) { + res += Math.min(nei, (long)n + 1) - cur; + cur *= 10; + nei *= 10; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int findKthNumber(int n, int k) { + long long cur = 1; + long long i = 1; + while (i < k) { + long long steps = count(cur, n); + if (i + steps <= k) { + cur++; + i += steps; + } else { + cur *= 10; + i++; + } + } + return (int)cur; + } + +private: + long long count(long long cur, int n) { + long long res = 0; + long long nei = cur + 1; + while (cur <= n) { + res += min(nei, (long long)n + 1) - cur; + cur *= 10; + nei *= 10; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @return {number} + */ + findKthNumber(n, k) { + let cur = 1, + i = 1; + const count = (curVal) => { + let res = 0, + nei = curVal + 1; + while (curVal <= n) { + res += Math.min(nei, n + 1) - curVal; + curVal *= 10; + nei *= 10; + } + return res; + }; + + while (i < k) { + const steps = count(cur); + if (i + steps <= k) { + cur++; + i += steps; + } else { + cur *= 10; + i++; + } + } + return cur; + } +} +``` + +```csharp +public class Solution { + public int FindKthNumber(int n, int k) { + long cur = 1; + long i = 1; + while (i < k) { + long steps = Count(cur, n); + if (i + steps <= k) { + cur++; + i += steps; + } else { + cur *= 10; + i++; + } + } + return (int)cur; + } + + private long Count(long cur, int n) { + long res = 0; + long nei = cur + 1; + while (cur <= n) { + res += Math.Min(nei, (long)n + 1) - cur; + cur *= 10; + nei *= 10; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O((\log n) ^ 2)$ +- Space complexity: $O(1)$ diff --git a/articles/k-th-symbol-in-grammar.md b/articles/k-th-symbol-in-grammar.md new file mode 100644 index 000000000..da176d7ae --- /dev/null +++ b/articles/k-th-symbol-in-grammar.md @@ -0,0 +1,414 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def kthGrammar(self, n: int, k: int) -> int: + prev = ['0'] + for i in range(2, n + 1): + cur = [] + for c in prev: + if c == '0': + cur.append('0') + cur.append('1') + else: + cur.append('1') + cur.append('0') + prev = cur + return int(prev[k - 1]) +``` + +```java +public class Solution { + public int kthGrammar(int n, int k) { + List prev = new ArrayList<>(); + prev.add('0'); + for (int i = 2; i <= n; i++) { + List cur = new ArrayList<>(); + for (char c : prev) { + if (c == '0') { + cur.add('0'); + cur.add('1'); + } else { + cur.add('1'); + cur.add('0'); + } + } + prev = cur; + } + return prev.get(k - 1) - '0'; + } +} +``` + +```cpp +class Solution { +public: + int kthGrammar(int n, int k) { + vector prev = {'0'}; + for (int i = 2; i <= n; i++) { + vector cur; + for (char c : prev) { + if (c == '0') { + cur.push_back('0'); + cur.push_back('1'); + } else { + cur.push_back('1'); + cur.push_back('0'); + } + } + prev = cur; + } + return prev[k - 1] - '0'; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @return {number} + */ + kthGrammar(n, k) { + let prev = ['0']; + for (let i = 2; i <= n; i++) { + let cur = []; + for (let c of prev) { + if (c === '0') { + cur.push('0'); + cur.push('1'); + } else { + cur.push('1'); + cur.push('0'); + } + } + prev = cur; + } + return parseInt(prev[k - 1]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(2 ^ n)$ + +--- + +## 2. Binary Tree Traversal (Recursion) + +::tabs-start + +```python +class Solution: + def kthGrammar(self, n: int, k: int) -> int: + def dfs(n, k, root): + if n == 1: + return root + + total = 1 << (n - 1) + if k > (total // 2): + return dfs(n - 1, k - (total // 2), root ^ 1) + else: + return dfs(n - 1, k, root) + + return dfs(n, k, 0) +``` + +```java +public class Solution { + public int kthGrammar(int n, int k) { + return dfs(n, k, 0); + } + + private int dfs(int n, int k, int root) { + if (n == 1) { + return root; + } + + int total = 1 << (n - 1); + if (k > total / 2) { + return dfs(n - 1, k - total / 2, root ^ 1); + } else { + return dfs(n - 1, k, root); + } + } +} +``` + +```cpp +class Solution { +public: + int kthGrammar(int n, int k) { + return dfs(n, k, 0); + } + + int dfs(int n, int k, int root){ + if (n == 1) return root; + + int total = 1 << (n - 1); + if (k > total / 2) { + return dfs(n - 1, k - total / 2, root ^ 1); + } else { + return dfs(n - 1, k, root); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @return {number} + */ + kthGrammar(n, k) { + const dfs = (n, k, root) => { + if (n === 1) return root; + + const total = 1 << (n - 1); + if (k > total / 2) { + return dfs(n - 1, k - total / 2, root ^ 1); + } else { + return dfs(n - 1, k, root); + } + }; + + return dfs(n, k, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Binary Tree Traversal (Iteration) + +::tabs-start + +```python +class Solution: + def kthGrammar(self, n: int, k: int) -> int: + cur = 0 + left, right = 1, 2 ** (n - 1) + + for _ in range(n - 1): + mid = (left + right) // 2 + if k <= mid: + right = mid + else: + left = mid + 1 + cur = 0 if cur else 1 + + return cur +``` + +```java +public class Solution { + public int kthGrammar(int n, int k) { + int cur = 0; + int left = 1, right = 1 << (n - 1); + + for (int i = 0; i < n - 1; i++) { + int mid = (left + right) / 2; + if (k <= mid) { + right = mid; + } else { + left = mid + 1; + cur = (cur == 0) ? 1 : 0; + } + } + + return cur; + } +} +``` + +```cpp +class Solution { +public: + int kthGrammar(int n, int k) { + int cur = 0; + int left = 1, right = 1 << (n - 1); + + for (int i = 0; i < n - 1; i++) { + int mid = (left + right) / 2; + if (k <= mid) { + right = mid; + } else { + left = mid + 1; + cur = (cur == 0) ? 1 : 0; + } + } + + return cur; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @return {number} + */ + kthGrammar(n, k) { + let cur = 0; + let left = 1, + right = 1 << (n - 1); + + for (let i = 0; i < n - 1; i++) { + let mid = Math.floor((left + right) / 2); + if (k <= mid) { + right = mid; + } else { + left = mid + 1; + cur = cur === 0 ? 1 : 0; + } + } + + return cur; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 4. Recursion (Traverse Towards Root) + +::tabs-start + +```python +class Solution: + def kthGrammar(self, n: int, k: int) -> int: + if n == 1: + return 0 + if k & 1: + return self.kthGrammar(n - 1, (k + 1) // 2) + return self.kthGrammar(n - 1, k // 2) ^ 1 +``` + +```java +public class Solution { + public int kthGrammar(int n, int k) { + if (n == 1) { + return 0; + } + if ((k & 1) == 1) { + return kthGrammar(n - 1, (k + 1) / 2); + } + return kthGrammar(n - 1, k / 2) ^ 1; + } +} +``` + +```cpp +class Solution { +public: + int kthGrammar(int n, int k) { + if (n == 1) { + return 0; + } + if (k & 1) { + return kthGrammar(n - 1, (k + 1) / 2); + } + return kthGrammar(n - 1, k / 2) ^ 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @return {number} + */ + kthGrammar(n, k) { + if (n === 1) { + return 0; + } + if (k % 2 === 1) { + return this.kthGrammar(n - 1, Math.floor((k + 1) / 2)); + } + return this.kthGrammar(n - 1, Math.floor(k / 2)) ^ 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 5. Math + +::tabs-start + +```python +class Solution: + def kthGrammar(self, n: int, k: int) -> int: + return bin(k - 1).count('1') & 1 +``` + +```java +public class Solution { + public int kthGrammar(int n, int k) { + return Integer.bitCount(k - 1) & 1; + } +} +``` + +```cpp +class Solution { +public: + int kthGrammar(int n, int k) { + return __builtin_popcount(k - 1) & 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} k + * @return {number} + */ + kthGrammar(n, k) { + return ((k - 1).toString(2).split('1').length - 1) & 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ or $O(\log n)$ depending on the language. diff --git a/articles/knight-dialer.md b/articles/knight-dialer.md new file mode 100644 index 000000000..26d95ccde --- /dev/null +++ b/articles/knight-dialer.md @@ -0,0 +1,988 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def knightDialer(self, n: int) -> int: + if n == 1: + return 10 + + mod = 1000000007 + jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ] + + def dfs(n, d): + if n == 0: + return 1 + + res = 0 + for j in jumps[d]: + res = (res + dfs(n - 1, j)) % mod + return res + + res = 0 + for d in range(10): + res = (res + dfs(n - 1, d)) % mod + return res +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + private static final int[][] jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + + public int knightDialer(int n) { + if (n == 1) return 10; + int res = 0; + + for (int d = 0; d < 10; d++) { + res = (res + dfs(n - 1, d)) % MOD; + } + return res; + } + + private int dfs(int n, int d) { + if (n == 0) return 1; + + int res = 0; + for (int next : jumps[d]) { + res = (res + dfs(n - 1, next)) % MOD; + } + return res; + } +} +``` + +```cpp +class Solution { +private: + static constexpr int MOD = 1000000007; + const vector> jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + +public: + int knightDialer(int n) { + if (n == 1) return 10; + int res = 0; + + for (int d = 0; d < 10; d++) { + res = (res + dfs(n - 1, d)) % MOD; + } + return res; + } + +private: + int dfs(int n, int d) { + if (n == 0) return 1; + + int res = 0; + for (int next : jumps[d]) { + res = (res + dfs(n - 1, next)) % MOD; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + knightDialer(n) { + if (n === 1) return 10; + const MOD = 1000000007; + const jumps = [ + [4, 6], + [6, 8], + [7, 9], + [4, 8], + [0, 3, 9], + [], + [0, 1, 7], + [2, 6], + [1, 3], + [2, 4], + ]; + + const dfs = (n, d) => { + if (n === 0) return 1; + + let res = 0; + for (const next of jumps[d]) { + res = (res + dfs(n - 1, next)) % MOD; + } + return res; + }; + + let res = 0; + for (let d = 0; d < 10; d++) { + res = (res + dfs(n - 1, d)) % MOD; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(3 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def knightDialer(self, n: int) -> int: + if n == 1: + return 10 + + mod = 1000000007 + jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ] + + dp = [[-1] * (n + 1) for _ in range(10)] + + def dfs(n, d): + if n == 0: + return 1 + if dp[d][n] != -1: + return dp[d][n] + + dp[d][n] = 0 + for j in jumps[d]: + dp[d][n] = (dp[d][n] + dfs(n - 1, j)) % mod + return dp[d][n] + + res = 0 + for d in range(10): + res = (res + dfs(n - 1, d)) % mod + return res +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + private static final int[][] jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + private int[][] dp; + + public int knightDialer(int n) { + if (n == 1) return 10; + dp = new int[10][n + 1]; + for (int[] row : dp) Arrays.fill(row, -1); + + int res = 0; + for (int d = 0; d < 10; d++) { + res = (res + dfs(n - 1, d)) % MOD; + } + return res; + } + + private int dfs(int n, int d) { + if (n == 0) return 1; + if (dp[d][n] != -1) return dp[d][n]; + + dp[d][n] = 0; + for (int next : jumps[d]) { + dp[d][n] = (dp[d][n] + dfs(n - 1, next)) % MOD; + } + return dp[d][n]; + } +} +``` + +```cpp +class Solution { +private: + static constexpr int MOD = 1000000007; + vector> jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + vector> dp; + +public: + int knightDialer(int n) { + if (n == 1) return 10; + dp.assign(10, vector(n + 1, -1)); + + int res = 0; + for (int d = 0; d < 10; d++) { + res = (res + dfs(n - 1, d)) % MOD; + } + return res; + } + +private: + int dfs(int n, int d) { + if (n == 0) return 1; + if (dp[d][n] != -1) return dp[d][n]; + + dp[d][n] = 0; + for (int next : jumps[d]) { + dp[d][n] = (dp[d][n] + dfs(n - 1, next)) % MOD; + } + return dp[d][n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + knightDialer(n) { + if (n === 1) return 10; + const MOD = 1000000007; + const jumps = [ + [4, 6], + [6, 8], + [7, 9], + [4, 8], + [0, 3, 9], + [], + [0, 1, 7], + [2, 6], + [1, 3], + [2, 4], + ]; + + const dp = Array.from({ length: 10 }, () => Array(n + 1).fill(-1)); + + const dfs = (n, d) => { + if (n === 0) return 1; + if (dp[d][n] !== -1) return dp[d][n]; + + dp[d][n] = 0; + for (const next of jumps[d]) { + dp[d][n] = (dp[d][n] + dfs(n - 1, next)) % MOD; + } + return dp[d][n]; + }; + + let res = 0; + for (let d = 0; d < 10; d++) { + res = (res + dfs(n - 1, d)) % MOD; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def knightDialer(self, n: int) -> int: + if n == 1: + return 10 + + mod = 1000000007 + jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ] + + dp = [[0] * (n + 1) for _ in range(10)] + + for d in range(10): + dp[d][0] = 1 + + for step in range(1, n): + for d in range(10): + dp[d][step] = sum(dp[j][step - 1] for j in jumps[d]) % mod + + return sum(dp[d][n - 1] for d in range(10)) % mod +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + private static final int[][] jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + + public int knightDialer(int n) { + if (n == 1) return 10; + + int[][] dp = new int[10][n + 1]; + for (int d = 0; d < 10; d++) { + dp[d][0] = 1; + } + + for (int step = 1; step < n; step++) { + for (int d = 0; d < 10; d++) { + for (int j : jumps[d]) { + dp[d][step] = (dp[d][step] + dp[j][step - 1]) % MOD; + } + } + } + + int res = 0; + for (int d = 0; d < 10; d++) { + res = (res + dp[d][n - 1]) % MOD; + } + return res; + } +} +``` + +```cpp +class Solution { +private: + static constexpr int MOD = 1000000007; + vector> jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + +public: + int knightDialer(int n) { + if (n == 1) return 10; + + vector> dp(10, vector(n + 1, 0)); + for (int d = 0; d < 10; d++) { + dp[d][0] = 1; + } + + for (int step = 1; step < n; step++) { + for (int d = 0; d < 10; d++) { + for (int j : jumps[d]) { + dp[d][step] = (dp[d][step] + dp[j][step - 1]) % MOD; + } + } + } + + int res = 0; + for (int d = 0; d < 10; d++) { + res = (res + dp[d][n - 1]) % MOD; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + knightDialer(n) { + if (n === 1) return 10; + const MOD = 1000000007; + const jumps = [ + [4, 6], + [6, 8], + [7, 9], + [4, 8], + [0, 3, 9], + [], + [0, 1, 7], + [2, 6], + [1, 3], + [2, 4], + ]; + + const dp = Array.from({ length: 10 }, () => Array(n + 1).fill(0)); + for (let d = 0; d < 10; d++) { + dp[d][0] = 1; + } + + for (let step = 1; step < n; step++) { + for (let d = 0; d < 10; d++) { + for (const j of jumps[d]) { + dp[d][step] = (dp[d][step] + dp[j][step - 1]) % MOD; + } + } + } + + let res = 0; + for (let d = 0; d < 10; d++) { + res = (res + dp[d][n - 1]) % MOD; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def knightDialer(self, n: int) -> int: + if n == 1: + return 10 + + mod = 1000000007 + jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ] + + dp = [1] * 10 + for step in range(n - 1): + next_dp = [0] * 10 + for d in range(10): + for j in jumps[d]: + next_dp[j] = (next_dp[j] + dp[d]) % mod + dp = next_dp + + res = 0 + for d in dp: + res = (res + d) % mod + return res +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + private static final int[][] jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + + public int knightDialer(int n) { + if (n == 1) return 10; + + int[] dp = new int[10]; + Arrays.fill(dp, 1); + + for (int step = 0; step < n - 1; step++) { + int[] nextDp = new int[10]; + for (int d = 0; d < 10; d++) { + for (int j : jumps[d]) { + nextDp[j] = (nextDp[j] + dp[d]) % MOD; + } + } + dp = nextDp; + } + + int res = 0; + for (int d : dp) { + res = (res + d) % MOD; + } + return res; + } +} +``` + +```cpp +class Solution { +private: + static constexpr int MOD = 1000000007; + vector> jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + +public: + int knightDialer(int n) { + if (n == 1) return 10; + + vector dp(10, 1); + + for (int step = 0; step < n - 1; step++) { + vector nextDp(10, 0); + for (int d = 0; d < 10; d++) { + for (int j : jumps[d]) { + nextDp[j] = (nextDp[j] + dp[d]) % MOD; + } + } + dp = nextDp; + } + + int res = 0; + for (int d : dp) { + res = (res + d) % MOD; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + knightDialer(n) { + if (n === 1) return 10; + const MOD = 1000000007; + const jumps = [ + [4, 6], + [6, 8], + [7, 9], + [4, 8], + [0, 3, 9], + [], + [0, 1, 7], + [2, 6], + [1, 3], + [2, 4], + ]; + + let dp = new Array(10).fill(1); + + for (let step = 0; step < n - 1; step++) { + let nextDp = new Array(10).fill(0); + for (let d = 0; d < 10; d++) { + for (const j of jumps[d]) { + nextDp[j] = (nextDp[j] + dp[d]) % MOD; + } + } + dp = nextDp; + } + + return dp.reduce((res, d) => (res + d) % MOD, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 5. Dynamic Programming (Optimal) + +::tabs-start + +```python +class Solution: + def knightDialer(self, n: int) -> int: + if n == 1: + return 10 + + mod = 10**9 + 7 + jumps = [1, 4, 2, 2] # [D, A, B, C] + + for _ in range(n - 1): + tmp = [0] * 4 + tmp[0] = jumps[3] + tmp[1] = 2 * jumps[2] + 2 * jumps[3] + tmp[2] = jumps[1] + tmp[3] = 2 * jumps[0] + jumps[1] + jumps = tmp + + return sum(jumps) % mod +``` + +```java +public class Solution { + public int knightDialer(int n) { + if (n == 1) return 10; + + int MOD = 1000000007; + long[] jumps = {1, 4, 2, 2}; // [D, A, B, C] + + for (int i = 0; i < n - 1; i++) { + long[] tmp = new long[4]; + tmp[0] = jumps[3]; + tmp[1] = (2 * jumps[2] + 2 * jumps[3]) % MOD; + tmp[2] = jumps[1]; + tmp[3] = (2 * jumps[0] + jumps[1]) % MOD; + jumps = tmp; + } + + long res = 0; + for (long num : jumps) { + res = (res + num) % MOD; + } + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int knightDialer(int n) { + if (n == 1) return 10; + + const int MOD = 1000000007; + vector jumps = {1, 4, 2, 2}; // [D, A, B, C] + + for (int i = 0; i < n - 1; i++) { + vector tmp(4); + tmp[0] = jumps[3]; + tmp[1] = (2 * jumps[2] + 2 * jumps[3]) % MOD; + tmp[2] = jumps[1]; + tmp[3] = (2 * jumps[0] + jumps[1]) % MOD; + jumps = tmp; + } + + return (jumps[0] + jumps[1] + jumps[2] + jumps[3]) % MOD; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + knightDialer(n) { + if (n === 1) return 10; + + const MOD = 1000000007; + let jumps = [1, 4, 2, 2]; // [D, A, B, C] + + for (let i = 0; i < n - 1; i++) { + let tmp = new Array(4).fill(0); + tmp[0] = jumps[3]; + tmp[1] = (2 * jumps[2] + 2 * jumps[3]) % MOD; + tmp[2] = jumps[1]; + tmp[3] = (2 * jumps[0] + jumps[1]) % MOD; + jumps = tmp; + } + + return jumps.reduce((sum, num) => (sum + num) % MOD, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 6. Matrix Exponentiation + +::tabs-start + +```python +class Matrix: + def __init__(self, size): + self.n = size + self.a = [[0] * size for _ in range(size)] + + def __mul__(self, other): + n = self.n + MOD = 10**9 + 7 + product = Matrix(n) + for i in range(n): + for j in range(n): + for k in range(n): + product.a[i][k] = (product.a[i][k] + self.a[i][j] * other.a[j][k]) % MOD + return product + + +def matpow(mat, n, size): + res = Matrix(size) + for i in range(size): + res.a[i][i] = 1 # Identity matrix + + while n: + if n & 1: + res = res * mat + mat = mat * mat + n >>= 1 + + return res + + +class Solution: + def knightDialer(self, n: int) -> int: + if n == 1: + return 10 + + MOD = 10**9 + 7 + jumps = [ + [4, 6], [6, 8], [7, 9], [4, 8], [0, 3, 9], + [], [0, 1, 7], [2, 6], [1, 3], [2, 4] + ] + + mat = Matrix(10) + for i in range(10): + for j in jumps[i]: + mat.a[i][j] = 1 + + res = matpow(mat, n - 1, 10) + + ans = sum(sum(res.a[i]) for i in range(10)) % MOD + return ans +``` + +```java +class Matrix { + int[][] a; + int size; + static final int MOD = 1_000_000_007; + + public Matrix(int size) { + this.size = size; + a = new int[size][size]; + } + + public Matrix multiply(Matrix other) { + Matrix product = new Matrix(size); + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + for (int k = 0; k < size; k++) { + product.a[i][k] = (int)((product.a[i][k] + (long) a[i][j] * other.a[j][k]) % MOD); + } + } + } + return product; + } +} + +public class Solution { + private Matrix matpow(Matrix mat, int n, int size) { + Matrix res = new Matrix(size); + for (int i = 0; i < size; i++) { + res.a[i][i] = 1; // Identity matrix + } + + while (n > 0) { + if ((n & 1) == 1) { + res = res.multiply(mat); + } + mat = mat.multiply(mat); + n >>= 1; + } + return res; + } + + public int knightDialer(int n) { + if (n == 1) return 10; + + int[][] jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + + Matrix mat = new Matrix(10); + for (int i = 0; i < 10; i++) { + for (int j : jumps[i]) { + mat.a[i][j] = 1; + } + } + + Matrix res = matpow(mat, n - 1, 10); + + int ans = 0; + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + ans = (ans + res.a[i][j]) % Matrix.MOD; + } + } + return ans; + } +} +``` + +```cpp +class Matrix { +public: + vector> a; + int size; + static const int MOD = 1'000'000'007; + + Matrix(int n) : size(n) { + a.assign(n, vector(n, 0)); + } + + Matrix operator*(const Matrix &other) const { + Matrix product(size); + for (int i = 0; i < size; i++) { + for (int j = 0; j < size; j++) { + for (int k = 0; k < size; k++) { + product.a[i][k] = (product.a[i][k] + 1LL * a[i][j] * other.a[j][k]) % MOD; + } + } + } + return product; + } +}; + +Matrix matpow(Matrix mat, int n, int size) { + Matrix res(size); + for (int i = 0; i < size; i++) { + res.a[i][i] = 1; // Identity matrix + } + + while (n > 0) { + if (n & 1) res = res * mat; + mat = mat * mat; + n >>= 1; + } + return res; +} + +class Solution { +public: + int knightDialer(int n) { + if (n == 1) return 10; + + vector> jumps = { + {4, 6}, {6, 8}, {7, 9}, {4, 8}, {0, 3, 9}, + {}, {0, 1, 7}, {2, 6}, {1, 3}, {2, 4} + }; + + Matrix mat(10); + for (int i = 0; i < 10; i++) { + for (int j : jumps[i]) { + mat.a[i][j] = 1; + } + } + + Matrix res = matpow(mat, n - 1, 10); + + int ans = 0; + for (int i = 0; i < 10; i++) { + for (int j = 0; j < 10; j++) { + ans = (ans + res.a[i][j]) % Matrix::MOD; + } + } + return ans; + } +}; +``` + +```javascript +class Matrix { + constructor(size) { + this.size = size; + this.a = Array.from({ length: size }, () => Array(size).fill(0)); + this.MOD = BigInt(1e9 + 7); + } + + multiply(other) { + const product = new Matrix(this.size); + for (let i = 0; i < this.size; i++) { + for (let j = 0; j < this.size; j++) { + let sum = BigInt(0); + for (let k = 0; k < this.size; k++) { + sum = + (sum + BigInt(this.a[i][k]) * BigInt(other.a[k][j])) % + this.MOD; + } + product.a[i][j] = Number(sum); + } + } + return product; + } +} + +class Solution { + /** + * @param {number} n + * @return {number} + */ + knightDialer(n) { + if (n === 1) return 10; + + const matpow = (mat, exp, size) => { + let res = new Matrix(size); + for (let i = 0; i < size; i++) { + res.a[i][i] = 1; // Identity matrix + } + + while (exp > 0) { + if (exp & 1) { + res = res.multiply(mat); + } + mat = mat.multiply(mat); + exp >>= 1; + } + return res; + }; + + const jumps = [ + [4, 6], + [6, 8], + [7, 9], + [4, 8], + [0, 3, 9], + [], + [0, 1, 7], + [2, 6], + [1, 3], + [2, 4], + ]; + + const mat = new Matrix(10); + for (let i = 0; i < 10; i++) { + for (let j of jumps[i]) { + mat.a[i][j] = 1; + } + } + + const res = matpow(mat, n - 1, 10); + const mod = 1e9 + 7; + let ans = 0; + + for (let i = 0; i < 10; i++) { + for (let j = 0; j < 10; j++) { + ans = (ans + res.a[i][j]) % mod; + } + } + + return ans; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/kth-distinct-string-in-an-array.md b/articles/kth-distinct-string-in-an-array.md new file mode 100644 index 000000000..feaae4e1e --- /dev/null +++ b/articles/kth-distinct-string-in-an-array.md @@ -0,0 +1,350 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def kthDistinct(self, arr: List[str], k: int) -> str: + for i in range(len(arr)): + flag = True + for j in range(len(arr)): + if i == j: + continue + + if arr[i] == arr[j]: + flag = False + break + + if flag: + k -= 1 + if k == 0: + return arr[i] + return "" +``` + +```java +public class Solution { + public String kthDistinct(String[] arr, int k) { + for (int i = 0; i < arr.length; i++) { + boolean flag = true; + for (int j = 0; j < arr.length; j++) { + if (i == j) continue; + + if (arr[i].equals(arr[j])) { + flag = false; + break; + } + } + + if (flag) { + k--; + if (k == 0) { + return arr[i]; + } + } + } + return ""; + } +} +``` + +```cpp +class Solution { +public: + string kthDistinct(vector& arr, int k) { + for (int i = 0; i < arr.size(); i++) { + bool flag = true; + for (int j = 0; j < arr.size(); j++) { + if (i == j) continue; + + if (arr[i] == arr[j]) { + flag = false; + break; + } + } + + if (flag) { + k--; + if (k == 0) { + return arr[i]; + } + } + } + return ""; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @param {number} k + * @return {string} + */ + kthDistinct(arr, k) { + for (let i = 0; i < arr.length; i++) { + let flag = true; + for (let j = 0; j < arr.length; j++) { + if (i === j) continue; + + if (arr[i] === arr[j]) { + flag = false; + break; + } + } + + if (flag) { + k--; + if (k === 0) { + return arr[i]; + } + } + } + return ''; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Hash Map + +::tabs-start + +```python +class Solution: + def kthDistinct(self, arr: List[str], k: int) -> str: + count = {} + + for s in arr: + if s not in count: + count[s] = 0 + count[s] += 1 + + for s in arr: + if count[s] == 1: + k -= 1 + if k == 0: + return s + + return "" +``` + +```java +public class Solution { + public String kthDistinct(String[] arr, int k) { + Map count = new HashMap<>(); + + for (String s : arr) { + count.put(s, count.getOrDefault(s, 0) + 1); + } + + for (String s : arr) { + if (count.get(s) == 1) { + k--; + if (k == 0) { + return s; + } + } + } + + return ""; + } +} +``` + +```cpp +class Solution { +public: + string kthDistinct(vector& arr, int k) { + unordered_map count; + + for (const string& s : arr) { + count[s]++; + } + + for (const string& s : arr) { + if (count[s] == 1) { + k--; + if (k == 0) { + return s; + } + } + } + + return ""; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @param {number} k + * @return {string} + */ + kthDistinct(arr, k) { + const count = {}; + + for (let s of arr) { + if (!(s in count)) { + count[s] = 0; + } + count[s]++; + } + + for (let s of arr) { + if (count[s] === 1) { + k--; + if (k === 0) { + return s; + } + } + } + + return ''; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Hash Set + +::tabs-start + +```python +class Solution: + def kthDistinct(self, arr: List[str], k: int) -> str: + distinct, seen = set(), set() + + for s in arr: + if s in distinct: + distinct.remove(s) + seen.add(s) + elif s not in seen: + distinct.add(s) + + for s in arr: + if s in distinct: + k -= 1 + if k == 0: + return s + + return "" +``` + +```java +public class Solution { + public String kthDistinct(String[] arr, int k) { + Set distinct = new HashSet<>(); + Set seen = new HashSet<>(); + + for (String s : arr) { + if (distinct.contains(s)) { + distinct.remove(s); + seen.add(s); + } else if (!seen.contains(s)) { + distinct.add(s); + } + } + + for (String s : arr) { + if (distinct.contains(s)) { + k--; + if (k == 0) { + return s; + } + } + } + + return ""; + } +} +``` + +```cpp +class Solution { +public: + string kthDistinct(vector& arr, int k) { + unordered_set distinct, seen; + + for (const string& s : arr) { + if (distinct.count(s)) { + distinct.erase(s); + seen.insert(s); + } else if (!seen.count(s)) { + distinct.insert(s); + } + } + + for (const string& s : arr) { + if (distinct.count(s)) { + k--; + if (k == 0) { + return s; + } + } + } + + return ""; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @param {number} k + * @return {string} + */ + kthDistinct(arr, k) { + const distinct = new Set(); + const seen = new Set(); + + for (let s of arr) { + if (distinct.has(s)) { + distinct.delete(s); + seen.add(s); + } else if (!seen.has(s)) { + distinct.add(s); + } + } + + for (let s of arr) { + if (distinct.has(s)) { + k--; + if (k === 0) { + return s; + } + } + } + + return ''; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/kth-largest-element-in-an-array.md b/articles/kth-largest-element-in-an-array.md index ba0f51363..35226ea32 100644 --- a/articles/kth-largest-element-in-an-array.md +++ b/articles/kth-largest-element-in-an-array.md @@ -13,7 +13,7 @@ class Solution: public class Solution { public int findKthLargest(int[] nums, int k) { Arrays.sort(nums); - return nums[nums.length - k]; + return nums[nums.length - k]; } } ``` @@ -67,12 +67,21 @@ class Solution { } ``` +```swift +class Solution { + func findKthLargest(_ nums: [Int], _ k: Int) -> Int { + let sortedNums = nums.sorted() + return sortedNums[sortedNums.count - k] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -155,14 +164,14 @@ public class Solution { ```go func findKthLargest(nums []int, k int) int { minHeap := priorityqueue.NewWith(utils.IntComparator) - + for _, num := range nums { minHeap.Enqueue(num) if minHeap.Size() > k { minHeap.Dequeue() } } - + val, _ := minHeap.Peek() return val.(int) } @@ -172,7 +181,7 @@ func findKthLargest(nums []int, k int) int { class Solution { fun findKthLargest(nums: IntArray, k: Int): Int { val minHeap = PriorityQueue() - + for (num in nums) { minHeap.offer(num) if (minHeap.size > k) { @@ -184,12 +193,29 @@ class Solution { } ``` +```swift +class Solution { + func findKthLargest(_ nums: [Int], _ k: Int) -> Int { + var minHeap = Heap() + + for num in nums { + minHeap.insert(num) + if minHeap.count > k { + _ = minHeap.removeMin() + } + } + + return minHeap.popMin()! + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log k)$ -* Space complexity: $O(k)$ +- Time complexity: $O(n \log k)$ +- Space complexity: $O(k)$ > Where $n$ is the length of the array $nums$. @@ -204,7 +230,7 @@ class Solution: def findKthLargest(self, nums: List[int], k: int) -> int: k = len(nums) - k - + def quickSelect(l, r): pivot, p = nums[r], l for i in range(l, r): @@ -213,7 +239,7 @@ class Solution: p += 1 nums[p], nums[r] = nums[r], nums[p] - if p > k: + if p > k: return quickSelect(l, p - 1) elif p < k: return quickSelect(p + 1, r) @@ -266,11 +292,11 @@ public: k = nums.size() - k; return quickSelect(nums, 0, nums.size() - 1, k); } - + int quickSelect(vector& nums, int left, int right, int k) { int pivot = nums[right]; int p = left; - + for (int i = left; i < right; ++i) { if (nums[i] <= pivot) { swap(nums[p], nums[i]); @@ -278,7 +304,7 @@ public: } } swap(nums[p], nums[right]); - + if (p > k) { return quickSelect(nums, left, p - 1, k); } else if (p < k) { @@ -364,7 +390,7 @@ public class Solution { ```go func findKthLargest(nums []int, k int) int { k = len(nums) - k - + var quickSelect func(l, r int) int quickSelect = func(l, r int) int { pivot, p := nums[r], l @@ -417,12 +443,44 @@ class Solution { } ``` +```swift +class Solution { + func findKthLargest(_ nums: [Int], _ k: Int) -> Int { + var nums = nums + let k = nums.count - k + + func quickSelect(_ l: Int, _ r: Int) -> Int { + let pivot = nums[r] + var p = l + + for i in l.. k { + return quickSelect(l, p - 1) + } else if p < k { + return quickSelect(p + 1, r) + } else { + return nums[p] + } + } + + return quickSelect(0, nums.count - 1) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ in average case, $O(n ^ 2)$ in worst case. -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ in average case, $O(n ^ 2)$ in worst case. +- Space complexity: $O(n)$ --- @@ -435,18 +493,18 @@ class Solution: def partition(self, nums: List[int], left: int, right: int) -> int: mid = (left + right) >> 1 nums[mid], nums[left + 1] = nums[left + 1], nums[mid] - + if nums[left] < nums[right]: nums[left], nums[right] = nums[right], nums[left] if nums[left + 1] < nums[right]: nums[left + 1], nums[right] = nums[right], nums[left + 1] if nums[left] < nums[left + 1]: nums[left], nums[left + 1] = nums[left + 1], nums[left] - + pivot = nums[left + 1] i = left + 1 j = right - + while True: while True: i += 1 @@ -459,27 +517,27 @@ class Solution: if i > j: break nums[i], nums[j] = nums[j], nums[i] - + nums[left + 1], nums[j] = nums[j], nums[left + 1] return j - + def quickSelect(self, nums: List[int], k: int) -> int: left = 0 right = len(nums) - 1 - + while True: if right <= left + 1: if right == left + 1 and nums[right] > nums[left]: nums[left], nums[right] = nums[right], nums[left] return nums[k] - + j = self.partition(nums, left, right) - + if j >= k: right = j - 1 if j <= k: left = j + 1 - + def findKthLargest(self, nums: List[int], k: int) -> int: return self.quickSelect(nums, k - 1) ``` @@ -489,54 +547,54 @@ public class Solution { private int partition(int[] nums, int left, int right) { int mid = (left + right) >> 1; swap(nums, mid, left + 1); - - if (nums[left] < nums[right]) + + if (nums[left] < nums[right]) swap(nums, left, right); - if (nums[left + 1] < nums[right]) + if (nums[left + 1] < nums[right]) swap(nums, left + 1, right); - if (nums[left] < nums[left + 1]) + if (nums[left] < nums[left + 1]) swap(nums, left, left + 1); - + int pivot = nums[left + 1]; int i = left + 1; int j = right; - + while (true) { while (nums[++i] > pivot); while (nums[--j] < pivot); if (i > j) break; swap(nums, i, j); } - + nums[left + 1] = nums[j]; nums[j] = pivot; return j; } - + private void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } - + private int quickSelect(int[] nums, int k) { int left = 0; int right = nums.length - 1; - + while (true) { if (right <= left + 1) { if (right == left + 1 && nums[right] > nums[left]) swap(nums, left, right); return nums[k]; } - + int j = partition(nums, left, right); - + if (j >= k) right = j - 1; if (j <= k) left = j + 1; } } - + public int findKthLargest(int[] nums, int k) { return quickSelect(nums, k - 1); } @@ -549,48 +607,48 @@ public: int partition(vector& nums, int left, int right) { int mid = (left + right) >> 1; swap(nums[mid], nums[left + 1]); - - if (nums[left] < nums[right]) + + if (nums[left] < nums[right]) swap(nums[left], nums[right]); - if (nums[left + 1] < nums[right]) + if (nums[left + 1] < nums[right]) swap(nums[left + 1], nums[right]); - if (nums[left] < nums[left + 1]) + if (nums[left] < nums[left + 1]) swap(nums[left], nums[left + 1]); - + int pivot = nums[left + 1]; int i = left + 1; int j = right; - + while (true) { while (nums[++i] > pivot); while (nums[--j] < pivot); if (i > j) break; swap(nums[i], nums[j]); } - + nums[left + 1] = nums[j]; nums[j] = pivot; return j; } - + int quickSelect(vector& nums, int k) { int left = 0; int right = nums.size() - 1; - + while (true) { if (right <= left + 1) { if (right == left + 1 && nums[right] > nums[left]) swap(nums[left], nums[right]); return nums[k]; } - + int j = partition(nums, left, right); - + if (j >= k) right = j - 1; if (j <= k) left = j + 1; } } - + int findKthLargest(vector& nums, int k) { return quickSelect(nums, k - 1); } @@ -608,48 +666,48 @@ class Solution { function partition(left, right) { const mid = (left + right) >> 1; [nums[mid], nums[left + 1]] = [nums[left + 1], nums[mid]]; - + if (nums[left] < nums[right]) [nums[left], nums[right]] = [nums[right], nums[left]]; if (nums[left + 1] < nums[right]) [nums[left + 1], nums[right]] = [nums[right], nums[left + 1]]; if (nums[left] < nums[left + 1]) [nums[left], nums[left + 1]] = [nums[left + 1], nums[left]]; - + const pivot = nums[left + 1]; let i = left + 1; let j = right; - + while (true) { while (nums[++i] > pivot); while (nums[--j] < pivot); if (i > j) break; [nums[i], nums[j]] = [nums[j], nums[i]]; } - + nums[left + 1] = nums[j]; nums[j] = pivot; return j; } - + function quickSelect(k) { let left = 0; let right = nums.length - 1; - + while (true) { if (right <= left + 1) { if (right == left + 1 && nums[right] > nums[left]) [nums[left], nums[right]] = [nums[right], nums[left]]; return nums[k]; } - + const j = partition(left, right); - + if (j >= k) right = j - 1; if (j <= k) left = j + 1; } } - + return quickSelect(k - 1); } } @@ -660,48 +718,48 @@ public class Solution { private int Partition(int[] nums, int left, int right) { int mid = (left + right) >> 1; (nums[mid], nums[left + 1]) = (nums[left + 1], nums[mid]); - + if (nums[left] < nums[right]) (nums[left], nums[right]) = (nums[right], nums[left]); if (nums[left + 1] < nums[right]) (nums[left + 1], nums[right]) = (nums[right], nums[left + 1]); if (nums[left] < nums[left + 1]) (nums[left], nums[left + 1]) = (nums[left + 1], nums[left]); - + int pivot = nums[left + 1]; int i = left + 1; int j = right; - + while (true) { while (nums[++i] > pivot); while (nums[--j] < pivot); if (i > j) break; (nums[i], nums[j]) = (nums[j], nums[i]); } - + nums[left + 1] = nums[j]; nums[j] = pivot; return j; } - + private int QuickSelect(int[] nums, int k) { int left = 0; int right = nums.Length - 1; - + while (true) { if (right <= left + 1) { if (right == left + 1 && nums[right] > nums[left]) (nums[left], nums[right]) = (nums[right], nums[left]); return nums[k]; } - + int j = Partition(nums, left, right); - + if (j >= k) right = j - 1; if (j <= k) left = j + 1; } } - + public int FindKthLargest(int[] nums, int k) { return QuickSelect(nums, k - 1); } @@ -714,7 +772,7 @@ func findKthLargest(nums []int, k int) int { partition = func(left, right int) int { mid := (left + right) >> 1 nums[mid], nums[left+1] = nums[left+1], nums[mid] - + if nums[left] < nums[right] { nums[left], nums[right] = nums[right], nums[left] } @@ -724,11 +782,11 @@ func findKthLargest(nums []int, k int) int { if nums[left] < nums[left+1] { nums[left], nums[left+1] = nums[left+1], nums[left] } - + pivot := nums[left+1] i := left + 1 j := right - + for { for i++; nums[i] > pivot; i++ {} for j--; nums[j] < pivot; j-- {} @@ -737,15 +795,15 @@ func findKthLargest(nums []int, k int) int { } nums[i], nums[j] = nums[j], nums[i] } - + nums[left+1], nums[j] = nums[j], nums[left+1] return j } - + quickSelect := func(k int) int { left := 0 right := len(nums) - 1 - + for { if right <= left+1 { if right == left+1 && nums[right] > nums[left] { @@ -753,9 +811,9 @@ func findKthLargest(nums []int, k int) int { } return nums[k] } - + j := partition(left, right) - + if j >= k { right = j - 1 } @@ -764,7 +822,7 @@ func findKthLargest(nums []int, k int) int { } } } - + return quickSelect(k - 1) } ``` @@ -774,57 +832,121 @@ class Solution { private fun partition(nums: IntArray, left: Int, right: Int): Int { val mid = (left + right) shr 1 nums[mid] = nums[left + 1].also { nums[left + 1] = nums[mid] } - + if (nums[left] < nums[right]) nums[left] = nums[right].also { nums[right] = nums[left] } if (nums[left + 1] < nums[right]) nums[left + 1] = nums[right].also { nums[right] = nums[left + 1] } if (nums[left] < nums[left + 1]) nums[left] = nums[left + 1].also { nums[left + 1] = nums[left] } - + val pivot = nums[left + 1] var i = left + 1 var j = right - + while (true) { while (nums[++i] > pivot); while (nums[--j] < pivot); if (i > j) break nums[i] = nums[j].also { nums[j] = nums[i] } } - + nums[left + 1] = nums[j] nums[j] = pivot return j } - + private fun quickSelect(nums: IntArray, k: Int): Int { var left = 0 var right = nums.size - 1 - + while (true) { if (right <= left + 1) { if (right == left + 1 && nums[right] > nums[left]) nums[left] = nums[right].also { nums[right] = nums[left] } return nums[k] } - + val j = partition(nums, left, right) - + if (j >= k) right = j - 1 if (j <= k) left = j + 1 } } - + fun findKthLargest(nums: IntArray, k: Int): Int { return quickSelect(nums, k - 1) } } ``` +```swift +class Solution { + func partition(_ nums: inout [Int], _ left: Int, _ right: Int) -> Int { + let mid = (left + right) >> 1 + nums.swapAt(mid, left + 1) + + if nums[left] < nums[right] { + nums.swapAt(left, right) + } + if nums[left + 1] < nums[right] { + nums.swapAt(left + 1, right) + } + if nums[left] < nums[left + 1] { + nums.swapAt(left, left + 1) + } + + let pivot = nums[left + 1] + var i = left + 1 + var j = right + + while true { + repeat { i += 1 } while nums[i] > pivot + repeat { j -= 1 } while nums[j] < pivot + + if i > j { + break + } + nums.swapAt(i, j) + } + + nums.swapAt(left + 1, j) + return j + } + + func quickSelect(_ nums: inout [Int], _ k: Int) -> Int { + var left = 0 + var right = nums.count - 1 + + while true { + if right <= left + 1 { + if right == left + 1 && nums[right] > nums[left] { + nums.swapAt(left, right) + } + return nums[k] + } + + let j = partition(&nums, left, right) + + if j >= k { + right = j - 1 + } + if j <= k { + left = j + 1 + } + } + } + + func findKthLargest(_ nums: [Int], _ k: Int) -> Int { + var nums = nums + return quickSelect(&nums, k - 1) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ in average case, $O(n ^ 2)$ in worst case. -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ in average case, $O(n ^ 2)$ in worst case. +- Space complexity: $O(1)$ diff --git a/articles/kth-largest-integer-in-a-stream.md b/articles/kth-largest-integer-in-a-stream.md index 7913b93ca..60191a21c 100644 --- a/articles/kth-largest-integer-in-a-stream.md +++ b/articles/kth-largest-integer-in-a-stream.md @@ -26,7 +26,7 @@ class KthLargest { arr.add(nums[i]); } } - + public int add(int val) { arr.add(val); Collections.sort(arr); @@ -44,7 +44,7 @@ public: this->arr = nums; this->k = k; } - + int add(int val) { arr.push_back(val); sort(arr.begin(), arr.end()); @@ -124,12 +124,32 @@ class KthLargest(k: Int, nums: IntArray) { } ``` +```swift +class KthLargest { + private var k: Int + private var arr: [Int] + + init(_ k: Int, _ nums: [Int]) { + self.k = k + self.arr = nums + } + + func add(_ val: Int) -> Int { + arr.append(val) + arr.sort() + return arr[arr.count - k] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n\log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(m * n\log n)$ +- Space complexity: + - $O(m)$ extra space. + - $O(1)$ or $O(n)$ space depending on the sorting algorithm. > Where $m$ is the number of calls made to $add()$ and $n$ is the current size of the array. @@ -141,7 +161,7 @@ class KthLargest(k: Int, nums: IntArray) { ```python class KthLargest: - + def __init__(self, k: int, nums: List[int]): self.minHeap, self.k = nums, k heapq.heapify(self.minHeap) @@ -157,7 +177,7 @@ class KthLargest: ```java class KthLargest { - + private PriorityQueue minHeap; private int k; @@ -248,7 +268,7 @@ class KthLargest { ```csharp public class KthLargest { - + private PriorityQueue minHeap; private int k; @@ -324,11 +344,37 @@ class KthLargest(k: Int, nums: IntArray) { } ``` +```swift +class KthLargest { + private var minHeap: Heap + private let k: Int + + init(_ k: Int, _ nums: [Int]) { + self.k = k + self.minHeap = Heap() + for num in nums { + minHeap.insert(num) + if minHeap.count > k { + minHeap.popMin() + } + } + } + + func add(_ val: Int) -> Int { + minHeap.insert(val) + if minHeap.count > k { + minHeap.popMin() + } + return minHeap.min! + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * \log k)$ -* Space complexity: $O(k)$ +- Time complexity: $O(m * \log k)$ +- Space complexity: $O(k)$ -> Where $m$ is the number of calls made to $add()$. \ No newline at end of file +> Where $m$ is the number of calls made to $add()$. diff --git a/articles/kth-smallest-integer-in-bst.md b/articles/kth-smallest-integer-in-bst.md index 1014ba6d4..0de482d68 100644 --- a/articles/kth-smallest-integer-in-bst.md +++ b/articles/kth-smallest-integer-in-bst.md @@ -17,11 +17,11 @@ class Solution: def dfs(node): if not node: return - + arr.append(node.val) dfs(node.left) dfs(node.right) - + dfs(root) arr.sort() return arr[k - 1] @@ -47,7 +47,7 @@ class Solution: public class Solution { public int kthSmallest(TreeNode root, int k) { List arr = new ArrayList<>(); - + dfs(root, arr); Collections.sort(arr); return arr.get(k - 1); @@ -177,18 +177,18 @@ public class Solution { */ func kthSmallest(root *TreeNode, k int) int { var arr []int - + var dfs func(node *TreeNode) dfs = func(node *TreeNode) { if node == nil { return } - + dfs(node.Left) arr = append(arr, node.Val) dfs(node.Right) } - + dfs(root) return arr[k-1] } @@ -207,17 +207,17 @@ func kthSmallest(root *TreeNode, k int) int { */ class Solution { private val arr = mutableListOf() - + fun kthSmallest(root: TreeNode?, k: Int): Int { dfs(root) return arr[k - 1] } - + private fun dfs(node: TreeNode?) { if (node == null) { return } - + dfs(node.left) arr.add(node.`val`) dfs(node.right) @@ -225,12 +225,46 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func kthSmallest(_ root: TreeNode?, _ k: Int) -> Int { + var arr = [Int]() + + func dfs(_ node: TreeNode?) { + guard let node = node else { return } + arr.append(node.val) + dfs(node.left) + dfs(node.right) + } + + dfs(root) + arr.sort() + return arr[k - 1] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -253,11 +287,11 @@ class Solution: def dfs(node): if not node: return - + dfs(node.left) arr.append(node.val) dfs(node.right) - + dfs(root) return arr[k - 1] ``` @@ -282,7 +316,7 @@ class Solution: public class Solution { public int kthSmallest(TreeNode root, int k) { List arr = new ArrayList<>(); - + dfs(root, arr); return arr.get(k - 1); } @@ -408,18 +442,18 @@ public class Solution { */ func kthSmallest(root *TreeNode, k int) int { var arr []int - + var dfs func(node *TreeNode) dfs = func(node *TreeNode) { if node == nil { return } - + dfs(node.Left) arr = append(arr, node.Val) dfs(node.Right) } - + dfs(root) return arr[k-1] } @@ -438,17 +472,17 @@ func kthSmallest(root *TreeNode, k int) int { */ class Solution { private val arr = mutableListOf() - + fun kthSmallest(root: TreeNode?, k: Int): Int { dfs(root) return arr[k - 1] } - + private fun dfs(node: TreeNode?) { if (node == null) { return } - + dfs(node.left) arr.add(node.`val`) dfs(node.right) @@ -456,12 +490,45 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func kthSmallest(_ root: TreeNode?, _ k: Int) -> Int { + var arr = [Int]() + + func dfs(_ node: TreeNode?) { + guard let node = node else { return } + dfs(node.left) + arr.append(node.val) + dfs(node.right) + } + + dfs(root) + return arr[k - 1] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -486,14 +553,14 @@ class Solution: nonlocal cnt, res if not node: return - + dfs(node.left) cnt -= 1 if cnt == 0: res = node.val return dfs(node.right) - + dfs(root) return res ``` @@ -663,13 +730,13 @@ public class Solution { */ func kthSmallest(root *TreeNode, k int) int { cnt, res := k, 0 - + var dfs func(node *TreeNode) dfs = func(node *TreeNode) { if node == nil { return } - + dfs(node.Left) cnt-- if cnt == 0 { @@ -678,7 +745,7 @@ func kthSmallest(root *TreeNode, k int) int { } dfs(node.Right) } - + dfs(root) return res } @@ -698,18 +765,18 @@ func kthSmallest(root *TreeNode, k int) int { class Solution { private var cnt = 0 private var res = 0 - + fun kthSmallest(root: TreeNode?, k: Int): Int { cnt = k dfs(root) return res } - + private fun dfs(node: TreeNode?) { if (node == null) { return } - + dfs(node.left) cnt-- if (cnt == 0) { @@ -721,12 +788,51 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func kthSmallest(_ root: TreeNode?, _ k: Int) -> Int { + var cnt = k + var res = root!.val + + func dfs(_ node: TreeNode?) { + guard let node = node else { return } + + dfs(node.left) + cnt -= 1 + if cnt == 0 { + res = node.val + return + } + dfs(node.right) + } + + dfs(root) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -831,7 +937,7 @@ public: curr = curr->right; } - return -1; + return -1; } }; ``` @@ -924,25 +1030,25 @@ public class Solution { func kthSmallest(root *TreeNode, k int) int { stack := []*TreeNode{} curr := root - + for len(stack) > 0 || curr != nil { for curr != nil { stack = append(stack, curr) curr = curr.Left } - + curr = stack[len(stack)-1] stack = stack[:len(stack)-1] - + k-- if k == 0 { return curr.Val } - + curr = curr.Right } - - return 0 + + return 0 } ``` @@ -962,23 +1068,62 @@ class Solution { val stack = mutableListOf() var curr: TreeNode? = root var k = k - + while (stack.isNotEmpty() || curr != null) { while (curr != null) { stack.add(curr) curr = curr.left } - + curr = stack.removeLast() k-- if (k == 0) { return curr.`val` } - + curr = curr.right } - - return 0 + + return 0 + } +} +``` + +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func kthSmallest(_ root: TreeNode?, _ k: Int) -> Int { + var stack = [TreeNode]() + var curr = root + var k = k + + while !stack.isEmpty || curr != nil { + while curr != nil { + stack.append(curr!) + curr = curr?.left + } + curr = stack.removeLast() + k -= 1 + if k == 0 { + return curr!.val + } + curr = curr?.right + } + return -1 } } ``` @@ -987,8 +1132,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -1007,7 +1152,7 @@ class Solution { class Solution: def kthSmallest(self, root: Optional[TreeNode], k: int) -> int: curr = root - + while curr: if not curr.left: k -= 1 @@ -1018,7 +1163,7 @@ class Solution: pred = curr.left while pred.right and pred.right != curr: pred = pred.right - + if not pred.right: pred.right = curr curr = curr.left @@ -1029,7 +1174,7 @@ class Solution: return curr.val curr = curr.right - return -1 + return -1 ``` ```java @@ -1052,7 +1197,7 @@ class Solution: public class Solution { public int kthSmallest(TreeNode root, int k) { TreeNode curr = root; - + while (curr != null) { if (curr.left == null) { k--; @@ -1062,7 +1207,7 @@ public class Solution { TreeNode pred = curr.left; while (pred.right != null && pred.right != curr) pred = pred.right; - + if (pred.right == null) { pred.right = curr; curr = curr.left; @@ -1096,7 +1241,7 @@ class Solution { public: int kthSmallest(TreeNode* root, int k) { TreeNode* curr = root; - + while (curr) { if (!curr->left) { k--; @@ -1106,7 +1251,7 @@ public: TreeNode* pred = curr->left; while (pred->right && pred->right != curr) pred = pred->right; - + if (!pred->right) { pred->right = curr; curr = curr->left; @@ -1143,7 +1288,7 @@ class Solution { */ kthSmallest(root, k) { let curr = root; - + while (curr) { if (!curr.left) { k--; @@ -1151,9 +1296,8 @@ class Solution { curr = curr.right; } else { let pred = curr.left; - while (pred.right && pred.right !== curr) - pred = pred.right; - + while (pred.right && pred.right !== curr) pred = pred.right; + if (!pred.right) { pred.right = curr; curr = curr.left; @@ -1188,7 +1332,7 @@ class Solution { public class Solution { public int KthSmallest(TreeNode root, int k) { TreeNode curr = root; - + while (curr != null) { if (curr.left == null) { k--; @@ -1198,7 +1342,7 @@ public class Solution { TreeNode pred = curr.left; while (pred.right != null && pred.right != curr) pred = pred.right; - + if (pred.right == null) { pred.right = curr; curr = curr.left; @@ -1298,9 +1442,61 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func kthSmallest(_ root: TreeNode?, _ k: Int) -> Int { + var curr = root + var k = k + + while curr != nil { + if curr?.left == nil { + k -= 1 + if k == 0 { + return curr!.val + } + curr = curr?.right + } else { + var pred = curr?.left + while pred?.right != nil && pred?.right !== curr { + pred = pred?.right + } + + if pred?.right == nil { + pred?.right = curr + curr = curr?.left + } else { + pred?.right = nil + k -= 1 + if k == 0 { + return curr!.val + } + curr = curr?.right + } + } + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/kth-smallest-product-of-two-sorted-arrays.md b/articles/kth-smallest-product-of-two-sorted-arrays.md new file mode 100644 index 000000000..7fb3d255b --- /dev/null +++ b/articles/kth-smallest-product-of-two-sorted-arrays.md @@ -0,0 +1,738 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def kthSmallestProduct(self, nums1: List[int], nums2: List[int], k: int) -> int: + prod = [] + + for i in range(len(nums1)): + for j in range(len(nums2)): + prod.append(nums1[i] * nums2[j]) + + prod.sort() + return prod[k - 1] +``` + +```java +public class Solution { + public long kthSmallestProduct(int[] nums1, int[] nums2, long k) { + int n = nums1.length, m = nums2.length; + long[] prod = new long[n * m]; + int idx = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + prod[idx++] = 1L * nums1[i] * nums2[j]; + } + } + Arrays.sort(prod); + return prod[(int)k - 1]; + } +} +``` + +```cpp +class Solution { +public: + long long kthSmallestProduct(vector& nums1, vector& nums2, long long k) { + int n = nums1.size(), m = nums2.size(); + vector prod; + prod.reserve((size_t)n * m); + for (int x : nums1) { + for (int y : nums2) { + prod.push_back(1LL * x * y); + } + } + sort(prod.begin(), prod.end()); + return prod[k - 1]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ + kthSmallestProduct(nums1, nums2, k) { + const prod = []; + for (let x of nums1) { + for (let y of nums2) { + prod.push(x * y); + } + } + prod.sort((a, b) => a - b); + return prod[k - 1]; + } +} +``` + +```csharp +public class Solution { + public long KthSmallestProduct(int[] nums1, int[] nums2, long k) { + int n = nums1.Length, m = nums2.Length; + long[] prod = new long[n * m]; + int idx = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < m; j++) { + prod[idx++] = (long)nums1[i] * nums2[j]; + } + } + Array.Sort(prod); + return prod[k - 1]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(m * n)$ + +> Where $m$ and $n$ are the lengths of the arrays $nums1$ and $nums2$, respectively. + +--- + +## 2. Binary Search + +::tabs-start + +```python +class Solution: + def kthSmallestProduct(self, nums1: List[int], nums2: List[int], k: int) -> int: + def count(prod): + cnt = 0 + n2 = len(nums2) + for a in nums1: + if a > 0: + cnt += bisect.bisect_right(nums2, prod // a) + elif a < 0: + threshold = math.ceil(prod / a) + idx = bisect.bisect_left(nums2, threshold) + cnt += n2 - idx + else: + if prod >= 0: + cnt += n2 + return cnt + + + l, r = -(10**10), 10**10 + while l <= r: + m = l + (r - l) // 2 + if count(m) < k: + l = m + 1 + else: + r = m - 1 + return l +``` + +```java +public class Solution { + public long kthSmallestProduct(int[] nums1, int[] nums2, long k) { + long left = -10_000_000_000L, right = 10_000_000_000L; + while (left <= right) { + long mid = left + (right - left) / 2; + if (count(nums1, nums2, mid) < k) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return left; + } + + private long count(int[] nums1, int[] nums2, long prod) { + long cnt = 0; + int n2 = nums2.length; + for (int a : nums1) { + if (a > 0) { + long bound = Math.floorDiv(prod, a); + cnt += upperBound(nums2, bound); + } else if (a < 0) { + double div = (double) prod / a; + long threshold = (long) Math.ceil(div); + cnt += n2 - lowerBound(nums2, threshold); + } else { + if (prod >= 0) { + cnt += n2; + } + } + } + return cnt; + } + + private int lowerBound(int[] arr, long target) { + int l = 0, r = arr.length; + while (l < r) { + int m = (l + r) / 2; + if (arr[m] < target) l = m + 1; + else r = m; + } + return l; + } + + private int upperBound(int[] arr, long target) { + int l = 0, r = arr.length; + while (l < r) { + int m = (l + r) / 2; + if (arr[m] <= target) l = m + 1; + else r = m; + } + return l; + } +} +``` + +```cpp +class Solution { +public: + long long kthSmallestProduct(vector& nums1, vector& nums2, long long k) { + long long left = -10000000000LL, right = 10000000000LL; + while (left <= right) { + long long mid = left + (right - left) / 2; + if (count(nums1, nums2, mid) < k) left = mid + 1; + else right = mid - 1; + } + return left; + } + +private: + long long count(vector& nums1, vector& nums2, long long prod) { + long long cnt = 0; + int n2 = nums2.size(); + for (int a : nums1) { + if (a > 0) { + long long bound = prod >= 0 + ? prod / a + : -(( -prod + a - 1) / a); + cnt += upper_bound(nums2.begin(), nums2.end(), bound) - nums2.begin(); + } else if (a < 0) { + long long threshold = (long long)ceil((long double)prod / a); + cnt += n2 - (lower_bound(nums2.begin(), nums2.end(), threshold) - nums2.begin()); + } else { + if (prod >= 0) cnt += n2; + } + } + return cnt; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ + kthSmallestProduct(nums1, nums2, k) { + const lowerBound = (arr, target) => { + let l = 0, r = arr.length; + while (l < r) { + const m = (l + r) >>> 1; + if (arr[m] < target) l = m + 1; + else r = m; + } + return l; + }; + + const upperBound = (arr, target) => { + let l = 0, r = arr.length; + while (l < r) { + const m = (l + r) >>> 1; + if (arr[m] <= target) l = m + 1; + else r = m; + } + return l; + }; + + let left = -1e10, right = 1e10; + const n2 = nums2.length; + while (left < right) { + const mid = Math.floor((left + right) / 2); + let cnt = 0; + for (const a of nums1) { + if (a > 0) { + cnt += upperBound(nums2, Math.floor(mid / a)); + } else if (a < 0) { + cnt += n2 - lowerBound(nums2, Math.ceil(mid / a)); + } else if (mid >= 0) { + cnt += n2; + } + if (cnt >= k) break; + } + if (cnt < k) left = mid + 1; + else right = mid; + } + return left; + } +} +``` + +```csharp +public class Solution { + public long KthSmallestProduct(int[] nums1, int[] nums2, long k) { + long left = -10000000000L, right = 10000000000L; + while (left <= right) { + long mid = left + (right - left) / 2; + if (Count(nums1, nums2, mid) < k) left = mid + 1; + else right = mid - 1; + } + return left; + } + + private long Count(int[] nums1, int[] nums2, long prod) { + long cnt = 0; + int n2 = nums2.Length; + foreach (int a in nums1) { + if (a > 0) { + long bound = prod >= 0 + ? prod / a + : -(( -prod + a - 1) / a); + cnt += UpperBound(nums2, bound); + } else if (a < 0) { + long threshold = (long)Math.Ceiling((double)prod / a); + cnt += n2 - LowerBound(nums2, threshold); + } else { + if (prod >= 0) cnt += n2; + } + } + return cnt; + } + + private int LowerBound(int[] arr, long target) { + int l = 0, r = arr.Length; + while (l < r) { + int m = (l + r) >> 1; + if (arr[m] < target) l = m + 1; + else r = m; + } + return l; + } + + private int UpperBound(int[] arr, long target) { + int l = 0, r = arr.Length; + while (l < r) { + int m = (l + r) >> 1; + if (arr[m] <= target) l = m + 1; + else r = m; + } + return l; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m \log (\log N))$ +* Space complexity: $O(1)$ + +> Where $m$ and $n$ are the lengths of the arrays $nums1$ and $nums2$, respectively. $N$ is the size of the range of the product. + +--- + +## 3. Binary Search + Two Pointers + +::tabs-start + +```python +class Solution: + def kthSmallestProduct(self, nums1: List[int], nums2: List[int], k: int) -> int: + n1, n2 = len(nums1), len(nums2) + pos1 = 0 # first non-negative in nums1 + while pos1 < n1 and nums1[pos1] < 0: + pos1 += 1 + + pos2 = 0 # first non-negative in nums2 + while pos2 < n2 and nums2[pos2] < 0: + pos2 += 1 + + def count(prod): + cnt = 0 + + # negative * negative -> positive + i, j = 0, pos2 - 1 + while i < pos1 and j >= 0: + if nums1[i] * nums2[j] > prod: + i += 1 + else: + cnt += (pos1 - i) + j -= 1 + + # positive * positive -> positive + i, j = pos1, n2 - 1 + while i < n1 and j >= pos2: + if nums1[i] * nums2[j] > prod: + j -= 1 + else: + cnt += (j - pos2 + 1) + i += 1 + + # negative * positive -> negative + i, j = 0, pos2 + while i < pos1 and j < n2: + if nums1[i] * nums2[j] > prod: + j += 1 + else: + cnt += (n2 - j) + i += 1 + + # positive * negative → negative + i, j = pos1, 0 + while i < n1 and j < pos2: + if nums1[i] * nums2[j] > prod: + i += 1 + else: + cnt += (n1 - i) + j += 1 + + return cnt + + left, right = -10**10, 10**10 + while left <= right: + mid = (left + right) // 2 + if count(mid) < k: + left = mid + 1 + else: + right = mid - 1 + + return left +``` + +```java +public class Solution { + public long kthSmallestProduct(int[] nums1, int[] nums2, long k) { + int n1 = nums1.length, n2 = nums2.length; + int pos1 = 0; // first non-negative in nums1 + while (pos1 < n1 && nums1[pos1] < 0) { + pos1++; + } + int pos2 = 0; // first non-negative in nums2 + while (pos2 < n2 && nums2[pos2] < 0) { + pos2++; + } + + long left = -10_000_000_000L, right = 10_000_000_000L; + while (left <= right) { + long mid = left + (right - left) / 2; + if (count(nums1, nums2, pos1, pos2, n1, n2, mid) < k) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return left; + } + + private long count(int[] nums1, int[] nums2, + int pos1, int pos2, int n1, int n2, + long prod) { + long cnt = 0; + + // negative * negative -> positive + int i = 0, j = pos2 - 1; + while (i < pos1 && j >= 0) { + if ((long)nums1[i] * nums2[j] > prod) { + i++; + } else { + cnt += (pos1 - i); + j--; + } + } + + // positive * positive -> positive + i = pos1; j = n2 - 1; + while (i < n1 && j >= pos2) { + if ((long)nums1[i] * nums2[j] > prod) { + j--; + } else { + cnt += (j - pos2 + 1); + i++; + } + } + + // negative * positive -> negative + i = 0; j = pos2; + while (i < pos1 && j < n2) { + if ((long)nums1[i] * nums2[j] > prod) { + j++; + } else { + cnt += (n2 - j); + i++; + } + } + + // positive * negative -> negative + i = pos1; j = 0; + while (i < n1 && j < pos2) { + if ((long)nums1[i] * nums2[j] > prod) { + i++; + } else { + cnt += (n1 - i); + j++; + } + } + + return cnt; + } +} +``` + +```cpp +class Solution { +public: + long long kthSmallestProduct(vector& nums1, vector& nums2, long long k) { + int n1 = nums1.size(), n2 = nums2.size(); + int pos1 = 0; // first non-negative in nums1 + while (pos1 < n1 && nums1[pos1] < 0) { + pos1++; + } + int pos2 = 0; // first non-negative in nums2 + while (pos2 < n2 && nums2[pos2] < 0) { + pos2++; + } + + long long left = -10000000000LL, right = 10000000000LL; + while (left <= right) { + long long mid = left + (right - left) / 2; + if (count(nums1, nums2, pos1, pos2, n1, n2, mid) < k) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return left; + } + +private: + long long count(const vector& nums1, const vector& nums2, + int pos1, int pos2, int n1, int n2, + long long prod) { + long long cnt = 0; + + // negative * negative -> positive + int i = 0, j = pos2 - 1; + while (i < pos1 && j >= 0) { + if ((long long)nums1[i] * nums2[j] > prod) { + i++; + } else { + cnt += (pos1 - i); + j--; + } + } + + // positive * positive -> positive + i = pos1; j = n2 - 1; + while (i < n1 && j >= pos2) { + if ((long long)nums1[i] * nums2[j] > prod) { + j--; + } else { + cnt += (j - pos2 + 1); + i++; + } + } + + // negative * positive -> negative + i = 0; j = pos2; + while (i < pos1 && j < n2) { + if ((long long)nums1[i] * nums2[j] > prod) { + j++; + } else { + cnt += (n2 - j); + i++; + } + } + + // positive * negative -> negative + i = pos1; j = 0; + while (i < n1 && j < pos2) { + if ((long long)nums1[i] * nums2[j] > prod) { + i++; + } else { + cnt += (n1 - i); + j++; + } + } + + return cnt; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ + kthSmallestProduct(nums1, nums2, k) { + const n1 = nums1.length, n2 = nums2.length; + + let pos1 = 0; // first non-negative in nums1 + while (pos1 < n1 && nums1[pos1] < 0) { + pos1++; + } + let pos2 = 0; // first non-negative in nums2 + while (pos2 < n2 && nums2[pos2] < 0) { + pos2++; + } + + let left = -1e10, right = 1e10; + while (left <= right) { + const mid = left + Math.floor((right - left) / 2); + let cnt = 0; + + // negative * negative -> positive + let i = 0, j = pos2 - 1; + while (i < pos1 && j >= 0) { + if (nums1[i] * nums2[j] > mid) { + i++; + } else { + cnt += (pos1 - i); + j--; + } + } + + // positive * positive -> positive + i = pos1; j = n2 - 1; + while (i < n1 && j >= pos2) { + if (nums1[i] * nums2[j] > mid) { + j--; + } else { + cnt += (j - pos2 + 1); + i++; + } + } + + // negative * positive -> negative + i = 0; j = pos2; + while (i < pos1 && j < n2) { + if (nums1[i] * nums2[j] > mid) { + j++; + } else { + cnt += (n2 - j); + i++; + } + } + + // positive * negative -> negative + i = pos1; j = 0; + while (i < n1 && j < pos2) { + if (nums1[i] * nums2[j] > mid) { + i++; + } else { + cnt += (n1 - i); + j++; + } + } + + if (cnt < k) { + left = mid + 1; + } else { + right = mid - 1; + } + } + + return left; + } +} +``` + +```csharp +public class Solution { + public long KthSmallestProduct(int[] nums1, int[] nums2, long k) { + int n1 = nums1.Length, n2 = nums2.Length; + int pos1 = 0; // first non-negative in nums1 + while (pos1 < n1 && nums1[pos1] < 0) { + pos1++; + } + int pos2 = 0; // first non-negative in nums2 + while (pos2 < n2 && nums2[pos2] < 0) { + pos2++; + } + + long left = -10000000000L, right = 10000000000L; + while (left <= right) { + long mid = left + (right - left) / 2; + if (count(nums1, nums2, pos1, pos2, n1, n2, mid) < k) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return left; + } + + private long count(int[] nums1, int[] nums2, + int pos1, int pos2, int n1, int n2, + long prod) { + long cnt = 0; + + // negative * negative -> positive + int i = 0, j = pos2 - 1; + while (i < pos1 && j >= 0) { + if ((long)nums1[i] * nums2[j] > prod) { + i++; + } else { + cnt += (pos1 - i); + j--; + } + } + + // positive * positive -> positive + i = pos1; j = n2 - 1; + while (i < n1 && j >= pos2) { + if ((long)nums1[i] * nums2[j] > prod) { + j--; + } else { + cnt += (j - pos2 + 1); + i++; + } + } + + // negative * positive -> negative + i = 0; j = pos2; + while (i < pos1 && j < n2) { + if ((long)nums1[i] * nums2[j] > prod) { + j++; + } else { + cnt += (n2 - j); + i++; + } + } + + // positive * negative -> negative + i = pos1; j = 0; + while (i < n1 && j < pos2) { + if ((long)nums1[i] * nums2[j] > prod) { + i++; + } else { + cnt += (n1 - i); + j++; + } + } + + return cnt; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O((m + n) \log N)$ +* Space complexity: $O(1)$ + +> Where $m$ and $n$ are the lengths of the arrays $nums1$ and $nums2$, respectively. $N$ is the size of the range of the product. \ No newline at end of file diff --git a/articles/largest-3-same-digit-number-in-string.md b/articles/largest-3-same-digit-number-in-string.md index f96e85ee3..003c5690a 100644 --- a/articles/largest-3-same-digit-number-in-string.md +++ b/articles/largest-3-same-digit-number-in-string.md @@ -7,14 +7,14 @@ class Solution: def largestGoodInteger(self, num: str) -> str: res = "" val = 0 - + for i in range(len(num) - 2): if num[i] == num[i + 1] == num[i + 2]: tmp = num[i : i + 3] if val <= int(tmp): val = int(tmp) res = tmp - + return res ``` @@ -23,9 +23,9 @@ public class Solution { public String largestGoodInteger(String num) { String res = ""; int val = 0; - + for (int i = 0; i < num.length() - 2; i++) { - if (num.charAt(i) == num.charAt(i + 1) && + if (num.charAt(i) == num.charAt(i + 1) && num.charAt(i) == num.charAt(i + 2)) { String tmp = num.substring(i, i + 3); if (val <= Integer.parseInt(tmp)) { @@ -34,7 +34,7 @@ public class Solution { } } } - + return res; } } @@ -46,7 +46,7 @@ public: string largestGoodInteger(string num) { string res = ""; int val = 0; - + for (int i = 0; i < num.length() - 2; i++) { if (num[i] == num[i + 1] && num[i] == num[i + 2]) { string tmp = num.substr(i, 3); @@ -56,7 +56,7 @@ public: } } } - + return res; } }; @@ -69,9 +69,9 @@ class Solution { * @return {string} */ largestGoodInteger(num) { - let res = ""; + let res = ''; let val = 0; - + for (let i = 0; i < num.length - 2; i++) { if (num[i] === num[i + 1] && num[i] === num[i + 2]) { const tmp = num.slice(i, i + 3); @@ -81,7 +81,7 @@ class Solution { } } } - + return res; } } @@ -91,8 +91,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -104,11 +104,11 @@ class Solution { class Solution: def largestGoodInteger(self, num: str) -> str: res = "0" - + for i in range(len(num) - 2): if num[i] == num[i + 1] == num[i + 2]: res = max(res, num[i : i + 3]) - + return "" if res == "0" else res ``` @@ -116,9 +116,9 @@ class Solution: public class Solution { public String largestGoodInteger(String num) { String res = ""; - + for (int i = 0; i < num.length() - 2; i++) { - if (num.charAt(i) == num.charAt(i + 1) && + if (num.charAt(i) == num.charAt(i + 1) && num.charAt(i) == num.charAt(i + 2)) { String curr = num.substring(i, i + 3); if (curr.compareTo(res) > 0) { @@ -126,7 +126,7 @@ public class Solution { } } } - + return res; } } @@ -137,13 +137,13 @@ class Solution { public: string largestGoodInteger(string num) { string res = "0"; - + for (int i = 0; i < num.length() - 2; i++) { if (num[i] == num[i + 1] && num[i] == num[i + 2]) { res = max(res, num.substr(i, 3)); } } - + return res == "0" ? "" : res; } }; @@ -156,15 +156,15 @@ class Solution { * @return {string} */ largestGoodInteger(num) { - let res = "0"; - + let res = '0'; + for (let i = 0; i < num.length - 2; i++) { if (num[i] === num[i + 1] && num[i] === num[i + 2]) { res = res > num.slice(i, i + 3) ? res : num.slice(i, i + 3); } } - - return res === "0" ? "" : res; + + return res === '0' ? '' : res; } } ``` @@ -173,8 +173,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -186,7 +186,7 @@ class Solution { class Solution: def largestGoodInteger(self, num: str) -> str: res = -1 - + for i in range(len(num) - 2): if num[i] == num[i + 1] == num[i + 2]: res = max(res, int(num[i])) @@ -199,7 +199,7 @@ public class Solution { int res = -1; for (int i = 0; i < num.length() - 2; i++) { - if (num.charAt(i) == num.charAt(i + 1) && + if (num.charAt(i) == num.charAt(i + 1) && num.charAt(i) == num.charAt(i + 2)) { res = Math.max(res, num.charAt(i) - '0'); } @@ -242,7 +242,7 @@ class Solution { } } - return res !== -1 ? String(res).repeat(3) : ""; + return res !== -1 ? String(res).repeat(3) : ''; } } ``` @@ -251,5 +251,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/largest-color-value-in-a-directed-graph.md b/articles/largest-color-value-in-a-directed-graph.md new file mode 100644 index 000000000..759487709 --- /dev/null +++ b/articles/largest-color-value-in-a-directed-graph.md @@ -0,0 +1,590 @@ +## 1. Brute Force (DFS) + +::tabs-start + +```python +class Solution: + def largestPathValue(self, colors: str, edges: list[list[int]]) -> int: + n = len(colors) + adj = [[] for _ in range(n)] + for u, v in edges: + adj[u].append(v) + + visit = [False] * n + def dfs(node, c): + if visit[node]: + return float("inf") + + visit[node] = True + clrCnt = 0 + for nei in adj[node]: + cur = dfs(nei, c) + if cur == float("inf"): + return cur + clrCnt = max(clrCnt, cur) + visit[node] = False + return clrCnt + (c == (ord(colors[node]) - ord('a'))) + + res = -1 + for i in range(n): + for c in range(26): + cnt = dfs(i, c) + if cnt == float("inf"): + return -1 + res = max(res, cnt) + return res +``` + +```java +public class Solution { + private int n; + private List[] adj; + private boolean[] visit; + + public int largestPathValue(String colors, int[][] edges) { + this.n = colors.length(); + this.adj = new ArrayList[n]; + this.visit = new boolean[n]; + + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + } + + int res = -1; + for (int i = 0; i < n; i++) { + for (int c = 0; c < 26; c++) { + int cnt = dfs(i, c, colors); + if (cnt == Integer.MAX_VALUE) return -1; + res = Math.max(res, cnt); + } + } + return res; + } + + private int dfs(int node, int c, String colors) { + if (visit[node]) return Integer.MAX_VALUE; + + visit[node] = true; + int clrCnt = 0; + for (int nei : adj[node]) { + int cur = dfs(nei, c, colors); + if (cur == Integer.MAX_VALUE) return cur; + clrCnt = Math.max(clrCnt, cur); + } + visit[node] = false; + return clrCnt + ((colors.charAt(node) - 'a') == c ? 1 : 0); + } +} +``` + +```cpp +class Solution { +public: + int n; + vector> adj; + vector visit; + + int largestPathValue(string colors, vector>& edges) { + n = colors.size(); + adj.assign(n, vector()); + visit.assign(n, false); + + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + } + + int res = -1; + for (int i = 0; i < n; i++) { + for (int c = 0; c < 26; c++) { + int cnt = dfs(i, c, colors); + if (cnt == 1e9) return -1; + res = max(res, cnt); + } + } + return res; + } + +private: + int dfs(int node, int c, string& colors) { + if (visit[node]) return 1e9; + + visit[node] = true; + int clrCnt = 0; + for (int nei : adj[node]) { + int cur = dfs(nei, c, colors); + if (cur == 1e9) return cur; + clrCnt = max(clrCnt, cur); + } + visit[node] = false; + return clrCnt + ((colors[node] - 'a') == c ? 1 : 0); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @param {number[][]} edges + * @return {number} + */ + largestPathValue(colors, edges) { + const n = colors.length; + const adj = Array.from({ length: n }, () => []); + for (const [u, v] of edges) { + adj[u].push(v); + } + + const visit = new Array(n).fill(false); + const dfs = (node, c) => { + if (visit[node]) return Infinity; + + visit[node] = true; + let clrCnt = 0; + for (const nei of adj[node]) { + const cur = dfs(nei, c); + if (cur === Infinity) return cur; + clrCnt = Math.max(clrCnt, cur); + } + visit[node] = false; + return clrCnt + (c === colors.charCodeAt(node) - 97 ? 1 : 0); + }; + + let res = -1; + for (let i = 0; i < n; i++) { + for (let c = 0; c < 26; c++) { + const cnt = dfs(i, c); + if (cnt === Infinity) return -1; + res = Math.max(res, cnt); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V * (V + E))$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of verticies and $E$ is the number of edges. + +--- + +## 2. Depth First Search + +::tabs-start + +```python +class Solution: + def largestPathValue(self, colors: str, edges: list[list[int]]) -> int: + adj = defaultdict(list) + for src, dst in edges: + adj[src].append(dst) + + def dfs(node): + if node in path: + return float("inf") + if node in visit: + return 0 + + visit.add(node) + path.add(node) + colorIndex = ord(colors[node]) - ord('a') + count[node][colorIndex] = 1 + + for nei in adj[node]: + if dfs(nei) == float("inf"): + return float("inf") + for c in range(26): + count[node][c] = max( + count[node][c], + (1 if c == colorIndex else 0) + count[nei][c] + ) + + path.remove(node) + return 0 + + n, res = len(colors), 0 + visit, path = set(), set() + count = [[0] * 26 for _ in range(n)] + + for i in range(n): + if dfs(i) == float("inf"): + return -1 + res = max(res, max(count[i])) + + return res +``` + +```java +public class Solution { + private int n; + private List[] adj; + private boolean[] visit, path; + private int[][] count; + + public int largestPathValue(String colors, int[][] edges) { + this.n = colors.length(); + this.adj = new ArrayList[n]; + this.visit = new boolean[n]; + this.path = new boolean[n]; + this.count = new int[n][26]; + + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + } + + int res = 0; + for (int i = 0; i < n; i++) { + if (dfs(i, colors) == Integer.MAX_VALUE) return -1; + for (int c = 0; c < 26; c++) { + res = Math.max(res, count[i][c]); + } + } + return res; + } + + private int dfs(int node, String colors) { + if (path[node]) return Integer.MAX_VALUE; + if (visit[node]) return 0; + + visit[node] = true; + path[node] = true; + int colorIndex = colors.charAt(node) - 'a'; + count[node][colorIndex] = 1; + + for (int nei : adj[node]) { + if (dfs(nei, colors) == Integer.MAX_VALUE) { + return Integer.MAX_VALUE; + } + for (int c = 0; c < 26; c++) { + count[node][c] = Math.max( + count[node][c], + (c == colorIndex ? 1 : 0) + count[nei][c] + ); + } + } + + path[node] = false; + return 0; + } +} +``` + +```cpp +class Solution { +public: + int n, INF = 1e9; + vector> adj; + vector visit, path; + vector> count; + + int largestPathValue(string colors, vector>& edges) { + this->n = colors.size(); + adj.resize(n); + visit.assign(n, false); + path.assign(n, false); + count.assign(n, vector(26)); + + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + } + + int res = 0; + for (int i = 0; i < n; i++) { + if (dfs(i, colors) == INF) return -1; + for (int c = 0; c < 26; c++) { + res = max(res, count[i][c]); + } + } + return res; + } + +private: + int dfs(int node, string& colors) { + if (path[node]) return INF; + if (visit[node]) return 0; + + visit[node] = true; + path[node] = true; + int colorIndex = colors[node] - 'a'; + count[node][colorIndex] = 1; + + for (int& nei : adj[node]) { + if (dfs(nei, colors) == INF) return INF; + for (int c = 0; c < 26; c++) { + count[node][c] = max( + count[node][c], + (c == colorIndex ? 1 : 0) + count[nei][c] + ); + } + } + + path[node] = false; + return 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @param {number[][]} edges + * @return {number} + */ + largestPathValue(colors, edges) { + const n = colors.length; + const adj = Array.from({ length: n }, () => []); + for (const [src, dst] of edges) { + adj[src].push(dst); + } + + const visit = new Array(n).fill(false); + const path = new Array(n).fill(false); + const count = Array.from({ length: n }, () => new Array(26).fill(0)); + + const dfs = (node) => { + if (path[node]) return Infinity; + if (visit[node]) return 0; + + visit[node] = true; + path[node] = true; + const colorIndex = colors.charCodeAt(node) - 'a'.charCodeAt(0); + count[node][colorIndex] = 1; + + for (const nei of adj[node]) { + if (dfs(nei) === Infinity) return Infinity; + for (let c = 0; c < 26; c++) { + count[node][c] = Math.max( + count[node][c], + (c === colorIndex ? 1 : 0) + count[nei][c], + ); + } + } + + path[node] = false; + return 0; + }; + + let res = 0; + for (let i = 0; i < n; i++) { + if (dfs(i) === Infinity) return -1; + for (let c = 0; c < 26; c++) { + res = Math.max(res, count[i][c]); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of verticies and $E$ is the number of edges. + +--- + +## 3. Topological Sort (Kahn's Algorithm) + +::tabs-start + +```python +class Solution: + def largestPathValue(self, colors: str, edges: list[list[int]]) -> int: + n = len(colors) + adj = [[] for _ in range(n)] + indegree = [0] * n + count = [[0] * 26 for _ in range(n)] + + for u, v in edges: + adj[u].append(v) + indegree[v] += 1 + + q = deque() + for i in range(n): + if indegree[i] == 0: + q.append(i) + + visit = res = 0 + while q: + node = q.popleft() + visit += 1 + colorIndex = ord(colors[node]) - ord('a') + count[node][colorIndex] += 1 + res = max(res, count[node][colorIndex]) + + for nei in adj[node]: + for c in range(26): + count[nei][c] = max(count[nei][c], count[node][c]) + + indegree[nei] -= 1 + if indegree[nei] == 0: + q.append(nei) + + return res if visit == n else -1 +``` + +```java +public class Solution { + public int largestPathValue(String colors, int[][] edges) { + int n = colors.length(); + List[] adj = new ArrayList[n]; + int[] indegree = new int[n]; + int[][] count = new int[n][26]; + + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + indegree[edge[1]]++; + } + + Queue q = new LinkedList<>(); + for (int i = 0; i < n; i++) { + if (indegree[i] == 0) { + q.add(i); + } + } + + int visit = 0, res = 0; + while (!q.isEmpty()) { + int node = q.poll(); + visit++; + int colorIndex = colors.charAt(node) - 'a'; + count[node][colorIndex]++; + res = Math.max(res, count[node][colorIndex]); + + for (int nei : adj[node]) { + for (int c = 0; c < 26; c++) { + count[nei][c] = Math.max(count[nei][c], count[node][c]); + } + if (--indegree[nei] == 0) { + q.add(nei); + } + } + } + + return visit == n ? res : -1; + } +} +``` + +```cpp +class Solution { +public: + int largestPathValue(string colors, vector>& edges) { + int n = colors.size(); + vector> adj(n); + vector indegree(n); + vector> count(n, vector(26)); + + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + indegree[edge[1]]++; + } + + queue q; + for (int i = 0; i < n; i++) { + if (indegree[i] == 0) { + q.push(i); + } + } + + int visit = 0, res = 0; + while (!q.empty()) { + int node = q.front();q.pop(); + visit++; + int colorIndex = colors[node] - 'a'; + count[node][colorIndex]++; + res = max(res, count[node][colorIndex]); + + for (int& nei : adj[node]) { + for (int c = 0; c < 26; c++) { + count[nei][c] = max(count[nei][c], count[node][c]); + } + if (--indegree[nei] == 0) { + q.push(nei); + } + } + } + + return visit == n ? res : -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @param {number[][]} edges + * @return {number} + */ + largestPathValue(colors, edges) { + const n = colors.length; + const adj = Array.from({ length: n }, () => []); + const indegree = new Array(n).fill(0); + const count = Array.from({ length: n }, () => new Array(26).fill(0)); + + for (const [u, v] of edges) { + adj[u].push(v); + indegree[v]++; + } + + const q = new Queue(); + for (let i = 0; i < n; i++) { + if (indegree[i] === 0) { + q.push(i); + } + } + + let visit = 0, + res = 0; + while (!q.isEmpty()) { + const node = q.pop(); + visit++; + const colorIndex = colors.charCodeAt(node) - 'a'.charCodeAt(0); + count[node][colorIndex]++; + res = Math.max(res, count[node][colorIndex]); + + for (const nei of adj[node]) { + for (let c = 0; c < 26; c++) { + count[nei][c] = Math.max(count[nei][c], count[node][c]); + } + if (--indegree[nei] === 0) { + q.push(nei); + } + } + } + + return visit === n ? res : -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of verticies and $E$ is the number of edges. diff --git a/articles/largest-divisible-subset.md b/articles/largest-divisible-subset.md new file mode 100644 index 000000000..1fc86d067 --- /dev/null +++ b/articles/largest-divisible-subset.md @@ -0,0 +1,740 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def largestDivisibleSubset(self, nums: List[int]) -> List[int]: + nums.sort() + cache = {} # (i, prevIndex) -> List + + def dfs(i, prevIndex): + if i == len(nums): + return [] + if (i, prevIndex) in cache: + return cache[(i, prevIndex)] + + res = dfs(i + 1, prevIndex) # Skip nums[i] + if prevIndex == -1 or nums[i] % nums[prevIndex] == 0: + tmp = [nums[i]] + dfs(i + 1, i) # Include nums[i] + res = tmp if len(tmp) > len(res) else res + + cache[(i, prevIndex)] = res + return res + + return dfs(0, -1) +``` + +```java +public class Solution { + private List[][] cache; + + public List largestDivisibleSubset(int[] nums) { + Arrays.sort(nums); + int n = nums.length; + cache = new ArrayList[n][n + 1]; + return dfs(0, -1, nums); + } + + private List dfs(int i, int prevIndex, int[] nums) { + if (i == nums.length) return new ArrayList<>(); + if (cache[i][prevIndex + 1] != null) return cache[i][prevIndex + 1]; + + List res = dfs(i + 1, prevIndex, nums); + + if (prevIndex == -1 || nums[i] % nums[prevIndex] == 0) { + List tmp = new ArrayList<>(); + tmp.add(nums[i]); + tmp.addAll(dfs(i + 1, i, nums)); + if (tmp.size() > res.size()) res = tmp; + } + + cache[i][prevIndex + 1] = res; + return res; + } +} +``` + +```cpp +class Solution { +private: + vector>> cache; + +public: + vector largestDivisibleSubset(vector& nums) { + sort(nums.begin(), nums.end()); + int n = nums.size(); + cache = vector>>(n, vector>(n + 1)); + return dfs(0, -1, nums); + } + + vector dfs(int i, int prevIndex, vector& nums) { + if (i == nums.size()) return {}; + if (!cache[i][prevIndex + 1].empty()) return cache[i][prevIndex + 1]; + + vector res = dfs(i + 1, prevIndex, nums); + + if (prevIndex == -1 || nums[i] % nums[prevIndex] == 0) { + vector tmp = {nums[i]}; + vector next = dfs(i + 1, i, nums); + tmp.insert(tmp.end(), next.begin(), next.end()); + if (tmp.size() > res.size()) res = tmp; + } + + return cache[i][prevIndex + 1] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + largestDivisibleSubset(nums) { + nums.sort((a, b) => a - b); + const cache = new Map(); + + const dfs = (i, prevIndex) => { + if (i === nums.length) return []; + + let key = `${i},${prevIndex}`; + if (cache.has(key)) return cache.get(key); + + let res = dfs(i + 1, prevIndex); + if (prevIndex === -1 || nums[i] % nums[prevIndex] === 0) { + let tmp = [nums[i], ...dfs(i + 1, i)]; + if (tmp.length > res.length) res = tmp; + } + + cache.set(key, res); + return res; + }; + + return dfs(0, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 2. Dynamic Programming (Top-Down) Space Optimized + +::tabs-start + +```python +class Solution: + def largestDivisibleSubset(self, nums: List[int]) -> List[int]: + nums.sort() + cache = {} + + def dfs(i): + if i in cache: + return cache[i] + + res = [nums[i]] + for j in range(i + 1, len(nums)): + if nums[j] % nums[i] == 0: + tmp = [nums[i]] + dfs(j) + if len(tmp) > len(res): + res = tmp + + cache[i] = res + return res + + res = [] + for i in range(len(nums)): + tmp = dfs(i) + if len(tmp) > len(res): + res = tmp + return res +``` + +```java +public class Solution { + private List[] cache; + + public List largestDivisibleSubset(int[] nums) { + Arrays.sort(nums); + int n = nums.length; + cache = new ArrayList[n]; + + List res = new ArrayList<>(); + for (int i = 0; i < n; i++) { + List tmp = dfs(i, nums); + if (tmp.size() > res.size()) { + res = tmp; + } + } + return res; + } + + private List dfs(int i, int[] nums) { + if (cache[i] != null) return cache[i]; + + List res = new ArrayList<>(); + res.add(nums[i]); + for (int j = i + 1; j < nums.length; j++) { + if (nums[j] % nums[i] == 0) { + List tmp = new ArrayList<>(); + tmp.add(nums[i]); + tmp.addAll(dfs(j, nums)); + + if (tmp.size() > res.size()) { + res = tmp; + } + } + } + return cache[i] = res; + } +} +``` + +```cpp +class Solution { +private: + vector> cache; + +public: + vector largestDivisibleSubset(vector& nums) { + sort(nums.begin(), nums.end()); + int n = nums.size(); + cache.resize(n, vector()); + + vector res; + for (int i = 0; i < n; i++) { + vector tmp = dfs(i, nums); + if (tmp.size() > res.size()) { + res = tmp; + } + } + return res; + } + + vector dfs(int i, vector& nums) { + if (!cache[i].empty()) return cache[i]; + + vector res = {nums[i]}; + for (int j = i + 1; j < nums.size(); j++) { + if (nums[j] % nums[i] == 0) { + vector tmp = {nums[i]}; + vector next = dfs(j, nums); + tmp.insert(tmp.end(), next.begin(), next.end()); + + if (tmp.size() > res.size()) { + res = tmp; + } + } + } + return cache[i] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + largestDivisibleSubset(nums) { + nums.sort((a, b) => a - b); + const n = nums.length; + const cache = new Array(n).fill(null); + + const dfs = (i) => { + if (cache[i] !== null) return cache[i]; + + let res = [nums[i]]; + for (let j = i + 1; j < n; j++) { + if (nums[j] % nums[i] === 0) { + let tmp = [nums[i], ...dfs(j)]; + if (tmp.length > res.length) { + res = tmp; + } + } + } + return (cache[i] = res); + }; + + let res = []; + for (let i = 0; i < n; i++) { + let tmp = dfs(i); + if (tmp.length > res.length) { + res = tmp; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def largestDivisibleSubset(self, nums: List[int]) -> List[int]: + nums.sort() + dp = [[num] for num in nums] # dp[i] = longest start at i + res = [] + for i in range(len(nums) - 1, -1, -1): + for j in range(i + 1, len(nums)): + if nums[j] % nums[i] == 0: + tmp = [nums[i]] + dp[j] + dp[i] = tmp if len(tmp) > len(dp[i]) else dp[i] + res = dp[i] if len(dp[i]) > len(res) else res + return res +``` + +```java +public class Solution { + public List largestDivisibleSubset(int[] nums) { + Arrays.sort(nums); + int n = nums.length; + List[] dp = new ArrayList[n]; + List res = new ArrayList<>(); + + for (int i = n - 1; i >= 0; i--) { + dp[i] = new ArrayList<>(); + dp[i].add(nums[i]); + + for (int j = i + 1; j < n; j++) { + if (nums[j] % nums[i] == 0) { + List tmp = new ArrayList<>(); + tmp.add(nums[i]); + tmp.addAll(dp[j]); + + if (tmp.size() > dp[i].size()) { + dp[i] = tmp; + } + } + } + if (dp[i].size() > res.size()) { + res = dp[i]; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector largestDivisibleSubset(vector& nums) { + sort(nums.begin(), nums.end()); + int n = nums.size(); + vector> dp(n); + vector res; + + for (int i = n - 1; i >= 0; i--) { + dp[i].push_back(nums[i]); + + for (int j = i + 1; j < n; j++) { + if (nums[j] % nums[i] == 0) { + vector tmp = dp[j]; + tmp.insert(tmp.begin(), nums[i]); + + if (tmp.size() > dp[i].size()) { + dp[i] = tmp; + } + } + } + if (dp[i].size() > res.size()) { + res = dp[i]; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + largestDivisibleSubset(nums) { + nums.sort((a, b) => a - b); + const n = nums.length; + const dp = new Array(n).fill(0).map(() => []); + let res = []; + + for (let i = n - 1; i >= 0; i--) { + dp[i] = [nums[i]]; + + for (let j = i + 1; j < n; j++) { + if (nums[j] % nums[i] === 0) { + let tmp = [nums[i], ...dp[j]]; + + if (tmp.length > dp[i].length) { + dp[i] = tmp; + } + } + } + if (dp[i].length > res.length) { + res = dp[i]; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Top-Down) + Tracing + +::tabs-start + +```python +class Solution: + def largestDivisibleSubset(self, nums: List[int]) -> List[int]: + nums.sort() + n = len(nums) + dp = [[-1, -1] for _ in range(n)] # dp[i] = [maxLen, prevIdx] + + def dfs(i): + if dp[i][0] != -1: + return dp[i][0] + + dp[i][0] = 1 + for j in range(i + 1, n): + if nums[j] % nums[i] == 0: + length = dfs(j) + 1 + if length > dp[i][0]: + dp[i][0] = length + dp[i][1] = j + + return dp[i][0] + + max_len, start_index = 1, 0 + for i in range(n): + if dfs(i) > max_len: + max_len = dfs(i) + start_index = i + + subset = [] + while start_index != -1: + subset.append(nums[start_index]) + start_index = dp[start_index][1] + + return subset +``` + +```java +public class Solution { + private int[][] dp; + + public List largestDivisibleSubset(int[] nums) { + Arrays.sort(nums); + int n = nums.length; + dp = new int[n][2]; + for (int i = 0; i < n; i++) { + dp[i][0] = -1; + dp[i][1] = -1; + } + + int maxLen = 1, startIndex = 0; + for (int i = 0; i < n; i++) { + if (dfs(i, nums) > maxLen) { + maxLen = dp[i][0]; + startIndex = i; + } + } + + List subset = new ArrayList<>(); + while (startIndex != -1) { + subset.add(nums[startIndex]); + startIndex = dp[startIndex][1]; + } + return subset; + } + + private int dfs(int i, int[] nums) { + if (dp[i][0] != -1) return dp[i][0]; + + dp[i][0] = 1; + for (int j = i + 1; j < nums.length; j++) { + if (nums[j] % nums[i] == 0) { + int length = dfs(j, nums) + 1; + if (length > dp[i][0]) { + dp[i][0] = length; + dp[i][1] = j; + } + } + } + return dp[i][0]; + } +} +``` + +```cpp +class Solution { + vector> dp; + +public: + vector largestDivisibleSubset(vector& nums) { + sort(nums.begin(), nums.end()); + int n = nums.size(); + dp.assign(n, vector(2, -1)); + + int maxLen = 1, startIndex = 0; + for (int i = 0; i < n; i++) { + if (dfs(i, nums) > maxLen) { + maxLen = dp[i][0]; + startIndex = i; + } + } + + vector subset; + while (startIndex != -1) { + subset.push_back(nums[startIndex]); + startIndex = dp[startIndex][1]; + } + return subset; + } + +private: + int dfs(int i, vector& nums) { + if (dp[i][0] != -1) return dp[i][0]; + + dp[i][0] = 1; + for (int j = i + 1; j < nums.size(); j++) { + if (nums[j] % nums[i] == 0) { + int length = dfs(j, nums) + 1; + if (length > dp[i][0]) { + dp[i][0] = length; + dp[i][1] = j; + } + } + } + return dp[i][0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + largestDivisibleSubset(nums) { + nums.sort((a, b) => a - b); + let n = nums.length; + let dp = Array.from({ length: n }, () => [-1, -1]); // dp[i] = [maxLen, prevIdx] + + const dfs = (i) => { + if (dp[i][0] !== -1) return dp[i][0]; + + dp[i][0] = 1; + for (let j = i + 1; j < n; j++) { + if (nums[j] % nums[i] === 0) { + let length = dfs(j) + 1; + if (length > dp[i][0]) { + dp[i][0] = length; + dp[i][1] = j; + } + } + } + return dp[i][0]; + }; + + let maxLen = 1, + startIndex = 0; + for (let i = 0; i < n; i++) { + if (dfs(i) > maxLen) { + maxLen = dfs(i); + startIndex = i; + } + } + + let subset = []; + while (startIndex !== -1) { + subset.push(nums[startIndex]); + startIndex = dp[startIndex][1]; + } + return subset; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 5. Dynamic Programming (Bottom-Up) + Tracing + +::tabs-start + +```python +class Solution: + def largestDivisibleSubset(self, nums: List[int]) -> List[int]: + nums.sort() + n = len(nums) + dp = [[1, -1] for _ in range(n)] # dp[i] = [maxLen, prevIdx] + + max_len, start_index = 1, 0 + + for i in range(n): + for j in range(i): + if nums[i] % nums[j] == 0 and dp[j][0] + 1 > dp[i][0]: + dp[i][0] = dp[j][0] + 1 + dp[i][1] = j + + if dp[i][0] > max_len: + max_len = dp[i][0] + start_index = i + + subset = [] + while start_index != -1: + subset.append(nums[start_index]) + start_index = dp[start_index][1] + return subset +``` + +```java +public class Solution { + public List largestDivisibleSubset(int[] nums) { + Arrays.sort(nums); + int n = nums.length; + int[][] dp = new int[n][2]; // dp[i] = {maxLen, prevIdx} + + int maxLen = 1, startIndex = 0; + for (int i = 0; i < n; i++) { + dp[i][0] = 1; + dp[i][1] = -1; + for (int j = 0; j < i; j++) { + if (nums[i] % nums[j] == 0 && dp[j][0] + 1 > dp[i][0]) { + dp[i][0] = dp[j][0] + 1; + dp[i][1] = j; + } + } + + if (dp[i][0] > maxLen) { + maxLen = dp[i][0]; + startIndex = i; + } + } + + List subset = new ArrayList<>(); + while (startIndex != -1) { + subset.add(nums[startIndex]); + startIndex = dp[startIndex][1]; + } + return subset; + } +} +``` + +```cpp +class Solution { +public: + vector largestDivisibleSubset(vector& nums) { + sort(nums.begin(), nums.end()); + int n = nums.size(); + vector> dp(n, vector(2, -1)); // dp[i] = {maxLen, prevIdx} + + int maxLen = 1, startIndex = 0; + for (int i = 0; i < n; i++) { + dp[i][0] = 1; + dp[i][1] = -1; + for (int j = 0; j < i; j++) { + if (nums[i] % nums[j] == 0 && dp[j][0] + 1 > dp[i][0]) { + dp[i][0] = dp[j][0] + 1; + dp[i][1] = j; + } + } + + if (dp[i][0] > maxLen) { + maxLen = dp[i][0]; + startIndex = i; + } + } + + vector subset; + while (startIndex != -1) { + subset.push_back(nums[startIndex]); + startIndex = dp[startIndex][1]; + } + return subset; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + largestDivisibleSubset(nums) { + nums.sort((a, b) => a - b); + let n = nums.length; + let dp = Array.from({ length: n }, () => [1, -1]); // dp[i] = [maxLen, prevIdx] + + let maxLen = 1, + startIndex = 0; + for (let i = 0; i < n; i++) { + for (let j = 0; j < i; j++) { + if (nums[i] % nums[j] === 0 && dp[j][0] + 1 > dp[i][0]) { + dp[i][0] = dp[j][0] + 1; + dp[i][1] = j; + } + } + + if (dp[i][0] > maxLen) { + maxLen = dp[i][0]; + startIndex = i; + } + } + + let subset = []; + while (startIndex !== -1) { + subset.push(nums[startIndex]); + startIndex = dp[startIndex][1]; + } + return subset; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ diff --git a/articles/largest-local-values-in-a-matrix.md b/articles/largest-local-values-in-a-matrix.md new file mode 100644 index 000000000..9d2ecb76e --- /dev/null +++ b/articles/largest-local-values-in-a-matrix.md @@ -0,0 +1,452 @@ +## 1. Iteration + +::tabs-start + +```python +class Solution: + def largestLocal(self, grid: List[List[int]]) -> List[List[int]]: + N = len(grid) + res = [[0] * (N - 2) for _ in range(N - 2)] + + for i in range(N - 2): + for j in range(N - 2): + for r in range(i, i + 3): + for c in range(j, j + 3): + res[i][j] = max(res[i][j], grid[r][c]) + + return res +``` + +```java +public class Solution { + public int[][] largestLocal(int[][] grid) { + int N = grid.length; + int[][] res = new int[N - 2][N - 2]; + + for (int i = 0; i < N - 2; i++) { + for (int j = 0; j < N - 2; j++) { + for (int r = i; r < i + 3; r++) { + for (int c = j; c < j + 3; c++) { + res[i][j] = Math.max(res[i][j], grid[r][c]); + } + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> largestLocal(vector>& grid) { + int N = grid.size(); + vector> res(N - 2, vector(N - 2, 0)); + + for (int i = 0; i < N - 2; i++) { + for (int j = 0; j < N - 2; j++) { + for (int r = i; r < i + 3; r++) { + for (int c = j; c < j + 3; c++) { + res[i][j] = max(res[i][j], grid[r][c]); + } + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number[][]} + */ + largestLocal(grid) { + const N = grid.length; + const res = Array.from({ length: N - 2 }, () => Array(N - 2).fill(0)); + + for (let i = 0; i < N - 2; i++) { + for (let j = 0; j < N - 2; j++) { + for (let r = i; r < i + 3; r++) { + for (let c = j; c < j + 3; c++) { + res[i][j] = Math.max(res[i][j], grid[r][c]); + } + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n ^ 2)$ for the output array. + +--- + +## 2. Generalized Approach (Sparse Table) + +::tabs-start + +```python +class SparseTable: + def __init__(self, grid: List[List[int]]): + self.n = len(grid) + self.LOG = [0] * (self.n + 1) + for i in range(2, self.n + 1): + self.LOG[i] = self.LOG[i // 2] + 1 + + self.sparse_table = [[[[0] * (self.LOG[self.n] + 1) for _ in range(self.LOG[self.n] + 1)] for _ in range(self.n)] for _ in range(self.n)] + + for r in range(self.n): + for c in range(self.n): + self.sparse_table[r][c][0][0] = grid[r][c] + + for i in range(self.LOG[self.n] + 1): + for j in range(self.LOG[self.n] + 1): + for r in range(self.n - (1 << i) + 1): + for c in range(self.n - (1 << j) + 1): + if i == 0 and j == 0: + self.sparse_table[r][c][i][j] = grid[r][c] + elif i == 0: + self.sparse_table[r][c][i][j] = max( + self.sparse_table[r][c][i][j - 1], + self.sparse_table[r][c + (1 << (j - 1))][i][j - 1], + ) + elif j == 0: + self.sparse_table[r][c][i][j] = max( + self.sparse_table[r][c][i - 1][j], + self.sparse_table[r + (1 << (i - 1))][c][i - 1][j], + ) + else: + self.sparse_table[r][c][i][j] = max( + self.sparse_table[r][c][i - 1][j - 1], + self.sparse_table[r + (1 << (i - 1))][c][i - 1][j - 1], + self.sparse_table[r][c + (1 << (j - 1))][i - 1][j - 1], + self.sparse_table[r + (1 << (i - 1))][c + (1 << (j - 1))][i - 1][j - 1], + ) + + def query(self, x1: int, y1: int, x2: int, y2: int) -> int: + lx, ly = self.LOG[x2 - x1 + 1], self.LOG[y2 - y1 + 1] + return max( + self.sparse_table[x1][y1][lx][ly], + self.sparse_table[x2 - (1 << lx) + 1][y1][lx][ly], + self.sparse_table[x1][y2 - (1 << ly) + 1][lx][ly], + self.sparse_table[x2 - (1 << lx) + 1][y2 - (1 << ly) + 1][lx][ly], + ) + + +class Solution: + def largestLocal(self, grid: List[List[int]]) -> List[List[int]]: + N, k = len(grid), 3 + sparse_table = SparseTable(grid) + res = [[0] * (N - k + 1) for _ in range(N - k + 1)] + + for i in range(N - k + 1): + for j in range(N - k + 1): + res[i][j] = sparse_table.query(i, j, i + k - 1, j + k - 1) + + return res +``` + +```java +class SparseTable { + private int[][][][] sparseTable; + private int[] log; + private int n; + + public SparseTable(int[][] grid) { + n = grid.length; + log = new int[n + 1]; + for (int i = 2; i <= n; i++) { + log[i] = log[i >> 1] + 1; + } + + int maxLog = log[n]; + sparseTable = new int[n][n][maxLog + 1][maxLog + 1]; + + for (int r = 0; r < n; r++) { + for (int c = 0; c < n; c++) { + sparseTable[r][c][0][0] = grid[r][c]; + } + } + + for (int i = 0; i <= maxLog; i++) { + for (int j = 0; j <= maxLog; j++) { + for (int r = 0; r + (1 << i) <= n; r++) { + for (int c = 0; c + (1 << j) <= n; c++) { + if (i == 0 && j == 0) continue; + if (i == 0) { + sparseTable[r][c][i][j] = Math.max( + sparseTable[r][c][i][j - 1], + sparseTable[r][c + (1 << (j - 1))][i][j - 1] + ); + } else if (j == 0) { + sparseTable[r][c][i][j] = Math.max( + sparseTable[r][c][i - 1][j], + sparseTable[r + (1 << (i - 1))][c][i - 1][j] + ); + } else { + sparseTable[r][c][i][j] = Math.max( + Math.max(sparseTable[r][c][i - 1][j - 1], sparseTable[r + (1 << (i - 1))][c][i - 1][j - 1]), + Math.max(sparseTable[r][c + (1 << (j - 1))][i - 1][j - 1], + sparseTable[r + (1 << (i - 1))][c + (1 << (j - 1))][i - 1][j - 1]) + ); + } + } + } + } + } + } + + public int query(int x1, int y1, int x2, int y2) { + int lx = log[x2 - x1 + 1]; + int ly = log[y2 - y1 + 1]; + return Math.max( + Math.max(sparseTable[x1][y1][lx][ly], sparseTable[x2 - (1 << lx) + 1][y1][lx][ly]), + Math.max(sparseTable[x1][y2 - (1 << ly) + 1][lx][ly], + sparseTable[x2 - (1 << lx) + 1][y2 - (1 << ly) + 1][lx][ly]) + ); + } +} + +public class Solution { + public int[][] largestLocal(int[][] grid) { + int n = grid.length; + int k = 3; + SparseTable st = new SparseTable(grid); + int[][] res = new int[n - k + 1][n - k + 1]; + + for (int i = 0; i <= n - k; i++) { + for (int j = 0; j <= n - k; j++) { + res[i][j] = st.query(i, j, i + k - 1, j + k - 1); + } + } + + return res; + } +} +``` + +```cpp +class SparseTable { +public: + vector>>> sparseTable; + vector log; + int n; + + SparseTable(vector>& grid) { + n = grid.size(); + log.resize(n + 1, 0); + for (int i = 2; i <= n; i++) { + log[i] = log[i / 2] + 1; + } + + int maxLog = log[n]; + sparseTable.resize(n, vector>>(n, vector>(maxLog + 1, vector(maxLog + 1)))); + + for (int r = 0; r < n; r++) { + for (int c = 0; c < n; c++) { + sparseTable[r][c][0][0] = grid[r][c]; + } + } + + for (int i = 0; i <= maxLog; i++) { + for (int j = 0; j <= maxLog; j++) { + for (int r = 0; r + (1 << i) <= n; r++) { + for (int c = 0; c + (1 << j) <= n; c++) { + if (i == 0 && j == 0) continue; + if (i == 0) { + sparseTable[r][c][i][j] = max( + sparseTable[r][c][i][j - 1], + sparseTable[r][c + (1 << (j - 1))][i][j - 1] + ); + } else if (j == 0) { + sparseTable[r][c][i][j] = max( + sparseTable[r][c][i - 1][j], + sparseTable[r + (1 << (i - 1))][c][i - 1][j] + ); + } else { + sparseTable[r][c][i][j] = max( + max(sparseTable[r][c][i - 1][j - 1], sparseTable[r + (1 << (i - 1))][c][i - 1][j - 1]), + max(sparseTable[r][c + (1 << (j - 1))][i - 1][j - 1], + sparseTable[r + (1 << (i - 1))][c + (1 << (j - 1))][i - 1][j - 1]) + ); + } + } + } + } + } + } + + int query(int x1, int y1, int x2, int y2) { + int lx = log[x2 - x1 + 1]; + int ly = log[y2 - y1 + 1]; + return max( + max(sparseTable[x1][y1][lx][ly], sparseTable[x2 - (1 << lx) + 1][y1][lx][ly]), + max(sparseTable[x1][y2 - (1 << ly) + 1][lx][ly], + sparseTable[x2 - (1 << lx) + 1][y2 - (1 << ly) + 1][lx][ly]) + ); + } +}; + +class Solution { +public: + vector> largestLocal(vector>& grid) { + int n = grid.size(), k = 3; + SparseTable st(grid); + vector> res(n - k + 1, vector(n - k + 1)); + + for (int i = 0; i <= n - k; i++) { + for (int j = 0; j <= n - k; j++) { + res[i][j] = st.query(i, j, i + k - 1, j + k - 1); + } + } + + return res; + } +}; +``` + +```javascript +class SparseTable { + /** + * @constructor + * @param {number[][]} grid + */ + constructor(grid) { + this.n = grid.length; + this.log = Array(this.n + 1).fill(0); + for (let i = 2; i <= this.n; i++) { + this.log[i] = this.log[Math.floor(i / 2)] + 1; + } + + const maxLog = this.log[this.n]; + this.sparseTable = Array.from({ length: this.n }, () => + Array.from({ length: this.n }, () => + Array.from({ length: maxLog + 1 }, () => + Array(maxLog + 1).fill(0), + ), + ), + ); + + for (let r = 0; r < this.n; r++) { + for (let c = 0; c < this.n; c++) { + this.sparseTable[r][c][0][0] = grid[r][c]; + } + } + + for (let i = 0; i <= maxLog; i++) { + for (let j = 0; j <= maxLog; j++) { + for (let r = 0; r + (1 << i) <= this.n; r++) { + for (let c = 0; c + (1 << j) <= this.n; c++) { + if (i === 0 && j === 0) continue; + if (i === 0) { + this.sparseTable[r][c][i][j] = Math.max( + this.sparseTable[r][c][i][j - 1], + this.sparseTable[r][c + (1 << (j - 1))][i][ + j - 1 + ], + ); + } else if (j === 0) { + this.sparseTable[r][c][i][j] = Math.max( + this.sparseTable[r][c][i - 1][j], + this.sparseTable[r + (1 << (i - 1))][c][i - 1][ + j + ], + ); + } else { + this.sparseTable[r][c][i][j] = Math.max( + Math.max( + this.sparseTable[r][c][i - 1][j - 1], + this.sparseTable[r + (1 << (i - 1))][c][ + i - 1 + ][j - 1], + ), + Math.max( + this.sparseTable[r][c + (1 << (j - 1))][ + i - 1 + ][j - 1], + this.sparseTable[r + (1 << (i - 1))][ + c + (1 << (j - 1)) + ][i - 1][j - 1], + ), + ); + } + } + } + } + } + } + + /** + * @param {number} x1 + * @param {number} y1 + * @param {number} x2 + * @param {number} y2 + * @return {number} + */ + query(x1, y1, x2, y2) { + const lx = this.log[x2 - x1 + 1]; + const ly = this.log[y2 - y1 + 1]; + return Math.max( + Math.max( + this.sparseTable[x1][y1][lx][ly], + this.sparseTable[x2 - (1 << lx) + 1][y1][lx][ly], + ), + Math.max( + this.sparseTable[x1][y2 - (1 << ly) + 1][lx][ly], + this.sparseTable[x2 - (1 << lx) + 1][y2 - (1 << ly) + 1][lx][ + ly + ], + ), + ); + } +} + +class Solution { + /** + * @param {number[][]} grid + * @return {number[][]} + */ + largestLocal(grid) { + const n = grid.length, + k = 3; + const st = new SparseTable(grid); + const res = Array.from({ length: n - k + 1 }, () => + Array(n - k + 1).fill(0), + ); + + for (let i = 0; i <= n - k; i++) { + for (let j = 0; j <= n - k; j++) { + res[i][j] = st.query(i, j, i + k - 1, j + k - 1); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2 \log ^ 2 n)$ +- Space complexity: + - $O(n ^ 2 \log ^ 2 n)$ extra space. + - $O((n - k) ^ 2)$ for the output matrix. + +> Where $n$ is the size of the given square grid and $k$ is the fixed size of the submatrix window. diff --git a/articles/largest-number.md b/articles/largest-number.md index 5b1822fb5..cb16f81db 100644 --- a/articles/largest-number.md +++ b/articles/largest-number.md @@ -6,7 +6,7 @@ class Solution: def largestNumber(self, nums: List[int]) -> str: arr = [str(num) for num in nums] - + res = [] while arr: maxi = 0 @@ -15,7 +15,7 @@ class Solution: maxi = i res.append(arr[maxi]) arr.pop(maxi) - + result = "".join(res) return result if result[0] != '0' else '0' ``` @@ -80,7 +80,7 @@ class Solution { */ largestNumber(nums) { let arr = nums.map(String); - + let res = []; while (arr.length > 0) { let maxi = 0; @@ -93,8 +93,8 @@ class Solution { arr.splice(maxi, 1); } - let result = res.join(""); - return result[0] === "0" ? "0" : result; + let result = res.join(''); + return result[0] === '0' ? '0' : result; } } ``` @@ -103,8 +103,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * N)$ -* Space complexity: $O(N)$ +- Time complexity: $O(n * N)$ +- Space complexity: $O(N)$ > Where $n$ is the size of the array $nums$ and $N$ is the total number of digits in the array $nums$. @@ -171,9 +171,9 @@ class Solution { */ largestNumber(nums) { let arr = nums.map(String); - arr.sort((a, b) => ((b + a) - (a + b))); - let res = arr.join(""); - return res[0] === "0" ? "0" : res; + arr.sort((a, b) => b + a - (a + b)); + let res = arr.join(''); + return res[0] === '0' ? '0' : res; } } ``` @@ -182,7 +182,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(N \log N)$ -* Space complexity: $O(N)$ +- Time complexity: $O(N \log N)$ +- Space complexity: $O(N)$ -> Where $N$ is the total number of digits in the array $nums$. \ No newline at end of file +> Where $N$ is the total number of digits in the array $nums$. diff --git a/articles/largest-odd-number-in-string.md b/articles/largest-odd-number-in-string.md new file mode 100644 index 000000000..451fee9d2 --- /dev/null +++ b/articles/largest-odd-number-in-string.md @@ -0,0 +1,168 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def largestOddNumber(self, num: str) -> str: + res = "" + for i in range(len(num)): + for j in range(i, len(num)): + ones_digit = ord(num[j]) - ord('0') + if ones_digit & 1: + cur = num[i:j + 1] + if len(res) < len(cur) or (len(cur) == len(res) and res < cur): + res = cur + return res +``` + +```java +public class Solution { + public String largestOddNumber(String num) { + String res = ""; + int n = num.length(); + + for (int i = 0; i < n; i++) { + for (int j = i; j < n; j++) { + int onesDigit = num.charAt(j) - '0'; + if ((onesDigit & 1) == 1) { + String cur = num.substring(i, j + 1); + if (res.length() < cur.length() || + (res.length() == cur.length() && res.compareTo(cur) < 0)) { + res = cur; + } + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + string largestOddNumber(string num) { + string res = ""; + int n = num.size(); + + for (int i = 0; i < n; i++) { + for (int j = i; j < n; j++) { + int onesDigit = num[j] - '0'; + if (onesDigit & 1) { + string cur = num.substr(i, j - i + 1); + if (res.size() < cur.size() || + (res.size() == cur.size() && res < cur)) { + res = cur; + } + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} num + * @return {string} + */ + largestOddNumber(num) { + let res = ''; + const n = num.length; + + for (let i = 0; i < n; i++) { + for (let j = i; j < n; j++) { + const onesDigit = num[j].charCodeAt(0) - '0'.charCodeAt(0); + if (onesDigit & 1) { + const cur = num.slice(i, j + 1); + if ( + res.length < cur.length || + (res.length === cur.length && res < cur) + ) { + res = cur; + } + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n)$ + +--- + +## 2. Find The Rightmost Odd Digit + +::tabs-start + +```python +class Solution: + def largestOddNumber(self, num: str) -> str: + for i in range(len(num) - 1, -1, -1): + if int(num[i]) % 2: + return num[:i + 1] + return "" +``` + +```java +public class Solution { + public String largestOddNumber(String num) { + for (int i = num.length() - 1; i >= 0; i--) { + if ((num.charAt(i) - '0') % 2 == 1) { + return num.substring(0, i + 1); + } + } + return ""; + } +} +``` + +```cpp +class Solution { +public: + string largestOddNumber(string num) { + for (int i = num.size() - 1; i >= 0; i--) { + if ((num[i] - '0') % 2 == 1) { + return num.substr(0, i + 1); + } + } + return ""; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} num + * @return {string} + */ + largestOddNumber(num) { + for (let i = num.length - 1; i >= 0; i--) { + if (parseInt(num[i]) % 2 === 1) { + return num.slice(0, i + 1); + } + } + return ''; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ for the output string. diff --git a/articles/largest-rectangle-in-histogram.md b/articles/largest-rectangle-in-histogram.md index 54d44de5b..14070def1 100644 --- a/articles/largest-rectangle-in-histogram.md +++ b/articles/largest-rectangle-in-histogram.md @@ -14,11 +14,11 @@ class Solution: rightMost = i + 1 while rightMost < n and heights[rightMost] >= height: rightMost += 1 - + leftMost = i while leftMost >= 0 and heights[leftMost] >= height: leftMost -= 1 - + rightMost -= 1 leftMost += 1 maxArea = max(maxArea, height * (rightMost - leftMost + 1)) @@ -146,29 +146,29 @@ public class Solution { func largestRectangleArea(heights []int) int { n := len(heights) maxArea := 0 - + for i := 0; i < n; i++ { height := heights[i] - + rightMost := i + 1 for rightMost < n && heights[rightMost] >= height { rightMost++ } - + leftMost := i for leftMost >= 0 && heights[leftMost] >= height { leftMost-- } - + rightMost-- leftMost++ - + area := height * (rightMost - leftMost + 1) if area > maxArea { maxArea = area } } - + return maxArea } ``` @@ -178,26 +178,55 @@ class Solution { fun largestRectangleArea(heights: IntArray): Int { val n = heights.size var maxArea = 0 - + for (i in 0 until n) { val height = heights[i] - + var rightMost = i + 1 while (rightMost < n && heights[rightMost] >= height) { rightMost++ } - + var leftMost = i while (leftMost >= 0 && heights[leftMost] >= height) { leftMost-- } - + rightMost-- leftMost++ - + maxArea = maxOf(maxArea, height * (rightMost - leftMost + 1)) } - + + return maxArea + } +} +``` + +```swift +class Solution { + func largestRectangleArea(_ heights: [Int]) -> Int { + let n = heights.count + var maxArea = 0 + + for i in 0..= height { + rightMost += 1 + } + + var leftMost = i + while leftMost >= 0 && heights[leftMost] >= height { + leftMost -= 1 + } + + rightMost -= 1 + leftMost += 1 + maxArea = max(maxArea, height * (rightMost - leftMost + 1)) + } + return maxArea } } @@ -207,8 +236,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -427,7 +456,7 @@ public: int minIdx = st.query(l, r); return max(max(getMaxArea(heights, l, minIdx - 1, st), - getMaxArea(heights, minIdx + 1, r, st)), + getMaxArea(heights, minIdx + 1, r, st)), (r - l + 1) * heights[minIdx]); } int largestRectangleArea(vector& heights) { @@ -526,7 +555,7 @@ class Solution { return Math.max( this.getMaxArea(heights, l, minIdx - 1, st), this.getMaxArea(heights, minIdx + 1, r, st), - (r - l + 1) * heights[minIdx] + (r - l + 1) * heights[minIdx], ); } } @@ -590,7 +619,7 @@ public class Solution { int minIdx = st.Query(l, r); return Math.Max( - Math.Max(GetMaxArea(heights, l, minIdx - 1, st), + Math.Max(GetMaxArea(heights, l, minIdx - 1, st), GetMaxArea(heights, minIdx + 1, r, st)), (r - l + 1) * heights[minIdx]); } @@ -612,12 +641,12 @@ func NewMinIdxSegtree(N int, A []int) *MinIdxSegtree { A: make([]int, N), } copy(st.A, A) - + for (st.n & (st.n - 1)) != 0 { st.A = append(st.A, st.INF) st.n++ } - + st.tree = make([]int, 2*st.n) st.build() return st @@ -627,7 +656,7 @@ func (st *MinIdxSegtree) build() { for i := 0; i < st.n; i++ { st.tree[st.n+i] = i } - + for j := st.n - 1; j > 0; j-- { a := st.tree[j<<1] b := st.tree[(j<<1)+1] @@ -690,7 +719,7 @@ func getMaxArea(heights []int, l, r int, st *MinIdxSegtree) int { area1 := getMaxArea(heights, l, minIdx-1, st) area2 := getMaxArea(heights, minIdx+1, r, st) area3 := (r - l + 1) * heights[minIdx] - + maxArea := area1 if area2 > maxArea { maxArea = area2 @@ -713,7 +742,7 @@ class MinIdxSegtree(private var n: Int, input: IntArray) { private val INF = 1000000000 private val A: IntArray private val tree: IntArray - + init { var size = n while (size and (size - 1) != 0) size++ @@ -727,17 +756,17 @@ class MinIdxSegtree(private var n: Int, input: IntArray) { tree[j] = if (A[left] <= A[right]) left else right } } - + fun query(ql: Int, qh: Int): Int = queryHelper(1, 0, n - 1, ql, qh) - + private fun queryHelper(node: Int, l: Int, h: Int, ql: Int, qh: Int): Int { if (ql > h || qh < l) return INF if (l >= ql && h <= qh) return tree[node] - + val mid = (l + h) shr 1 val a = queryHelper(node shl 1, l, mid, ql, qh) val b = queryHelper((node shl 1) + 1, mid + 1, h, ql, qh) - + return when { a == INF -> b b == INF -> a @@ -751,7 +780,7 @@ class Solution { fun largestRectangleArea(heights: IntArray): Int { val n = heights.size val st = MinIdxSegtree(n, heights) - + fun getMaxArea(l: Int, r: Int): Int { if (l > r) return 0 if (l == r) return heights[l] @@ -761,18 +790,98 @@ class Solution { val rightArea = getMaxArea(minIdx + 1, r) return maxOf(area, leftArea, rightArea) } - + return getMaxArea(0, n - 1) } } ``` +```swift +class MinIdxSegmentTree { + private var n: Int + private var INF = Int(1e9) + private var A: [Int] + private var tree: [Int] + + init(_ N: Int, _ A: [Int]) { + self.n = N + self.A = A + while (self.n & (self.n - 1)) != 0 { + self.A.append(self.INF) + self.n += 1 + } + self.tree = [Int](repeating: 0, count: 2 * self.n) + build() + } + + private func build() { + for i in 0..> 1 + while j >= 1 { + let a = tree[j << 1] + let b = tree[(j << 1) + 1] + tree[j] = (A[a] <= A[b]) ? a : b + j >>= 1 + } + } + + func query(_ ql: Int, _ qh: Int) -> Int { + return _query(1, 0, n - 1, ql, qh) + } + + private func _query(_ node: Int, _ l: Int, _ h: Int, _ ql: Int, _ qh: Int) -> Int { + if ql > h || qh < l { + return INF + } + if l >= ql && h <= qh { + return tree[node] + } + let a = _query(node << 1, l, (l + h) >> 1, ql, qh) + let b = _query((node << 1) + 1, ((l + h) >> 1) + 1, h, ql, qh) + if a == INF { return b } + if b == INF { return a } + return (A[a] <= A[b]) ? a : b + } +} + +class Solution { + func getMaxArea(_ heights: [Int], _ l: Int, _ r: Int, _ st: MinIdxSegmentTree) -> Int { + if l > r { return 0 } + if l == r { return heights[l] } + + let minIdx = st.query(l, r) + return max( + max(getMaxArea(heights, l, minIdx - 1, st), + getMaxArea(heights, minIdx + 1, r, st)), + (r - l + 1) * heights[minIdx] + ) + } + + func largestRectangleArea(_ heights: [Int]) -> Int { + let n = heights.count + let st = MinIdxSegmentTree(n, heights) + return getMaxArea(heights, 0, n - 1, st) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -793,7 +902,7 @@ class Solution: if stack: leftMost[i] = stack[-1] stack.append(i) - + stack = [] rightMost = [n] * n for i in range(n - 1, -1, -1): @@ -802,7 +911,7 @@ class Solution: if stack: rightMost[i] = stack[-1] stack.append(i) - + maxArea = 0 for i in range(n): leftMost[i] += 1 @@ -818,7 +927,7 @@ public class Solution { int[] leftMost = new int[n]; int[] rightMost = new int[n]; Stack stack = new Stack<>(); - + for (int i = 0; i < n; i++) { leftMost[i] = -1; while (!stack.isEmpty() && heights[stack.peek()] >= heights[i]) { @@ -909,7 +1018,10 @@ class Solution { const stack = []; for (let i = 0; i < n; i++) { - while (stack.length && heights[stack[stack.length - 1]] >= heights[i]) { + while ( + stack.length && + heights[stack[stack.length - 1]] >= heights[i] + ) { stack.pop(); } if (stack.length) { @@ -920,7 +1032,10 @@ class Solution { stack.length = 0; for (let i = n - 1; i >= 0; i--) { - while (stack.length && heights[stack[stack.length - 1]] >= heights[i]) { + while ( + stack.length && + heights[stack[stack.length - 1]] >= heights[i] + ) { stack.pop(); } if (stack.length) { @@ -933,7 +1048,10 @@ class Solution { for (let i = 0; i < n; i++) { leftMost[i] += 1; rightMost[i] -= 1; - maxArea = Math.max(maxArea, heights[i] * (rightMost[i] - leftMost[i] + 1)); + maxArea = Math.max( + maxArea, + heights[i] * (rightMost[i] - leftMost[i] + 1), + ); } return maxArea; @@ -988,12 +1106,12 @@ public class Solution { func largestRectangleArea(heights []int) int { n := len(heights) stack := make([]int, 0) - + leftMost := make([]int, n) for i := range leftMost { leftMost[i] = -1 } - + for i := 0; i < n; i++ { for len(stack) > 0 && heights[stack[len(stack)-1]] >= heights[i] { stack = stack[:len(stack)-1] @@ -1003,13 +1121,13 @@ func largestRectangleArea(heights []int) int { } stack = append(stack, i) } - + stack = stack[:0] rightMost := make([]int, n) for i := range rightMost { rightMost[i] = n } - + for i := n - 1; i >= 0; i-- { for len(stack) > 0 && heights[stack[len(stack)-1]] >= heights[i] { stack = stack[:len(stack)-1] @@ -1019,7 +1137,7 @@ func largestRectangleArea(heights []int) int { } stack = append(stack, i) } - + maxArea := 0 for i := 0; i < n; i++ { leftMost[i]++ @@ -1029,7 +1147,7 @@ func largestRectangleArea(heights []int) int { maxArea = area } } - + return maxArea } ``` @@ -1039,7 +1157,7 @@ class Solution { fun largestRectangleArea(heights: IntArray): Int { val n = heights.size val stack = ArrayDeque() - + val leftMost = IntArray(n) { -1 } for (i in 0 until n) { while (stack.isNotEmpty() && heights[stack.last()] >= heights[i]) { @@ -1050,7 +1168,7 @@ class Solution { } stack.addLast(i) } - + stack.clear() val rightMost = IntArray(n) { n } for (i in n - 1 downTo 0) { @@ -1062,14 +1180,54 @@ class Solution { } stack.addLast(i) } - + var maxArea = 0 for (i in 0 until n) { leftMost[i]++ rightMost[i]-- maxArea = maxOf(maxArea, heights[i] * (rightMost[i] - leftMost[i] + 1)) } - + + return maxArea + } +} +``` + +```swift +class Solution { + func largestRectangleArea(_ heights: [Int]) -> Int { + let n = heights.count + var stack = [Int]() + + var leftMost = [Int](repeating: -1, count: n) + for i in 0..= heights[i] { + stack.removeLast() + } + if !stack.isEmpty { + leftMost[i] = stack.last! + } + stack.append(i) + } + + stack.removeAll() + var rightMost = [Int](repeating: n, count: n) + for i in stride(from: n - 1, through: 0, by: -1) { + while !stack.isEmpty && heights[stack.last!] >= heights[i] { + stack.removeLast() + } + if !stack.isEmpty { + rightMost[i] = stack.last! + } + stack.append(i) + } + + var maxArea = 0 + for i in 0.. 0 && stack[len(stack)-1][1] > h { @@ -1244,7 +1402,7 @@ func largestRectangleArea(heights []int) int { } stack = append(stack, [2]int{start, h}) } - + n := len(heights) for _, pair := range stack { area := pair[1] * (n - pair[0]) @@ -1252,7 +1410,7 @@ func largestRectangleArea(heights []int) int { maxArea = area } } - + return maxArea } ``` @@ -1262,7 +1420,7 @@ class Solution { fun largestRectangleArea(heights: IntArray): Int { var maxArea = 0 val stack = ArrayDeque>() - + heights.forEachIndexed { i, h -> var start = i while (stack.isNotEmpty() && stack.last().second > h) { @@ -1272,12 +1430,37 @@ class Solution { } stack.addLast(start to h) } - + val n = heights.size for ((i, h) in stack) { maxArea = maxOf(maxArea, h * (n - i)) } - + + return maxArea + } +} +``` + +```swift +class Solution { + func largestRectangleArea(_ heights: [Int]) -> Int { + var maxArea = 0 + var stack = [(Int, Int)]() // Pair: (index, height) + + for (i, h) in heights.enumerated() { + var start = i + while !stack.isEmpty && stack.last!.1 > h { + let (index, height) = stack.removeLast() + maxArea = max(maxArea, height * (i - index)) + start = index + } + stack.append((start, h)) + } + + for (i, h) in stack { + maxArea = max(maxArea, h * (heights.count - i)) + } + return maxArea } } @@ -1287,12 +1470,12 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- -## 5. Stack (One Pass) +## 5. Stack (Optimal) ::tabs-start @@ -1368,10 +1551,13 @@ class Solution { const stack = []; for (let i = 0; i <= n; i++) { - while (stack.length && - (i === n || heights[stack[stack.length - 1]] >= heights[i])) { + while ( + stack.length && + (i === n || heights[stack[stack.length - 1]] >= heights[i]) + ) { const height = heights[stack.pop()]; - const width = stack.length === 0 ? i : i - stack[stack.length - 1] - 1; + const width = + stack.length === 0 ? i : i - stack[stack.length - 1] - 1; maxArea = Math.max(maxArea, height * width); } stack.push(i); @@ -1407,17 +1593,17 @@ func largestRectangleArea(heights []int) int { n := len(heights) maxArea := 0 stack := make([]int, 0) - + for i := 0; i <= n; i++ { for len(stack) > 0 && (i == n || heights[stack[len(stack)-1]] >= heights[i]) { height := heights[stack[len(stack)-1]] stack = stack[:len(stack)-1] - + width := i if len(stack) > 0 { width = i - stack[len(stack)-1] - 1 } - + area := height * width if area > maxArea { maxArea = area @@ -1427,7 +1613,7 @@ func largestRectangleArea(heights []int) int { stack = append(stack, i) } } - + return maxArea } ``` @@ -1438,7 +1624,7 @@ class Solution { val n = heights.size var maxArea = 0 val stack = ArrayDeque() - + for (i in 0..n) { while (stack.isNotEmpty() && (i == n || heights[stack.last()] >= heights[i])) { val height = heights[stack.removeLast()] @@ -1447,7 +1633,27 @@ class Solution { } if (i < n) stack.addLast(i) } - + + return maxArea + } +} +``` + +```swift +class Solution { + func largestRectangleArea(_ heights: [Int]) -> Int { + let n = heights.count + var maxArea = 0 + var stack = [Int]() + + for i in 0...n { + while !stack.isEmpty && (i == n || heights[stack.last!] >= heights[i]) { + let height = heights[stack.removeLast()] + let width = stack.isEmpty ? i : i - stack.last! - 1 + maxArea = max(maxArea, height * width) + } + stack.append(i) + } return maxArea } } @@ -1457,5 +1663,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/largest-submatrix-with-rearrangements.md b/articles/largest-submatrix-with-rearrangements.md new file mode 100644 index 000000000..d1aec6383 --- /dev/null +++ b/articles/largest-submatrix-with-rearrangements.md @@ -0,0 +1,527 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def largestSubmatrix(self, matrix: List[List[int]]) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + res = 0 + + for start_row in range(ROWS): + ones = deque(list(range(COLS))) + + for r in range(start_row, ROWS): + if not ones: + break + for _ in range(len(ones)): + c = ones.popleft() + if matrix[r][c] == 1: + ones.append(c) + + res = max(res, len(ones) * (r - start_row + 1)) + + return res +``` + +```java +public class Solution { + public int largestSubmatrix(int[][] matrix) { + int ROWS = matrix.length, COLS = matrix[0].length; + int res = 0; + + for (int startRow = 0; startRow < ROWS; startRow++) { + Queue ones = new LinkedList<>(); + for (int c = 0; c < COLS; c++) { + ones.add(c); + } + + for (int r = startRow; r < ROWS; r++) { + if (ones.isEmpty()) break; + + for (int i = ones.size(); i > 0; i--) { + int c = ones.poll(); + if (matrix[r][c] == 1) { + ones.add(c); + } + } + + res = Math.max(res, ones.size() * (r - startRow + 1)); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int largestSubmatrix(vector>& matrix) { + int ROWS = matrix.size(), COLS = matrix[0].size(); + int res = 0; + + for (int startRow = 0; startRow < ROWS; startRow++) { + queue ones; + for (int c = 0; c < COLS; c++) { + ones.push(c); + } + + for (int r = startRow; r < ROWS; r++) { + if (ones.empty()) break; + + for (int i = ones.size(); i > 0; i--) { + int c = ones.front(); ones.pop(); + if (matrix[r][c] == 1) { + ones.push(c); + } + } + + res = max(res, (int)ones.size() * (r - startRow + 1)); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @return {number} + */ + largestSubmatrix(matrix) { + const ROWS = matrix.length, + COLS = matrix[0].length; + let res = 0; + + for (let startRow = 0; startRow < ROWS; startRow++) { + const ones = new Queue(); + for (let c = 0; c < COLS; c++) { + ones.push(c); + } + + for (let r = startRow; r < ROWS; r++) { + if (ones.isEmpty()) break; + + for (let i = ones.size(); i > 0; i--) { + let c = ones.pop(); + if (matrix[r][c] === 1) { + ones.push(c); + } + } + + res = Math.max(res, ones.size() * (r - startRow + 1)); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n ^ 2)$ +- Space complexity: $O(n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 2. Greedy + Sorting + +::tabs-start + +```python +class Solution: + def largestSubmatrix(self, matrix: List[List[int]]) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + res = 0 + prev_heights = [0] * COLS + + for r in range(ROWS): + heights = matrix[r][:] + for c in range(COLS): + if heights[c] > 0: + heights[c] += prev_heights[c] + + sorted_heights = sorted(heights, reverse=True) + for i in range(COLS): + res = max(res, (i + 1) * sorted_heights[i]) + + prev_heights = heights + + return res +``` + +```java +public class Solution { + public int largestSubmatrix(int[][] matrix) { + int ROWS = matrix.length, COLS = matrix[0].length; + int res = 0; + int[] prevHeights = new int[COLS]; + + for (int r = 0; r < ROWS; r++) { + int[] heights = Arrays.copyOf(matrix[r], COLS); + int[] sortedHgts = Arrays.copyOf(matrix[r], COLS); + + for (int c = 0; c < COLS; c++) { + if (heights[c] > 0) { + heights[c] += prevHeights[c]; + sortedHgts[c] = heights[c]; + } + } + + Arrays.sort(sortedHgts); + for (int i = COLS - 1; i >= 0; i--) { + res = Math.max(res, (COLS - i) * sortedHgts[i]); + } + + prevHeights = heights; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int largestSubmatrix(vector>& matrix) { + int ROWS = matrix.size(), COLS = matrix[0].size(); + int res = 0; + vector prevHeights(COLS); + + for (int r = 0; r < ROWS; r++) { + vector heights = matrix[r]; + vector sortedHgts = matrix[r]; + + for (int c = 0; c < COLS; c++) { + if (heights[c] > 0) { + heights[c] += prevHeights[c]; + sortedHgts[c] = heights[c]; + } + } + + sort(sortedHgts.begin(), sortedHgts.end(), greater()); + for (int i = 0; i < COLS; i++) { + res = max(res, (i + 1) * sortedHgts[i]); + } + + prevHeights = heights; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @return {number} + */ + largestSubmatrix(matrix) { + const ROWS = matrix.length, + COLS = matrix[0].length; + let res = 0; + let prevHeights = new Array(COLS).fill(0); + + for (let r = 0; r < ROWS; r++) { + let heights = [...matrix[r]]; + let sortedHgts = [...matrix[r]]; + + for (let c = 0; c < COLS; c++) { + if (heights[c] > 0) { + heights[c] += prevHeights[c]; + sortedHgts[c] = heights[c]; + } + } + + sortedHgts.sort((a, b) => b - a); + for (let i = 0; i < COLS; i++) { + res = Math.max(res, (i + 1) * sortedHgts[i]); + } + + prevHeights = heights; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n \log n)$ +- Space complexity: $O(n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 3. Greedy + Sorting (Overwriting the Input) + +::tabs-start + +```python +class Solution: + def largestSubmatrix(self, matrix: List[List[int]]) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + res = 0 + + for r in range(1, ROWS): + for c in range(COLS): + if matrix[r][c]: + matrix[r][c] += matrix[r - 1][c] + + for r in range(ROWS): + matrix[r].sort(reverse=True) + for i in range(COLS): + res = max(res, (i + 1) * matrix[r][i]) + + return res +``` + +```java +public class Solution { + public int largestSubmatrix(int[][] matrix) { + int ROWS = matrix.length, COLS = matrix[0].length; + int res = 0; + + for (int r = 1; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (matrix[r][c] > 0) { + matrix[r][c] += matrix[r - 1][c]; + } + } + } + + for (int r = 0; r < ROWS; r++) { + Arrays.sort(matrix[r]); + for (int i = 0; i < COLS; i++) { + res = Math.max(res, (COLS - i) * matrix[r][i]); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int largestSubmatrix(vector>& matrix) { + int ROWS = matrix.size(), COLS = matrix[0].size(); + int res = 0; + + for (int r = 1; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (matrix[r][c] > 0) { + matrix[r][c] += matrix[r - 1][c]; + } + } + } + + for (int r = 0; r < ROWS; r++) { + sort(matrix[r].begin(), matrix[r].end(), greater()); + for (int i = 0; i < COLS; i++) { + res = max(res, (i + 1) * matrix[r][i]); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @return {number} + */ + largestSubmatrix(matrix) { + const ROWS = matrix.length, + COLS = matrix[0].length; + let res = 0; + + for (let r = 1; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (matrix[r][c] > 0) { + matrix[r][c] += matrix[r - 1][c]; + } + } + } + + for (let r = 0; r < ROWS; r++) { + matrix[r].sort((a, b) => b - a); + for (let i = 0; i < COLS; i++) { + res = Math.max(res, (i + 1) * matrix[r][i]); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algoirhtm. + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 4. Greedy + +::tabs-start + +```python +class Solution: + def largestSubmatrix(self, matrix: List[List[int]]) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + res = 0 + prevHeights = [] + + for r in range(ROWS): + heights = [] + for c in prevHeights: + if matrix[r][c]: + matrix[r][c] += matrix[r - 1][c] + heights.append(c) + + for c in range(COLS): + if matrix[r][c] == 1: + heights.append(c) + + for i, c in enumerate(heights): + res = max(res, (i + 1) * matrix[r][c]) + + prevHeights = heights + + return res +``` + +```java +public class Solution { + public int largestSubmatrix(int[][] matrix) { + int ROWS = matrix.length, COLS = matrix[0].length; + int res = 0; + List prevHeights = new ArrayList<>(); + + for (int r = 0; r < ROWS; r++) { + List heights = new ArrayList<>(); + + for (int c : prevHeights) { + if (matrix[r][c] == 1) { + matrix[r][c] += matrix[r - 1][c]; + heights.add(c); + } + } + + for (int c = 0; c < COLS; c++) { + if (matrix[r][c] == 1) { + heights.add(c); + } + } + + for (int i = 0; i < heights.size(); i++) { + res = Math.max(res, (i + 1) * matrix[r][heights.get(i)]); + } + + prevHeights = heights; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int largestSubmatrix(vector>& matrix) { + int ROWS = matrix.size(), COLS = matrix[0].size(), res = 0; + vector prevHeights; + + for (int r = 0; r < ROWS; r++) { + vector heights; + + for (int c : prevHeights) { + if (matrix[r][c] == 1) { + matrix[r][c] += matrix[r - 1][c]; + heights.push_back(c); + } + } + + for (int c = 0; c < COLS; c++) { + if (matrix[r][c] == 1) { + heights.push_back(c); + } + } + + for (int i = 0; i < heights.size(); i++) { + res = max(res, (i + 1) * matrix[r][heights[i]]); + } + + prevHeights = heights; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @return {number} + */ + largestSubmatrix(matrix) { + const ROWS = matrix.length, + COLS = matrix[0].length; + let res = 0, + prevHeights = []; + + for (let r = 0; r < ROWS; r++) { + let heights = []; + + for (let c of prevHeights) { + if (matrix[r][c] === 1) { + matrix[r][c] += matrix[r - 1][c]; + heights.push(c); + } + } + + for (let c = 0; c < COLS; c++) { + if (matrix[r][c] === 1) { + heights.push(c); + } + } + + for (let i = 0; i < heights.length; i++) { + res = Math.max(res, (i + 1) * matrix[r][heights[i]]); + } + + prevHeights = heights; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns. diff --git a/articles/largest-substring-between-two-equal-characters.md b/articles/largest-substring-between-two-equal-characters.md index dc4108a60..172a0aff4 100644 --- a/articles/largest-substring-between-two-equal-characters.md +++ b/articles/largest-substring-between-two-equal-characters.md @@ -78,8 +78,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -93,16 +93,16 @@ class Solution: res = -1 firstIdx = {} lastIdx = {} - + for i, c in enumerate(s): if c not in firstIdx: firstIdx[c] = i else: lastIdx[c] = i - + for c in lastIdx: res = max(res, lastIdx[c] - firstIdx[c] - 1) - + return res ``` @@ -187,8 +187,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. --- @@ -207,7 +207,7 @@ class Solution: res = max(res, i - char_index[c] - 1) else: char_index[c] = i - + return res ``` @@ -278,8 +278,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. --- @@ -299,7 +299,7 @@ class Solution: res = max(res, i - firstIdx[j] - 1) else: firstIdx[j] = i - + return res ``` @@ -376,5 +376,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. diff --git a/articles/last-stone-weight-ii.md b/articles/last-stone-weight-ii.md index f902d45d2..eaa55357d 100644 --- a/articles/last-stone-weight-ii.md +++ b/articles/last-stone-weight-ii.md @@ -76,10 +76,7 @@ class Solution { if (total >= target || i === stones.length) { return Math.abs(total - (stoneSum - total)); } - return Math.min( - dfs(i + 1, total), - dfs(i + 1, total + stones[i]) - ); + return Math.min(dfs(i + 1, total), dfs(i + 1, total + stones[i])); }; return dfs(0, 0); @@ -87,12 +84,36 @@ class Solution { } ``` +```csharp +public class Solution { + public int LastStoneWeightII(int[] stones) { + int stoneSum = 0; + foreach (int stone in stones) { + stoneSum += stone; + } + int target = (stoneSum + 1) / 2; + return Dfs(0, 0, stones, stoneSum, target); + } + + private int Dfs(int i, int total, int[] stones, int stoneSum, int target) { + if (total >= target || i == stones.Length) { + return Math.Abs(total - (stoneSum - total)); + } + + return Math.Min( + Dfs(i + 1, total, stones, stoneSum, target), + Dfs(i + 1, total + stones[i], stones, stoneSum, target) + ); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(min(n, m))$ for recursion stack. +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(min(n, m))$ for recursion stack. > Where $n$ is the number of stones and $m$ is the sum of the weights of the stones. @@ -198,7 +219,9 @@ class Solution { lastStoneWeightII(stones) { const stoneSum = stones.reduce((a, b) => a + b, 0); const target = Math.ceil(stoneSum / 2); - const dp = Array.from({ length: stones.length }, () => Array(target + 1).fill(-1)); + const dp = Array.from({ length: stones.length }, () => + Array(target + 1).fill(-1), + ); const dfs = (i, total) => { if (total >= target || i === stones.length) { @@ -210,7 +233,7 @@ class Solution { dp[i][total] = Math.min( dfs(i + 1, total), - dfs(i + 1, total + stones[i]) + dfs(i + 1, total + stones[i]), ); return dp[i][total]; }; @@ -220,12 +243,51 @@ class Solution { } ``` +```csharp +public class Solution { + private int[][] dp; + + public int LastStoneWeightII(int[] stones) { + int stoneSum = 0; + foreach (int stone in stones) { + stoneSum += stone; + } + int target = (stoneSum + 1) / 2; + dp = new int[stones.Length][]; + for (int i = 0; i < stones.Length; i++) { + dp[i] = new int[target + 1]; + for (int j = 0; j <= target; j++) { + dp[i][j] = -1; + } + } + + return Dfs(0, 0, stones, stoneSum, target); + } + + private int Dfs(int i, int total, int[] stones, int stoneSum, int target) { + if (total >= target || i == stones.Length) { + return Math.Abs(total - (stoneSum - total)); + } + if (dp[i][total] != -1) { + return dp[i][total]; + } + + dp[i][total] = Math.Min( + Dfs(i + 1, total, stones, stoneSum, target), + Dfs(i + 1, total + stones[i], stones, stoneSum, target) + ); + + return dp[i][total]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ > Where $n$ is the number of stones and $m$ is the sum of the weights of the stones. @@ -317,12 +379,17 @@ class Solution { const target = Math.floor(stoneSum / 2); const n = stones.length; - const dp = Array.from({ length: n + 1 }, () => Array(target + 1).fill(0)); + const dp = Array.from({ length: n + 1 }, () => + Array(target + 1).fill(0), + ); for (let i = 1; i <= n; i++) { for (let t = 0; t <= target; t++) { if (t >= stones[i - 1]) { - dp[i][t] = Math.max(dp[i - 1][t], dp[i - 1][t - stones[i - 1]] + stones[i - 1]); + dp[i][t] = Math.max( + dp[i - 1][t], + dp[i - 1][t - stones[i - 1]] + stones[i - 1], + ); } else { dp[i][t] = dp[i - 1][t]; } @@ -334,12 +401,39 @@ class Solution { } ``` +```csharp +public class Solution { + public int LastStoneWeightII(int[] stones) { + int stoneSum = 0; + foreach (int stone in stones) { + stoneSum += stone; + } + int target = stoneSum / 2; + int n = stones.Length; + + int[,] dp = new int[n + 1, target + 1]; + + for (int i = 1; i <= n; i++) { + for (int t = 0; t <= target; t++) { + if (t >= stones[i - 1]) { + dp[i, t] = Math.Max(dp[i - 1, t], dp[i - 1, t - stones[i - 1]] + stones[i - 1]); + } else { + dp[i, t] = dp[i - 1, t]; + } + } + } + + return stoneSum - 2 * dp[n, target]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ > Where $n$ is the number of stones and $m$ is the sum of the weights of the stones. @@ -425,12 +519,33 @@ class Solution { } ``` +```csharp +public class Solution { + public int LastStoneWeightII(int[] stones) { + int stoneSum = 0; + foreach (int stone in stones) { + stoneSum += stone; + } + int target = stoneSum / 2; + int[] dp = new int[target + 1]; + + foreach (int stone in stones) { + for (int t = target; t >= stone; t--) { + dp[t] = Math.Max(dp[t], dp[t - stone] + stone); + } + } + + return stoneSum - 2 * dp[target]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(m)$ > Where $n$ is the number of stones and $m$ is the sum of the weights of the stones. @@ -556,12 +671,47 @@ class Solution { } ``` +```csharp +public class Solution { + public int LastStoneWeightII(int[] stones) { + int stoneSum = 0; + foreach (int stone in stones) { + stoneSum += stone; + } + int target = stoneSum / 2; + + HashSet dp = new HashSet(); + dp.Add(0); + + foreach (int stone in stones) { + HashSet newDp = new HashSet(dp); + foreach (int val in dp) { + if (val + stone == target) { + return stoneSum - 2 * target; + } + if (val + stone < target) { + newDp.Add(val + stone); + } + } + dp = newDp; + } + + int maxVal = 0; + foreach (int val in dp) { + maxVal = Math.Max(maxVal, val); + } + + return stoneSum - 2 * maxVal; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(m)$ > Where $n$ is the number of stones and $m$ is the sum of the weights of the stones. @@ -576,7 +726,7 @@ class Solution: def lastStoneWeightII(self, stones: List[int]) -> int: stoneSum = sum(stones) target = stoneSum // 2 - dp = 1 + dp = 1 for stone in stones: dp |= dp << stone @@ -591,14 +741,14 @@ class Solution { public: int lastStoneWeightII(vector& stones) { int stoneSum = accumulate(stones.begin(), stones.end(), 0); - int target = stoneSum / 2; + int target = stoneSum / 2; bitset<3001> dp; dp[0] = true; - + for (int stone : stones) { dp |= (dp << stone); } - + for (int t = target; t >= 0; --t) { if (dp[t]) { return stoneSum - 2 * t; @@ -613,7 +763,7 @@ public: ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(m)$ -> Where $n$ is the number of stones and $m$ is the sum of the weights of the stones. \ No newline at end of file +> Where $n$ is the number of stones and $m$ is the sum of the weights of the stones. diff --git a/articles/last-stone-weight.md b/articles/last-stone-weight.md index da1ec745e..658773016 100644 --- a/articles/last-stone-weight.md +++ b/articles/last-stone-weight.md @@ -5,13 +5,13 @@ ```python class Solution: def lastStoneWeight(self, stones: List[int]) -> int: - + while len(stones) > 1: stones.sort() cur = stones.pop() - stones.pop() if cur: stones.append(cur) - + return stones[0] if stones else 0 ``` @@ -81,10 +81,10 @@ public class Solution { while (stoneList.Count > 1) { stoneList.Sort(); int cur = stoneList[stoneList.Count - 1] - stoneList[stoneList.Count - 2]; - stoneList.RemoveAt(stoneList.Count - 1); - stoneList.RemoveAt(stoneList.Count - 1); + stoneList.RemoveAt(stoneList.Count - 1); + stoneList.RemoveAt(stoneList.Count - 1); if (cur != 0) { - stoneList.Add(cur); + stoneList.Add(cur); } } @@ -106,7 +106,7 @@ func lastStoneWeight(stones []int) int { if len(stones) == 0 { return 0 } - return stones[0] + return stones[0] } ``` @@ -114,7 +114,7 @@ func lastStoneWeight(stones []int) int { class Solution { fun lastStoneWeight(stones: IntArray): Int { var stonesList = stones.toMutableList() - + while (stonesList.size > 1) { stonesList.sort() val cur = stonesList.removeAt(stonesList.size - 1) - stonesList.removeAt(stonesList.size - 1) @@ -127,12 +127,30 @@ class Solution { } ``` +```swift +class Solution { + func lastStoneWeight(_ stones: [Int]) -> Int { + var stones = stones + + while stones.count > 1 { + stones.sort() + let cur = stones.removeLast() - stones.removeLast() + if cur > 0 { + stones.append(cur) + } + } + + return stones.isEmpty ? 0 : stones[0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2 \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n ^ 2 \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -248,7 +266,8 @@ class Solution { let cur = stones.pop() - stones.pop(); n -= 2; if (cur > 0) { - let l = 0, r = n; + let l = 0, + r = n; while (l < r) { let mid = Math.floor((l + r) / 2); if (stones[mid] < cur) { @@ -308,16 +327,16 @@ public class Solution { func lastStoneWeight(stones []int) int { sort.Ints(stones) n := len(stones) - + for n > 1 { cur := stones[n-1] - stones[n-2] n -= 2 - + if cur > 0 { pos := sort.Search(n, func(i int) bool { return stones[i] >= cur }) - + for i := n; i > pos; i-- { stones[i] = stones[i-1] } @@ -325,7 +344,7 @@ func lastStoneWeight(stones []int) int { n++ } } - + if n > 0 { return stones[0] } @@ -338,11 +357,11 @@ class Solution { fun lastStoneWeight(stones: IntArray): Int { stones.sort() var n = stones.size - + while (n > 1) { val cur = stones[n-1] - stones[n-2] n -= 2 - + if (cur > 0) { var l = 0 var r = n @@ -354,7 +373,7 @@ class Solution { r = mid } } - + for (i in n downTo l+1) { stones[i] = stones[i-1] } @@ -362,18 +381,52 @@ class Solution { n++ } } - + return if (n > 0) stones[0] else 0 } } ``` +```swift +class Solution { + func lastStoneWeight(_ stones: [Int]) -> Int { + var stones = stones.sorted() + var n = stones.count + + while n > 1 { + let cur = stones.removeLast() - stones.removeLast() + n -= 2 + if cur > 0 { + var l = 0, r = n + while l < r { + let mid = (l + r) / 2 + if stones[mid] < cur { + l = mid + 1 + } else { + r = mid + } + } + let pos = l + stones.append(0) + n += 1 + for i in stride(from: n - 1, to: pos, by: -1) { + stones[i] = stones[i - 1] + } + stones[pos] = cur + } + } + + return n > 0 ? stones[0] : 0 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -500,13 +553,13 @@ public class Solution { ```go func lastStoneWeight(stones []int) int { pq := priorityqueue.NewWith(func(a, b interface{}) int { - return a.(int) - b.(int) + return a.(int) - b.(int) }) - + for _, s := range stones { pq.Enqueue(-s) } - + for pq.Size() > 1 { first, _ := pq.Dequeue() second, _ := pq.Dequeue() @@ -514,7 +567,7 @@ func lastStoneWeight(stones []int) int { pq.Enqueue(first.(int) - second.(int)) } } - + pq.Enqueue(0) result, _ := pq.Dequeue() return -result.(int) @@ -528,7 +581,7 @@ class Solution { for (s in stones) { minHeap.offer(-s) } - + while (minHeap.size > 1) { val first = minHeap.poll() val second = minHeap.poll() @@ -536,19 +589,35 @@ class Solution { minHeap.offer(first - second) } } - + minHeap.offer(0) return Math.abs(minHeap.peek()) } } ``` +```swift +class Solution { + func lastStoneWeight(_ stones: [Int]) -> Int { + var heap = Heap(stones) + while heap.count > 1 { + let first = heap.popMax()! + let second = heap.popMax()! + if first > second { + heap.insert(first - second) + } + } + return heap.isEmpty ? 0 : heap.popMax()! + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -564,17 +633,17 @@ class Solution: bucket = [0] * (maxStone + 1) for stone in stones: bucket[stone] += 1 - + first = second = maxStone while first > 0: if bucket[first] % 2 == 0: first -= 1 continue - + j = min(first - 1, second) while j > 0 and bucket[j] == 0: j -= 1 - + if j == 0: return first second = j @@ -597,30 +666,30 @@ public class Solution { for (int stone : stones) { bucket[stone]++; } - + int first = maxStone, second = maxStone; while (first > 0) { if (bucket[first] % 2 == 0) { first--; continue; } - + int j = Math.min(first - 1, second); while (j > 0 && bucket[j] == 0) { j--; } - + if (j == 0) { return first; } - + second = j; bucket[first]--; bucket[second]--; bucket[first - second]++; first = Math.max(first - second, second); } - + return first; } } @@ -639,7 +708,7 @@ public: for (int stone : stones) { bucket[stone]++; } - + int first = maxStone, second = maxStone; while (first > 0) { if (bucket[first] % 2 == 0) { @@ -685,7 +754,8 @@ class Solution { bucket[stone]++; } - let first = maxStone, second = maxStone; + let first = maxStone, + second = maxStone; while (first > 0) { if (bucket[first] % 2 === 0) { first--; @@ -762,24 +832,24 @@ func lastStoneWeight(stones []int) int { maxStone = stone } } - + bucket := make([]int, maxStone+1) for _, stone := range stones { bucket[stone]++ } - + first, second := maxStone, maxStone for first > 0 { if bucket[first]%2 == 0 { first-- continue } - + j := min(first-1, second) for j > 0 && bucket[j] == 0 { j-- } - + if j == 0 { return first } @@ -815,7 +885,7 @@ class Solution { for (stone in stones) { bucket[stone]++ } - + var first = maxStone var second = maxStone while (first > 0) { @@ -823,12 +893,12 @@ class Solution { first-- continue } - + var j = minOf(first - 1, second) while (j > 0 && bucket[j] == 0) { j-- } - + if (j == 0) { return first } @@ -843,11 +913,51 @@ class Solution { } ``` +```swift +class Solution { + func lastStoneWeight(_ stones: [Int]) -> Int { + guard let maxStone = stones.max() else { return 0 } + + var bucket = [Int](repeating: 0, count: maxStone + 1) + for stone in stones { + bucket[stone] += 1 + } + + var first = maxStone + var second = maxStone + + while first > 0 { + if bucket[first] % 2 == 0 { + first -= 1 + continue + } + + var j = min(first - 1, second) + while j > 0 && bucket[j] == 0 { + j -= 1 + } + + if j == 0 { + return first + } + + second = j + bucket[first] -= 1 + bucket[second] -= 1 + bucket[first - second] += 1 + first = max(first - second, second) + } + + return first + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n + w)$ -* Space complexity: $O(w)$ +- Time complexity: $O(n + w)$ +- Space complexity: $O(w)$ -> Where $n$ is the length of the $stones$ array and $w$ is the maximum value in the $stones$ array. \ No newline at end of file +> Where $n$ is the length of the $stones$ array and $w$ is the maximum value in the $stones$ array. diff --git a/articles/leaf-similar-trees.md b/articles/leaf-similar-trees.md new file mode 100644 index 000000000..7a874fd6a --- /dev/null +++ b/articles/leaf-similar-trees.md @@ -0,0 +1,505 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def leafSimilar(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool: + def dfs(root, leaf): + if not root: + return + if not root.left and not root.right: + leaf.append(root.val) + return + dfs(root.left, leaf) + dfs(root.right, leaf) + + leaf1, leaf2 = [], [] + dfs(root1, leaf1) + dfs(root2, leaf2) + return leaf1 == leaf2 +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean leafSimilar(TreeNode root1, TreeNode root2) { + List leaf1 = new ArrayList<>(); + List leaf2 = new ArrayList<>(); + + dfs(root1, leaf1); + dfs(root2, leaf2); + + return leaf1.equals(leaf2); + } + + private void dfs(TreeNode root, List leaf) { + if (root == null) return; + if (root.left == null && root.right == null) { + leaf.add(root.val); + return; + } + dfs(root.left, leaf); + dfs(root.right, leaf); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool leafSimilar(TreeNode* root1, TreeNode* root2) { + vector leaf1, leaf2; + dfs(root1, leaf1); + dfs(root2, leaf2); + return leaf1 == leaf2; + } + +private: + void dfs(TreeNode* root, vector& leaf) { + if (!root) return; + if (!root->left && !root->right) { + leaf.push_back(root->val); + return; + } + dfs(root->left, leaf); + dfs(root->right, leaf); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root1 + * @param {TreeNode} root2 + * @return {boolean} + */ + leafSimilar(root1, root2) { + const dfs = (root, leaf) => { + if (!root) return; + if (!root.left && !root.right) { + leaf.push(root.val); + return; + } + dfs(root.left, leaf); + dfs(root.right, leaf); + }; + + const leaf1 = []; + const leaf2 = []; + dfs(root1, leaf1); + dfs(root2, leaf2); + + return JSON.stringify(leaf1) === JSON.stringify(leaf2); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ + +> Where $n$ and $m$ are the number of nodes in the given trees. + +--- + +## 2. Depth First Search (Space Optimized) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def leafSimilar(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool: + def dfs(root, leaf): + if not root: + return + if not root.left and not root.right: + leaf.append(root.val) + return + dfs(root.left, leaf) + dfs(root.right, leaf) + + leaf1 = [] + dfs(root1, leaf1) + + def dfs1(root, leaf): + if not root: + return True + if not root.left and not root.right: + if not leaf: + return False + return leaf.pop() == root.val + return dfs1(root.right, leaf) and dfs1(root.left, leaf) + + return dfs1(root2, leaf1) and not leaf1 +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean leafSimilar(TreeNode root1, TreeNode root2) { + Stack leaf1 = new Stack<>(); + dfs(root1, leaf1); + return dfs1(root2, leaf1) && leaf1.isEmpty(); + } + + private void dfs(TreeNode root, Stack leaf) { + if (root == null) return; + if (root.left == null && root.right == null) { + leaf.push(root.val); + return; + } + dfs(root.left, leaf); + dfs(root.right, leaf); + } + + private boolean dfs1(TreeNode root, Stack leaf) { + if (root == null) return true; + if (root.left == null && root.right == null) { + if (leaf.isEmpty()) return false; + return leaf.pop() == root.val; + } + return dfs1(root.right, leaf) && dfs1(root.left, leaf); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool leafSimilar(TreeNode* root1, TreeNode* root2) { + vector leaf1; + dfs(root1, leaf1); + return dfs1(root2, leaf1) && leaf1.empty(); + } + +private: + void dfs(TreeNode* root, vector& leaf) { + if (!root) return; + if (!root->left && !root->right) { + leaf.push_back(root->val); + return; + } + dfs(root->left, leaf); + dfs(root->right, leaf); + } + + bool dfs1(TreeNode* root, vector& leaf) { + if (!root) return true; + if (!root->left && !root->right) { + if (leaf.empty() || leaf.back() != root->val) { + return false; + } + leaf.pop_back(); + return true; + } + return dfs1(root->right, leaf) && dfs1(root->left, leaf); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root1 + * @param {TreeNode} root2 + * @return {boolean} + */ + leafSimilar(root1, root2) { + const dfs = (root, leaf) => { + if (!root) return; + if (!root.left && !root.right) { + leaf.push(root.val); + return; + } + dfs(root.left, leaf); + dfs(root.right, leaf); + }; + + const dfs1 = (root, leaf) => { + if (!root) return true; + if (!root.left && !root.right) { + if (!leaf.length) return false; + return leaf.pop() === root.val; + } + return dfs1(root.right, leaf) && dfs1(root.left, leaf); + }; + + const leaf1 = []; + dfs(root1, leaf1); + return dfs1(root2, leaf1) && leaf1.length === 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ + +> Where $n$ and $m$ are the number of nodes in the given trees. + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def leafSimilar(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> bool: + def getPathLeaf(stack): + while stack: + node = stack.pop() + if node.right: + stack.append(node.right) + if node.left: + stack.append(node.left) + if not node.left and not node.right: + return node.val + + stack1, stack2 = [root1], [root2] + while stack1 and stack2: + if getPathLeaf(stack1) != getPathLeaf(stack2): + return False + + return not stack1 and not stack2 +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean leafSimilar(TreeNode root1, TreeNode root2) { + Stack stack1 = new Stack<>(); + Stack stack2 = new Stack<>(); + stack1.push(root1); + stack2.push(root2); + + while (!stack1.isEmpty() && !stack2.isEmpty()) { + if (getPathLeaf(stack1) != getPathLeaf(stack2)) { + return false; + } + } + return stack1.isEmpty() && stack2.isEmpty(); + } + + private int getPathLeaf(Stack stack) { + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + if (node.right != null) { + stack.push(node.right); + } + if (node.left != null) { + stack.push(node.left); + } + if (node.left == null && node.right == null) { + return node.val; + } + } + return -1; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool leafSimilar(TreeNode* root1, TreeNode* root2) { + stack stack1, stack2; + stack1.push(root1); + stack2.push(root2); + + while (!stack1.empty() && !stack2.empty()) { + if (getPathLeaf(stack1) != getPathLeaf(stack2)) { + return false; + } + } + return stack1.empty() && stack2.empty(); + } + +private: + int getPathLeaf(stack& stack) { + while (!stack.empty()) { + TreeNode* node = stack.top(); + stack.pop(); + if (node->right) { + stack.push(node->right); + } + if (node->left) { + stack.push(node->left); + } + if (!node->left && !node->right) { + return node->val; + } + } + return -1; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root1 + * @param {TreeNode} root2 + * @return {boolean} + */ + leafSimilar(root1, root2) { + const getPathLeaf = (stack) => { + while (stack.length) { + const node = stack.pop(); + if (node.right) stack.push(node.right); + if (node.left) stack.push(node.left); + if (!node.left && !node.right) return node.val; + } + }; + + const stack1 = [root1], + stack2 = [root2]; + while (stack1.length && stack2.length) { + if (getPathLeaf(stack1) !== getPathLeaf(stack2)) { + return false; + } + } + return stack1.length === 0 && stack2.length === 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ + +> Where $n$ and $m$ are the number of nodes in the given trees. diff --git a/articles/least-number-of-unique-integers-after-k-removals.md b/articles/least-number-of-unique-integers-after-k-removals.md new file mode 100644 index 000000000..3bfa46a2d --- /dev/null +++ b/articles/least-number-of-unique-integers-after-k-removals.md @@ -0,0 +1,343 @@ +## 1. Sorting + +::tabs-start + +```python +class Solution: + def findLeastNumOfUniqueInts(self, arr: List[int], k: int) -> int: + freq = sorted(Counter(arr).values()) + n = len(freq) + for i in range(n): + if k >= freq[i]: + k -= freq[i] + else: + return n - i + return 0 +``` + +```java +public class Solution { + public int findLeastNumOfUniqueInts(int[] arr, int k) { + Map freqMap = new HashMap<>(); + for (int num : arr) { + freqMap.put(num, freqMap.getOrDefault(num, 0) + 1); + } + + List freq = new ArrayList<>(freqMap.values()); + Collections.sort(freq); + + int n = freq.size(); + for (int i = 0; i < n; i++) { + if (k >= freq.get(i)) { + k -= freq.get(i); + } else { + return n - i; + } + } + return 0; + } +} +``` + +```cpp +class Solution { +public: + int findLeastNumOfUniqueInts(vector& arr, int k) { + unordered_map freqMap; + for (int num : arr) { + freqMap[num]++; + } + + vector freq; + for (auto& [_, count] : freqMap) { + freq.push_back(count); + } + + sort(freq.begin(), freq.end()); + + int n = freq.size(); + for (int i = 0; i < n; i++) { + if (k >= freq[i]) { + k -= freq[i]; + } else { + return n - i; + } + } + return 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ + findLeastNumOfUniqueInts(arr, k) { + let freqMap = new Map(); + for (let num of arr) { + freqMap.set(num, (freqMap.get(num) || 0) + 1); + } + + let freq = Array.from(freqMap.values()).sort((a, b) => a - b); + + let n = freq.length; + for (let i = 0; i < n; i++) { + if (k >= freq[i]) { + k -= freq[i]; + } else { + return n - i; + } + } + return 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Min-Heap + +::tabs-start + +```python +class Solution: + def findLeastNumOfUniqueInts(self, arr: List[int], k: int) -> int: + freq = Counter(arr) + heap = list(freq.values()) + heapq.heapify(heap) + + res = len(heap) + while k > 0 and heap: + f = heapq.heappop(heap) + if k >= f: + k -= f + res -= 1 + return res +``` + +```java +public class Solution { + public int findLeastNumOfUniqueInts(int[] arr, int k) { + Map freqMap = new HashMap<>(); + for (int num : arr) { + freqMap.put(num, freqMap.getOrDefault(num, 0) + 1); + } + + PriorityQueue minHeap = new PriorityQueue<>(freqMap.values()); + + int res = minHeap.size(); + while (k > 0 && !minHeap.isEmpty()) { + int f = minHeap.poll(); + if (k >= f) { + k -= f; + res--; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int findLeastNumOfUniqueInts(vector& arr, int k) { + unordered_map freqMap; + for (int num : arr) { + freqMap[num]++; + } + + priority_queue, greater> minHeap; + for (auto& [_, count] : freqMap) { + minHeap.push(count); + } + + int res = minHeap.size(); + while (k > 0 && !minHeap.empty()) { + int f = minHeap.top(); + minHeap.pop(); + if (k >= f) { + k -= f; + res--; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ + findLeastNumOfUniqueInts(arr, k) { + let freqMap = new Map(); + for (let num of arr) { + freqMap.set(num, (freqMap.get(num) || 0) + 1); + } + + const minHeap = MinPriorityQueue.fromArray([...freqMap.values()]); + + let res = minHeap.size(); + while (k > 0 && !minHeap.isEmpty()) { + let f = minHeap.pop(); + if (k >= f) { + k -= f; + res--; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Bucket Sort + +::tabs-start + +```python +class Solution: + def findLeastNumOfUniqueInts(self, arr: List[int], k: int) -> int: + freq = Counter(arr) + freq_list = [0] * (len(arr) + 1) + + for n, f in freq.items(): + freq_list[f] += 1 + + res = len(freq) + for f in range(1, len(freq_list)): + remove = freq_list[f] + if k >= f * remove: + k -= f * remove + res -= remove + else: + remove = k // f + res -= remove + break + return res +``` + +```java +public class Solution { + public int findLeastNumOfUniqueInts(int[] arr, int k) { + Map freqMap = new HashMap<>(); + for (int num : arr) { + freqMap.put(num, freqMap.getOrDefault(num, 0) + 1); + } + + int[] freqList = new int[arr.length + 1]; + for (int f : freqMap.values()) { + freqList[f]++; + } + + int res = freqMap.size(); + for (int f = 1; f < freqList.length; f++) { + int remove = freqList[f]; + if (k >= f * remove) { + k -= f * remove; + res -= remove; + } else { + remove = k / f; + res -= remove; + break; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int findLeastNumOfUniqueInts(vector& arr, int k) { + unordered_map freqMap; + for (int num : arr) { + freqMap[num]++; + } + + vector freqList(arr.size() + 1, 0); + for (auto& [_, f] : freqMap) { + freqList[f]++; + } + + int res = freqMap.size(); + for (int f = 1; f < freqList.size(); f++) { + int remove = freqList[f]; + if (k >= f * remove) { + k -= f * remove; + res -= remove; + } else { + remove = k / f; + res -= remove; + break; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ + findLeastNumOfUniqueInts(arr, k) { + let freqMap = new Map(); + for (let num of arr) { + freqMap.set(num, (freqMap.get(num) || 0) + 1); + } + + let freqList = new Array(arr.length + 1).fill(0); + for (let f of freqMap.values()) { + freqList[f]++; + } + + let res = freqMap.size; + for (let f = 1; f < freqList.length; f++) { + let remove = freqList[f]; + if (k >= f * remove) { + k -= f * remove; + res -= remove; + } else { + remove = Math.floor(k / f); + res -= remove; + break; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/lemonade-change.md b/articles/lemonade-change.md index 662b4dc91..c9215562b 100644 --- a/articles/lemonade-change.md +++ b/articles/lemonade-change.md @@ -95,7 +95,8 @@ class Solution { * @return {boolean} */ lemonadeChange(bills) { - let five = 0, ten = 0; + let five = 0, + ten = 0; for (let b of bills) { if (b === 5) { five++; @@ -122,12 +123,43 @@ class Solution { } ``` +```csharp +public class Solution { + public bool LemonadeChange(int[] bills) { + int five = 0, ten = 0; + foreach (int b in bills) { + if (b == 5) { + five++; + } else if (b == 10) { + ten++; + if (five > 0) { + five--; + } else { + return false; + } + } else { + int change = b - 5; + if (change == 15 && five > 0 && ten > 0) { + five--; + ten--; + } else if (change == 15 && five >= 3) { + five -= 3; + } else { + return false; + } + } + } + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -211,7 +243,8 @@ class Solution { * @return {boolean} */ lemonadeChange(bills) { - let five = 0, ten = 0; + let five = 0, + ten = 0; for (let b of bills) { if (b === 5) { five++; @@ -233,9 +266,35 @@ class Solution { } ``` +```csharp +public class Solution { + public bool LemonadeChange(int[] bills) { + int five = 0, ten = 0; + foreach (int b in bills) { + if (b == 5) { + five++; + } else if (b == 10) { + five--; + ten++; + } else if (ten > 0) { + five--; + ten--; + } else { + five -= 3; + } + + if (five < 0) { + return false; + } + } + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/length-of-last-word.md b/articles/length-of-last-word.md index baa94e557..8952e481b 100644 --- a/articles/length-of-last-word.md +++ b/articles/length-of-last-word.md @@ -73,7 +73,8 @@ class Solution { * @return {number} */ lengthOfLastWord(s) { - let length = 0, i = 0; + let length = 0, + i = 0; while (i < s.length) { if (s[i] === ' ') { while (i < s.length && s[i] === ' ') { @@ -97,8 +98,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -159,7 +160,8 @@ class Solution { */ lengthOfLastWord(s) { let n = s.length; - let i = n - 1, length = 0; + let i = n - 1, + length = 0; while (s.charAt(i) === ' ') { i--; } @@ -176,8 +178,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -194,7 +196,7 @@ class Solution: ```java public class Solution { public int lengthOfLastWord(String s) { - s = s.trim(); + s = s.trim(); return s.length() - s.lastIndexOf(" ") - 1; } } @@ -204,7 +206,7 @@ public class Solution { class Solution { public: int lengthOfLastWord(string s) { - s.erase(s.find_last_not_of(' ') + 1); + s.erase(s.find_last_not_of(' ') + 1); return s.substr(s.find_last_of(' ') + 1).length(); } }; @@ -217,7 +219,7 @@ class Solution { * @return {number} */ lengthOfLastWord(s) { - return s.trim().split(' ').pop().length + return s.trim().split(' ').pop().length; } } ``` @@ -226,5 +228,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/length-of-longest-subarray-with-at-most-k-frequency.md b/articles/length-of-longest-subarray-with-at-most-k-frequency.md new file mode 100644 index 000000000..db3af563f --- /dev/null +++ b/articles/length-of-longest-subarray-with-at-most-k-frequency.md @@ -0,0 +1,280 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maxSubarrayLength(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + + for i in range(n): + count = defaultdict(int) + for j in range(i, n): + count[nums[j]] += 1 + if count[nums[j]] > k: + break + res = max(res, j - i + 1) + + return res +``` + +```java +public class Solution { + public int maxSubarrayLength(int[] nums, int k) { + int n = nums.length, res = 0; + + for (int i = 0; i < n; i++) { + Map count = new HashMap<>(); + for (int j = i; j < n; j++) { + count.put(nums[j], count.getOrDefault(nums[j], 0) + 1); + if (count.get(nums[j]) > k) { + break; + } + res = Math.max(res, j - i + 1); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxSubarrayLength(vector& nums, int k) { + int n = nums.size(), res = 0; + + for (int i = 0; i < n; i++) { + unordered_map count; + for (int j = i; j < n; j++) { + count[nums[j]]++; + if (count[nums[j]] > k) { + break; + } + res = max(res, j - i + 1); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maxSubarrayLength(nums, k) { + let n = nums.length, + res = 0; + + for (let i = 0; i < n; i++) { + let count = new Map(); + for (let j = i; j < n; j++) { + count.set(nums[j], (count.get(nums[j]) || 0) + 1); + if (count.get(nums[j]) > k) { + break; + } + res = Math.max(res, j - i + 1); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 2. Sliding Window + +::tabs-start + +```python +class Solution: + def maxSubarrayLength(self, nums: List[int], k: int) -> int: + res = 0 + count = defaultdict(int) + l = 0 + for r in range(len(nums)): + count[nums[r]] += 1 + while count[nums[r]] > k: + count[nums[l]] -= 1 + l += 1 + res = max(res, r - l + 1) + return res +``` + +```java +public class Solution { + public int maxSubarrayLength(int[] nums, int k) { + int res = 0; + Map count = new HashMap<>(); + int l = 0; + + for (int r = 0; r < nums.length; r++) { + count.put(nums[r], count.getOrDefault(nums[r], 0) + 1); + while (count.get(nums[r]) > k) { + count.put(nums[l], count.get(nums[l]) - 1); + l++; + } + res = Math.max(res, r - l + 1); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxSubarrayLength(vector& nums, int k) { + int res = 0; + unordered_map count; + int l = 0; + + for (int r = 0; r < nums.size(); r++) { + count[nums[r]]++; + while (count[nums[r]] > k) { + count[nums[l]]--; + l++; + } + res = max(res, r - l + 1); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maxSubarrayLength(nums, k) { + let res = 0; + let count = new Map(); + let l = 0; + + for (let r = 0; r < nums.length; r++) { + count.set(nums[r], (count.get(nums[r]) || 0) + 1); + while (count.get(nums[r]) > k) { + count.set(nums[l], count.get(nums[l]) - 1); + l++; + } + res = Math.max(res, r - l + 1); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Sliding Window (Optimal) + +::tabs-start + +```python +class Solution: + def maxSubarrayLength(self, nums: List[int], k: int) -> int: + count = defaultdict(int) + l = res = 0 + cnt = 0 # count of numbers with freq > k + for r in range(len(nums)): + count[nums[r]] += 1 + cnt += count[nums[r]] > k + if cnt > 0: + cnt -= count[nums[l]] > k + count[nums[l]] -= 1 + l += 1 + return len(nums) - l +``` + +```java +public class Solution { + public int maxSubarrayLength(int[] nums, int k) { + HashMap count = new HashMap<>(); + int l = 0, cnt = 0; // count of numbers with freq > k + for (int r = 0; r < nums.length; r++) { + count.put(nums[r], count.getOrDefault(nums[r], 0) + 1); + if (count.get(nums[r]) > k) cnt++; + if (cnt > 0) { + if (count.get(nums[l]) > k) cnt--; + count.put(nums[l], count.get(nums[l]) - 1); + l++; + } + } + return nums.length - l; + } +} +``` + +```cpp +class Solution { +public: + int maxSubarrayLength(vector& nums, int k) { + unordered_map count; + int l = 0, cnt = 0; // count of numbers with freq > k + for (int r = 0; r < nums.size(); r++) { + count[nums[r]]++; + cnt += count[nums[r]] > k; + if (cnt > 0) { + cnt -= count[nums[l]] > k; + count[nums[l]]--; + l++; + } + } + return nums.size() - l; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maxSubarrayLength(nums, k) { + let count = new Map(); + let l = 0, + cnt = 0; // count of numbers with freq > k + for (let r = 0; r < nums.length; r++) { + count.set(nums[r], (count.get(nums[r]) || 0) + 1); + if (count.get(nums[r]) > k) cnt++; + if (cnt > 0) { + if (count.get(nums[l]) > k) cnt--; + count.set(nums[l], count.get(nums[l]) - 1); + l++; + } + } + return nums.length - l; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/level-order-traversal-of-binary-tree.md b/articles/level-order-traversal-of-binary-tree.md index 3bb08fe9a..1a0ab21e1 100644 --- a/articles/level-order-traversal-of-binary-tree.md +++ b/articles/level-order-traversal-of-binary-tree.md @@ -19,11 +19,11 @@ class Solution: return None if len(res) == depth: res.append([]) - + res[depth].append(node.val) dfs(node.left, depth + 1) dfs(node.right, depth + 1) - + dfs(root, 0) return res ``` @@ -47,21 +47,21 @@ class Solution: public class Solution { List> res = new ArrayList<>(); - + public List> levelOrder(TreeNode root) { dfs(root, 0); return res; } - + private void dfs(TreeNode node, int depth) { if (node == null) { return; } - + if (res.size() == depth) { res.add(new ArrayList<>()); } - + res.get(depth).add(node.val); dfs(node.left, depth + 1); dfs(node.right, depth + 1); @@ -85,19 +85,19 @@ public class Solution { class Solution { public: vector> res; - + vector> levelOrder(TreeNode* root) { dfs(root, 0); return res; } - + void dfs(TreeNode* node, int depth) { if (!node) return; - + if (res.size() == depth) { res.push_back(vector()); } - + res[depth].push_back(node->val); dfs(node->left, depth + 1); dfs(node->right, depth + 1); @@ -124,7 +124,7 @@ class Solution { */ levelOrder(root) { let res = []; - + /** * @param {TreeNode} node * @param {number} depth @@ -161,24 +161,24 @@ class Solution { * } * } */ - + public class Solution { List> res = new List>(); - + public List> LevelOrder(TreeNode root) { dfs(root, 0); return res; } - + private void dfs(TreeNode node, int depth) { if (node == null) { return; } - + if (res.Count == depth) { res.Add(new List()); } - + res[depth].Add(node.val); dfs(node.left, depth + 1); dfs(node.right, depth + 1); @@ -197,22 +197,22 @@ public class Solution { */ func levelOrder(root *TreeNode) [][]int { res := [][]int{} - + var dfs func(node *TreeNode, depth int) dfs = func(node *TreeNode, depth int) { if node == nil { return } - + if len(res) == depth { res = append(res, []int{}) } - + res[depth] = append(res[depth], node.Val) dfs(node.Left, depth+1) dfs(node.Right, depth+1) } - + dfs(root, 0) return res } @@ -232,19 +232,57 @@ func levelOrder(root *TreeNode) [][]int { class Solution { fun levelOrder(root: TreeNode?): List> { val res = mutableListOf>() - + fun dfs(node: TreeNode?, depth: Int) { if (node == null) return - + if (res.size == depth) { res.add(mutableListOf()) } - + res[depth].add(node.`val`) dfs(node.left, depth + 1) dfs(node.right, depth + 1) } - + + dfs(root, 0) + return res + } +} +``` + +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func levelOrder(_ root: TreeNode?) -> [[Int]] { + var res = [[Int]]() + + func dfs(_ node: TreeNode?, _ depth: Int) { + guard let node = node else { return } + + if res.count == depth { + res.append([]) + } + + res[depth].append(node.val) + dfs(node.left, depth + 1) + dfs(node.right, depth + 1) + } + dfs(root, 0) return res } @@ -255,8 +293,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -290,7 +328,7 @@ class Solution: q.append(node.right) if level: res.append(level) - + return res ``` @@ -440,7 +478,7 @@ class Solution { * } * } */ - + public class Solution { public List> LevelOrder(TreeNode root) { List> res = new List>(); @@ -492,7 +530,7 @@ func levelOrder(root *TreeNode) [][]int { for i := 0; i < qLen; i++ { node := q[0] - q = q[1:] + q = q[1:] level = append(level, node.Val) if node.Left != nil { @@ -502,7 +540,7 @@ func levelOrder(root *TreeNode) [][]int { q = append(q, node.Right) } } - + res = append(res, level) } @@ -532,7 +570,7 @@ class Solution { while (q.isNotEmpty()) { val level = mutableListOf() val qLen = q.size - + for (i in 0 until qLen) { val node = q.removeFirst() level.add(node.`val`) @@ -540,10 +578,52 @@ class Solution { node.left?.let { q.add(it) } node.right?.let { q.add(it) } } - + res.add(level) } - + + return res + } +} +``` + +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func levelOrder(_ root: TreeNode?) -> [[Int]] { + var res = [[Int]]() + var q = Deque() + q.append(root) + + while !q.isEmpty { + let qLen = q.count + var level = [Int]() + + for _ in 0.. [value, frequency, timestamp] self.timestamp = 0 - + def get(self, key: int) -> int: if key not in self.cache: return -1 - + self.cache[key][1] += 1 self.timestamp += 1 self.cache[key][2] = self.timestamp return self.cache[key][0] - + def put(self, key: int, value: int) -> None: if self.capacity <= 0: return - + self.timestamp += 1 if key in self.cache: self.cache[key][0] = value self.cache[key][1] += 1 self.cache[key][2] = self.timestamp return - + if len(self.cache) >= self.capacity: min_freq = float('inf') min_timestamp = float('inf') lfu_key = None - + for k, (_, freq, ts) in self.cache.items(): if freq < min_freq or (freq == min_freq and ts < min_timestamp): min_freq = freq @@ -42,7 +42,7 @@ class LFUCache: lfu_key = k if lfu_key is not None: del self.cache[lfu_key] - + self.cache[key] = [value, 1, self.timestamp] ``` @@ -171,7 +171,7 @@ class LFUCache { this.cache = new Map(); } - /** + /** * @param {number} key * @return {number} */ @@ -184,8 +184,8 @@ class LFUCache { return node.value; } - /** - * @param {number} key + /** + * @param {number} key * @param {number} value * @return {void} */ @@ -202,10 +202,15 @@ class LFUCache { } if (this.cache.size >= this.capacity) { - let minFreq = Infinity, minTimestamp = Infinity, lfuKey = null; + let minFreq = Infinity, + minTimestamp = Infinity, + lfuKey = null; for (const [k, node] of this.cache.entries()) { - if (node.freq < minFreq || (node.freq === minFreq && node.timestamp < minTimestamp)) { + if ( + node.freq < minFreq || + (node.freq === minFreq && node.timestamp < minTimestamp) + ) { minFreq = node.freq; minTimestamp = node.timestamp; lfuKey = k; @@ -220,15 +225,84 @@ class LFUCache { } ``` +```csharp +public class Node { + public int Value; + public int Freq; + public int Timestamp; + + public Node(int value, int freq, int timestamp) { + this.Value = value; + this.Freq = freq; + this.Timestamp = timestamp; + } +} + +public class LFUCache { + private int capacity; + private int timestamp; + private Dictionary cache; + + public LFUCache(int capacity) { + this.capacity = capacity; + this.timestamp = 0; + this.cache = new Dictionary(); + } + + public int Get(int key) { + if (!cache.ContainsKey(key)) return -1; + + Node node = cache[key]; + node.Freq++; + node.Timestamp = ++timestamp; + return node.Value; + } + + public void Put(int key, int value) { + if (capacity <= 0) return; + + timestamp++; + if (cache.ContainsKey(key)) { + Node node = cache[key]; + node.Value = value; + node.Freq++; + node.Timestamp = timestamp; + return; + } + + if (cache.Count >= capacity) { + int minFreq = int.MaxValue; + int minTimestamp = int.MaxValue; + int lfuKey = -1; + + foreach (var entry in cache) { + Node node = entry.Value; + if (node.Freq < minFreq || (node.Freq == minFreq && node.Timestamp < minTimestamp)) { + minFreq = node.Freq; + minTimestamp = node.Timestamp; + lfuKey = entry.Key; + } + } + + if (lfuKey != -1) { + cache.Remove(lfuKey); + } + } + + cache[key] = new Node(value, 1, timestamp); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(1)$ time for initialization. - * $O(1)$ time for each $get()$ function call. - * $O(n)$ time for each $put()$ function call. -* Space complexity: $O(n)$ +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $get()$ function call. + - $O(n)$ time for each $put()$ function call. +- Space complexity: $O(n)$ --- @@ -268,12 +342,12 @@ class LinkedList: next.prev = prev prev.next = next self.map.pop(val, None) - + def popLeft(self): res = self.left.next.val self.pop(self.left.next.val) return res - + def update(self, val): self.pop(val) self.pushRight(val) @@ -296,7 +370,7 @@ class LFUCache: if cnt == self.lfuCnt and self.listMap[cnt].length() == 0: self.lfuCnt += 1 - + def get(self, key: int) -> int: if key not in self.valMap: @@ -307,12 +381,12 @@ class LFUCache: def put(self, key: int, value: int) -> None: if self.cap == 0: return - + if key not in self.valMap and len(self.valMap) == self.cap: res = self.listMap[self.lfuCnt].popLeft() self.valMap.pop(res) self.countMap.pop(res) - + self.valMap[key] = value self.counter(key) self.lfuCnt = min(self.lfuCnt, self.countMap[key]) @@ -398,7 +472,7 @@ public class LFUCache { countMap.put(key, count + 1); listMap.putIfAbsent(count, new DoublyLinkedList()); listMap.get(count).pop(key); - + listMap.putIfAbsent(count + 1, new DoublyLinkedList()); listMap.get(count + 1).pushRight(key); @@ -449,14 +523,14 @@ class LFUCache { ListNode* left; ListNode* right; unordered_map map; - + LinkedList() { left = new ListNode(0); right = new ListNode(0); left->next = right; right->prev = left; } - + ~LinkedList() { while (left->next != right) { ListNode* temp = left->next; @@ -513,7 +587,7 @@ class LFUCache { countMap[key] = count + 1; listMap[count]->pop(key); - + if (!listMap.count(count + 1)) { listMap[count + 1] = new LinkedList(); } @@ -528,7 +602,7 @@ public: LFUCache(int capacity) : capacity(capacity), lfuCount(0) { listMap[0] = new LinkedList(); } - + ~LFUCache() { for (auto& pair : listMap) { delete pair.second; @@ -705,11 +779,128 @@ class LFUCache { } ``` +```csharp +public class ListNode { + public int Val; + public ListNode Prev, Next; + + public ListNode(int val) { + Val = val; + } + + public ListNode(int val, ListNode prev, ListNode next) { + Val = val; + Prev = prev; + Next = next; + } +} + +public class DoublyLinkedList { + private ListNode left, right; + private Dictionary map; + + public DoublyLinkedList() { + left = new ListNode(0); + right = new ListNode(0, left, null); + left.Next = right; + map = new Dictionary(); + } + + public int Length() { + return map.Count; + } + + public void PushRight(int val) { + var node = new ListNode(val, right.Prev, right); + map[val] = node; + right.Prev.Next = node; + right.Prev = node; + } + + public void Pop(int val) { + if (map.ContainsKey(val)) { + var node = map[val]; + var prev = node.Prev; + var next = node.Next; + prev.Next = next; + next.Prev = prev; + map.Remove(val); + } + } + + public int PopLeft() { + int res = left.Next.Val; + Pop(res); + return res; + } +} + +public class LFUCache { + private int capacity; + private int lfuCount; + private Dictionary valMap; + private Dictionary countMap; + private Dictionary listMap; + + public LFUCache(int capacity) { + this.capacity = capacity; + lfuCount = 0; + valMap = new Dictionary(); + countMap = new Dictionary(); + listMap = new Dictionary(); + } + + private void Counter(int key) { + int count = countMap[key]; + countMap[key] = count + 1; + + if (!listMap.ContainsKey(count)) { + listMap[count] = new DoublyLinkedList(); + } + listMap[count].Pop(key); + + if (!listMap.ContainsKey(count + 1)) { + listMap[count + 1] = new DoublyLinkedList(); + } + listMap[count + 1].PushRight(key); + + if (count == lfuCount && listMap[count].Length() == 0) { + lfuCount++; + } + } + + public int Get(int key) { + if (!valMap.ContainsKey(key)) { + return -1; + } + Counter(key); + return valMap[key]; + } + + public void Put(int key, int value) { + if (capacity == 0) return; + + if (!valMap.ContainsKey(key) && valMap.Count == capacity) { + int toRemove = listMap[lfuCount].PopLeft(); + valMap.Remove(toRemove); + countMap.Remove(toRemove); + } + + valMap[key] = value; + if (!countMap.ContainsKey(key)) { + countMap[key] = 0; + } + Counter(key); + lfuCount = Math.Min(lfuCount, countMap[key]); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(1)$ time for initialization. - * $O(1)$ time for each $get()$ and $put()$ function calls. -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: + - $O(1)$ time for initialization. + - $O(1)$ time for each $get()$ and $put()$ function calls. +- Space complexity: $O(n)$ diff --git a/articles/linked-list-cycle-detection.md b/articles/linked-list-cycle-detection.md index bcc21ee62..adaca46d0 100644 --- a/articles/linked-list-cycle-detection.md +++ b/articles/linked-list-cycle-detection.md @@ -186,12 +186,43 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * } + * } + */ + +class Solution { + func hasCycle(_ head: ListNode?) -> Bool { + var seen = Set() + var cur = head + + while cur != nil { + let nodeId = ObjectIdentifier(cur!) + if seen.contains(nodeId) { + return true + } + seen.insert(nodeId) + cur = cur?.next + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -234,7 +265,7 @@ class Solution { public boolean hasCycle(ListNode head) { ListNode fast = head; ListNode slow = head; - + while (fast != null && fast.next != null) { fast = fast.next.next; slow = slow.next; @@ -266,12 +297,12 @@ public: while (fast != nullptr && fast->next != nullptr) { fast = fast->next->next; slow = slow->next; - + if (fast == slow) { return true; } } - + return false; } }; @@ -387,9 +418,39 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init(_ val: Int) { + * self.val = val + * self.next = nil + * } + * } + */ + +class Solution { + func hasCycle(_ head: ListNode?) -> Bool { + var slow = head + var fast = head + + while fast != nil && fast?.next != nil { + slow = slow?.next + fast = fast?.next?.next + if slow === fast { + return true + } + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/linked-list-cycle-ii.md b/articles/linked-list-cycle-ii.md new file mode 100644 index 000000000..4d1a014c2 --- /dev/null +++ b/articles/linked-list-cycle-ii.md @@ -0,0 +1,265 @@ +## 1. Hash Set + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: + seen = set() + cur = head + while cur: + if cur in seen: + return cur + seen.add(cur) + cur = cur.next + return None +``` + +```java +/** + * Definition for singly-linked list. + * class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class Solution { + public ListNode detectCycle(ListNode head) { + Set seen = new HashSet<>(); + ListNode cur = head; + while (cur != null) { + if (seen.contains(cur)) { + return cur; + } + seen.add(cur); + cur = cur.next; + } + return null; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* detectCycle(ListNode* head) { + unordered_set seen; + ListNode* cur = head; + while (cur) { + if (seen.find(cur) != seen.end()) { + return cur; + } + seen.insert(cur); + cur = cur->next; + } + return nullptr; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + detectCycle(head) { + const seen = new Set(); + let cur = head; + while (cur) { + if (seen.has(cur)) { + return cur; + } + seen.add(cur); + cur = cur.next; + } + return null; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Fast & Slow Pointers + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, x): +# self.val = x +# self.next = None + +class Solution: + def detectCycle(self, head: Optional[ListNode]) -> Optional[ListNode]: + if not head or not head.next: + return None + + slow, fast = head, head + while fast and fast.next: + slow = slow.next + fast = fast.next.next + if slow == fast: + slow = head + while slow != fast: + slow = slow.next + fast = fast.next + return slow + return None +``` + +```java +/** + * Definition for singly-linked list. + * class ListNode { + * int val; + * ListNode next; + * ListNode(int x) { + * val = x; + * next = null; + * } + * } + */ +public class Solution { + public ListNode detectCycle(ListNode head) { + if (head == null || head.next == null) { + return null; + } + + ListNode slow = head, fast = head; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + if (slow == fast) { + slow = head; + while (slow != fast) { + slow = slow.next; + fast = fast.next; + } + return slow; + } + } + return null; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode(int x) : val(x), next(NULL) {} + * }; + */ +class Solution { +public: + ListNode* detectCycle(ListNode* head) { + if (!head || !head->next) { + return nullptr; + } + + ListNode* slow = head; + ListNode* fast = head; + + while (fast && fast->next) { + slow = slow->next; + fast = fast->next->next; + + if (slow == fast) { + slow = head; + while (slow != fast) { + slow = slow->next; + fast = fast->next; + } + return slow; + } + } + return nullptr; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + detectCycle(head) { + if (!head || !head.next) { + return null; + } + + let slow = head, + fast = head; + + while (fast && fast.next) { + slow = slow.next; + fast = fast.next.next; + + if (slow === fast) { + slow = head; + while (slow !== fast) { + slow = slow.next; + fast = fast.next; + } + return slow; + } + } + return null; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/longest-common-prefix.md b/articles/longest-common-prefix.md index 27c30160f..b03fa2a75 100644 --- a/articles/longest-common-prefix.md +++ b/articles/longest-common-prefix.md @@ -78,12 +78,33 @@ class Solution { } ``` +```csharp +public class Solution { + public string LongestCommonPrefix(string[] strs) { + string prefix = strs[0]; + + for (int i = 1; i < strs.Length; i++) { + int j = 0; + while (j < Math.Min(prefix.Length, strs[i].Length)) { + if (prefix[j] != strs[i][j]) { + break; + } + j++; + } + prefix = prefix.Substring(0, j); + } + + return prefix; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(1)$ > Where $n$ is the length of the shortest string and $m$ is the number of strings. @@ -153,12 +174,27 @@ class Solution { } ``` +```csharp +public class Solution { + public string LongestCommonPrefix(string[] strs) { + for (int i = 0; i < strs[0].Length; i++) { + foreach (string s in strs) { + if (i == s.Length || s[i] != strs[0][i]) { + return s.Substring(0, i); + } + } + } + return strs[0]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(1)$ since we did not use extra space. +- Time complexity: $O(n * m)$ +- Space complexity: $O(1)$ since we did not use extra space. > Where $n$ is the length of the shortest string and $m$ is the number of strings. @@ -173,7 +209,7 @@ class Solution: def longestCommonPrefix(self, strs: List[str]) -> str: if len(strs) == 1: return strs[0] - + strs = sorted(strs) for i in range(min(len(strs[0]), len(strs[-1]))): if strs[0][i] != strs[-1][i]: @@ -187,7 +223,7 @@ public class Solution { if (strs.length == 1) { return strs[0]; } - + Arrays.sort(strs); int N = Math.min(strs[0].length(), strs[strs.length - 1].length()); for (int i = 0; i < N; i++) { @@ -207,7 +243,7 @@ public: if (strs.size() == 1) { return strs[0]; } - + sort(strs.begin(), strs.end()); for (int i = 0; i < min(strs[0].length(), strs.back().length()); i++) { if (strs[0][i] != strs.back()[i]) { @@ -229,7 +265,7 @@ class Solution { if (strs.length === 1) { return strs[0]; } - + strs.sort(); let N = Math.min(strs[0].length, strs[strs.length - 1].length); for (let i = 0; i < N; i++) { @@ -242,12 +278,36 @@ class Solution { } ``` +```csharp +public class Solution { + public string LongestCommonPrefix(string[] strs) { + if (strs.Length == 1) { + return strs[0]; + } + + Array.Sort(strs); + string first = strs[0]; + string last = strs[strs.Length - 1]; + + int i = 0; + while (i < Math.Min(first.Length, last.Length)) { + if (first[i] != last[i]) { + return first.Substring(0, i); + } + i++; + } + + return first; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m \log m)$ -* Space complexity: $O(1)$ or $O(m)$ depending on the sorting algorithm. +- Time complexity: $O(n * m \log m)$ +- Space complexity: $O(1)$ or $O(m)$ depending on the sorting algorithm. > Where $n$ is the length of the longest string and $m$ is the number of strings. @@ -272,7 +332,7 @@ class Trie: if char not in node.children: node.children[char] = TrieNode() node = node.children[char] - + def lcp(self, word: str, prefixLen: int) -> int: node = self.root for i in range(min(len(word), prefixLen)): @@ -472,7 +532,7 @@ class Solution { if (strs.length === 1) { return strs[0]; } - + let mini = 0; for (let i = 1; i < strs.length; i++) { if (strs[mini].length > strs[i].length) { @@ -493,11 +553,69 @@ class Solution { } ``` +```csharp +public class TrieNode { + public Dictionary Children = new Dictionary(); +} + +public class Trie { + public TrieNode Root; + + public Trie() { + Root = new TrieNode(); + } + + public void Insert(string word) { + TrieNode node = Root; + foreach (char c in word) { + if (!node.Children.ContainsKey(c)) { + node.Children[c] = new TrieNode(); + } + node = node.Children[c]; + } + } + + public int Lcp(string word, int prefixLen) { + TrieNode node = Root; + for (int i = 0; i < Math.Min(word.Length, prefixLen); i++) { + if (!node.Children.ContainsKey(word[i])) { + return i; + } + node = node.Children[word[i]]; + } + return Math.Min(word.Length, prefixLen); + } +} + +public class Solution { + public string LongestCommonPrefix(string[] strs) { + if (strs.Length == 1) return strs[0]; + + int mini = 0; + for (int i = 1; i < strs.Length; i++) { + if (strs[i].Length < strs[mini].Length) { + mini = i; + } + } + + Trie trie = new Trie(); + trie.Insert(strs[mini]); + + int prefixLen = strs[mini].Length; + for (int i = 0; i < strs.Length; i++) { + prefixLen = trie.Lcp(strs[i], prefixLen); + } + + return strs[0].Substring(0, prefixLen); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n)$ -> Where $n$ is the length of the shortest string and $m$ is the number of strings. \ No newline at end of file +> Where $n$ is the length of the shortest string and $m$ is the number of strings. diff --git a/articles/longest-common-subsequence.md b/articles/longest-common-subsequence.md index f75a48573..0c89c32e5 100644 --- a/articles/longest-common-subsequence.md +++ b/articles/longest-common-subsequence.md @@ -5,14 +5,14 @@ ```python class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: - + def dfs(i, j): if i == len(text1) or j == len(text2): return 0 if text1[i] == text2[j]: return 1 + dfs(i + 1, j + 1) return max(dfs(i + 1, j), dfs(i, j + 1)) - + return dfs(0, 0) ``` @@ -64,7 +64,6 @@ class Solution { * @return {number} */ longestCommonSubsequence(text1, text2) { - const dfs = (i, j) => { if (i === text1.length || j === text2.length) { return 0; @@ -73,8 +72,8 @@ class Solution { return 1 + dfs(i + 1, j + 1); } return Math.max(dfs(i + 1, j), dfs(i, j + 1)); - } - + }; + return dfs(0, 0); } } @@ -93,7 +92,7 @@ public class Solution { if (text1[i] == text2[j]) { return 1 + Dfs(text1, text2, i + 1, j + 1); } - return Math.Max(Dfs(text1, text2, i + 1, j), + return Math.Max(Dfs(text1, text2, i + 1, j), Dfs(text1, text2, i, j + 1)); } } @@ -136,12 +135,33 @@ class Solution { } ``` +```swift +class Solution { + func longestCommonSubsequence(_ text1: String, _ text2: String) -> Int { + let arr1 = Array(text1) + let arr2 = Array(text2) + + func dfs(_ i: Int, _ j: Int) -> Int { + if i == arr1.count || j == arr2.count { + return 0 + } + if arr1[i] == arr2[j] { + return 1 + dfs(i + 1, j + 1) + } + return max(dfs(i + 1, j), dfs(i, j + 1)) + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ {m + n})$ -* Space complexity: $O(m + n)$ +- Time complexity: $O(2 ^ {m + n})$ +- Space complexity: $O(m + n)$ > Where $m$ is the length of the string $text1$ and $n$ is the length of the string $text2$. @@ -161,14 +181,14 @@ class Solution: return 0 if (i, j) in memo: return memo[(i, j)] - + if text1[i] == text2[j]: memo[(i, j)] = 1 + dfs(i + 1, j + 1) else: memo[(i, j)] = max(dfs(i + 1, j), dfs(i, j + 1)) - + return memo[(i, j)] - + return dfs(0, 0) ``` @@ -196,7 +216,7 @@ public class Solution { if (text1.charAt(i) == text2.charAt(j)) { memo[i][j] = 1 + dfs(text1, text2, i + 1, j + 1); } else { - memo[i][j] = Math.max(dfs(text1, text2, i + 1, j), + memo[i][j] = Math.max(dfs(text1, text2, i + 1, j), dfs(text1, text2, i, j + 1)); } return memo[i][j]; @@ -225,7 +245,7 @@ public: if (text1[i] == text2[j]) { memo[i][j] = 1 + dfs(text1, text2, i + 1, j + 1); } else { - memo[i][j] = max(dfs(text1, text2, i + 1, j), + memo[i][j] = max(dfs(text1, text2, i + 1, j), dfs(text1, text2, i, j + 1)); } return memo[i][j]; @@ -241,9 +261,9 @@ class Solution { * @return {number} */ longestCommonSubsequence(text1, text2) { - - const memo = Array(text1.length).fill().map(() => - Array(text2.length).fill(-1)); + const memo = Array(text1.length) + .fill() + .map(() => Array(text2.length).fill(-1)); const dfs = (i, j) => { if (i === text1.length || j === text2.length) { @@ -255,8 +275,7 @@ class Solution { if (text1[i] === text2[j]) { memo[i][j] = 1 + dfs(i + 1, j + 1); } else { - memo[i][j] = Math.max(dfs(i + 1, j), - dfs(i, j + 1)); + memo[i][j] = Math.max(dfs(i + 1, j), dfs(i, j + 1)); } return memo[i][j]; }; @@ -290,7 +309,7 @@ public class Solution { if (text1[i] == text2[j]) { memo[i, j] = 1 + Dfs(text1, text2, i + 1, j + 1); } else { - memo[i, j] = Math.Max(Dfs(text1, text2, i + 1, j), + memo[i, j] = Math.Max(Dfs(text1, text2, i + 1, j), Dfs(text1, text2, i, j + 1)); } return memo[i, j]; @@ -317,13 +336,13 @@ func longestCommonSubsequence(text1 string, text2 string) int { if memo[i][j] != -1 { return memo[i][j] } - + if text1[i] == text2[j] { memo[i][j] = 1 + dfs(i+1, j+1) } else { memo[i][j] = max(dfs(i+1, j), dfs(i, j+1)) } - + return memo[i][j] } @@ -354,7 +373,7 @@ class Solution { } else { maxOf(dfs(i + 1, j), dfs(i, j + 1)) } - + return memo[i][j] } @@ -363,12 +382,41 @@ class Solution { } ``` +```swift +class Solution { + func longestCommonSubsequence(_ text1: String, _ text2: String) -> Int { + let arr1 = Array(text1) + let arr2 = Array(text2) + var memo = [String: Int]() + + func dfs(_ i: Int, _ j: Int) -> Int { + if i == arr1.count || j == arr2.count { + return 0 + } + let key = "\(i),\(j)" + if let val = memo[key] { + return val + } + + if arr1[i] == arr2[j] { + memo[key] = 1 + dfs(i + 1, j + 1) + } else { + memo[key] = max(dfs(i + 1, j), dfs(i, j + 1)) + } + return memo[key]! + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the length of the string $text1$ and $n$ is the length of the string $text2$. @@ -381,7 +429,7 @@ class Solution { ```python class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: - dp = [[0 for j in range(len(text2) + 1)] + dp = [[0 for j in range(len(text2) + 1)] for i in range(len(text1) + 1)] for i in range(len(text1) - 1, -1, -1): @@ -418,7 +466,7 @@ public class Solution { class Solution { public: int longestCommonSubsequence(string text1, string text2) { - vector> dp(text1.size() + 1, + vector> dp(text1.size() + 1, vector(text2.size() + 1)); for (int i = text1.size() - 1; i >= 0; i--) { @@ -534,12 +582,37 @@ class Solution { } ``` +```swift +class Solution { + func longestCommonSubsequence(_ text1: String, _ text2: String) -> Int { + let m = text1.count + let n = text2.count + let arr1 = Array(text1) + let arr2 = Array(text2) + + var dp = Array(repeating: Array(repeating: 0, count: n + 1), count: m + 1) + + for i in stride(from: m - 1, through: 0, by: -1) { + for j in stride(from: n - 1, through: 0, by: -1) { + if arr1[i] == arr2[j] { + dp[i][j] = 1 + dp[i + 1][j + 1] + } else { + dp[i][j] = max(dp[i][j + 1], dp[i + 1][j]) + } + } + } + + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the length of the string $text1$ and $n$ is the length of the string $text2$. @@ -554,7 +627,7 @@ class Solution: def longestCommonSubsequence(self, text1: str, text2: str) -> int: if len(text1) < len(text2): text1, text2 = text2, text1 - + prev = [0] * (len(text2) + 1) curr = [0] * (len(text2) + 1) @@ -690,7 +763,7 @@ func longestCommonSubsequence(text1 string, text2 string) int { if len(text1) < len(text2) { text1, text2 = text2, text1 } - + prev := make([]int, len(text2)+1) curr := make([]int, len(text2)+1) @@ -739,9 +812,38 @@ class Solution { } } val temp = prev - prev.fill(0) + prev.fill(0) prev.indices.forEach { prev[it] = curr[it] } - curr.fill(0) + curr.fill(0) + } + + return prev[0] + } +} +``` + +```swift +class Solution { + func longestCommonSubsequence(_ text1: String, _ text2: String) -> Int { + var t1 = Array(text1) + var t2 = Array(text2) + + if t1.count < t2.count { + swap(&t1, &t2) + } + + var prev = Array(repeating: 0, count: t2.count + 1) + var curr = Array(repeating: 0, count: t2.count + 1) + + for i in stride(from: t1.count - 1, through: 0, by: -1) { + for j in stride(from: t2.count - 1, through: 0, by: -1) { + if t1[i] == t2[j] { + curr[j] = 1 + prev[j + 1] + } else { + curr[j] = max(curr[j + 1], prev[j]) + } + } + swap(&prev, &curr) } return prev[0] @@ -753,8 +855,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(min(m, n))$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(min(m, n))$ > Where $m$ is the length of the string $text1$ and $n$ is the length of the string $text2$. @@ -966,11 +1068,41 @@ class Solution { } ``` +```swift +class Solution { + func longestCommonSubsequence(_ text1: String, _ text2: String) -> Int { + var t1 = Array(text1) + var t2 = Array(text2) + + if t1.count < t2.count { + swap(&t1, &t2) + } + + var dp = Array(repeating: 0, count: t2.count + 1) + + for i in stride(from: t1.count - 1, through: 0, by: -1) { + var prev = 0 + for j in stride(from: t2.count - 1, through: 0, by: -1) { + let temp = dp[j] + if t1[i] == t2[j] { + dp[j] = 1 + prev + } else { + dp[j] = max(dp[j], dp[j + 1]) + } + prev = temp + } + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(min(m, n))$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(min(m, n))$ -> Where $m$ is the length of the string $text1$ and $n$ is the length of the string $text2$. \ No newline at end of file +> Where $m$ is the length of the string $text1$ and $n$ is the length of the string $text2$. diff --git a/articles/longest-consecutive-sequence.md b/articles/longest-consecutive-sequence.md index 9f7193486..6112daf7b 100644 --- a/articles/longest-consecutive-sequence.md +++ b/articles/longest-consecutive-sequence.md @@ -70,7 +70,8 @@ class Solution { const store = new Set(nums); for (let num of nums) { - let streak = 0, curr = num; + let streak = 0, + curr = num; while (store.has(curr)) { streak++; curr++; @@ -143,12 +144,35 @@ class Solution { } ``` +```swift +class Solution { + func longestConsecutive(_ nums: [Int]) -> Int { + var res = 0 + let store = Set(nums) + + for num in nums { + var streak = 0 + var curr = num + + while store.contains(curr) { + streak += 1 + curr += 1 + } + + res = max(res, streak) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -163,7 +187,7 @@ class Solution: return 0 res = 0 nums.sort() - + curr, streak = nums[0], 0 i = 0 while i < len(nums): @@ -212,7 +236,7 @@ public: sort(nums.begin(), nums.end()); int res = 0, curr = nums[0], streak = 0, i = 0; - + while (i < nums.size()) { if (curr != nums[i]) { curr = nums[i]; @@ -241,8 +265,11 @@ class Solution { return 0; } nums.sort((a, b) => a - b); - - let res = 0, curr = nums[0], streak = 0, i = 0; + + let res = 0, + curr = nums[0], + streak = 0, + i = 0; while (i < nums.length) { if (curr !== nums[i]) { @@ -268,7 +295,7 @@ public class Solution { return 0; } Array.Sort(nums); - + int res = 0, curr = nums[0], streak = 0, i = 0; while (i < nums.Length) { @@ -294,7 +321,7 @@ func longestConsecutive(nums []int) int { return 0 } sort.Ints(nums) - + res := 0 curr, streak := nums[0], 0 i := 0 @@ -343,12 +370,44 @@ class Solution { } ``` +```swift +class Solution { + func longestConsecutive(_ nums: [Int]) -> Int { + if nums.isEmpty { + return 0 + } + + var res = 0 + var nums = nums.sorted() + + var curr = nums[0] + var streak = 0 + var i = 0 + + while i < nums.count { + if curr != nums[i] { + curr = nums[i] + streak = 0 + } + while i < nums.count && nums[i] == curr { + i += 1 + } + streak += 1 + curr += 1 + res = max(res, streak) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -454,7 +513,7 @@ public class Solution { longest = Math.Max(longest, length); } } - return longest; + return longest; } } ``` @@ -506,12 +565,33 @@ class Solution { } ``` +```swift +class Solution { + func longestConsecutive(_ nums: [Int]) -> Int { + let numSet = Set(nums) + var longest = 0 + + for num in numSet { + if !numSet.contains(num - 1) { + var length = 1 + while numSet.contains(num + length) { + length += 1 + } + longest = max(length, longest) + } + } + + return longest + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -585,7 +665,10 @@ class Solution { for (let num of nums) { if (!mp.has(num)) { - mp.set(num, (mp.get(num - 1) || 0) + (mp.get(num + 1) || 0) + 1); + mp.set( + num, + (mp.get(num - 1) || 0) + (mp.get(num + 1) || 0) + 1, + ); mp.set(num - (mp.get(num - 1) || 0), mp.get(num)); mp.set(num + (mp.get(num + 1) || 0), mp.get(num)); res = Math.max(res, mp.get(num)); @@ -604,7 +687,7 @@ public class Solution { foreach (int num in nums) { if (!mp.ContainsKey(num)) { - mp[num] = (mp.ContainsKey(num - 1) ? mp[num - 1] : 0) + + mp[num] = (mp.ContainsKey(num - 1) ? mp[num - 1] : 0) + (mp.ContainsKey(num + 1) ? mp[num + 1] : 0) + 1; mp[num - (mp.ContainsKey(num - 1) ? mp[num - 1] : 0)] = mp[num]; @@ -662,9 +745,34 @@ class Solution { } ``` +```swift +class Solution { + func longestConsecutive(_ nums: [Int]) -> Int { + var mp = [Int: Int]() + var res = 0 + + for num in nums { + if mp[num] == nil { + let left = mp[num - 1] ?? 0 + let right = mp[num + 1] ?? 0 + let length = left + right + 1 + + mp[num] = length + mp[num - left] = length + mp[num + right] = length + + res = max(res, length) + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit.md b/articles/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit.md new file mode 100644 index 000000000..a40a183f0 --- /dev/null +++ b/articles/longest-continuous-subarray-with-absolute-diff-less-than-or-equal-to-limit.md @@ -0,0 +1,737 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def longestSubarray(self, nums: List[int], limit: int) -> int: + n = len(nums) + res = 1 + + for i in range(n): + mini = maxi = nums[i] + for j in range(i + 1, n): + mini = min(mini, nums[j]) + maxi = max(maxi, nums[j]) + if maxi - mini > limit: + break + res = max(res, j - i + 1) + + return res +``` + +```java +public class Solution { + public int longestSubarray(int[] nums, int limit) { + int n = nums.length; + int res = 1; + + for (int i = 0; i < n; i++) { + int mini = nums[i], maxi = nums[i]; + for (int j = i + 1; j < n; j++) { + mini = Math.min(mini, nums[j]); + maxi = Math.max(maxi, nums[j]); + if (maxi - mini > limit) { + break; + } + res = Math.max(res, j - i + 1); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestSubarray(vector& nums, int limit) { + int n = nums.size(); + int res = 1; + + for (int i = 0; i < n; i++) { + int mini = nums[i], maxi = nums[i]; + for (int j = i + 1; j < n; j++) { + mini = min(mini, nums[j]); + maxi = max(maxi, nums[j]); + if (maxi - mini > limit) { + break; + } + res = max(res, j - i + 1); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} limit + * @return {number} + */ + longestSubarray(nums, limit) { + const n = nums.length; + let res = 1; + + for (let i = 0; i < n; i++) { + let mini = nums[i], + maxi = nums[i]; + for (let j = i + 1; j < n; j++) { + mini = Math.min(mini, nums[j]); + maxi = Math.max(maxi, nums[j]); + if (maxi - mini > limit) { + break; + } + res = Math.max(res, j - i + 1); + } + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int LongestSubarray(int[] nums, int limit) { + int n = nums.Length; + int res = 1; + + for (int i = 0; i < n; i++) { + int mini = nums[i], maxi = nums[i]; + for (int j = i + 1; j < n; j++) { + mini = Math.Min(mini, nums[j]); + maxi = Math.Max(maxi, nums[j]); + if (maxi - mini > limit) { + break; + } + res = Math.Max(res, j - i + 1); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Heap + +::tabs-start + +```python +class Solution: + def longestSubarray(self, nums: List[int], limit: int) -> int: + maxHeap = [] + minHeap = [] + j = 0 + res = 0 + + for i, v in enumerate(nums): + heapq.heappush(maxHeap, (-v, i)) + heapq.heappush(minHeap, (v, i)) + + while -maxHeap[0][0] - minHeap[0][0] > limit: + j += 1 + while maxHeap and maxHeap[0][1] < j: + heapq.heappop(maxHeap) + while minHeap and minHeap[0][1] < j: + heapq.heappop(minHeap) + + res = max(res, i - j + 1) + + return res +``` + +```java +public class Solution { + public int longestSubarray(int[] nums, int limit) { + PriorityQueue maxHeap = new PriorityQueue<>( + (a,b) -> b[0] - a[0] + ); + PriorityQueue minHeap = new PriorityQueue<>( + (a,b) -> a[0] - b[0] + ); + int j = 0, res = 0; + for (int i = 0; i < nums.length; ++i) { + int v = nums[i]; + maxHeap.offer(new int[]{v, i}); + minHeap.offer(new int[]{v, i}); + + while (maxHeap.peek()[0] - minHeap.peek()[0] > limit) { + ++j; + while (!maxHeap.isEmpty() && maxHeap.peek()[1] < j) { + maxHeap.poll(); + } + while (!minHeap.isEmpty() && minHeap.peek()[1] < j) { + minHeap.poll(); + } + } + + res = Math.max(res, i - j + 1); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestSubarray(vector& nums, int limit) { + priority_queue> maxHeap; + priority_queue< + pair, + vector>, + greater> + > minHeap; + + int j = 0, res = 0; + for (int i = 0; i < (int)nums.size(); ++i) { + int v = nums[i]; + maxHeap.emplace(v, i); + minHeap.emplace(v, i); + + while (maxHeap.top().first - minHeap.top().first > limit) { + ++j; + while (!maxHeap.empty() && maxHeap.top().second < j) + maxHeap.pop(); + while (!minHeap.empty() && minHeap.top().second < j) + minHeap.pop(); + } + + res = max(res, i - j + 1); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} limit + * @return {number} + */ + longestSubarray(nums, limit) { + const maxHeap = new PriorityQueue((a, b) => b[0] - a[0]); + const minHeap = new PriorityQueue((a, b) => a[0] - b[0]); + let j = 0, + res = 0; + + for (let i = 0; i < nums.length; ++i) { + const v = nums[i]; + maxHeap.push([v, i]); + minHeap.push([v, i]); + + while (maxHeap.front()[0] - minHeap.front()[0] > limit) { + ++j; + while (!maxHeap.isEmpty() && maxHeap.front()[1] < j) + maxHeap.pop(); + while (!minHeap.isEmpty() && minHeap.front()[1] < j) + minHeap.pop(); + } + + res = Math.max(res, i - j + 1); + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int LongestSubarray(int[] nums, int limit) { + var maxHeap = new PriorityQueue(); + var minHeap = new PriorityQueue(); + + int j = 0, res = 0; + for (int i = 0; i < nums.Length; ++i) { + int v = nums[i]; + maxHeap.Enqueue(new[]{v, i}, -v); + minHeap.Enqueue(new[]{v, i}, v); + + while (maxHeap.Peek()[0] - minHeap.Peek()[0] > limit) { + ++j; + while (maxHeap.Count > 0 && maxHeap.Peek()[1] < j) + maxHeap.Dequeue(); + while (minHeap.Count > 0 && minHeap.Peek()[1] < j) + minHeap.Dequeue(); + } + + res = Math.Max(res, i - j + 1); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Sorted Dict + +::tabs-start + +```python +class Solution: + def longestSubarray(self, nums: List[int], limit: int) -> int: + tree = SortedDict() + l = res = 0 + for r, x in enumerate(nums): + tree[x] = tree.get(x, 0) + 1 + while tree.peekitem(-1)[0] - tree.peekitem(0)[0] > limit: + y = nums[l] + tree[y] -= 1 + if tree[y] == 0: + del tree[y] + l += 1 + res = max(res, r - l + 1) + return res +``` + +```java +public class Solution { + public int longestSubarray(int[] nums, int limit) { + TreeMap map = new TreeMap<>(); + int l = 0, res = 0; + for (int r = 0; r < nums.length; r++) { + map.put(nums[r], map.getOrDefault(nums[r],0) + 1); + while (map.lastKey() - map.firstKey() > limit) { + int cnt = map.get(nums[l]); + if (cnt == 1) map.remove(nums[l]); + else map.put(nums[l], cnt - 1); + l++; + } + res = Math.max(res, r - l + 1); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestSubarray(vector& nums, int limit) { + multiset ms; + int l = 0, res = 0; + for (int r = 0; r < nums.size(); r++) { + ms.insert(nums[r]); + while (*ms.rbegin() - *ms.begin() > limit) { + ms.erase(ms.find(nums[l])); + l++; + } + res = max(res, r - l + 1); + } + return res; + } +}; +``` + +```csharp +public class Solution { + public int LongestSubarray(int[] nums, int limit) { + var map = new SortedList(); + int l = 0, res = 0; + for (int r = 0; r < nums.Length; r++) { + int x = nums[r]; + if (!map.ContainsKey(x)) map[x] = 0; + map[x]++; + + while (map.Keys[map.Count - 1] - map.Keys[0] > limit) { + int y = nums[l++]; + map[y]--; + if (map[y] == 0) map.Remove(y); + } + + res = Math.Max(res, r - l + 1); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Deque - I + +::tabs-start + +```python +class Solution: + def longestSubarray(self, nums: List[int], limit: int) -> int: + min_q = deque() # mono increasing + max_q = deque() # mono decreasing + l = res = 0 + + for r in range(len(nums)): + while min_q and nums[r] < min_q[-1]: + min_q.pop() + while max_q and nums[r] > max_q[-1]: + max_q.pop() + + min_q.append(nums[r]) + max_q.append(nums[r]) + + while max_q[0] - min_q[0] > limit: + if nums[l] == max_q[0]: + max_q.popleft() + if nums[l] == min_q[0]: + min_q.popleft() + l += 1 + res = max(res, r - l + 1) + return res +``` + +```java +public class Solution { + public int longestSubarray(int[] nums, int limit) { + Deque minQ = new ArrayDeque<>(); + Deque maxQ = new ArrayDeque<>(); + int l = 0, res = 0; + for (int r = 0; r < nums.length; r++) { + while (!minQ.isEmpty() && nums[r] < minQ.peekLast()) { + minQ.removeLast(); + } + while (!maxQ.isEmpty() && nums[r] > maxQ.peekLast()) { + maxQ.removeLast(); + } + minQ.addLast(nums[r]); + maxQ.addLast(nums[r]); + while (maxQ.peekFirst() - minQ.peekFirst() > limit) { + if (nums[l] == maxQ.peekFirst()) { + maxQ.removeFirst(); + } + if (nums[l] == minQ.peekFirst()) { + minQ.removeFirst(); + } + l++; + } + res = Math.max(res, r - l + 1); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestSubarray(vector& nums, int limit) { + deque minQ, maxQ; + int l = 0, res = 0; + for (int r = 0; r < nums.size(); r++) { + while (!minQ.empty() && nums[r] < minQ.back()) { + minQ.pop_back(); + } + while (!maxQ.empty() && nums[r] > maxQ.back()) { + maxQ.pop_back(); + } + minQ.push_back(nums[r]); + maxQ.push_back(nums[r]); + while (maxQ.front() - minQ.front() > limit) { + if (nums[l] == maxQ.front()) { + maxQ.pop_front(); + } + if (nums[l] == minQ.front()) { + minQ.pop_front(); + } + l++; + } + res = max(res, r - l + 1); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} limit + * @return {number} + */ + longestSubarray(nums, limit) { + const minQ = new Deque(); + const maxQ = new Deque(); + let l = 0, + res = 0; + for (let r = 0; r < nums.length; r++) { + while (!minQ.isEmpty() && nums[r] < minQ.back()) { + minQ.popBack(); + } + while (!maxQ.isEmpty() && nums[r] > maxQ.back()) { + maxQ.popBack(); + } + + minQ.pushBack(nums[r]); + maxQ.pushBack(nums[r]); + + while (maxQ.front() - minQ.front() > limit) { + if (nums[l] === maxQ.front()) { + maxQ.popFront(); + } + if (nums[l] === minQ.front()) { + minQ.popFront(); + } + l++; + } + + res = Math.max(res, r - l + 1); + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int LongestSubarray(int[] nums, int limit) { + var minQ = new LinkedList(); + var maxQ = new LinkedList(); + int l = 0, res = 0; + for (int r = 0; r < nums.Length; r++) { + while (minQ.Count > 0 && nums[r] < minQ.Last.Value) { + minQ.RemoveLast(); + } + while (maxQ.Count > 0 && nums[r] > maxQ.Last.Value) { + maxQ.RemoveLast(); + } + minQ.AddLast(nums[r]); + maxQ.AddLast(nums[r]); + while (maxQ.First.Value - minQ.First.Value > limit) { + if (nums[l] == maxQ.First.Value) { + maxQ.RemoveFirst(); + } + if (nums[l] == minQ.First.Value) { + minQ.RemoveFirst(); + } + l++; + } + res = System.Math.Max(res, r - l + 1); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 5. Deque - II + +::tabs-start + +```python +class Solution: + def longestSubarray(self, nums: List[int], limit: int) -> int: + inc = deque([nums[0]]) + dec = deque([nums[0]]) + res = 1 + j = 0 + + for i in range(1, len(nums)): + while inc and inc[-1] > nums[i]: + inc.pop() + while dec and dec[-1] < nums[i]: + dec.pop() + + inc.append(nums[i]) + dec.append(nums[i]) + if dec[0] - inc[0] > limit: + if dec[0] == nums[j]: + dec.popleft() + if inc[0] == nums[j]: + inc.popleft() + j += 1 + + return len(nums) - j +``` + +```java +public class Solution { + public int longestSubarray(int[] nums, int limit) { + Deque inc = new ArrayDeque<>(); + Deque dec = new ArrayDeque<>(); + inc.addLast(nums[0]); + dec.addLast(nums[0]); + int res = 1, j = 0; + + for (int i = 1; i < nums.length; i++) { + while (!inc.isEmpty() && inc.peekLast() > nums[i]) { + inc.removeLast(); + } + while (!dec.isEmpty() && dec.peekLast() < nums[i]) { + dec.removeLast(); + } + + inc.addLast(nums[i]); + dec.addLast(nums[i]); + if (dec.peekFirst() - inc.peekFirst() > limit) { + if (dec.peekFirst().equals(nums[j])) { + dec.removeFirst(); + } + if (inc.peekFirst().equals(nums[j])) { + inc.removeFirst(); + } + j++; + } + } + + return nums.length - j; + } +} +``` + +```cpp +class Solution { +public: + int longestSubarray(vector& nums, int limit) { + deque inc, dec; + inc.push_back(nums[0]); + dec.push_back(nums[0]); + int res = 1, j = 0, n = nums.size(); + + for (int i = 1; i < n; i++) { + while (!inc.empty() && inc.back() > nums[i]) { + inc.pop_back(); + } + while (!dec.empty() && dec.back() < nums[i]) { + dec.pop_back(); + } + + inc.push_back(nums[i]); + dec.push_back(nums[i]); + if (dec.front() - inc.front() > limit) { + if (dec.front() == nums[j]) { + dec.pop_front(); + } + if (inc.front() == nums[j]) { + inc.pop_front(); + } + j++; + } + } + + return n - j; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} limit + * @return {number} + */ + longestSubarray(nums, limit) { + const inc = new Deque([nums[0]]); + const dec = new Deque([nums[0]]); + let res = 1, + j = 0; + + for (let i = 1; i < nums.length; i++) { + while (!inc.isEmpty() && inc.back() > nums[i]) { + inc.popBack(); + } + while (!dec.isEmpty() && dec.back() < nums[i]) { + dec.popBack(); + } + + inc.pushBack(nums[i]); + dec.pushBack(nums[i]); + if (dec.front() - inc.front() > limit) { + if (dec.front() === nums[j]) { + dec.popFront(); + } + if (inc.front() === nums[j]) { + inc.popFront(); + } + j++; + } + } + + return nums.length - j; + } +} +``` + +```csharp +public class Solution { + public int LongestSubarray(int[] nums, int limit) { + var inc = new LinkedList(); + var dec = new LinkedList(); + inc.AddLast(nums[0]); + dec.AddLast(nums[0]); + int res = 1, j = 0; + + for (int i = 1; i < nums.Length; i++) { + while (inc.Count > 0 && inc.Last.Value > nums[i]) { + inc.RemoveLast(); + } + while (dec.Count > 0 && dec.Last.Value < nums[i]) { + dec.RemoveLast(); + } + + inc.AddLast(nums[i]); + dec.AddLast(nums[i]); + if (dec.First.Value - inc.First.Value > limit) { + if (dec.First.Value == nums[j]) { + dec.RemoveFirst(); + } + if (inc.First.Value == nums[j]) { + inc.RemoveFirst(); + } + j++; + } + } + + return nums.Length - j; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/longest-happy-string.md b/articles/longest-happy-string.md index e5f2e0573..7befbdb5e 100644 --- a/articles/longest-happy-string.md +++ b/articles/longest-happy-string.md @@ -166,14 +166,53 @@ class Solution { } ``` +```csharp +public class Solution { + public string LongestDiverseString(int a, int b, int c) { + int[] count = new int[] { a, b, c }; + List res = new List(); + + int GetMax(int repeated) { + int idx = -1; + int maxCnt = 0; + for (int i = 0; i < 3; i++) { + if (i == repeated || count[i] == 0) continue; + if (maxCnt < count[i]) { + maxCnt = count[i]; + idx = i; + } + } + return idx; + } + + int repeated = -1; + while (true) { + int maxChar = GetMax(repeated); + if (maxChar == -1) break; + + res.Add((char)(maxChar + 'a')); + count[maxChar]--; + + if (res.Count > 1 && res[res.Count - 1] == res[res.Count - 2]) { + repeated = maxChar; + } else { + repeated = -1; + } + } + + return new string(res.ToArray()); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(1)$ extra space. - * $O(n)$ space for the output string. +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output string. --- @@ -189,7 +228,7 @@ class Solution: for count, char in [(-a, "a"), (-b, "b"), (-c, "c")]: if count != 0: heapq.heappush(maxHeap, (count, char)) - + while maxHeap: count, char = heapq.heappop(maxHeap) if len(res) > 1 and res[-1] == res[-2] == char: @@ -283,18 +322,22 @@ class Solution { */ longestDiverseString(a, b, c) { const res = []; - const maxHeap = new MaxPriorityQueue({ priority: (x) => x[0] }); + const maxHeap = new MaxPriorityQueue((x) => x[0]); if (a > 0) maxHeap.enqueue([a, 'a']); if (b > 0) maxHeap.enqueue([b, 'b']); if (c > 0) maxHeap.enqueue([c, 'c']); while (!maxHeap.isEmpty()) { - const [count, char] = maxHeap.dequeue().element; + const [count, char] = maxHeap.dequeue(); - if (res.length > 1 && res[res.length - 1] === char && res[res.length - 2] === char) { + if ( + res.length > 1 && + res[res.length - 1] === char && + res[res.length - 2] === char + ) { if (maxHeap.isEmpty()) break; - const [count2, char2] = maxHeap.dequeue().element; + const [count2, char2] = maxHeap.dequeue(); res.push(char2); if (count2 - 1 > 0) maxHeap.enqueue([count2 - 1, char2]); maxHeap.enqueue([count, char]); @@ -309,14 +352,55 @@ class Solution { } ``` +```csharp +public class Solution { + public string LongestDiverseString(int a, int b, int c) { + string res = ""; + PriorityQueue<(int count, char ch), int> maxHeap = new PriorityQueue<(int, char), int>(); + + void AddToHeap(int count, char ch) { + if (count > 0) { + maxHeap.Enqueue((count, ch), -count); + } + } + + AddToHeap(a, 'a'); + AddToHeap(b, 'b'); + AddToHeap(c, 'c'); + + while (maxHeap.Count > 0) { + var (count1, ch1) = maxHeap.Dequeue(); + if (res.Length >= 2 && res[^1] == ch1 && res[^2] == ch1) { + if (maxHeap.Count == 0) break; + var (count2, ch2) = maxHeap.Dequeue(); + res += ch2; + count2--; + if (count2 > 0) { + maxHeap.Enqueue((count2, ch2), -count2); + } + maxHeap.Enqueue((count1, ch1), -count1); + } else { + res += ch1; + count1--; + if (count1 > 0) { + maxHeap.Enqueue((count1, ch1), -count1); + } + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(1)$ extra space. - * $O(n)$ space for the output string. +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output string. --- @@ -334,12 +418,12 @@ class Solution: return rec(max1, max3, max2, char1, char3, char2) if max2 == 0: return [char1] * min(2, max1) - + use1 = min(2, max1) use2 = 1 if max1 - use1 >= max2 else 0 res = [char1] * use1 + [char2] * use2 return res + rec(max1 - use1, max2 - use2, max3, char1, char2, char3) - + return ''.join(rec(a, b, c, 'a', 'b', 'c')) ``` @@ -440,7 +524,9 @@ class Solution { const use2 = max1 - use1 >= max2 ? 1 : 0; const res = Array(use1).fill(char1).concat(Array(use2).fill(char2)); - return res.concat(rec(max1 - use1, max2 - use2, max3, char1, char2, char3)); + return res.concat( + rec(max1 - use1, max2 - use2, max3, char1, char2, char3), + ); }; return rec(a, b, c, 'a', 'b', 'c').join(''); @@ -448,11 +534,40 @@ class Solution { } ``` +```csharp +public class Solution { + public string LongestDiverseString(int a, int b, int c) { + return string.Join("", Rec(a, b, c, 'a', 'b', 'c')); + } + + private List Rec(int max1, int max2, int max3, char char1, char char2, char char3) { + if (max1 < max2) return Rec(max2, max1, max3, char2, char1, char3); + if (max2 < max3) return Rec(max1, max3, max2, char1, char3, char2); + if (max2 == 0) { + int use = Math.Min(2, max1); + var res = new List(); + for (int i = 0; i < use; i++) res.Add(char1); + return res; + } + + int use1 = Math.Min(2, max1); + int use2 = (max1 - use1 >= max2) ? 1 : 0; + + var result = new List(); + for (int i = 0; i < use1; i++) result.Add(char1); + for (int i = 0; i < use2; i++) result.Add(char2); + + result.AddRange(Rec(max1 - use1, max2 - use2, max3, char1, char2, char3)); + return result; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(n)$ for recursion stack. - * $O(n)$ space for the output string. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: + - $O(n)$ for recursion stack. + - $O(n)$ space for the output string. diff --git a/articles/longest-ideal-subsequence.md b/articles/longest-ideal-subsequence.md index 2162b48ec..5d4e9c95e 100644 --- a/articles/longest-ideal-subsequence.md +++ b/articles/longest-ideal-subsequence.md @@ -88,8 +88,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -200,7 +200,10 @@ class Solution { } const skip = dfs(i + 1, prev); let include = 0; - if (prev === -1 || Math.abs(s.charCodeAt(i) - ('a'.charCodeAt(0) + prev)) <= k) { + if ( + prev === -1 || + Math.abs(s.charCodeAt(i) - ('a'.charCodeAt(0) + prev)) <= k + ) { include = 1 + dfs(i + 1, s.charCodeAt(i) - 'a'.charCodeAt(0)); } dp[i][prev + 1] = Math.max(skip, include); @@ -216,8 +219,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -236,7 +239,7 @@ class Solution: dp[i][prev] = max(dp[i][prev], dp[i - 1][prev]) if abs(curr - prev) <= k: dp[i][curr] = max(dp[i][curr], 1 + dp[i - 1][prev]) - + return max(dp[len(s)]) ``` @@ -316,8 +319,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -337,7 +340,7 @@ class Solution: if abs(curr - prev) <= k: longest = max(longest, 1 + dp[prev]) dp[curr] = max(dp[curr], longest) - + return max(dp) ``` @@ -418,5 +421,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since we have at most 26 different characters. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we have at most 26 different characters. diff --git a/articles/longest-increasing-path-in-matrix.md b/articles/longest-increasing-path-in-matrix.md index 950ac6e73..07f6ec163 100644 --- a/articles/longest-increasing-path-in-matrix.md +++ b/articles/longest-increasing-path-in-matrix.md @@ -9,11 +9,11 @@ class Solution: directions = [[-1, 0], [1, 0], [0, -1], [0, 1]] def dfs(r, c, prevVal): - if (min(r, c) < 0 or r >= ROWS or + if (min(r, c) < 0 or r >= ROWS or c >= COLS or matrix[r][c] <= prevVal ): return 0 - + res = 1 for d in directions: res = max(res, 1 + dfs(r + d[0], c + d[1], matrix[r][c])) @@ -32,14 +32,14 @@ public class Solution { private int dfs(int[][] matrix, int r, int c, int prevVal) { int ROWS = matrix.length, COLS = matrix[0].length; - if (r < 0 || r >= ROWS || c < 0 || + if (r < 0 || r >= ROWS || c < 0 || c >= COLS || matrix[r][c] <= prevVal) { return 0; } int res = 1; for (int[] d : directions) { - res = Math.max(res, 1 + dfs(matrix, r + d[0], + res = Math.max(res, 1 + dfs(matrix, r + d[0], c + d[1], matrix[r][c])); } return res; @@ -61,18 +61,18 @@ public class Solution { ```cpp class Solution { public: - vector> directions = {{-1, 0}, {1, 0}, + vector> directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; - + int dfs(vector>& matrix, int r, int c, int prevVal) { int ROWS = matrix.size(), COLS = matrix[0].size(); - if (r < 0 || r >= ROWS || c < 0 || + if (r < 0 || r >= ROWS || c < 0 || c >= COLS || matrix[r][c] <= prevVal) return 0; - + int res = 1; for (auto d : directions) - res = max(res, 1 + dfs(matrix, r + d[0], + res = max(res, 1 + dfs(matrix, r + d[0], c + d[1], matrix[r][c])); return res; } @@ -96,19 +96,29 @@ class Solution { * @return {number} */ longestIncreasingPath(matrix) { - const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]; - const ROWS = matrix.length, COLS = matrix[0].length; + const directions = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], + ]; + const ROWS = matrix.length, + COLS = matrix[0].length; const dfs = (r, c, prevVal) => { - if (r < 0 || r >= ROWS || c < 0 || - c >= COLS || matrix[r][c] <= prevVal) { + if ( + r < 0 || + r >= ROWS || + c < 0 || + c >= COLS || + matrix[r][c] <= prevVal + ) { return 0; } let res = 1; for (let d of directions) { - res = Math.max(res, 1 + dfs(r + d[0], - c + d[1], matrix[r][c])); + res = Math.max(res, 1 + dfs(r + d[0], c + d[1], matrix[r][c])); } return res; }; @@ -127,20 +137,20 @@ class Solution { ```csharp public class Solution { private static int[][] directions = new int[][] { - new int[] {-1, 0}, new int[] {1, 0}, + new int[] {-1, 0}, new int[] {1, 0}, new int[] {0, -1}, new int[] {0, 1} }; private int Dfs(int[][] matrix, int r, int c, int prevVal) { int ROWS = matrix.Length, COLS = matrix[0].Length; - if (r < 0 || r >= ROWS || c < 0 || + if (r < 0 || r >= ROWS || c < 0 || c >= COLS || matrix[r][c] <= prevVal) { return 0; } int res = 1; foreach (var dir in directions) { - res = Math.Max(res, 1 + Dfs(matrix, r + dir[0], + res = Math.Max(res, 1 + Dfs(matrix, r + dir[0], c + dir[1], matrix[r][c])); } return res; @@ -166,7 +176,7 @@ func longestIncreasingPath(matrix [][]int) int { var dfs func(r, c, prevVal int) int dfs = func(r, c, prevVal int) int { - if r < 0 || r >= rows || c < 0 || c >= cols || + if r < 0 || r >= rows || c < 0 || c >= cols || matrix[r][c] <= prevVal { return 0 } @@ -198,7 +208,7 @@ func max(a, b int) int { ```kotlin class Solution { private val directions = arrayOf( - intArrayOf(-1, 0), intArrayOf(1, 0), + intArrayOf(-1, 0), intArrayOf(1, 0), intArrayOf(0, -1), intArrayOf(0, 1) ) @@ -207,7 +217,7 @@ class Solution { val cols = matrix[0].size fun dfs(r: Int, c: Int, prevVal: Int): Int { - if (r < 0 || r >= rows || c < 0 || c >= cols || + if (r < 0 || r >= rows || c < 0 || c >= cols || matrix[r][c] <= prevVal) { return 0 } @@ -230,12 +240,41 @@ class Solution { } ``` +```swift +class Solution { + func longestIncreasingPath(_ matrix: [[Int]]) -> Int { + let rows = matrix.count, cols = matrix[0].count + let directions = [(-1, 0), (1, 0), (0, -1), (0, 1)] + + func dfs(_ r: Int, _ c: Int, _ prevVal: Int) -> Int { + if r < 0 || c < 0 || r >= rows || c >= cols || matrix[r][c] <= prevVal { + return 0 + } + + var res = 1 + for (dr, dc) in directions { + res = max(res, 1 + dfs(r + dr, c + dc, matrix[r][c])) + } + return res + } + + var lip = 0 + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns in the given $matrix$. @@ -252,7 +291,7 @@ class Solution: dp = {} # (r, c) -> LIP def dfs(r, c, prevVal): - if (r < 0 or r == ROWS or c < 0 or + if (r < 0 or r == ROWS or c < 0 or c == COLS or matrix[r][c] <= prevVal ): return 0 @@ -280,7 +319,7 @@ public class Solution { private int dfs(int[][] matrix, int r, int c, int prevVal) { int ROWS = matrix.length, COLS = matrix[0].length; - if (r < 0 || r >= ROWS || c < 0 || + if (r < 0 || r >= ROWS || c < 0 || c >= COLS || matrix[r][c] <= prevVal) { return 0; } @@ -288,7 +327,7 @@ public class Solution { int res = 1; for (int[] d : directions) { - res = Math.max(res, 1 + dfs(matrix, r + d[0], + res = Math.max(res, 1 + dfs(matrix, r + d[0], c + d[1], matrix[r][c])); } return dp[r][c] = res; @@ -316,13 +355,13 @@ public class Solution { ```cpp class Solution { public: - vector> directions = {{-1, 0}, {1, 0}, + vector> directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; vector> dp; int dfs(vector>& matrix, int r, int c, int prevVal) { int ROWS = matrix.size(), COLS = matrix[0].size(); - if (r < 0 || r >= ROWS || c < 0 || + if (r < 0 || r >= ROWS || c < 0 || c >= COLS || matrix[r][c] <= prevVal) { return 0; } @@ -330,7 +369,7 @@ public: int res = 1; for (vector d : directions) { - res = max(res, 1 + dfs(matrix, r + d[0], + res = max(res, 1 + dfs(matrix, r + d[0], c + d[1], matrix[r][c])); } dp[r][c] = res; @@ -359,22 +398,31 @@ class Solution { * @return {number} */ longestIncreasingPath(matrix) { - const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]; - const ROWS = matrix.length, COLS = matrix[0].length; - let dp = Array.from({ length: ROWS }, () => - Array(COLS).fill(-1)); + const directions = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], + ]; + const ROWS = matrix.length, + COLS = matrix[0].length; + let dp = Array.from({ length: ROWS }, () => Array(COLS).fill(-1)); const dfs = (r, c, prevVal) => { - if (r < 0 || r >= ROWS || c < 0 || - c >= COLS || matrix[r][c] <= prevVal) { + if ( + r < 0 || + r >= ROWS || + c < 0 || + c >= COLS || + matrix[r][c] <= prevVal + ) { return 0; } if (dp[r][c] !== -1) return dp[r][c]; let res = 1; for (let d of directions) { - res = Math.max(res, 1 + dfs(r + d[0], - c + d[1], matrix[r][c])); + res = Math.max(res, 1 + dfs(r + d[0], c + d[1], matrix[r][c])); } dp[r][c] = res; return res; @@ -394,14 +442,14 @@ class Solution { ```csharp public class Solution { int[][] directions = new int[][] { - new int[] {-1, 0}, new int[] {1, 0}, + new int[] {-1, 0}, new int[] {1, 0}, new int[] {0, -1}, new int[] {0, 1} }; int[,] dp; private int Dfs(int[][] matrix, int r, int c, int prevVal) { int ROWS = matrix.Length, COLS = matrix[0].Length; - if (r < 0 || r >= ROWS || c < 0 || + if (r < 0 || r >= ROWS || c < 0 || c >= COLS || matrix[r][c] <= prevVal) { return 0; } @@ -409,7 +457,7 @@ public class Solution { int res = 1; foreach (int[] d in directions) { - res = Math.Max(res, 1 + Dfs(matrix, r + d[0], + res = Math.Max(res, 1 + Dfs(matrix, r + d[0], c + d[1], matrix[r][c])); } @@ -420,7 +468,7 @@ public class Solution { public int LongestIncreasingPath(int[][] matrix) { int ROWS = matrix.Length, COLS = matrix[0].Length; dp = new int[ROWS, COLS]; - + for (int i = 0; i < ROWS; i++) { for (int j = 0; j < COLS; j++) { dp[i, j] = -1; @@ -448,7 +496,7 @@ func longestIncreasingPath(matrix [][]int) int { var dfs func(r, c, prevVal int) int dfs = func(r, c, prevVal int) int { - if r < 0 || r >= rows || c < 0 || c >= cols || + if r < 0 || r >= rows || c < 0 || c >= cols || matrix[r][c] <= prevVal { return 0 } @@ -490,7 +538,7 @@ class Solution { val dp = Array(rows) { IntArray(cols) } fun dfs(r: Int, c: Int, prevVal: Int): Int { - if (r < 0 || r >= rows || c < 0 || c >= cols || + if (r < 0 || r >= rows || c < 0 || c >= cols || matrix[r][c] <= prevVal) { return 0 } @@ -518,12 +566,47 @@ class Solution { } ``` +```swift +class Solution { + func longestIncreasingPath(_ matrix: [[Int]]) -> Int { + let rows = matrix.count, cols = matrix[0].count + var dp = Array(repeating: Array(repeating: -1, count: cols), count: rows) + + func dfs(_ r: Int, _ c: Int, _ prevVal: Int) -> Int { + if r < 0 || r >= rows || c < 0 || c >= cols || matrix[r][c] <= prevVal { + return 0 + } + if dp[r][c] != -1 { + return dp[r][c] + } + + var res = 1 + res = max(res, 1 + dfs(r + 1, c, matrix[r][c])) + res = max(res, 1 + dfs(r - 1, c, matrix[r][c])) + res = max(res, 1 + dfs(r, c + 1, matrix[r][c])) + res = max(res, 1 + dfs(r, c - 1, matrix[r][c])) + + dp[r][c] = res + return res + } + + var maxPath = 0 + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns in the given $matrix$. @@ -539,12 +622,12 @@ class Solution: ROWS, COLS = len(matrix), len(matrix[0]) directions = [[-1, 0], [1, 0], [0, -1], [0, 1]] indegree = [[0] * COLS for _ in range(ROWS)] - + for r in range(ROWS): for c in range(COLS): for d in directions: nr, nc = d[0] + r, d[1] + c - if (0 <= nr < ROWS and 0 <= nc < COLS and + if (0 <= nr < ROWS and 0 <= nc < COLS and matrix[nr][nc] < matrix[r][c] ): indegree[r][c] += 1 @@ -561,7 +644,7 @@ class Solution: r, c = q.popleft() for d in directions: nr, nc = r + d[0], c + d[1] - if (0 <= nr < ROWS and 0 <= nc < COLS and + if (0 <= nr < ROWS and 0 <= nc < COLS and matrix[nr][nc] > matrix[r][c] ): indegree[nr][nc] -= 1 @@ -582,7 +665,7 @@ public class Solution { for (int c = 0; c < COLS; ++c) { for (int[] d : directions) { int nr = r + d[0], nc = c + d[1]; - if (nr >= 0 && nr < ROWS && nc >= 0 && + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && matrix[nr][nc] < matrix[r][c]) { indegree[r][c]++; } @@ -607,7 +690,7 @@ public class Solution { int r = node[0], c = node[1]; for (int[] d : directions) { int nr = r + d[0], nc = c + d[1]; - if (nr >= 0 && nr < ROWS && nc >= 0 && + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && matrix[nr][nc] > matrix[r][c]) { if (--indegree[nr][nc] == 0) { q.offer(new int[]{nr, nc}); @@ -628,21 +711,21 @@ public: int longestIncreasingPath(vector>& matrix) { int ROWS = matrix.size(), COLS = matrix[0].size(); vector> indegree(ROWS, vector(COLS, 0)); - vector> directions = {{-1, 0}, {1, 0}, + vector> directions = {{-1, 0}, {1, 0}, {0, -1}, {0, 1}}; - + for (int r = 0; r < ROWS; ++r) { for (int c = 0; c < COLS; ++c) { for (auto& d : directions) { int nr = r + d[0], nc = c + d[1]; - if (nr >= 0 && nr < ROWS && nc >= 0 && + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && matrix[nr][nc] < matrix[r][c]) { indegree[r][c]++; } } } } - + queue> q; for (int r = 0; r < ROWS; ++r) { for (int c = 0; c < COLS; ++c) { @@ -651,7 +734,7 @@ public: } } } - + int LIS = 0; while (!q.empty()) { int size = q.size(); @@ -660,7 +743,7 @@ public: q.pop(); for (auto& d : directions) { int nr = r + d[0], nc = c + d[1]; - if (nr >= 0 && nr < ROWS && nc >= 0 && + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && matrix[nr][nc] > matrix[r][c]) { if (--indegree[nr][nc] == 0) { q.push({nr, nc}); @@ -682,17 +765,28 @@ class Solution { * @return {number} */ longestIncreasingPath(matrix) { - const ROWS = matrix.length, COLS = matrix[0].length; - const directions = [[-1, 0], [1, 0], [0, -1], [0, 1]]; - let indegree = Array.from({ length: ROWS }, () => - Array(COLS).fill(0)); - + const ROWS = matrix.length, + COLS = matrix[0].length; + const directions = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], + ]; + let indegree = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); + for (let r = 0; r < ROWS; r++) { for (let c = 0; c < COLS; c++) { for (const [dr, dc] of directions) { - const nr = r + dr, nc = c + dc; - if (nr >= 0 && nr < ROWS && nc >= 0 && - nc < COLS && matrix[nr][nc] < matrix[r][c]) { + const nr = r + dr, + nc = c + dc; + if ( + nr >= 0 && + nr < ROWS && + nc >= 0 && + nc < COLS && + matrix[nr][nc] < matrix[r][c] + ) { indegree[r][c]++; } } @@ -714,9 +808,15 @@ class Solution { for (let i = 0; i < size; i++) { const [r, c] = q.pop(); for (const [dr, dc] of directions) { - const nr = r + dr, nc = c + dc; - if (nr >= 0 && nr < ROWS && nc >= 0 && - nc < COLS && matrix[nr][nc] > matrix[r][c]) { + const nr = r + dr, + nc = c + dc; + if ( + nr >= 0 && + nr < ROWS && + nc >= 0 && + nc < COLS && + matrix[nr][nc] > matrix[r][c] + ) { indegree[nr][nc]--; if (indegree[nr][nc] === 0) { q.push([nr, nc]); @@ -739,16 +839,16 @@ public class Solution { for (int i = 0; i < ROWS; i++) { indegree[i] = new int[COLS]; } - int[][] directions = new int[][] { - new int[] { -1, 0 }, new int[] { 1, 0 }, - new int[] { 0, -1 }, new int[] { 0, 1 } + int[][] directions = new int[][] { + new int[] { -1, 0 }, new int[] { 1, 0 }, + new int[] { 0, -1 }, new int[] { 0, 1 } }; for (int r = 0; r < ROWS; r++) { for (int c = 0; c < COLS; c++) { foreach (var d in directions) { int nr = r + d[0], nc = c + d[1]; - if (nr >= 0 && nr < ROWS && nc >= 0 && + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && matrix[nr][nc] < matrix[r][c]) { indegree[r][c]++; } @@ -773,7 +873,7 @@ public class Solution { int r = node[0], c = node[1]; foreach (var d in directions) { int nr = r + d[0], nc = c + d[1]; - if (nr >= 0 && nr < ROWS && nc >= 0 && + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && matrix[nr][nc] > matrix[r][c]) { if (--indegree[nr][nc] == 0) { q.Enqueue(new int[] { nr, nc }); @@ -795,14 +895,14 @@ func longestIncreasingPath(matrix [][]int) int { for i := range indegree { indegree[i] = make([]int, cols) } - + directions := [][]int{{-1, 0}, {1, 0}, {0, -1}, {0, 1}} for r := 0; r < rows; r++ { for c := 0; c < cols; c++ { for _, d := range directions { nr, nc := r + d[0], c + d[1] - if nr >= 0 && nr < rows && nc >= 0 && nc < cols && + if nr >= 0 && nr < rows && nc >= 0 && nc < cols && matrix[nr][nc] < matrix[r][c] { indegree[r][c]++ } @@ -828,7 +928,7 @@ func longestIncreasingPath(matrix [][]int) int { r, c := node[0], node[1] for _, d := range directions { nr, nc := r + d[0], c + d[1] - if nr >= 0 && nr < rows && nc >= 0 && nc < cols && + if nr >= 0 && nr < rows && nc >= 0 && nc < cols && matrix[nr][nc] > matrix[r][c] { indegree[nr][nc]-- if indegree[nr][nc] == 0 { @@ -850,7 +950,7 @@ class Solution { val rows = matrix.size val cols = matrix[0].size val indegree = Array(rows) { IntArray(cols) } - val directions = arrayOf(intArrayOf(-1, 0), intArrayOf(1, 0), + val directions = arrayOf(intArrayOf(-1, 0), intArrayOf(1, 0), intArrayOf(0, -1), intArrayOf(0, 1)) for (r in 0 until rows) { @@ -858,7 +958,7 @@ class Solution { for (d in directions) { val nr = r + d[0] val nc = c + d[1] - if (nr in 0 until rows && nc in 0 until cols && + if (nr in 0 until rows && nc in 0 until cols && matrix[nr][nc] < matrix[r][c]) { indegree[r][c]++ } @@ -882,7 +982,7 @@ class Solution { for (d in directions) { val nr = r + d[0] val nc = c + d[1] - if (nr in 0 until rows && nc in 0 until cols && + if (nr in 0 until rows && nc in 0 until cols && matrix[nr][nc] > matrix[r][c]) { if (--indegree[nr][nc] == 0) { queue.offer(intArrayOf(nr, nc)) @@ -898,11 +998,61 @@ class Solution { } ``` +```swift +class Solution { + func longestIncreasingPath(_ matrix: [[Int]]) -> Int { + let rows = matrix.count, cols = matrix[0].count + let directions = [(-1, 0), (1, 0), (0, -1), (0, 1)] + var indegree = Array(repeating: Array(repeating: 0, count: cols), count: rows) + + for r in 0..= 0 && nr < rows && nc >= 0 && nc < cols && + matrix[nr][nc] < matrix[r][c]) { + indegree[r][c] += 1 + } + } + } + } + + var q = Deque<(Int, Int)>() + for r in 0..= 0 && nr < rows && nc >= 0 && nc < cols && + matrix[nr][nc] > matrix[r][c]) { + indegree[nr][nc] -= 1 + if indegree[nr][nc] == 0 { + q.append((nr, nc)) + } + } + } + } + LIS += 1 + } + return LIS + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ -> Where $m$ is the number of rows and $n$ is the number of columns in the given $matrix$. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns in the given $matrix$. diff --git a/articles/longest-increasing-subsequence-ii.md b/articles/longest-increasing-subsequence-ii.md new file mode 100644 index 000000000..694390207 --- /dev/null +++ b/articles/longest-increasing-subsequence-ii.md @@ -0,0 +1,752 @@ +## 1. Brute Force (Recursion) + +::tabs-start + +```python +class Solution: + def lengthOfLIS(self, nums: List[int], k: int) -> int: + def dfs(i): + res = 1 + for j in range(i + 1, len(nums)): + if nums[j] <= nums[i]: + continue + if nums[j] - nums[i] <= k: + res = max(res, 1 + dfs(j)) + return res + + res = 0 + for i in range(len(nums)): + res = max(res, dfs(i)) + return res +``` + +```java +public class Solution { + public int lengthOfLIS(int[] nums, int k) { + int n = nums.length; + int res = 0; + + for (int i = 0; i < n; i++) { + res = Math.max(res, dfs(nums, k, i)); + } + + return res; + } + + private int dfs(int[] nums, int k, int i) { + int res = 1; + + for (int j = i + 1; j < nums.length; j++) { + if (nums[j] <= nums[i]) continue; + if (nums[j] - nums[i] <= k) { + res = Math.max(res, 1 + dfs(nums, k, j)); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int lengthOfLIS(vector& nums, int k) { + int n = nums.size(); + int res = 0; + + for (int i = 0; i < n; i++) { + res = max(res, dfs(nums, k, i)); + } + + return res; + } + +private: + int dfs(vector& nums, int k, int i) { + int res = 1; + + for (int j = i + 1; j < nums.size(); j++) { + if (nums[j] <= nums[i]) continue; + if (nums[j] - nums[i] <= k) { + res = max(res, 1 + dfs(nums, k, j)); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + lengthOfLIS(nums, k) { + const dfs = (i) => { + let res = 1; + + for (let j = i + 1; j < nums.length; j++) { + if (nums[j] <= nums[i]) continue; + if (nums[j] - nums[i] <= k) { + res = Math.max(res, 1 + dfs(j)); + } + } + + return res; + }; + + let res = 0; + for (let i = 0; i < nums.length; i++) { + res = Math.max(res, dfs(i)); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def lengthOfLIS(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + dp = [1] * n + for i in range(n): + for j in range(i): + if nums[j] >= nums[i]: + continue + if nums[i] - nums[j] <= k: + dp[i] = max(dp[i], 1 + dp[j]) + res = max(res, dp[i]) + return res +``` + +```java +public class Solution { + public int lengthOfLIS(int[] nums, int k) { + int n = nums.length, res = 0; + int[] dp = new int[n]; + Arrays.fill(dp, 1); + + for (int i = 0; i < n; i++) { + for (int j = 0; j < i; j++) { + if (nums[j] >= nums[i]) continue; + if (nums[i] - nums[j] <= k) { + dp[i] = Math.max(dp[i], 1 + dp[j]); + } + } + res = Math.max(res, dp[i]); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int lengthOfLIS(vector& nums, int k) { + int n = nums.size(), res = 0; + vector dp(n, 1); + + for (int i = 0; i < n; i++) { + for (int j = 0; j < i; j++) { + if (nums[j] >= nums[i]) continue; + if (nums[i] - nums[j] <= k) { + dp[i] = max(dp[i], 1 + dp[j]); + } + } + res = max(res, dp[i]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + lengthOfLIS(nums, k) { + const n = nums.length; + let res = 0; + const dp = new Array(n).fill(1); + + for (let i = 0; i < n; i++) { + for (let j = 0; j < i; j++) { + if (nums[j] >= nums[i]) continue; + if (nums[i] - nums[j] <= k) { + dp[i] = Math.max(dp[i], 1 + dp[j]); + } + } + res = Math.max(res, dp[i]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming + Segment Tree (Coordinate Compression) + +::tabs-start + +```python +class SegmentTree: + def __init__(self, N): + self.n = N + while (self.n & (self.n - 1)) != 0: + self.n += 1 + self.tree = [0] * (2 * self.n) + + def update(self, i, val): + if val <= self.tree[self.n + i]: + return + self.tree[self.n + i] = val + j = (self.n + i) >> 1 + while j >= 1: + self.tree[j] = max(self.tree[j << 1], self.tree[j << 1 | 1]) + j >>= 1 + + def query(self, ql, qh): + l = ql + self.n + r = qh + self.n + 1 + res = 0 + while l < r: + if l & 1: + res = max(res, self.tree[l]) + l += 1 + if r & 1: + r -= 1 + res = max(res, self.tree[r]) + l >>= 1 + r >>= 1 + return res + + +class Solution: + def lengthOfLIS(self, nums: List[int], k: int) -> int: + n = len(nums) + mp = {} + tmp = set([0]) + for num in nums: + if num - k > 0: + tmp.add(num - k) + if num - 1 > 0: + tmp.add(num - 1) + tmp.add(num) + + index = 0 + for value in sorted(tmp): + mp[value] = index + index += 1 + + ST = SegmentTree(index) + res = 0 + for num in nums: + l = mp.get(num - k, 0) + r = mp.get(num - 1, 0) + curr = ST.query(l, r) + 1 + res = max(res, curr) + ST.update(mp[num], curr) + + return res +``` + +```java +class SegmentTree { + private int n; + private int[] tree; + + public SegmentTree(int N) { + this.n = N; + while (Integer.bitCount(n) != 1) { + n++; + } + tree = new int[2 * n]; + } + + public void update(int i, int val) { + if (val <= tree[n + i]) return; + tree[n + i] = val; + for (int j = (n + i) >> 1; j >= 1; j >>= 1) { + tree[j] = Math.max(tree[j << 1], tree[(j << 1) + 1]); + } + } + + public int query(int ql, int qh) { + int l = ql + n, r = qh + n + 1, res = 0; + while (l < r) { + if ((l & 1) == 1) res = Math.max(res, tree[l++]); + if ((r & 1) == 1) res = Math.max(res, tree[--r]); + l >>= 1; + r >>= 1; + } + return res; + } +} + +public class Solution { + public int lengthOfLIS(int[] nums, int k) { + int n = nums.length; + TreeSet tmp = new TreeSet<>(); + tmp.add(0); + for (int num : nums) { + if (num - k > 0) tmp.add(num - k); + if (num - 1 > 0) tmp.add(num - 1); + tmp.add(num); + } + + Map mp = new HashMap<>(); + int index = 0; + for (int val : tmp) { + mp.put(val, index++); + } + + SegmentTree ST = new SegmentTree(index); + int res = 0; + for (int num : nums) { + int l = mp.getOrDefault(num - k, 0); + int r = mp.getOrDefault(num - 1, 0); + int curr = ST.query(l, r) + 1; + res = Math.max(res, curr); + ST.update(mp.get(num), curr); + } + return res; + } +} +``` + +```cpp +class SegmentTree { +public: + int n; + vector tree; + + SegmentTree(int N) { + this->n = N; + while (__builtin_popcount(n) != 1) { + n++; + } + tree.resize(2 * n, 0); + } + + void update(int i, int val) { + if (val <= tree[n + i]) return; + tree[n + i] = val; + for (int j = (n + i) >> 1; j >= 1; j >>= 1) { + tree[j] = max(tree[j << 1], tree[(j << 1) + 1]); + } + } + + int query(int ql, int qh) { + int l = ql + n, r = qh + n + 1, res = 0; + while (l < r) { + if (l & 1) res = max(res, tree[l++]); + if (r & 1) res = max(res, tree[--r]); + l >>= 1; + r >>= 1; + } + return res; + } +}; + +class Solution { +public: + int lengthOfLIS(vector& nums, int k) { + int n = nums.size(); + unordered_map mp; + set tmp = {0}; + + for (int num : nums) { + if (num - k > 0) tmp.insert(num - k); + if (num - 1 > 0) tmp.insert(num - 1); + tmp.insert(num); + } + + int index = 0; + for (const int& val : tmp) { + mp[val] = index++; + } + + SegmentTree ST(index); + int ans = 0; + for (int& num : nums) { + int l = mp[num - k]; + int r = mp[num - 1]; + int curr = ST.query(l, r) + 1; + ans = max(ans, curr); + ST.update(mp[num], curr); + } + + return ans; + } +}; +``` + +```javascript +class SegmentTree { + /** + * @constructor + * @param {number} N + */ + constructor(N) { + this.n = N; + while ((this.n & (this.n - 1)) !== 0) { + this.n++; + } + this.tree = Array(2 * this.n).fill(0); + } + + /** + * @param {number} i + * @param {number} val + * @return {void} + */ + update(i, val) { + if (val <= this.tree[this.n + i]) return; + this.tree[this.n + i] = val; + for (let j = (this.n + i) >> 1; j >= 1; j >>= 1) { + this.tree[j] = Math.max(this.tree[j << 1], this.tree[(j << 1) + 1]); + } + } + + /** + * @param {number} ql + * @param {number} qh + * @return {number} + */ + query(ql, qh) { + let l = ql + this.n, + r = qh + this.n + 1, + res = 0; + while (l < r) { + if (l & 1) res = Math.max(res, this.tree[l++]); + if (r & 1) res = Math.max(res, this.tree[--r]); + l >>= 1; + r >>= 1; + } + return res; + } +} + +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + lengthOfLIS(nums, k) { + const n = nums.length; + const tmp = new Set([0]); + for (const num of nums) { + if (num - k > 0) tmp.add(num - k); + if (num - 1 > 0) tmp.add(num - 1); + tmp.add(num); + } + + const mp = new Map(); + let index = 0; + Array.from(tmp) + .sort((a, b) => a - b) + .forEach((val) => mp.set(val, index++)); + + const ST = new SegmentTree(index); + let ans = 0; + for (const num of nums) { + const l = mp.has(num - k) ? mp.get(num - k) : 0; + const r = mp.has(num - 1) ? mp.get(num - 1) : 0; + const curr = ST.query(l, r) + 1; + ans = Math.max(ans, curr); + ST.update(mp.get(num), curr); + } + return ans; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming + Segment Tree + +::tabs-start + +```python +class SegmentTree: + def __init__(self, N): + self.n = N + while (self.n & (self.n - 1)) != 0: + self.n += 1 + self.tree = [0] * (2 * self.n) + + def update(self, i, val): + if val <= self.tree[self.n + i]: + return + self.tree[self.n + i] = val + j = (self.n + i) >> 1 + while j >= 1: + self.tree[j] = max(self.tree[j << 1], self.tree[j << 1 | 1]) + j >>= 1 + + def query(self, ql, qh): + l = ql + self.n + r = qh + self.n + 1 + res = 0 + while l < r: + if l & 1: + res = max(res, self.tree[l]) + l += 1 + if r & 1: + r -= 1 + res = max(res, self.tree[r]) + l >>= 1 + r >>= 1 + return res + + +class Solution: + def lengthOfLIS(self, nums: List[int], k: int) -> int: + max_val = max(nums) + ST = SegmentTree(max_val + 1) + res = 0 + for num in nums: + l = max(0, num - k) + r = max(0, num - 1) + curr = ST.query(l, r) + 1 + res = max(res, curr) + ST.update(num, curr) + + return res +``` + +```java +class SegmentTree { + private int[] tree; + private int n; + + public SegmentTree(int N) { + this.n = N; + while ((this.n & (this.n - 1)) != 0) { + this.n++; + } + this.tree = new int[2 * this.n]; + } + + public void update(int i, int val) { + if (val <= tree[n + i]) return; + tree[n + i] = val; + for (int j = (n + i) >> 1; j >= 1; j >>= 1) { + tree[j] = Math.max(tree[j << 1], tree[(j << 1) + 1]); + } + } + + public int query(int l, int r) { + l += n; + r += n + 1; + int res = 0; + while (l < r) { + if ((l & 1) == 1) { + res = Math.max(res, tree[l++]); + } + if ((r & 1) == 1) { + res = Math.max(res, tree[--r]); + } + l >>= 1; + r >>= 1; + } + return res; + } +} + +public class Solution { + public int lengthOfLIS(int[] nums, int k) { + int maxVal = 0; + for (int num : nums) { + maxVal = Math.max(maxVal, num); + } + + SegmentTree ST = new SegmentTree(maxVal + 1); + int res = 0; + for (int num : nums) { + int l = Math.max(0, num - k); + int r = Math.max(0, num - 1); + int curr = ST.query(l, r) + 1; + res = Math.max(res, curr); + ST.update(num, curr); + } + return res; + } +} +``` + +```cpp +class SegmentTree { +public: + int n; + vector tree; + + SegmentTree(int N) { + n = N; + while ((n & (n - 1)) != 0) { + n++; + } + tree.resize(2 * n, 0); + } + + void update(int i, int val) { + if (val <= tree[n + i]) return; + tree[n + i] = val; + for (int j = (n + i) >> 1; j >= 1; j >>= 1) { + tree[j] = max(tree[j << 1], tree[(j << 1) + 1]); + } + } + + int query(int l, int r) { + l += n; + r += n + 1; + int res = 0; + while (l < r) { + if (l & 1) { + res = max(res, tree[l++]); + } + if (r & 1) { + res = max(res, tree[--r]); + } + l >>= 1; + r >>= 1; + } + return res; + } +}; + +class Solution { +public: + int lengthOfLIS(vector& nums, int k) { + int maxVal = *max_element(nums.begin(), nums.end()); + SegmentTree ST(maxVal + 1); + int res = 0; + for (int& num : nums) { + int l = max(0, num - k); + int r = max(0, num - 1); + int curr = ST.query(l, r) + 1; + res = max(res, curr); + ST.update(num, curr); + } + return res; + } +}; +``` + +```javascript +class SegmentTree { + /** + * @constructor + * @param {number} N + */ + constructor(N) { + this.n = N; + while ((this.n & (this.n - 1)) !== 0) { + this.n++; + } + this.tree = Array(2 * this.n).fill(0); + } + + /** + * @param {number} i + * @param {number} val + * @return {void} + */ + update(i, val) { + if (val <= this.tree[this.n + i]) return; + this.tree[this.n + i] = val; + for (let j = (this.n + i) >> 1; j >= 1; j >>= 1) { + this.tree[j] = Math.max(this.tree[j << 1], this.tree[(j << 1) + 1]); + } + } + + /** + * @param {number} ql + * @param {number} qh + * @return {number} + */ + query(ql, qh) { + let l = ql + this.n, + r = qh + this.n + 1, + res = 0; + while (l < r) { + if (l & 1) res = Math.max(res, this.tree[l++]); + if (r & 1) res = Math.max(res, this.tree[--r]); + l >>= 1; + r >>= 1; + } + return res; + } +} + +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + lengthOfLIS(nums, k) { + const maxVal = Math.max(...nums); + const ST = new SegmentTree(maxVal + 1); + let res = 0; + for (const num of nums) { + const l = Math.max(0, num - k); + const r = Math.max(0, num - 1); + const curr = ST.query(l, r) + 1; + res = Math.max(res, curr); + ST.update(num, curr); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n\log m)$ +- Space complexity: $O(m)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in the array. diff --git a/articles/longest-increasing-subsequence.md b/articles/longest-increasing-subsequence.md index 1b24412eb..c02c4264f 100644 --- a/articles/longest-increasing-subsequence.md +++ b/articles/longest-increasing-subsequence.md @@ -5,16 +5,16 @@ ```python class Solution: def lengthOfLIS(self, nums: List[int]) -> int: - + def dfs(i, j): if i == len(nums): return 0 - + LIS = dfs(i + 1, j) # not include if j == -1 or nums[j] < nums[i]: LIS = max(LIS, 1 + dfs(i + 1, i)) # include - + return LIS return dfs(0, -1) @@ -55,7 +55,7 @@ private: return 0; } - int LIS = dfs(nums, i + 1, j); // not include + int LIS = dfs(nums, i + 1, j); // not include if (j == -1 || nums[j] < nums[i]) { LIS = max(LIS, 1 + dfs(nums, i + 1, i)); // include @@ -87,7 +87,7 @@ class Solution { return 0; } - let LIS = this.dfs(nums, i + 1, j); // not include + let LIS = this.dfs(nums, i + 1, j); // not include if (j === -1 || nums[j] < nums[i]) { LIS = Math.max(LIS, 1 + this.dfs(nums, i + 1, i)); // include @@ -170,16 +170,38 @@ class Solution { } ``` +```swift +class Solution { + func lengthOfLIS(_ nums: [Int]) -> Int { + func dfs(_ i: Int, _ j: Int) -> Int { + if i == nums.count { + return 0 + } + + var LIS = dfs(i + 1, j) // not include + + if j == -1 || nums[j] < nums[i] { + LIS = max(LIS, 1 + dfs(i + 1, i)) // include + } + + return LIS + } + + return dfs(0, -1) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- -## 2. Dynamic Programming (Top-Down) +## 2. Dynamic Programming (Top-Down) - I ::tabs-start @@ -187,7 +209,7 @@ class Solution { class Solution: def lengthOfLIS(self, nums): n = len(nums) - memo = [[-1] * (n + 1) for _ in range(n)] + memo = [[-1] * (n + 1) for _ in range(n)] def dfs(i, j): if i == n: @@ -214,7 +236,7 @@ public class Solution { if (i == nums.length) { return 0; } - if (memo[i][j + 1] != -1) { + if (memo[i][j + 1] != -1) { return memo[i][j + 1]; } @@ -230,9 +252,9 @@ public class Solution { public int lengthOfLIS(int[] nums) { int n = nums.length; - memo = new int[n][n + 1]; + memo = new int[n][n + 1]; for (int[] row : memo) { - Arrays.fill(row, -1); + Arrays.fill(row, -1); } return dfs(0, -1, nums); } @@ -243,12 +265,12 @@ public class Solution { class Solution { public: vector> memo; - + int dfs(int i, int j, vector& nums) { if (i == nums.size()) { return 0; } - if (memo[i][j + 1] != -1) { + if (memo[i][j + 1] != -1) { return memo[i][j + 1]; } @@ -261,10 +283,10 @@ public: memo[i][j + 1] = LIS; return LIS; } - + int lengthOfLIS(vector& nums) { int n = nums.size(); - memo = vector>(n, vector(n + 1, -1)); + memo = vector>(n, vector(n + 1, -1)); return dfs(0, -1, nums); } }; @@ -278,9 +300,8 @@ class Solution { */ lengthOfLIS(nums) { const n = nums.length; - const memo = Array.from({ length: n }, () => - Array(n + 2).fill(-1)); - + const memo = Array.from({ length: n }, () => Array(n + 2).fill(-1)); + return this.dfs(nums, 0, -1, memo); } @@ -292,9 +313,8 @@ class Solution { * @return {number} */ dfs(nums, i, j, memo) { - if (i === nums.length) return 0; - if (memo[i][j + 1] !== -1) - return memo[i][j + 1]; + if (i === nums.length) return 0; + if (memo[i][j + 1] !== -1) return memo[i][j + 1]; let LIS = this.dfs(nums, i + 1, j, memo); @@ -322,7 +342,7 @@ public class Solution { } private int DFS(int[] nums, int i, int j, int[,] memo) { - if (i == nums.Length) return 0; + if (i == nums.Length) return 0; if (memo[i, j + 1] != -1) { return memo[i, j + 1]; } @@ -344,9 +364,9 @@ func lengthOfLIS(nums []int) int { n := len(nums) memo := make([][]int, n) for i := range memo { - memo[i] = make([]int, n+1) + memo[i] = make([]int, n+1) for j := range memo[i] { - memo[i][j] = -1 + memo[i][j] = -1 } } @@ -359,10 +379,10 @@ func lengthOfLIS(nums []int) int { return memo[i][j+1] } - LIS := dfs(i + 1, j) + LIS := dfs(i + 1, j) if j == -1 || nums[j] < nums[i] { - LIS = max(LIS, 1 + dfs(i + 1, i)) + LIS = max(LIS, 1 + dfs(i + 1, i)) } memo[i][j+1] = LIS @@ -392,10 +412,10 @@ class Solution { return memo[i][j + 1] } - var LIS = dfs(i + 1, j, nums) + var LIS = dfs(i + 1, j, nums) if (j == -1 || nums[j] < nums[i]) { - LIS = maxOf(LIS, 1 + dfs(i + 1, i, nums)) + LIS = maxOf(LIS, 1 + dfs(i + 1, i, nums)) } memo[i][j + 1] = LIS @@ -404,22 +424,526 @@ class Solution { fun lengthOfLIS(nums: IntArray): Int { val n = nums.size - memo = Array(n) { IntArray(n + 1) { -1 } } + memo = Array(n) { IntArray(n + 1) { -1 } } return dfs(0, -1, nums) } } ``` +```swift +class Solution { + func lengthOfLIS(_ nums: [Int]) -> Int { + let n = nums.count + var memo = Array(repeating: Array(repeating: -1, count: n + 1), count: n) + + func dfs(_ i: Int, _ j: Int) -> Int { + if i == n { + return 0 + } + if memo[i][j + 1] != -1 { + return memo[i][j + 1] + } + + var LIS = dfs(i + 1, j) // not include + + if j == -1 || nums[j] < nums[i] { + LIS = max(LIS, 1 + dfs(i + 1, i)) // include + } + + memo[i][j + 1] = LIS + return LIS + } + + return dfs(0, -1) + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 3. Dynamic Programming (Top-Down) - II + +::tabs-start + +```python +class Solution: + def lengthOfLIS(self, nums: List[int]) -> int: + n = len(nums) + memo = [-1] * n + + def dfs(i): + if memo[i] != -1: + return memo[i] + + LIS = 1 + for j in range(i + 1, n): + if nums[i] < nums[j]: + LIS = max(LIS, 1 + dfs(j)) + + memo[i] = LIS + return LIS + + return max(dfs(i) for i in range(n)) +``` + +```java +public class Solution { + private int[] memo; + + public int lengthOfLIS(int[] nums) { + int n = nums.length; + memo = new int[n]; + Arrays.fill(memo, -1); + + int maxLIS = 1; + for (int i = 0; i < n; i++) { + maxLIS = Math.max(maxLIS, dfs(nums, i)); + } + return maxLIS; + } + + private int dfs(int[] nums, int i) { + if (memo[i] != -1) { + return memo[i]; + } + + int LIS = 1; + for (int j = i + 1; j < nums.length; j++) { + if (nums[i] < nums[j]) { + LIS = Math.max(LIS, 1 + dfs(nums, j)); + } + } + + memo[i] = LIS; + return LIS; + } +} +``` + +```cpp +class Solution { +private: + vector memo; + + int dfs(vector& nums, int i) { + if (memo[i] != -1) { + return memo[i]; + } + + int LIS = 1; + for (int j = i + 1; j < nums.size(); j++) { + if (nums[i] < nums[j]) { + LIS = max(LIS, 1 + dfs(nums, j)); + } + } + + return memo[i] = LIS; + } + +public: + int lengthOfLIS(vector& nums) { + int n = nums.size(); + memo.assign(n, -1); + + int maxLIS = 1; + for (int i = 0; i < n; i++) { + maxLIS = max(maxLIS, dfs(nums, i)); + } + return maxLIS; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + lengthOfLIS(nums) { + const n = nums.length; + const memo = new Array(n).fill(-1); + + const dfs = (i) => { + if (memo[i] !== -1) { + return memo[i]; + } + + let LIS = 1; + for (let j = i + 1; j < n; j++) { + if (nums[i] < nums[j]) { + LIS = Math.max(LIS, 1 + dfs(j)); + } + } + + memo[i] = LIS; + return LIS; + }; + + return Math.max(...nums.map((_, i) => dfs(i))); + } +} +``` + +```csharp +public class Solution { + private int[] memo; + + public int LengthOfLIS(int[] nums) { + int n = nums.Length; + memo = new int[n]; + Array.Fill(memo, -1); + + int maxLIS = 1; + for (int i = 0; i < n; i++) { + maxLIS = Math.Max(maxLIS, Dfs(nums, i)); + } + return maxLIS; + } + + private int Dfs(int[] nums, int i) { + if (memo[i] != -1) { + return memo[i]; + } + + int LIS = 1; + for (int j = i + 1; j < nums.Length; j++) { + if (nums[i] < nums[j]) { + LIS = Math.Max(LIS, 1 + Dfs(nums, j)); + } + } + + memo[i] = LIS; + return LIS; + } +} +``` + +```go +func lengthOfLIS(nums []int) int { + n := len(nums) + memo := make([]int, n) + for i := range memo { + memo[i] = -1 + } + + var dfs func(int) int + dfs = func(i int) int { + if memo[i] != -1 { + return memo[i] + } + + LIS := 1 + for j := i + 1; j < n; j++ { + if nums[i] < nums[j] { + LIS = max(LIS, 1+dfs(j)) + } + } + + memo[i] = LIS + return LIS + } + + maxLIS := 1 + for i := 0; i < n; i++ { + maxLIS = max(maxLIS, dfs(i)) + } + + return maxLIS +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` + +```kotlin +class Solution { + private lateinit var memo: IntArray + + fun lengthOfLIS(nums: IntArray): Int { + val n = nums.size + memo = IntArray(n) { -1 } + + var maxLIS = 1 + for (i in nums.indices) { + maxLIS = maxOf(maxLIS, dfs(nums, i)) + } + return maxLIS + } + + private fun dfs(nums: IntArray, i: Int): Int { + if (memo[i] != -1) { + return memo[i] + } + + var LIS = 1 + for (j in i + 1 until nums.size) { + if (nums[i] < nums[j]) { + LIS = maxOf(LIS, 1 + dfs(nums, j)) + } + } + + memo[i] = LIS + return LIS + } +} +``` + +```swift +class Solution { + func lengthOfLIS(_ nums: [Int]) -> Int { + let n = nums.count + var memo = Array(repeating: -1, count: n) + + func dfs(_ i: Int) -> Int { + if memo[i] != -1 { + return memo[i] + } + + var LIS = 1 + for j in (i + 1)..= 0; i--) { + for (int j = i - 1; j >= -1; j--) { + int LIS = dp[i + 1][j + 1]; // Not including nums[i] + + if (j == -1 || nums[j] < nums[i]) { + LIS = Math.max(LIS, 1 + dp[i + 1][i + 1]); // Including nums[i] + } + + dp[i][j + 1] = LIS; + } + } + + return dp[0][0]; + } +} +``` + +```cpp +class Solution { +public: + int lengthOfLIS(vector& nums) { + int n = nums.size(); + vector> dp(n + 1, vector(n + 1, 0)); + + for (int i = n - 1; i >= 0; --i) { + for (int j = i - 1; j >= -1; --j) { + int LIS = dp[i + 1][j + 1]; // Not including nums[i] + + if (j == -1 || nums[j] < nums[i]) { + LIS = max(LIS, 1 + dp[i + 1][i + 1]); // Including nums[i] + } + + dp[i][j + 1] = LIS; + } + } + + return dp[0][0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + lengthOfLIS(nums) { + const n = nums.length; + const dp = Array.from({ length: n + 1 }, () => + new Array(n + 1).fill(0), + ); + + for (let i = n - 1; i >= 0; i--) { + for (let j = i - 1; j >= -1; j--) { + let LIS = dp[i + 1][j + 1]; // Not including nums[i] + + if (j === -1 || nums[j] < nums[i]) { + LIS = Math.max(LIS, 1 + dp[i + 1][i + 1]); // Including nums[i] + } + + dp[i][j + 1] = LIS; + } + } + + return dp[0][0]; + } +} +``` + +```csharp +public class Solution { + public int LengthOfLIS(int[] nums) { + int n = nums.Length; + int[,] dp = new int[n + 1, n + 1]; + + for (int i = n - 1; i >= 0; i--) { + for (int j = i - 1; j >= -1; j--) { + int LIS = dp[i + 1, j + 1]; // Not including nums[i] + + if (j == -1 || nums[j] < nums[i]) { + LIS = Math.Max(LIS, 1 + dp[i + 1, i + 1]); // Including nums[i] + } + + dp[i, j + 1] = LIS; + } + } + + return dp[0, 0]; + } +} +``` + +```go +func lengthOfLIS(nums []int) int { + n := len(nums) + dp := make([][]int, n+1) + for i := range dp { + dp[i] = make([]int, n+1) + } + + for i := n - 1; i >= 0; i-- { + for j := i - 1; j >= -1; j-- { + LIS := dp[i+1][j+1] // Not including nums[i] + + if j == -1 || nums[j] < nums[i] { + LIS = max(LIS, 1+dp[i+1][i+1]) // Including nums[i] + } + + dp[i][j+1] = LIS + } + } + + return dp[0][0] +} + +func max(a, b int) int { + if a > b { + return a + } + return b +} +``` + +```kotlin +class Solution { + fun lengthOfLIS(nums: IntArray): Int { + val n = nums.size + val dp = Array(n + 1) { IntArray(n + 1) } + + for (i in n - 1 downTo 0) { + for (j in i - 1 downTo -1) { + var LIS = dp[i + 1][j + 1] // Not including nums[i] + + if (j == -1 || nums[j] < nums[i]) { + LIS = maxOf(LIS, 1 + dp[i + 1][i + 1]) // Including nums[i] + } + + dp[i][j + 1] = LIS + } + } + + return dp[0][0] + } +} +``` + +```swift +class Solution { + func lengthOfLIS(_ nums: [Int]) -> Int { + let n = nums.count + var dp = Array(repeating: Array(repeating: 0, count: n + 1), count: n + 1) + + for i in stride(from: n - 1, through: 0, by: -1) { + for j in stride(from: i - 1, through: -1, by: -1) { + var LIS = dp[i + 1][j + 1] // Not including nums[i] + + if j == -1 || nums[j] < nums[i] { + LIS = max(LIS, 1 + dp[i + 1][i + 1]) // Including nums[i] + } + + dp[i][j + 1] = LIS + } + } + + return dp[0][0] + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 5. Dynamic Programming (Bottom-Up) - II ::tabs-start @@ -516,7 +1040,7 @@ func lengthOfLIS(nums []int) int { for i := range LIS { LIS[i] = 1 } - + for i := len(nums) - 1; i >= 0; i-- { for j := i + 1; j < len(nums); j++ { if nums[i] < nums[j] { @@ -526,14 +1050,14 @@ func lengthOfLIS(nums []int) int { } } } - + maxLen := 1 for _, length := range LIS { if length > maxLen { maxLen = length } } - + return maxLen } ``` @@ -542,7 +1066,7 @@ func lengthOfLIS(nums []int) int { class Solution { fun lengthOfLIS(nums: IntArray): Int { val LIS = IntArray(nums.size) { 1 } - + for (i in nums.size - 1 downTo 0) { for (j in (i + 1) until nums.size) { if (nums[i] < nums[j]) { @@ -550,22 +1074,39 @@ class Solution { } } } - + return LIS.maxOrNull() ?: 1 } } ``` +```swift +class Solution { + func lengthOfLIS(_ nums: [Int]) -> Int { + var LIS = Array(repeating: 1, count: nums.count) + + for i in stride(from: nums.count - 1, through: 0, by: -1) { + for j in (i + 1)..& nums) { vector sortedArr = nums; sort(sortedArr.begin(), sortedArr.end()); - sortedArr.erase(unique(sortedArr.begin(), + sortedArr.erase(unique(sortedArr.begin(), sortedArr.end()), sortedArr.end()); vector order(nums.size()); @@ -781,7 +1322,7 @@ class SegmentTree { this.tree[this.n + i] = val; let j = (this.n + i) >> 1; while (j >= 1) { - this.tree[j] = Math.max(this.tree[j << 1], this.tree[j << 1 | 1]); + this.tree[j] = Math.max(this.tree[j << 1], this.tree[(j << 1) | 1]); j >>= 1; } } @@ -822,12 +1363,12 @@ class Solution { lengthOfLIS(nums) { const sortedArr = Array.from(new Set(nums)).sort((a, b) => a - b); const map = new Map(); - + sortedArr.forEach((num, index) => { map.set(num, index); }); - - const order = nums.map(num => map.get(num)); + + const order = nums.map((num) => map.get(num)); const n = sortedArr.length; const segTree = new SegmentTree(n, order); @@ -889,14 +1430,14 @@ public class Solution { public int LengthOfLIS(int[] nums) { var sortedArr = nums.Distinct().OrderBy(x => x).ToArray(); var map = new Dictionary(); - + for (int i = 0; i < sortedArr.Length; i++) { map[sortedArr[i]] = i; } - + int n = sortedArr.Length; var segTree = new SegmentTree(n); - + int LIS = 0; foreach (var num in nums) { int compressedIndex = map[num]; @@ -1050,16 +1591,83 @@ class Solution { } ``` +```swift +class SegmentTree { + private var n: Int + private var tree: [Int] + + init(_ N: Int) { + self.n = N + while (self.n & (self.n - 1)) != 0 { + self.n += 1 + } + self.tree = Array(repeating: 0, count: 2 * self.n) + } + + func update(_ i: Int, _ val: Int) { + tree[n + i] = val + var j = (n + i) >> 1 + while j >= 1 { + tree[j] = max(tree[j << 1], tree[j << 1 | 1]) + j >>= 1 + } + } + + func query(_ l: Int, _ r: Int) -> Int { + if l > r { + return 0 + } + var res = Int.min + var l = l + n + var r = r + n + 1 + while l < r { + if l & 1 == 1 { + res = max(res, tree[l]) + l += 1 + } + if r & 1 == 1 { + r -= 1 + res = max(res, tree[r]) + } + l >>= 1 + r >>= 1 + } + return res + } +} + +class Solution { + func lengthOfLIS(_ nums: [Int]) -> Int { + func compress(_ arr: [Int]) -> [Int] { + let sortedArr = Array(Set(arr)).sorted() + return arr.map { sortedArr.firstIndex(of: $0)! } + } + + let nums = compress(nums) + let n = nums.count + let segTree = SegmentTree(n) + + var LIS = 0 + for num in nums { + let curLIS = segTree.query(0, num - 1) + 1 + segTree.update(num, curLIS) + LIS = max(LIS, curLIS) + } + return LIS + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- -## 5. Binary Search +## 7. Dynamic Programming + Binary Search ::tabs-start @@ -1072,13 +1680,13 @@ class Solution: LIS = 1 for i in range(1, len(nums)): - if dp[-1] < nums[i]: + if dp[-1] < nums[i]: dp.append(nums[i]) LIS += 1 continue idx = bisect_left(dp, nums[i]) - dp[idx] = nums[i] + dp[idx] = nums[i] return LIS ``` @@ -1091,15 +1699,15 @@ public class Solution { int LIS = 1; for (int i = 1; i < nums.length; i++) { - if (dp.get(dp.size() - 1) < nums[i]) { + if (dp.get(dp.size() - 1) < nums[i]) { dp.add(nums[i]); LIS++; continue; } int idx = Collections.binarySearch(dp, nums[i]); - if (idx < 0) idx = -idx - 1; - dp.set(idx, nums[i]); + if (idx < 0) idx = -idx - 1; + dp.set(idx, nums[i]); } return LIS; @@ -1116,15 +1724,15 @@ public: int LIS = 1; for (int i = 1; i < nums.size(); i++) { - if (dp.back() < nums[i]) { + if (dp.back() < nums[i]) { dp.push_back(nums[i]); LIS++; continue; } - int idx = lower_bound(dp.begin(), + int idx = lower_bound(dp.begin(), dp.end(), nums[i]) - dp.begin(); - dp[idx] = nums[i]; + dp[idx] = nums[i]; } return LIS; @@ -1144,13 +1752,14 @@ class Solution { let LIS = 1; for (let i = 1; i < nums.length; i++) { - if (dp[dp.length - 1] < nums[i]) { + if (dp[dp.length - 1] < nums[i]) { dp.push(nums[i]); LIS++; continue; } - let left = 0, right = dp.length - 1; + let left = 0, + right = dp.length - 1; while (left < right) { const mid = Math.floor((left + right) / 2); if (dp[mid] < nums[i]) { @@ -1159,7 +1768,7 @@ class Solution { right = mid; } } - dp[left] = nums[i]; + dp[left] = nums[i]; } return LIS; @@ -1175,15 +1784,15 @@ public class Solution { int LIS = 1; for (int i = 1; i < nums.Length; i++) { - if (dp[dp.Count - 1] < nums[i]) { + if (dp[dp.Count - 1] < nums[i]) { dp.Add(nums[i]); LIS++; continue; } int idx = dp.BinarySearch(nums[i]); - if (idx < 0) idx = ~idx; - dp[idx] = nums[i]; + if (idx < 0) idx = ~idx; + dp[idx] = nums[i]; } return LIS; @@ -1237,9 +1846,42 @@ class Solution { } ``` +```swift +class Solution { + func lengthOfLIS(_ nums: [Int]) -> Int { + var dp = [nums[0]] + var LIS = 1 + + for i in 1.. Int { + var left = 0, right = dp.count - 1 + while left < right { + let mid = (left + right) / 2 + if dp[mid] < target { + left = mid + 1 + } else { + right = mid + } + } + return left + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/longest-palindrome.md b/articles/longest-palindrome.md new file mode 100644 index 000000000..454318e98 --- /dev/null +++ b/articles/longest-palindrome.md @@ -0,0 +1,419 @@ +## 1. Hash Map + +::tabs-start + +```python +class Solution: + def longestPalindrome(self, s: str) -> int: + count = defaultdict(int) + res = 0 + + for c in s: + count[c] += 1 + if count[c] % 2 == 0: + res += 2 + + for cnt in count.values(): + if cnt % 2: + res += 1 + break + + return res +``` + +```java +public class Solution { + public int longestPalindrome(String s) { + Map count = new HashMap<>(); + int res = 0; + + for (char c : s.toCharArray()) { + count.put(c, count.getOrDefault(c, 0) + 1); + if (count.get(c) % 2 == 0) { + res += 2; + } + } + + for (int cnt : count.values()) { + if (cnt % 2 == 1) { + res += 1; + break; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestPalindrome(string s) { + unordered_map count; + int res = 0; + + for (char c : s) { + count[c]++; + if (count[c] % 2 == 0) { + res += 2; + } + } + + for (auto& [ch, cnt] : count) { + if (cnt % 2 == 1) { + res += 1; + break; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + longestPalindrome(s) { + const count = {}; + let res = 0; + + for (let c of s) { + count[c] = (count[c] || 0) + 1; + if (count[c] % 2 === 0) { + res += 2; + } + } + + for (let key in count) { + if (count[key] % 2 === 1) { + res += 1; + break; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(m)$ + +> Where $n$ is the length of the given string, and $m$ is the number of distinct characters in the string. + +--- + +## 2. Hash Map (Optimal) + +::tabs-start + +```python +class Solution: + def longestPalindrome(self, s: str) -> int: + count = defaultdict(int) + res = 0 + + for c in s: + count[c] += 1 + if count[c] % 2 == 0: + res += 2 + + return res + (res < len(s)) +``` + +```java +public class Solution { + public int longestPalindrome(String s) { + Map count = new HashMap<>(); + int res = 0; + + for (char c : s.toCharArray()) { + count.put(c, count.getOrDefault(c, 0) + 1); + if (count.get(c) % 2 == 0) { + res += 2; + } + } + + return res + (res < s.length() ? 1 : 0); + } +} +``` + +```cpp +class Solution { +public: + int longestPalindrome(string s) { + unordered_map count; + int res = 0; + + for (char c : s) { + count[c]++; + if (count[c] % 2 == 0) { + res += 2; + } + } + + return res + (res < s.size()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + longestPalindrome(s) { + const count = {}; + let res = 0; + + for (let c of s) { + count[c] = (count[c] || 0) + 1; + if (count[c] % 2 === 0) { + res += 2; + } + } + + return res + (res < s.length ? 1 : 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(m)$ + +> Where $n$ is the length of the given string, and $m$ is the number of distinct characters in the string. + +--- + +## 3. Hash Set + +::tabs-start + +```python +class Solution: + def longestPalindrome(self, s: str) -> int: + seen = set() + res = 0 + + for c in s: + if c in seen: + seen.remove(c) + res += 2 + else: + seen.add(c) + + return res + 1 if seen else res +``` + +```java +public class Solution { + public int longestPalindrome(String s) { + Set seen = new HashSet<>(); + int res = 0; + + for (char c : s.toCharArray()) { + if (seen.contains(c)) { + seen.remove(c); + res += 2; + } else { + seen.add(c); + } + } + + return seen.isEmpty() ? res : res + 1; + } +} +``` + +```cpp +class Solution { +public: + int longestPalindrome(string s) { + unordered_set seen; + int res = 0; + + for (char c : s) { + if (seen.count(c)) { + seen.erase(c); + res += 2; + } else { + seen.insert(c); + } + } + + return seen.empty() ? res : res + 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + longestPalindrome(s) { + const seen = new Set(); + let res = 0; + + for (let c of s) { + if (seen.has(c)) { + seen.delete(c); + res += 2; + } else { + seen.add(c); + } + } + + return seen.size === 0 ? res : res + 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(m)$ + +> Where $n$ is the length of the given string, and $m$ is the number of distinct characters in the string. + +--- + +## 4. Bitmask + +::tabs-start + +```python +class Solution: + def longestPalindrome(self, s: str) -> int: + mask1 = 0 # [a - z] + mask2 = 0 # [A - Z] + res = 0 + + for c in s: + if 'a' <= c <= 'z': + bit = 1 << (ord(c) - ord('a')) + if mask1 & bit: + res += 2 + mask1 ^= bit + else: + bit = 1 << (ord(c) - ord('A')) + if mask2 & bit: + res += 2 + mask2 ^= bit + + return res + 1 if mask1 or mask2 else res +``` + +```java +public class Solution { + public int longestPalindrome(String s) { + int mask1 = 0; // [a - z] + int mask2 = 0; // [A - Z] + int res = 0; + + for (char c : s.toCharArray()) { + if (c >= 'a' && c <= 'z') { + int bit = 1 << (c - 'a'); + if ((mask1 & bit) != 0) { + res += 2; + } + mask1 ^= bit; + } else { + int bit = 1 << (c - 'A'); + if ((mask2 & bit) != 0) { + res += 2; + } + mask2 ^= bit; + } + } + + return (mask1 != 0 || mask2 != 0) ? res + 1 : res; + } +} +``` + +```cpp +class Solution { +public: + int longestPalindrome(string s) { + int mask1 = 0; // [a - z] + int mask2 = 0; // [A - Z] + int res = 0; + + for (char c : s) { + if ('a' <= c && c <= 'z') { + int bit = 1 << (c - 'a'); + if (mask1 & bit) { + res += 2; + } + mask1 ^= bit; + } else { + int bit = 1 << (c - 'A'); + if (mask2 & bit) { + res += 2; + } + mask2 ^= bit; + } + } + + return (mask1 || mask2) ? res + 1 : res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + longestPalindrome(s) { + let mask1 = 0; // [a - z] + let mask2 = 0; // [A - Z] + let res = 0; + + for (let c of s) { + if (c >= 'a' && c <= 'z') { + let bit = 1 << (c.charCodeAt(0) - 97); + if (mask1 & bit) { + res += 2; + } + mask1 ^= bit; + } else { + let bit = 1 << (c.charCodeAt(0) - 65); + if (mask2 & bit) { + res += 2; + } + mask2 ^= bit; + } + } + + return mask1 || mask2 ? res + 1 : res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/longest-palindromic-subsequence.md b/articles/longest-palindromic-subsequence.md index c216ab542..693d178fa 100644 --- a/articles/longest-palindromic-subsequence.md +++ b/articles/longest-palindromic-subsequence.md @@ -13,19 +13,19 @@ class Solution: return 0 if dp[i][j] != -1: return dp[i][j] - + if s[i] == s[j]: length = 1 if i == j else 2 dp[i][j] = length + dfs(i - 1, j + 1) else: dp[i][j] = max(dfs(i - 1, j), dfs(i, j + 1)) - + return dp[i][j] for i in range(n): dfs(i, i) # odd length dfs(i, i + 1) # even length - + return max(max(row) for row in dp if row != -1) ``` @@ -151,8 +151,8 @@ class Solution { }; for (let i = 0; i < n; i++) { - dfs(i, i); // Odd length - dfs(i, i + 1); // Even length + dfs(i, i); // Odd length + dfs(i, i + 1); // Even length } let maxLength = 0; @@ -171,8 +171,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -192,12 +192,12 @@ class Solution: return 1 if (i, j) in cache: return cache[(i, j)] - + if s[i] == s[j]: cache[(i, j)] = dfs(i + 1, j - 1) + 2 else: cache[(i, j)] = max(dfs(i + 1, j), dfs(i, j - 1)) - + return cache[(i, j)] return dfs(0, len(s) - 1) @@ -314,8 +314,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -411,7 +411,8 @@ class Solution { * @return {number} */ longestCommonSubsequence(s1, s2) { - const N = s1.length, M = s2.length; + const N = s1.length, + M = s2.length; const dp = Array.from({ length: N + 1 }, () => Array(M + 1).fill(0)); for (let i = 0; i < N; i++) { @@ -433,8 +434,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -458,7 +459,7 @@ class Solution: dp[j] = prev + 2 else: dp[j] = max(dp[j], dp[j - 1]) - + prev = temp return dp[n - 1] @@ -469,7 +470,7 @@ public class Solution { public int longestPalindromeSubseq(String s) { int n = s.length(); int[] dp = new int[n]; - + for (int i = n - 1; i >= 0; i--) { dp[i] = 1; int prev = 0; @@ -484,7 +485,7 @@ public class Solution { prev = temp; } } - + return dp[n - 1]; } } @@ -553,5 +554,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ diff --git a/articles/longest-palindromic-substring.md b/articles/longest-palindromic-substring.md index 715d7c512..2e5b429fa 100644 --- a/articles/longest-palindromic-substring.md +++ b/articles/longest-palindromic-substring.md @@ -13,7 +13,7 @@ class Solution: while l < r and s[l] == s[r]: l += 1 r -= 1 - + if l >= r and resLen < (j - i + 1): res = s[i : j + 1] resLen = j - i + 1 @@ -80,18 +80,19 @@ class Solution { * @return {string} */ longestPalindrome(s) { - let res = ""; + let res = ''; let resLen = 0; for (let i = 0; i < s.length; i++) { for (let j = i; j < s.length; j++) { - let l = i, r = j; + let l = i, + r = j; while (l < r && s[l] === s[r]) { l++; r--; } - if (l >= r && resLen < (j - i + 1)) { + if (l >= r && resLen < j - i + 1) { res = s.slice(i, j + 1); resLen = j - i + 1; } @@ -180,12 +181,38 @@ class Solution { } ``` +```swift +class Solution { + func longestPalindrome(_ s: String) -> String { + let chars = Array(s) + var res = "" + var resLen = 0 + + for i in 0..= r && resLen < (j - i + 1) { + res = String(chars[i...j]) + resLen = j - i + 1 + } + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n)$ --- @@ -222,9 +249,9 @@ public class Solution { for (int i = n - 1; i >= 0; i--) { for (int j = i; j < n; j++) { - if (s.charAt(i) == s.charAt(j) && + if (s.charAt(i) == s.charAt(j) && (j - i <= 2 || dp[i + 1][j - 1])) { - + dp[i][j] = true; if (resLen < (j - i + 1)) { resIdx = i; @@ -250,7 +277,7 @@ public: for (int i = n - 1; i >= 0; i--) { for (int j = i; j < n; j++) { - if (s[i] == s[j] && + if (s[i] == s[j] && (j - i <= 2 || dp[i + 1][j - 1])) { dp[i][j] = true; @@ -274,18 +301,17 @@ class Solution { * @return {string} */ longestPalindrome(s) { - let resIdx = 0, resLen = 0; + let resIdx = 0, + resLen = 0; const n = s.length; const dp = Array.from({ length: n }, () => Array(n).fill(false)); for (let i = n - 1; i >= 0; i--) { for (let j = i; j < n; j++) { - if (s[i] === s[j] && - (j - i <= 2 || dp[i + 1][j - 1])) { - + if (s[i] === s[j] && (j - i <= 2 || dp[i + 1][j - 1])) { dp[i][j] = true; - if (resLen < (j - i + 1)) { + if (resLen < j - i + 1) { resIdx = i; resLen = j - i + 1; } @@ -308,9 +334,9 @@ public class Solution { for (int i = n - 1; i >= 0; i--) { for (int j = i; j < n; j++) { - if (s[i] == s[j] && + if (s[i] == s[j] && (j - i <= 2 || dp[i + 1, j - 1])) { - + dp[i, j] = true; if (resLen < (j - i + 1)) { resIdx = i; @@ -377,12 +403,37 @@ class Solution { } ``` +```swift +class Solution { + func longestPalindrome(_ s: String) -> String { + let chars = Array(s) + let n = chars.count + var resIdx = 0, resLen = 0 + var dp = Array(repeating: Array(repeating: false, count: n), count: n) + + for i in stride(from: n - 1, through: 0, by: -1) { + for j in i..= 0 && r < s.length() && + while (l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r)) { if (r - l + 1 > resLen) { resIdx = l; @@ -439,7 +490,7 @@ class Solution { // even length l = i; r = i + 1; - while (l >= 0 && r < s.length() && + while (l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r)) { if (r - l + 1 > resLen) { resIdx = l; @@ -506,9 +557,8 @@ class Solution { for (let i = 0; i < s.length; i++) { // odd length let l = i; - let r = i; - while (l >= 0 && r < s.length && - s.charAt(l) === s.charAt(r)) { + let r = i; + while (l >= 0 && r < s.length && s.charAt(l) === s.charAt(r)) { if (r - l + 1 > resLen) { resIdx = l; resLen = r - l + 1; @@ -520,8 +570,7 @@ class Solution { // even length l = i; r = i + 1; - while (l >= 0 && r < s.length && - s.charAt(l) === s.charAt(r)) { + while (l >= 0 && r < s.length && s.charAt(l) === s.charAt(r)) { if (r - l + 1 > resLen) { resIdx = l; resLen = r - l + 1; @@ -642,12 +691,51 @@ class Solution { } ``` +```swift +class Solution { + func longestPalindrome(_ s: String) -> String { + let chars = Array(s) + var resIdx = 0 + var resLen = 0 + + for i in 0..= 0 && r < chars.count && chars[l] == chars[r] { + if (r - l + 1) > resLen { + resIdx = l + resLen = r - l + 1 + } + l -= 1 + r += 1 + } + + // Even length palindrome + l = i + r = i + 1 + while l >= 0 && r < chars.count && chars[l] == chars[r] { + if (r - l + 1) > resLen { + resIdx = l + resLen = r - l + 1 + } + l -= 1 + r += 1 + } + } + + return String(chars[resIdx..= 0 + while (i + p[i] + 1 < n and i - p[i] - 1 >= 0 and t[i + p[i] + 1] == t[i - p[i] - 1]): p[i] += 1 if i + p[i] > r: l, r = i - p[i], i + p[i] return p - + p = manacher(s) resLen, center_idx = max((v, i) for i, v in enumerate(p)) resIdx = (center_idx - resLen) // 2 @@ -701,7 +789,7 @@ public class Solution { } return p; } - + public String longestPalindrome(String s) { int[] p = manacher(s); int resLen = 0, center_idx = 0; @@ -738,7 +826,7 @@ public: } return p; } - + string longestPalindrome(string s) { vector p = manacher(s); int resLen = 0, center_idx = 0; @@ -764,11 +852,15 @@ class Solution { const t = '#' + s.split('').join('#') + '#'; const n = t.length; const p = new Array(n).fill(0); - let l = 0, r = 0; + let l = 0, + r = 0; for (let i = 0; i < n; i++) { - p[i] = (i < r) ? Math.min(r - i, p[l + (r - i)]) : 0; - while (i + p[i] + 1 < n && i - p[i] - 1 >= 0 && - t[i + p[i] + 1] === t[i - p[i] - 1]) { + p[i] = i < r ? Math.min(r - i, p[l + (r - i)]) : 0; + while ( + i + p[i] + 1 < n && + i - p[i] - 1 >= 0 && + t[i + p[i] + 1] === t[i - p[i] - 1] + ) { p[i]++; } if (i + p[i] > r) { @@ -785,7 +877,8 @@ class Solution { */ longestPalindrome(s) { const p = this.manacher(s); - let resLen = 0, center_idx = 0; + let resLen = 0, + center_idx = 0; for (let i = 0; i < p.length; i++) { if (p[i] > resLen) { resLen = p[i]; @@ -857,7 +950,7 @@ func longestPalindrome(s string) string { } return p } - + p := manacher(s) resLen, centerIdx := 0, 0 for i, v := range p { @@ -866,7 +959,7 @@ func longestPalindrome(s string) string { centerIdx = i } } - + resIdx := (centerIdx - resLen) / 2 return s[resIdx : resIdx + resLen] } @@ -881,10 +974,10 @@ class Solution { val p = IntArray(n) var l = 0 var r = 0 - + for (i in 0 until n) { p[i] = if (i < r) Math.min(r - i, p[l + (r - i)]) else 0 - while (i + p[i] + 1 < n && i - p[i] - 1 >= 0 && + while (i + p[i] + 1 < n && i - p[i] - 1 >= 0 && t[i + p[i] + 1] == t[i - p[i] - 1]) { p[i]++ } @@ -895,7 +988,7 @@ class Solution { } return p } - + val p = manacher(s) var resLen = 0 var centerIdx = 0 @@ -905,16 +998,60 @@ class Solution { centerIdx = i } } - + val resIdx = (centerIdx - resLen) / 2 return s.substring(resIdx, resIdx + resLen) } } ``` +```swift +class Solution { + func longestPalindrome(_ s: String) -> String { + func manacher(_ s: String) -> [Int] { + let t = "#" + s.map { String($0) }.joined(separator: "#") + "#" + let tArray = Array(t) + let n = tArray.count + var p = [Int](repeating: 0, count: n) + var l = 0, r = 0 + + for i in 0..= 0 && + tArray[i + p[i] + 1] == tArray[i - p[i] - 1]) { + p[i] += 1 + } + if i + p[i] > r { + l = i - p[i] + r = i + p[i] + } + } + return p + } + + let p = manacher(s) + var resLen = 0, centerIndex = 0 + for (i, v) in p.enumerated() { + if v > resLen { + resLen = v + centerIndex = i + } + } + let resIdx = (centerIndex - resLen) / 2 + let start = s.index(s.startIndex, offsetBy: resIdx) + let end = s.index(start, offsetBy: resLen) + return String(s[start.. Int { + var res = 0 + let chars = Array(s) + + for i in 0.. Where $n$ is the length of the string and $m$ is the total number of unique characters in the string. @@ -182,7 +206,7 @@ class Solution: if s[l] == c: count -= 1 l += 1 - + res = max(res, r - l + 1) return res ``` @@ -259,13 +283,14 @@ class Solution { let charSet = new Set(s); for (let c of charSet) { - let count = 0, l = 0; + let count = 0, + l = 0; for (let r = 0; r < s.length; r++) { if (s[r] === c) { count++; } - while ((r - l + 1) - count > k) { + while (r - l + 1 - count > k) { if (s[l] === c) { count--; } @@ -312,7 +337,7 @@ public class Solution { func characterReplacement(s string, k int) int { res := 0 charSet := make(map[byte]bool) - + for i := 0; i < len(s); i++ { charSet[s[i]] = true } @@ -334,7 +359,7 @@ func characterReplacement(s string, k int) int { res = max(res, r - l + 1) } } - + return res } @@ -376,12 +401,42 @@ class Solution { } ``` +```swift +class Solution { + func characterReplacement(_ s: String, _ k: Int) -> Int { + var res = 0 + let charSet = Set(s) + let chars = Array(s) + + for c in charSet { + var count = 0, l = 0 + + for r in 0.. k { + if chars[l] == c { + count -= 1 + } + l += 1 + } + + res = max(res, r - l + 1) + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m)$ > Where $n$ is the length of the string and $m$ is the total number of unique characters in the string. @@ -396,7 +451,7 @@ class Solution: def characterReplacement(self, s: str, k: int) -> int: count = {} res = 0 - + l = 0 maxf = 0 for r in range(len(s)): @@ -469,12 +524,13 @@ class Solution { let count = new Map(); let res = 0; - let l = 0, maxf = 0; + let l = 0, + maxf = 0; for (let r = 0; r < s.length; r++) { count.set(s[r], (count.get(s[r]) || 0) + 1); maxf = Math.max(maxf, count.get(s[r])); - while ((r - l + 1) - maxf > k) { + while (r - l + 1 - maxf > k) { count.set(s[l], count.get(s[l]) - 1); l++; } @@ -528,12 +584,12 @@ func characterReplacement(s string, k int) int { count[s[l]]-- l++ } - + if r - l + 1 > res { res = r - l + 1 } } - + return res } ``` @@ -554,7 +610,7 @@ class Solution { count[s[l]] = count[s[l]]!! - 1 l++ } - + res = maxOf(res, r - l + 1) } @@ -563,11 +619,35 @@ class Solution { } ``` +```swift +class Solution { + func characterReplacement(_ s: String, _ k: Int) -> Int { + var count = [Character: Int]() + var res = 0 + var l = 0, maxf = 0 + let chars = Array(s) + + for r in 0.. k { + count[chars[l], default: 0] -= 1 + l += 1 + } + res = max(res, r - l + 1) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n)$ +- Space complexity: $O(m)$ -> Where $n$ is the length of the string and $m$ is the total number of unique characters in the string. \ No newline at end of file +> Where $n$ is the length of the string and $m$ is the total number of unique characters in the string. diff --git a/articles/longest-strictly-increasing-or-strictly-decreasing-subarray.md b/articles/longest-strictly-increasing-or-strictly-decreasing-subarray.md new file mode 100644 index 000000000..614f61df8 --- /dev/null +++ b/articles/longest-strictly-increasing-or-strictly-decreasing-subarray.md @@ -0,0 +1,461 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def longestMonotonicSubarray(self, nums: List[int]) -> int: + n = len(nums) + res = 1 + + for i in range(n - 1): + curLen = 1 + for j in range(i + 1, n): + if nums[j] == nums[j - 1] or ((nums[i] < nums[i + 1]) != (nums[j - 1] < nums[j])): + break + curLen += 1 + + res = max(res, curLen) + + return res +``` + +```java +public class Solution { + public int longestMonotonicSubarray(int[] nums) { + int n = nums.length; + int res = 1; + + for (int i = 0; i < n - 1; i++) { + int curLen = 1; + for (int j = i + 1; j < n; j++) { + if (nums[j] == nums[j - 1] || ((nums[i] < nums[i + 1]) != (nums[j - 1] < nums[j]))) { + break; + } + curLen++; + } + res = Math.max(res, curLen); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestMonotonicSubarray(vector& nums) { + int n = nums.size(); + int res = 1; + + for (int i = 0; i < n - 1; i++) { + int curLen = 1; + for (int j = i + 1; j < n; j++) { + if (nums[j] == nums[j - 1] || ((nums[i] < nums[i + 1]) != (nums[j - 1] < nums[j]))) { + break; + } + curLen++; + } + res = max(res, curLen); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + longestMonotonicSubarray(nums) { + let n = nums.length; + let res = 1; + + for (let i = 0; i < n - 1; i++) { + let curLen = 1; + for (let j = i + 1; j < n; j++) { + if ( + nums[j] === nums[j - 1] || + nums[i] < nums[i + 1] !== nums[j - 1] < nums[j] + ) { + break; + } + curLen++; + } + res = Math.max(res, curLen); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Iteration - I + +::tabs-start + +```python +class Solution: + def longestMonotonicSubarray(self, nums: List[int]) -> int: + cur = 1 + res = 1 + increasing = 0 + + for i in range(1, len(nums)): + if nums[i - 1] < nums[i]: + if increasing > 0: + cur += 1 + else: + cur = 2 + increasing = 1 + elif nums[i - 1] > nums[i]: + if increasing < 0: + cur += 1 + else: + cur = 2 + increasing = -1 + else: + cur = 1 + increasing = 0 + res = max(res, cur) + + return res +``` + +```java +public class Solution { + public int longestMonotonicSubarray(int[] nums) { + int cur = 1; + int res = 1; + int increasing = 0; + + for (int i = 1; i < nums.length; i++) { + if (nums[i - 1] < nums[i]) { + if (increasing > 0) { + cur++; + } else { + cur = 2; + increasing = 1; + } + } else if (nums[i - 1] > nums[i]) { + if (increasing < 0) { + cur++; + } else { + cur = 2; + increasing = -1; + } + } else { + cur = 1; + increasing = 0; + } + res = Math.max(res, cur); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestMonotonicSubarray(vector& nums) { + int cur = 1; + int res = 1; + int increasing = 0; + + for (int i = 1; i < nums.size(); i++) { + if (nums[i - 1] < nums[i]) { + if (increasing > 0) { + cur++; + } else { + cur = 2; + increasing = 1; + } + } else if (nums[i - 1] > nums[i]) { + if (increasing < 0) { + cur++; + } else { + cur = 2; + increasing = -1; + } + } else { + cur = 1; + increasing = 0; + } + res = max(res, cur); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + longestMonotonicSubarray(nums) { + let cur = 1; + let res = 1; + let increasing = 0; + + for (let i = 1; i < nums.length; i++) { + if (nums[i - 1] < nums[i]) { + if (increasing > 0) { + cur++; + } else { + cur = 2; + increasing = 1; + } + } else if (nums[i - 1] > nums[i]) { + if (increasing < 0) { + cur++; + } else { + cur = 2; + increasing = -1; + } + } else { + cur = 1; + increasing = 0; + } + res = Math.max(res, cur); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 3. Iteration - II + +::tabs-start + +```python +class Solution: + def longestMonotonicSubarray(self, nums: List[int]) -> int: + inc = dec = 1 + res = 1 + + for i in range(1, len(nums)): + if nums[i] == nums[i - 1]: + inc = dec = 1 + elif nums[i] > nums[i - 1]: + inc, dec = inc + 1, 1 + else: + inc, dec = 1, dec + 1 + + res = max(res, inc, dec) + + return res +``` + +```java +public class Solution { + public int longestMonotonicSubarray(int[] nums) { + int inc = 1, dec = 1, res = 1; + + for (int i = 1; i < nums.length; i++) { + if (nums[i] == nums[i - 1]) { + inc = dec = 1; + } else if (nums[i] > nums[i - 1]) { + inc = inc + 1; + dec = 1; + } else { + inc = 1; + dec = dec + 1; + } + res = Math.max(res, Math.max(inc, dec)); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestMonotonicSubarray(vector& nums) { + int inc = 1, dec = 1, res = 1; + + for (int i = 1; i < nums.size(); i++) { + if (nums[i] == nums[i - 1]) { + inc = dec = 1; + } else if (nums[i] > nums[i - 1]) { + inc = inc + 1; + dec = 1; + } else { + inc = 1; + dec = dec + 1; + } + res = max(res, max(inc, dec)); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + longestMonotonicSubarray(nums) { + let inc = 1, + dec = 1, + res = 1; + + for (let i = 1; i < nums.length; i++) { + if (nums[i] === nums[i - 1]) { + inc = dec = 1; + } else if (nums[i] > nums[i - 1]) { + inc = inc + 1; + dec = 1; + } else { + inc = 1; + dec = dec + 1; + } + res = Math.max(res, inc, dec); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 4. Iteration - III + +::tabs-start + +```python +class Solution: + def longestMonotonicSubarray(self, nums: List[int]) -> int: + curLen = res = 1 + + for i in range(1, len(nums)): + if (nums[i] == nums[i - 1] or + ((nums[i - curLen] < nums[i - curLen + 1]) != (nums[i - 1] < nums[i])) + ): + curLen = 1 if (nums[i] == nums[i - 1]) else 2 + continue + + curLen += 1 + res = max(res, curLen) + + return res +``` + +```java +public class Solution { + public int longestMonotonicSubarray(int[] nums) { + int curLen = 1, res = 1; + + for (int i = 1; i < nums.length; i++) { + if (nums[i] == nums[i - 1] || + ((nums[i - curLen] < nums[i - curLen + 1]) != (nums[i - 1] < nums[i]))) { + curLen = (nums[i] == nums[i - 1]) ? 1 : 2; + continue; + } + + curLen++; + res = Math.max(res, curLen); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestMonotonicSubarray(vector& nums) { + int curLen = 1, res = 1; + + for (int i = 1; i < nums.size(); i++) { + if (nums[i] == nums[i - 1] || + ((nums[i - curLen] < nums[i - curLen + 1]) != (nums[i - 1] < nums[i]))) { + curLen = (nums[i] == nums[i - 1]) ? 1 : 2; + continue; + } + + curLen++; + res = max(res, curLen); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + longestMonotonicSubarray(nums) { + let curLen = 1, + res = 1; + + for (let i = 1; i < nums.length; i++) { + if ( + nums[i] === nums[i - 1] || + nums[i - curLen] < nums[i - curLen + 1] !== + nums[i - 1] < nums[i] + ) { + curLen = nums[i] === nums[i - 1] ? 1 : 2; + continue; + } + + curLen++; + res = Math.max(res, curLen); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/longest-string-chain.md b/articles/longest-string-chain.md index b033bad4a..5dd13a5d2 100644 --- a/articles/longest-string-chain.md +++ b/articles/longest-string-chain.md @@ -152,8 +152,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m ^ 2)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n * m ^ 2)$ +- Space complexity: $O(n * m)$ > Where $n$ is the number of words and $m$ is the average length of each word. @@ -303,7 +303,10 @@ class Solution { if (words[j].length + 1 < words[i].length) { break; } - if (words[j].length + 1 > words[i].length || !isPred(words[j], words[i])) { + if ( + words[j].length + 1 > words[i].length || + !isPred(words[j], words[i]) + ) { continue; } dp[i] = Math.max(dp[i], 1 + dp[j]); @@ -319,8 +322,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2 * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2 * m)$ +- Space complexity: $O(n)$ > Where $n$ is the number of words and $m$ is the average length of each word. @@ -429,7 +432,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m ^ 2)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n * m ^ 2)$ +- Space complexity: $O(n * m)$ -> Where $n$ is the number of words and $m$ is the average length of each word. \ No newline at end of file +> Where $n$ is the number of words and $m$ is the average length of each word. diff --git a/articles/longest-substring-without-duplicates.md b/articles/longest-substring-without-duplicates.md index a37747ed3..66169d861 100644 --- a/articles/longest-substring-without-duplicates.md +++ b/articles/longest-substring-without-duplicates.md @@ -137,12 +137,33 @@ class Solution { } ``` +```kotlin +class Solution { + func lengthOfLongestSubstring(_ s: String) -> Int { + var res = 0 + let chars = Array(s) + + for i in 0..() + for j in i.. Where $n$ is the length of the string and $m$ is the total number of unique characters in the string. @@ -292,12 +313,32 @@ class Solution { } ``` +```swift +class Solution { + func lengthOfLongestSubstring(_ s: String) -> Int { + var charSet = Set() + var l = 0, res = 0 + let chars = Array(s) + + for r in 0.. Where $n$ is the length of the string and $m$ is the total number of unique characters in the string. @@ -313,7 +354,7 @@ class Solution: mp = {} l = 0 res = 0 - + for r in range(len(s)): if s[r] in mp: l = max(mp[s[r]] + 1, l) @@ -327,7 +368,7 @@ public class Solution { public int lengthOfLongestSubstring(String s) { HashMap mp = new HashMap<>(); int l = 0, res = 0; - + for (int r = 0; r < s.length(); r++) { if (mp.containsKey(s.charAt(r))) { l = Math.max(mp.get(s.charAt(r)) + 1, l); @@ -346,7 +387,7 @@ public: int lengthOfLongestSubstring(string s) { unordered_map mp; int l = 0, res = 0; - + for (int r = 0; r < s.size(); r++) { if (mp.find(s[r]) != mp.end()) { l = max(mp[s[r]] + 1, l); @@ -367,8 +408,9 @@ class Solution { */ lengthOfLongestSubstring(s) { let mp = new Map(); - let l = 0, res = 0; - + let l = 0, + res = 0; + for (let r = 0; r < s.length; r++) { if (mp.has(s[r])) { l = Math.max(mp.get(s[r]) + 1, l); @@ -386,7 +428,7 @@ public class Solution { public int LengthOfLongestSubstring(string s) { Dictionary mp = new Dictionary(); int l = 0, res = 0; - + for (int r = 0; r < s.Length; r++) { if (mp.ContainsKey(s[r])) { l = Math.Max(mp[s[r]] + 1, l); @@ -436,11 +478,30 @@ class Solution { } ``` +```swift +class Solution { + func lengthOfLongestSubstring(_ s: String) -> Int { + var mp = [Character: Int]() + var l = 0, res = 0 + let chars = Array(s) + + for r in 0.. Where $n$ is the length of the string and $m$ is the total number of unique characters in the string. \ No newline at end of file +> Where $n$ is the length of the string and $m$ is the total number of unique characters in the string. diff --git a/articles/longest-turbulent-subarray.md b/articles/longest-turbulent-subarray.md index a7876d5c0..1ff1ccd4f 100644 --- a/articles/longest-turbulent-subarray.md +++ b/articles/longest-turbulent-subarray.md @@ -7,11 +7,11 @@ class Solution: def maxTurbulenceSize(self, arr: List[int]) -> int: n = len(arr) res = 1 - + for i in range(n - 1): if arr[i] == arr[i + 1]: continue - + sign = 1 if arr[i] > arr[i + 1] else 0 j = i + 1 while j < n - 1: @@ -19,12 +19,12 @@ class Solution: break curSign = 1 if arr[j] > arr[j + 1] else 0 if sign == curSign: - break + break sign = curSign j += 1 - + res = max(res, j - i + 1) - + return res ``` @@ -123,12 +123,42 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxTurbulenceSize(int[] arr) { + int n = arr.Length; + int res = 1; + + for (int i = 0; i < n - 1; i++) { + if (arr[i] == arr[i + 1]) continue; + + int sign = arr[i] > arr[i + 1] ? 1 : 0; + int j = i + 1; + + while (j < n - 1) { + if (arr[j] == arr[j + 1]) break; + + int curSign = arr[j] > arr[j + 1] ? 1 : 0; + if (sign == curSign) break; + + sign = curSign; + j++; + } + + res = Math.Max(res, j - i + 1); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. --- @@ -149,7 +179,7 @@ class Solution: return memo[(i, sign)] res = 1 - if ((sign and arr[i] > arr[i + 1]) or + if ((sign and arr[i] > arr[i + 1]) or (not sign and arr[i] < arr[i + 1]) ): res = 1 + dfs(i + 1, not sign) @@ -194,7 +224,7 @@ public class Solution { } int res = 1; - if ((sign && arr[i] > arr[i + 1]) || + if ((sign && arr[i] > arr[i + 1]) || (!sign && arr[i] < arr[i + 1])) { res = 1 + dfs(i + 1, !sign, arr); } @@ -231,7 +261,7 @@ public: } int res = 1; - if ((sign && arr[i] > arr[i + 1]) || + if ((sign && arr[i] > arr[i + 1]) || (!sign && arr[i] < arr[i + 1])) { res = 1 + dfs(i + 1, !sign, arr); } @@ -260,8 +290,10 @@ class Solution { } let res = 1; - if ((sign && arr[i] > arr[i + 1]) || - (!sign && arr[i] < arr[i + 1])) { + if ( + (sign && arr[i] > arr[i + 1]) || + (!sign && arr[i] < arr[i + 1]) + ) { res = 1 + dfs(i + 1, !sign); } @@ -279,12 +311,47 @@ class Solution { } ``` +```csharp +public class Solution { + private int[] arr; + private int n; + private Dictionary<(int, bool), int> memo; + + public int MaxTurbulenceSize(int[] arr) { + this.arr = arr; + this.n = arr.Length; + this.memo = new Dictionary<(int, bool), int>(); + + int maxLen = 1; + for (int i = 0; i < n; i++) { + maxLen = Math.Max(maxLen, Dfs(i, true)); + maxLen = Math.Max(maxLen, Dfs(i, false)); + } + + return maxLen; + } + + private int Dfs(int i, bool sign) { + if (i == n - 1) return 1; + if (memo.ContainsKey((i, sign))) return memo[(i, sign)]; + + int res = 1; + if ((sign && arr[i] > arr[i + 1]) || (!sign && arr[i] < arr[i + 1])) { + res = 1 + Dfs(i + 1, !sign); + } + + memo[(i, sign)] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -391,12 +458,40 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxTurbulenceSize(int[] arr) { + int n = arr.Length; + if (n == 1) return 1; + + int[,] dp = new int[n, 2]; + for (int i = 0; i < n; i++) { + dp[i, 0] = 1; + dp[i, 1] = 1; + } + + int maxLen = 1; + for (int i = 1; i < n; i++) { + if (arr[i] > arr[i - 1]) { + dp[i, 1] = dp[i - 1, 0] + 1; + } else if (arr[i] < arr[i - 1]) { + dp[i, 0] = dp[i - 1, 1] + 1; + } + + maxLen = Math.Max(maxLen, Math.Max(dp[i, 0], dp[i, 1])); + } + + return maxLen; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -488,19 +583,49 @@ class Solution { * @return {number} */ maxTurbulenceSize(arr) { - let l = 0, r = 1, res = 1, prev = ""; + let l = 0, + r = 1, + res = 1, + prev = ''; while (r < arr.length) { - if (arr[r - 1] > arr[r] && prev !== ">") { + if (arr[r - 1] > arr[r] && prev !== '>') { res = Math.max(res, r - l + 1); r++; - prev = ">"; - } else if (arr[r - 1] < arr[r] && prev !== "<") { + prev = '>'; + } else if (arr[r - 1] < arr[r] && prev !== '<') { res = Math.max(res, r - l + 1); r++; + prev = '<'; + } else { + r = arr[r] === arr[r - 1] ? r + 1 : r; + l = r - 1; + prev = ''; + } + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int MaxTurbulenceSize(int[] arr) { + int l = 0, r = 1, res = 1; + string prev = ""; + + while (r < arr.Length) { + if (arr[r - 1] > arr[r] && prev != ">") { + res = Math.Max(res, r - l + 1); + r++; + prev = ">"; + } else if (arr[r - 1] < arr[r] && prev != "<") { + res = Math.Max(res, r - l + 1); + r++; prev = "<"; } else { - r = (arr[r] === arr[r - 1]) ? r + 1 : r; + r = (arr[r] == arr[r - 1]) ? r + 1 : r; l = r - 1; prev = ""; } @@ -515,8 +640,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -530,7 +655,7 @@ class Solution: n = len(arr) res = cnt = 0 sign = -1 - + for i in range(n - 1): if arr[i] > arr[i + 1]: cnt = cnt + 1 if sign == 0 else 1 @@ -541,9 +666,9 @@ class Solution: else: cnt = 0 sign = -1 - + res = max(res, cnt) - + return res + 1 ``` @@ -552,7 +677,7 @@ public class Solution { public int maxTurbulenceSize(int[] arr) { int n = arr.length; int res = 0, cnt = 0, sign = -1; - + for (int i = 0; i < n - 1; i++) { if (arr[i] > arr[i + 1]) { cnt = (sign == 0) ? cnt + 1 : 1; @@ -564,10 +689,10 @@ public class Solution { cnt = 0; sign = -1; } - + res = Math.max(res, cnt); } - + return res + 1; } } @@ -579,7 +704,7 @@ public: int maxTurbulenceSize(vector& arr) { int n = arr.size(); int res = 0, cnt = 0, sign = -1; - + for (int i = 0; i < n - 1; i++) { if (arr[i] > arr[i + 1]) { cnt = (sign == 0) ? cnt + 1 : 1; @@ -591,10 +716,10 @@ public: cnt = 0; sign = -1; } - + res = max(res, cnt); } - + return res + 1; } }; @@ -608,23 +733,51 @@ class Solution { */ maxTurbulenceSize(arr) { const n = arr.length; - let res = 0, cnt = 0, sign = -1; - + let res = 0, + cnt = 0, + sign = -1; + for (let i = 0; i < n - 1; i++) { if (arr[i] > arr[i + 1]) { - cnt = (sign === 0) ? cnt + 1 : 1; + cnt = sign === 0 ? cnt + 1 : 1; sign = 1; } else if (arr[i] < arr[i + 1]) { - cnt = (sign === 1) ? cnt + 1 : 1; + cnt = sign === 1 ? cnt + 1 : 1; sign = 0; } else { cnt = 0; sign = -1; } - + res = Math.max(res, cnt); } - + + return res + 1; + } +} +``` + +```csharp +public class Solution { + public int MaxTurbulenceSize(int[] arr) { + int n = arr.Length; + int res = 0, cnt = 0, sign = -1; + + for (int i = 0; i < n - 1; i++) { + if (arr[i] > arr[i + 1]) { + cnt = (sign == 0) ? cnt + 1 : 1; + sign = 1; + } else if (arr[i] < arr[i + 1]) { + cnt = (sign == 1) ? cnt + 1 : 1; + sign = 0; + } else { + cnt = 0; + sign = -1; + } + + res = Math.Max(res, cnt); + } + return res + 1; } } @@ -634,5 +787,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/lowest-common-ancestor-in-binary-search-tree.md b/articles/lowest-common-ancestor-in-binary-search-tree.md index 70d66615b..0dd47e964 100644 --- a/articles/lowest-common-ancestor-in-binary-search-tree.md +++ b/articles/lowest-common-ancestor-in-binary-search-tree.md @@ -211,12 +211,44 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init(_ val: Int) { + * self.val = val + * self.left = nil + * self.right = nil + * } + * } + */ + +class Solution { + func lowestCommonAncestor(_ root: TreeNode?, _ p: TreeNode?, _ q: TreeNode?) -> TreeNode? { + guard let root = root, let p = p, let q = q else { + return nil + } + + if max(p.val, q.val) < root.val { + return lowestCommonAncestor(root.left, p, q) + } else if min(p.val, q.val) > root.val { + return lowestCommonAncestor(root.right, p, q) + } else { + return root + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(h)$ -* Space complexity: $O(h)$ +- Time complexity: $O(h)$ +- Space complexity: $O(h)$ > Where $h$ is the height of the tree. @@ -267,7 +299,7 @@ class Solution: public class Solution { public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { TreeNode cur = root; - + while (cur != null) { if (p.val > cur.val && q.val > cur.val) { cur = cur.right; @@ -436,11 +468,46 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init(_ val: Int) { + * self.val = val + * self.left = nil + * self.right = nil + * } + * } + */ + +class Solution { + func lowestCommonAncestor(_ root: TreeNode?, _ p: TreeNode?, _ q: TreeNode?) -> TreeNode? { + var cur = root + + while let node = cur { + if let p = p, let q = q { + if p.val > node.val && q.val > node.val { + cur = node.right + } else if p.val < node.val && q.val < node.val { + cur = node.left + } else { + return node + } + } + } + return nil + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(h)$ -* Space complexity: $O(1)$ +- Time complexity: $O(h)$ +- Space complexity: $O(1)$ -> Where $h$ is the height of the tree. \ No newline at end of file +> Where $h$ is the height of the tree. diff --git a/articles/lowest-common-ancestor-of-a-binary-tree-iii.md b/articles/lowest-common-ancestor-of-a-binary-tree-iii.md new file mode 100644 index 000000000..6f6084f25 --- /dev/null +++ b/articles/lowest-common-ancestor-of-a-binary-tree-iii.md @@ -0,0 +1,504 @@ +## 1. Hash Set + +::tabs-start + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val): + self.val = val + self.left = None + self.right = None + self.parent = None +""" + +class Solution: + def lowestCommonAncestor(self, p: 'Node', q: 'Node') -> 'Node': + seen = set() + while p: + seen.add(p) + p = p.parent + + while q: + if q in seen: + return q + q = q.parent +``` + +```java +/* +// Definition for a Node. +class Node { + public int val; + public Node left; + public Node right; + public Node parent; +}; +*/ + +public class Solution { + public Node lowestCommonAncestor(Node p, Node q) { + Set seen = new HashSet<>(); + while (p != null) { + seen.add(p); + p = p.parent; + } + while (q != null) { + if (seen.contains(q)) return q; + q = q.parent; + } + return null; + } +} +``` + +```cpp +/* +// Definition for a Node. +class Node { +public: + int val; + Node* left; + Node* right; + Node* parent; +}; +*/ + +class Solution { +public: + Node* lowestCommonAncestor(Node* p, Node* q) { + unordered_set seen; + while (p) { + seen.insert(p); + p = p->parent; + } + while (q) { + if (seen.count(q)) return q; + q = q->parent; + } + return nullptr; + } +}; +``` + +```javascript +/** + * // Definition for a _Node. + * function _Node(val) { + * this.val = val; + * this.left = null; + * this.right = null; + * this.parent = null; + * }; + */ +class Solution { + /** + * @param {_Node} p + * @param {_Node} q + * @return {_Node} + */ + lowestCommonAncestor(p, q) { + const seen = new Set(); + while (p) { + seen.add(p); + p = p.parent; + } + while (q) { + if (seen.has(q)) return q; + q = q.parent; + } + return null; + } +} +``` + +```csharp +/* +// Definition for a Node. +public class Node { + public int val; + public Node left; + public Node right; + public Node parent; +} +*/ + +public class Solution { + public Node LowestCommonAncestor(Node p, Node q) { + var seen = new HashSet(); + while (p != null) { + seen.Add(p); + p = p.parent; + } + while (q != null) { + if (seen.Contains(q)) return q; + q = q.parent; + } + return null; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Iteration - I + +::tabs-start + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val): + self.val = val + self.left = None + self.right = None + self.parent = None +""" + +class Solution: + def lowestCommonAncestor(self, p: 'Node', q: 'Node') -> 'Node': + def height(node): + h = 0 + while node: + h += 1 + node = node.parent + return h + + h1, h2 = height(p), height(q) + if h2 < h1: + p, q = q, p + + diff = abs(h1 - h2) + while diff: + q = q.parent + diff -= 1 + + while p != q: + p = p.parent + q = q.parent + + return p +``` + +```java +/* +// Definition for a Node. +class Node { + public int val; + public Node left; + public Node right; + public Node parent; +}; +*/ + +public class Solution { + public Node lowestCommonAncestor(Node p, Node q) { + int h1 = height(p), h2 = height(q); + if (h2 < h1) { + Node tmp = p; p = q; q = tmp; + int th = h1; h1 = h2; h2 = th; + } + + int diff = h2 - h1; + while (diff-- > 0) { + q = q.parent; + } + + while (p != q) { + p = p.parent; + q = q.parent; + } + return p; + } + + private int height(Node node) { + int h = 0; + while (node != null) { + h++; + node = node.parent; + } + return h; + } +} +``` + +```cpp +/* +// Definition for a Node. +class Node { +public: + int val; + Node* left; + Node* right; + Node* parent; +}; +*/ + +class Solution { +public: + Node* lowestCommonAncestor(Node* p, Node* q) { + int h1 = height(p), h2 = height(q); + if (h2 < h1) { + swap(p, q); + swap(h1, h2); + } + int diff = h2 - h1; + while (diff-- > 0) { + q = q->parent; + } + while (p != q) { + p = p->parent; + q = q->parent; + } + return p; + } + +private: + int height(Node* node) { + int h = 0; + while (node) { + h++; + node = node->parent; + } + return h; + } +}; +``` + +```javascript +/** + * // Definition for a _Node. + * function _Node(val) { + * this.val = val; + * this.left = null; + * this.right = null; + * this.parent = null; + * }; + */ +class Solution { + /** + * @param {_Node} p + * @param {_Node} q + * @return {_Node} + */ + lowestCommonAncestor(p, q) { + const height = (node) => { + let h = 0; + while (node) { + h++; + node = node.parent; + } + return h; + }; + + let h1 = height(p), + h2 = height(q); + if (h2 < h1) { + [p, q] = [q, p]; + [h1, h2] = [h2, h1]; + } + + let diff = h2 - h1; + while (diff-- > 0) { + q = q.parent; + } + + while (p !== q) { + p = p.parent; + q = q.parent; + } + return p; + } +} +``` + +```csharp +/* +// Definition for a Node. +public class Node { + public int val; + public Node left; + public Node right; + public Node parent; +} +*/ + +public class Solution { + public Node LowestCommonAncestor(Node p, Node q) { + int h1 = Height(p), h2 = Height(q); + if (h2 < h1) { + var tmp = p; p = q; q = tmp; + int th = h1; h1 = h2; h2 = th; + } + + int diff = h2 - h1; + while (diff-- > 0) { + q = q.parent; + } + + while (p != q) { + p = p.parent; + q = q.parent; + } + return p; + } + + private int Height(Node node) { + int h = 0; + while (node != null) { + h++; + node = node.parent; + } + return h; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 3. Iteration - II + +::tabs-start + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val): + self.val = val + self.left = None + self.right = None + self.parent = None +""" + +class Solution: + def lowestCommonAncestor(self, p: 'Node', q: 'Node') -> 'Node': + ptr1, ptr2 = p, q + while ptr1 != ptr2: + ptr1 = ptr1.parent if ptr1 else q + ptr2 = ptr2.parent if ptr2 else p + return ptr1 +``` + +```java +/* +// Definition for a Node. +class Node { + public int val; + public Node left; + public Node right; + public Node parent; +}; +*/ + +public class Solution { + public Node lowestCommonAncestor(Node p, Node q) { + Node ptr1 = p, ptr2 = q; + while (ptr1 != ptr2) { + ptr1 = (ptr1 != null) ? ptr1.parent : q; + ptr2 = (ptr2 != null) ? ptr2.parent : p; + } + return ptr1; + } +} +``` + +```cpp +/* +// Definition for a Node. +class Node { +public: + int val; + Node* left; + Node* right; + Node* parent; +}; +*/ + +class Solution { +public: + Node* lowestCommonAncestor(Node* p, Node* q) { + Node* ptr1 = p; + Node* ptr2 = q; + while (ptr1 != ptr2) { + ptr1 = ptr1 ? ptr1->parent : q; + ptr2 = ptr2 ? ptr2->parent : p; + } + return ptr1; + } +}; +``` + +```javascript +/** + * // Definition for a _Node. + * function _Node(val) { + * this.val = val; + * this.left = null; + * this.right = null; + * this.parent = null; + * }; + */ +class Solution { + /** + * @param {_Node} p + * @param {_Node} q + * @return {_Node} + */ + lowestCommonAncestor(p, q) { + let ptr1 = p, + ptr2 = q; + while (ptr1 !== ptr2) { + ptr1 = ptr1 ? ptr1.parent : q; + ptr2 = ptr2 ? ptr2.parent : p; + } + return ptr1; + } +} +``` + +```csharp +/* +// Definition for a Node. +public class Node { + public int val; + public Node left; + public Node right; + public Node parent; +} +*/ + +public class Solution { + public Node LowestCommonAncestor(Node p, Node q) { + Node ptr1 = p, ptr2 = q; + while (ptr1 != ptr2) { + ptr1 = ptr1 != null ? ptr1.parent : q; + ptr2 = ptr2 != null ? ptr2.parent : p; + } + return ptr1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/lowest-common-ancestor-of-a-binary-tree.md b/articles/lowest-common-ancestor-of-a-binary-tree.md new file mode 100644 index 000000000..d6fdbe8e4 --- /dev/null +++ b/articles/lowest-common-ancestor-of-a-binary-tree.md @@ -0,0 +1,546 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def lowestCommonAncestor(self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode') -> 'TreeNode': + lca = None + + def dfs(node): + nonlocal lca + if not node: + return [False, False] + if lca: + return [False, False] + + left = dfs(node.left) + right = dfs(node.right) + res = [left[0] or right[0] or (node == p), left[1] or right[1] or (node == q)] + if res[0] and res[1] and not lca: + lca = node + + return res + + dfs(root) + return lca +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class Solution { + private TreeNode lca = null; + + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + lca = null; + dfs(root, p, q); + return lca; + } + + private boolean[] dfs(TreeNode node, TreeNode p, TreeNode q) { + if (node == null || lca != null) { + return new boolean[]{false, false}; + } + boolean[] left = dfs(node.left, p, q); + boolean[] right = dfs(node.right, p, q); + boolean foundP = left[0] || right[0] || node == p; + boolean foundQ = left[1] || right[1] || node == q; + if (foundP && foundQ && lca == null) { + lca = node; + } + return new boolean[]{foundP, foundQ}; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + lca = nullptr; + dfs(root, p, q); + return lca; + } + +private: + TreeNode* lca; + + pair dfs(TreeNode* node, TreeNode* p, TreeNode* q) { + if (!node || lca) { + return {false, false}; + } + auto left = dfs(node->left, p, q); + auto right = dfs(node->right, p, q); + bool foundP = left.first || right.first || node == p; + bool foundQ = left.second || right.second || node == q; + if (foundP && foundQ && !lca) { + lca = node; + } + return {foundP, foundQ}; + } +}; +``` + +```javascript +/** + * // Definition for a Node. + * function Node(val) { + * this.val = val; + * this.left = null; + * this.right = null; + * this.parent = null; + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ + lowestCommonAncestor(root, p, q) { + let lca = null; + const dfs = node => { + if (!node || lca) return [false, false]; + const left = dfs(node.left); + const right = dfs(node.right); + const foundP = left[0] || right[0] || node === p; + const foundQ = left[1] || right[1] || node === q; + if (foundP && foundQ && !lca) { + lca = node; + } + return [foundP, foundQ]; + }; + dfs(root); + return lca; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int x) { val = x; } + * } + */ +public class Solution { + private TreeNode lca = null; + + public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + lca = null; + Dfs(root, p, q); + return lca; + } + + private (bool, bool) Dfs(TreeNode node, TreeNode p, TreeNode q) { + if (node == null || lca != null) { + return (false, false); + } + var left = Dfs(node.left, p, q); + var right = Dfs(node.right, p, q); + bool foundP = left.Item1 || right.Item1 || node == p; + bool foundQ = left.Item2 || right.Item2 || node == q; + if (foundP && foundQ && lca == null) { + lca = node; + } + return (foundP, foundQ); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Depth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def lowestCommonAncestor( + self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode' + ) -> 'TreeNode': + if root is None or root is p or root is q: + return root + + left = self.lowestCommonAncestor(root.left, p, q) + right = self.lowestCommonAncestor(root.right, p, q) + + if left and right: + return root + + return left if left else right +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) { + return root; + } + TreeNode left = lowestCommonAncestor(root.left, p, q); + TreeNode right = lowestCommonAncestor(root.right, p, q); + if (left != null && right != null) { + return root; + } + return left != null ? left : right; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + if (!root || root == p || root == q) { + return root; + } + TreeNode* left = lowestCommonAncestor(root->left, p, q); + TreeNode* right = lowestCommonAncestor(root->right, p, q); + if (left && right) { + return root; + } + return left ? left : right; + } +}; +``` + +```javascript +/** + * // Definition for a Node. + * function Node(val) { + * this.val = val; + * this.left = null; + * this.right = null; + * this.parent = null; + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ + lowestCommonAncestor(root, p, q) { + if (!root || root === p || root === q) { + return root; + } + const left = this.lowestCommonAncestor(root.left, p, q); + const right = this.lowestCommonAncestor(root.right, p, q); + return left && right ? root : (left || right); + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int x) { val = x; } + * } + */ +public class Solution { + public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null || root == p || root == q) { + return root; + } + TreeNode left = LowestCommonAncestor(root.left, p, q); + TreeNode right = LowestCommonAncestor(root.right, p, q); + if (left != null && right != null) { + return root; + } + return left ?? right; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, x): +# self.val = x +# self.left = None +# self.right = None + +class Solution: + def lowestCommonAncestor( + self, root: 'TreeNode', p: 'TreeNode', q: 'TreeNode' + ) -> 'TreeNode': + parent = {root: None} + queue = deque([root]) + while p not in parent or q not in parent: + node = queue.popleft() + if node.left: + parent[node.left] = node + queue.append(node.left) + if node.right: + parent[node.right] = node + queue.append(node.right) + + ancestors = set() + while p: + ancestors.add(p) + p = parent[p] + + while q not in ancestors: + q = parent[q] + + return q +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode(int x) { val = x; } + * } + */ +public class Solution { + public TreeNode lowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null) return null; + Map parent = new HashMap<>(); + Queue queue = new LinkedList<>(); + parent.put(root, null); + queue.add(root); + while (!parent.containsKey(p) || !parent.containsKey(q)) { + TreeNode node = queue.poll(); + if (node.left != null) { + parent.put(node.left, node); + queue.add(node.left); + } + if (node.right != null) { + parent.put(node.right, node); + queue.add(node.right); + } + } + + Set ancestors = new HashSet<>(); + while (p != null) { + ancestors.add(p); + p = parent.get(p); + } + while (!ancestors.contains(q)) { + q = parent.get(q); + } + return q; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode(int x) : val(x), left(NULL), right(NULL) {} + * }; + */ +class Solution { +public: + TreeNode* lowestCommonAncestor(TreeNode* root, TreeNode* p, TreeNode* q) { + if (!root) return nullptr; + unordered_map parent; + queue queue; + parent[root] = nullptr; + queue.push(root); + while (!parent.count(p) || !parent.count(q)) { + TreeNode* node = queue.front(); queue.pop(); + if (node->left) { + parent[node->left] = node; + queue.push(node->left); + } + if (node->right) { + parent[node->right] = node; + queue.push(node->right); + } + } + + unordered_set ancestors; + while (p) { + ancestors.insert(p); + p = parent[p]; + } + while (!ancestors.count(q)) { + q = parent[q]; + } + return q; + } +}; +``` + +```javascript +/** + * // Definition for a Node. + * function Node(val) { + * this.val = val; + * this.left = null; + * this.right = null; + * this.parent = null; + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {TreeNode} p + * @param {TreeNode} q + * @return {TreeNode} + */ + lowestCommonAncestor(root, p, q) { + if (!root) return null; + const parent = new Map(); + const queue = new Queue([root]); + parent.set(root, null); + while (!parent.has(p) || !parent.has(q)) { + const node = queue.pop(); + if (node.left) { + parent.set(node.left, node); + queue.push(node.left); + } + if (node.right) { + parent.set(node.right, node); + queue.push(node.right); + } + } + + const ancestors = new Set(); + while (p) { + ancestors.add(p); + p = parent.get(p); + } + while (!ancestors.has(q)) { + q = parent.get(q); + } + return q; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public int val; + * public TreeNode left; + * public TreeNode right; + * public TreeNode(int x) { val = x; } + * } + */ +public class Solution { + public TreeNode LowestCommonAncestor(TreeNode root, TreeNode p, TreeNode q) { + if (root == null) return null; + var parent = new Dictionary(); + var queue = new Queue(); + parent[root] = null; + queue.Enqueue(root); + while (!parent.ContainsKey(p) || !parent.ContainsKey(q)) { + var node = queue.Dequeue(); + if (node.left != null) { + parent[node.left] = node; + queue.Enqueue(node.left); + } + if (node.right != null) { + parent[node.right] = node; + queue.Enqueue(node.right); + } + } + + var ancestors = new HashSet(); + while (p != null) { + ancestors.Add(p); + p = parent[p]; + } + while (!ancestors.Contains(q)) { + q = parent[q]; + } + return q; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/lru-cache.md b/articles/lru-cache.md index d93c79886..d36605c15 100644 --- a/articles/lru-cache.md +++ b/articles/lru-cache.md @@ -27,7 +27,7 @@ class LRUCache: if self.capacity == len(self.cache): self.cache.pop(0) - + self.cache.append([key, value]) ``` @@ -82,7 +82,7 @@ public: LRUCache(int capacity) { this->capacity = capacity; } - + int get(int key) { for (int i = 0; i < cache.size(); i++) { if (cache[i].first == key) { @@ -94,7 +94,7 @@ public: } return -1; } - + void put(int key, int value) { for (int i = 0; i < cache.size(); i++) { if (cache[i].first == key) { @@ -170,7 +170,7 @@ public class LRUCache { this.cache = new List>(); this.capacity = capacity; } - + public int Get(int key) { for (int i = 0; i < cache.Count; i++) { if (cache[i].Key == key) { @@ -182,7 +182,7 @@ public class LRUCache { } return -1; } - + public void Put(int key, int value) { for (int i = 0; i < cache.Count; i++) { if (cache[i].Key == key) { @@ -236,11 +236,11 @@ func (this *LRUCache) Put(key int, value int) { return } } - + if len(this.cache) == this.capacity { this.cache = this.cache[1:] } - + this.cache = append(this.cache, [2]int{key, value}) } ``` @@ -249,7 +249,7 @@ func (this *LRUCache) Put(key int, value int) { class LRUCache(capacity: Int) { private val capacity = capacity private val cache = mutableListOf>() - + fun get(key: Int): Int { for (i in cache.indices) { if (cache[i].first == key) { @@ -260,7 +260,7 @@ class LRUCache(capacity: Int) { } return -1 } - + fun put(key: Int, value: Int) { for (i in cache.indices) { if (cache[i].first == key) { @@ -269,22 +269,62 @@ class LRUCache(capacity: Int) { return } } - + if (cache.size == capacity) { cache.removeAt(0) } - + cache.add(Pair(key, value)) } } ``` +```swift +class LRUCache { + private var cache: [(Int, Int)] + private let capacity: Int + + init(_ capacity: Int) { + self.cache = [] + self.capacity = capacity + } + + func get(_ key: Int) -> Int { + for i in 0.. cache; private Node left; @@ -578,7 +618,7 @@ public class Node { } public class LRUCache { - + private int cap; private Dictionary cache; private Node left; @@ -687,11 +727,11 @@ func (this *LRUCache) Put(key int, value int) { this.remove(node) delete(this.cache, key) } - + node := &Node{key: key, val: value} this.cache[key] = node this.insert(node) - + if len(this.cache) > this.cap { lru := this.left.next this.remove(lru) @@ -709,23 +749,23 @@ class LRUCache(capacity: Int) { var prev: Node? = null, var next: Node? = null ) - + private val cache = mutableMapOf() private val left = Node(0, 0) private val right = Node(0, 0) - + init { left.next = right right.prev = left } - + private fun remove(node: Node) { val prev = node.prev val next = node.next prev?.next = next next?.prev = prev } - + private fun insert(node: Node) { val prev = right.prev val next = right @@ -734,7 +774,7 @@ class LRUCache(capacity: Int) { node.next = next node.prev = prev } - + fun get(key: Int): Int { return cache[key]?.let { node -> remove(node) @@ -742,17 +782,17 @@ class LRUCache(capacity: Int) { node.value } ?: -1 } - + fun put(key: Int, value: Int) { cache[key]?.let { node -> remove(node) cache.remove(key) } - + val node = Node(key, value) cache[key] = node insert(node) - + if (cache.size > capacity) { left.next?.let { lru -> remove(lru) @@ -763,12 +803,82 @@ class LRUCache(capacity: Int) { } ``` +```swift +class Node { + var key: Int + var val: Int + var prev: Node? + var next: Node? + + init(_ key: Int, _ val: Int) { + self.key = key + self.val = val + } +} + +class LRUCache { + private var cap: Int + private var cache: [Int: Node] = [:] + private var left: Node + private var right: Node + + init(_ capacity: Int) { + self.cap = capacity + self.left = Node(0, 0) + self.right = Node(0, 0) + self.left.next = self.right + self.right.prev = self.left + } + + private func remove(_ node: Node?) { + let prev = node?.prev + let next = node?.next + prev?.next = next + next?.prev = prev + } + + private func insert(_ node: Node?) { + let prev = right.prev + let next = right + prev?.next = node + next.prev = node + node?.prev = prev + node?.next = next + } + + func get(_ key: Int) -> Int { + if let node = cache[key] { + remove(node) + insert(node) + return node.val + } + return -1 + } + + func put(_ key: Int, _ value: Int) { + if let node = cache[key] { + remove(node) + } + let newNode = Node(key, value) + cache[key] = newNode + insert(newNode) + + if cache.count > cap { + if let lru = left.next { + remove(lru) + cache.removeValue(forKey: lru.key) + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ for each $put()$ and $get()$ operation. -* Space complexity: $O(n)$ +- Time complexity: $O(1)$ for each $put()$ and $get()$ operation. +- Space complexity: $O(n)$ --- @@ -833,7 +943,7 @@ public: LRUCache(int capacity) { this->capacity = capacity; } - + int get(int key) { if (cache.find(key) == cache.end()) return -1; order.erase(cache[key].second); @@ -841,7 +951,7 @@ public: cache[key].second = --order.end(); return cache[key].first; } - + void put(int key, int value) { if (cache.find(key) != cache.end()) { order.erase(cache[key].second); @@ -991,20 +1101,59 @@ class LRUCache(capacity: Int) { return size > capacity } } - + fun get(key: Int): Int { return cache.getOrDefault(key, -1) } - + fun put(key: Int, value: Int) { cache[key] = value } } ``` +```swift +class LRUCache { + private var capacity: Int + private var cache: [Int: Int] = [:] + private var keyOrder: [Int] = [] + + init(_ capacity: Int) { + self.capacity = capacity + } + + func get(_ key: Int) -> Int { + if let value = cache[key] { + if let index = keyOrder.firstIndex(of: key) { + keyOrder.remove(at: index) + } + keyOrder.append(key) + return value + } + return -1 + } + + func put(_ key: Int, _ value: Int) { + if cache[key] != nil { + if let index = keyOrder.firstIndex(of: key) { + keyOrder.remove(at: index) + } + } else if cache.count >= capacity { + if let lruKey = keyOrder.first { + cache.removeValue(forKey: lruKey) + keyOrder.removeFirst() + } + } + + cache[key] = value + keyOrder.append(key) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ for each $put()$ and $get()$ operation. -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(1)$ for each $put()$ and $get()$ operation. +- Space complexity: $O(n)$ diff --git a/articles/majority-element-ii.md b/articles/majority-element-ii.md index 6ba0f2fd1..ea1a647ef 100644 --- a/articles/majority-element-ii.md +++ b/articles/majority-element-ii.md @@ -72,12 +72,30 @@ class Solution { } ``` +```csharp +public class Solution { + public List MajorityElement(int[] nums) { + HashSet res = new HashSet(); + int n = nums.Length; + + foreach (int num in nums) { + int count = nums.Count(x => x == num); + if (count > n / 3) { + res.Add(num); + } + } + + return res.ToList(); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ since output array size will be at most $2$. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ since output array size will be at most $2$. --- @@ -90,7 +108,7 @@ class Solution: def majorityElement(self, nums: List[int]) -> List[int]: nums.sort() res, n = [], len(nums) - + i = 0 while i < n: j = i + 1 @@ -121,7 +139,7 @@ public class Solution { } i = j; } - + return res; } } @@ -146,7 +164,7 @@ public: } i = j; } - + return res; } }; @@ -174,7 +192,31 @@ class Solution { } i = j; } - + + return res; + } +} +``` + +```csharp +public class Solution { + public List MajorityElement(int[] nums) { + Array.Sort(nums); + List res = new List(); + int n = nums.Length; + + int i = 0; + while (i < n) { + int j = i + 1; + while (j < n && nums[j] == nums[i]) { + j++; + } + if (j - i > n / 3) { + res.Add(nums[i]); + } + i = j; + } + return res; } } @@ -184,8 +226,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -202,7 +244,7 @@ class Solution: for key in count: if count[key] > len(nums) // 3: res.append(key) - + return res ``` @@ -220,7 +262,7 @@ public class Solution { res.add(key); } } - + return res; } } @@ -241,7 +283,7 @@ public: res.push_back(pair.first); } } - + return res; } }; @@ -271,12 +313,37 @@ class Solution { } ``` +```csharp +public class Solution { + public List MajorityElement(int[] nums) { + Dictionary count = new Dictionary(); + List res = new List(); + int n = nums.Length; + + foreach (int num in nums) { + if (!count.ContainsKey(num)) { + count[num] = 0; + } + count[num]++; + } + + foreach (var kvp in count) { + if (kvp.Value > n / 3) { + res.Add(kvp.Key); + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -305,20 +372,20 @@ class Solution: else: cnt1 -= 1 cnt2 -= 1 - + cnt1 = cnt2 = 0 for num in nums: if num == num1: cnt1 += 1 elif num == num2: cnt2 += 1 - + res = [] if cnt1 > n // 3: res.append(num1) if cnt2 > n // 3: res.append(num2) - + return res ``` @@ -410,7 +477,10 @@ class Solution { */ majorityElement(nums) { const n = nums.length; - let num1 = -1, num2 = -1, cnt1 = 0, cnt2 = 0; + let num1 = -1, + num2 = -1, + cnt1 = 0, + cnt2 = 0; for (const num of nums) { if (num === num1) { @@ -444,12 +514,51 @@ class Solution { } ``` +```csharp +public class Solution { + public List MajorityElement(int[] nums) { + int n = nums.Length; + int num1 = -1, num2 = -1; + int cnt1 = 0, cnt2 = 0; + + foreach (int num in nums) { + if (num == num1) { + cnt1++; + } else if (num == num2) { + cnt2++; + } else if (cnt1 == 0) { + num1 = num; + cnt1 = 1; + } else if (cnt2 == 0) { + num2 = num; + cnt2 = 1; + } else { + cnt1--; + cnt2--; + } + } + + cnt1 = cnt2 = 0; + foreach (int num in nums) { + if (num == num1) cnt1++; + else if (num == num2) cnt2++; + } + + List res = new List(); + if (cnt1 > n / 3) res.Add(num1); + if (cnt2 > n / 3) res.Add(num2); + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since output array size will be at most $2$. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since output array size will be at most $2$. --- @@ -461,24 +570,24 @@ class Solution { class Solution: def majorityElement(self, nums: List[int]) -> List[int]: count = defaultdict(int) - + for num in nums: count[num] += 1 - + if len(count) <= 2: continue - + new_count = defaultdict(int) for num, c in count.items(): if c > 1: new_count[num] = c - 1 count = new_count - + res = [] for num in count: if nums.count(num) > len(nums) // 3: res.append(num) - + return res ``` @@ -578,7 +687,7 @@ class Solution { const res = []; for (const [key] of count.entries()) { - const frequency = nums.filter(num => num === key).length; + const frequency = nums.filter((num) => num === key).length; if (frequency > Math.floor(nums.length / 3)) { res.push(key); } @@ -589,9 +698,52 @@ class Solution { } ``` +```csharp +public class Solution { + public List MajorityElement(int[] nums) { + Dictionary count = new Dictionary(); + + foreach (int num in nums) { + if (count.ContainsKey(num)) { + count[num]++; + } else { + count[num] = 1; + } + + if (count.Count <= 2) { + continue; + } + + Dictionary newCount = new Dictionary(); + foreach (var kvp in count) { + if (kvp.Value > 1) { + newCount[kvp.Key] = kvp.Value - 1; + } + } + count = newCount; + } + + List res = new List(); + foreach (int candidate in count.Keys) { + int freq = 0; + foreach (int num in nums) { + if (num == candidate) { + freq++; + } + } + if (freq > nums.Length / 3) { + res.Add(candidate); + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since output array size will be at most $2$. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since output array size will be at most $2$. diff --git a/articles/majority-element.md b/articles/majority-element.md index 9ac32df2c..c87bb8139 100644 --- a/articles/majority-element.md +++ b/articles/majority-element.md @@ -62,7 +62,10 @@ class Solution { majorityElement(nums) { let n = nums.length; for (let num of nums) { - let count = nums.reduce((acc, val) => acc + (val === num ? 1 : 0), 0); + let count = nums.reduce( + (acc, val) => acc + (val === num ? 1 : 0), + 0, + ); if (count > Math.floor(n / 2)) { return num; } @@ -72,12 +75,32 @@ class Solution { } ``` +```csharp +public class Solution { + public int MajorityElement(int[] nums) { + int n = nums.Length; + foreach (int num in nums) { + int count = 0; + foreach (int i in nums) { + if (i == num) { + count++; + } + } + if (count > n / 2) { + return num; + } + } + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -144,7 +167,8 @@ class Solution { */ majorityElement(nums) { const count = new Map(); - let res = 0, maxCount = 0; + let res = 0, + maxCount = 0; for (let num of nums) { count.set(num, (count.get(num) || 0) + 1); @@ -158,12 +182,35 @@ class Solution { } ``` +```csharp +public class Solution { + public int MajorityElement(int[] nums) { + Dictionary count = new Dictionary(); + int res = 0, maxCount = 0; + + foreach (int num in nums) { + if (!count.ContainsKey(num)) { + count[num] = 0; + } + count[num]++; + + if (count[num] > maxCount) { + res = num; + maxCount = count[num]; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -210,12 +257,21 @@ class Solution { } ``` +```csharp +public class Solution { + public int MajorityElement(int[] nums) { + Array.Sort(nums); + return nums[nums.Length / 2]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -231,11 +287,11 @@ class Solution: for num in nums: for i in range(32): bit[i] += ((num >> i) & 1) - + res = 0 for i in range(32): if bit[i] > (n // 2): - if i == 31: + if i == 31: res -= (1 << i) else: res |= (1 << i) @@ -305,9 +361,33 @@ class Solution { let res = 0; for (let i = 0; i < 32; i++) { if (bit[i] > Math.floor(n / 2)) { + res |= 1 << i; + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public int MajorityElement(int[] nums) { + int n = nums.Length; + int[] bit = new int[32]; + + foreach (int num in nums) { + for (int i = 0; i < 32; i++) { + bit[i] += (num >> i) & 1; + } + } + + int res = 0; + for (int i = 0; i < 32; i++) { + if (bit[i] > n / 2) { res |= (1 << i); } } + return res; } } @@ -317,8 +397,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * 32)$ -* Space complexity: $O(32)$ +- Time complexity: $O(n * 32)$ +- Space complexity: $O(32)$ > $32$ represents the number of bits as the given numbers are integers. @@ -380,14 +460,32 @@ class Solution { * @return {number} */ majorityElement(nums) { - let res = 0, count = 0; + let res = 0, + count = 0; for (let num of nums) { if (count === 0) { res = num; } - count += (num === res) ? 1 : -1; + count += num === res ? 1 : -1; + } + return res; + } +} +``` + +```csharp +public class Solution { + public int MajorityElement(int[] nums) { + int res = 0, count = 0; + + foreach (int num in nums) { + if (count == 0) { + res = num; + } + count += (num == res) ? 1 : -1; } + return res; } } @@ -397,8 +495,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -484,11 +582,30 @@ class Solution { } ``` +```csharp +public class Solution { + private static Random random = new Random(); + + public int MajorityElement(int[] nums) { + int n = nums.Length; + + while (true) { + int candidate = nums[random.Next(n)]; + int count = nums.Count(x => x == candidate); + + if (count > n / 2) { + return candidate; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ -> The probability of randomly choosing the majority element is greater than $50\%$, so the expected number of iterations in the outer while loop is constant. \ No newline at end of file +> The probability of randomly choosing the majority element is greater than $50\%$, so the expected number of iterations in the outer while loop is constant. diff --git a/articles/make-sum-divisible-by-p.md b/articles/make-sum-divisible-by-p.md new file mode 100644 index 000000000..921528010 --- /dev/null +++ b/articles/make-sum-divisible-by-p.md @@ -0,0 +1,235 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def minSubarray(self, nums: List[int], p: int) -> int: + n = len(nums) + totSum = sum(nums) + + if totSum % p == 0: + return 0 + + for l in range(1, n): + curSum = 0 + for i in range(n): + curSum += nums[i] + if i >= l: + curSum -= nums[i - l] + + remainSum = totSum - curSum + if remainSum % p == 0: + return l + + return -1 +``` + +```java +public class Solution { + public int minSubarray(int[] nums, int p) { + int n = nums.length; + long totSum = 0; + for (int num : nums) totSum += num; + + if (totSum % p == 0) return 0; + + for (int l = 1; l < n; l++) { + long curSum = 0; + for (int i = 0; i < n; i++) { + curSum += nums[i]; + if (i >= l) curSum -= nums[i - l]; + + long remainSum = totSum - curSum; + if (remainSum % p == 0) return l; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int minSubarray(vector& nums, int p) { + int n = nums.size(); + long long totSum = 0; + for (int num : nums) totSum += num; + + if (totSum % p == 0) return 0; + + for (int l = 1; l < n; l++) { + long long curSum = 0; + for (int i = 0; i < n; i++) { + curSum += nums[i]; + if (i >= l) curSum -= nums[i - l]; + + long long remainSum = totSum - curSum; + if (remainSum % p == 0) return l; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ + minSubarray(nums, p) { + const n = nums.length; + let totSum = nums.reduce((a, b) => a + b, 0); + + if (totSum % p === 0) return 0; + + for (let l = 1; l < n; l++) { + let curSum = 0; + for (let i = 0; i < n; i++) { + curSum += nums[i]; + if (i >= l) curSum -= nums[i - l]; + + const remainSum = totSum - curSum; + if (remainSum % p === 0) return l; + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Prefix Sum + +::tabs-start + +```python +class Solution: + def minSubarray(self, nums: List[int], p: int) -> int: + total = sum(nums) + remain = total % p + if remain == 0: + return 0 + + res = len(nums) + cur_sum = 0 + remain_to_idx = {0: -1} + + for i, n in enumerate(nums): + cur_sum = (cur_sum + n) % p + prefix = (cur_sum - remain + p) % p + if prefix in remain_to_idx: + length = i - remain_to_idx[prefix] + res = min(res, length) + remain_to_idx[cur_sum] = i + + return -1 if res == len(nums) else res +``` + +```java +public class Solution { + public int minSubarray(int[] nums, int p) { + long total = 0; + for (int num : nums) total += num; + int remain = (int)(total % p); + if (remain == 0) return 0; + + int res = nums.length; + long curSum = 0; + Map map = new HashMap<>(); + map.put(0, -1); + + for (int i = 0; i < nums.length; i++) { + curSum = (curSum + nums[i]) % p; + int prefix = (int)((curSum - remain + p) % p); + if (map.containsKey(prefix)) { + res = Math.min(res, i - map.get(prefix)); + } + map.put((int)curSum, i); + } + + return res == nums.length ? -1 : res; + } +} +``` + +```cpp +class Solution { +public: + int minSubarray(vector& nums, int p) { + long total = 0; + for (int num : nums) total += num; + int remain = total % p; + if (remain == 0) return 0; + + int res = nums.size(); + long curSum = 0; + unordered_map map; + map[0] = -1; + + for (int i = 0; i < nums.size(); i++) { + curSum = (curSum + nums[i]) % p; + int prefix = (curSum - remain + p) % p; + if (map.count(prefix)) { + res = min(res, i - map[prefix]); + } + map[curSum] = i; + } + + return res == nums.size() ? -1 : res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ + minSubarray(nums, p) { + let total = nums.reduce((a, b) => a + b, 0); + let remain = total % p; + if (remain === 0) return 0; + + let res = nums.length; + let curSum = 0; + const map = new Map(); + map.set(0, -1); + + for (let i = 0; i < nums.length; i++) { + curSum = (curSum + nums[i]) % p; + let prefix = (curSum - remain + p) % p; + if (map.has(prefix)) { + res = Math.min(res, i - map.get(prefix)); + } + map.set(curSum, i); + } + + return res === nums.length ? -1 : res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/make-the-string-great.md b/articles/make-the-string-great.md new file mode 100644 index 000000000..74e991df2 --- /dev/null +++ b/articles/make-the-string-great.md @@ -0,0 +1,348 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def makeGood(self, s: str) -> str: + n = len(s) + i = 0 + while i < n: + if i and s[i] != s[i - 1] and s[i].lower() == s[i - 1].lower(): + s = s[:i - 1] + s[i + 1:] + n -= 2 + i -= 2 + i += 1 + return s +``` + +```java +public class Solution { + public String makeGood(String s) { + int n = s.length(); + int i = 0; + while (i < n) { + if (i > 0 && s.charAt(i) != s.charAt(i - 1) && + Character.toLowerCase(s.charAt(i)) == Character.toLowerCase(s.charAt(i - 1))) { + s = s.substring(0, i - 1) + s.substring(i + 1); + n -= 2; + i -= 2; + } + i++; + } + return s; + } +} +``` + +```cpp +class Solution { +public: + string makeGood(string s) { + int n = s.length(); + int i = 0; + while (i < n) { + if (i > 0 && s[i] != s[i - 1] && tolower(s[i]) == tolower(s[i - 1])) { + s = s.substr(0, i - 1) + s.substr(i + 1); + n -= 2; + i -= 2; + } + i++; + } + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + makeGood(s) { + let n = s.length; + let i = 0; + while (i < n) { + if ( + i > 0 && + s[i] !== s[i - 1] && + s[i].toLowerCase() === s[i - 1].toLowerCase() + ) { + s = s.slice(0, i - 1) + s.slice(i + 1); + n -= 2; + i -= 2; + } + i++; + } + return s; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 2. Stack - I + +::tabs-start + +```python +class Solution: + def makeGood(self, s: str) -> str: + def lower(c): + if ord(c) < ord('a'): + return chr(ord('a') + ord(c) - ord('A')) + return c + + stack = [] + i = 0 + while i < len(s): + if stack and stack[-1] != s[i] and lower(stack[-1]) == lower(s[i]): + stack.pop() + else: + stack.append(s[i]) + i += 1 + return "".join(stack) +``` + +```java +public class Solution { + public String makeGood(String s) { + StringBuilder stack = new StringBuilder(); + for (char c : s.toCharArray()) { + if (stack.length() > 0 && stack.charAt(stack.length() - 1) != c && + Character.toLowerCase(stack.charAt(stack.length() - 1)) == Character.toLowerCase(c)) { + stack.deleteCharAt(stack.length() - 1); + } else { + stack.append(c); + } + } + return stack.toString(); + } +} +``` + +```cpp +class Solution { +public: + string makeGood(string s) { + string stack; + for (char c : s) { + if (!stack.empty() && stack.back() != c && + tolower(stack.back()) == tolower(c)) { + stack.pop_back(); + } else { + stack.push_back(c); + } + } + return stack; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + makeGood(s) { + const stack = []; + for (const c of s) { + if ( + stack.length > 0 && + stack[stack.length - 1] !== c && + stack[stack.length - 1].toLowerCase() === c.toLowerCase() + ) { + stack.pop(); + } else { + stack.push(c); + } + } + return stack.join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Stack - II + +::tabs-start + +```python +class Solution: + def makeGood(self, s: str) -> str: + stack = [] + for i in range(len(s)): + if stack and abs(ord(s[i]) - ord(stack[-1])) == 32: + stack.pop() + else: + stack.append(s[i]) + return "".join(stack) +``` + +```java +public class Solution { + public String makeGood(String s) { + StringBuilder stack = new StringBuilder(); + for (int i = 0; i < s.length(); i++) { + if (stack.length() > 0 && + Math.abs(stack.charAt(stack.length() - 1) - s.charAt(i)) == 32) { + stack.deleteCharAt(stack.length() - 1); + } else { + stack.append(s.charAt(i)); + } + } + return stack.toString(); + } +} +``` + +```cpp +class Solution { +public: + string makeGood(string s) { + string stack; + for (char& c : s) { + if (!stack.empty() && abs(stack.back() - c) == 32) { + stack.pop_back(); + } else { + stack.push_back(c); + } + } + return stack; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + makeGood(s) { + const stack = []; + for (const c of s) { + if ( + stack.length > 0 && + Math.abs( + stack[stack.length - 1].charCodeAt(0) - c.charCodeAt(0), + ) === 32 + ) { + stack.pop(); + } else { + stack.push(c); + } + } + return stack.join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Two Pointers + +::tabs-start + +```python +class Solution: + def makeGood(self, s: str) -> str: + l = 0 + s = list(s) + for r in range(len(s)): + if l > 0 and abs(ord(s[r]) - ord(s[l - 1])) == 32: + l -= 1 + else: + s[l] = s[r] + l += 1 + return ''.join(s[:l]) +``` + +```java +public class Solution { + public String makeGood(String s) { + int l = 0; + char[] arr = s.toCharArray(); + for (int r = 0; r < arr.length; r++) { + if (l > 0 && Math.abs(arr[r] - arr[l - 1]) == 32) { + l--; + } else { + arr[l++] = arr[r]; + } + } + return new String(arr, 0, l); + } +} +``` + +```cpp +class Solution { +public: + string makeGood(string s) { + int l = 0; + for (int r = 0; r < s.length(); r++) { + if (l > 0 && abs(s[r] - s[l - 1]) == 32) { + l--; + } else { + s[l++] = s[r]; + } + } + return s.substr(0, l); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + makeGood(s) { + let l = 0; + let arr = s.split(''); + for (let r = 0; r < arr.length; r++) { + if ( + l > 0 && + Math.abs(arr[r].charCodeAt(0) - arr[l - 1].charCodeAt(0)) === 32 + ) { + l--; + } else { + arr[l++] = arr[r]; + } + } + return arr.slice(0, l).join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the language. diff --git a/articles/matchsticks-to-square.md b/articles/matchsticks-to-square.md index c05819570..91cb7ede0 100644 --- a/articles/matchsticks-to-square.md +++ b/articles/matchsticks-to-square.md @@ -7,21 +7,21 @@ class Solution: def makesquare(self, matchsticks: List[int]) -> bool: if sum(matchsticks) % 4 != 0: return False - + sides = [0] * 4 - + def dfs(i): if i == len(matchsticks): return sides[0] == sides[1] == sides[2] == sides[3] - + for side in range(4): sides[side] += matchsticks[i] if dfs(i + 1): return True sides[side] -= matchsticks[i] - + return False - + return dfs(0) ``` @@ -92,7 +92,11 @@ class Solution { const sides = Array(4).fill(0); const dfs = (i) => { if (i === matchsticks.length) { - return sides[0] === sides[1] && sides[1] === sides[2] && sides[2] === sides[3]; + return ( + sides[0] === sides[1] && + sides[1] === sides[2] && + sides[2] === sides[3] + ); } for (let j = 0; j < 4; j++) { @@ -109,12 +113,45 @@ class Solution { } ``` +```csharp +public class Solution { + public bool Makesquare(int[] matchsticks) { + int total = 0; + foreach (int stick in matchsticks) { + total += stick; + } + if (total % 4 != 0) return false; + + int target = total / 4; + int[] sides = new int[4]; + + bool Dfs(int i) { + if (i == matchsticks.Length) { + return sides[0] == sides[1] && sides[1] == sides[2] && sides[2] == sides[3]; + } + + for (int side = 0; side < 4; side++) { + sides[side] += matchsticks[i]; + if (sides[side] <= target && Dfs(i + 1)) { + return true; + } + sides[side] -= matchsticks[i]; + } + + return false; + } + + return Dfs(0); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(4 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(4 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -128,27 +165,27 @@ class Solution: total_length = sum(matchsticks) if total_length % 4 != 0: return False - + length = total_length // 4 sides = [0] * 4 matchsticks.sort(reverse=True) - + def dfs(i): if i == len(matchsticks): return True - + for side in range(4): if sides[side] + matchsticks[i] <= length: sides[side] += matchsticks[i] if dfs(i + 1): return True sides[side] -= matchsticks[i] - + if sides[side] == 0: break - + return False - + return dfs(0) ``` @@ -157,33 +194,33 @@ public class Solution { public boolean makesquare(int[] matchsticks) { int totalLength = Arrays.stream(matchsticks).sum(); if (totalLength % 4 != 0) return false; - + int length = totalLength / 4; int[] sides = new int[4]; Arrays.sort(matchsticks); reverse(matchsticks); - + return dfs(matchsticks, sides, 0, length); } - + private boolean dfs(int[] matchsticks, int[] sides, int index, int length) { if (index == matchsticks.length) { return true; } - + for (int i = 0; i < 4; i++) { if (sides[i] + matchsticks[index] <= length) { sides[i] += matchsticks[index]; if (dfs(matchsticks, sides, index + 1, length)) return true; sides[i] -= matchsticks[index]; } - + if (sides[i] == 0) break; } - + return false; } - + private void reverse(int[] matchsticks) { for (int i = 0, j = matchsticks.length - 1; i < j; i++, j--) { int temp = matchsticks[i]; @@ -266,12 +303,51 @@ class Solution { } ``` +```csharp +public class Solution { + public bool Makesquare(int[] matchsticks) { + int totalLength = 0; + foreach (int stick in matchsticks) { + totalLength += stick; + } + + if (totalLength % 4 != 0) { + return false; + } + + int length = totalLength / 4; + int[] sides = new int[4]; + Array.Sort(matchsticks, (a, b) => b.CompareTo(a)); // Sort in descending order + + bool Dfs(int i) { + if (i == matchsticks.Length) { + return true; + } + + for (int side = 0; side < 4; side++) { + if (sides[side] + matchsticks[i] <= length) { + sides[side] += matchsticks[i]; + if (Dfs(i + 1)) return true; + sides[side] -= matchsticks[i]; + } + + if (sides[side] == 0) break; + } + + return false; + } + + return Dfs(0); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(4 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(4 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -285,11 +361,11 @@ class Solution: total_length = sum(matchsticks) if total_length % 4 != 0: return False - + length = total_length // 4 if max(matchsticks) > length: return False - + n = len(matchsticks) dp = [float("-inf")] * (1 << n) matchsticks.sort(reverse=True) @@ -299,7 +375,7 @@ class Solution: return 0 if dp[mask] != float("-inf"): return dp[mask] - + for i in range(n): if mask & (1 << i): res = dfs(mask ^ (1 << i)) @@ -309,10 +385,10 @@ class Solution: if mask == (1 << n) - 1: dp[mask] = -1 return -1 - + dp[mask] = -1 return -1 - + return not dfs((1 << n) - 1) ``` @@ -387,7 +463,7 @@ public: if (*max_element(matchsticks.begin(), matchsticks.end()) > length) { return false; } - + sort(matchsticks.rbegin(), matchsticks.rend()); n = matchsticks.size(); dp.resize(1 << n, INT_MIN); @@ -466,9 +542,49 @@ class Solution { } ``` +```csharp +public class Solution { + public bool Makesquare(int[] matchsticks) { + int totalLength = matchsticks.Sum(); + if (totalLength % 4 != 0) return false; + + int length = totalLength / 4; + if (matchsticks.Max() > length) return false; + + int n = matchsticks.Length; + int[] dp = Enumerable.Repeat(int.MinValue, 1 << n).ToArray(); + Array.Sort(matchsticks, (a, b) => b.CompareTo(a)); // Sort descending + + int Dfs(int mask) { + if (mask == 0) return 0; + if (dp[mask] != int.MinValue) return dp[mask]; + + for (int i = 0; i < n; i++) { + if ((mask & (1 << i)) != 0) { + int res = Dfs(mask ^ (1 << i)); + if (res >= 0 && res + matchsticks[i] <= length) { + dp[mask] = (res + matchsticks[i]) % length; + return dp[mask]; + } + if (mask == (1 << n) - 1) { + dp[mask] = -1; + return -1; + } + } + } + + dp[mask] = -1; + return -1; + } + + return Dfs((1 << n) - 1) != -1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n + 2 ^ n)$ \ No newline at end of file +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: $O(n + 2 ^ n)$ diff --git a/articles/matrix-diagonal-sum.md b/articles/matrix-diagonal-sum.md new file mode 100644 index 000000000..122fe8286 --- /dev/null +++ b/articles/matrix-diagonal-sum.md @@ -0,0 +1,238 @@ +## 1. Iteration + +::tabs-start + +```python +class Solution: + def diagonalSum(self, mat: List[List[int]]) -> int: + n = len(mat) + + def helper(matrix): + res = 0 + for i in range(n): + for j in range(n): + if i == j: + res += matrix[i][j] + matrix[i].reverse() + return res + + return helper(mat) + helper(mat) - (mat[n // 2][n // 2] if n & 1 else 0) +``` + +```java +public class Solution { + public int diagonalSum(int[][] mat) { + int n = mat.length; + return helper(mat) + helper(mat) - (n % 2 == 1 ? mat[n / 2][n / 2] : 0); + } + + int helper(int[][] matrix) { + int res = 0, n = matrix.length; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (i == j) { + res += matrix[i][j]; + } + } + reverse(matrix[i]); + } + return res; + } + + void reverse(int[] row) { + int left = 0, right = row.length - 1; + while (left < right) { + int temp = row[left]; + row[left++] = row[right]; + row[right--] = temp; + } + } +} +``` + +```cpp +class Solution { +public: + int diagonalSum(vector>& mat) { + int n = mat.size(); + return helper(mat) + helper(mat) - (n % 2 == 1 ? mat[n / 2][n / 2] : 0); + } + +private: + int helper(vector>& matrix) { + int res = 0, n = matrix.size(); + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (i == j) { + res += matrix[i][j]; + } + } + reverse(matrix[i].begin(), matrix[i].end()); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} mat + * @return {number} + */ + diagonalSum(mat) { + const n = mat.length; + + const helper = (matrix) => { + let res = 0; + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if (i === j) { + res += matrix[i][j]; + } + } + matrix[i].reverse(); + } + return res; + }; + + return ( + helper(mat) + + helper(mat) - + (n % 2 === 1 ? mat[Math.floor(n / 2)][Math.floor(n / 2)] : 0) + ); + } +} +``` + +```csharp +public class Solution { + public int DiagonalSum(int[][] mat) { + int n = mat.Length; + + int Helper(int[][] matrix) { + int res = 0; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (i == j) { + res += matrix[i][j]; + } + } + Array.Reverse(matrix[i]); + } + return res; + } + + int sum = Helper(mat) + Helper(mat); + if ((n & 1) == 1) { + sum -= mat[n / 2][n / 2]; + } + return sum; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 2. Iteration (Optimal) + +::tabs-start + +```python +class Solution: + def diagonalSum(self, mat: List[List[int]]) -> int: + res, n = 0, len(mat) + + for r in range(n): + res += mat[r][r] + res += mat[r][n - r - 1] + + return res - (mat[n // 2][n // 2] if n & 1 else 0) +``` + +```java +public class Solution { + public int diagonalSum(int[][] mat) { + int res = 0, n = mat.length; + + for (int r = 0; r < n; r++) { + res += mat[r][r]; + res += mat[r][n - r - 1]; + } + + return res - (n % 2 == 1 ? mat[n / 2][n / 2] : 0); + } +} +``` + +```cpp +class Solution { +public: + int diagonalSum(vector>& mat) { + int res = 0, n = mat.size(); + + for (int r = 0; r < n; r++) { + res += mat[r][r]; + res += mat[r][n - r - 1]; + } + + return res - (n % 2 == 1 ? mat[n / 2][n / 2] : 0); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} mat + * @return {number} + */ + diagonalSum(mat) { + let res = 0, + n = mat.length; + + for (let r = 0; r < n; r++) { + res += mat[r][r]; + res += mat[r][n - r - 1]; + } + + return ( + res - (n % 2 == 1 ? mat[Math.floor(n / 2)][Math.floor(n / 2)] : 0) + ); + } +} +``` + +```csharp +public class Solution { + public int DiagonalSum(int[][] mat) { + int res = 0; + int n = mat.Length; + + for (int r = 0; r < n; r++) { + res += mat[r][r]; + res += mat[r][n - r - 1]; + } + + if ((n & 1) == 1) { + res -= mat[n / 2][n / 2]; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/max-area-of-island.md b/articles/max-area-of-island.md index 22f9f8b53..b9d0e944f 100644 --- a/articles/max-area-of-island.md +++ b/articles/max-area-of-island.md @@ -15,9 +15,9 @@ class Solution: ): return 0 visit.add((r, c)) - return (1 + dfs(r + 1, c) + - dfs(r - 1, c) + - dfs(r, c + 1) + + return (1 + dfs(r + 1, c) + + dfs(r - 1, c) + + dfs(r, c + 1) + dfs(r, c - 1)) area = 0 @@ -29,13 +29,13 @@ class Solution: ```java public class Solution { - private static final int[][] directions = {{1, 0}, {-1, 0}, + private static final int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; - + public int maxAreaOfIsland(int[][] grid) { int ROWS = grid.length, COLS = grid[0].length; int area = 0; - + for (int r = 0; r < ROWS; r++) { for (int c = 0; c < COLS; c++) { if (grid[r][c] == 1) { @@ -43,16 +43,16 @@ public class Solution { } } } - + return area; } - + private int dfs(int[][] grid, int r, int c) { - if (r < 0 || c < 0 || r >= grid.length || + if (r < 0 || c < 0 || r >= grid.length || c >= grid[0].length || grid[r][c] == 0) { return 0; } - + grid[r][c] = 0; int res = 1; for (int[] dir : directions) { @@ -78,20 +78,20 @@ public: } } } - + return area; } - + int dfs(vector>& grid, int r, int c) { - if (r < 0 || c < 0 || r >= grid.size() || + if (r < 0 || c < 0 || r >= grid.size() || c >= grid[0].size() || grid[r][c] == 0) { return 0; } - + grid[r][c] = 0; int res = 1; for (int i = 0; i < 4; i++) { - res += dfs(grid, r + directions[i][0], + res += dfs(grid, r + directions[i][0], c + directions[i][1]); } return res; @@ -106,13 +106,19 @@ class Solution { * @return {number} */ maxAreaOfIsland(grid) { - const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; - const ROWS = grid.length, COLS = grid[0].length; + const directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; + const ROWS = grid.length, + COLS = grid[0].length; const dfs = (r, c) => { - if (r < 0 || c < 0 || r >= ROWS || - c >= COLS || grid[r][c] === 0) return 0; - + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] === 0) + return 0; + grid[r][c] = 0; let res = 1; for (const [dr, dc] of directions) { @@ -138,10 +144,10 @@ class Solution { ```csharp public class Solution { private static readonly int[][] directions = new int[][] { - new int[] {1, 0}, new int[] {-1, 0}, + new int[] {1, 0}, new int[] {-1, 0}, new int[] {0, 1}, new int[] {0, -1} }; - + public int MaxAreaOfIsland(int[][] grid) { int ROWS = grid.Length, COLS = grid[0].Length; int area = 0; @@ -158,7 +164,7 @@ public class Solution { } private int Dfs(int[][] grid, int r, int c) { - if (r < 0 || c < 0 || r >= grid.Length || + if (r < 0 || c < 0 || r >= grid.Length || c >= grid[0].Length || grid[r][c] == 0) { return 0; } @@ -180,7 +186,7 @@ func maxAreaOfIsland(grid [][]int) int { var dfs func(r, c int) int dfs = func(r, c int) int { - if r < 0 || r >= rows || c < 0 || c >= cols || + if r < 0 || r >= rows || c < 0 || c >= cols || grid[r][c] == 0 || visit[[2]int{r, c}] { return 0 } @@ -213,7 +219,7 @@ class Solution { val visit = HashSet>() fun dfs(r: Int, c: Int): Int { - if (r < 0 || r >= rows || c < 0 || c >= cols || + if (r < 0 || r >= rows || c < 0 || c >= cols || grid[r][c] == 0 || visit.contains(r to c)) { return 0 } @@ -232,12 +238,40 @@ class Solution { } ``` +```swift +class Solution { + func maxAreaOfIsland(_ grid: [[Int]]) -> Int { + let ROWS = grid.count + let COLS = grid[0].count + var visit = Set<[Int]>() + var grid = grid + + func dfs(_ r: Int, _ c: Int) -> Int { + if (r < 0 || r == ROWS || c < 0 || c == COLS || + grid[r][c] == 0 || visit.contains([r, c])) { + return 0 + } + visit.insert([r, c]) + return 1 + dfs(r + 1, c) + dfs(r - 1, c) + dfs(r, c + 1) + dfs(r, c - 1) + } + + var area = 0 + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. @@ -261,7 +295,7 @@ class Solution: res = 1 while q: - row, col = q.popleft() + row, col = q.popleft() for dr, dc in directions: nr, nc = dr + row, dc + col if (nr < 0 or nc < 0 or nr >= ROWS or @@ -283,13 +317,13 @@ class Solution: ```java public class Solution { - private static final int[][] directions = {{1, 0}, {-1, 0}, + private static final int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; - + public int maxAreaOfIsland(int[][] grid) { int ROWS = grid.length, COLS = grid[0].length; int area = 0; - + for (int r = 0; r < ROWS; r++) { for (int c = 0; c < COLS; c++) { if (grid[r][c] == 1) { @@ -297,10 +331,10 @@ public class Solution { } } } - + return area; } - + private int bfs(int[][] grid, int r, int c) { Queue q = new LinkedList<>(); grid[r][c] = 0; @@ -310,10 +344,10 @@ public class Solution { while (!q.isEmpty()) { int[] node = q.poll(); int row = node[0], col = node[1]; - + for (int[] dir : directions) { int nr = row + dir[0], nc = col + dir[1]; - if (nr >= 0 && nc >= 0 && nr < grid.length && + if (nr >= 0 && nc >= 0 && nr < grid.length && nc < grid[0].length && grid[nr][nc] == 1) { q.add(new int[]{nr, nc}); grid[nr][nc] = 0; @@ -328,7 +362,7 @@ public class Solution { ```cpp class Solution { - int directions[4][2] = {{1, 0}, {-1, 0}, + int directions[4][2] = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; public: int maxAreaOfIsland(vector>& grid) { @@ -358,7 +392,7 @@ public: for (int i = 0; i < 4; i++) { int nr = row + directions[i][0]; int nc = col + directions[i][1]; - if (nr >= 0 && nc >= 0 && nr < grid.size() && + if (nr >= 0 && nc >= 0 && nr < grid.size() && nc < grid[0].size() && grid[nr][nc] == 1) { q.push({nr, nc}); grid[nr][nc] = 0; @@ -378,8 +412,14 @@ class Solution { * @return {number} */ maxAreaOfIsland(grid) { - const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; - const ROWS = grid.length, COLS = grid[0].length; + const directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; + const ROWS = grid.length, + COLS = grid[0].length; let area = 0; const bfs = (r, c) => { @@ -387,13 +427,19 @@ class Solution { q.push([r, c]); grid[r][c] = 0; let res = 1; - + while (!q.isEmpty()) { const [row, col] = q.pop(); for (const [dr, dc] of directions) { - const nr = row + dr, nc = col + dc; - if (nr >= 0 && nc >= 0 && nr < ROWS && - nc < COLS && grid[nr][nc] === 1) { + const nr = row + dr, + nc = col + dc; + if ( + nr >= 0 && + nc >= 0 && + nr < ROWS && + nc < COLS && + grid[nr][nc] === 1 + ) { q.push([nr, nc]); grid[nr][nc] = 0; res++; @@ -419,7 +465,7 @@ class Solution { ```csharp public class Solution { private static readonly int[][] directions = new int[][] { - new int[] {1, 0}, new int[] {-1, 0}, + new int[] {1, 0}, new int[] {-1, 0}, new int[] {0, 1}, new int[] {0, -1} }; @@ -450,7 +496,7 @@ public class Solution { foreach (var dir in directions) { int nr = row + dir[0], nc = col + dir[1]; - if (nr >= 0 && nc >= 0 && nr < grid.Length && + if (nr >= 0 && nc >= 0 && nr < grid.Length && nc < grid[0].Length && grid[nr][nc] == 1) { q.Enqueue(new int[] { nr, nc }); grid[nr][nc] = 0; @@ -481,7 +527,7 @@ func maxAreaOfIsland(grid [][]int) int { row, col := front[0], front[1] for _, dir := range directions { nr, nc := row+dir[0], col+dir[1] - if nr < 0 || nc < 0 || nr >= rows || + if nr < 0 || nc < 0 || nr >= rows || nc >= cols || grid[nr][nc] == 0 { continue } @@ -514,41 +560,41 @@ func max(a, b int) int { ```kotlin class Solution { fun maxAreaOfIsland(grid: Array): Int { - val directions = arrayOf(intArrayOf(1, 0), - intArrayOf(-1, 0), - intArrayOf(0, 1), + val directions = arrayOf(intArrayOf(1, 0), + intArrayOf(-1, 0), + intArrayOf(0, 1), intArrayOf(0, -1)) val rows = grid.size val cols = grid[0].size var area = 0 - + fun bfs(r: Int, c: Int): Int { val queue = ArrayDeque>() grid[r][c] = 0 queue.add(Pair(r, c)) var res = 1 - + while (queue.isNotEmpty()) { val (row, col) = queue.removeFirst() - + for ((dr, dc) in directions) { val nr = dr + row val nc = dc + col - - if (nr < 0 || nc < 0 || nr >= rows || + + if (nr < 0 || nc < 0 || nr >= rows || nc >= cols || grid[nr][nc] == 0) { continue } - + queue.add(Pair(nr, nc)) grid[nr][nc] = 0 res++ } } - + return res } - + for (r in 0 until rows) { for (c in 0 until cols) { if (grid[r][c] == 1) { @@ -556,7 +602,51 @@ class Solution { } } } - + + return area + } +} +``` + +```swift +class Solution { + func maxAreaOfIsland(_ grid: [[Int]]) -> Int { + let directions = [[1, 0], [-1, 0], [0, 1], [0, -1]] + let ROWS = grid.count + let COLS = grid[0].count + var grid = grid + var area = 0 + + func bfs(_ r: Int, _ c: Int) -> Int { + var queue = Deque<(Int, Int)>() + grid[r][c] = 0 + queue.append((r, c)) + var res = 1 + + while !queue.isEmpty { + let (row, col) = queue.popFirst()! + for dir in directions { + let nr = row + dir[0] + let nc = col + dir[1] + if nr < 0 || nc < 0 || nr >= ROWS || nc >= COLS || grid[nr][nc] == 0 { + continue + } + queue.append((nr, nc)) + grid[nr][nc] = 0 + res += 1 + } + } + return res + } + + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. @@ -600,7 +690,7 @@ class DSU: self.Size[pv] += self.Size[pu] self.Parent[pu] = pv return True - + def getSize(self, node): par = self.find(node) return self.Size[par] @@ -625,7 +715,7 @@ class Solution: nc >= COLS or grid[nr][nc] == 0 ): continue - + dsu.union(index(r, c), index(nr, nc)) area = max(area, dsu.getSize(index(r, c))) @@ -634,7 +724,7 @@ class Solution: ``` ```java -public class DSU { +class DSU { private int[] Parent, Size; public DSU(int n) { @@ -687,7 +777,7 @@ public class Solution { for (int[] d : directions) { int nr = r + d[0]; int nc = c + d[1]; - if (nr >= 0 && nc >= 0 && nr < ROWS && + if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS && grid[nr][nc] == 1) { dsu.union(r * COLS + c, nr * COLS + nc); } @@ -761,7 +851,7 @@ public: for (auto& d : directions) { int nr = r + d[0]; int nc = c + d[1]; - if (nr >= 0 && nc >= 0 && nr < ROWS && + if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS && grid[nr][nc] == 1) { dsu.unionBySize(index(r, c), index(nr, nc)); } @@ -779,7 +869,9 @@ public: ```javascript class DSU { constructor(n) { - this.Parent = Array(n + 1).fill(0).map((_, i) => i); + this.Parent = Array(n + 1) + .fill(0) + .map((_, i) => i); this.Size = Array(n + 1).fill(1); } @@ -833,7 +925,10 @@ class Solution { const dsu = new DSU(ROWS * COLS); const directions = [ - [1, 0], [-1, 0], [0, 1], [0, -1] + [1, 0], + [-1, 0], + [0, 1], + [0, -1], ]; let area = 0; @@ -843,9 +938,15 @@ class Solution { for (let c = 0; c < COLS; c++) { if (grid[r][c] === 1) { for (let [dr, dc] of directions) { - let nr = r + dr, nc = c + dc; - if (nr >= 0 && nc >= 0 && nr < ROWS && - nc < COLS && grid[nr][nc] === 1) { + let nr = r + dr, + nc = c + dc; + if ( + nr >= 0 && + nc >= 0 && + nr < ROWS && + nc < COLS && + grid[nr][nc] === 1 + ) { dsu.union(index(r, c), index(nr, nc)); } } @@ -905,7 +1006,7 @@ public class Solution { DSU dsu = new DSU(ROWS * COLS); int[][] directions = new int[][] { - new int[] { 1, 0 }, new int[] { -1, 0 }, + new int[] { 1, 0 }, new int[] { -1, 0 }, new int[] { 0, 1 }, new int[] { 0, -1 } }; int area = 0; @@ -916,7 +1017,7 @@ public class Solution { foreach (var d in directions) { int nr = r + d[0]; int nc = c + d[1]; - if (nr >= 0 && nc >= 0 && nr < ROWS && + if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS && grid[nr][nc] == 1) { dsu.Union(r * COLS + c, nr * COLS + nc); } @@ -989,7 +1090,7 @@ func maxAreaOfIsland(grid [][]int) int { if grid[r][c] == 1 { for _, dir := range directions { nr, nc := r+dir[0], c+dir[1] - if nr < 0 || nc < 0 || nr >= rows || + if nr < 0 || nc < 0 || nr >= rows || nc >= cols || grid[nr][nc] == 0 { continue } @@ -1066,7 +1167,7 @@ class Solution { for (dir in directions) { val nr = r + dir[0] val nc = c + dir[1] - if (nr < 0 || nc < 0 || nr >= rows || + if (nr < 0 || nc < 0 || nr >= rows || nc >= cols || grid[nr][nc] == 0) { continue } @@ -1081,11 +1182,85 @@ class Solution { } ``` +```swift +class DSU { + private var parent: [Int] + private var size: [Int] + + init(_ n: Int) { + parent = Array(0...n) + size = Array(repeating: 1, count: n + 1) + } + + func find(_ node: Int) -> Int { + if parent[node] != node { + parent[node] = find(parent[node]) + } + return parent[node] + } + + func union(_ u: Int, _ v: Int) -> Bool { + let pu = find(u) + let pv = find(v) + if pu == pv { + return false + } + if size[pu] >= size[pv] { + size[pu] += size[pv] + parent[pv] = pu + } else { + size[pv] += size[pu] + parent[pu] = pv + } + return true + } + + func getSize(_ node: Int) -> Int { + let par = find(node) + return size[par] + } +} + +class Solution { + func maxAreaOfIsland(_ grid: [[Int]]) -> Int { + var grid = grid + let ROWS = grid.count + let COLS = grid[0].count + let dsu = DSU(ROWS * COLS) + + func index(_ r: Int, _ c: Int) -> Int { + return r * COLS + c + } + + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + var area = 0 + + for r in 0..= ROWS || nc >= COLS || grid[nr][nc] == 0 { + continue + } + dsu.union(index(r, c), index(nr, nc)) + } + area = max(area, dsu.getSize(index(r, c))) + } + } + } + + return area + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ -> Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. diff --git a/articles/max-consecutive-ones-iii.md b/articles/max-consecutive-ones-iii.md new file mode 100644 index 000000000..3e990f84b --- /dev/null +++ b/articles/max-consecutive-ones-iii.md @@ -0,0 +1,355 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def longestOnes(self, nums: List[int], k: int) -> int: + res = 0 + for l in range(len(nums)): + cnt, r = 0, l + while r < len(nums): + if nums[r] == 0: + if cnt == k: + break + cnt += 1 + r += 1 + res = max(res, r - l) + return res +``` + +```java +public class Solution { + public int longestOnes(int[] nums, int k) { + int res = 0; + for (int l = 0; l < nums.length; l++) { + int cnt = 0, r = l; + while (r < nums.length) { + if (nums[r] == 0) { + if (cnt == k) break; + cnt++; + } + r++; + } + res = Math.max(res, r - l); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestOnes(vector& nums, int k) { + int res = 0; + for (int l = 0; l < nums.size(); l++) { + int cnt = 0, r = l; + while (r < nums.size()) { + if (nums[r] == 0) { + if (cnt == k) break; + cnt++; + } + r++; + } + res = max(res, r - l); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + longestOnes(nums, k) { + let res = 0; + for (let l = 0; l < nums.length; l++) { + let cnt = 0, r = l; + while (r < nums.length) { + if (nums[r] === 0) { + if (cnt === k) break; + cnt++; + } + r++; + } + res = Math.max(res, r - l); + } + return res; + } +} +``` + +```csharp +public class Solution { + public int LongestOnes(int[] nums, int k) { + int res = 0; + for (int l = 0; l < nums.Length; l++) { + int cnt = 0, r = l; + while (r < nums.Length) { + if (nums[r] == 0) { + if (cnt == k) break; + cnt++; + } + r++; + } + res = Math.Max(res, r - l); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Binary Search + Prefix Sum + +::tabs-start + +```python +class Solution: + def longestOnes(self, nums: List[int], k: int) -> int: + prefix = [0] + for num in nums: + prefix.append(prefix[-1] + (1 if num == 0 else 0)) + + res = 0 + for l in range(len(nums)): + low, high = l, len(nums) + while low < high: + mid = (low + high) // 2 + if prefix[mid + 1] - prefix[l] <= k: + low = mid + 1 + else: + high = mid + res = max(res, low - l) + return res +``` + +```java +public class Solution { + public int longestOnes(int[] nums, int k) { + int[] prefix = new int[nums.length + 1]; + for (int i = 0; i < nums.length; i++) { + prefix[i + 1] = prefix[i] + (nums[i] == 0 ? 1 : 0); + } + + int res = 0; + for (int l = 0; l < nums.length; l++) { + int low = l, high = nums.length; + while (low < high) { + int mid = (low + high) / 2; + if (prefix[mid + 1] - prefix[l] <= k) { + low = mid + 1; + } else { + high = mid; + } + } + res = Math.max(res, low - l); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestOnes(vector& nums, int k) { + vector prefix(nums.size() + 1, 0); + for (int i = 0; i < nums.size(); ++i) { + prefix[i + 1] = prefix[i] + (nums[i] == 0 ? 1 : 0); + } + + int res = 0; + for (int l = 0; l < nums.size(); ++l) { + int low = l, high = nums.size(); + while (low < high) { + int mid = (low + high) / 2; + if (prefix[mid + 1] - prefix[l] <= k) { + low = mid + 1; + } else { + high = mid; + } + } + res = max(res, low - l); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + longestOnes(nums, k) { + const prefix = [0]; + for (let i = 0; i < nums.length; i++) { + prefix.push(prefix[prefix.length - 1] + (nums[i] === 0 ? 1 : 0)); + } + + let res = 0; + for (let l = 0; l < nums.length; l++) { + let low = l, high = nums.length; + while (low < high) { + let mid = Math.floor((low + high) / 2); + if (prefix[mid + 1] - prefix[l] <= k) { + low = mid + 1; + } else { + high = mid; + } + } + res = Math.max(res, low - l); + } + return res; + } +} +``` + +```csharp +public class Solution { + public int LongestOnes(int[] nums, int k) { + int[] prefix = new int[nums.Length + 1]; + for (int i = 0; i < nums.Length; i++) { + prefix[i + 1] = prefix[i] + (nums[i] == 0 ? 1 : 0); + } + + int res = 0; + for (int l = 0; l < nums.Length; l++) { + int low = l, high = nums.Length; + while (low < high) { + int mid = (low + high) / 2; + if (prefix[mid + 1] - prefix[l] <= k) { + low = mid + 1; + } else { + high = mid; + } + } + res = Math.Max(res, low - l); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Sliding Window + +::tabs-start + +```python +class Solution: + def longestOnes(self, nums: List[int], k: int) -> int: + l = res = 0 + for r in range(len(nums)): + k -= (1 if nums[r] == 0 else 0) + while k < 0: + k += (1 if nums[l] == 0 else 0) + l += 1 + res = max(res, r - l + 1) + return res +``` + +```java +public class Solution { + public int longestOnes(int[] nums, int k) { + int l = 0, res = 0; + for (int r = 0; r < nums.length; r++) { + k -= (nums[r] == 0 ? 1 : 0); + while (k < 0) { + k += (nums[l] == 0 ? 1 : 0); + l++; + } + res = Math.max(res, r - l + 1); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int longestOnes(vector& nums, int k) { + int l = 0, res = 0; + for (int r = 0; r < nums.size(); ++r) { + k -= (nums[r] == 0 ? 1 : 0); + while (k < 0) { + k += (nums[l] == 0 ? 1 : 0); + ++l; + } + res = max(res, r - l + 1); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + longestOnes(nums, k) { + let l = 0, res = 0; + for (let r = 0; r < nums.length; r++) { + k -= (nums[r] === 0 ? 1 : 0); + while (k < 0) { + k += (nums[l] === 0 ? 1 : 0); + l++; + } + res = Math.max(res, r - l + 1); + } + return res; + } +} +``` + +```csharp +public class Solution { + public int LongestOnes(int[] nums, int k) { + int l = 0, res = 0; + for (int r = 0; r < nums.Length; r++) { + k -= (nums[r] == 0 ? 1 : 0); + while (k < 0) { + k += (nums[l] == 0 ? 1 : 0); + l++; + } + res = Math.Max(res, r - l + 1); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/max-consecutive-ones.md b/articles/max-consecutive-ones.md new file mode 100644 index 000000000..2b067be81 --- /dev/null +++ b/articles/max-consecutive-ones.md @@ -0,0 +1,279 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def findMaxConsecutiveOnes(self, nums: List[int]) -> int: + n, res = len(nums), 0 + + for i in range(n): + cnt = 0 + for j in range(i, n): + if nums[j] == 0: break + cnt += 1 + res = max(res, cnt) + + return res +``` + +```java +public class Solution { + public int findMaxConsecutiveOnes(int[] nums) { + int n = nums.length, res = 0; + for (int i = 0; i < n; i++) { + int cnt = 0; + for (int j = i; j < n; j++) { + if (nums[j] == 0) break; + cnt++; + } + res = Math.max(res, cnt); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int findMaxConsecutiveOnes(vector& nums) { + int n = nums.size(), res = 0; + for (int i = 0; i < n; i++) { + int cnt = 0; + for (int j = i; j < n; j++) { + if (nums[j] == 0) break; + cnt++; + } + res = max(res, cnt); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findMaxConsecutiveOnes(nums) { + const n = nums.length; + let res = 0; + for (let i = 0; i < n; i++) { + let cnt = 0; + for (let j = i; j < n; j++) { + if (nums[j] === 0) break; + cnt++; + } + res = Math.max(res, cnt); + } + return res; + } +} +``` + +```csharp +public class Solution { + public int FindMaxConsecutiveOnes(int[] nums) { + int n = nums.Length, res = 0; + for (int i = 0; i < n; i++) { + int cnt = 0; + for (int j = i; j < n; j++) { + if (nums[j] == 0) break; + cnt++; + } + res = Math.Max(res, cnt); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Iteration - I + +::tabs-start + +```python +class Solution: + def findMaxConsecutiveOnes(self, nums: List[int]) -> int: + res = cnt = 0 + for num in nums: + if num == 0: + res = max(res, cnt) + cnt = 0 + else: + cnt += 1 + + return max(cnt, res) +``` + +```java +public class Solution { + public int findMaxConsecutiveOnes(int[] nums) { + int res = 0, cnt = 0; + for (int num : nums) { + if (num == 0) { + res = Math.max(res, cnt); + cnt = 0; + } else { + cnt++; + } + } + return Math.max(res, cnt); + } +} +``` + +```cpp +class Solution { +public: + int findMaxConsecutiveOnes(vector& nums) { + int res = 0, cnt = 0; + for (int num : nums) { + if (num == 0) { + res = max(res, cnt); + cnt = 0; + } else { + cnt++; + } + } + return max(res, cnt); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findMaxConsecutiveOnes(nums) { + let res = 0, cnt = 0; + for (const num of nums) { + if (num === 0) { + res = Math.max(res, cnt); + cnt = 0; + } else { + cnt++; + } + } + return Math.max(res, cnt); + } +} +``` + +```csharp +public class Solution { + public int FindMaxConsecutiveOnes(int[] nums) { + int res = 0, cnt = 0; + foreach (int num in nums) { + if (num == 0) { + res = Math.Max(res, cnt); + cnt = 0; + } else { + cnt++; + } + } + return Math.Max(res, cnt); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ + +--- + +## 3. Iteration - II + +::tabs-start + +```python +class Solution: + def findMaxConsecutiveOnes(self, nums: List[int]) -> int: + res = cnt = 0 + for num in nums: + cnt += 1 if num else -cnt + res = max(res, cnt) + return res +``` + +```java +public class Solution { + public int findMaxConsecutiveOnes(int[] nums) { + int res = 0, cnt = 0; + for (int num : nums) { + cnt = (num == 1) ? cnt + 1 : 0; + res = Math.max(res, cnt); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int findMaxConsecutiveOnes(vector& nums) { + int res = 0, cnt = 0; + for (int num : nums) { + cnt = num ? cnt + 1 : 0; + res = max(res, cnt); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + findMaxConsecutiveOnes(nums) { + let res = 0, cnt = 0; + for (const num of nums) { + cnt = num === 1 ? cnt + 1 : 0; + res = Math.max(res, cnt); + } + return res; + } +} +``` + +```csharp +public class Solution { + public int FindMaxConsecutiveOnes(int[] nums) { + int res = 0, cnt = 0; + foreach (int num in nums) { + cnt = (num == 1) ? cnt + 1 : 0; + res = Math.Max(res, cnt); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/max-points-on-a-line.md b/articles/max-points-on-a-line.md new file mode 100644 index 000000000..a760de0e4 --- /dev/null +++ b/articles/max-points-on-a-line.md @@ -0,0 +1,386 @@ +## 1. Math + +::tabs-start + +```python +class Solution: + def maxPoints(self, points: List[List[int]]) -> int: + n = len(points) + if n <= 2: + return n + + def get_slope(p1, p2): + if p1[0] == p2[0]: + return float("inf") + return (p2[1] - p1[1]) / (p2[0] - p1[0]) + + res = 1 + for i in range(n): + for j in range(i + 1, n): + slope = get_slope(points[i], points[j]) + cnt = 2 + for k in range(j + 1, n): + if slope == get_slope(points[i], points[k]): + cnt += 1 + res = max(res, cnt) + + return res +``` + +```java +public class Solution { + public int maxPoints(int[][] points) { + int n = points.length; + if (n <= 2) { + return n; + } + + int res = 1; + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + double slope = getSlope(points[i], points[j]); + int cnt = 2; + for (int k = j + 1; k < n; k++) { + if (slope == getSlope(points[i], points[k])) { + cnt++; + } + } + res = Math.max(res, cnt); + } + } + + return res; + } + + private double getSlope(int[] p1, int[] p2) { + if (p1[0] == p2[0]) { + return Double.POSITIVE_INFINITY; + } + return (double) (p2[1] - p1[1]) / (p2[0] - p1[0]); + } +} +``` + +```cpp +class Solution { +public: + int maxPoints(vector>& points) { + int n = points.size(); + if (n <= 2) { + return n; + } + + int res = 1; + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + double slope = getSlope(points[i], points[j]); + int cnt = 2; + for (int k = j + 1; k < n; k++) { + if (slope == getSlope(points[i], points[k])) { + cnt++; + } + } + res = max(res, cnt); + } + } + + return res; + } + +private: + double getSlope(vector& p1, vector& p2) { + if (p1[0] == p2[0]) { + return INFINITY; + } + return (double)(p2[1] - p1[1]) / (p2[0] - p1[0]); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + maxPoints(points) { + const n = points.length; + if (n <= 2) { + return n; + } + + let res = 1; + const getSlope = (p1, p2) => { + if (p1[0] === p2[0]) { + return Infinity; + } + return (p2[1] - p1[1]) / (p2[0] - p1[0]); + }; + + for (let i = 0; i < n; i++) { + for (let j = i + 1; j < n; j++) { + const slope = getSlope(points[i], points[j]); + let cnt = 2; + for (let k = j + 1; k < n; k++) { + if (slope === getSlope(points[i], points[k])) { + cnt++; + } + } + res = Math.max(res, cnt); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 2. Math + Hash Map + +::tabs-start + +```python +class Solution: + def maxPoints(self, points: List[List[int]]) -> int: + res = 1 + for i in range(len(points)): + p1 = points[i] + count = defaultdict(int) + for j in range(i + 1, len(points)): + p2 = points[j] + if p2[0] == p1[0]: + slope = float("inf") + else: + slope = (p2[1] - p1[1]) / (p2[0] - p1[0]) + count[slope] += 1 + res = max(res, count[slope] + 1) + return res +``` + +```java +public class Solution { + public int maxPoints(int[][] points) { + int res = 1; + for (int i = 0; i < points.length; i++) { + Map count = new HashMap<>(); + for (int j = i + 1; j < points.length; j++) { + double slope = getSlope(points[i], points[j]); + if (slope == -0.0) slope = 0.0; + + count.put(slope, count.getOrDefault(slope, 0) + 1); + res = Math.max(res, count.get(slope) + 1); + } + } + return res; + } + + private double getSlope(int[] p1, int[] p2) { + if (p1[0] == p2[0]) { + return Double.POSITIVE_INFINITY; + } + return (double) (p2[1] - p1[1]) / (p2[0] - p1[0]); + } +} +``` + +```cpp +class Solution { +public: + int maxPoints(vector>& points) { + int res = 1; + for (int i = 0; i < points.size(); i++) { + vector& p1 = points[i]; + unordered_map count; + for (int j = i + 1; j < points.size(); j++) { + vector& p2 = points[j]; + double slope = (p2[0] == p1[0]) ? INFINITY : + (double)(p2[1] - p1[1]) / (p2[0] - p1[0]); + count[slope]++; + res = max(res, count[slope] + 1); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + maxPoints(points) { + let res = 1; + for (let i = 0; i < points.length; i++) { + const p1 = points[i]; + const count = new Map(); + for (let j = i + 1; j < points.length; j++) { + const p2 = points[j]; + const slope = + p2[0] === p1[0] + ? Infinity + : (p2[1] - p1[1]) / (p2[0] - p1[0]); + count.set(slope, (count.get(slope) || 0) + 1); + res = Math.max(res, count.get(slope) + 1); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 3. Math + Hash Map (Optimal) + +::tabs-start + +```python +class Solution: + def maxPoints(self, points: List[List[int]]) -> int: + if len(points) <= 2: + return len(points) + + def gcd(a, b): + return gcd(b, a % b) if b else a + + res = 1 + for i in range(len(points) - 1): + count = defaultdict(int) + for j in range(i + 1, len(points)): + dx = points[j][0] - points[i][0] + dy = points[j][1] - points[i][1] + g = gcd(dx, dy) + dx //= g + dy //= g + slope = (dx, dy) + count[slope] += 1 + res = max(res, max(count.values()) + 1) + return res +``` + +```java +public class Solution { + public int maxPoints(int[][] points) { + if (points.length <= 2) { + return points.length; + } + + int res = 1; + for (int i = 0; i < points.length - 1; i++) { + Map count = new HashMap<>(); + for (int j = i + 1; j < points.length; j++) { + int dx = points[j][0] - points[i][0]; + int dy = points[j][1] - points[i][1]; + int g = gcd(dx, dy); + dx /= g; + dy /= g; + String slope = dx + ":" + dy; + count.put(slope, count.getOrDefault(slope, 0) + 1); + } + for (int val : count.values()) { + res = Math.max(res, val + 1); + } + } + return res; + } + + private int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); + } +} +``` + +```cpp +class Solution { +public: + int maxPoints(vector>& points) { + if (points.size() <= 2) { + return points.size(); + } + + int res = 1; + for (int i = 0; i < points.size() - 1; i++) { + unordered_map count; + for (int j = i + 1; j < points.size(); j++) { + int dx = points[j][0] - points[i][0]; + int dy = points[j][1] - points[i][1]; + int g = gcd(dx, dy); + dx /= g; + dy /= g; + string slope = to_string(dx) + ":" + to_string(dy); + count[slope]++; + } + for (const auto& [slope, freq] : count) { + res = max(res, freq + 1); + } + } + return res; + } + +private: + int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + maxPoints(points) { + if (points.length <= 2) { + return points.length; + } + + const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b)); + + let res = 1; + for (let i = 0; i < points.length - 1; i++) { + const count = new Map(); + for (let j = i + 1; j < points.length; j++) { + let dx = points[j][0] - points[i][0]; + let dy = points[j][1] - points[i][1]; + const g = gcd(dx, dy); + dx /= g; + dy /= g; + const slope = `${dx}:${dy}`; + count.set(slope, (count.get(slope) || 0) + 1); + } + for (const freq of count.values()) { + res = Math.max(res, freq + 1); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2 \log m)$ +- Space complexity: $O(n)$ + +> Where $n$ is the number of points and $m$ is the maximum value in the points. diff --git a/articles/max-water-container.md b/articles/max-water-container.md index dfd046f07..f2c2a83df 100644 --- a/articles/max-water-container.md +++ b/articles/max-water-container.md @@ -110,12 +110,26 @@ class Solution { } ``` +```swift +class Solution { + func maxArea(_ heights: [Int]) -> Int { + var res = 0 + for i in 0.. Int { + var l = 0, r = heights.count - 1 + var res = 0 + + while l < r { + let area = min(heights[l], heights[r]) * (r - l) + res = max(res, area) + if heights[l] <= heights[r] { + l += 1 + } else { + r -= 1 + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/maximal-square.md b/articles/maximal-square.md index ab7d2fce0..fd294c36f 100644 --- a/articles/maximal-square.md +++ b/articles/maximal-square.md @@ -17,7 +17,7 @@ class Solution: if r + k > m or c + k > n: break flag = True - + for i in range(r, r + k): if matrix[i][c + k - 1] == "0": flag = False @@ -26,12 +26,12 @@ class Solution: if matrix[r + k - 1][j] == "0": flag = False break - + if not flag: - break + break res = max(res, k * k) k += 1 - + return res ``` @@ -52,7 +52,7 @@ public class Solution { break; } boolean flag = true; - + for (int i = r; i < r + k; i++) { if (matrix[i][c + k - 1] == '0') { flag = false; @@ -65,7 +65,7 @@ public class Solution { break; } } - + if (!flag) { break; } @@ -74,7 +74,7 @@ public class Solution { } } } - + return res; } } @@ -98,7 +98,7 @@ public: break; } bool flag = true; - + for (int i = r; i < r + k; i++) { if (matrix[i][c + k - 1] == '0') { flag = false; @@ -111,7 +111,7 @@ public: break; } } - + if (!flag) { break; } @@ -120,7 +120,7 @@ public: } } } - + return res; } }; @@ -133,12 +133,13 @@ class Solution { * @return {number} */ maximalSquare(matrix) { - const m = matrix.length, n = matrix[0].length; + const m = matrix.length, + n = matrix[0].length; let res = 0; for (let r = 0; r < m; r++) { for (let c = 0; c < n; c++) { - if (matrix[r][c] === "0") { + if (matrix[r][c] === '0') { continue; } let k = 1; @@ -149,13 +150,13 @@ class Solution { let flag = true; for (let i = r; i < r + k; i++) { - if (matrix[i][c + k - 1] === "0") { + if (matrix[i][c + k - 1] === '0') { flag = false; break; } } for (let j = c; j < c + k; j++) { - if (matrix[r + k - 1][j] === "0") { + if (matrix[r + k - 1][j] === '0') { flag = false; break; } @@ -179,8 +180,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O((m * n) ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O((m * n) ^ 2)$ +- Space complexity: $O(1)$ > Where $m$ is the number of rows and $n$ is the number columns. @@ -300,7 +301,8 @@ class Solution { * @return {number} */ maximalSquare(matrix) { - const ROWS = matrix.length, COLS = matrix[0].length; + const ROWS = matrix.length, + COLS = matrix[0].length; const dp = Array.from({ length: ROWS }, () => Array(COLS).fill(-1)); const dfs = (r, c) => { @@ -314,7 +316,7 @@ class Solution { const right = dfs(r, c + 1); const diag = dfs(r + 1, c + 1); dp[r][c] = 0; - if (matrix[r][c] === "1") { + if (matrix[r][c] === '1') { dp[r][c] = 1 + Math.min(down, Math.min(right, diag)); } return dp[r][c]; @@ -336,8 +338,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number columns. @@ -413,14 +415,17 @@ class Solution { * @return {number} */ maximalSquare(matrix) { - const m = matrix.length, n = matrix[0].length; + const m = matrix.length, + n = matrix[0].length; const dp = Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)); let maxSquare = 0; for (let r = m - 1; r >= 0; r--) { for (let c = n - 1; c >= 0; c--) { - if (matrix[r][c] === "1") { - dp[r][c] = 1 + Math.min(dp[r + 1][c], dp[r][c + 1], dp[r + 1][c + 1]); + if (matrix[r][c] === '1') { + dp[r][c] = + 1 + + Math.min(dp[r + 1][c], dp[r][c + 1], dp[r + 1][c + 1]); maxSquare = Math.max(maxSquare, dp[r][c]); } } @@ -435,8 +440,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number columns. @@ -527,7 +532,8 @@ class Solution { * @return {number} */ maximalSquare(matrix) { - const m = matrix.length, n = matrix[0].length; + const m = matrix.length, + n = matrix[0].length; const dp = new Array(n + 1).fill(0); let maxSquare = 0; let prev = 0; @@ -535,7 +541,7 @@ class Solution { for (let r = m - 1; r >= 0; r--) { for (let c = n - 1; c >= 0; c--) { const temp = dp[c]; - if (matrix[r][c] === "1") { + if (matrix[r][c] === '1') { dp[c] = 1 + Math.min(dp[c], dp[c + 1], prev); maxSquare = Math.max(maxSquare, dp[c]); } else { @@ -554,7 +560,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(n)$ -> Where $m$ is the number of rows and $n$ is the number columns. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number columns. diff --git a/articles/maximize-score-after-n-operations.md b/articles/maximize-score-after-n-operations.md new file mode 100644 index 000000000..26608bfdf --- /dev/null +++ b/articles/maximize-score-after-n-operations.md @@ -0,0 +1,629 @@ +## 1. Brute Force (Backtracking) + +::tabs-start + +```python +class Solution: + def maxScore(self, nums: List[int]) -> int: + N = len(nums) + visit = [False] * N + + def dfs(n): + if n > (N // 2): + return 0 + + res = 0 + for i in range(N): + if visit[i]: + continue + visit[i] = True + for j in range(i + 1, N): + if visit[j]: + continue + visit[j] = True + g = gcd(nums[i], nums[j]) + res = max(res, n * g + dfs(n + 1)) + visit[j] = False + visit[i] = False + + return res + + return dfs(1) +``` + +```java +public class Solution { + public int maxScore(int[] nums) { + int N = nums.length; + boolean[] visit = new boolean[N]; + return dfs(nums, visit, 1, N); + } + + private int dfs(int[] nums, boolean[] visit, int n, int N) { + if (n > N / 2) { + return 0; + } + + int res = 0; + for (int i = 0; i < N; i++) { + if (visit[i]) continue; + visit[i] = true; + for (int j = i + 1; j < N; j++) { + if (visit[j]) continue; + visit[j] = true; + int g = gcd(nums[i], nums[j]); + res = Math.max(res, n * g + dfs(nums, visit, n + 1, N)); + visit[j] = false; + } + visit[i] = false; + } + + return res; + } + + private int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& nums) { + int N = nums.size(); + vector visit(N, false); + return dfs(nums, visit, 1, N); + } + +private: + int dfs(vector& nums, vector& visit, int n, int N) { + if (n > N / 2) { + return 0; + } + + int res = 0; + for (int i = 0; i < N; i++) { + if (visit[i]) continue; + visit[i] = true; + for (int j = i + 1; j < N; j++) { + if (visit[j]) continue; + visit[j] = true; + int g = gcd(nums[i], nums[j]); + res = max(res, n * g + dfs(nums, visit, n + 1, N)); + visit[j] = false; + } + visit[i] = false; + } + + return res; + } + + int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxScore(nums) { + const N = nums.length; + const visit = new Array(N).fill(false); + + const gcd = (a, b) => { + return b === 0 ? a : gcd(b, a % b); + }; + const dfs = (n) => { + if (n > N / 2) { + return 0; + } + + let res = 0; + for (let i = 0; i < N; i++) { + if (visit[i]) continue; + visit[i] = true; + for (let j = i + 1; j < N; j++) { + if (visit[j]) continue; + visit[j] = true; + let g = gcd(nums[i], nums[j]); + res = Math.max(res, n * g + dfs(n + 1)); + visit[j] = false; + } + visit[i] = false; + } + + return res; + }; + + return dfs(1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ n * \log m)$ +- Space complexity: $O(n)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in the array. + +--- + +## 2. Bitmask DP (Top-Down) - I + +::tabs-start + +```python +class Solution: + def maxScore(self, nums: List[int]) -> int: + cache = collections.defaultdict(int) + + def dfs(mask, op): + if mask in cache: + return cache[mask] + + for i in range(len(nums)): + for j in range(i + 1, len(nums)): + if (1 << i) & mask or (1 << j) & mask: + continue + + newMask = mask | (1 << i) | (1 << j) + score = op * math.gcd(nums[i], nums[j]) + cache[mask] = max( + cache[mask], + score + dfs(newMask, op + 1) + ) + + return cache[mask] + + return dfs(0, 1) +``` + +```java +public class Solution { + private Map cache; + + public int maxScore(int[] nums) { + cache = new HashMap<>(); + return dfs(0, 1, nums); + } + + private int dfs(int mask, int op, int[] nums) { + if (cache.containsKey(mask)) { + return cache.get(mask); + } + + int maxScore = 0; + int n = nums.length; + for (int i = 0; i < n; i++) { + if ((mask & (1 << i)) != 0) continue; + for (int j = i + 1; j < n; j++) { + if ((mask & (1 << j)) != 0) continue; + int newMask = mask | (1 << i) | (1 << j); + int score = op * gcd(nums[i], nums[j]) + dfs(newMask, op + 1, nums); + maxScore = Math.max(maxScore, score); + } + } + + cache.put(mask, maxScore); + return maxScore; + } + + private int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& nums) { + return dfs(0, 1, nums); + } + +private: + unordered_map cache; + + int dfs(int mask, int op, vector& nums) { + if (cache.count(mask)) { + return cache[mask]; + } + + int maxScore = 0; + int n = nums.size(); + for (int i = 0; i < n; i++) { + if ((mask & (1 << i)) != 0) continue; + for (int j = i + 1; j < n; j++) { + if ((mask & (1 << j)) != 0) continue; + int newMask = mask | (1 << i) | (1 << j); + int score = op * gcd(nums[i], nums[j]) + dfs(newMask, op + 1, nums); + maxScore = max(maxScore, score); + } + } + + return cache[mask] = maxScore; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxScore(nums) { + const cache = new Map(); + + const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b)); + + const dfs = (mask, op) => { + if (cache.has(mask)) { + return cache.get(mask); + } + + let maxScore = 0; + const n = nums.length; + for (let i = 0; i < n; i++) { + if ((mask & (1 << i)) !== 0) continue; + for (let j = i + 1; j < n; j++) { + if ((mask & (1 << j)) !== 0) continue; + let newMask = mask | (1 << i) | (1 << j); + let score = + op * gcd(nums[i], nums[j]) + dfs(newMask, op + 1); + maxScore = Math.max(maxScore, score); + } + } + + cache.set(mask, maxScore); + return maxScore; + }; + + return dfs(0, 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2 * 2 ^ n * \log m)$ +- Space complexity: $O(2 ^ n)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in the array. + +--- + +## 3. Bitmask DP (Top-Down) - II + +::tabs-start + +```python +class Solution: + def maxScore(self, nums: List[int]) -> int: + n = len(nums) + GCD = [[0] * n for _ in range(n)] + for i in range(n): + for j in range(i + 1, n): + GCD[i][j] = gcd(nums[i], nums[j]) + + dp = [-1] * (1 << n) + def dfs(mask, op): + if dp[mask] != -1: + return dp[mask] + + max_score = 0 + for i in range(n): + if mask & (1 << i): + continue + for j in range(i + 1, n): + if mask & (1 << j): + continue + new_mask = mask | (1 << i) | (1 << j) + max_score = max( + max_score, + op * GCD[i][j] + dfs(new_mask, op + 1) + ) + + dp[mask] = max_score + return max_score + + return dfs(0, 1) +``` + +```java +public class Solution { + private int[][] GCD; + private int[] dp; + + public int maxScore(int[] nums) { + int n = nums.length; + GCD = new int[n][n]; + dp = new int[1 << n]; + Arrays.fill(dp, -1); + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + GCD[i][j] = gcd(nums[i], nums[j]); + } + } + + return (int) dfs(0, 1, nums); + } + + private int dfs(int mask, int op, int[] nums) { + if (dp[mask] != -1) return dp[mask]; + + int maxScore = 0; + for (int i = 0; i < nums.length; i++) { + if ((mask & (1 << i)) != 0) continue; + for (int j = i + 1; j < nums.length; j++) { + if ((mask & (1 << j)) != 0) continue; + int newMask = mask | (1 << i) | (1 << j); + maxScore = Math.max( + maxScore, + op * GCD[i][j] + dfs(newMask, op + 1, nums) + ); + } + } + return dp[mask] = maxScore; + } + + private int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& nums) { + int n = nums.size(); + GCD.assign(n, vector(n, 0)); + dp.assign(1 << n, -1); + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + GCD[i][j] = gcd(nums[i], nums[j]); + } + } + + return dfs(0, 1, nums); + } + +private: + vector> GCD; + vector dp; + + int dfs(int mask, int op, vector& nums) { + if (dp[mask] != -1) return dp[mask]; + + int maxScore = 0; + for (int i = 0; i < nums.size(); i++) { + if (mask & (1 << i)) continue; + for (int j = i + 1; j < nums.size(); j++) { + if (mask & (1 << j)) continue; + int newMask = mask | (1 << i) | (1 << j); + maxScore = max( + maxScore, + op * GCD[i][j] + dfs(newMask, op + 1, nums) + ); + } + } + return dp[mask] = maxScore; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxScore(nums) { + const n = nums.length; + const GCD = Array.from({ length: n }, () => Array(n).fill(0)); + const dp = Array(1 << n).fill(-1); + + const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b)); + for (let i = 0; i < n; i++) { + for (let j = i + 1; j < n; j++) { + GCD[i][j] = gcd(nums[i], nums[j]); + } + } + + const dfs = (mask, op) => { + if (dp[mask] !== -1) return dp[mask]; + + let maxScore = 0; + for (let i = 0; i < n; i++) { + if (mask & (1 << i)) continue; + for (let j = i + 1; j < n; j++) { + if (mask & (1 << j)) continue; + const newMask = mask | (1 << i) | (1 << j); + maxScore = Math.max( + maxScore, + op * GCD[i][j] + dfs(newMask, op + 1), + ); + } + } + return (dp[mask] = maxScore); + }; + + return dfs(0, 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2 * (2 ^ n + \log m))$ +- Space complexity: $O(n ^ 2 + 2 ^ n)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in the array. + +--- + +## 4. Bitmask DP (Bottom-Up) + +::tabs-start + +```python +class Solution: + def maxScore(self, nums: List[int]) -> int: + n = len(nums) + N = 1 << n + GCD = [[0] * n for _ in range(n)] + for i in range(n): + for j in range(i + 1, n): + GCD[i][j] = gcd(nums[i], nums[j]) + + dp = [0] * N + for mask in range(N - 1, -1, -1): + bits = bin(mask).count('1') + if bits % 2 == 1: + continue + op = bits // 2 + 1 + + for i in range(n): + if mask & (1 << i): + continue + for j in range(i + 1, n): + if mask & (1 << j): + continue + new_mask = mask | (1 << i) | (1 << j) + dp[mask] = max(dp[mask], op * GCD[i][j] + dp[new_mask]) + + return dp[0] +``` + +```java +public class Solution { + public int maxScore(int[] nums) { + int n = nums.length; + int N = 1 << n; + int[][] GCD = new int[n][n]; + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + GCD[i][j] = gcd(nums[i], nums[j]); + } + } + + int[] dp = new int[N]; + for (int mask = N - 1; mask >= 0; mask--) { + int bits = Integer.bitCount(mask); + if (bits % 2 == 1) continue; + int op = bits / 2 + 1; + + for (int i = 0; i < n; i++) { + if ((mask & (1 << i)) != 0) continue; + for (int j = i + 1; j < n; j++) { + if ((mask & (1 << j)) != 0) continue; + int newMask = mask | (1 << i) | (1 << j); + dp[mask] = Math.max(dp[mask], op * GCD[i][j] + dp[newMask]); + } + } + } + return dp[0]; + } + + private int gcd(int a, int b) { + return b == 0 ? a : gcd(b, a % b); + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& nums) { + int n = nums.size(); + int N = 1 << n; + vector> GCD(n, vector(n, 0)); + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + GCD[i][j] = __gcd(nums[i], nums[j]); + } + } + + vector dp(N, 0); + for (int mask = N - 1; mask >= 0; mask--) { + int bits = __builtin_popcount(mask); + if (bits % 2 == 1) continue; + int op = bits / 2 + 1; + + for (int i = 0; i < n; i++) { + if (mask & (1 << i)) continue; + for (int j = i + 1; j < n; j++) { + if (mask & (1 << j)) continue; + int newMask = mask | (1 << i) | (1 << j); + dp[mask] = max(dp[mask], op * GCD[i][j] + dp[newMask]); + } + } + } + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxScore(nums) { + const n = nums.length; + const N = 1 << n; + const GCD = Array.from({ length: n }, () => Array(n).fill(0)); + + const gcd = (a, b) => (b === 0 ? a : gcd(b, a % b)); + for (let i = 0; i < n; i++) { + for (let j = i + 1; j < n; j++) { + GCD[i][j] = gcd(nums[i], nums[j]); + } + } + + const dp = Array(N).fill(0); + for (let mask = N - 1; mask >= 0; mask--) { + let bits = mask.toString(2).split('0').join('').length; + if (bits % 2 === 1) continue; + let op = bits / 2 + 1; + + for (let i = 0; i < n; i++) { + if ((mask & (1 << i)) !== 0) continue; + for (let j = i + 1; j < n; j++) { + if ((mask & (1 << j)) !== 0) continue; + let newMask = mask | (1 << i) | (1 << j); + dp[mask] = Math.max(dp[mask], op * GCD[i][j] + dp[newMask]); + } + } + } + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2 * (2 ^ n + \log m))$ +- Space complexity: $O(n ^ 2 + 2 ^ n)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in the array. diff --git a/articles/maximize-ysum-by-picking-a-triplet-of-distinct-xvalues.md b/articles/maximize-ysum-by-picking-a-triplet-of-distinct-xvalues.md new file mode 100644 index 000000000..6edca0eb9 --- /dev/null +++ b/articles/maximize-ysum-by-picking-a-triplet-of-distinct-xvalues.md @@ -0,0 +1,435 @@ +## 1. Hash Map + +::tabs-start + +```python +class Solution: + def maxSumDistinctTriplet(self, x: List[int], y: List[int]) -> int: + mp = {} + + for i in range(len(x)): + if x[i] not in mp: + mp[x[i]] = y[i] + + mp[x[i]] = max(mp[x[i]], y[i]) + + return -1 if len(mp) < 3 else sum(sorted(list(mp.values()))[-3:]) +``` + +```java +public class Solution { + public int maxSumDistinctTriplet(int[] x, int[] y) { + Map mp = new HashMap<>(); + for (int i = 0; i < x.length; i++) { + int key = x[i], val = y[i]; + mp.put(key, Math.max(mp.getOrDefault(key, 0), val)); + } + if (mp.size() < 3) return -1; + List vals = new ArrayList<>(mp.values()); + Collections.sort(vals); + int n = vals.size(); + return vals.get(n-1) + vals.get(n-2) + vals.get(n-3); + } +} +``` + +```cpp +class Solution { +public: + int maxSumDistinctTriplet(vector& x, vector& y) { + unordered_map mp; + for (int i = 0; i < x.size(); i++) { + int key = x[i], val = y[i]; + mp[key] = max(mp[key], val); + } + if (mp.size() < 3) return -1; + vector vals; + vals.reserve(mp.size()); + for (auto &p : mp) vals.push_back(p.second); + sort(vals.begin(), vals.end()); + int n = vals.size(); + return vals[n-1] + vals[n-2] + vals[n-3]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} x + * @param {number[]} y + * @return {number} + */ + maxSumDistinctTriplet(x, y) { + const mp = new Map(); + for (let i = 0; i < x.length; i++) { + const key = x[i], val = y[i]; + mp.set(key, Math.max(mp.get(key) || 0, val)); + } + if (mp.size < 3) return -1; + const vals = Array.from(mp.values()).sort((a, b) => a - b); + const n = vals.length; + return vals[n-1] + vals[n-2] + vals[n-3]; + } +} +``` + +```csharp +public class Solution { + public int MaxSumDistinctTriplet(int[] x, int[] y) { + var mp = new Dictionary(); + for (int i = 0; i < x.Length; i++) { + int key = x[i], val = y[i]; + if (mp.TryGetValue(key, out var existing)) { + mp[key] = Math.Max(existing, val); + } else { + mp[key] = val; + } + } + if (mp.Count < 3) return -1; + var vals = mp.Values.ToList(); + vals.Sort(); + int n = vals.Count; + return vals[n-1] + vals[n-2] + vals[n-3]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Hash Map + Min-Heap + +::tabs-start + +```python +class Solution: + def maxSumDistinctTriplet(self, x: List[int], y: List[int]) -> int: + mp = {} + for xi, yi in zip(x, y): + mp[xi] = max(mp.get(xi, 0), yi) + + minHeap = [] + for val in mp.values(): + heapq.heappush(minHeap, val) + if len(minHeap) > 3: + heapq.heappop(minHeap) + + return -1 if len(minHeap) < 3 else sum(minHeap) +``` + +```java +public class Solution { + public int maxSumDistinctTriplet(int[] x, int[] y) { + Map mp = new HashMap<>(); + for (int i = 0; i < x.length; i++) { + mp.put(x[i], Math.max(mp.getOrDefault(x[i], 0), y[i])); + } + PriorityQueue pq = new PriorityQueue<>(); + for (int val : mp.values()) { + pq.offer(val); + if (pq.size() > 3) { + pq.poll(); + } + } + + if (pq.size() < 3) { + return -1; + } + int sum = 0; + while (!pq.isEmpty()) { + sum += pq.poll(); + } + return sum; + } +} +``` + +```cpp +class Solution { +public: + int maxSumDistinctTriplet(vector& x, vector& y) { + unordered_map mp; + for (int i = 0; i < x.size(); i++) { + mp[x[i]] = max(mp[x[i]], y[i]); + } + priority_queue, greater> pq; + for (auto &p : mp) { + pq.push(p.second); + if (pq.size() > 3) { + pq.pop(); + } + } + + if (pq.size() < 3) return -1; + int sum = 0; + while (!pq.empty()) { + sum += pq.top(); + pq.pop(); + } + return sum; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} x + * @param {number[]} y + * @return {number} + */ + maxSumDistinctTriplet(x, y) { + const mp = new Map(); + for (let i = 0; i < x.length; i++) { + mp.set(x[i], Math.max(mp.get(x[i])||0, y[i])); + } + const heap = new MinPriorityQueue(); + for (const val of mp.values()) { + heap.enqueue(val); + if (heap.size() > 3) { + heap.dequeue(); + } + } + if (heap.size() < 3) { + return -1; + } + return heap.dequeue() + heap.dequeue() + heap.dequeue(); + } +} +``` + +```csharp +public class Solution { + public int MaxSumDistinctTriplet(int[] x, int[] y) { + var mp = new Dictionary(); + for (int i = 0; i < x.Length; i++) { + int key = x[i], val = y[i]; + if (mp.TryGetValue(key, out var prev)) { + mp[key] = Math.Max(prev, val); + } else { + mp[key] = val; + } + } + var pq = new PriorityQueue(); + foreach (var val in mp.Values) { + pq.Enqueue(val, val); + if (pq.Count > 3) { + pq.Dequeue(); + } + } + + if (pq.Count < 3) { + return -1; + } + int sum = 0; + while (pq.Count > 0) { + sum += pq.Dequeue(); + } + return sum; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Greedy + +::tabs-start + +```python +class Solution: + def maxSumDistinctTriplet(self, x: List[int], y: List[int]) -> int: + best = [(None, float("-inf"))] * 3 + for xi, yi in zip(x, y): + for i, (xj, yj) in enumerate(best): + if xi == xj: + if yi > yj: + best[i] = (xi, yi) + best.sort(key=lambda t: t[1], reverse=True) + break + else: + if yi > best[0][1]: + best = [(xi, yi), best[0], best[1]] + elif yi > best[1][1]: + best = [best[0], (xi, yi), best[1]] + elif yi > best[2][1]: + best[2] = (xi, yi) + + return sum(v for _, v in best) if best[2][1] > float("-inf") else -1 +``` + +```java +public class Solution { + public int maxSumDistinctTriplet(int[] x, int[] y) { + List best = new ArrayList<>(); + for (int i = 0; i < 3; i++) { + best.add(new int[]{Integer.MIN_VALUE, Integer.MIN_VALUE}); + } + for (int idx = 0; idx < x.length; idx++) { + int xi = x[idx], yi = y[idx]; + boolean updated = false; + for (int i = 0; i < 3; i++) { + if (best.get(i)[0] == xi) { + if (yi > best.get(i)[1]) { + best.get(i)[1] = yi; + best.sort((a, b) -> Integer.compare(b[1], a[1])); + } + updated = true; + break; + } + } + if (updated) continue; + if (yi > best.get(0)[1]) { + best.add(0, new int[]{xi, yi}); + best.remove(3); + } else if (yi > best.get(1)[1]) { + best.add(1, new int[]{xi, yi}); + best.remove(3); + } else if (yi > best.get(2)[1]) { + best.get(2)[1] = yi; + best.get(2)[0] = xi; + } + } + if (best.get(2)[1] == Integer.MIN_VALUE) { + return -1; + } + return best.get(0)[1] + best.get(1)[1] + best.get(2)[1]; + } +} +``` + +```cpp +class Solution { +public: + int maxSumDistinctTriplet(vector& x, vector& y) { + vector> best(3, {INT_MIN, INT_MIN}); + for (int i = 0; i < x.size(); i++) { + int xi = x[i], yi = y[i]; + bool updated = false; + for (int j = 0; j < 3; j++) { + if (best[j].first == xi) { + if (yi > best[j].second) { + best[j].second = yi; + sort(best.begin(), best.end(), + [](auto &a, auto &b){ return a.second > b.second; }); + } + updated = true; + break; + } + } + if (updated) continue; + if (yi > best[0].second) { + best.insert(best.begin(), {xi, yi}); + best.pop_back(); + } else if (yi > best[1].second) { + best.insert(best.begin()+1, {xi, yi}); + best.pop_back(); + } else if (yi > best[2].second) { + best[2] = {xi, yi}; + } + } + if (best[2].second == INT_MIN) return -1; + return best[0].second + best[1].second + best[2].second; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} x + * @param {number[]} y + * @return {number} + */ + maxSumDistinctTriplet(x, y) { + let best = [ + [null, -Infinity], + [null, -Infinity], + [null, -Infinity] + ]; + for (let i = 0; i < x.length; i++) { + const xi = x[i], yi = y[i]; + let updated = false; + for (let j = 0; j < 3; j++) { + if (best[j][0] === xi) { + if (yi > best[j][1]) { + best[j][1] = yi; + best.sort((a, b) => b[1] - a[1]); + } + updated = true; + break; + } + } + if (updated) continue; + if (yi > best[0][1]) { + best = [[xi, yi], best[0], best[1]]; + } else if (yi > best[1][1]) { + best = [best[0], [xi, yi], best[1]]; + } else if (yi > best[2][1]) { + best[2] = [xi, yi]; + } + } + return best[2][1] === -Infinity + ? -1 + : best[0][1] + best[1][1] + best[2][1]; + } +} +``` + +```csharp +public class Solution { + public int MaxSumDistinctTriplet(int[] x, int[] y) { + var best = new List<(int xi, int yi)> { + (int.MinValue, int.MinValue), + (int.MinValue, int.MinValue), + (int.MinValue, int.MinValue) + }; + for (int i = 0; i < x.Length; i++) { + int xi = x[i], yi = y[i]; + bool updated = false; + for (int j = 0; j < 3; j++) { + if (best[j].xi == xi) { + if (yi > best[j].yi) { + best[j] = (xi, yi); + best = best.OrderByDescending(t => t.yi).ToList(); + } + updated = true; + break; + } + } + if (updated) continue; + if (yi > best[0].yi) { + best = new List<(int,int)> { (xi, yi), best[0], best[1] }; + } else if (yi > best[1].yi) { + best = new List<(int,int)> { best[0], (xi, yi), best[1] }; + } else if (yi > best[2].yi) { + best[2] = (xi, yi); + } + } + return best[2].yi == int.MinValue + ? -1 + : best[0].yi + best[1].yi + best[2].yi; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/maximum-alternating-subsequence-sum.md b/articles/maximum-alternating-subsequence-sum.md index 0f296306c..21e7642f0 100644 --- a/articles/maximum-alternating-subsequence-sum.md +++ b/articles/maximum-alternating-subsequence-sum.md @@ -10,7 +10,7 @@ class Solution: return 0 total = nums[i] if even else -nums[i] return max(total + dfs(i + 1, not even), dfs(i + 1, even)) - + return dfs(0, True) ``` @@ -73,8 +73,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -92,11 +92,11 @@ class Solution: return 0 if (i, even) in dp: return dp[(i, even)] - + total = nums[i] if even else -nums[i] dp[(i, even)] = max(total + dfs(i + 1, not even), dfs(i + 1, even)) return dp[(i, even)] - + return dfs(0, True) ``` @@ -173,7 +173,10 @@ class Solution { } const total = even === 1 ? nums[i] : -nums[i]; - dp[i][even] = Math.max(total + dfs(i + 1, 1 - even), dfs(i + 1, even)); + dp[i][even] = Math.max( + total + dfs(i + 1, 1 - even), + dfs(i + 1, even), + ); return dp[i][even]; }; @@ -186,8 +189,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -265,8 +268,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -283,7 +286,7 @@ class Solution: tmpEven = max(sumOdd + nums[i], sumEven) tmpOdd = max(sumEven - nums[i], sumOdd) sumEven, sumOdd = tmpEven, tmpOdd - + return sumEven ``` @@ -329,7 +332,8 @@ class Solution { * @return {number} */ maxAlternatingSum(nums) { - let sumEven = 0, sumOdd = 0; + let sumEven = 0, + sumOdd = 0; for (let i = nums.length - 1; i >= 0; i--) { let tmpEven = Math.max(nums[i] + sumOdd, sumEven); @@ -347,5 +351,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/maximum-ascending-subarray-sum.md b/articles/maximum-ascending-subarray-sum.md new file mode 100644 index 000000000..c980a6b7a --- /dev/null +++ b/articles/maximum-ascending-subarray-sum.md @@ -0,0 +1,174 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maxAscendingSum(self, nums: List[int]) -> int: + res = 0 + for i in range(len(nums)): + curSum = nums[i] + for j in range(i + 1, len(nums)): + if nums[j] <= nums[j - 1]: + break + curSum += nums[j] + res = max(res, curSum) + return res +``` + +```java +public class Solution { + public int maxAscendingSum(int[] nums) { + int res = 0; + for (int i = 0; i < nums.length; i++) { + int curSum = nums[i]; + for (int j = i + 1; j < nums.length; j++) { + if (nums[j] <= nums[j - 1]) { + break; + } + curSum += nums[j]; + } + res = Math.max(res, curSum); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxAscendingSum(vector& nums) { + int res = 0; + for (int i = 0; i < nums.size(); i++) { + int curSum = nums[i]; + for (int j = i + 1; j < nums.size(); j++) { + if (nums[j] <= nums[j - 1]) { + break; + } + curSum += nums[j]; + } + res = max(res, curSum); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxAscendingSum(nums) { + let res = 0; + for (let i = 0; i < nums.length; i++) { + let curSum = nums[i]; + for (let j = i + 1; j < nums.length; j++) { + if (nums[j] <= nums[j - 1]) { + break; + } + curSum += nums[j]; + } + res = Math.max(res, curSum); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Iteration + +::tabs-start + +```python +class Solution: + def maxAscendingSum(self, nums: List[int]) -> int: + res = curSum= nums[0] + + for i in range(1, len(nums)): + if nums[i] <= nums[i - 1]: + curSum = 0 + + curSum += nums[i] + res = max(res, curSum) + + return res +``` + +```java +public class Solution { + public int maxAscendingSum(int[] nums) { + int res = nums[0], curSum = nums[0]; + + for (int i = 1; i < nums.length; i++) { + if (nums[i] <= nums[i - 1]) { + curSum = 0; + } + curSum += nums[i]; + res = Math.max(res, curSum); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxAscendingSum(vector& nums) { + int res = nums[0], curSum = nums[0]; + + for (int i = 1; i < nums.size(); i++) { + if (nums[i] <= nums[i - 1]) { + curSum = 0; + } + curSum += nums[i]; + res = max(res, curSum); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + maxAscendingSum(nums) { + let res = nums[0], + curSum = nums[0]; + + for (let i = 1; i < nums.length; i++) { + if (nums[i] <= nums[i - 1]) { + curSum = 0; + } + curSum += nums[i]; + res = Math.max(res, curSum); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/maximum-difference-between-even-and-odd-frequency-i.md b/articles/maximum-difference-between-even-and-odd-frequency-i.md new file mode 100644 index 000000000..f151f4fb9 --- /dev/null +++ b/articles/maximum-difference-between-even-and-odd-frequency-i.md @@ -0,0 +1,235 @@ +## 1. Counting + +::tabs-start + +```python +class Solution: + def maxDifference(self, s: str) -> int: + count = Counter(s) + res = float("-inf") + + for odd in count.values(): + if odd % 2 == 0: continue + for even in count.values(): + if even % 2 == 1: continue + res = max(res, odd - even) + + return res +``` + +```java +public class Solution { + public int maxDifference(String s) { + int[] count = new int[26]; + for (char c : s.toCharArray()) { + count[c - 'a']++; + } + + int res = Integer.MIN_VALUE; + for (int odd : count) { + if (odd == 0 || odd % 2 == 0) continue; + for (int even : count) { + if (even == 0 || even % 2 == 1) continue; + res = Math.max(res, odd - even); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxDifference(string s) { + vector count(26, 0); + for (char c : s) { + count[c - 'a']++; + } + + int res = INT_MIN; + for (int odd : count) { + if (odd == 0 || odd % 2 == 0) continue; + for (int even : count) { + if (even == 0 || even % 2 == 1) continue; + res = max(res, odd - even); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + maxDifference(s) { + const count = new Array(26).fill(0); + for (const c of s) { + count[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + let res = -Infinity; + for (const odd of count) { + if (odd === 0 || odd % 2 === 0) continue; + for (const even of count) { + if (even === 0 || even % 2 === 1) continue; + res = Math.max(res, odd - even); + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public int MaxDifference(string s) { + int[] count = new int[26]; + foreach (char c in s) { + count[c - 'a']++; + } + + int res = int.MinValue; + foreach (int odd in count) { + if (odd == 0 || odd % 2 == 0) continue; + foreach (int even in count) { + if (even == 0 || even % 2 == 1) continue; + res = Math.Max(res, odd - even); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ since we have at most $26$ different characters. + +--- + +## 2. Counting (Optimal) + +::tabs-start + +```python +class Solution: + def maxDifference(self, s: str) -> int: + count = Counter(s) + oddMax, evenMin = 0, len(s) + + for cnt in count.values(): + if cnt & 1: + oddMax = max(oddMax, cnt) + else: + evenMin = min(evenMin, cnt) + + return oddMax - evenMin +``` + +```java +public class Solution { + public int maxDifference(String s) { + int[] count = new int[26]; + for (char c : s.toCharArray()) { + count[c - 'a']++; + } + + int oddMax = 0, evenMin = s.length(); + for (int c : count) { + if ((c & 1) == 1) { + oddMax = Math.max(oddMax, c); + } else if (c > 0) { + evenMin = Math.min(evenMin, c); + } + } + + return oddMax - evenMin; + } +} +``` + +```cpp +class Solution { +public: + int maxDifference(string s) { + vector count(26, 0); + for (char c : s) { + count[c - 'a']++; + } + + int oddMax = 0, evenMin = s.length(); + for (int c : count) { + if (c & 1) { + oddMax = max(oddMax, c); + } else if (c > 0) { + evenMin = min(evenMin, c); + } + } + + return oddMax - evenMin; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + maxDifference(s) { + const count = new Array(26).fill(0); + for (const c of s) { + count[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + let oddMax = 0, evenMin = s.length; + for (const c of count) { + if (c & 1) { + oddMax = Math.max(oddMax, c); + } else if (c > 0) { + evenMin = Math.min(evenMin, c); + } + } + + return oddMax - evenMin; + } +} +``` + +```csharp +public class Solution { + public int MaxDifference(string s) { + int[] count = new int[26]; + foreach (char c in s) { + count[c - 'a']++; + } + + int oddMax = 0, evenMin = s.Length; + foreach (int c in count) { + if ((c & 1) == 1) { + oddMax = Math.Max(oddMax, c); + } else if (c > 0) { + evenMin = Math.Min(evenMin, c); + } + } + + return oddMax - evenMin; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ since we have at most $26$ different characters. \ No newline at end of file diff --git a/articles/maximum-element-after-decreasing-and-rearranging.md b/articles/maximum-element-after-decreasing-and-rearranging.md new file mode 100644 index 000000000..811cb9673 --- /dev/null +++ b/articles/maximum-element-after-decreasing-and-rearranging.md @@ -0,0 +1,158 @@ +## 1. Greedy + Sorting + +::tabs-start + +```python +class Solution: + def maximumElementAfterDecrementingAndRearranging(self, arr: List[int]) -> int: + arr.sort() + prev = 0 + for num in arr: + prev = min(prev + 1, num) + return prev +``` + +```java +public class Solution { + public int maximumElementAfterDecrementingAndRearranging(int[] arr) { + Arrays.sort(arr); + int prev = 0; + for (int num : arr) { + prev = Math.min(prev + 1, num); + } + return prev; + } +} +``` + +```cpp +class Solution { +public: + int maximumElementAfterDecrementingAndRearranging(vector& arr) { + sort(arr.begin(), arr.end()); + int prev = 0; + for (int num : arr) { + prev = min(prev + 1, num); + } + return prev; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + maximumElementAfterDecrementingAndRearranging(arr) { + arr.sort((a, b) => a - b); + let prev = 0; + for (let num of arr) { + prev = Math.min(prev + 1, num); + } + return prev; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 2. Greedy + +::tabs-start + +```python +class Solution: + def maximumElementAfterDecrementingAndRearranging(self, arr: List[int]) -> int: + n = len(arr) + count = [0] * (n + 1) + + for num in arr: + count[min(num, n)] += 1 + + prev = 1 + for num in range(2, n + 1): + prev = min(prev + count[num], num) + + return prev +``` + +```java +public class Solution { + public int maximumElementAfterDecrementingAndRearranging(int[] arr) { + int n = arr.length; + int[] count = new int[n + 1]; + + for (int num : arr) { + count[Math.min(num, n)]++; + } + + int prev = 1; + for (int num = 2; num <= n; num++) { + prev = Math.min(prev + count[num], num); + } + + return prev; + } +} +``` + +```cpp +class Solution { +public: + int maximumElementAfterDecrementingAndRearranging(vector& arr) { + int n = arr.size(); + vector count(n + 1, 0); + + for (int num : arr) { + count[min(num, n)]++; + } + + int prev = 1; + for (int num = 2; num <= n; num++) { + prev = min(prev + count[num], num); + } + + return prev; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + maximumElementAfterDecrementingAndRearranging(arr) { + let n = arr.length; + let count = new Array(n + 1).fill(0); + + for (let num of arr) { + count[Math.min(num, n)]++; + } + + let prev = 1; + for (let num = 2; num <= n; num++) { + prev = Math.min(prev + count[num], num); + } + + return prev; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/maximum-frequency-after-subarray-operation.md b/articles/maximum-frequency-after-subarray-operation.md new file mode 100644 index 000000000..79c12ee17 --- /dev/null +++ b/articles/maximum-frequency-after-subarray-operation.md @@ -0,0 +1,381 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maxFrequency(self, nums: List[int], k: int) -> int: + n = len(nums) + cntK = nums.count(k) + res = cntK + + for num in range(1, 51): + if num == k: continue + for i in range(n): + tmp, cnt = cntK, 0 + for j in range(i, n): + if nums[j] == num: + cnt += 1 + elif nums[j] == k: + cntK -= 1 + res = max(res, cnt + cntK) + + cntK = tmp + + return res +``` + +```java +public class Solution { + public int maxFrequency(int[] nums, int k) { + int n = nums.length; + int cntK = 0; + for (int x : nums) if (x == k) cntK++; + int res = cntK; + + for (int num = 1; num <= 50; num++) { + if (num == k) continue; + for (int i = 0; i < n; i++) { + int tmp = cntK; + int cnt = 0; + for (int j = i; j < n; j++) { + if (nums[j] == num) { + cnt++; + } else if (nums[j] == k) { + cntK--; + } + res = Math.max(res, cnt + cntK); + } + cntK = tmp; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxFrequency(vector& nums, int k) { + int n = nums.size(); + int cntK = 0; + for (int x : nums) if (x == k) cntK++; + int res = cntK; + + for (int num = 1; num <= 50; num++) { + if (num == k) continue; + for (int i = 0; i < n; i++) { + int tmp = cntK, cnt = 0; + for (int j = i; j < n; j++) { + if (nums[j] == num) { + cnt++; + } else if (nums[j] == k) { + cntK--; + } + res = max(res, cnt + cntK); + } + cntK = tmp; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maxFrequency(nums, k) { + const n = nums.length; + let cntK = nums.filter(x => x === k).length; + let res = cntK; + + for (let num = 1; num <= 50; num++) { + if (num === k) continue; + for (let i = 0; i < n; i++) { + const tmp = cntK; + let cnt = 0; + for (let j = i; j < n; j++) { + if (nums[j] === num) { + cnt++; + } else if (nums[j] === k) { + cntK--; + } + res = Math.max(res, cnt + cntK); + } + cntK = tmp; + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public int MaxFrequency(int[] nums, int k) { + int n = nums.Length; + int cntK = 0; + foreach (var x in nums) if (x == k) cntK++; + int res = cntK; + + for (int num = 1; num <= 50; num++) { + if (num == k) continue; + for (int i = 0; i < n; i++) { + int tmp = cntK; + int cnt = 0; + for (int j = i; j < n; j++) { + if (nums[j] == num) { + cnt++; + } else if (nums[j] == k) { + cntK--; + } + res = Math.Max(res, cnt + cntK); + } + cntK = tmp; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(50 * n ^ 2)$ +* Space complexity: $O(1)$ + +--- + +## 2. Kadane's Algorithm - I + +::tabs-start + +```python +class Solution: + def maxFrequency(self, nums: List[int], k: int) -> int: + cntK = nums.count(k) + res = 0 + + for i in range(1, 51): + if i == k: + continue + cnt = 0 + for num in nums: + if num == i: + cnt += 1 + if num == k: + cnt -= 1 + cnt = max(cnt, 0) + res = max(res, cntK + cnt) + return res +``` + +```java +public class Solution { + public int maxFrequency(int[] nums, int k) { + int cntK = 0; + for (int num : nums) { + if (num == k) cntK++; + } + int res = 0; + + for (int i = 1; i <= 50; i++) { + if (i == k) continue; + int cnt = 0; + for (int num : nums) { + if (num == i) cnt++; + if (num == k) cnt--; + cnt = Math.max(cnt, 0); + res = Math.max(res, cntK + cnt); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxFrequency(vector& nums, int k) { + int cntK = 0; + for (int num : nums) { + if (num == k) cntK++; + } + int res = 0; + + for (int i = 1; i <= 50; i++) { + if (i == k) continue; + int cnt = 0; + for (int num : nums) { + if (num == i) cnt++; + if (num == k) cnt--; + cnt = max(cnt, 0); + res = max(res, cntK + cnt); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maxFrequency(nums, k) { + let cntK = 0; + for (const num of nums) { + if (num === k) cntK++; + } + let res = 0; + + for (let i = 1; i <= 50; i++) { + if (i === k) continue; + let cnt = 0; + for (const num of nums) { + if (num === i) cnt++; + if (num === k) cnt--; + cnt = Math.max(cnt, 0); + res = Math.max(res, cntK + cnt); + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public int MaxFrequency(int[] nums, int k) { + int cntK = 0; + foreach (var num in nums) { + if (num == k) cntK++; + } + int res = 0; + + for (int i = 1; i <= 50; i++) { + if (i == k) continue; + int cnt = 0; + foreach (var num in nums) { + if (num == i) cnt++; + if (num == k) cnt--; + cnt = Math.Max(cnt, 0); + res = Math.Max(res, cntK + cnt); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(50 * n)$ +* Space complexity: $O(1)$ + +--- + +## 3. Kadane's Algorithm - II + +::tabs-start + +```python +class Solution: + def maxFrequency(self, nums: List[int], k: int) -> int: + cnt = defaultdict(int) + res = 0 + for num in nums: + cnt[num] = max(cnt[num], cnt[k]) + 1 + res = max(res, cnt[num] - cnt[k]) + return cnt[k] + res +``` + +```java +public class Solution { + public int maxFrequency(int[] nums, int k) { + Map cnt = new HashMap<>(); + int res = 0; + for (int num : nums) { + int prev = Math.max(cnt.getOrDefault(num, 0), cnt.getOrDefault(k, 0)); + cnt.put(num, prev + 1); + res = Math.max(res, cnt.get(num) - cnt.getOrDefault(k, 0)); + } + return cnt.getOrDefault(k, 0) + res; + } +} +``` + +```cpp +class Solution { +public: + int maxFrequency(vector& nums, int k) { + unordered_map cnt; + int res = 0; + for (int num : nums) { + int prev = max(cnt[num], cnt[k]); + cnt[num] = prev + 1; + res = max(res, cnt[num] - cnt[k]); + } + return cnt[k] + res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maxFrequency(nums, k) { + const cnt = new Map(); + let res = 0; + for (const num of nums) { + const prev = Math.max(cnt.get(num) || 0, cnt.get(k) || 0); + cnt.set(num, prev + 1); + res = Math.max(res, cnt.get(num) - (cnt.get(k) || 0)); + } + return (cnt.get(k) || 0) + res; + } +} +``` + +```csharp +public class Solution { + public int MaxFrequency(int[] nums, int k) { + var cnt = new Dictionary(); + int res = 0; + foreach (var num in nums) { + int prev = Math.Max( + cnt.TryGetValue(num, out var cn) ? cn : 0, + cnt.TryGetValue(k, out var ck) ? ck : 0 + ); + cnt[num] = prev + 1; + res = Math.Max(res, cnt[num] - (cnt.TryGetValue(k, out ck) ? ck : 0)); + } + return (cnt.TryGetValue(k, out var ckk) ? ckk : 0) + res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(50)$ \ No newline at end of file diff --git a/articles/maximum-frequency-stack.md b/articles/maximum-frequency-stack.md index 317e2546c..bee45e019 100644 --- a/articles/maximum-frequency-stack.md +++ b/articles/maximum-frequency-stack.md @@ -88,7 +88,7 @@ class FreqStack { this.stack = []; } - /** + /** * @param {number} val * @return {void} */ @@ -113,14 +113,52 @@ class FreqStack { } ``` +```csharp +public class FreqStack { + private Dictionary cnt; + private List stack; + + public FreqStack() { + cnt = new Dictionary(); + stack = new List(); + } + + public void Push(int val) { + stack.Add(val); + if (!cnt.ContainsKey(val)) { + cnt[val] = 0; + } + cnt[val]++; + } + + public int Pop() { + int maxCnt = 0; + foreach (var kvp in cnt) { + maxCnt = Math.Max(maxCnt, kvp.Value); + } + + for (int i = stack.Count - 1; i >= 0; i--) { + int val = stack[i]; + if (cnt[val] == maxCnt) { + cnt[val]--; + stack.RemoveAt(i); + return val; + } + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(1)$ time for each $push()$ function call. - * $O(n)$ time for each $pop()$ function call. -* Space complexity: $O(n)$ +- Time complexity: + - $O(1)$ time for each $push()$ function call. + - $O(n)$ time for each $pop()$ function call. +- Space complexity: $O(n)$ > Where $n$ is the number of elements in the stack. @@ -132,7 +170,7 @@ class FreqStack { ```python class FreqStack: - + def __init__(self): self.heap = [] self.cnt = defaultdict(int) @@ -156,7 +194,7 @@ public class FreqStack { private int index; public FreqStack() { - heap = new PriorityQueue<>((a, b) -> + heap = new PriorityQueue<>((a, b) -> a[0] != b[0] ? Integer.compare(b[0], a[0]) : Integer.compare(b[1], a[1]) ); cnt = new HashMap<>(); @@ -212,7 +250,7 @@ class FreqStack { this.index = 0; } - /** + /** * @param {number} val * @return {void} */ @@ -232,14 +270,61 @@ class FreqStack { } ``` +```csharp +public class FreqStack { + private class Entry : IComparable { + public int Freq { get; } + public int Index { get; } + public int Value { get; } + + public Entry(int freq, int index, int value) { + Freq = freq; + Index = index; + Value = value; + } + + public int CompareTo(Entry other) { + if (Freq != other.Freq) + return other.Freq.CompareTo(Freq); + return other.Index.CompareTo(Index); + } + } + + private Dictionary cnt; + private PriorityQueue heap; + private int index; + + public FreqStack() { + cnt = new Dictionary(); + heap = new PriorityQueue(); + index = 0; + } + + public void Push(int val) { + if (!cnt.ContainsKey(val)) { + cnt[val] = 0; + } + cnt[val]++; + var entry = new Entry(cnt[val], index++, val); + heap.Enqueue(entry, entry); + } + + public int Pop() { + var entry = heap.Dequeue(); + cnt[entry.Value]--; + return entry.Value; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(\log n)$ time for each $push()$ function call. - * $O(\log n)$ time for each $pop()$ function call. -* Space complexity: $O(n)$ +- Time complexity: + - $O(\log n)$ time for each $push()$ function call. + - $O(\log n)$ time for each $pop()$ function call. +- Space complexity: $O(n)$ > Where $n$ is the number of elements in the stack. @@ -346,7 +431,7 @@ class FreqStack { this.maxCnt = 0; } - /** + /** * @param {number} val * @return {void} */ @@ -376,14 +461,54 @@ class FreqStack { } ``` +```csharp +public class FreqStack { + private Dictionary cnt; + private Dictionary> stacks; + private int maxCnt; + + public FreqStack() { + cnt = new Dictionary(); + stacks = new Dictionary>(); + maxCnt = 0; + } + + public void Push(int val) { + int valCnt = cnt.ContainsKey(val) ? cnt[val] + 1 : 1; + cnt[val] = valCnt; + + if (!stacks.ContainsKey(valCnt)) { + stacks[valCnt] = new Stack(); + } + + stacks[valCnt].Push(val); + + if (valCnt > maxCnt) { + maxCnt = valCnt; + } + } + + public int Pop() { + int res = stacks[maxCnt].Pop(); + cnt[res]--; + + if (stacks[maxCnt].Count == 0) { + maxCnt--; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(1)$ time for each $push()$ function call. - * $O(1)$ time for each $pop()$ function call. -* Space complexity: $O(n)$ +- Time complexity: + - $O(1)$ time for each $push()$ function call. + - $O(1)$ time for each $pop()$ function call. +- Space complexity: $O(n)$ > Where $n$ is the number of elements in the stack. @@ -485,7 +610,7 @@ class FreqStack { this.stacks = [[]]; } - /** + /** * @param {number} val * @return {void} */ @@ -513,13 +638,52 @@ class FreqStack { } ``` +```csharp +public class FreqStack { + private Dictionary cnt; + private List> stacks; + + public FreqStack() { + cnt = new Dictionary(); + stacks = new List>(); + stacks.Add(new List()); + } + + public void Push(int val) { + int valCnt = cnt.ContainsKey(val) ? cnt[val] + 1 : 1; + cnt[val] = valCnt; + + if (valCnt == stacks.Count) { + stacks.Add(new List()); + } + + stacks[valCnt].Add(val); + } + + public int Pop() { + int lastIndex = stacks.Count - 1; + List lastStack = stacks[lastIndex]; + int res = lastStack[lastStack.Count - 1]; + lastStack.RemoveAt(lastStack.Count - 1); + + cnt[res]--; + + if (lastStack.Count == 0) { + stacks.RemoveAt(lastIndex); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(1)$ time for each $push()$ function call. - * $O(1)$ time for each $pop()$ function call. -* Space complexity: $O(n)$ +- Time complexity: + - $O(1)$ time for each $push()$ function call. + - $O(1)$ time for each $pop()$ function call. +- Space complexity: $O(n)$ -> Where $n$ is the number of elements in the stack. \ No newline at end of file +> Where $n$ is the number of elements in the stack. diff --git a/articles/maximum-length-of-a-concatenated-string-with-unique-characters.md b/articles/maximum-length-of-a-concatenated-string-with-unique-characters.md new file mode 100644 index 000000000..b32a1bb69 --- /dev/null +++ b/articles/maximum-length-of-a-concatenated-string-with-unique-characters.md @@ -0,0 +1,860 @@ +## 1. Backtracking (Hash Set) + +::tabs-start + +```python +class Solution: + def maxLength(self, arr: List[str]) -> int: + charSet = set() + + def overlap(charSet, s): + prev = set() + for c in s: + if c in charSet or c in prev: + return True + prev.add(c) + return False + + def backtrack(i): + if i == len(arr): + return len(charSet) + + res = 0 + if not overlap(charSet, arr[i]): + for c in arr[i]: + charSet.add(c) + res = backtrack(i + 1) + for c in arr[i]: + charSet.remove(c) + + return max(res, backtrack(i + 1)) + + return backtrack(0) +``` + +```java +public class Solution { + public int maxLength(List arr) { + Set charSet = new HashSet<>(); + return backtrack(0, arr, charSet); + } + + private boolean overlap(Set charSet, String s) { + Set prev = new HashSet<>(); + for (char c : s.toCharArray()) { + if (charSet.contains(c) || prev.contains(c)) { + return true; + } + prev.add(c); + } + return false; + } + + private int backtrack(int i, List arr, Set charSet) { + if (i == arr.size()) { + return charSet.size(); + } + + int res = 0; + if (!overlap(charSet, arr.get(i))) { + for (char c : arr.get(i).toCharArray()) { + charSet.add(c); + } + res = backtrack(i + 1, arr, charSet); + for (char c : arr.get(i).toCharArray()) { + charSet.remove(c); + } + } + + return Math.max(res, backtrack(i + 1, arr, charSet)); + } +} +``` + +```cpp +class Solution { +public: + int maxLength(vector& arr) { + unordered_set charSet; + return backtrack(0, arr, charSet); + } + +private: + bool overlap(unordered_set& charSet, const string& s) { + unordered_set prev; + for (char c : s) { + if (charSet.count(c) || prev.count(c)) { + return true; + } + prev.insert(c); + } + return false; + } + + int backtrack(int i, vector& arr, unordered_set& charSet) { + if (i == arr.size()) { + return charSet.size(); + } + + int res = 0; + if (!overlap(charSet, arr[i])) { + for (char c : arr[i]) { + charSet.insert(c); + } + res = backtrack(i + 1, arr, charSet); + for (char c : arr[i]) { + charSet.erase(c); + } + } + + return max(res, backtrack(i + 1, arr, charSet)); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @return {number} + */ + maxLength(arr) { + let charSet = new Set(); + + const overlap = (charSet, s) => { + let prev = new Set(); + for (const c of s) { + if (charSet.has(c) || prev.has(c)) { + return true; + } + prev.add(c); + } + return false; + }; + + const backtrack = (i) => { + if (i === arr.length) { + return charSet.size; + } + + let res = 0; + if (!overlap(charSet, arr[i])) { + for (const c of arr[i]) { + charSet.add(c); + } + res = backtrack(i + 1); + for (const c of arr[i]) { + charSet.delete(c); + } + } + + return Math.max(res, backtrack(i + 1)); + }; + + return backtrack(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * 2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. + +> Where $n$ is the number of strings and $m$ is the maximum length of a string. + +--- + +## 2. Backtracking (Boolean Array) + +::tabs-start + +```python +class Solution: + def maxLength(self, arr: List[str]) -> int: + charSet = [False] * 26 + + def getIdx(c): + return ord(c) - ord('a') + + def overlap(charSet, s): + for i in range(len(s)): + c = getIdx(s[i]) + if charSet[c]: + for j in range(i): + charSet[getIdx(s[j])] = False + return True + charSet[c] = True + return False + + def backtrack(i): + if i == len(arr): + return 0 + + res = 0 + if not overlap(charSet, arr[i]): + res = len(arr[i]) + backtrack(i + 1) + for c in arr[i]: + charSet[getIdx(c)] = False + return max(res, backtrack(i + 1)) + + return backtrack(0) +``` + +```java +public class Solution { + public int maxLength(List arr) { + boolean[] charSet = new boolean[26]; + return backtrack(0, arr, charSet); + } + + private int getIdx(char c) { + return c - 'a'; + } + + private boolean overlap(boolean[] charSet, String s) { + for (int i = 0; i < s.length(); i++) { + int c = getIdx(s.charAt(i)); + if (charSet[c]) { + for (int j = 0; j < i; j++) { + charSet[getIdx(s.charAt(j))] = false; + } + return true; + } + charSet[c] = true; + } + return false; + } + + private int backtrack(int i, List arr, boolean[] charSet) { + if (i == arr.size()) { + return 0; + } + + int res = 0; + if (!overlap(charSet, arr.get(i))) { + res = arr.get(i).length() + backtrack(i + 1, arr, charSet); + for (char c : arr.get(i).toCharArray()) { + charSet[getIdx(c)] = false; + } + } + return Math.max(res, backtrack(i + 1, arr, charSet)); + } +} +``` + +```cpp +class Solution { +public: + int maxLength(vector& arr) { + bool charSet[26] = {false}; + return backtrack(0, arr, charSet); + } + +private: + int getIdx(char c) { + return c - 'a'; + } + + bool overlap(bool charSet[], const string& s) { + for (int i = 0; i < s.length(); i++) { + int c = getIdx(s[i]); + if (charSet[c]) { + for (int j = 0; j < i; j++) { + charSet[getIdx(s[j])] = false; + } + return true; + } + charSet[c] = true; + } + return false; + } + + int backtrack(int i, vector& arr, bool charSet[]) { + if (i == arr.size()) { + return 0; + } + + int res = 0; + if (!overlap(charSet, arr[i])) { + res = arr[i].length() + backtrack(i + 1, arr, charSet); + for (char c : arr[i]) { + charSet[getIdx(c)] = false; + } + } + return max(res, backtrack(i + 1, arr, charSet)); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @return {number} + */ + maxLength(arr) { + let charSet = new Array(26).fill(false); + + const getIdx = (c) => c.charCodeAt(0) - 'a'.charCodeAt(0); + + const overlap = (charSet, s) => { + for (let i = 0; i < s.length; i++) { + let c = getIdx(s[i]); + if (charSet[c]) { + for (let j = 0; j < i; j++) { + charSet[getIdx(s[j])] = false; + } + return true; + } + charSet[c] = true; + } + return false; + }; + + const backtrack = (i) => { + if (i === arr.length) { + return 0; + } + + let res = 0; + if (!overlap(charSet, arr[i])) { + res = arr[i].length + backtrack(i + 1); + for (const c of arr[i]) { + charSet[getIdx(c)] = false; + } + } + return Math.max(res, backtrack(i + 1)); + }; + + return backtrack(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * 2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. + +> Where $n$ is the number of strings and $m$ is the maximum length of a string. + +--- + +## 3. Recursion (Bit Mask) - I + +::tabs-start + +```python +class Solution: + def maxLength(self, arr: List[str]) -> int: + def getIdx(c): + return ord(c) - ord('a') + + A = [] + for s in arr: + cur = 0 + valid = True + for c in s: + if cur & (1 << getIdx(c)): + valid = False + break + cur |= (1 << getIdx(c)) + + if valid: + A.append([cur, len(s)]) + + def dfs(i, subSeq): + if i == len(A): + return 0 + + res = dfs(i + 1, subSeq) + + curSeq, length = A[i][0], A[i][1] + if (subSeq & curSeq) == 0: + res = max(res, length + dfs(i + 1, subSeq | curSeq)) + return res + + return dfs(0, 0) +``` + +```java +public class Solution { + public int maxLength(List arr) { + List A = new ArrayList<>(); + + for (String s : arr) { + int cur = 0; + boolean valid = true; + + for (char c : s.toCharArray()) { + if ((cur & (1 << (c - 'a'))) != 0) { + valid = false; + break; + } + cur |= (1 << (c - 'a')); + } + + if (valid) { + A.add(new int[]{cur, s.length()}); + } + } + + return dfs(0, 0, A); + } + + private int dfs(int i, int subSeq, List A) { + if (i == A.size()) { + return 0; + } + + int res = dfs(i + 1, subSeq, A); + + int curSeq = A.get(i)[0], length = A.get(i)[1]; + if ((subSeq & curSeq) == 0) { + res = Math.max(res, length + dfs(i + 1, subSeq | curSeq, A)); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxLength(vector& arr) { + vector> A; + + for (const string& s : arr) { + int cur = 0; + bool valid = true; + + for (char c : s) { + if (cur & (1 << (c - 'a'))) { + valid = false; + break; + } + cur |= (1 << (c - 'a')); + } + + if (valid) { + A.emplace_back(cur, s.length()); + } + } + + return dfs(0, 0, A); + } + +private: + int dfs(int i, int subSeq, vector>& A) { + if (i == A.size()) { + return 0; + } + + int res = dfs(i + 1, subSeq, A); + + int curSeq = A[i].first, length = A[i].second; + if ((subSeq & curSeq) == 0) { + res = max(res, length + dfs(i + 1, subSeq | curSeq, A)); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @return {number} + */ + maxLength(arr) { + let A = []; + + for (const s of arr) { + let cur = 0; + let valid = true; + + for (const c of s) { + if (cur & (1 << (c.charCodeAt(0) - 97))) { + valid = false; + break; + } + cur |= 1 << (c.charCodeAt(0) - 97); + } + + if (valid) { + A.push([cur, s.length]); + } + } + + const dfs = (i, subSeq) => { + if (i === A.length) { + return 0; + } + + let res = dfs(i + 1, subSeq); + + let [curSeq, length] = A[i]; + if ((subSeq & curSeq) === 0) { + res = Math.max(res, length + dfs(i + 1, subSeq | curSeq)); + } + return res; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n + 2 ^ n)$ +- Space complexity: $O(n)$ + +> Where $n$ is the number of strings and $m$ is the maximum length of a string. + +--- + +## 4. Recursion (Bit Mask) - II + +::tabs-start + +```python +class Solution: + def maxLength(self, arr: List[str]) -> int: + def getIdx(c): + return ord(c) - ord('a') + + A = [] + for s in arr: + cur = 0 + valid = True + for c in s: + if cur & (1 << getIdx(c)): + valid = False + break + cur |= (1 << getIdx(c)) + + if valid: + A.append([cur, len(s)]) + + def dfs(i, subSeq): + res = 0 + for j in range(i, len(A)): + curSeq, length = A[j][0], A[j][1] + if (subSeq & curSeq) == 0: + res = max(res, length + dfs(j + 1, subSeq | curSeq)) + return res + + return dfs(0, 0) +``` + +```java +public class Solution { + public int maxLength(List arr) { + List A = new ArrayList<>(); + + for (String s : arr) { + int cur = 0; + boolean valid = true; + + for (char c : s.toCharArray()) { + if ((cur & (1 << (c - 'a'))) != 0) { + valid = false; + break; + } + cur |= (1 << (c - 'a')); + } + + if (valid) { + A.add(new int[]{cur, s.length()}); + } + } + + return dfs(0, 0, A); + } + + private int dfs(int i, int subSeq, List A) { + int res = 0; + for (int j = i; j < A.size(); j++) { + int curSeq = A.get(j)[0], length = A.get(j)[1]; + if ((subSeq & curSeq) == 0) { + res = Math.max(res, length + dfs(j + 1, subSeq | curSeq, A)); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxLength(vector& arr) { + vector> A; + + for (const string& s : arr) { + int cur = 0; + bool valid = true; + + for (char c : s) { + if (cur & (1 << (c - 'a'))) { + valid = false; + break; + } + cur |= (1 << (c - 'a')); + } + + if (valid) { + A.emplace_back(cur, s.length()); + } + } + + return dfs(0, 0, A); + } + +private: + int dfs(int i, int subSeq, vector>& A) { + int res = 0; + for (int j = i; j < A.size(); j++) { + int curSeq = A[j].first, length = A[j].second; + if ((subSeq & curSeq) == 0) { + res = max(res, length + dfs(j + 1, subSeq | curSeq, A)); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @return {number} + */ + maxLength(arr) { + let A = []; + + for (const s of arr) { + let cur = 0; + let valid = true; + + for (const c of s) { + if (cur & (1 << (c.charCodeAt(0) - 97))) { + valid = false; + break; + } + cur |= 1 << (c.charCodeAt(0) - 97); + } + + if (valid) { + A.push([cur, s.length]); + } + } + + const dfs = (i, subSeq) => { + let res = 0; + for (let j = i; j < A.length; j++) { + let [curSeq, length] = A[j]; + if ((subSeq & curSeq) === 0) { + res = Math.max(res, length + dfs(j + 1, subSeq | curSeq)); + } + } + return res; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * (m + 2 ^ n))$ +- Space complexity: $O(n)$ + +> Where $n$ is the number of strings and $m$ is the maximum length of a string. + +--- + +## 5. Dynamic Programming + +::tabs-start + +```python +class Solution: + def maxLength(self, arr: List[str]) -> int: + dp = {0} + res = 0 + + for s in arr: + cur = 0 + valid = True + + for c in s: + bit = 1 << (ord(c) - ord('a')) + if cur & bit: + valid = False + break + cur |= bit + + if not valid: + continue + + next_dp = dp.copy() + for seq in dp: + if (seq & cur) or (seq | cur) in dp: + continue + next_dp.add(seq | cur) + res = max(res, bin(seq | cur).count('1')) + dp = next_dp + + return res +``` + +```java +public class Solution { + public int maxLength(List arr) { + Set dp = new HashSet<>(); + dp.add(0); + int res = 0; + + for (String s : arr) { + int cur = 0; + boolean valid = true; + + for (char c : s.toCharArray()) { + int bit = 1 << (c - 'a'); + if ((cur & bit) != 0) { + valid = false; + break; + } + cur |= bit; + } + + if (!valid) { + continue; + } + + Set next_dp = new HashSet<>(dp); + for (int seq : dp) { + if ((seq & cur) != 0 || next_dp.contains(seq | cur)) { + continue; + } + next_dp.add(seq | cur); + res = Math.max(res, Integer.bitCount(seq | cur)); + } + dp = next_dp; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxLength(vector& arr) { + unordered_set dp; + dp.insert(0); + int res = 0; + + for (const string& s : arr) { + int cur = 0; + bool valid = true; + + for (char c : s) { + int bit = 1 << (c - 'a'); + if (cur & bit) { + valid = false; + break; + } + cur |= bit; + } + + if (!valid) { + continue; + } + + unordered_set next_dp(dp); + for (int seq : dp) { + if ((seq & cur) || next_dp.count(seq | cur)) { + continue; + } + next_dp.insert(seq | cur); + res = max(res, __builtin_popcount(seq | cur)); + } + dp = next_dp; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} arr + * @return {number} + */ + maxLength(arr) { + let dp = new Set(); + dp.add(0); + let res = 0; + + for (const s of arr) { + let cur = 0; + let valid = true; + + for (const c of s) { + let bit = 1 << (c.charCodeAt(0) - 97); + if (cur & bit) { + valid = false; + break; + } + cur |= bit; + } + + if (!valid) { + continue; + } + + let next_dp = new Set(dp); + for (let seq of dp) { + if (seq & cur || next_dp.has(seq | cur)) { + continue; + } + next_dp.add(seq | cur); + res = Math.max( + res, + (seq | cur).toString(2).split('0').join('').length, + ); + } + dp = next_dp; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * (m + 2 ^ n))$ +- Space complexity: $O(2 ^ n)$ + +> Where $n$ is the number of strings and $m$ is the maximum length of a string. diff --git a/articles/maximum-length-of-pair-chain.md b/articles/maximum-length-of-pair-chain.md new file mode 100644 index 000000000..4aa351d1a --- /dev/null +++ b/articles/maximum-length-of-pair-chain.md @@ -0,0 +1,557 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def findLongestChain(self, pairs: List[List[int]]) -> int: + n = len(pairs) + pairs.sort(key=lambda x: x[1]) + + def dfs(i, j): + if i == n: + return 0 + + res = dfs(i + 1, j) + if j == -1 or pairs[j][1] < pairs[i][0]: + res = max(res, 1 + dfs(i + 1, i)) + + return res + + return dfs(0, -1) +``` + +```java +public class Solution { + public int findLongestChain(int[][] pairs) { + int n = pairs.length; + Arrays.sort(pairs, (a, b) -> Integer.compare(a[1], b[1])); + return dfs(pairs, 0, -1, n); + } + + private int dfs(int[][] pairs, int i, int j, int n) { + if (i == n) { + return 0; + } + + int res = dfs(pairs, i + 1, j, n); + if (j == -1 || pairs[j][1] < pairs[i][0]) { + res = Math.max(res, 1 + dfs(pairs, i + 1, i, n)); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int findLongestChain(vector>& pairs) { + int n = pairs.size(); + sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) { + return a[1] < b[1]; + }); + + return dfs(pairs, 0, -1, n); + } + +private: + int dfs(vector>& pairs, int i, int j, int n) { + if (i == n) { + return 0; + } + + int res = dfs(pairs, i + 1, j, n); + if (j == -1 || pairs[j][1] < pairs[i][0]) { + res = max(res, 1 + dfs(pairs, i + 1, i, n)); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} pairs + * @return {number} + */ + findLongestChain(pairs) { + pairs.sort((a, b) => a[1] - b[1]); + let n = pairs.length; + + const dfs = (i, j) => { + if (i === n) { + return 0; + } + + let res = dfs(i + 1, j); + if (j === -1 || pairs[j][1] < pairs[i][0]) { + res = Math.max(res, 1 + dfs(i + 1, i)); + } + + return res; + }; + + return dfs(0, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def findLongestChain(self, pairs: List[List[int]]) -> int: + n = len(pairs) + pairs.sort(key=lambda x: x[1]) + dp = [[-1] * (n + 1) for _ in range(n)] + + def dfs(i, j): + if i == n: + return 0 + if dp[i][j + 1] != -1: + return dp[i][j + 1] + + res = dfs(i + 1, j) + if j == -1 or pairs[j][1] < pairs[i][0]: + res = max(res, 1 + dfs(i + 1, i)) + + dp[i][j + 1] = res + return res + + return dfs(0, -1) +``` + +```java +public class Solution { + private int[][] dp; + + public int findLongestChain(int[][] pairs) { + int n = pairs.length; + Arrays.sort(pairs, (a, b) -> Integer.compare(a[1], b[1])); + dp = new int[n][n + 1]; + + for (int[] row : dp) { + Arrays.fill(row, -1); + } + + return dfs(pairs, 0, -1, n); + } + + private int dfs(int[][] pairs, int i, int j, int n) { + if (i == n) { + return 0; + } + if (dp[i][j + 1] != -1) { + return dp[i][j + 1]; + } + + int res = dfs(pairs, i + 1, j, n); + if (j == -1 || pairs[j][1] < pairs[i][0]) { + res = Math.max(res, 1 + dfs(pairs, i + 1, i, n)); + } + + dp[i][j + 1] = res; + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> dp; + + int findLongestChain(vector>& pairs) { + int n = pairs.size(); + sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) { + return a[1] < b[1]; + }); + + dp = vector>(n, vector(n + 1, -1)); + return dfs(pairs, 0, -1, n); + } + +private: + int dfs(vector>& pairs, int i, int j, int n) { + if (i == n) { + return 0; + } + if (dp[i][j + 1] != -1) { + return dp[i][j + 1]; + } + + int res = dfs(pairs, i + 1, j, n); + if (j == -1 || pairs[j][1] < pairs[i][0]) { + res = max(res, 1 + dfs(pairs, i + 1, i, n)); + } + + dp[i][j + 1] = res; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} pairs + * @return {number} + */ + findLongestChain(pairs) { + pairs.sort((a, b) => a[1] - b[1]); + let n = pairs.length; + let dp = Array.from({ length: n }, () => new Array(n + 1).fill(-1)); + + const dfs = (i, j) => { + if (i === n) { + return 0; + } + if (dp[i][j + 1] !== -1) { + return dp[i][j + 1]; + } + + let res = dfs(i + 1, j); + if (j === -1 || pairs[j][1] < pairs[i][0]) { + res = Math.max(res, 1 + dfs(i + 1, i)); + } + + dp[i][j + 1] = res; + return res; + }; + + return dfs(0, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def findLongestChain(self, pairs: List[List[int]]) -> int: + n = len(pairs) + pairs.sort(key=lambda x: x[1]) + dp = [1] * n + + for i in range(n): + for j in range(i): + if pairs[j][1] < pairs[i][0]: + dp[i] = max(dp[i], dp[j] + 1) + + return max(dp) +``` + +```java +public class Solution { + public int findLongestChain(int[][] pairs) { + int n = pairs.length; + Arrays.sort(pairs, (a, b) -> Integer.compare(a[1], b[1])); + int[] dp = new int[n]; + Arrays.fill(dp, 1); + + for (int i = 0; i < n; i++) { + for (int j = 0; j < i; j++) { + if (pairs[j][1] < pairs[i][0]) { + dp[i] = Math.max(dp[i], dp[j] + 1); + } + } + } + + return Arrays.stream(dp).max().getAsInt(); + } +} +``` + +```cpp +class Solution { +public: + int findLongestChain(vector>& pairs) { + int n = pairs.size(); + sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) { + return a[1] < b[1]; + }); + + vector dp(n, 1); + + for (int i = 0; i < n; i++) { + for (int j = 0; j < i; j++) { + if (pairs[j][1] < pairs[i][0]) { + dp[i] = max(dp[i], dp[j] + 1); + } + } + } + + return *max_element(dp.begin(), dp.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} pairs + * @return {number} + */ + findLongestChain(pairs) { + let n = pairs.length; + pairs.sort((a, b) => a[1] - b[1]); + let dp = new Array(n).fill(1); + + for (let i = 0; i < n; i++) { + for (let j = 0; j < i; j++) { + if (pairs[j][1] < pairs[i][0]) { + dp[i] = Math.max(dp[i], dp[j] + 1); + } + } + } + + return Math.max(...dp); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Bianry Search) + +::tabs-start + +```python +class Solution: + def findLongestChain(self, pairs: List[List[int]]) -> int: + pairs.sort(key=lambda x: x[0]) + dp = [] + + for a, b in pairs: + pos = bisect_left(dp, a) + if pos == len(dp): + dp.append(b) + else: + dp[pos] = min(dp[pos], b) + + return len(dp) +``` + +```java +public class Solution { + public int findLongestChain(int[][] pairs) { + Arrays.sort(pairs, Comparator.comparingInt(a -> a[0])); + List dp = new ArrayList<>(); + + for (int[] pair : pairs) { + int pos = binarySearch(dp, pair[0]); + if (pos == dp.size()) { + dp.add(pair[1]); + } else { + dp.set(pos, Math.min(dp.get(pos), pair[1])); + } + } + + return dp.size(); + } + + private int binarySearch(List dp, int target) { + int left = 0, right = dp.size() - 1; + while (left <= right) { + int mid = left + (right - left) / 2; + if (dp.get(mid) < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return left; + } +} +``` + +```cpp +class Solution { +public: + int findLongestChain(vector>& pairs) { + sort(pairs.begin(), pairs.end()); + vector dp; + + for (auto& pair : pairs) { + auto it = lower_bound(dp.begin(), dp.end(), pair[0]); + if (it == dp.end()) { + dp.push_back(pair[1]); + } else { + *it = min(*it, pair[1]); + } + } + + return dp.size(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} pairs + * @return {number} + */ + findLongestChain(pairs) { + pairs.sort((a, b) => a[0] - b[0]); + let dp = []; + + const binarySearch = (target) => { + let left = 0, + right = dp.length - 1; + while (left <= right) { + let mid = Math.floor((left + right) / 2); + if (dp[mid] < target) { + left = mid + 1; + } else { + right = mid - 1; + } + } + return left; + }; + + for (let i = 0; i < pairs.length; i++) { + let pos = binarySearch(pairs[i][0]); + if (pos === dp.length) { + dp.push(pairs[i][1]); + } else { + dp[pos] = Math.min(dp[pos], pairs[i][1]); + } + } + + return dp.length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 5. Greedy + +::tabs-start + +```python +class Solution: + def findLongestChain(self, pairs: List[List[int]]) -> int: + pairs.sort(key=lambda p: p[1]) + length = 1 + end = pairs[0][1] + + for i in range(1, len(pairs)): + if end < pairs[i][0]: + length += 1 + end = pairs[i][1] + + return length +``` + +```java +public class Solution { + public int findLongestChain(int[][] pairs) { + Arrays.sort(pairs, (a, b) -> Integer.compare(a[1], b[1])); + int length = 1; + int end = pairs[0][1]; + + for (int i = 1; i < pairs.length; i++) { + if (end < pairs[i][0]) { + length++; + end = pairs[i][1]; + } + } + + return length; + } +} +``` + +```cpp +class Solution { +public: + int findLongestChain(vector>& pairs) { + sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) { + return a[1] < b[1]; + }); + + int length = 1, end = pairs[0][1]; + + for (int i = 1; i < pairs.size(); i++) { + if (end < pairs[i][0]) { + length++; + end = pairs[i][1]; + } + } + + return length; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} pairs + * @return {number} + */ + findLongestChain(pairs) { + pairs.sort((a, b) => a[1] - b[1]); + let length = 1; + let end = pairs[0][1]; + + for (let i = 1; i < pairs.length; i++) { + if (end < pairs[i][0]) { + length++; + end = pairs[i][1]; + } + } + + return length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n\log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. diff --git a/articles/maximum-nesting-depth-of-the-parentheses.md b/articles/maximum-nesting-depth-of-the-parentheses.md new file mode 100644 index 000000000..9ec049cec --- /dev/null +++ b/articles/maximum-nesting-depth-of-the-parentheses.md @@ -0,0 +1,376 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def maxDepth(self, s: str) -> int: + res = 0 + + def dfs(i): + nonlocal res + if i == len(s): + return 0 + + cur = dfs(i + 1) + if s[i] == '(': + cur += 1 + elif s[i] == ')': + cur -= 1 + + res = max(res, abs(cur)) + return cur + + dfs(0) + return res +``` + +```java +public class Solution { + private int res = 0; + + public int maxDepth(String s) { + dfs(s, 0); + return res; + } + + private int dfs(String s, int i) { + if (i == s.length()) { + return 0; + } + + int cur = dfs(s, i + 1); + if (s.charAt(i) == '(') { + cur += 1; + } else if (s.charAt(i) == ')') { + cur -= 1; + } + + res = Math.max(res, Math.abs(cur)); + return cur; + } +} +``` + +```cpp +class Solution { +private: + int res = 0; + + int dfs(const string& s, int i) { + if (i == s.length()) { + return 0; + } + + int cur = dfs(s, i + 1); + if (s[i] == '(') { + cur += 1; + } else if (s[i] == ')') { + cur -= 1; + } + + res = max(res, abs(cur)); + return cur; + } + +public: + int maxDepth(string s) { + dfs(s, 0); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + maxDepth(s) { + let res = 0; + + const dfs = (i) => { + if (i === s.length) { + return 0; + } + + let cur = dfs(i + 1); + if (s[i] === '(') { + cur += 1; + } else if (s[i] === ')') { + cur -= 1; + } + + res = Math.max(res, Math.abs(cur)); + return cur; + }; + + dfs(0); + return res; + } +} +``` + +```csharp +public class Solution { + public int MaxDepth(string s) { + int res = 0; + + int Dfs(int i) { + if (i == s.Length) { + return 0; + } + + int cur = Dfs(i + 1); + if (s[i] == '(') { + cur += 1; + } + else if (s[i] == ')') { + cur -= 1; + } + + res = Math.Max(res, Math.Abs(cur)); + return cur; + } + + Dfs(0); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Stack + +::tabs-start + +```python +class Solution: + def maxDepth(self, s: str) -> int: + res, stack = 0, [] + + for c in s: + if c == "(": + stack.append(c) + res = max(res, len(stack)) + elif c == ")": + stack.pop() + + return res +``` + +```java +public class Solution { + public int maxDepth(String s) { + int res = 0; + Stack stack = new Stack<>(); + + for (char c : s.toCharArray()) { + if (c == '(') { + stack.push(c); + res = Math.max(res, stack.size()); + } else if (c == ')') { + stack.pop(); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxDepth(string s) { + int res = 0; + stack stack; + + for (char c : s) { + if (c == '(') { + stack.push(c); + res = max(res, (int)stack.size()); + } else if (c == ')') { + stack.pop(); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + maxDepth(s) { + let res = 0; + let stack = []; + + for (let c of s) { + if (c === '(') { + stack.push(c); + res = Math.max(res, stack.length); + } else if (c === ')') { + stack.pop(); + } + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int MaxDepth(string s) { + int res = 0; + Stack stack = new Stack(); + + foreach (char c in s) { + if (c == '(') { + stack.Push(c); + res = Math.Max(res, stack.Count); + } + else if (c == ')') { + stack.Pop(); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Iteration + +::tabs-start + +```python +class Solution: + def maxDepth(self, s: str) -> int: + res = 0 + cur = 0 + + for c in s: + if c == "(": + cur += 1 + elif c == ")": + cur -= 1 + res = max(res, cur) + + return res +``` + +```java +public class Solution { + public int maxDepth(String s) { + int res = 0, cur = 0; + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '(') { + cur++; + } else if (c == ')') { + cur--; + } + res = Math.max(res, cur); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxDepth(string s) { + int res = 0, cur = 0; + + for (char c : s) { + if (c == '(') { + cur++; + } else if (c == ')') { + cur--; + } + res = max(res, cur); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + maxDepth(s) { + let res = 0, + cur = 0; + + for (let c of s) { + if (c === '(') { + cur++; + } else if (c === ')') { + cur--; + } + res = Math.max(res, cur); + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int MaxDepth(string s) { + int res = 0; + int cur = 0; + + foreach (char c in s) { + if (c == '(') { + cur++; + } + else if (c == ')') { + cur--; + } + res = Math.Max(res, cur); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/maximum-number-of-balloons.md b/articles/maximum-number-of-balloons.md index 597cbf295..1985fb9c3 100644 --- a/articles/maximum-number-of-balloons.md +++ b/articles/maximum-number-of-balloons.md @@ -45,7 +45,7 @@ public: countText[c]++; } - unordered_map balloon = {{'b', 1}, {'a', 1}, + unordered_map balloon = {{'b', 1}, {'a', 1}, {'l', 2}, {'o', 2}, {'n', 1}}; int res = text.length(); @@ -84,8 +84,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. --- @@ -100,10 +100,10 @@ class Solution: for c in text: if c in "balon": mp[c] += 1 - + if len(mp) < 5: return 0 - + mp['l'] //= 2 mp['o'] //= 2 return min(mp.values()) @@ -118,11 +118,11 @@ public class Solution { mp.put(c, mp.getOrDefault(c, 0) + 1); } } - + if (mp.size() < 5) { return 0; } - + mp.put('l', mp.get('l') / 2); mp.put('o', mp.get('o') / 2); return Collections.min(mp.values()); @@ -140,11 +140,11 @@ public: mp[c]++; } } - + if (mp.size() < 5) { return 0; } - + mp['l'] /= 2; mp['o'] /= 2; return min({mp['b'], mp['a'], mp['l'], mp['o'], mp['n']}); @@ -161,15 +161,15 @@ class Solution { maxNumberOfBalloons(text) { const mp = new Map(); for (let c of text) { - if ("balon".includes(c)) { + if ('balon'.includes(c)) { mp.set(c, (mp.get(c) || 0) + 1); } } - + if (mp.size < 5) { return 0; } - + mp.set('l', Math.floor(mp.get('l') / 2)); mp.set('o', Math.floor(mp.get('o') / 2)); return Math.min(...Array.from(mp.values())); @@ -181,5 +181,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since $balloon$ has $5$ different characters. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since $balloon$ has $5$ different characters. diff --git a/articles/maximum-number-of-points-with-cost.md b/articles/maximum-number-of-points-with-cost.md new file mode 100644 index 000000000..9eb2dd62b --- /dev/null +++ b/articles/maximum-number-of-points-with-cost.md @@ -0,0 +1,630 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def maxPoints(self, points: List[List[int]]) -> int: + m, n = len(points), len(points[0]) + + def dfs(r, c): + if r == m - 1: + return 0 + + res = 0 + for col in range(n): + res = max(res, points[r + 1][col] - abs(col - c) + dfs(r + 1, col)) + return res + + ans = 0 + for c in range(n): + ans = max(ans, points[0][c] + dfs(0, c)) + return ans +``` + +```java +public class Solution { + int m, n; + int[][] points; + + long dfs(int r, int c) { + if (r == m - 1) return 0; + long res = 0; + for (int col = 0; col < n; col++) { + res = Math.max(res, points[r + 1][col] - Math.abs(col - c) + dfs(r + 1, col)); + } + return res; + } + + public long maxPoints(int[][] points) { + this.m = points.length; + this.n = points[0].length; + this.points = points; + long ans = 0; + for (int c = 0; c < n; c++) { + ans = Math.max(ans, points[0][c] + dfs(0, c)); + } + return ans; + } +} +``` + +```cpp +class Solution { +public: + int m, n; + vector> points; + + long long dfs(int r, int c) { + if (r == m - 1) return 0; + long long res = 0; + for (int col = 0; col < n; col++) { + res = max(res, points[r + 1][col] - abs(col - c) + dfs(r + 1, col)); + } + return res; + } + + long long maxPoints(vector>& points) { + this->points = points; + m = points.size(); + n = points[0].size(); + long long ans = 0; + for (int c = 0; c < n; c++) { + ans = max(ans, points[0][c] + dfs(0, c)); + } + return ans; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + maxPoints(points) { + let m = points.length, n = points[0].length; + + function dfs(r, c) { + if (r === m - 1) return 0; + let res = 0; + for (let col = 0; col < n; col++) { + res = Math.max(res, points[r + 1][col] - Math.abs(col - c) + dfs(r + 1, col)); + } + return res; + } + + let ans = 0; + for (let c = 0; c < n; c++) { + ans = Math.max(ans, points[0][c] + dfs(0, c)); + } + return ans; + } +} +``` + +```csharp +public class Solution { + int m, n; + int[][] points; + + long Dfs(int r, int c) { + if (r == m - 1) return 0; + long res = 0; + for (int col = 0; col < n; col++) { + res = Math.Max(res, points[r + 1][col] - Math.Abs(col - c) + Dfs(r + 1, col)); + } + return res; + } + + public long MaxPoints(int[][] points) { + this.points = points; + m = points.Length; + n = points[0].Length; + long ans = 0; + for (int c = 0; c < n; c++) { + ans = Math.Max(ans, points[0][c] + Dfs(0, c)); + } + return ans; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ m)$ +* Space complexity: $O(m)$ for recursion stack. + +> Where $m$ is the number of rows, and $n$ is the number of columns. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def maxPoints(self, points: List[List[int]]) -> int: + m, n = len(points), len(points[0]) + memo = {} + + def dfs(r, c): + if (r, c) in memo: + return memo[(r, c)] + if r == m - 1: + return 0 + + res = 0 + for col in range(n): + res = max(res, points[r + 1][col] - abs(col - c) + dfs(r + 1, col)) + + memo[(r, c)] = res + return res + + ans = 0 + for c in range(n): + ans = max(ans, points[0][c] + dfs(0, c)) + return ans +``` + +```java +class Solution { + int m, n; + int[][] points; + Long[][] memo; + + long dfs(int r, int c) { + if (memo[r][c] != null) return memo[r][c]; + if (r == m - 1) return 0; + + long res = 0; + for (int col = 0; col < n; col++) { + res = Math.max(res, points[r + 1][col] - Math.abs(col - c) + dfs(r + 1, col)); + } + return memo[r][c] = res; + } + + public long maxPoints(int[][] points) { + this.points = points; + m = points.length; + n = points[0].length; + memo = new Long[m][n]; + long ans = 0; + for (int c = 0; c < n; c++) { + ans = Math.max(ans, points[0][c] + dfs(0, c)); + } + return ans; + } +} +``` + +```cpp +class Solution { +public: + int m, n; + vector> points; + vector> memo; + + long long dfs(int r, int c) { + if (memo[r][c] != -1) return memo[r][c]; + if (r == m - 1) return 0; + + long long res = 0; + for (int col = 0; col < n; col++) { + res = max(res, (long long)points[r + 1][col] - abs(col - c) + dfs(r + 1, col)); + } + return memo[r][c] = res; + } + + long long maxPoints(vector>& points) { + this->points = points; + m = points.size(); + n = points[0].size(); + memo.assign(m, vector(n, -1)); + long long ans = 0; + for (int c = 0; c < n; c++) { + ans = max(ans, (long long)points[0][c] + dfs(0, c)); + } + return ans; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + maxPoints(points) { + let m = points.length, n = points[0].length; + let memo = {}; + + function dfs(r, c) { + let key = r + "," + c; + if (key in memo) return memo[key]; + if (r === m - 1) return 0; + + let res = 0; + for (let col = 0; col < n; col++) { + res = Math.max(res, points[r + 1][col] - Math.abs(col - c) + dfs(r + 1, col)); + } + return memo[key] = res; + } + + let ans = 0; + for (let c = 0; c < n; c++) { + ans = Math.max(ans, points[0][c] + dfs(0, c)); + } + return ans; + } +} +``` + +```csharp +public class Solution { + int m, n; + int[][] points; + long[,] memo; + + long Dfs(int r, int c) { + if (memo[r, c] != -1) return memo[r, c]; + if (r == m - 1) return 0; + + long res = 0; + for (int col = 0; col < n; col++) { + res = Math.Max(res, points[r + 1][col] - Math.Abs(col - c) + Dfs(r + 1, col)); + } + memo[r, c] = res; + return res; + } + + public long MaxPoints(int[][] points) { + this.points = points; + m = points.Length; + n = points[0].Length; + memo = new long[m, n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + memo[i, j] = -1; + } + } + long ans = 0; + for (int c = 0; c < n; c++) { + ans = Math.Max(ans, points[0][c] + Dfs(0, c)); + } + return ans; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n ^ 2)$ +* Space complexity: $O(n)$ + +> Where $m$ is the number of rows, and $n$ is the number of columns. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def maxPoints(self, points: List[List[int]]) -> int: + ROWS, COLS = len(points), len(points[0]) + dp = points[0] + + for r in range(1, ROWS): + left = [0] * COLS + left[0] = dp[0] + for c in range(1, COLS): + left[c] = max(dp[c], left[c - 1] - 1) + + right = [0] * COLS + right[COLS - 1] = dp[COLS - 1] + for c in range(COLS - 2, -1, -1): + right[c] = max(dp[c], right[c + 1] - 1) + + nextDp = points[r][:] + for c in range(COLS): + nextDp[c] += max(left[c], right[c]) + + dp = nextDp + + return max(dp) +``` + +```java +public class Solution { + public long maxPoints(int[][] points) { + int ROWS = points.length, COLS = points[0].length; + long[] dp = new long[COLS]; + for (int c = 0; c < COLS; c++) dp[c] = points[0][c]; + + for (int r = 1; r < ROWS; r++) { + long[] left = new long[COLS]; + left[0] = dp[0]; + for (int c = 1; c < COLS; c++) + left[c] = Math.max(dp[c], left[c - 1] - 1); + + long[] right = new long[COLS]; + right[COLS - 1] = dp[COLS - 1]; + for (int c = COLS - 2; c >= 0; c--) + right[c] = Math.max(dp[c], right[c + 1] - 1); + + long[] nextDp = new long[COLS]; + for (int c = 0; c < COLS; c++) + nextDp[c] = points[r][c] + Math.max(left[c], right[c]); + + dp = nextDp; + } + + long ans = 0; + for (long val : dp) ans = Math.max(ans, val); + return ans; + } +} +``` + +```cpp +class Solution { +public: + long long maxPoints(vector>& points) { + int ROWS = points.size(), COLS = points[0].size(); + vector dp(points[0].begin(), points[0].end()); + + for (int r = 1; r < ROWS; r++) { + vector left(COLS), right(COLS); + left[0] = dp[0]; + for (int c = 1; c < COLS; c++) + left[c] = max(dp[c], left[c - 1] - 1); + + right[COLS - 1] = dp[COLS - 1]; + for (int c = COLS - 2; c >= 0; c--) + right[c] = max(dp[c], right[c + 1] - 1); + + vector nextDp(COLS); + for (int c = 0; c < COLS; c++) + nextDp[c] = points[r][c] + max(left[c], right[c]); + + dp = move(nextDp); + } + + return *max_element(dp.begin(), dp.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + maxPoints(points) { + let ROWS = points.length, COLS = points[0].length; + let dp = [...points[0]]; + + for (let r = 1; r < ROWS; r++) { + let left = Array(COLS).fill(0); + left[0] = dp[0]; + for (let c = 1; c < COLS; c++) + left[c] = Math.max(dp[c], left[c - 1] - 1); + + let right = Array(COLS).fill(0); + right[COLS - 1] = dp[COLS - 1]; + for (let c = COLS - 2; c >= 0; c--) + right[c] = Math.max(dp[c], right[c + 1] - 1); + + let nextDp = [...points[r]]; + for (let c = 0; c < COLS; c++) + nextDp[c] += Math.max(left[c], right[c]); + + dp = nextDp; + } + + return Math.max(...dp); + } +} +``` + +```csharp +public class Solution { + public long MaxPoints(int[][] points) { + int ROWS = points.Length, COLS = points[0].Length; + long[] dp = new long[COLS]; + for (int c = 0; c < COLS; c++) dp[c] = points[0][c]; + + for (int r = 1; r < ROWS; r++) { + long[] left = new long[COLS]; + left[0] = dp[0]; + for (int c = 1; c < COLS; c++) + left[c] = Math.Max(dp[c], left[c - 1] - 1); + + long[] right = new long[COLS]; + right[COLS - 1] = dp[COLS - 1]; + for (int c = COLS - 2; c >= 0; c--) + right[c] = Math.Max(dp[c], right[c + 1] - 1); + + long[] nextDp = new long[COLS]; + for (int c = 0; c < COLS; c++) + nextDp[c] = points[r][c] + Math.Max(left[c], right[c]); + + dp = nextDp; + } + + long ans = 0; + foreach (long val in dp) ans = Math.Max(ans, val); + return ans; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(n)$ + +> Where $m$ is the number of rows, and $n$ is the number of columns. + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def maxPoints(self, points: List[List[int]]) -> int: + ROWS, COLS = len(points), len(points[0]) + prev = points[0] + + for r in range(1, ROWS): + cur = [0] * COLS + cur[0] = prev[0] + for c in range(1, COLS): + cur[c] = max(prev[c], cur[c - 1] - 1) + + rightMax = prev[COLS - 1] + for c in range(COLS - 2, -1 , -1): + rightMax = max(prev[c], rightMax - 1) + cur[c] = max(cur[c], rightMax) + points[r][c] + + cur[COLS - 1] += points[r][COLS - 1] + prev = cur + + return max(prev) +``` + +```java +public class Solution { + public long maxPoints(int[][] points) { + int rows = points.length, cols = points[0].length; + long[] prev = new long[cols]; + for (int c = 0; c < cols; c++) prev[c] = points[0][c]; + + for (int r = 1; r < rows; r++) { + long[] cur = new long[cols]; + cur[0] = prev[0]; + for (int c = 1; c < cols; c++) + cur[c] = Math.max(prev[c], cur[c - 1] - 1); + + long rightMax = prev[cols - 1]; + for (int c = cols - 2; c >= 0; c--) { + rightMax = Math.max(prev[c], rightMax - 1); + cur[c] = Math.max(cur[c], rightMax) + points[r][c]; + } + cur[cols - 1] += points[r][cols - 1]; + prev = cur; + } + + long ans = 0; + for (long val : prev) ans = Math.max(ans, val); + return ans; + } +} +``` + +```cpp +class Solution { +public: + long long maxPoints(vector>& points) { + int rows = points.size(), cols = points[0].size(); + vector prev(cols); + for (int c = 0; c < cols; c++) prev[c] = points[0][c]; + + for (int r = 1; r < rows; r++) { + vector cur(cols); + cur[0] = prev[0]; + for (int c = 1; c < cols; c++) + cur[c] = max(prev[c], cur[c - 1] - 1); + + long long rightMax = prev[cols - 1]; + for (int c = cols - 2; c >= 0; c--) { + rightMax = max(prev[c], rightMax - 1); + cur[c] = max(cur[c], rightMax) + points[r][c]; + } + cur[cols - 1] += points[r][cols - 1]; + prev = cur; + } + return *max_element(prev.begin(), prev.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + maxPoints(points) { + let rows = points.length, cols = points[0].length; + let prev = points[0].map(v => v); + + for (let r = 1; r < rows; r++) { + let cur = Array(cols).fill(0); + cur[0] = prev[0]; + for (let c = 1; c < cols; c++) + cur[c] = Math.max(prev[c], cur[c - 1] - 1); + + let rightMax = prev[cols - 1]; + for (let c = cols - 2; c >= 0; c--) { + rightMax = Math.max(prev[c], rightMax - 1); + cur[c] = Math.max(cur[c], rightMax) + points[r][c]; + } + cur[cols - 1] += points[r][cols - 1]; + prev = cur; + } + return Math.max(...prev); + } +} +``` + +```csharp +public class Solution { + public long MaxPoints(int[][] points) { + int rows = points.Length, cols = points[0].Length; + long[] prev = new long[cols]; + for (int c = 0; c < cols; c++) prev[c] = points[0][c]; + + for (int r = 1; r < rows; r++) { + long[] cur = new long[cols]; + cur[0] = prev[0]; + for (int c = 1; c < cols; c++) + cur[c] = Math.Max(prev[c], cur[c - 1] - 1); + + long rightMax = prev[cols - 1]; + for (int c = cols - 2; c >= 0; c--) { + rightMax = Math.Max(prev[c], rightMax - 1); + cur[c] = Math.Max(cur[c], rightMax) + points[r][c]; + } + cur[cols - 1] += points[r][cols - 1]; + prev = cur; + } + long ans = long.MinValue; + foreach (long val in prev) ans = Math.Max(ans, val); + return ans; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(n)$ + +> Where $m$ is the number of rows, and $n$ is the number of columns. \ No newline at end of file diff --git a/articles/maximum-number-of-removable-characters.md b/articles/maximum-number-of-removable-characters.md new file mode 100644 index 000000000..efba78ca4 --- /dev/null +++ b/articles/maximum-number-of-removable-characters.md @@ -0,0 +1,459 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maximumRemovals(self, s: str, p: str, removable: List[int]) -> int: + n, m = len(s), len(p) + marked = set() + res = 0 + + for removeIdx in removable: + marked.add(removeIdx) + + sIdx = pIdx = 0 + while pIdx < m and sIdx < n: + if sIdx not in marked and s[sIdx] == p[pIdx]: + pIdx += 1 + sIdx += 1 + if pIdx != m: + break + res += 1 + + return res +``` + +```java +public class Solution { + public int maximumRemovals(String s, String p, int[] removable) { + int n = s.length(), m = p.length(); + Set marked = new HashSet<>(); + int res = 0; + + for (int removeIdx : removable) { + marked.add(removeIdx); + + int sIdx = 0, pIdx = 0; + while (pIdx < m && sIdx < n) { + if (!marked.contains(sIdx) && s.charAt(sIdx) == p.charAt(pIdx)) { + pIdx++; + } + sIdx++; + } + + if (pIdx != m) break; + res++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximumRemovals(string s, string p, vector& removable) { + int n = s.size(), m = p.size(); + unordered_set marked; + int res = 0; + + for (int removeIdx : removable) { + marked.insert(removeIdx); + + int sIdx = 0, pIdx = 0; + while (pIdx < m && sIdx < n) { + if (marked.find(sIdx) == marked.end() && s[sIdx] == p[pIdx]) { + pIdx++; + } + sIdx++; + } + + if (pIdx != m) break; + res++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} p + * @param {number[]} removable + * @return {number} + */ + maximumRemovals(s, p, removable) { + let n = s.length, + m = p.length; + let marked = new Set(); + let res = 0; + + for (let removeIdx of removable) { + marked.add(removeIdx); + + let sIdx = 0, + pIdx = 0; + while (pIdx < m && sIdx < n) { + if (!marked.has(sIdx) && s[sIdx] === p[pIdx]) { + pIdx++; + } + sIdx++; + } + + if (pIdx !== m) break; + res++; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(k * (n + m))$ +- Space complexity: $O(k)$ + +> Where $n$ and $m$ are the lengths of the given strings $s$ and $p$ respectively. $k$ is the size of the array $removable$. + +--- + +## 2. Binary Search + Hash Set + +::tabs-start + +```python +class Solution: + def maximumRemovals(self, s: str, p: str, removable: List[int]) -> int: + def isSubseq(s, subseq, removed): + i1 = i2 = 0 + while i1 < len(s) and i2 < len(subseq): + if i1 in removed or s[i1] != subseq[i2]: + i1 += 1 + continue + i1 += 1 + i2 += 1 + return i2 == len(subseq) + + res = 0 + l, r = 0, len(removable) - 1 + while l <= r: + m = (l + r) // 2 + removed = set(removable[:m + 1]) + if isSubseq(s, p, removed): + res = max(res, m + 1) + l = m + 1 + else: + r = m - 1 + + return res +``` + +```java +public class Solution { + public int maximumRemovals(String s, String p, int[] removable) { + int res = 0, l = 0, r = removable.length - 1; + + while (l <= r) { + int m = (l + r) / 2; + Set removed = new HashSet<>(); + for (int i = 0; i <= m; i++) { + removed.add(removable[i]); + } + + if (isSubseq(s, p, removed)) { + res = Math.max(res, m + 1); + l = m + 1; + } else { + r = m - 1; + } + } + + return res; + } + + private boolean isSubseq(String s, String subseq, Set removed) { + int i1 = 0, i2 = 0; + while (i1 < s.length() && i2 < subseq.length()) { + if (removed.contains(i1) || s.charAt(i1) != subseq.charAt(i2)) { + i1++; + continue; + } + i1++; + i2++; + } + return i2 == subseq.length(); + } +} +``` + +```cpp +class Solution { +public: + int maximumRemovals(string s, string p, vector& removable) { + int res = 0, l = 0, r = removable.size() - 1; + + while (l <= r) { + int m = (l + r) / 2; + unordered_set removed(removable.begin(), removable.begin() + m + 1); + + if (isSubseq(s, p, removed)) { + res = max(res, m + 1); + l = m + 1; + } else { + r = m - 1; + } + } + + return res; + } + +private: + bool isSubseq(string& s, string& subseq, unordered_set& removed) { + int i1 = 0, i2 = 0; + while (i1 < s.size() && i2 < subseq.size()) { + if (removed.count(i1) || s[i1] != subseq[i2]) { + i1++; + continue; + } + i1++; + i2++; + } + return i2 == subseq.size(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} p + * @param {number[]} removable + * @return {number} + */ + maximumRemovals(s, p, removable) { + let res = 0, + l = 0, + r = removable.length - 1; + + while (l <= r) { + let m = Math.floor((l + r) / 2); + let removed = new Set(removable.slice(0, m + 1)); + + if (this.isSubseq(s, p, removed)) { + res = Math.max(res, m + 1); + l = m + 1; + } else { + r = m - 1; + } + } + + return res; + } + + /** + * @param {string} s + * @param {string} subseq + * @param {Set} removed + * @return {boolean} + */ + isSubseq(s, subseq, removed) { + let i1 = 0, + i2 = 0; + while (i1 < s.length && i2 < subseq.length) { + if (removed.has(i1) || s[i1] !== subseq[i2]) { + i1++; + continue; + } + i1++; + i2++; + } + return i2 === subseq.length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O((n + m) * \log k)$ +- Space complexity: $O(k)$ + +> Where $n$ and $m$ are the lengths of the given strings $s$ and $p$ respectively. $k$ is the size of the array $removable$. + +--- + +## 3. Binary Search + +::tabs-start + +```python +class Solution: + def maximumRemovals(self, s: str, p: str, removable: List[int]) -> int: + l, r = 0, len(removable) + n, m = len(s), len(p) + + def isSubseq(tmpS): + i1 = i2 = 0 + while i1 < n and i2 < m: + if tmpS[i1] == p[i2]: + i2 += 1 + i1 += 1 + return i2 == m + + while l < r: + mid = l + (r - l) // 2 + tmpS = list(s) + + for i in range(mid + 1): + tmpS[removable[i]] = '#' + + if isSubseq(tmpS): + l = mid + 1 + else: + r = mid + + return l +``` + +```java +public class Solution { + public int maximumRemovals(String s, String p, int[] removable) { + int l = 0, r = removable.length; + int n = s.length(), m = p.length(); + + while (l < r) { + int mid = l + (r - l) / 2; + char[] tmpS = s.toCharArray(); + + for (int i = 0; i <= mid; i++) { + tmpS[removable[i]] = '#'; + } + + if (isSubseq(tmpS, p)) { + l = mid + 1; + } else { + r = mid; + } + } + + return l; + } + + private boolean isSubseq(char[] s, String p) { + int i1 = 0, i2 = 0, n = s.length, m = p.length(); + + while (i1 < n && i2 < m) { + if (s[i1] == p.charAt(i2)) { + i2++; + } + i1++; + } + return i2 == m; + } +} +``` + +```cpp +class Solution { +public: + int maximumRemovals(string s, string p, vector& removable) { + int l = 0, r = removable.size(); + int n = s.size(), m = p.size(); + + while (l < r) { + int mid = l + (r - l) / 2; + string tmpS = s; + + for (int i = 0; i <= mid; i++) { + tmpS[removable[i]] = '#'; + } + + if (isSubseq(tmpS, p)) { + l = mid + 1; + } else { + r = mid; + } + } + + return l; + } + +private: + bool isSubseq(const string& s, const string& p) { + int i1 = 0, i2 = 0, n = s.size(), m = p.size(); + + while (i1 < n && i2 < m) { + if (s[i1] == p[i2]) { + i2++; + } + i1++; + } + return i2 == m; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {string} p + * @param {number[]} removable + * @return {number} + */ + maximumRemovals(s, p, removable) { + let l = 0, + r = removable.length; + let n = s.length, + m = p.length; + + const isSubseq = (tmpS) => { + let i1 = 0, + i2 = 0; + while (i1 < n && i2 < m) { + if (tmpS[i1] === p[i2]) { + i2++; + } + i1++; + } + return i2 === m; + }; + + while (l < r) { + let mid = Math.floor(l + (r - l) / 2); + let tmpS = s.split(''); + + for (let i = 0; i <= mid; i++) { + tmpS[removable[i]] = '#'; + } + + if (isSubseq(tmpS)) { + l = mid + 1; + } else { + r = mid; + } + } + + return l; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O((n + m) * \log k)$ +- Space complexity: $O(n)$ + +> Where $n$ and $m$ are the lengths of the given strings $s$ and $p$ respectively. $k$ is the size of the array $removable$. diff --git a/articles/maximum-number-of-vowels-in-a-substring-of-given-length.md b/articles/maximum-number-of-vowels-in-a-substring-of-given-length.md index 371aff2b3..9dd1f6645 100644 --- a/articles/maximum-number-of-vowels-in-a-substring-of-given-length.md +++ b/articles/maximum-number-of-vowels-in-a-substring-of-given-length.md @@ -13,7 +13,7 @@ class Solution: for j in range(i, i + k): cnt += 1 if s[j] in vowel else 0 res = max(res, cnt) - + return res ``` @@ -90,8 +90,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. --- @@ -106,11 +106,11 @@ class Solution: prefix = [0] * (len(s) + 1) for i in range(len(s)): prefix[i + 1] = prefix[i] + (1 if s[i] in vowel else 0) - + res = 0 for i in range(k, len(s) + 1): res = max(res, prefix[i] - prefix[i - k]) - + return res ``` @@ -184,8 +184,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -197,7 +197,7 @@ class Solution { class Solution: def maxVowels(self, s: str, k: int) -> int: vowel = {'a', 'e', 'i', 'o', 'u'} - + l = cnt = res = 0 for r in range(len(s)): cnt += 1 if s[r] in vowel else 0 @@ -212,7 +212,7 @@ class Solution: public class Solution { public int maxVowels(String s, int k) { Set vowels = Set.of('a', 'e', 'i', 'o', 'u'); - + int l = 0, cnt = 0, res = 0; for (int r = 0; r < s.length(); r++) { cnt += (vowels.contains(s.charAt(r)) ? 1 : 0); @@ -232,7 +232,7 @@ class Solution { public: int maxVowels(string s, int k) { unordered_set vowels = {'a', 'e', 'i', 'o', 'u'}; - + int l = 0, cnt = 0, res = 0; for (int r = 0; r < s.length(); r++) { cnt += (vowels.count(s[r]) ? 1 : 0); @@ -255,12 +255,14 @@ class Solution { */ maxVowels(s, k) { const vowels = new Set(['a', 'e', 'i', 'o', 'u']); - - let l = 0, cnt = 0, res = 0; + + let l = 0, + cnt = 0, + res = 0; for (let r = 0; r < s.length; r++) { - cnt += (vowels.has(s[r]) ? 1 : 0); + cnt += vowels.has(s[r]) ? 1 : 0; if (r - l + 1 > k) { - cnt -= (vowels.has(s[l++]) ? 1 : 0); + cnt -= vowels.has(s[l++]) ? 1 : 0; } res = Math.max(res, cnt); } @@ -273,8 +275,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -291,7 +293,7 @@ class Solution: mask = (1 << getId('a')) | (1 << getId('e')) | \ (1 << getId('i')) | (1 << getId('o')) | \ (1 << getId('u')) - + l = cnt = res = 0 for r in range(len(s)): cnt += ((mask >> getId(s[r])) & 1) @@ -305,8 +307,8 @@ class Solution: ```java public class Solution { public int maxVowels(String s, int k) { - int mask = (1 << ('a' - 'a')) | (1 << ('e' - 'a')) | - (1 << ('i' - 'a')) | (1 << ('o' - 'a')) | + int mask = (1 << ('a' - 'a')) | (1 << ('e' - 'a')) | + (1 << ('i' - 'a')) | (1 << ('o' - 'a')) | (1 << ('u' - 'a')); int l = 0, cnt = 0, res = 0; @@ -328,8 +330,8 @@ public class Solution { class Solution { public: int maxVowels(string s, int k) { - int mask = (1 << ('a' - 'a')) | (1 << ('e' - 'a')) | - (1 << ('i' - 'a')) | (1 << ('o' - 'a')) | + int mask = (1 << ('a' - 'a')) | (1 << ('e' - 'a')) | + (1 << ('i' - 'a')) | (1 << ('o' - 'a')) | (1 << ('u' - 'a')); int l = 0, cnt = 0, res = 0; @@ -356,13 +358,18 @@ class Solution { */ maxVowels(s, k) { const getId = (c) => { - return c.charCodeAt(0) - 'a'.charCodeAt(0); + return c.charCodeAt(0) - 'a'.charCodeAt(0); }; - const mask = (1 << getId('a')) | (1 << getId('e')) | - (1 << getId('i')) | (1 << getId('o')) | - (1 << getId('u')); - - let l = 0, cnt = 0, res = 0; + const mask = + (1 << getId('a')) | + (1 << getId('e')) | + (1 << getId('i')) | + (1 << getId('o')) | + (1 << getId('u')); + + let l = 0, + cnt = 0, + res = 0; for (let r = 0; r < s.length; r++) { cnt += (mask >> getId(s.charAt(r))) & 1; if (r - l + 1 > k) { @@ -381,5 +388,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/maximum-odd-binary-number.md b/articles/maximum-odd-binary-number.md index 41846d673..98add8b40 100644 --- a/articles/maximum-odd-binary-number.md +++ b/articles/maximum-odd-binary-number.md @@ -10,7 +10,7 @@ class Solution: i = len(s) - 1 while i >= 0 and s[i] == "0": i -= 1 - + s[i], s[len(s) - 1] = s[len(s) - 1], s[i] return ''.join(s) ``` @@ -57,7 +57,7 @@ public: while (i >= 0 && s[i] == '0') { i--; } - + swap(s[i], s[n - 1]); return s; } @@ -85,12 +85,30 @@ class Solution { } ``` +```csharp +public class Solution { + public string MaximumOddBinaryNumber(string s) { + char[] arr = s.ToCharArray(); + Array.Sort(arr); + Array.Reverse(arr); + int i = arr.Length - 1; + while (i >= 0 && arr[i] == '0') { + i--; + } + char temp = arr[i]; + arr[i] = arr[arr.Length - 1]; + arr[arr.Length - 1] = temp; + return new string(arr); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -105,7 +123,7 @@ class Solution: for c in s: if c == "1": count += 1 - + return (count - 1) * "1" + (len(s) - count) * "0" + "1" ``` @@ -116,12 +134,12 @@ public class Solution { for (char c : s.toCharArray()) { if (c == '1') count++; } - + StringBuilder result = new StringBuilder(); for (int i = 0; i < count - 1; i++) result.append('1'); for (int i = 0; i < s.length() - count; i++) result.append('0'); result.append('1'); - + return result.toString(); } } @@ -135,11 +153,11 @@ public: for (char c : s) { if (c == '1') count++; } - + string result((count - 1), '1'); result += string(s.length() - count, '0'); result += '1'; - + return result; } }; @@ -156,18 +174,32 @@ class Solution { for (const c of s) { if (c === '1') count++; } - + return '1'.repeat(count - 1) + '0'.repeat(s.length - count) + '1'; } } ``` +```csharp +public class Solution { + public string MaximumOddBinaryNumber(string s) { + int count = 0; + foreach (char c in s) { + if (c == '1') { + count++; + } + } + return new string('1', count - 1) + new string('0', s.Length - count) + "1"; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -226,7 +258,7 @@ public: left++; } } - + swap(arr[left - 1], arr[arr.size() - 1]); return string(arr.begin(), arr.end()); } @@ -250,15 +282,41 @@ class Solution { } } - [arr[left - 1], arr[arr.length - 1]] = [arr[arr.length - 1], arr[left - 1]]; + [arr[left - 1], arr[arr.length - 1]] = [ + arr[arr.length - 1], + arr[left - 1], + ]; return arr.join(''); } } ``` +```csharp +public class Solution { + public string MaximumOddBinaryNumber(string s) { + char[] arr = s.ToCharArray(); + int left = 0; + + for (int i = 0; i < arr.Length; i++) { + if (arr[i] == '1') { + char temp = arr[i]; + arr[i] = arr[left]; + arr[left] = temp; + left++; + } + } + char t = arr[left - 1]; + arr[left - 1] = arr[arr.Length - 1]; + arr[arr.Length - 1] = t; + + return new string(arr); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/maximum-performance-of-a-team.md b/articles/maximum-performance-of-a-team.md new file mode 100644 index 000000000..b51355ecd --- /dev/null +++ b/articles/maximum-performance-of-a-team.md @@ -0,0 +1,244 @@ +## 1. Brute Force (Recursion) + +::tabs-start + +```python +class Solution: + def maxPerformance(self, n: int, speed: List[int], efficiency: List[int], k: int) -> int: + MOD = 1000000007 + res = 0 + + def dfs(i, k, speedSum, minEff): + nonlocal res + res = max(res, speedSum * minEff) + if i == n or k == 0: + return + + dfs(i + 1, k, speedSum, minEff) + dfs(i + 1, k - 1, speedSum + speed[i], min(minEff, efficiency[i])) + + dfs(0, k, 0, float("inf")) + return res % MOD +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + private int[] speed, efficiency; + private int n; + private long res; + + public int maxPerformance(int n, int[] speed, int[] efficiency, int k) { + this.n = n; + this.speed = speed; + this.efficiency = efficiency; + this.res = 0; + + dfs(0, k, Integer.MAX_VALUE, 0); + return (int) (res % MOD); + } + + private void dfs(int i, int k, int minEff, long speedSum) { + res = Math.max(res, speedSum * minEff); + if (i == n || k == 0) return; + + dfs(i + 1, k, minEff, speedSum); + dfs(i + 1, k - 1, Math.min(minEff, efficiency[i]), speedSum + speed[i]); + } +} +``` + +```cpp +class Solution { +private: + static constexpr int MOD = 1000000007; + vector speed, efficiency; + int n; + long long res; + +public: + int maxPerformance(int n, vector& speed, vector& efficiency, int k) { + this->n = n; + this->speed = speed; + this->efficiency = efficiency; + res = 0; + + dfs(0, k, INT_MAX, 0); + return int(res % MOD); + } + +private: + void dfs(int i, int k, int minEff, long long speedSum) { + res = max(res, speedSum * minEff); + if (i == n || k == 0) return; + + dfs(i + 1, k, minEff, speedSum); + dfs(i + 1, k - 1, min(minEff, efficiency[i]), speedSum + speed[i]); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[]} speed + * @param {number[]} efficiency + * @param {number} k + * @return {number} + */ + maxPerformance(n, speed, efficiency, k) { + const MOD = 1000000007; + let res = 0; + + const dfs = (i, k, minEff, speedSum) => { + res = Math.max(res, minEff === Infinity ? 0 : speedSum * minEff); + if (i === n || k === 0) return; + + dfs(i + 1, k, minEff, speedSum); + dfs( + i + 1, + k - 1, + Math.min(minEff, efficiency[i]), + speedSum + speed[i], + ); + }; + + dfs(0, k, Infinity, 0); + return res % MOD; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Sorting + Min-Heap + +::tabs-start + +```python +class Solution: + def maxPerformance(self, n: int, speed: List[int], efficiency: List[int], k: int) -> int: + MOD = 10**9 + 7 + eng = sorted(zip(efficiency, speed), reverse=True) + + res = speedSum = 0 + minHeap = [] + + for eff, spd in eng: + if len(minHeap) == k: + speedSum -= heapq.heappop(minHeap) + speedSum += spd + heapq.heappush(minHeap, spd) + res = max(res, eff * speedSum) + + return res % MOD +``` + +```java +public class Solution { + public int maxPerformance(int n, int[] speed, int[] efficiency, int k) { + final int MOD = 1_000_000_007; + int[][] engineers = new int[n][2]; + + for (int i = 0; i < n; i++) { + engineers[i] = new int[]{efficiency[i], speed[i]}; + } + + Arrays.sort(engineers, (a, b) -> Integer.compare(b[0], a[0])); + + PriorityQueue minHeap = new PriorityQueue<>(); + long speedSum = 0, res = 0; + + for (int[] eng : engineers) { + if (minHeap.size() == k) { + speedSum -= minHeap.poll(); + } + speedSum += eng[1]; + minHeap.offer(eng[1]); + res = Math.max(res, speedSum * eng[0]); + } + + return (int) (res % MOD); + } +} +``` + +```cpp +class Solution { +public: + int maxPerformance(int n, vector& speed, vector& efficiency, int k) { + constexpr int MOD = 1'000'000'007; + vector> engineers; + + for (int i = 0; i < n; i++) { + engineers.emplace_back(efficiency[i], speed[i]); + } + + sort(engineers.rbegin(), engineers.rend()); + + priority_queue, greater> minHeap; + long long speedSum = 0, res = 0; + + for (const auto& [eff, spd] : engineers) { + if (minHeap.size() == k) { + speedSum -= minHeap.top(); + minHeap.pop(); + } + speedSum += spd; + minHeap.push(spd); + res = max(res, speedSum * eff); + } + + return res % MOD; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[]} speed + * @param {number[]} efficiency + * @param {number} k + * @return {number} + */ + maxPerformance(n, speed, efficiency, k) { + const MOD = BigInt(1e9 + 7); + const engineers = efficiency.map((eff, i) => [eff, speed[i]]); + engineers.sort((a, b) => b[0] - a[0]); + + const minHeap = new MinPriorityQueue(); + let speedSum = BigInt(0), + res = BigInt(0); + + for (const [eff, spd] of engineers) { + if (minHeap.size() === k) { + speedSum -= BigInt(minHeap.dequeue()); + } + speedSum += BigInt(spd); + minHeap.enqueue(spd); + res = res > speedSum * BigInt(eff) ? res : speedSum * BigInt(eff); + } + + return Number(res % MOD); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * (\log n + \log k))$ +- Space complexity: $O(n + k)$ + +> Where $n$ is the number of engineers and $k$ is the maximum number of engineers that can be selected. diff --git a/articles/maximum-points-you-can-obtain-from-cards.md b/articles/maximum-points-you-can-obtain-from-cards.md new file mode 100644 index 000000000..87d28bbd8 --- /dev/null +++ b/articles/maximum-points-you-can-obtain-from-cards.md @@ -0,0 +1,463 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maxScore(self, cardPoints: List[int], k: int) -> int: + n = len(cardPoints) + res = 0 + + for left in range(k + 1): + leftSum = sum(cardPoints[:left]) + rightSum = sum(cardPoints[n - (k - left):]) + res = max(res, leftSum + rightSum) + + return res +``` + +```java +public class Solution { + public int maxScore(int[] cardPoints, int k) { + int n = cardPoints.length; + int res = 0; + + for (int left = 0; left <= k; left++) { + int leftSum = 0; + for (int i = 0; i < left; i++) { + leftSum += cardPoints[i]; + } + + int rightSum = 0; + for (int i = n - (k - left); i < n; i++) { + rightSum += cardPoints[i]; + } + + res = Math.max(res, leftSum + rightSum); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& cardPoints, int k) { + int n = cardPoints.size(); + int res = 0; + + for (int left = 0; left <= k; left++) { + int leftSum = 0; + for (int i = 0; i < left; i++) { + leftSum += cardPoints[i]; + } + + int rightSum = 0; + for (int i = n - (k - left); i < n; i++) { + rightSum += cardPoints[i]; + } + + res = max(res, leftSum + rightSum); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} cardPoints + * @param {number} k + * @return {number} + */ + maxScore(cardPoints, k) { + let n = cardPoints.length; + let res = 0; + + for (let left = 0; left <= k; left++) { + let leftSum = 0; + for (let i = 0; i < left; i++) { + leftSum += cardPoints[i]; + } + + let rightSum = 0; + for (let i = n - (k - left); i < n; i++) { + rightSum += cardPoints[i]; + } + + res = Math.max(res, leftSum + rightSum); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(k ^ 2)$ +- Space complexity: $O(1)$ extra space. + +> Where $k$ is the number of cards to pick. + +--- + +## 2. Prefix & Suffix Sums + +::tabs-start + +```python +class Solution: + def maxScore(self, cardPoints: List[int], k: int) -> int: + n = len(cardPoints) + + prefix = [0] * (n + 1) + for i in range(n): + prefix[i + 1] = prefix[i] + cardPoints[i] + + suffix = [0] * (n + 1) + for i in range(n - 1, -1, -1): + suffix[i] = suffix[i + 1] + cardPoints[i] + + res = 0 + for left in range(k + 1): + right = k - left + res = max(res, prefix[left] + suffix[n - right]) + + return res +``` + +```java +public class Solution { + public int maxScore(int[] cardPoints, int k) { + int n = cardPoints.length; + + int[] prefix = new int[n + 1]; + for (int i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + cardPoints[i]; + } + + int[] suffix = new int[n + 1]; + for (int i = n - 1; i >= 0; i--) { + suffix[i] = suffix[i + 1] + cardPoints[i]; + } + + int res = 0; + for (int left = 0; left <= k; left++) { + int right = k - left; + res = Math.max(res, prefix[left] + suffix[n - right]); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& cardPoints, int k) { + int n = cardPoints.size(); + + vector prefix(n + 1, 0); + for (int i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + cardPoints[i]; + } + + vector suffix(n + 1, 0); + for (int i = n - 1; i >= 0; i--) { + suffix[i] = suffix[i + 1] + cardPoints[i]; + } + + int res = 0; + for (int left = 0; left <= k; left++) { + int right = k - left; + res = max(res, prefix[left] + suffix[n - right]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} cardPoints + * @param {number} k + * @return {number} + */ + maxScore(cardPoints, k) { + let n = cardPoints.length; + + let prefix = new Array(n + 1).fill(0); + for (let i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + cardPoints[i]; + } + + let suffix = new Array(n + 1).fill(0); + for (let i = n - 1; i >= 0; i--) { + suffix[i] = suffix[i + 1] + cardPoints[i]; + } + + let res = 0; + for (let left = 0; left <= k; left++) { + let right = k - left; + res = Math.max(res, prefix[left] + suffix[n - right]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Sliding Window (Minimum Sum Window) + +::tabs-start + +```python +class Solution: + def maxScore(self, cardPoints: List[int], k: int) -> int: + n = len(cardPoints) + windowSize = n - k + + if windowSize == 0: + return sum(cardPoints) + + total = 0 + minWindowSum = float("inf") + curSum = 0 + + for i in range(n): + total += cardPoints[i] + curSum += cardPoints[i] + if i >= windowSize - 1: + minWindowSum = min(minWindowSum, curSum) + curSum -= cardPoints[i - windowSize + 1] + + return total - minWindowSum +``` + +```java +public class Solution { + public int maxScore(int[] cardPoints, int k) { + int n = cardPoints.length; + int windowSize = n - k; + + if (windowSize == 0) { + int sum = 0; + for (int num : cardPoints) sum += num; + return sum; + } + + int total = 0; + int minWindowSum = Integer.MAX_VALUE; + int curSum = 0; + + for (int i = 0; i < n; i++) { + total += cardPoints[i]; + curSum += cardPoints[i]; + if (i >= windowSize - 1) { + minWindowSum = Math.min(minWindowSum, curSum); + curSum -= cardPoints[i - windowSize + 1]; + } + } + + return total - minWindowSum; + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& cardPoints, int k) { + int n = cardPoints.size(); + int windowSize = n - k; + + if (windowSize == 0) { + return accumulate(cardPoints.begin(), cardPoints.end(), 0); + } + + int total = 0; + int minWindowSum = INT_MAX; + int curSum = 0; + + for (int i = 0; i < n; i++) { + total += cardPoints[i]; + curSum += cardPoints[i]; + if (i >= windowSize - 1) { + minWindowSum = min(minWindowSum, curSum); + curSum -= cardPoints[i - windowSize + 1]; + } + } + + return total - minWindowSum; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} cardPoints + * @param {number} k + * @return {number} + */ + maxScore(cardPoints, k) { + let n = cardPoints.length; + let windowSize = n - k; + + if (windowSize === 0) { + return cardPoints.reduce((sum, num) => sum + num, 0); + } + + let total = 0; + let minWindowSum = Infinity; + let curSum = 0; + + for (let i = 0; i < n; i++) { + total += cardPoints[i]; + curSum += cardPoints[i]; + if (i >= windowSize - 1) { + minWindowSum = Math.min(minWindowSum, curSum); + curSum -= cardPoints[i - windowSize + 1]; + } + } + + return total - minWindowSum; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 4. Sliding Window + +::tabs-start + +```python +class Solution: + def maxScore(self, cardPoints: List[int], k: int) -> int: + l, r = 0, len(cardPoints) - k + total = sum(cardPoints[r:]) + res = total + + while r < len(cardPoints): + total += cardPoints[l] - cardPoints[r] + res = max(res, total) + l += 1 + r += 1 + + return res +``` + +```java +public class Solution { + public int maxScore(int[] cardPoints, int k) { + int l = 0, r = cardPoints.length - k; + int total = 0; + + for (int i = r; i < cardPoints.length; i++) { + total += cardPoints[i]; + } + + int res = total; + + while (r < cardPoints.length) { + total += cardPoints[l] - cardPoints[r]; + res = Math.max(res, total); + l++; + r++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxScore(vector& cardPoints, int k) { + int l = 0, r = cardPoints.size() - k; + int total = 0; + + for (int i = r; i < cardPoints.size(); i++) { + total += cardPoints[i]; + } + + int res = total; + + while (r < cardPoints.size()) { + total += cardPoints[l] - cardPoints[r]; + res = max(res, total); + l++; + r++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} cardPoints + * @param {number} k + * @return {number} + */ + maxScore(cardPoints, k) { + let l = 0, + r = cardPoints.length - k; + let total = 0; + + for (let i = r; i < cardPoints.length; i++) { + total += cardPoints[i]; + } + + let res = total; + + while (r < cardPoints.length) { + total += cardPoints[l] - cardPoints[r]; + res = Math.max(res, total); + l++; + r++; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(k)$ +- Space complexity: $O(1)$ extra space. + +> Where $k$ is the number of cards to pick. diff --git a/articles/maximum-product-difference-between-two-pairs.md b/articles/maximum-product-difference-between-two-pairs.md index e5425c2f8..1f5f4ce9d 100644 --- a/articles/maximum-product-difference-between-two-pairs.md +++ b/articles/maximum-product-difference-between-two-pairs.md @@ -76,7 +76,10 @@ class Solution { if (a === c || b === c) continue; for (let d = 0; d < n; d++) { if (a === d || b === d || c === d) continue; - res = Math.max(res, nums[a] * nums[b] - nums[c] * nums[d]); + res = Math.max( + res, + nums[a] * nums[b] - nums[c] * nums[d], + ); } } } @@ -90,8 +93,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 4)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 4)$ +- Space complexity: $O(1)$ --- @@ -133,7 +136,9 @@ class Solution { */ maxProductDifference(nums) { nums.sort((a, b) => a - b); - return nums[nums.length - 1] * nums[nums.length - 2] - nums[0] * nums[1]; + return ( + nums[nums.length - 1] * nums[nums.length - 2] - nums[0] * nums[1] + ); } } ``` @@ -142,8 +147,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -166,7 +171,7 @@ class Solution: min1, min2 = num, min1 elif num < min2: min2 = num - + return (max1 * max2) - (min1 * min2) ``` @@ -226,8 +231,10 @@ class Solution { * @return {number} */ maxProductDifference(nums) { - let max1 = 0, max2 = 0; - let min1 = Infinity, min2 = Infinity; + let max1 = 0, + max2 = 0; + let min1 = Infinity, + min2 = Infinity; for (const num of nums) { if (num > max1) { max2 = max1; @@ -242,7 +249,7 @@ class Solution { min2 = num; } } - return (max1 * max2) - (min1 * min2); + return max1 * max2 - min1 * min2; } } ``` @@ -251,5 +258,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/maximum-product-of-the-length-of-two-palindromic-subsequences.md b/articles/maximum-product-of-the-length-of-two-palindromic-subsequences.md index bd17730e3..5aaccd7a7 100644 --- a/articles/maximum-product-of-the-length-of-two-palindromic-subsequences.md +++ b/articles/maximum-product-of-the-length-of-two-palindromic-subsequences.md @@ -21,11 +21,11 @@ class Solution: if isPal(seq1) and isPal(seq2): res = max(res, len(seq1) * len(seq2)) return - + rec(i + 1, seq1, seq2) rec(i + 1, seq1 + s[i], seq2) rec(i + 1, seq1, seq2 + s[i]) - + rec(0, "", "") return res ``` @@ -115,7 +115,8 @@ class Solution { */ maxProduct(s) { const isPal = (str) => { - let i = 0, j = str.length - 1; + let i = 0, + j = str.length - 1; while (i < j) { if (str[i] !== str[j]) return false; i++; @@ -139,7 +140,7 @@ class Solution { rec(i + 1, seq1, seq2 + s[i]); }; - rec(0, "", ""); + rec(0, '', ''); return res; } } @@ -149,8 +150,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * 3 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * 3 ^ n)$ +- Space complexity: $O(n)$ --- @@ -177,16 +178,16 @@ class Solution: for i in range(N): if mask & (1 << i): subseq += s[i] - + if isPal(subseq): pali[mask] = len(subseq) - + res = 0 for m1 in pali: for m2 in pali: if m1 & m2 == 0: res = max(res, pali[m1] * pali[m2]) - + return res ``` @@ -290,7 +291,8 @@ class Solution { */ maxProduct(s) { const isPal = (str) => { - let i = 0, j = str.length - 1; + let i = 0, + j = str.length - 1; while (i < j) { if (str[i] !== str[j]) return false; i++; @@ -298,13 +300,13 @@ class Solution { } return true; }; - + const N = s.length; let res = 0; const pali = new Map(); - for (let mask = 1; mask < (1 << N); mask++) { - let subseq = ""; + for (let mask = 1; mask < 1 << N; mask++) { + let subseq = ''; for (let i = 0; i < N; i++) { if ((mask & (1 << i)) !== 0) { subseq += s[i]; @@ -333,8 +335,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(4 ^ n)$ -* Space complexity: $O(2 ^ n)$ +- Time complexity: $O(4 ^ n)$ +- Space complexity: $O(2 ^ n)$ --- @@ -348,7 +350,7 @@ class Solution: n = len(s) if n == 0: return 0 - + dp = [1] * n for i in range(n - 1, -1, -1): prev = 0 @@ -360,14 +362,14 @@ class Solution: dp[j] = max(dp[j - 1], dp[j]) prev = tmp return dp[n - 1] - + def maxProduct(self, s: str) -> int: n = len(s) res = 0 - + for i in range(1, 1 << n): seq1, seq2 = [], [] - + for j in range(n): if (i & (1 << j)) != 0: seq1.append(s[j]) @@ -379,9 +381,9 @@ class Solution: lps = self.longestPalindromeSubseq(''.join(seq2)) res = max(res, len(seq1) * lps) - + return res - + def isPal(self, s: str) -> bool: i, j = 0, len(s) - 1 while i < j: @@ -397,7 +399,7 @@ public class Solution { public int longestPalindromeSubseq(String s) { int n = s.length(); if (n == 0) return 0; - + int[] dp = new int[n]; Arrays.fill(dp, 1); for (int i = n - 1; i >= 0; i--) { @@ -414,14 +416,14 @@ public class Solution { } return dp[n - 1]; } - + public int maxProduct(String s) { int n = s.length(); int res = 0; - + for (int i = 1; i < (1 << n); i++) { StringBuilder seq1 = new StringBuilder(), seq2 = new StringBuilder(); - + for (int j = 0; j < n; j++) { char c = s.charAt(j); if ((i & (1 << j)) != 0) seq1.append(c); @@ -432,7 +434,7 @@ public class Solution { int lps = longestPalindromeSubseq(seq2.toString()); res = Math.max(res, seq1.length() * lps); } - + return res; } @@ -456,7 +458,7 @@ public: int longestPalindromeSubseq(string& s) { int n = s.length(); if (n == 0) return 0; - + vector dp(n, 1); for (int i = n - 1; i >= 0; i--) { int prev = 0; @@ -476,10 +478,10 @@ public: int maxProduct(string s) { int n = s.length(); int res = 0; - + for (int i = 1; i < (1 << n); i++) { string seq1 = "", seq2 = ""; - + for (int j = 0; j < n; j++) { if ((i & (1 << j)) != 0) seq1 += s[j]; else seq2 += s[j]; @@ -490,7 +492,7 @@ public: int lps = longestPalindromeSubseq(seq2); res = max(res, int(seq1.length()) * lps); } - + return res; } @@ -517,7 +519,7 @@ class Solution { longestPalindromeSubseq(s) { const n = s.length; if (n === 0) return 0; - + const dp = new Array(n).fill(1); for (let i = n - 1; i >= 0; i--) { let prev = 0; @@ -541,10 +543,11 @@ class Solution { maxProduct(s) { const n = s.length; let res = 0; - - for (let i = 1; i < (1 << n); i++) { - let seq1 = "", seq2 = ""; - + + for (let i = 1; i < 1 << n; i++) { + let seq1 = '', + seq2 = ''; + for (let j = 0; j < n; j++) { if ((i & (1 << j)) !== 0) seq1 += s[j]; else seq2 += s[j]; @@ -555,7 +558,7 @@ class Solution { const lps = this.longestPalindromeSubseq(seq2); res = Math.max(res, seq1.length * lps); } - + return res; } @@ -564,7 +567,8 @@ class Solution { * @return {boolean} */ isPal(s) { - let i = 0, j = s.length - 1; + let i = 0, + j = s.length - 1; while (i < j) { if (s[i] !== s[j]) { return false; @@ -581,8 +585,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2 * 2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2 * 2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -806,7 +810,7 @@ class Solution { let res = 0; const dp = Array(n).fill(1); - for (let i = 1; i < (1 << n); i++) { + for (let i = 1; i < 1 << n; i++) { const m1 = this.palsize(s, i); if (m1 === 0) continue; @@ -822,21 +826,22 @@ class Solution { } return res; } - + /** * @param {string} s * @param {number} mask * @return {number} */ palsize(s, mask) { - let i = 0, j = s.length - 1; + let i = 0, + j = s.length - 1; let res = 0; while (i <= j) { if ((mask & (1 << i)) === 0) i++; else if ((mask & (1 << j)) === 0) j--; else { if (s[i] !== s[j]) return 0; - res += (i === j) ? 1 : 2; + res += i === j ? 1 : 2; i++; j--; } @@ -850,5 +855,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2 * 2 ^ n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n ^ 2 * 2 ^ n)$ +- Space complexity: $O(n)$ diff --git a/articles/maximum-product-subarray.md b/articles/maximum-product-subarray.md index 5f5f0e299..83fcbea27 100644 --- a/articles/maximum-product-subarray.md +++ b/articles/maximum-product-subarray.md @@ -13,7 +13,7 @@ class Solution: for j in range(i + 1, len(nums)): cur *= nums[j] res = max(res, cur) - + return res ``` @@ -30,7 +30,7 @@ public class Solution { res = Math.max(res, cur); } } - + return res; } } @@ -50,7 +50,7 @@ public: res = max(res, cur); } } - + return res; } }; @@ -73,7 +73,7 @@ class Solution { res = Math.max(res, cur); } } - + return res; } } @@ -92,7 +92,7 @@ public class Solution { res = Math.Max(res, cur); } } - + return res; } } @@ -137,12 +137,31 @@ class Solution { } ``` +```swift +class Solution { + func maxProduct(_ nums: [Int]) -> Int { + var res = nums[0] + + for i in 0.. { + nums.forEach((num) => { res = Math.max(res, num); if (num === 0) { if (cur.length) A.push(cur); @@ -301,14 +320,14 @@ class Solution { }); if (cur.length) A.push(cur); - A.forEach(sub => { + A.forEach((sub) => { let negs = 0; - sub.forEach(i => { + sub.forEach((i) => { if (i < 0) negs++; }); let prod = 1; - let need = (negs % 2 === 0) ? negs : (negs - 1); + let need = negs % 2 === 0 ? negs : negs - 1; negs = 0; for (let i = 0, j = 0; i < sub.length; i++) { prod *= sub[i]; @@ -496,12 +515,65 @@ class Solution { } ``` +```swift +class Solution { + func maxProduct(_ nums: [Int]) -> Int { + var A = [[Int]]() + var cur = [Int]() + var res = Int.min + + for num in nums { + res = max(res, num) + if num == 0 { + if !cur.isEmpty { + A.append(cur) + } + cur = [] + } else { + cur.append(num) + } + } + + if !cur.isEmpty { + A.append(cur) + } + + for sub in A { + let negsCount = sub.filter { $0 < 0 }.count + var prod = 1 + var need = negsCount % 2 == 0 ? negsCount : negsCount - 1 + var negs = 0 + var j = 0 + + for i in 0.. need { + prod /= sub[j] + if sub[j] < 0 { + negs -= 1 + } + j += 1 + } + } + if j <= i { + res = max(res, prod) + } + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -642,12 +714,29 @@ class Solution { } ``` +```swift +class Solution { + func maxProduct(_ nums: [Int]) -> Int { + var res = nums[0] + var curMin = 1, curMax = 1 + + for num in nums { + let tmp = curMax * num + curMax = max(num * curMax, num * curMin, num) + curMin = min(tmp, num * curMin, num) + res = max(res, curMax) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -709,8 +798,10 @@ class Solution { * @return {number} */ maxProduct(nums) { - let n = nums.length, res = nums[0]; - let prefix = 0, suffix = 0; + let n = nums.length, + res = nums[0]; + let prefix = 0, + suffix = 0; for (let i = 0; i < n; i++) { prefix = nums[i] * (prefix === 0 ? 1 : prefix); @@ -752,7 +843,7 @@ func maxProduct(nums []int) int { if suffix == 0 { suffix = 1 } - + prefix *= nums[i] suffix *= nums[n-1-i] res = max(res, max(prefix, suffix)) @@ -791,9 +882,26 @@ class Solution { } ``` +```swift +class Solution { + func maxProduct(_ nums: [Int]) -> Int { + let n = nums.count + var res = nums[0] + var prefix = 0, suffix = 0 + + for i in 0.. int: + intervals = sorted(zip(startTime, endTime, profit)) + cache = {} + + def dfs(i): + if i == len(intervals): + return 0 + if i in cache: + return cache[i] + + # don't include + res = dfs(i + 1) + + # include + j = i + 1 + while j < len(intervals): + if intervals[i][1] <= intervals[j][0]: + break + j += 1 + + cache[i] = res = max(res, intervals[i][2] + dfs(j)) + return res + + return dfs(0) +``` + +```java +public class Solution { + private int[][] intervals; + private int[] cache; + + public int jobScheduling(int[] startTime, int[] endTime, int[] profit) { + int n = startTime.length; + intervals = new int[n][3]; + cache = new int[n]; + Arrays.fill(cache, -1); + + for (int i = 0; i < n; i++) { + intervals[i] = new int[]{startTime[i], endTime[i], profit[i]}; + } + Arrays.sort(intervals, Comparator.comparingInt(a -> a[0])); + + return dfs(0); + } + + private int dfs(int i) { + if (i == intervals.length) { + return 0; + } + if (cache[i] != -1) { + return cache[i]; + } + + // Don't include + int res = dfs(i + 1); + + // Include + int j = i + 1; + while (j < intervals.length && intervals[i][1] > intervals[j][0]) { + j++; + } + + return cache[i] = Math.max(res, intervals[i][2] + dfs(j)); + } +} +``` + +```cpp +class Solution { +public: + vector> intervals; + vector cache; + + int jobScheduling(vector& startTime, vector& endTime, vector& profit) { + int n = startTime.size(); + intervals.resize(n, vector(3)); + cache.assign(n, -1); + + for (int i = 0; i < n; i++) { + intervals[i] = {startTime[i], endTime[i], profit[i]}; + } + sort(intervals.begin(), intervals.end()); + + return dfs(0); + } + +private: + int dfs(int i) { + if (i == intervals.size()) { + return 0; + } + if (cache[i] != -1) { + return cache[i]; + } + + // Don't include + int res = dfs(i + 1); + + // Include + int j = i + 1; + while (j < intervals.size() && intervals[i][1] > intervals[j][0]) { + j++; + } + + return cache[i] = max(res, intervals[i][2] + dfs(j)); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} startTime + * @param {number[]} endTime + * @param {number[]} profit + * @return {number} + */ + jobScheduling(startTime, endTime, profit) { + let n = startTime.length; + let intervals = new Array(n) + .fill(null) + .map((_, i) => [startTime[i], endTime[i], profit[i]]); + intervals.sort((a, b) => a[0] - b[0]); + + let cache = new Array(n).fill(-1); + + const dfs = (i) => { + if (i === n) { + return 0; + } + if (cache[i] !== -1) { + return cache[i]; + } + + // Don't include + let res = dfs(i + 1); + + // Include + let j = i + 1; + while (j < n && intervals[i][1] > intervals[j][0]) { + j++; + } + + return (cache[i] = Math.max(res, intervals[i][2] + dfs(j))); + }; + + return dfs(0); + } +} +``` + +```csharp +public class Solution { + public int JobScheduling(int[] startTime, int[] endTime, int[] profit) { + int n = startTime.Length; + var intervals = new List<(int start, int end, int profit)>(); + + for (int i = 0; i < n; i++) { + intervals.Add((startTime[i], endTime[i], profit[i])); + } + + intervals.Sort((a, b) => a.start.CompareTo(b.start)); + Dictionary cache = new(); + + int Dfs(int i) { + if (i == n) return 0; + if (cache.ContainsKey(i)) return cache[i]; + + // Option 1: don't include + int res = Dfs(i + 1); + + // Option 2: include current job + int j = i + 1; + while (j < n && intervals[j].start < intervals[i].end) { + j++; + } + + res = Math.Max(res, intervals[i].profit + Dfs(j)); + cache[i] = res; + return res; + } + + return Dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Top-Down) + Binary Search + +::tabs-start + +```python +class Solution: + def jobScheduling(self, startTime: List[int], endTime: List[int], profit: List[int]) -> int: + intervals = sorted(zip(startTime, endTime, profit)) + cache = {} + + def dfs(i): + if i == len(intervals): + return 0 + if i in cache: + return cache[i] + + # don't include + res = dfs(i + 1) + + # include + j = bisect.bisect(intervals, (intervals[i][1], -1, -1)) + cache[i] = res = max(res, intervals[i][2] + dfs(j)) + return res + + return dfs(0) +``` + +```java +public class Solution { + private int[][] intervals; + private int[] cache; + + public int jobScheduling(int[] startTime, int[] endTime, int[] profit) { + int n = startTime.length; + intervals = new int[n][3]; + cache = new int[n]; + Arrays.fill(cache, -1); + + for (int i = 0; i < n; i++) { + intervals[i] = new int[]{startTime[i], endTime[i], profit[i]}; + } + Arrays.sort(intervals, Comparator.comparingInt(a -> a[0])); + + return dfs(0); + } + + private int dfs(int i) { + if (i == intervals.length) { + return 0; + } + if (cache[i] != -1) { + return cache[i]; + } + + int res = dfs(i + 1); + + int left = i + 1, right = intervals.length, j = intervals.length; + while (left < right) { + int mid = left + (right - left) / 2; + if (intervals[mid][0] >= intervals[i][1]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + return cache[i] = Math.max(res, intervals[i][2] + dfs(j)); + } +} +``` + +```cpp +class Solution { +public: + vector> intervals; + vector cache; + + int jobScheduling(vector& startTime, vector& endTime, vector& profit) { + int n = startTime.size(); + intervals.resize(n, vector(3)); + cache.assign(n, -1); + + for (int i = 0; i < n; i++) { + intervals[i] = {startTime[i], endTime[i], profit[i]}; + } + sort(intervals.begin(), intervals.end()); + + return dfs(0); + } + +private: + int dfs(int i) { + if (i == intervals.size()) { + return 0; + } + if (cache[i] != -1) { + return cache[i]; + } + + int res = dfs(i + 1); + + int left = i + 1, right = intervals.size(), j = intervals.size(); + while (left < right) { + int mid = left + (right - left) / 2; + if (intervals[mid][0] >= intervals[i][1]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + return cache[i] = max(res, intervals[i][2] + dfs(j)); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} startTime + * @param {number[]} endTime + * @param {number[]} profit + * @return {number} + */ + jobScheduling(startTime, endTime, profit) { + let n = startTime.length; + let intervals = new Array(n) + .fill(null) + .map((_, i) => [startTime[i], endTime[i], profit[i]]); + intervals.sort((a, b) => a[0] - b[0]); + + let cache = new Array(n).fill(-1); + + const dfs = (i) => { + if (i === n) { + return 0; + } + if (cache[i] !== -1) { + return cache[i]; + } + + let res = dfs(i + 1); + + let left = i + 1, + right = n, + j = n; + while (left < right) { + let mid = Math.floor((left + right) / 2); + if (intervals[mid][0] >= intervals[i][1]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + return (cache[i] = Math.max(res, intervals[i][2] + dfs(j))); + }; + + return dfs(0); + } +} +``` + +```csharp +public class Solution { + private int[][] intervals; + private int[] cache; + + public int JobScheduling(int[] startTime, int[] endTime, int[] profit) { + int n = startTime.Length; + intervals = new int[n][]; + cache = new int[n]; + Array.Fill(cache, -1); + + for (int i = 0; i < n; i++) { + intervals[i] = new int[] { startTime[i], endTime[i], profit[i] }; + } + + Array.Sort(intervals, (a, b) => a[0].CompareTo(b[0])); + return Dfs(0); + } + + private int Dfs(int i) { + if (i == intervals.Length) return 0; + if (cache[i] != -1) return cache[i]; + + int res = Dfs(i + 1); + + int left = i + 1, right = intervals.Length, j = intervals.Length; + while (left < right) { + int mid = left + (right - left) / 2; + if (intervals[mid][0] >= intervals[i][1]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + cache[i] = Math.Max(res, intervals[i][2] + Dfs(j)); + return cache[i]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Top-Down) + Binary Search (Optimal) + +::tabs-start + +```python +class Solution: + def jobScheduling(self, startTime: List[int], endTime: List[int], profit: List[int]) -> int: + n = len(startTime) + index = list(range(n)) + index.sort(key=lambda i: startTime[i]) + + cache = [-1] * n + + def dfs(i): + if i == n: + return 0 + if cache[i] != -1: + return cache[i] + + res = dfs(i + 1) + + left, right, j = i + 1, n, n + while left < right: + mid = (left + right) // 2 + if startTime[index[mid]] >= endTime[index[i]]: + j = mid + right = mid + else: + left = mid + 1 + + cache[i] = res = max(res, profit[index[i]] + dfs(j)) + return res + + return dfs(0) +``` + +```java +public class Solution { + private int[] startTime, endTime, profit, cache; + private Integer[] index; + private int n; + + public int jobScheduling(int[] startTime, int[] endTime, int[] profit) { + this.n = startTime.length; + this.startTime = startTime; + this.endTime = endTime; + this.profit = profit; + this.index = new Integer[n]; + this.cache = new int[n]; + Arrays.fill(cache, -1); + + for (int i = 0; i < n; i++) { + index[i] = i; + } + Arrays.sort(index, Comparator.comparingInt(i -> startTime[i])); + + return dfs(0); + } + + private int dfs(int i) { + if (i == n) { + return 0; + } + if (cache[i] != -1) { + return cache[i]; + } + + int res = dfs(i + 1); + + int left = i + 1, right = n, j = n; + while (left < right) { + int mid = left + (right - left) / 2; + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + return cache[i] = Math.max(res, profit[index[i]] + dfs(j)); + } +} +``` + +```cpp +class Solution { +public: + vector startTime, endTime, profit, index, cache; + int n; + + int jobScheduling(vector& startTime, vector& endTime, vector& profit) { + this->n = startTime.size(); + this->startTime = startTime; + this->endTime = endTime; + this->profit = profit; + this->index.resize(n); + this->cache.assign(n, -1); + + for (int i = 0; i < n; i++) { + index[i] = i; + } + sort(index.begin(), index.end(), [&](int i, int j) { + return startTime[i] < startTime[j]; + }); + + return dfs(0); + } + +private: + int dfs(int i) { + if (i == n) { + return 0; + } + if (cache[i] != -1) { + return cache[i]; + } + + int res = dfs(i + 1); + + int left = i + 1, right = n, j = n; + while (left < right) { + int mid = left + (right - left) / 2; + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + return cache[i] = max(res, profit[index[i]] + dfs(j)); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} startTime + * @param {number[]} endTime + * @param {number[]} profit + * @return {number} + */ + jobScheduling(startTime, endTime, profit) { + let n = startTime.length; + let index = Array.from({ length: n }, (_, i) => i); + index.sort((a, b) => startTime[a] - startTime[b]); + + let cache = new Array(n).fill(-1); + + const dfs = (i) => { + if (i === n) { + return 0; + } + if (cache[i] !== -1) { + return cache[i]; + } + + let res = dfs(i + 1); + + let left = i + 1, + right = n, + j = n; + while (left < right) { + let mid = Math.floor((left + right) / 2); + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + return (cache[i] = Math.max(res, profit[index[i]] + dfs(j))); + }; + + return dfs(0); + } +} +``` + +```csharp +public class Solution { + private int[] startTime, endTime, profit, cache; + private int[] index; + private int n; + + public int JobScheduling(int[] startTime, int[] endTime, int[] profit) { + this.n = startTime.Length; + this.startTime = startTime; + this.endTime = endTime; + this.profit = profit; + this.index = new int[n]; + this.cache = new int[n]; + Array.Fill(cache, -1); + + for (int i = 0; i < n; i++) { + index[i] = i; + } + + Array.Sort(index, (a, b) => startTime[a].CompareTo(startTime[b])); + + return Dfs(0); + } + + private int Dfs(int i) { + if (i == n) return 0; + if (cache[i] != -1) return cache[i]; + + int res = Dfs(i + 1); + + int left = i + 1, right = n, j = n; + while (left < right) { + int mid = left + (right - left) / 2; + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + return cache[i] = Math.Max(res, profit[index[i]] + Dfs(j)); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Bottom-Up) + Binary Search + +::tabs-start + +```python +class Solution: + def jobScheduling(self, startTime: List[int], endTime: List[int], profit: List[int]) -> int: + n = len(startTime) + index = list(range(n)) + index.sort(key=lambda i: startTime[i]) + + dp = [0] * (n + 1) + + for i in range(n - 1, -1, -1): + left, right, j = i + 1, n, n + while left < right: + mid = (left + right) // 2 + if startTime[index[mid]] >= endTime[index[i]]: + j = mid + right = mid + else: + left = mid + 1 + + dp[i] = max(dp[i + 1], profit[index[i]] + dp[j]) + + return dp[0] +``` + +```java +public class Solution { + public int jobScheduling(int[] startTime, int[] endTime, int[] profit) { + int n = startTime.length; + Integer[] index = new Integer[n]; + for (int i = 0; i < n; i++) index[i] = i; + Arrays.sort(index, Comparator.comparingInt(i -> startTime[i])); + + int[] dp = new int[n + 1]; + + for (int i = n - 1; i >= 0; i--) { + int left = i + 1, right = n, j = n; + while (left < right) { + int mid = left + (right - left) / 2; + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + dp[i] = Math.max(dp[i + 1], profit[index[i]] + dp[j]); + } + + return dp[0]; + } +} +``` + +```cpp +class Solution { +public: + int jobScheduling(vector& startTime, vector& endTime, vector& profit) { + int n = startTime.size(); + vector index(n), dp(n + 1, 0); + for (int i = 0; i < n; i++) index[i] = i; + sort(index.begin(), index.end(), [&](int i, int j) { + return startTime[i] < startTime[j]; + }); + + for (int i = n - 1; i >= 0; i--) { + int left = i + 1, right = n, j = n; + while (left < right) { + int mid = left + (right - left) / 2; + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + dp[i] = max(dp[i + 1], profit[index[i]] + dp[j]); + } + + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} startTime + * @param {number[]} endTime + * @param {number[]} profit + * @return {number} + */ + jobScheduling(startTime, endTime, profit) { + let n = startTime.length; + let index = Array.from({ length: n }, (_, i) => i); + index.sort((a, b) => startTime[a] - startTime[b]); + + let dp = new Array(n + 1).fill(0); + + for (let i = n - 1; i >= 0; i--) { + let left = i + 1, + right = n, + j = n; + while (left < right) { + let mid = Math.floor((left + right) / 2); + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + dp[i] = Math.max(dp[i + 1], profit[index[i]] + dp[j]); + } + + return dp[0]; + } +} +``` + +```csharp +public class Solution { + public int JobScheduling(int[] startTime, int[] endTime, int[] profit) { + int n = startTime.Length; + int[] index = new int[n]; + for (int i = 0; i < n; i++) index[i] = i; + + Array.Sort(index, (a, b) => startTime[a].CompareTo(startTime[b])); + + int[] dp = new int[n + 1]; + + for (int i = n - 1; i >= 0; i--) { + int left = i + 1, right = n, j = n; + while (left < right) { + int mid = left + (right - left) / 2; + if (startTime[index[mid]] >= endTime[index[i]]) { + j = mid; + right = mid; + } else { + left = mid + 1; + } + } + + dp[i] = Math.Max(dp[i + 1], profit[index[i]] + dp[j]); + } + + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/maximum-score-after-splitting-a-string.md b/articles/maximum-score-after-splitting-a-string.md index 04d95fb31..dc14477e0 100644 --- a/articles/maximum-score-after-splitting-a-string.md +++ b/articles/maximum-score-after-splitting-a-string.md @@ -76,7 +76,8 @@ class Solution { const n = s.length; let res = 0; for (let i = 1; i < n; i++) { - let leftZero = 0, rightOne = 0; + let leftZero = 0, + rightOne = 0; for (let j = 0; j < i; j++) { if (s[j] === '0') { leftZero++; @@ -98,8 +99,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -250,8 +251,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -334,7 +335,9 @@ class Solution { * @return {number} */ maxScore(s) { - let zero = 0, one = 0, res = 0; + let zero = 0, + one = 0, + res = 0; for (const c of s) { if (c === '1') { @@ -360,8 +363,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -391,7 +394,7 @@ class Solution: zeros += 1 else: ones += 1 - + return res + ones ``` @@ -465,7 +468,9 @@ class Solution { // res = Max of all (leftZeros + (totalOnes - leftOnes)) // res = totalOnes (constant) + Max of all (leftZeros - leftOnes) - let zeros = 0, ones = 0, res = -Infinity; + let zeros = 0, + ones = 0, + res = -Infinity; if (s[0] === '0') { zeros++; @@ -491,5 +496,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/maximum-score-of-a-good-subarray.md b/articles/maximum-score-of-a-good-subarray.md new file mode 100644 index 000000000..4af0c3934 --- /dev/null +++ b/articles/maximum-score-of-a-good-subarray.md @@ -0,0 +1,742 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maximumScore(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + + for i in range(k + 1): + minEle = nums[i] + for j in range(i, n): + minEle = min(minEle, nums[j]) + if j >= k: + res = max(res, minEle * (j - i + 1)) + + return res +``` + +```java +public class Solution { + public int maximumScore(int[] nums, int k) { + int n = nums.length, res = 0; + + for (int i = 0; i <= k; i++) { + int minEle = nums[i]; + for (int j = i; j < n; j++) { + minEle = Math.min(minEle, nums[j]); + if (j >= k) { + res = Math.max(res, minEle * (j - i + 1)); + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximumScore(vector& nums, int k) { + int n = nums.size(), res = 0; + + for (int i = 0; i <= k; i++) { + int minEle = nums[i]; + for (int j = i; j < n; j++) { + minEle = min(minEle, nums[j]); + if (j >= k) { + res = max(res, minEle * (j - i + 1)); + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maximumScore(nums, k) { + let n = nums.length, + res = 0; + + for (let i = 0; i <= k; i++) { + let minEle = nums[i]; + for (let j = i; j < n; j++) { + minEle = Math.min(minEle, nums[j]); + if (j >= k) { + res = Math.max(res, minEle * (j - i + 1)); + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 2. Binary Search + +::tabs-start + +```python +class Solution: + def maximumScore(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + arr = nums[:] + + for i in range(k - 1, -1, -1): + arr[i] = min(arr[i], arr[i + 1]) + for i in range(k + 1, n): + arr[i] = min(arr[i], arr[i - 1]) + + left_arr = arr[:k+1] + right_arr = arr[k:] + + def find_right(target): + lo, hi = 0, len(right_arr) - 1 + pos = 0 + while lo <= hi: + mid = (lo + hi) // 2 + if right_arr[mid] >= target: + pos = mid + lo = mid + 1 + else: + hi = mid - 1 + return pos + + for minVal in set(arr): + l = bisect_left(left_arr, minVal) + r = find_right(minVal) + res = max(res, minVal * (k - l + 1 + r)) + return res +``` + +```java +public class Solution { + public int maximumScore(int[] nums, int k) { + int n = nums.length, res = 0; + int[] arr = Arrays.copyOf(nums, n); + Set candidates = new HashSet<>(); + candidates.add(arr[k]); + + for (int i = k - 1; i >= 0; i--) { + arr[i] = Math.min(arr[i], arr[i + 1]); + candidates.add(arr[i]); + } + for (int i = k + 1; i < n; i++) { + arr[i] = Math.min(arr[i], arr[i - 1]); + candidates.add(arr[i]); + } + + int[] leftArr = Arrays.copyOfRange(arr, 0, k + 1); + int[] rightArr = Arrays.copyOfRange(arr, k, n); + + for (int minVal : candidates) { + int l = findLeft(leftArr, minVal); + int r = findRight(rightArr, minVal); + res = Math.max(res, minVal * (k - l + 1 + r)); + } + return res; + } + + private int findLeft(int[] arr, int target) { + int lo = 0, hi = arr.length - 1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (arr[mid] < target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return lo; + } + + private int findRight(int[] arr, int target) { + int lo = 0, hi = arr.length - 1, pos = 0; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (arr[mid] >= target) { + pos = mid; + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return pos; + } +} +``` + +```cpp +class Solution { +public: + int maximumScore(vector& nums, int k) { + int n = nums.size(), res = 0; + vector arr = nums; + + for (int i = k - 1; i >= 0; i--) { + arr[i] = min(arr[i], arr[i + 1]); + } + for (int i = k + 1; i < n; i++) { + arr[i] = min(arr[i], arr[i - 1]); + } + + vector leftArr(arr.begin(), arr.begin() + k + 1); + vector rightArr(arr.begin() + k, arr.end()); + + set candidates(arr.begin(), arr.end()); + for (int minVal : candidates) { + int l = lower_bound(leftArr.begin(), leftArr.end(), minVal) - leftArr.begin(); + int r = findRight(rightArr, minVal); + res = max(res, minVal * (k - l + 1 + r)); + } + return res; + } + +private: + int findRight(vector& arr, int target) { + int lo = 0, hi = arr.size() - 1, pos = 0; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (arr[mid] >= target) { + pos = mid; + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return pos; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maximumScore(nums, k) { + let n = nums.length, + res = 0; + let arr = [...nums]; + + for (let i = k - 1; i >= 0; i--) { + arr[i] = Math.min(arr[i], arr[i + 1]); + } + for (let i = k + 1; i < n; i++) { + arr[i] = Math.min(arr[i], arr[i - 1]); + } + + let leftArr = arr.slice(0, k + 1); + let rightArr = arr.slice(k); + + const findLeft = (target) => { + let lo = 0, + hi = leftArr.length - 1; + while (lo <= hi) { + let mid = Math.floor((lo + hi) / 2); + if (leftArr[mid] < target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return lo; + }; + + const findRight = (target) => { + let lo = 0, + hi = rightArr.length - 1, + pos = 0; + while (lo <= hi) { + let mid = Math.floor((lo + hi) / 2); + if (rightArr[mid] >= target) { + pos = mid; + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return pos; + }; + + let candidates = [...new Set(arr)]; + for (let minVal of candidates) { + let l = findLeft(minVal); + let r = findRight(minVal); + res = Math.max(res, minVal * (k - l + 1 + r)); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Binary Search (Overwriting the Input) + +::tabs-start + +```python +class Solution: + def maximumScore(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + + for i in range(k - 1, -1, -1): + nums[i] = min(nums[i], nums[i + 1]) + for i in range(k + 1, n): + nums[i] = min(nums[i], nums[i - 1]) + + def find_left(target): + lo, hi = 0, k + while lo <= hi: + mid = (lo + hi) // 2 + if nums[mid] < target: + lo = mid + 1 + else: + hi = mid - 1 + return lo + + def find_right(target): + lo, hi = k, n - 1 + while lo <= hi: + mid = (lo + hi) // 2 + if nums[mid] >= target: + lo = mid + 1 + else: + hi = mid - 1 + return hi + + for minVal in set(nums): + i = find_left(minVal) + j = find_right(minVal) + res = max(res, minVal * (j - i + 1)) + return res +``` + +```java +public class Solution { + public int maximumScore(int[] nums, int k) { + int n = nums.length, res = 0; + + for (int i = k - 1; i >= 0; i--) { + nums[i] = Math.min(nums[i], nums[i + 1]); + } + for (int i = k + 1; i < n; i++) { + nums[i] = Math.min(nums[i], nums[i - 1]); + } + + Set candidates = new TreeSet<>(); + for (int num : nums) { + candidates.add(num); + } + + for (int minVal : candidates) { + int i = findLeft(nums, k, minVal); + int j = findRight(nums, k, minVal); + res = Math.max(res, minVal * (j - i + 1)); + } + return res; + } + + int findLeft(int[] nums, int k, int target) { + int lo = 0, hi = k; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (nums[mid] < target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return lo; + } + + int findRight(int[] nums, int k, int target) { + int lo = k, hi = nums.length - 1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (nums[mid] >= target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return hi; + } +} +``` + +```cpp +class Solution { +public: + int maximumScore(vector& nums, int k) { + int n = nums.size(), res = 0; + + for (int i = k - 1; i >= 0; i--) { + nums[i] = min(nums[i], nums[i + 1]); + } + for (int i = k + 1; i < n; i++) { + nums[i] = min(nums[i], nums[i - 1]); + } + + auto findLeft = [&](int target) { + int lo = 0, hi = k; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (nums[mid] < target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return lo; + }; + + auto findRight = [&](int target) { + int lo = k, hi = n - 1; + while (lo <= hi) { + int mid = (lo + hi) / 2; + if (nums[mid] >= target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return hi; + }; + + set candidates(nums.begin(), nums.end()); + for (int minVal : candidates) { + int i = findLeft(minVal); + int j = findRight(minVal); + res = max(res, minVal * (j - i + 1)); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maximumScore(nums, k) { + let n = nums.length, + res = 0; + + for (let i = k - 1; i >= 0; i--) { + nums[i] = Math.min(nums[i], nums[i + 1]); + } + for (let i = k + 1; i < n; i++) { + nums[i] = Math.min(nums[i], nums[i - 1]); + } + + const findLeft = (target) => { + let lo = 0, + hi = k; + while (lo <= hi) { + let mid = Math.floor((lo + hi) / 2); + if (nums[mid] < target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return lo; + }; + + const findRight = (target) => { + let lo = k, + hi = n - 1; + while (lo <= hi) { + let mid = Math.floor((lo + hi) / 2); + if (nums[mid] >= target) { + lo = mid + 1; + } else { + hi = mid - 1; + } + } + return hi; + }; + + let candidates = new Set(nums); + for (let minVal of candidates) { + let i = findLeft(minVal); + let j = findRight(minVal); + res = Math.max(res, minVal * (j - i + 1)); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Monotonic Stack + +::tabs-start + +```python +class Solution: + def maximumScore(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + stack = [] + + for i in range(n + 1): + while stack and (i == n or nums[stack[-1]] >= nums[i]): + mini = nums[stack.pop()] + j = stack[-1] if stack else -1 + if j < k < i: + res = max(res, mini * (i - j - 1)) + stack.append(i) + + return res +``` + +```java +public class Solution { + public int maximumScore(int[] nums, int k) { + int n = nums.length, res = 0; + Stack stack = new Stack<>(); + + for (int i = 0; i <= n; i++) { + while (!stack.isEmpty() && (i == n || nums[stack.peek()] >= nums[i])) { + int mini = nums[stack.pop()]; + int j = stack.isEmpty() ? -1 : stack.peek(); + if (j < k && k < i) { + res = Math.max(res, mini * (i - j - 1)); + } + } + stack.push(i); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximumScore(vector& nums, int k) { + int n = nums.size(), res = 0; + stack stk; + + for (int i = 0; i <= n; i++) { + while (!stk.empty() && (i == n || nums[stk.top()] >= nums[i])) { + int mini = nums[stk.top()]; + stk.pop(); + int j = stk.empty() ? -1 : stk.top(); + if (j < k && k < i) { + res = max(res, mini * (i - j - 1)); + } + } + stk.push(i); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maximumScore(nums, k) { + let n = nums.length, + res = 0; + let stack = []; + + for (let i = 0; i <= n; i++) { + while ( + stack.length && + (i === n || nums[stack[stack.length - 1]] >= nums[i]) + ) { + let mini = nums[stack.pop()]; + let j = stack.length ? stack[stack.length - 1] : -1; + if (j < k && k < i) { + res = Math.max(res, mini * (i - j - 1)); + } + } + stack.push(i); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 5. Greedy + Two Pointers + +::tabs-start + +```python +class Solution: + def maximumScore(self, nums: List[int], k: int) -> int: + l = r = k + res = nums[k] + cur_min = nums[k] + + while l > 0 or r < len(nums) - 1: + left = nums[l - 1] if l > 0 else 0 + right = nums[r + 1] if r < len(nums) - 1 else 0 + + if left > right: + l -= 1 + cur_min = min(cur_min, left) + else: + r += 1 + cur_min = min(cur_min, right) + + res = max(res, cur_min * (r - l + 1)) + + return res +``` + +```java +public class Solution { + public int maximumScore(int[] nums, int k) { + int l = k, r = k; + int res = nums[k]; + int curMin = nums[k]; + int n = nums.length; + + while (l > 0 || r < n - 1) { + int left = (l > 0) ? nums[l - 1] : 0; + int right = (r < n - 1) ? nums[r + 1] : 0; + + if (left > right) { + l--; + curMin = Math.min(curMin, left); + } else { + r++; + curMin = Math.min(curMin, right); + } + + res = Math.max(res, curMin * (r - l + 1)); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maximumScore(vector& nums, int k) { + int l = k, r = k; + int res = nums[k]; + int curMin = nums[k]; + int n = nums.size(); + + while (l > 0 || r < n - 1) { + int left = (l > 0) ? nums[l - 1] : 0; + int right = (r < n - 1) ? nums[r + 1] : 0; + + if (left > right) { + l--; + curMin = min(curMin, left); + } else { + r++; + curMin = min(curMin, right); + } + + res = max(res, curMin * (r - l + 1)); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + maximumScore(nums, k) { + let l = k, + r = k; + let res = nums[k]; + let curMin = nums[k]; + let n = nums.length; + + while (l > 0 || r < n - 1) { + let left = l > 0 ? nums[l - 1] : 0; + let right = r < n - 1 ? nums[r + 1] : 0; + + if (left > right) { + l--; + curMin = Math.min(curMin, left); + } else { + r++; + curMin = Math.min(curMin, right); + } + + res = Math.max(res, curMin * (r - l + 1)); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/maximum-score-words-formed-by-letters.md b/articles/maximum-score-words-formed-by-letters.md new file mode 100644 index 000000000..30ab627ee --- /dev/null +++ b/articles/maximum-score-words-formed-by-letters.md @@ -0,0 +1,678 @@ +## 1. Backtracking + +::tabs-start + +```python +class Solution: + def maxScoreWords(self, words: List[str], letters: List[str], score: List[int]) -> int: + def can_form_word(w, letter_cnt): + word_cnt = Counter(w) + for c in word_cnt: + if word_cnt[c] > letter_cnt[c]: + return False + return True + + def get_score(w): + res = 0 + for c in w: + res += score[ord(c) - ord('a')] + return res + + letter_cnt = Counter(letters) + + def backtrack(i): + if i == len(words): + return 0 + + res = backtrack(i + 1) # skip + if can_form_word(words[i], letter_cnt): # include (when possible) + for c in words[i]: + letter_cnt[c] -= 1 + res = max(res, get_score(words[i]) + backtrack(i + 1)) + for c in words[i]: + letter_cnt[c] += 1 + + return res + + return backtrack(0) +``` + +```java +public class Solution { + int[] letterCnt; + int[] score; + + public int maxScoreWords(String[] words, char[] letters, int[] score) { + this.score = score; + this.letterCnt = new int[26]; + + for (char c : letters) { + letterCnt[c - 'a']++; + } + + return backtrack(0, words); + } + + private int canFormWord(String word) { + int[] wordCnt = new int[26]; + for (char c : word.toCharArray()) { + wordCnt[c - 'a']++; + if (wordCnt[c - 'a'] > letterCnt[c - 'a']) { + return 0; + } + } + return 1; + } + + private int getScore(String word) { + int res = 0; + for (char c : word.toCharArray()) { + res += score[c - 'a']; + } + return res; + } + + private int backtrack(int i, String[] words) { + if (i == words.length) { + return 0; + } + + int res = backtrack(i + 1, words); // skip + if (canFormWord(words[i]) == 1) { // include (when possible) + for (char c : words[i].toCharArray()) { + letterCnt[c - 'a']--; + } + res = Math.max(res, getScore(words[i]) + backtrack(i + 1, words)); + for (char c : words[i].toCharArray()) { + letterCnt[c - 'a']++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector letterCnt = vector(26, 0); + vector score; + vector words; + + int maxScoreWords(vector& words, vector& letters, vector& score) { + this->words = words; + this->score = score; + + for (char c : letters) { + letterCnt[c - 'a']++; + } + + return backtrack(0); + } + + bool canFormWord(string& word) { + vector wordCnt(26, 0); + for (char c : word) { + wordCnt[c - 'a']++; + if (wordCnt[c - 'a'] > letterCnt[c - 'a']) { + return false; + } + } + return true; + } + + int getScore(string& word) { + int res = 0; + for (char c : word) { + res += score[c - 'a']; + } + return res; + } + + int backtrack(int i) { + if (i == words.size()) { + return 0; + } + + int res = backtrack(i + 1); // skip + if (canFormWord(words[i])) { // include (when possible) + for (char c : words[i]) { + letterCnt[c - 'a']--; + } + res = max(res, getScore(words[i]) + backtrack(i + 1)); + for (char c : words[i]) { + letterCnt[c - 'a']++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {string[]} letters + * @param {number[]} score + * @return {number} + */ + maxScoreWords(words, letters, score) { + const canFormWord = (w, letterCnt) => { + let wordCnt = new Array(26).fill(0); + for (let c of w) { + let idx = c.charCodeAt(0) - 'a'.charCodeAt(0); + wordCnt[idx]++; + if (wordCnt[idx] > letterCnt[idx]) { + return false; + } + } + return true; + }; + + const getScore = (w) => { + let res = 0; + for (let c of w) { + res += score[c.charCodeAt(0) - 'a'.charCodeAt(0)]; + } + return res; + }; + + let letterCnt = new Array(26).fill(0); + for (let c of letters) { + letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + const backtrack = (i) => { + if (i === words.length) { + return 0; + } + + let res = backtrack(i + 1); // skip + + if (canFormWord(words[i], letterCnt)) { + // include (when possible) + for (let c of words[i]) { + letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]--; + } + res = Math.max(res, getScore(words[i]) + backtrack(i + 1)); + for (let c of words[i]) { + letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + } + + return res; + }; + + return backtrack(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(2 ^ n * (w + m) + N)$ +- Space complexity: $O(n + w)$ + +> Where $n$ is the number of words, $w$ is the maximum length of a word, $m$ is the size of the array $scores$, and $N$ is the size of the array $letters$. + +--- + +## 2. Bactracking + Precomputation + +::tabs-start + +```python +class Solution: + def maxScoreWords(self, words: List[str], letters: List[str], score: List[int]) -> int: + letter_cnt = [0] * 26 + for c in letters: + letter_cnt[ord(c) - ord('a')] += 1 + + n = len(words) + word_scores = [0] * n + word_freqs = [[0] * 26 for _ in range(n)] + + for i, word in enumerate(words): + for c in word: + idx = ord(c) - ord('a') + word_freqs[i][idx] += 1 + word_scores[i] += score[idx] + + def backtrack(i): + if i == n: + return 0 + + res = backtrack(i + 1) # skip + can_include = all(word_freqs[i][j] <= letter_cnt[j] for j in range(26)) + + if can_include: # include (when possible) + for j in range(26): + letter_cnt[j] -= word_freqs[i][j] + res = max(res, word_scores[i] + backtrack(i + 1)) + for j in range(26): + letter_cnt[j] += word_freqs[i][j] + + return res + + return backtrack(0) +``` + +```java +public class Solution { + private int[] letterCnt = new int[26]; + private int[] wordScores; + private int[][] wordFreqs; + private int n; + + public int maxScoreWords(String[] words, char[] letters, int[] score) { + Arrays.fill(letterCnt, 0); + for (char c : letters) { + letterCnt[c - 'a']++; + } + + n = words.length; + wordScores = new int[n]; + wordFreqs = new int[n][26]; + + for (int i = 0; i < n; i++) { + for (char c : words[i].toCharArray()) { + int idx = c - 'a'; + wordFreqs[i][idx]++; + wordScores[i] += score[idx]; + } + } + + return backtrack(0, words); + } + + private int backtrack(int i, String[] words) { + if (i == n) { + return 0; + } + + int res = backtrack(i + 1, words); // skip + boolean canInclude = true; + + for (int j = 0; j < 26; j++) { + if (wordFreqs[i][j] > letterCnt[j]) { + canInclude = false; + break; + } + } + + if (canInclude) { // include (when possible) + for (int j = 0; j < 26; j++) { + letterCnt[j] -= wordFreqs[i][j]; + } + res = Math.max(res, wordScores[i] + backtrack(i + 1, words)); + for (int j = 0; j < 26; j++) { + letterCnt[j] += wordFreqs[i][j]; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector letterCnt = vector(26, 0); + vector wordScores; + vector> wordFreqs; + int n; + + int maxScoreWords(vector& words, vector& letters, vector& score) { + fill(letterCnt.begin(), letterCnt.end(), 0); + for (char c : letters) { + letterCnt[c - 'a']++; + } + + n = words.size(); + wordScores = vector(n, 0); + wordFreqs = vector>(n, vector(26, 0)); + + for (int i = 0; i < n; i++) { + for (char c : words[i]) { + int idx = c - 'a'; + wordFreqs[i][idx]++; + wordScores[i] += score[idx]; + } + } + + return backtrack(0, words); + } + +private: + int backtrack(int i, vector& words) { + if (i == n) { + return 0; + } + + int res = backtrack(i + 1, words); // skip + bool canInclude = true; + + for (int j = 0; j < 26; j++) { + if (wordFreqs[i][j] > letterCnt[j]) { + canInclude = false; + break; + } + } + + if (canInclude) { // include (when possible) + for (int j = 0; j < 26; j++) { + letterCnt[j] -= wordFreqs[i][j]; + } + res = max(res, wordScores[i] + backtrack(i + 1, words)); + for (int j = 0; j < 26; j++) { + letterCnt[j] += wordFreqs[i][j]; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {string[]} letters + * @param {number[]} score + * @return {number} + */ + maxScoreWords(words, letters, score) { + let letterCnt = new Array(26).fill(0); + for (let c of letters) { + letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + let n = words.length; + let wordScores = new Array(n).fill(0); + let wordFreqs = Array.from({ length: n }, () => new Array(26).fill(0)); + + for (let i = 0; i < n; i++) { + for (let c of words[i]) { + let idx = c.charCodeAt(0) - 'a'.charCodeAt(0); + wordFreqs[i][idx]++; + wordScores[i] += score[idx]; + } + } + + const backtrack = (i) => { + if (i === n) { + return 0; + } + + let res = backtrack(i + 1); // skip + let canInclude = true; + + for (let j = 0; j < 26; j++) { + if (wordFreqs[i][j] > letterCnt[j]) { + canInclude = false; + break; + } + } + + if (canInclude) { + // include (when possible) + for (let j = 0; j < 26; j++) { + letterCnt[j] -= wordFreqs[i][j]; + } + res = Math.max(res, wordScores[i] + backtrack(i + 1)); + for (let j = 0; j < 26; j++) { + letterCnt[j] += wordFreqs[i][j]; + } + } + + return res; + }; + + return backtrack(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * 2 ^ n + N)$ +- Space complexity: $O(n + w)$ + +> Where $n$ is the number of words, $w$ is the maximum length of a word, $m$ is the size of the array $scores$, and $N$ is the size of the array $letters$. + +--- + +## 3. Backtracking (Bit Mask) + +::tabs-start + +```python +class Solution: + def maxScoreWords(self, words: List[str], letters: List[str], score: List[int]) -> int: + letter_cnt = [0] * 26 + for c in letters: + letter_cnt[ord(c) - ord('a')] += 1 + + n = len(words) + word_scores = [0] * n + word_freqs = [[0] * 26 for _ in range(n)] + + for i, word in enumerate(words): + for c in word: + idx = ord(c) - ord('a') + word_freqs[i][idx] += 1 + word_scores[i] += score[idx] + + res = 0 + + for mask in range(1 << n): + cur_score = 0 + cur_letter_cnt = letter_cnt[:] + valid = True + + for i in range(n): + if mask & (1 << i): + for j in range(26): + if word_freqs[i][j] > cur_letter_cnt[j]: + valid = False + break + if not valid: + break + + for j in range(26): + cur_letter_cnt[j] -= word_freqs[i][j] + + cur_score += word_scores[i] + + if valid: + res = max(res, cur_score) + + return res +``` + +```java +public class Solution { + public int maxScoreWords(String[] words, char[] letters, int[] score) { + int[] letterCnt = new int[26]; + for (char c : letters) { + letterCnt[c - 'a']++; + } + + int n = words.length; + int[] wordScores = new int[n]; + int[][] wordFreqs = new int[n][26]; + + for (int i = 0; i < n; i++) { + for (char c : words[i].toCharArray()) { + int idx = c - 'a'; + wordFreqs[i][idx]++; + wordScores[i] += score[idx]; + } + } + + int res = 0; + for (int mask = 0; mask < (1 << n); mask++) { + int curScore = 0; + int[] curLetterCnt = Arrays.copyOf(letterCnt, 26); + boolean valid = true; + + for (int i = 0; i < n; i++) { + if ((mask & (1 << i)) != 0) { + for (int j = 0; j < 26; j++) { + if (wordFreqs[i][j] > curLetterCnt[j]) { + valid = false; + break; + } + } + if (!valid) break; + + for (int j = 0; j < 26; j++) { + curLetterCnt[j] -= wordFreqs[i][j]; + } + + curScore += wordScores[i]; + } + } + + if (valid) { + res = Math.max(res, curScore); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxScoreWords(vector& words, vector& letters, vector& score) { + vector letterCnt(26, 0); + for (char c : letters) { + letterCnt[c - 'a']++; + } + + int n = words.size(); + vector wordScores(n, 0); + vector> wordFreqs(n, vector(26, 0)); + + for (int i = 0; i < n; i++) { + for (char c : words[i]) { + int idx = c - 'a'; + wordFreqs[i][idx]++; + wordScores[i] += score[idx]; + } + } + + int res = 0; + for (int mask = 0; mask < (1 << n); mask++) { + int curScore = 0; + vector curLetterCnt = letterCnt; + bool valid = true; + + for (int i = 0; i < n; i++) { + if (mask & (1 << i)) { + for (int j = 0; j < 26; j++) { + if (wordFreqs[i][j] > curLetterCnt[j]) { + valid = false; + break; + } + } + if (!valid) break; + + for (int j = 0; j < 26; j++) { + curLetterCnt[j] -= wordFreqs[i][j]; + } + + curScore += wordScores[i]; + } + } + + if (valid) { + res = max(res, curScore); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {string[]} letters + * @param {number[]} score + * @return {number} + */ + maxScoreWords(words, letters, score) { + let letterCnt = new Array(26).fill(0); + for (let c of letters) { + letterCnt[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + let n = words.length; + let wordScores = new Array(n).fill(0); + let wordFreqs = Array.from({ length: n }, () => new Array(26).fill(0)); + + for (let i = 0; i < n; i++) { + for (let c of words[i]) { + let idx = c.charCodeAt(0) - 'a'.charCodeAt(0); + wordFreqs[i][idx]++; + wordScores[i] += score[idx]; + } + } + + let res = 0; + for (let mask = 0; mask < 1 << n; mask++) { + let curScore = 0; + let curLetterCnt = [...letterCnt]; + let valid = true; + + for (let i = 0; i < n; i++) { + if ((mask & (1 << i)) !== 0) { + for (let j = 0; j < 26; j++) { + if (wordFreqs[i][j] > curLetterCnt[j]) { + valid = false; + break; + } + } + if (!valid) break; + + for (let j = 0; j < 26; j++) { + curLetterCnt[j] -= wordFreqs[i][j]; + } + + curScore += wordScores[i]; + } + } + + if (valid) { + res = Math.max(res, curScore); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n * 2 ^ n + N)$ +- Space complexity: $O(n + w)$ + +> Where $n$ is the number of words, $w$ is the maximum length of a word, $m$ is the size of the array $scores$, and $N$ is the size of the array $letters$. diff --git a/articles/maximum-subarray-min-product.md b/articles/maximum-subarray-min-product.md index 1ac42156b..84cc2cab6 100644 --- a/articles/maximum-subarray-min-product.md +++ b/articles/maximum-subarray-min-product.md @@ -61,9 +61,11 @@ class Solution { * @return {number} */ maxSumMinProduct(nums) { - let res = 0, MOD = 1000000007; + let res = 0, + MOD = 1000000007; for (let i = 0; i < nums.length; i++) { - let totalSum = 0, mini = Infinity; + let totalSum = 0, + mini = Infinity; for (let j = i; j < nums.length; j++) { mini = Math.min(mini, nums[j]); totalSum += nums[j]; @@ -80,8 +82,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. --- @@ -97,20 +99,20 @@ class Solution: def rec(l, r): if l > r: return 0 - + min_idx = l total_sum = 0 for i in range(l, r + 1): total_sum += nums[i] if nums[i] < nums[min_idx]: min_idx = i - + cur = total_sum * nums[min_idx] left = rec(l, min_idx - 1) right = rec(min_idx + 1, r) - + return max(cur, left, right) - + return rec(0, len(nums) - 1) % MOD ``` @@ -196,7 +198,7 @@ class Solution { let cur = totalSum * BigInt(nums[minIdx]); let left = rec(l, minIdx - 1); let right = rec(minIdx + 1, r); - + if (cur < left) cur = left; if (cur < right) cur = right; return cur; @@ -211,8 +213,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -261,15 +263,15 @@ class Solution: def rec(l, r): if l > r: return 0 - + min_idx = segTree.query(l, r) total_sum = prefix_sum[r + 1] - prefix_sum[l] - cur = total_sum * nums[min_idx] + cur = total_sum * nums[min_idx] left = rec(l, min_idx - 1) right = rec(min_idx + 1, r) - + return max(cur, left, right) - + return rec(0, len(nums) - 1) % MOD ``` @@ -421,12 +423,18 @@ class SegmentTree { * @return {void} */ build(n, nums) { - this.tree = Array(2 * this.n).fill([BigInt(-1), BigInt(Number.MAX_SAFE_INTEGER)]); + this.tree = Array(2 * this.n).fill([ + BigInt(-1), + BigInt(Number.MAX_SAFE_INTEGER), + ]); for (let i = 0; i < n; i++) { this.tree[this.n + i] = [BigInt(i), BigInt(nums[i])]; } for (let i = this.n - 1; i > 0; i--) { - this.tree[i] = this._merge(this.tree[i << 1], this.tree[i << 1 | 1]); + this.tree[i] = this._merge( + this.tree[i << 1], + this.tree[(i << 1) | 1], + ); } } @@ -478,7 +486,7 @@ class Solution { let cur = totalSum * BigInt(nums[minIdx]); let left = rec(l, minIdx - 1); let right = rec(minIdx + 1, r); - + if (cur < left) cur = left; if (cur < right) cur = right; return cur; @@ -493,8 +501,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -512,30 +520,30 @@ class Solution: prev_min, nxt_min = [-1] * n, [n] * n stack = [] - + for i in range(n): while stack and nums[stack[-1]] >= nums[i]: stack.pop() if stack: prev_min[i] = stack[-1] stack.append(i) - + stack.clear() - + for i in range(n - 1, -1, -1): while stack and nums[stack[-1]] >= nums[i]: stack.pop() if stack: nxt_min[i] = stack[-1] stack.append(i) - + res = 0 - + for i in range(n): l, r = prev_min[i] + 1, nxt_min[i] - 1 total_sum = prefix_sum[r + 1] - prefix_sum[l] res = max(res, nums[i] * total_sum) - + return res % (10 ** 9 + 7) ``` @@ -552,7 +560,7 @@ public class Solution { int[] nxtMin = new int[n]; Arrays.fill(prevMin, -1); Arrays.fill(nxtMin, n); - + Stack stack = new Stack<>(); for (int i = 0; i < n; i++) { while (!stack.isEmpty() && nums[stack.peek()] >= nums[i]) { @@ -563,7 +571,7 @@ public class Solution { } stack.push(i); } - + stack.clear(); for (int i = n - 1; i >= 0; i--) { while (!stack.isEmpty() && nums[stack.peek()] >= nums[i]) { @@ -574,7 +582,7 @@ public class Solution { } stack.push(i); } - + long res = 0; int MOD = 1_000_000_007; for (int i = 0; i < n; i++) { @@ -582,7 +590,7 @@ public class Solution { long totalSum = prefixSum[r + 1] - prefixSum[l]; res = Math.max(res, nums[i] * totalSum); } - + return (int)(res % MOD); } } @@ -600,7 +608,7 @@ public: vector prevMin(n, -1), nxtMin(n, n); stack stack; - + for (int i = 0; i < n; i++) { while (!stack.empty() && nums[stack.top()] >= nums[i]) { stack.pop(); @@ -610,7 +618,7 @@ public: } stack.push(i); } - + while (!stack.empty()) stack.pop(); for (int i = n - 1; i >= 0; i--) { while (!stack.empty() && nums[stack.top()] >= nums[i]) { @@ -621,7 +629,7 @@ public: } stack.push(i); } - + long long res = 0; int MOD = 1e9 + 7; for (int i = 0; i < n; i++) { @@ -629,7 +637,7 @@ public: long long totalSum = prefixSum[r + 1] - prefixSum[l]; res = max(res, nums[i] * totalSum); } - + return res % MOD; } }; @@ -651,7 +659,7 @@ class Solution { const prevMin = new Array(n).fill(-1); const nxtMin = new Array(n).fill(n); const stack = []; - + for (let i = 0; i < n; i++) { while (stack.length && nums[stack[stack.length - 1]] >= nums[i]) { stack.pop(); @@ -661,7 +669,7 @@ class Solution { } stack.push(i); } - + stack.length = 0; for (let i = n - 1; i >= 0; i--) { while (stack.length && nums[stack[stack.length - 1]] >= nums[i]) { @@ -672,7 +680,7 @@ class Solution { } stack.push(i); } - + let res = 0n; const MOD = 10n ** 9n + 7n; for (let i = 0; i < n; i++) { @@ -682,7 +690,7 @@ class Solution { const tmp = BigInt(nums[i]) * totalSum; if (tmp > res) res = tmp; } - + return Number(res % MOD); } } @@ -692,8 +700,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -816,7 +824,7 @@ class Solution { let res = 0n; const MOD = 10n ** 9n + 7n; const stack = []; - + for (let i = 0; i < n; i++) { let newStart = i; while (stack.length && stack[stack.length - 1][1] > nums[i]) { @@ -845,8 +853,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -861,7 +869,7 @@ class Solution: prefix_sum = [0] * (n + 1) for i in range(n): prefix_sum[i + 1] = prefix_sum[i] + nums[i] - + res, stack = 0, [] for i in range(n + 1): while stack and (i == n or nums[i] < nums[stack[-1]]): @@ -869,7 +877,7 @@ class Solution: start = 0 if not stack else stack[-1] + 1 res = max(res, nums[j] * (prefix_sum[i] - prefix_sum[start])) stack.append(i) - + return res % (10 ** 9 + 7) ``` @@ -881,7 +889,7 @@ public class Solution { for (int i = 0; i < n; i++) { prefixSum[i + 1] = prefixSum[i] + nums[i]; } - + long res = 0; int mod = 1_000_000_007; Stack stack = new Stack<>(); @@ -893,7 +901,7 @@ public class Solution { } stack.push(i); } - + return (int) (res % mod); } } @@ -908,7 +916,7 @@ public: for (int i = 0; i < n; i++) { prefixSum[i + 1] = prefixSum[i] + nums[i]; } - + long long res = 0; const int mod = 1e9 + 7; stack st; @@ -921,7 +929,7 @@ public: } st.push(i); } - + return res % mod; } }; @@ -944,9 +952,13 @@ class Solution { const MOD = 10n ** 9n + 7n; const stack = []; for (let i = 0; i <= n; i++) { - while (stack.length && (i === n || nums[i] < nums[stack[stack.length - 1]])) { + while ( + stack.length && + (i === n || nums[i] < nums[stack[stack.length - 1]]) + ) { const j = stack.pop(); - const start = stack.length === 0 ? 0 : stack[stack.length - 1] + 1; + const start = + stack.length === 0 ? 0 : stack[stack.length - 1] + 1; const total = BigInt(prefixSum[i] - prefixSum[start]); const tmp = BigInt(nums[j]) * total; if (tmp > res) res = tmp; @@ -963,5 +975,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/maximum-subarray.md b/articles/maximum-subarray.md index afdcd634f..cc8073f80 100644 --- a/articles/maximum-subarray.md +++ b/articles/maximum-subarray.md @@ -54,7 +54,8 @@ class Solution { * @return {number} */ maxSubArray(nums) { - let n = nums.length, res = nums[0]; + let n = nums.length, + res = nums[0]; for (let i = 0; i < n; i++) { let cur = 0; for (let j = i; j < n; j++) { @@ -119,12 +120,31 @@ class Solution { } ``` +```swift +class Solution { + func maxSubArray(_ nums: [Int]) -> Int { + let n = nums.count + var res = nums[0] + + for i in 0..& nums, int i, bool flag) { if (i == nums.size()) return flag ? 0 : -1e6; if (flag) return max(0, nums[i] + dfs(nums, i + 1, true)); - return max(dfs(nums, i + 1, false), + return max(dfs(nums, i + 1, false), nums[i] + dfs(nums, i + 1, true)); } }; @@ -190,8 +210,7 @@ class Solution { const dfs = (i, flag) => { if (i === nums.length) return flag ? 0 : -1e6; if (flag) return Math.max(0, nums[i] + dfs(i + 1, true)); - return Math.max(dfs(i + 1, false), - nums[i] + dfs(i + 1, true)); + return Math.max(dfs(i + 1, false), nums[i] + dfs(i + 1, true)); }; return dfs(0, false); } @@ -207,7 +226,7 @@ public class Solution { private int Dfs(int[] nums, int i, bool flag) { if (i == nums.Length) return flag ? 0 : (int)-1e6; if (flag) return Math.Max(0, nums[i] + Dfs(nums, i + 1, true)); - return Math.Max(Dfs(nums, i + 1, false), + return Math.Max(Dfs(nums, i + 1, false), nums[i] + Dfs(nums, i + 1, true)); } } @@ -221,7 +240,7 @@ func maxSubArray(nums []int) int { if flag { return 0 } - return -1e6 + return -1e6 } if flag { return max(0, nums[i] + dfs(i + 1, true)) @@ -259,12 +278,32 @@ class Solution { } ``` +```swift +class Solution { + func maxSubArray(_ nums: [Int]) -> Int { + func dfs(_ i: Int, _ flag: Bool) -> Int { + if i == nums.count { + return flag ? 0 : Int.min + } + + if flag { + return max(0, nums[i] + dfs(i + 1, true)) + } + + return max(dfs(i + 1, false), nums[i] + dfs(i + 1, true)) + } + + return dfs(0, false) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -285,7 +324,7 @@ class Solution: if flag: memo[i][flag] = max(0, nums[i] + dfs(i + 1, True)) else: - memo[i][flag] = max(dfs(i + 1, False), + memo[i][flag] = max(dfs(i + 1, False), nums[i] + dfs(i + 1, True)) return memo[i][flag] @@ -307,7 +346,7 @@ public class Solution { int f = flag ? 1 : 0; if (memo[i][f] != Integer.MIN_VALUE) return memo[i][f]; memo[i][f] = flag ? Math.max(0, nums[i] + dfs(nums, i + 1, true)) - : Math.max(dfs(nums, i + 1, false), + : Math.max(dfs(nums, i + 1, false), nums[i] + dfs(nums, i + 1, true)); return memo[i][f]; } @@ -321,7 +360,7 @@ public: vector> memo(nums.size() + 1, vector(2, INT_MIN)); return dfs(nums, 0, false, memo); } - + private: int dfs(vector& nums, int i, bool flag, vector>& memo) { if (i == nums.size()) return flag ? 0 : -1e6; @@ -330,7 +369,7 @@ private: if (flag) memo[i][f] = max(0, nums[i] + dfs(nums, i + 1, true, memo)); else - memo[i][f] = max(dfs(nums, i + 1, false, memo), + memo[i][f] = max(dfs(nums, i + 1, false, memo), nums[i] + dfs(nums, i + 1, true, memo)); return memo[i][f]; } @@ -344,18 +383,18 @@ class Solution { * @return {number} */ maxSubArray(nums) { - const memo = Array(nums.length + 1).fill(null).map( - () => [null, null] - ); + const memo = Array(nums.length + 1) + .fill(null) + .map(() => [null, null]); const dfs = (i, flag) => { if (i === nums.length) return flag ? 0 : -1e6; if (memo[i][+flag] !== null) return memo[i][+flag]; - memo[i][+flag] = flag ? Math.max(0, nums[i] + dfs(i + 1, true)) - : Math.max(dfs(i + 1, false), - nums[i] + dfs(i + 1, true)); + memo[i][+flag] = flag + ? Math.max(0, nums[i] + dfs(i + 1, true)) + : Math.max(dfs(i + 1, false), nums[i] + dfs(i + 1, true)); return memo[i][+flag]; - } + }; return dfs(0, false); } } @@ -378,7 +417,7 @@ public class Solution { int f = flag ? 1 : 0; if (memo[i, f] != int.MinValue) return memo[i, f]; memo[i, f] = flag ? Math.Max(0, nums[i] + Dfs(nums, i + 1, true)) - : Math.Max(Dfs(nums, i + 1, false), + : Math.Max(Dfs(nums, i + 1, false), nums[i] + Dfs(nums, i + 1, true)); return memo[i, f]; } @@ -449,12 +488,39 @@ class Solution { } ``` +```swift +class Solution { + func maxSubArray(_ nums: [Int]) -> Int { + var memo = Array(repeating: [Int?](repeating: nil, count: 2), count: nums.count + 1) + + func dfs(_ i: Int, _ flag: Bool) -> Int { + if i == nums.count { + return flag ? 0 : Int.min + } + if let value = memo[i][flag ? 1 : 0] { + return value + } + + if flag { + memo[i][flag ? 1 : 0] = max(0, nums[i] + dfs(i + 1, true)) + } else { + memo[i][flag ? 1 : 0] = max(dfs(i + 1, false), nums[i] + dfs(i + 1, true)) + } + + return memo[i][flag ? 1 : 0]! + } + + return dfs(0, false) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -471,7 +537,7 @@ class Solution: for i in range(n - 2, -1, -1): dp[i][1] = max(nums[i], nums[i] + dp[i + 1][1]) dp[i][0] = max(dp[i + 1][0], dp[i][1]) - + return dp[0][0] ``` @@ -480,13 +546,13 @@ public class Solution { public int maxSubArray(int[] nums) { int n = nums.length; int[][] dp = new int[n + 1][2]; - + dp[n - 1][1] = dp[n - 1][0] = nums[n - 1]; for (int i = n - 2; i >= 0; i--) { dp[i][1] = Math.max(nums[i], nums[i] + dp[i + 1][1]); dp[i][0] = Math.max(dp[i + 1][0], dp[i][1]); } - + return dp[0][0]; } } @@ -498,13 +564,13 @@ public: int maxSubArray(vector& nums) { int n = nums.size(); vector> dp(n + 1, vector(2, 0)); - + dp[n - 1][1] = dp[n - 1][0] = nums[n - 1]; for (int i = n - 2; i >= 0; i--) { dp[i][1] = max(nums[i], nums[i] + dp[i + 1][1]); dp[i][0] = max(dp[i + 1][0], dp[i][1]); } - + return dp[0][0]; } }; @@ -519,13 +585,13 @@ class Solution { maxSubArray(nums) { const n = nums.length; const dp = Array.from({ length: n + 1 }, () => Array(2).fill(0)); - + dp[n - 1][1] = dp[n - 1][0] = nums[n - 1]; for (let i = n - 2; i >= 0; i--) { dp[i][1] = Math.max(nums[i], nums[i] + dp[i + 1][1]); dp[i][0] = Math.max(dp[i + 1][0], dp[i][1]); } - + return dp[0][0]; } } @@ -536,13 +602,13 @@ public class Solution { public int MaxSubArray(int[] nums) { int n = nums.Length; int[,] dp = new int[n + 1, 2]; - + dp[n - 1, 1] = dp[n - 1, 0] = nums[n - 1]; for (int i = n - 2; i >= 0; i--) { dp[i, 1] = Math.Max(nums[i], nums[i] + dp[i + 1, 1]); dp[i, 0] = Math.Max(dp[i + 1, 0], dp[i, 1]); } - + return dp[0, 0]; } } @@ -555,15 +621,15 @@ func maxSubArray(nums []int) int { for i := range dp { dp[i] = make([]int, 2) } - + dp[n-1][1] = nums[n-1] dp[n-1][0] = nums[n-1] - + for i := n-2; i >= 0; i-- { dp[i][1] = max(nums[i], nums[i] + dp[i+1][1]) dp[i][0] = max(dp[i+1][0], dp[i][1]) } - + return dp[0][0] } @@ -580,15 +646,33 @@ class Solution { fun maxSubArray(nums: IntArray): Int { val n = nums.size val dp = Array(n) { IntArray(2) } - + dp[n-1][1] = nums[n-1] dp[n-1][0] = nums[n-1] - + for (i in n-2 downTo 0) { dp[i][1] = maxOf(nums[i], nums[i] + dp[i+1][1]) dp[i][0] = maxOf(dp[i+1][0], dp[i][1]) } - + + return dp[0][0] + } +} +``` + +```swift +class Solution { + func maxSubArray(_ nums: [Int]) -> Int { + let n = nums.count + var dp = Array(repeating: [0, 0], count: n) + dp[n - 1][1] = nums[n - 1] + dp[n - 1][0] = nums[n - 1] + + for i in (0.. maxSum { maxSum = v } } - + return maxSum } @@ -708,22 +792,36 @@ func max(a, b int) int { class Solution { fun maxSubArray(nums: IntArray): Int { val dp = nums.copyOf() - + for (i in 1 until nums.size) { dp[i] = maxOf(nums[i], nums[i] + dp[i-1]) } - + return dp.maxOrNull() ?: nums[0] } } ``` +```swift +class Solution { + func maxSubArray(_ nums: [Int]) -> Int { + var dp = nums + + for i in 1.. Int { + var maxSub = nums[0] + var curSum = 0 + + for num in nums { + if curSum < 0 { + curSum = 0 + } + curSum += num + maxSub = max(maxSub, curSum) + } + + return maxSub + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -882,10 +1000,10 @@ class Solution: curSum += nums[i] rightSum = max(rightSum, curSum) - return (max(dfs(l, m - 1), - dfs(m + 1, r), + return (max(dfs(l, m - 1), + dfs(m + 1, r), leftSum + nums[m] + rightSum)) - + return dfs(0, len(nums) - 1) ``` @@ -894,7 +1012,7 @@ public class Solution { public int maxSubArray(int[] nums) { return dfs(nums, 0, nums.length - 1); } - + private int dfs(int[] nums, int l, int r) { if (l > r) { return Integer.MIN_VALUE; @@ -912,8 +1030,8 @@ public class Solution { rightSum = Math.max(rightSum, curSum); } - return Math.max(dfs(nums, l, m - 1), - Math.max(dfs(nums, m + 1, r), + return Math.max(dfs(nums, l, m - 1), + Math.max(dfs(nums, m + 1, r), leftSum + nums[m] + rightSum)); } } @@ -942,8 +1060,8 @@ private: curSum += nums[i]; rightSum = max(rightSum, curSum); } - return max(dfs(nums, l, m - 1), - max(dfs(nums, m + 1, r), + return max(dfs(nums, l, m - 1), + max(dfs(nums, m + 1, r), leftSum + nums[m] + rightSum)); } }; @@ -961,7 +1079,9 @@ class Solution { return -Infinity; } let m = (l + r) >> 1; - let leftSum = 0, rightSum = 0, curSum = 0; + let leftSum = 0, + rightSum = 0, + curSum = 0; for (let i = m - 1; i >= l; i--) { curSum += nums[i]; leftSum = Math.max(leftSum, curSum); @@ -972,11 +1092,12 @@ class Solution { curSum += nums[i]; rightSum = Math.max(rightSum, curSum); } - return Math.max(dfs(l, m - 1), - Math.max(dfs(m + 1, r), - leftSum + nums[m] + rightSum)); - } - + return Math.max( + dfs(l, m - 1), + Math.max(dfs(m + 1, r), leftSum + nums[m] + rightSum), + ); + }; + return dfs(0, nums.length - 1); } } @@ -987,7 +1108,7 @@ public class Solution { public int MaxSubArray(int[] nums) { return Dfs(nums, 0, nums.Length - 1); } - + private int Dfs(int[] nums, int l, int r) { if (l > r) { return int.MinValue; @@ -1005,8 +1126,8 @@ public class Solution { rightSum = Math.Max(rightSum, curSum); } - return Math.Max(Dfs(nums, l, m - 1), - Math.Max(Dfs(nums, m + 1, r), + return Math.Max(Dfs(nums, l, m - 1), + Math.Max(Dfs(nums, m + 1, r), leftSum + nums[m] + rightSum)); } } @@ -1019,17 +1140,17 @@ func maxSubArray(nums []int) int { if l > r { return math.MinInt64 } - + m := (l + r) >> 1 leftSum, rightSum, curSum := 0, 0, 0 - + for i := m - 1; i >= l; i-- { curSum += nums[i] if curSum > leftSum { leftSum = curSum } } - + curSum = 0 for i := m + 1; i <= r; i++ { curSum += nums[i] @@ -1037,14 +1158,14 @@ func maxSubArray(nums []int) int { rightSum = curSum } } - + maxLeft := dfs(l, m-1) maxRight := dfs(m+1, r) crossSum := leftSum + nums[m] + rightSum - + return max(max(maxLeft, maxRight), crossSum) } - + return dfs(0, len(nums)-1) } @@ -1063,38 +1184,71 @@ class Solution { if (l > r) { return Int.MIN_VALUE } - + val m = (l + r) shr 1 var leftSum = 0 var rightSum = 0 var curSum = 0 - + for (i in (m - 1) downTo l) { curSum += nums[i] leftSum = maxOf(leftSum, curSum) } - + curSum = 0 for (i in (m + 1)..r) { curSum += nums[i] rightSum = maxOf(rightSum, curSum) } - + return maxOf( dfs(l, m - 1), dfs(m + 1, r), leftSum + nums[m] + rightSum ) } - + return dfs(0, nums.size - 1) } } ``` +```swift +class Solution { + func maxSubArray(_ nums: [Int]) -> Int { + + func dfs(_ l: Int, _ r: Int) -> Int { + if l > r { + return Int.min + } + + let m = (l + r) / 2 + var leftSum = 0 + var rightSum = 0 + var curSum = 0 + + for i in stride(from: m - 1, through: l, by: -1) { + curSum += nums[i] + leftSum = max(leftSum, curSum) + } + + curSum = 0 + for i in stride(from: m + 1, to: r + 1, by: 1) { + curSum += nums[i] + rightSum = max(rightSum, curSum) + } + + return max(dfs(l, m - 1), dfs(m + 1, r), leftSum + nums[m] + rightSum) + } + + return dfs(0, nums.count - 1) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(\log n)$ \ No newline at end of file +- Time complexity: $O(n \log n)$ +- Space complexity: $O(\log n)$ diff --git a/articles/maximum-subsequence-score.md b/articles/maximum-subsequence-score.md new file mode 100644 index 000000000..b2f71c469 --- /dev/null +++ b/articles/maximum-subsequence-score.md @@ -0,0 +1,419 @@ +## 1. Brute Force (Recursion) + +::tabs-start + +```python +class Solution: + def maxScore(self, nums1: List[int], nums2: List[int], k: int) -> int: + n = len(nums1) + + def dfs(i, k, minVal, curSum): + if k == 0: + return curSum * minVal + if i == n or (n - i) < k: + return float("-inf") + if minVal == 0: + return 0 + + res = dfs(i + 1, k, minVal, curSum) + res = max(res, dfs(i + 1, k - 1, min(minVal, nums2[i]), curSum + nums1[i])) + return res + + return dfs(0, k, float("inf"), 0) +``` + +```java +public class Solution { + private int[] nums1, nums2; + private int n; + + public long maxScore(int[] nums1, int[] nums2, int k) { + this.nums1 = nums1; + this.nums2 = nums2; + this.n = nums1.length; + return dfs(0, k, Integer.MAX_VALUE, 0); + } + + private long dfs(int i, int k, int minVal, long curSum) { + if (k == 0) { + return curSum * minVal; + } + if (i == n || (n - i) < k) { + return Integer.MIN_VALUE; + } + if (minVal == 0) { + return 0; + } + + long res = dfs(i + 1, k, minVal, curSum); + res = Math.max( + res, + dfs(i + 1, k - 1, Math.min(minVal, nums2[i]), curSum + nums1[i]) + ); + return res; + } +} +``` + +```cpp +class Solution { +private: + vector nums1, nums2; + int n; + +public: + long long maxScore(vector& nums1, vector& nums2, int k) { + this->nums1 = nums1; + this->nums2 = nums2; + this->n = nums1.size(); + return dfs(0, k, INT_MAX, 0); + } + +private: + long long dfs(int i, int k, int minVal, long long curSum) { + if (k == 0) { + return curSum * minVal; + } + if (i == n || (n - i) < k) { + return INT_MIN; + } + if (minVal == 0) { + return 0; + } + + long long res = dfs(i + 1, k, minVal, curSum); + res = max(res, dfs(i + 1, k - 1, min(minVal, nums2[i]), curSum + nums1[i])); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ + maxScore(nums1, nums2, k) { + const n = nums1.length; + + const dfs = (i, k, minVal, curSum) => { + if (k === 0) { + return curSum * minVal; + } + if (i === n || n - i < k) { + return -Infinity; + } + if (minVal === 0) { + return 0; + } + + let res = dfs(i + 1, k, minVal, curSum); + res = Math.max( + res, + dfs( + i + 1, + k - 1, + Math.min(minVal, nums2[i]), + curSum + nums1[i], + ), + ); + return res; + }; + + return dfs(0, k, Infinity, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Min-Heap - I + +::tabs-start + +```python +class Solution: + def maxScore(self, nums1: List[int], nums2: List[int], k: int) -> int: + pairs = sorted(zip(nums1, nums2), key=lambda p: p[1], reverse=True) + + minHeap = [] + n1Sum = 0 + res = 0 + + for n1, n2 in pairs: + n1Sum += n1 + heapq.heappush(minHeap, n1) + + if len(minHeap) > k: + n1Sum -= heapq.heappop(minHeap) + + if len(minHeap) == k: + res = max(res, n1Sum * n2) + + return res +``` + +```java +public class Solution { + public long maxScore(int[] nums1, int[] nums2, int k) { + int n = nums1.length; + int[][] pairs = new int[n][2]; + + for (int i = 0; i < n; i++) { + pairs[i][0] = nums1[i]; + pairs[i][1] = nums2[i]; + } + + Arrays.sort(pairs, (a, b) -> Integer.compare(b[1], a[1])); + + PriorityQueue minHeap = new PriorityQueue<>(); + long n1Sum = 0, res = 0; + + for (int[] pair : pairs) { + n1Sum += pair[0]; + minHeap.offer(pair[0]); + + if (minHeap.size() > k) { + n1Sum -= minHeap.poll(); + } + + if (minHeap.size() == k) { + res = Math.max(res, n1Sum * pair[1]); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long maxScore(vector& nums1, vector& nums2, int k) { + int n = nums1.size(); + vector> pairs(n); + + for (int i = 0; i < n; i++) { + pairs[i] = {nums1[i], nums2[i]}; + } + + sort(pairs.begin(), pairs.end(), [](const auto& a, const auto& b) { + return b.second < a.second; + }); + + priority_queue, greater> minHeap; + long long n1Sum = 0, res = 0; + + for (auto& pair : pairs) { + n1Sum += pair.first; + minHeap.push(pair.first); + + if (minHeap.size() > k) { + n1Sum -= minHeap.top(); + minHeap.pop(); + } + + if (minHeap.size() == k) { + res = max(res, n1Sum * (long long)pair.second); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ + maxScore(nums1, nums2, k) { + let pairs = nums1.map((n1, i) => [n1, nums2[i]]); + pairs.sort((a, b) => b[1] - a[1]); + + let minHeap = new MinPriorityQueue(); + let n1Sum = 0, + res = 0; + + for (let [n1, n2] of pairs) { + n1Sum += n1; + minHeap.enqueue(n1); + + if (minHeap.size() > k) { + n1Sum -= minHeap.dequeue(); + } + + if (minHeap.size() === k) { + res = Math.max(res, n1Sum * n2); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Min-Heap - II + +::tabs-start + +```python +class Solution: + def maxScore(self, nums1: List[int], nums2: List[int], k: int) -> int: + n = len(nums1) + arr = [(nums2[i] << 30) | nums1[i] for i in range(n)] + arr.sort(reverse=True) + + minHeap = [] + n1Sum = 0 + res = 0 + + for num in arr: + n1, n2 = num & ((1 << 30) - 1), num >> 30 + n1Sum += n1 + heapq.heappush(minHeap, n1) + + if len(minHeap) > k: + n1Sum -= heapq.heappop(minHeap) + + if len(minHeap) == k: + res = max(res, n1Sum * n2) + + return res +``` + +```java +public class Solution { + public long maxScore(int[] nums1, int[] nums2, int k) { + int n = nums1.length; + long[] arr = new long[n]; + for (int i = 0; i < n; i++) { + arr[i] = ((long) nums2[i] << 30) | nums1[i]; + } + + Arrays.sort(arr); + PriorityQueue minHeap = new PriorityQueue<>(); + long n1Sum = 0, res = 0; + + for (int i = n - 1; i >= 0; i--) { + int n1 = (int) (arr[i] & ((1L << 30) - 1)); + int n2 = (int) (arr[i] >> 30); + n1Sum += n1; + minHeap.offer(n1); + + if (minHeap.size() > k) { + n1Sum -= minHeap.poll(); + } + if (minHeap.size() == k) { + res = Math.max(res, n1Sum * (long) n2); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long maxScore(vector& nums1, vector& nums2, int k) { + int n = nums1.size(); + vector arr(n); + for (int i = 0; i < n; i++) { + arr[i] = ((long long) nums2[i] << 30) | nums1[i]; + } + + sort(arr.rbegin(), arr.rend()); + priority_queue, greater> minHeap; + long long n1Sum = 0, res = 0; + + for (long long& num : arr) { + int n1 = num & ((1LL << 30) - 1); + int n2 = num >> 30; + n1Sum += n1; + minHeap.push(n1); + + if (minHeap.size() > k) { + n1Sum -= minHeap.top(); + minHeap.pop(); + } + if (minHeap.size() == k) { + res = max(res, n1Sum * (long long)n2); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums1 + * @param {number[]} nums2 + * @param {number} k + * @return {number} + */ + maxScore(nums1, nums2, k) { + const n = nums1.length; + const arr = []; + for (let i = 0; i < n; i++) { + arr.push((BigInt(nums2[i]) << BigInt(30)) | BigInt(nums1[i])); + } + + arr.sort((a, b) => Number(b - a)); + const minHeap = new MinPriorityQueue(); + let n1Sum = 0n, + res = 0n; + + for (let num of arr) { + let n1 = Number(num & ((1n << 30n) - 1n)); + let n2 = Number(num >> 30n); + n1Sum += BigInt(n1); + minHeap.enqueue(n1); + + if (minHeap.size() > k) { + n1Sum -= BigInt(minHeap.dequeue()); + } + if (minHeap.size() === k) { + res = BigInt(Math.max(Number(res), Number(n1Sum * BigInt(n2)))); + } + } + + return Number(res); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/maximum-sum-circular-subarray.md b/articles/maximum-sum-circular-subarray.md index d1f717448..844b40c7d 100644 --- a/articles/maximum-sum-circular-subarray.md +++ b/articles/maximum-sum-circular-subarray.md @@ -13,7 +13,7 @@ class Solution: for j in range(i, i + n): cur_sum += nums[j % n] res = max(res, cur_sum) - + return res ``` @@ -79,12 +79,31 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxSubarraySumCircular(int[] nums) { + int n = nums.Length; + int res = nums[0]; + + for (int i = 0; i < n; i++) { + int curSum = 0; + for (int j = i; j < i + n; j++) { + curSum += nums[j % n]; + res = Math.Max(res, curSum); + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. --- @@ -99,22 +118,22 @@ class Solution: right_max = [0] * n right_max[-1] = nums[-1] suffix_sum = nums[-1] - + for i in range(n - 2, -1, -1): suffix_sum += nums[i] right_max[i] = max(right_max[i + 1], suffix_sum) - + max_sum = nums[0] cur_max = 0 prefix_sum = 0 - + for i in range(n): cur_max = max(cur_max, 0) + nums[i] max_sum = max(max_sum, cur_max) prefix_sum += nums[i] if i + 1 < n: max_sum = max(max_sum, prefix_sum + right_max[i + 1]) - + return max_sum ``` @@ -216,12 +235,43 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxSubarraySumCircular(int[] nums) { + int n = nums.Length; + int[] rightMax = new int[n]; + rightMax[n - 1] = nums[n - 1]; + int suffixSum = nums[n - 1]; + + for (int i = n - 2; i >= 0; i--) { + suffixSum += nums[i]; + rightMax[i] = Math.Max(rightMax[i + 1], suffixSum); + } + + int maxSum = nums[0]; + int curMax = 0; + int prefixSum = 0; + + for (int i = 0; i < n; i++) { + curMax = Math.Max(curMax, 0) + nums[i]; + maxSum = Math.Max(maxSum, curMax); + prefixSum += nums[i]; + if (i + 1 < n) { + maxSum = Math.Max(maxSum, prefixSum + rightMax[i + 1]); + } + } + + return maxSum; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -292,8 +342,11 @@ class Solution { * @return {number} */ maxSubarraySumCircular(nums) { - let globMax = nums[0], globMin = nums[0]; - let curMax = 0, curMin = 0, total = 0; + let globMax = nums[0], + globMin = nums[0]; + let curMax = 0, + curMin = 0, + total = 0; for (const num of nums) { curMax = Math.max(curMax + num, num); @@ -308,9 +361,30 @@ class Solution { } ``` +```csharp +public class Solution { + public int MaxSubarraySumCircular(int[] nums) { + int globMax = nums[0], globMin = nums[0]; + int curMax = 0, curMin = 0, total = 0; + + foreach (int num in nums) { + curMax = Math.Max(curMax + num, num); + globMax = Math.Max(globMax, curMax); + + curMin = Math.Min(curMin + num, num); + globMin = Math.Min(globMin, curMin); + + total += num; + } + + return globMax > 0 ? Math.Max(globMax, total - globMin) : globMax; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/maximum-twin-sum-of-a-linked-list.md b/articles/maximum-twin-sum-of-a-linked-list.md new file mode 100644 index 000000000..d10e9ec86 --- /dev/null +++ b/articles/maximum-twin-sum-of-a-linked-list.md @@ -0,0 +1,458 @@ +## 1. Convert To Array + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def pairSum(self, head: Optional[ListNode]) -> int: + arr = [] + cur = head + while cur: + arr.append(cur.val) + cur = cur.next + + i, j = 0, len(arr) - 1 + res = 0 + while i < j: + res = max(res, arr[i] + arr[j]) + i, j = i + 1, j - 1 + + return res +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public int pairSum(ListNode head) { + List arr = new ArrayList<>(); + ListNode cur = head; + + while (cur != null) { + arr.add(cur.val); + cur = cur.next; + } + + int i = 0, j = arr.size() - 1, res = 0; + while (i < j) { + res = Math.max(res, arr.get(i) + arr.get(j)); + i++; + j--; + } + + return res; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + int pairSum(ListNode* head) { + vector arr; + ListNode* cur = head; + + while (cur) { + arr.push_back(cur->val); + cur = cur->next; + } + + int i = 0, j = arr.size() - 1, res = 0; + while (i < j) { + res = max(res, arr[i] + arr[j]); + i++; + j--; + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {number} + */ + pairSum(head) { + let arr = []; + let cur = head; + + while (cur) { + arr.push(cur.val); + cur = cur.next; + } + + let i = 0, + j = arr.length - 1, + res = 0; + while (i < j) { + res = Math.max(res, arr[i] + arr[j]); + i++; + j--; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Reverse the Second Half + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def pairSum(self, head: Optional[ListNode]) -> int: + slow, fast = head, head + while fast and fast.next: + slow = slow.next + fast = fast.next.next + + prev, cur = None, slow + while cur: + nxt = cur.next + cur.next = prev + prev = cur + cur = nxt + + res = 0 + first, second = head, prev + while second: + res = max(res, first.val + second.val) + first, second = first.next, second.next + + return res +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public int pairSum(ListNode head) { + ListNode slow = head, fast = head; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + } + + ListNode prev = null, cur = slow; + while (cur != null) { + ListNode nxt = cur.next; + cur.next = prev; + prev = cur; + cur = nxt; + } + + int res = 0; + ListNode first = head, second = prev; + while (second != null) { + res = Math.max(res, first.val + second.val); + first = first.next; + second = second.next; + } + + return res; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + int pairSum(ListNode* head) { + ListNode* slow = head, *fast = head; + while (fast && fast->next) { + slow = slow->next; + fast = fast->next->next; + } + + ListNode* prev = nullptr, *cur = slow; + while (cur) { + ListNode* nxt = cur->next; + cur->next = prev; + prev = cur; + cur = nxt; + } + + int res = 0; + ListNode* first = head, *second = prev; + while (second) { + res = max(res, first->val + second->val); + first = first->next; + second = second->next; + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {number} + */ + pairSum(head) { + let slow = head, + fast = head; + while (fast && fast.next) { + slow = slow.next; + fast = fast.next.next; + } + + let prev = null, + cur = slow; + while (cur) { + let nxt = cur.next; + cur.next = prev; + prev = cur; + cur = nxt; + } + + let res = 0, + first = head, + second = prev; + while (second) { + res = Math.max(res, first.val + second.val); + first = first.next; + second = second.next; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 3. Reverse the First Half + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def pairSum(self, head: Optional[ListNode]) -> int: + slow, fast = head, head + prev = None + + while fast and fast.next: + fast = fast.next.next + tmp = slow.next + slow.next = prev + prev = slow + slow = tmp + + res = 0 + while slow: + res = max(res, prev.val + slow.val) + prev = prev.next + slow = slow.next + + return res +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public int pairSum(ListNode head) { + ListNode slow = head, fast = head, prev = null; + + while (fast != null && fast.next != null) { + fast = fast.next.next; + ListNode tmp = slow.next; + slow.next = prev; + prev = slow; + slow = tmp; + } + + int res = 0; + while (slow != null) { + res = Math.max(res, prev.val + slow.val); + prev = prev.next; + slow = slow.next; + } + + return res; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + int pairSum(ListNode* head) { + ListNode* slow = head, *fast = head, *prev = nullptr; + + while (fast && fast->next) { + fast = fast->next->next; + ListNode* tmp = slow->next; + slow->next = prev; + prev = slow; + slow = tmp; + } + + int res = 0; + while (slow) { + res = max(res, prev->val + slow->val); + prev = prev->next; + slow = slow->next; + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {number} + */ + pairSum(head) { + let slow = head, + fast = head, + prev = null; + + while (fast && fast.next) { + fast = fast.next.next; + let tmp = slow.next; + slow.next = prev; + prev = slow; + slow = tmp; + } + + let res = 0; + while (slow) { + res = Math.max(res, prev.val + slow.val); + prev = prev.next; + slow = slow.next; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/maximum-value-of-k-coins-from-piles.md b/articles/maximum-value-of-k-coins-from-piles.md index bf108e73c..9f97cf068 100644 --- a/articles/maximum-value-of-k-coins-from-piles.md +++ b/articles/maximum-value-of-k-coins-from-piles.md @@ -100,8 +100,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(k ^ n)$ -* Space complexity: $O(n)$ for the recursion stack. +- Time complexity: $O(k ^ n)$ +- Space complexity: $O(n)$ for the recursion stack. > Where $n$ is the number of piles and $k$ is the number of coins to choose. @@ -215,7 +215,10 @@ class Solution { let curPile = 0; for (let j = 0; j < Math.min(coins, piles[i].length); j++) { curPile += piles[i][j]; - dp[i][coins] = Math.max(dp[i][coins], curPile + dfs(i + 1, coins - (j + 1))); + dp[i][coins] = Math.max( + dp[i][coins], + curPile + dfs(i + 1, coins - (j + 1)), + ); } return dp[i][coins]; }; @@ -229,8 +232,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * k)$ -* Space complexity: $O(n * k)$ +- Time complexity: $O(m * k)$ +- Space complexity: $O(n * k)$ > Where $n$ is the number of piles, $k$ is the number of coins to choose, and $m$ is the total number of coins among all the piles. @@ -245,11 +248,11 @@ class Solution: def maxValueOfCoins(self, piles: List[List[int]], k: int) -> int: n = len(piles) dp = [[0] * (k + 1) for _ in range(n + 1)] - + for i in range(n - 1, -1, -1): for coins in range(k + 1): dp[i][coins] = dp[i + 1][coins] - + curPile = 0 for j in range(min(coins, len(piles[i]))): curPile += piles[i][j] @@ -257,7 +260,7 @@ class Solution: dp[i][coins], curPile + dp[i + 1][coins - (j + 1)] ) - + return dp[0][k] ``` @@ -334,7 +337,7 @@ class Solution { curPile += piles[i][j]; dp[i][coins] = Math.max( dp[i][coins], - curPile + dp[i + 1][coins - (j + 1)] + curPile + dp[i + 1][coins - (j + 1)], ); } } @@ -349,8 +352,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * k)$ -* Space complexity: $O(n * k)$ +- Time complexity: $O(m * k)$ +- Space complexity: $O(n * k)$ > Where $n$ is the number of piles, $k$ is the number of coins to choose, and $m$ is the total number of coins among all the piles. @@ -431,7 +434,10 @@ class Solution { let curPile = 0; for (let j = 0; j < Math.min(coins, pile.length); j++) { curPile += pile[j]; - dp[coins] = Math.max(dp[coins], dp[coins - (j + 1)] + curPile); + dp[coins] = Math.max( + dp[coins], + dp[coins - (j + 1)] + curPile, + ); } } } @@ -445,7 +451,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * k)$ -* Space complexity: $O(n * k)$ +- Time complexity: $O(m * k)$ +- Space complexity: $O(n * k)$ -> Where $n$ is the number of piles, $k$ is the number of coins to choose, and $m$ is the total number of coins among all the piles. \ No newline at end of file +> Where $n$ is the number of piles, $k$ is the number of coins to choose, and $m$ is the total number of coins among all the piles. diff --git a/articles/maximum-width-of-binary-tree.md b/articles/maximum-width-of-binary-tree.md new file mode 100644 index 000000000..3c86c8f23 --- /dev/null +++ b/articles/maximum-width-of-binary-tree.md @@ -0,0 +1,514 @@ +## 1. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def widthOfBinaryTree(self, root: Optional[TreeNode]) -> int: + res = 0 + q = deque([(root, 1, 0)]) # [node, num, level] + prevLevel, prevNum = 0, 1 + + while q: + node, num, level = q.popleft() + + if level > prevLevel: + prevLevel = level + prevNum = num + + res = max(res, num - prevNum + 1) + if node.left: + q.append((node.left, 2 * num, level + 1)) + if node.right: + q.append((node.right, 2 * num + 1, level + 1)) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int widthOfBinaryTree(TreeNode root) { + if (root == null) return 0; + + int res = 0; + Queue queue = new LinkedList<>(); + queue.offer(new Tuple(root, 1, 0)); // [node, num, level] + int prevLevel = 0, prevNum = 1; + + while (!queue.isEmpty()) { + Tuple current = queue.poll(); + TreeNode node = current.node; + int num = current.num; + int level = current.level; + + if (level > prevLevel) { + prevLevel = level; + prevNum = num; + } + + res = Math.max(res, num - prevNum + 1); + if (node.left != null) { + queue.offer(new Tuple(node.left, 2 * num, level + 1)); + } + if (node.right != null) { + queue.offer(new Tuple(node.right, 2 * num + 1, level + 1)); + } + } + + return res; + } + + class Tuple { + TreeNode node; + int num, level; + + Tuple(TreeNode node, int num, int level) { + this.node = node; + this.num = num; + this.level = level; + } + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int widthOfBinaryTree(TreeNode* root) { + if (!root) return 0; + + int res = 0; + queue> q; // [node, num, level] + q.push({root, 1, 0}); + int prevLevel = 0, prevNum = 1; + + while (!q.empty()) { + auto [node, num, level] = q.front(); + q.pop(); + + if (level > prevLevel) { + prevLevel = level; + prevNum = num; + } + + res = max(res, int(num - prevNum) + 1); + if (node->left) { + q.push({node->left, 2 * num, level + 1}); + } + if (node->right) { + q.push({node->right, 2 * num + 1, level + 1}); + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + widthOfBinaryTree(root) { + if (!root) return 0; + + let res = 0n; + const queue = new Queue([[root, 1n, 0]]); // [node, num, level] + let prevLevel = 0, + prevNum = 1n; + + while (!queue.isEmpty()) { + const [node, num, level] = queue.pop(); + + if (level > prevLevel) { + prevLevel = level; + prevNum = num; + } + + res = res > num - prevNum + 1n ? res : num - prevNum + 1n; + if (node.left) { + queue.push([node.left, 2n * num, level + 1]); + } + if (node.right) { + queue.push([node.right, 2n * num + 1n, level + 1]); + } + } + + return Number(res); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Breadth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def widthOfBinaryTree(self, root: Optional[TreeNode]) -> int: + res = 0 + q = deque([(root, 0)]) + + while q: + start = q[0][1] + for _ in range(len(q)): + node, num = q.popleft() + curNum = num - start + res = max(res, curNum + 1) + if node.left: + q.append((node.left, 2 * curNum)) + if node.right: + q.append((node.right, 2 * curNum + 1)) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int widthOfBinaryTree(TreeNode root) { + int res = 0; + Queue> q = new LinkedList<>(); + q.offer(new Pair<>(root, 0)); + + while (!q.isEmpty()) { + int start = q.peek().getValue(); + for (int i = q.size(); i > 0; i--) { + Pair pair = q.poll(); + TreeNode node = pair.getKey(); + int num = pair.getValue() - start; + + res = Math.max(res, num + 1); + if (node.left != null) { + q.offer(new Pair<>(node.left, 2 * num)); + } + if (node.right != null) { + q.offer(new Pair<>(node.right, 2 * num + 1)); + } + } + } + + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int widthOfBinaryTree(TreeNode* root) { + int res = 0; + queue> q; + q.push({root, 0}); + + while (!q.empty()) { + int start = q.front().second; + + for (int i = q.size(); i > 0; --i) { + auto [node, num] = q.front(); + q.pop(); + uint curNum = num - start; + res = max(res, int(curNum) + 1); + if (node->left) { + q.push({node->left, 2 * curNum}); + } + if (node->right) { + q.push({node->right, 2 * curNum + 1}); + } + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + widthOfBinaryTree(root) { + let res = 0; + const q = new Queue([[root, 0]]); + + while (!q.isEmpty()) { + const start = q.front()[1]; + + for (let i = q.size(); i > 0; i--) { + const [node, num] = q.pop(); + const curNum = num - start; + res = Math.max(res, curNum + 1); + if (node.left) { + q.push([node.left, 2 * curNum]); + } + if (node.right) { + q.push([node.right, 2 * curNum + 1]); + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def widthOfBinaryTree(self, root: Optional[TreeNode]) -> int: + first = {} + res = 0 + + def dfs(node, level, num): + nonlocal res + if not node: + return + + if level not in first: + first[level] = num + + res = max(res, num - first[level] + 1) + dfs(node.left, level + 1, 2 * num) + dfs(node.right, level + 1, 2 * num + 1) + + dfs(root, 0, 0) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private Map first; + public int widthOfBinaryTree(TreeNode root) { + first = new HashMap<>(); + int[] res = new int[1]; + + dfs(root, 0, 0, res); + return res[0]; + } + + private void dfs(TreeNode node, int level, int num, int[] res) { + if (node == null) { + return; + } + + first.putIfAbsent(level, num); + res[0] = Math.max(res[0], num - first.get(level) + 1); + dfs(node.left, level + 1, 2 * num, res); + dfs(node.right, level + 1, 2 * num + 1, res); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { + unordered_map first; + +public: + int widthOfBinaryTree(TreeNode* root) { + unsigned long long res = 0; + + dfs(root, 0, 0, res); + return int(res); + } + +private: + void dfs(TreeNode* node, int level, unsigned long long num, unsigned long long& res) { + if (!node) { + return; + } + + if (!first.count(level)) { + first[level] = num; + } + + res = max(res, num - first[level] + 1); + dfs(node->left, level + 1, 2 * (num - first[level]), res); + dfs(node->right, level + 1, 2 * (num - first[level]) + 1, res); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + widthOfBinaryTree(root) { + const first = new Map(); + let res = 0; + + const dfs = (node, level, curNum) => { + if (!node) return; + + if (!first.has(level)) { + first.set(level, curNum); + } + + res = Math.max(res, curNum - first.get(level) + 1); + dfs(node.left, level + 1, 2 * (curNum - first.get(level))); + dfs(node.right, level + 1, 2 * (curNum - first.get(level)) + 1); + }; + + dfs(root, 0, 0); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/median-of-two-sorted-arrays.md b/articles/median-of-two-sorted-arrays.md index 6fb01b6af..562924891 100644 --- a/articles/median-of-two-sorted-arrays.md +++ b/articles/median-of-two-sorted-arrays.md @@ -9,7 +9,7 @@ class Solution: len2 = len(nums2) merged = nums1 + nums2 merged.sort() - + totalLen = len(merged) if totalLen % 2 == 0: return (merged[totalLen // 2 - 1] + merged[totalLen // 2]) / 2.0 @@ -25,7 +25,7 @@ public class Solution { System.arraycopy(nums1, 0, merged, 0, len1); System.arraycopy(nums2, 0, merged, len1, len2); Arrays.sort(merged); - + int totalLen = merged.length; if (totalLen % 2 == 0) { return (merged[totalLen / 2 - 1] + merged[totalLen / 2]) / 2.0; @@ -46,7 +46,7 @@ public: copy(nums1.begin(), nums1.end(), merged.begin()); copy(nums2.begin(), nums2.end(), merged.begin() + len1); sort(merged.begin(), merged.end()); - + int totalLen = merged.size(); if (totalLen % 2 == 0) { return (merged[totalLen / 2 - 1] + merged[totalLen / 2]) / 2.0; @@ -69,7 +69,7 @@ class Solution { const len2 = nums2.length; const merged = nums1.concat(nums2); merged.sort((a, b) => a - b); - + const totalLen = merged.length; if (totalLen % 2 === 0) { return (merged[totalLen / 2 - 1] + merged[totalLen / 2]) / 2.0; @@ -89,7 +89,7 @@ public class Solution { Array.Copy(nums1, merged, len1); Array.Copy(nums2, 0, merged, len1, len2); Array.Sort(merged); - + int totalLen = merged.Length; if (totalLen % 2 == 0) { return (merged[totalLen / 2 - 1] + merged[totalLen / 2]) / 2.0; @@ -127,12 +127,28 @@ class Solution { } ``` +```swift +class Solution { + func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double { + var merged = nums1 + nums2 + merged.sort() + + let totalLen = merged.count + if totalLen % 2 == 0 { + return (Double(merged[totalLen / 2 - 1]) + Double(merged[totalLen / 2])) / 2.0 + } else { + return Double(merged[totalLen / 2]) + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O((n + m)\log (n + m))$ -* Space complexity: $O(n + m)$ +- Time complexity: $O((n + m)\log (n + m))$ +- Space complexity: $O(n + m)$ > Where $n$ is the length of $nums1$ and $m$ is the length of $nums2$. @@ -250,11 +266,18 @@ class Solution { * @return {number} */ findMedianSortedArrays(nums1, nums2) { - let len1 = nums1.length, len2 = nums2.length; - let i = 0, j = 0; - let median1 = 0, median2 = 0; - - for (let count = 0; count < Math.floor((len1 + len2) / 2) + 1; count++) { + let len1 = nums1.length, + len2 = nums2.length; + let i = 0, + j = 0; + let median1 = 0, + median2 = 0; + + for ( + let count = 0; + count < Math.floor((len1 + len2) / 2) + 1; + count++ + ) { median2 = median1; if (i < len1 && j < len2) { if (nums1[i] > nums2[j]) { @@ -391,12 +414,47 @@ class Solution { } ``` +```kotlin +class Solution { + func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double { + let len1 = nums1.count, len2 = nums2.count + var i = 0, j = 0 + var median1 = 0, median2 = 0 + + for _ in 0..<(len1 + len2) / 2 + 1 { + median2 = median1 + if i < len1 && j < len2 { + if nums1[i] > nums2[j] { + median1 = nums2[j] + j += 1 + } else { + median1 = nums1[i] + i += 1 + } + } else if i < len1 { + median1 = nums1[i] + i += 1 + } else { + median1 = nums2[j] + j += 1 + } + } + + if (len1 + len2) % 2 == 1 { + return Double(median1) + } else { + return (Double(median1) + Double(median2)) / 2.0 + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(1)$ > Where $n$ is the length of $nums1$ and $m$ is the length of $nums2$. @@ -415,15 +473,15 @@ class Solution: return b[b_start + k - 1] if k == 1: return min(a[a_start], b[b_start]) - + i = min(m, k // 2) j = min(n, k // 2) - + if a[a_start + i - 1] > b[b_start + j - 1]: return self.get_kth(a, m, b, n - j, k - j, a_start, b_start + j) else: return self.get_kth(a, m - i, b, n, k - i, a_start + i, b_start) - + def findMedianSortedArrays(self, nums1: List[int], nums2: List[int]) -> float: left = (len(nums1) + len(nums2) + 1) // 2 right = (len(nums1) + len(nums2) + 2) // 2 @@ -508,9 +566,12 @@ class Solution { const n = nums2.length; const left = Math.floor((m + n + 1) / 2); const right = Math.floor((m + n + 2) / 2); - - return (this.getKth(nums1, m, nums2, n, left) + - this.getKth(nums1, m, nums2, n, right)) / 2.0; + + return ( + (this.getKth(nums1, m, nums2, n, left) + + this.getKth(nums1, m, nums2, n, right)) / + 2.0 + ); } /** @@ -596,10 +657,10 @@ func getKth(a []int, m int, b []int, n int, k int, aStart int, bStart int) int { } return b[bStart] } - + i := min(m, k/2) j := min(n, k/2) - + if a[aStart+i-1] > b[bStart+j-1] { return getKth(a, m, b[bStart+j:], n-j, k-j, aStart, 0) } @@ -633,17 +694,17 @@ class Solution { if (k == 1) { return minOf(a[aStart], b[bStart]) } - + val i = minOf(m, k / 2) val j = minOf(n, k / 2) - + return if (a[aStart + i - 1] > b[bStart + j - 1]) { getKth(a, m, b, n - j, k - j, aStart, bStart + j) } else { getKth(a, m - i, b, n, k - i, aStart + i, bStart) } } - + fun findMedianSortedArrays(nums1: IntArray, nums2: IntArray): Double { val left = (nums1.size + nums2.size + 1) / 2 val right = (nums1.size + nums2.size + 2) / 2 @@ -653,12 +714,44 @@ class Solution { } ``` +```swift +class Solution { + func getKth(_ a: [Int], _ m: Int, _ b: [Int], _ n: Int, _ k: Int, _ aStart: Int = 0, _ bStart: Int = 0) -> Int { + if m > n { + return getKth(b, n, a, m, k, bStart, aStart) + } + if m == 0 { + return b[bStart + k - 1] + } + if k == 1 { + return min(a[aStart], b[bStart]) + } + + let i = min(m, k / 2) + let j = min(n, k / 2) + + if a[aStart + i - 1] > b[bStart + j - 1] { + return getKth(a, m, b, n - j, k - j, aStart, bStart + j) + } else { + return getKth(a, m - i, b, n, k - i, aStart + i, bStart) + } + } + + func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double { + let left = (nums1.count + nums2.count + 1) / 2 + let right = (nums1.count + nums2.count + 2) / 2 + return (Double(getKth(nums1, nums1.count, nums2, nums2.count, left)) + + Double(getKth(nums1, nums1.count, nums2, nums2.count, right))) / 2.0 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log (m + n))$ -* Space complexity: $O(\log (m + n))$ +- Time complexity: $O(\log (m + n))$ +- Space complexity: $O(\log (m + n))$ for recursion stack. > Where $n$ is the length of $nums1$ and $m$ is the length of $nums2$. @@ -955,7 +1048,7 @@ class Solution { return if (total % 2 != 0) { Math.max(Aleft.toDouble(), Bleft.toDouble()) } else { - (Math.max(Aleft.toDouble(), Bleft.toDouble()) + + (Math.max(Aleft.toDouble(), Bleft.toDouble()) + Math.min(Aright.toDouble(), Bright.toDouble())) / 2.0 } } else if (Aleft > Bright) { @@ -969,11 +1062,49 @@ class Solution { } ``` +```swift +class Solution { + func findMedianSortedArrays(_ nums1: [Int], _ nums2: [Int]) -> Double { + var A = nums1, B = nums2 + if A.count > B.count { + swap(&A, &B) + } + + let total = A.count + B.count + let half = total / 2 + var l = 0 + var r = A.count + + while true { + let i = (l + r) / 2 + let j = half - i + + let Aleft = i > 0 ? Double(A[i - 1]) : -Double.infinity + let Aright = i < A.count ? Double(A[i]) : Double.infinity + let Bleft = j > 0 ? Double(B[j - 1]) : -Double.infinity + let Bright = j < B.count ? Double(B[j]) : Double.infinity + + if Aleft <= Bright && Bleft <= Aright { + if total % 2 == 1 { + return min(Aright, Bright) + } else { + return (max(Aleft, Bleft) + min(Aright, Bright)) / 2.0 + } + } else if Aleft > Bright { + r = i - 1 + } else { + l = i + 1 + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log (min(n, m)))$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log (min(n, m)))$ +- Space complexity: $O(1)$ -> Where $n$ is the length of $nums1$ and $m$ is the length of $nums2$. \ No newline at end of file +> Where $n$ is the length of $nums1$ and $m$ is the length of $nums2$. diff --git a/articles/meeting-rooms-iii.md b/articles/meeting-rooms-iii.md index d8d33bcdb..3505e7bb0 100644 --- a/articles/meeting-rooms-iii.md +++ b/articles/meeting-rooms-iii.md @@ -18,14 +18,14 @@ class Solution: meeting_count[i] += 1 rooms[i] = e break - + if rooms[min_room] > rooms[i]: min_room = i if found: continue meeting_count[min_room] += 1 rooms[min_room] += e - s - + return meeting_count.index(max(meeting_count)) ``` @@ -148,12 +148,54 @@ class Solution { } ``` +```csharp +public class Solution { + public int MostBooked(int n, int[][] meetings) { + Array.Sort(meetings, (a, b) => a[0].CompareTo(b[0])); + long[] rooms = new long[n]; // end times of meetings in rooms + int[] meetingCount = new int[n]; + + foreach (var meeting in meetings) { + int start = meeting[0], end = meeting[1]; + int minRoom = 0; + bool found = false; + + for (int i = 0; i < n; i++) { + if (rooms[i] <= start) { + meetingCount[i]++; + rooms[i] = end; + found = true; + break; + } + if (rooms[minRoom] > rooms[i]) { + minRoom = i; + } + } + + if (!found) { + meetingCount[minRoom]++; + rooms[minRoom] += end - start; + } + } + + int maxIndex = 0; + for (int i = 1; i < n; i++) { + if (meetingCount[i] > meetingCount[maxIndex]) { + maxIndex = i; + } + } + + return maxIndex; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m\log m + n * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(m\log m + n * m)$ +- Space complexity: $O(n)$ > Where $n$ is the number of rooms and $m$ is the number of meetings. @@ -180,7 +222,7 @@ class Solution: end_time, room = heapq.heappop(used) end = end_time + (end - start) heapq.heappush(available, room) - + room = heapq.heappop(available) heapq.heappush(used, (end, room)) count[room] += 1 @@ -191,14 +233,14 @@ class Solution: ```java public class Solution { public int mostBooked(int n, int[][] meetings) { - Arrays.sort(meetings, (a, b) -> Long.compare(a[0], b[0])); - PriorityQueue available = new PriorityQueue<>(); - PriorityQueue used = new PriorityQueue<>((a, b) -> + Arrays.sort(meetings, (a, b) -> Long.compare(a[0], b[0])); + PriorityQueue available = new PriorityQueue<>(); + PriorityQueue used = new PriorityQueue<>((a, b) -> a[0] == b[0] ? Long.compare(a[1], b[1]) : Long.compare(a[0], b[0]) - ); + ); for (int i = 0; i < n; i++) { available.offer(i); - } + } int[] count = new int[n]; for (int[] meeting : meetings) { @@ -286,10 +328,10 @@ class Solution { */ mostBooked(n, meetings) { meetings.sort((a, b) => a[0] - b[0]); - const available = new MinPriorityQueue({ compare: (a, b) => a - b }); - const used = new MinPriorityQueue({ - compare: (a, b) => (a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]), - }); + const available = new PriorityQueue((a, b) => a - b); + const used = new PriorityQueue((a, b) => + a[0] === b[0] ? a[1] - b[1] : a[0] - b[0], + ); for (let i = 0; i < n; i++) { available.enqueue(i); } @@ -318,12 +360,61 @@ class Solution { } ``` +```csharp +public class Solution { + public int MostBooked(int n, int[][] meetings) { + Array.Sort(meetings, (a, b) => a[0].CompareTo(b[0])); + + var available = new SortedSet(); + for (int i = 0; i < n; i++) { + available.Add(i); + } + + var used = new PriorityQueue<(long end, int room), (long end, int room)>( + Comparer<(long end, int room)>.Create((a, b) => + a.end != b.end ? a.end.CompareTo(b.end) : a.room.CompareTo(b.room)) + ); + + int[] count = new int[n]; + + foreach (var meeting in meetings) { + long start = meeting[0], end = meeting[1]; + + while (used.Count > 0 && used.Peek().end <= start) { + var (_, room) = used.Dequeue(); + available.Add(room); + } + + if (available.Count == 0) { + var (prevEnd, room) = used.Dequeue(); + end = prevEnd + (end - start); + available.Add(room); + } + + int assignedRoom = available.Min; + available.Remove(assignedRoom); + used.Enqueue((end, assignedRoom), (end, assignedRoom)); + count[assignedRoom]++; + } + + int maxRoom = 0; + for (int i = 1; i < n; i++) { + if (count[i] > count[maxRoom]) { + maxRoom = i; + } + } + + return maxRoom; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m\log m + m \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(m\log m + m \log n)$ +- Space complexity: $O(n)$ > Where $n$ is the number of rooms and $m$ is the number of meetings. @@ -347,7 +438,7 @@ class Solution: while available and available[0][0] < start: end_time, room = heapq.heappop(available) heapq.heappush(available, (start, room)) - + end_time, room = heapq.heappop(available) heapq.heappush(available, (end_time + (end - start), room)) count[room] += 1 @@ -359,7 +450,7 @@ class Solution: public class Solution { public int mostBooked(int n, int[][] meetings) { Arrays.sort(meetings, (a, b) -> Integer.compare(a[0], b[0])); - PriorityQueue available = new PriorityQueue<>((a, b) -> + PriorityQueue available = new PriorityQueue<>((a, b) -> a[0] == b[0] ? Long.compare(a[1], b[1]) : Long.compare(a[0], b[0]) ); for (int i = 0; i < n; i++) { @@ -430,9 +521,9 @@ class Solution { */ mostBooked(n, meetings) { meetings.sort((a, b) => a[0] - b[0]); - const available = new MinPriorityQueue({ - compare: (a, b) => (a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]) - }); + const available = new PriorityQueue((a, b) => + a[0] === b[0] ? a[1] - b[1] : a[0] - b[0], + ); for (let i = 0; i < n; i++) { available.enqueue([0, i]); } @@ -454,13 +545,62 @@ class Solution { } ``` +```csharp +public class Solution { + public int MostBooked(int n, int[][] meetings) { + Array.Sort(meetings, (a, b) => a[0].CompareTo(b[0])); + + var pq = new PriorityQueue<(long end, int room), (long end, int room)>( + Comparer<(long end, int room)>.Create((a, b) => + a.end != b.end ? a.end.CompareTo(b.end) : a.room.CompareTo(b.room)) + ); + + for (int i = 0; i < n; i++) { + pq.Enqueue((0, i), (0, i)); + } + + int[] count = new int[n]; + + foreach (var meeting in meetings) { + int start = meeting[0], end = meeting[1]; + + List<(long end, int room)> temp = new List<(long end, int room)>(); + + // Make sure rooms are not idle before meeting start + while (pq.Count > 0 && pq.Peek().end < start) { + var room = pq.Dequeue(); + temp.Add((start, room.room)); + } + + foreach (var item in temp) { + pq.Enqueue(item, item); + } + + var current = pq.Dequeue(); + long newEnd = current.end + (end - start); + pq.Enqueue((newEnd, current.room), (newEnd, current.room)); + count[current.room]++; + } + + int maxRoom = 0; + for (int i = 1; i < n; i++) { + if (count[i] > count[maxRoom]) { + maxRoom = i; + } + } + + return maxRoom; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(m \log m + m \log n)$ time in average case. - * $O(m \log m + m * n)$ time in worst case. -* Space complexity: $O(n)$ +- Time complexity: + - $O(m \log m + m \log n)$ time in average case. + - $O(m \log m + m * n)$ time in worst case. +- Space complexity: $O(n)$ -> Where $n$ is the number of rooms and $m$ is the number of meetings. \ No newline at end of file +> Where $n$ is the number of rooms and $m$ is the number of meetings. diff --git a/articles/meeting-schedule-ii.md b/articles/meeting-schedule-ii.md index ce53b1e92..e8bd996b2 100644 --- a/articles/meeting-schedule-ii.md +++ b/articles/meeting-schedule-ii.md @@ -128,14 +128,14 @@ public class Solution { public int MinMeetingRooms(List intervals) { intervals.Sort((a, b) => a.start.CompareTo(b.start)); var minHeap = new PriorityQueue(); - + foreach (var interval in intervals) { if (minHeap.Count > 0 && minHeap.Peek() <= interval.start) { minHeap.Dequeue(); } minHeap.Enqueue(interval.end, interval.end); } - + return minHeap.Count; } } @@ -193,12 +193,40 @@ class Solution { } ``` +```swift +/** + * Definition of Interval: + * class Interval { + * var start: Int + * var end: Int + * init(start: Int, end: Int) { + * self.start = start + * self.end = end + * } + * } + */ + +class Solution { + func minMeetingRooms(_ intervals: [Interval]) -> Int { + let sortedIntervals = intervals.sorted { $0.start < $1.start } + var minHeap = Heap() + for interval in sortedIntervals { + if !minHeap.isEmpty, let earliest = minHeap.min!, earliest <= interval.start { + minHeap.removeMin() + } + minHeap.insert(interval.end) + } + return minHeap.count + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -313,7 +341,8 @@ class Solution { mp.set(i.end, (mp.get(i.end) || 0) - 1); } const sortedKeys = Array.from(mp.keys()).sort((a, b) => a - b); - let prev = 0, res = 0; + let prev = 0, + res = 0; for (const key of sortedKeys) { prev += mp.get(key); res = Math.max(res, prev); @@ -369,13 +398,13 @@ func minMeetingRooms(intervals []Interval) int { mp[i.start]++ mp[i.end]-- } - + keys := make([]int, 0, len(mp)) for k := range mp { keys = append(keys, k) } sort.Ints(keys) - + prev := 0 res := 0 for _, k := range keys { @@ -401,7 +430,7 @@ class Solution { mp[i.start] = mp.getOrDefault(i.start, 0) + 1 mp[i.end] = mp.getOrDefault(i.end, 0) - 1 } - + val keys = mp.keys.sorted() var prev = 0 var res = 0 @@ -414,12 +443,43 @@ class Solution { } ``` +```swift +/** + * Definition of Interval: + * class Interval { + * var start: Int + * var end: Int + * init(start: Int, end: Int) { + * self.start = start + * self.end = end + * } + * } + */ + +class Solution { + func minMeetingRooms(_ intervals: [Interval]) -> Int { + var mp = [Int: Int]() + for interval in intervals { + mp[interval.start, default: 0] += 1 + mp[interval.end, default: 0] -= 1 + } + var prev = 0 + var res = 0 + for key in mp.keys.sorted() { + prev += mp[key]! + res = max(res, prev) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -440,7 +500,7 @@ class Solution: def minMeetingRooms(self, intervals: List[Interval]) -> int: start = sorted([i.start for i in intervals]) end = sorted([i.end for i in intervals]) - + res = count = 0 s = e = 0 while s < len(intervals): @@ -471,15 +531,15 @@ public class Solution { int n = intervals.size(); int[] start = new int[n]; int[] end = new int[n]; - + for (int i = 0; i < n; i++) { start[i] = intervals.get(i).start; end[i] = intervals.get(i).end; } - + Arrays.sort(start); Arrays.sort(end); - + int res = 0, count = 0, s = 0, e = 0; while (s < n) { if (start[s] < end[e]) { @@ -513,15 +573,15 @@ class Solution { public: int minMeetingRooms(vector& intervals) { vector start, end; - + for (const auto& i : intervals) { start.push_back(i.start); end.push_back(i.end); } - + sort(start.begin(), start.end()); sort(end.begin(), end.end()); - + int res = 0, count = 0, s = 0, e = 0; while (s < intervals.size()) { if (start[s] < end[e]) { @@ -555,10 +615,13 @@ class Solution { * @returns {number} */ minMeetingRooms(intervals) { - const start = intervals.map(i => i.start).sort((a, b) => a - b); - const end = intervals.map(i => i.end).sort((a, b) => a - b); - - let res = 0, count = 0, s = 0, e = 0; + const start = intervals.map((i) => i.start).sort((a, b) => a - b); + const end = intervals.map((i) => i.end).sort((a, b) => a - b); + + let res = 0, + count = 0, + s = 0, + e = 0; while (s < intervals.length) { if (start[s] < end[e]) { s++; @@ -591,15 +654,15 @@ public class Solution { int n = intervals.Count; int[] start = new int[n]; int[] end = new int[n]; - + for (int i = 0; i < n; i++) { start[i] = intervals[i].start; end[i] = intervals[i].end; } - + Array.Sort(start); Array.Sort(end); - + int res = 0, count = 0, s = 0, e = 0; while (s < n) { if (start[s] < end[e]) { @@ -628,18 +691,18 @@ public class Solution { func minMeetingRooms(intervals []Interval) int { start := make([]int, len(intervals)) end := make([]int, len(intervals)) - + for i, interval := range intervals { start[i] = interval.start end[i] = interval.end } - + sort.Ints(start) sort.Ints(end) - + res, count := 0, 0 s, e := 0, 0 - + for s < len(intervals) { if start[s] < end[e] { s++ @@ -652,7 +715,7 @@ func minMeetingRooms(intervals []Interval) int { res = count } } - + return res } ``` @@ -667,12 +730,12 @@ class Solution { fun minMeetingRooms(intervals: List): Int { val start = intervals.map { it.start }.sorted() val end = intervals.map { it.end }.sorted() - + var res = 0 var count = 0 var s = 0 var e = 0 - + while (s < intervals.size) { if (start[s] < end[e]) { s++ @@ -683,7 +746,41 @@ class Solution { } res = maxOf(res, count) } - + + return res + } +} +``` + +```swift +/** + * Definition of Interval: + * class Interval { + * var start: Int + * var end: Int + * init(start: Int, end: Int) { + * self.start = start + * self.end = end + * } + * } + */ + +class Solution { + func minMeetingRooms(_ intervals: [Interval]) -> Int { + let starts = intervals.map { $0.start }.sorted() + let ends = intervals.map { $0.end }.sorted() + + var res = 0, count = 0, s = 0, e = 0 + while s < intervals.count { + if starts[s] < ends[e] { + count += 1 + s += 1 + } else { + count -= 1 + e += 1 + } + res = max(res, count) + } return res } } @@ -693,8 +790,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -717,9 +814,9 @@ class Solution: for i in intervals: time.append((i.start, 1)) time.append((i.end, -1)) - + time.sort(key=lambda x: (x[0], x[1])) - + res = count = 0 for t in time: count += t[1] @@ -746,9 +843,9 @@ public class Solution { time.add(new int[] { i.start, 1 }); time.add(new int[] { i.end, -1 }); } - + time.sort((a, b) -> a[0] == b[0] ? a[1] - b[1] : a[0] - b[0]); - + int res = 0, count = 0; for (int[] t : time) { count += t[1]; @@ -780,11 +877,11 @@ public: time.push_back({i.start, 1}); time.push_back({i.end, -1}); } - + sort(time.begin(), time.end(), [](auto& a, auto& b) { return a.first == b.first ? a.second < b.second : a.first < b.first; }); - + int res = 0, count = 0; for (const auto& t : time) { count += t.second; @@ -817,10 +914,11 @@ class Solution { time.push([i.start, 1]); time.push([i.end, -1]); } - - time.sort((a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0]); - - let res = 0, count = 0; + + time.sort((a, b) => (a[0] === b[0] ? a[1] - b[1] : a[0] - b[0])); + + let res = 0, + count = 0; for (const t of time) { count += t[1]; res = Math.max(res, count); @@ -849,11 +947,11 @@ public class Solution { time.Add(new int[] { i.start, 1 }); time.Add(new int[] { i.end, -1 }); } - - time.Sort((a, b) => a[0] == b[0] ? + + time.Sort((a, b) => a[0] == b[0] ? a[1].CompareTo(b[1]) : a[0].CompareTo(b[0] )); - + int res = 0, count = 0; foreach (var t in time) { count += t[1]; @@ -907,23 +1005,64 @@ func minMeetingRooms(intervals []Interval) int { class Solution { fun minMeetingRooms(intervals: Array): Int { val time = mutableListOf>() - + for (i in intervals) { time.add(Pair(i.start, 1)) time.add(Pair(i.end, -1)) } - + time.sortWith(compareBy> { it.first } .thenBy { it.second }) - + var res = 0 var count = 0 - + for (t in time) { count += t.second res = maxOf(res, count) } - + + return res + } +} +``` + +```swift +/** + * Definition of Interval: + * class Interval { + * var start: Int + * var end: Int + * init(start: Int, end: Int) { + * self.start = start + * self.end = end + * } + * } + */ + +class Solution { + func minMeetingRooms(_ intervals: [Interval]) -> Int { + var times = [(Int, Int)]() + for interval in intervals { + times.append((interval.start, 1)) + times.append((interval.end, -1)) + } + + times.sort { + if $0.0 != $1.0 { + return $0.0 < $1.0 + } else { + return $0.1 < $1.1 + } + } + + var count = 0 + var res = 0 + for t in times { + count += t.1 + res = max(res, count) + } + return res } } @@ -933,5 +1072,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/meeting-schedule.md b/articles/meeting-schedule.md index 735df876a..e86091d50 100644 --- a/articles/meeting-schedule.md +++ b/articles/meeting-schedule.md @@ -205,12 +205,42 @@ class Solution { } ``` +```swift +/** + * Definition of Interval: + * class Interval { + * var start: Int + * var end: Int + * init(start: Int, end: Int) { + * self.start = start + * self.end = end + * } + * } + */ + +class Solution { + func canAttendMeetings(_ intervals: [Interval]) -> Bool { + let n = intervals.count + for i in 0.. max(A.start, B.start) { + return false + } + } + } + return true + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -286,8 +316,8 @@ public class Solution { class Solution { public: bool canAttendMeetings(vector& intervals) { - sort(intervals.begin(), intervals.end(), [](auto& x, auto& y) { - return x.start < y.start; + sort(intervals.begin(), intervals.end(), [](auto& x, auto& y) { + return x.start < y.start; }); for (int i = 1; i < intervals.size(); ++i) { if (intervals[i].start < intervals[i - 1].end) { @@ -400,9 +430,35 @@ class Solution { } ``` +```swift +/** + * Definition of Interval: + * class Interval { + * var start: Int + * var end: Int + * init(start: Int, end: Int) { + * self.start = start + * self.end = end + * } + * } + */ + +class Solution { + func canAttendMeetings(_ intervals: [Interval]) -> Bool { + let sortedIntervals = intervals.sorted { $0.start < $1.start } + for i in 1.. sortedIntervals[i].start { + return false + } + } + return true + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. \ No newline at end of file +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. diff --git a/articles/merge-in-between-linked-lists.md b/articles/merge-in-between-linked-lists.md index 2d8a1774f..5901892e9 100644 --- a/articles/merge-in-between-linked-lists.md +++ b/articles/merge-in-between-linked-lists.md @@ -20,7 +20,7 @@ class Solution: cur = list2 while cur.next: cur = cur.next - + cur.next = arr[b + 1] return list1 ``` @@ -40,19 +40,19 @@ public class Solution { public ListNode mergeInBetween(ListNode list1, int a, int b, ListNode list2) { ListNode cur = list1; List arr = new ArrayList<>(); - + while (cur != null) { arr.add(cur); cur = cur.next; } - + arr.get(a - 1).next = list2; cur = list2; - + while (cur.next != null) { cur = cur.next; } - + cur.next = arr.get(b + 1); return list1; } @@ -75,19 +75,19 @@ public: ListNode* mergeInBetween(ListNode* list1, int a, int b, ListNode* list2) { ListNode* cur = list1; vector arr; - + while (cur) { arr.push_back(cur); cur = cur->next; } - + arr[a - 1]->next = list2; cur = list2; - + while (cur->next) { cur = cur->next; } - + cur->next = arr[b + 1]; return list1; } @@ -115,19 +115,19 @@ class Solution { mergeInBetween(list1, a, b, list2) { let cur = list1; let arr = []; - + while (cur) { arr.push(cur); cur = cur.next; } - + arr[a - 1].next = list2; cur = list2; - + while (cur.next) { cur = cur.next; } - + cur.next = arr[b + 1]; return list1; } @@ -138,8 +138,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n)$ > Where $n$ is the length of the first list and $m$ is the length of the second list. @@ -159,23 +159,23 @@ class Solution: def mergeInBetween(self, list1: ListNode, a: int, b: int, list2: ListNode) -> ListNode: curr = list1 i = 0 - + while i < a - 1: curr = curr.next i += 1 head = curr - + while i <= b: curr = curr.next i += 1 - + head.next = list2 - + while list2.next: list2 = list2.next list2.next = curr - - return list1 + + return list1 ``` ```java @@ -193,25 +193,25 @@ public class Solution { public ListNode mergeInBetween(ListNode list1, int a, int b, ListNode list2) { ListNode curr = list1; int i = 0; - + while (i < a - 1) { curr = curr.next; i++; } ListNode head = curr; - + while (i <= b) { curr = curr.next; i++; } - + head.next = list2; - + while (list2.next != null) { list2 = list2.next; } list2.next = curr; - + return list1; } } @@ -233,24 +233,24 @@ public: ListNode* mergeInBetween(ListNode* list1, int a, int b, ListNode* list2) { ListNode* curr = list1; int i = 0; - + while (i < a - 1) { curr = curr->next; i++; } ListNode* head = curr; - + while (i <= b) { curr = curr->next; i++; } head->next = list2; - + while (list2->next) { list2 = list2->next; } list2->next = curr; - + return list1; } }; @@ -275,25 +275,26 @@ class Solution { * @return {ListNode} */ mergeInBetween(list1, a, b, list2) { - let curr = list1, i = 0; - + let curr = list1, + i = 0; + while (i < a - 1) { curr = curr.next; i++; } let head = curr; - + while (i <= b) { curr = curr.next; i++; } head.next = list2; - + while (list2.next) { list2 = list2.next; } list2.next = curr; - + return list1; } } @@ -303,8 +304,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n + m)$ +- Space complexity: $O(1)$ extra space. > Where $n$ is the length of the first list and $m$ is the length of the second list. @@ -329,11 +330,11 @@ class Solution: list2 = list2.next self.mergeInBetween(nxt, 0, b - 1, list2) return list1 - + if b == 0: list2.next = list1.next return list1 - + self.mergeInBetween(list1.next, a - 1, b - 1, list2) return list1 ``` @@ -354,19 +355,19 @@ public class Solution { if (a == 1) { ListNode nxt = list1.next; list1.next = list2; - + while (list2.next != null) { list2 = list2.next; } mergeInBetween(nxt, 0, b - 1, list2); return list1; } - + if (b == 0) { list2.next = list1.next; return list1; } - + mergeInBetween(list1.next, a - 1, b - 1, list2); return list1; } @@ -390,19 +391,19 @@ public: if (a == 1) { ListNode* nxt = list1->next; list1->next = list2; - + while (list2->next) { list2 = list2->next; } mergeInBetween(nxt, 0, b - 1, list2); return list1; } - + if (b == 0) { list2->next = list1->next; return list1; } - + mergeInBetween(list1->next, a - 1, b - 1, list2); return list1; } @@ -431,19 +432,19 @@ class Solution { if (a === 1) { let nxt = list1.next; list1.next = list2; - + while (list2.next) { list2 = list2.next; } this.mergeInBetween(nxt, 0, b - 1, list2); return list1; } - + if (b === 0) { list2.next = list1.next; return list1; } - + this.mergeInBetween(list1.next, a - 1, b - 1, list2); return list1; } @@ -454,7 +455,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n + m)$ +- Space complexity: $O(n)$ for recursion stack. -> Where $n$ is the length of the first list and $m$ is the length of the second list. \ No newline at end of file +> Where $n$ is the length of the first list and $m$ is the length of the second list. diff --git a/articles/merge-intervals.md b/articles/merge-intervals.md index 56f8a6313..9662e4587 100644 --- a/articles/merge-intervals.md +++ b/articles/merge-intervals.md @@ -164,12 +164,36 @@ class Solution { } ``` +```swift +class Solution { + func merge(_ intervals: [[Int]]) -> [[Int]] { + let intervals = intervals.sorted { $0[0] < $1[0] } + var output: [[Int]] = [intervals[0]] + + for interval in intervals { + let start = interval[0] + let end = interval[1] + var lastEnd = output.last![1] + + if start <= lastEnd { + output[output.count - 1][1] = max(lastEnd, end) + } else { + output.append([start, end]) + } + } + return output + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: + - $O(1)$ or $O(n)$ space depending on the sorting algorithm. + - $O(n)$ for the output list. --- @@ -203,16 +227,16 @@ class Solution: public class Solution { public int[][] merge(int[][] intervals) { TreeMap map = new TreeMap<>(); - + for (int[] interval : intervals) { map.put(interval[0], map.getOrDefault(interval[0], 0) + 1); map.put(interval[1], map.getOrDefault(interval[1], 0) - 1); } - + List res = new ArrayList<>(); int have = 0; int[] interval = new int[2]; - + for (int point : map.keySet()) { if (have == 0) interval[0] = point; have += map.get(point); @@ -221,7 +245,7 @@ public class Solution { res.add(new int[] {interval[0], interval[1]}); } } - + return res.toArray(new int[res.size()][]); } } @@ -381,12 +405,44 @@ class Solution { } ``` +```swift +class Solution { + func merge(_ intervals: [[Int]]) -> [[Int]] { + var mp = [Int: Int]() + + for interval in intervals { + let start = interval[0] + let end = interval[1] + mp[start, default: 0] += 1 + mp[end, default: 0] -= 1 + } + + var res = [[Int]]() + var interval = [Int]() + var have = 0 + + for i in mp.keys.sorted() { + if interval.isEmpty { + interval.append(i) + } + have += mp[i, default: 0] + if have == 0 { + interval.append(i) + res.append(interval) + interval = [] + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -398,7 +454,7 @@ class Solution { class Solution: def merge(self, intervals: List[List[int]]) -> List[List[int]]: max_val = max(interval[0] for interval in intervals) - + mp = [0] * (max_val + 1) for start, end in intervals: mp[start] = max(end + 1, mp[start]) @@ -676,11 +732,49 @@ class Solution { } ``` +```swift +class Solution { + func merge(_ intervals: [[Int]]) -> [[Int]] { + let maxVal = intervals.map { $0[0] }.max() ?? 0 + var mp = [Int](repeating: 0, count: maxVal + 1) + for interval in intervals { + let start = interval[0] + let end = interval[1] + mp[start] = max(end + 1, mp[start]) + } + + var res = [[Int]]() + var have = -1 + var intervalStart = -1 + + for i in 0.. Where $n$ is the length of the array and $m$ is the maximum start value among all the intervals. \ No newline at end of file +> Where $n$ is the length of the array and $m$ is the maximum start value among all the intervals. diff --git a/articles/merge-k-sorted-linked-lists.md b/articles/merge-k-sorted-linked-lists.md index fd102df3f..a57acd659 100644 --- a/articles/merge-k-sorted-linked-lists.md +++ b/articles/merge-k-sorted-linked-lists.md @@ -9,7 +9,7 @@ # self.val = val # self.next = next -class Solution: +class Solution: def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: nodes = [] for lst in lists: @@ -38,7 +38,7 @@ class Solution: * } */ -public class Solution { +public class Solution { public ListNode mergeKLists(ListNode[] lists) { List nodes = new ArrayList<>(); for (ListNode lst : lists) { @@ -72,7 +72,7 @@ public class Solution { * }; */ -class Solution { +class Solution { public: ListNode* mergeKLists(vector& lists) { vector nodes; @@ -145,7 +145,7 @@ class Solution { * } */ -public class Solution { +public class Solution { public ListNode MergeKLists(ListNode[] lists) { List nodes = new List(); foreach (ListNode lst in lists) { @@ -178,7 +178,7 @@ public class Solution { */ func mergeKLists(lists []*ListNode) *ListNode { nodes := make([]int, 0) - + for _, list := range lists { curr := list for curr != nil { @@ -186,17 +186,17 @@ func mergeKLists(lists []*ListNode) *ListNode { curr = curr.Next } } - + sort.Ints(nodes) - + dummy := &ListNode{Val: 0} curr := dummy - + for _, val := range nodes { curr.Next = &ListNode{Val: val} curr = curr.Next } - + return dummy.Next } ``` @@ -214,7 +214,7 @@ func mergeKLists(lists []*ListNode) *ListNode { class Solution { fun mergeKLists(lists: Array): ListNode? { val nodes = mutableListOf() - + for (list in lists) { var curr = list while (curr != null) { @@ -222,17 +222,54 @@ class Solution { curr = curr.next } } - + nodes.sort() - + val dummy = ListNode(0) var curr = dummy - + for (value in nodes) { curr.next = ListNode(value) curr = curr.next!! } - + + return dummy.next + } +} +``` + +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func mergeKLists(_ lists: [ListNode?]) -> ListNode? { + var nodes: [Int] = [] + + for list in lists { + var lst = list + while lst != nil { + nodes.append(lst!.val) + lst = lst?.next + } + } + + nodes.sort() + + let dummy = ListNode(0) + var cur = dummy + for node in nodes { + cur.next = ListNode(node) + cur = cur.next! + } + return dummy.next } } @@ -242,8 +279,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -258,11 +295,11 @@ class Solution { # self.val = val # self.next = next -class Solution: +class Solution: def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: res = ListNode(0) cur = res - + while True: minNode = -1 for i in range(len(lists)): @@ -270,7 +307,7 @@ class Solution: continue if minNode == -1 or lists[minNode].val > lists[i].val: minNode = i - + if minNode == -1: break cur.next = lists[minNode] @@ -292,7 +329,7 @@ class Solution: * } */ -public class Solution { +public class Solution { public ListNode mergeKLists(ListNode[] lists) { ListNode res = new ListNode(0); ListNode cur = res; @@ -333,7 +370,7 @@ public class Solution { * }; */ -class Solution { +class Solution { public: ListNode* mergeKLists(vector& lists) { ListNode* res = new ListNode(0); @@ -410,7 +447,7 @@ class Solution { * } */ -public class Solution { +public class Solution { public ListNode MergeKLists(ListNode[] lists) { ListNode res = new ListNode(0); ListNode cur = res; @@ -445,7 +482,7 @@ public class Solution { func mergeKLists(lists []*ListNode) *ListNode { res := &ListNode{Val: 0} cur := res - + for { minNode := -1 for i := range lists { @@ -456,16 +493,16 @@ func mergeKLists(lists []*ListNode) *ListNode { minNode = i } } - + if minNode == -1 { break } - + cur.Next = lists[minNode] lists[minNode] = lists[minNode].Next cur = cur.Next } - + return res.Next } ``` @@ -484,7 +521,7 @@ class Solution { fun mergeKLists(lists: Array): ListNode? { val res = ListNode(0) var cur = res - + while (true) { var minNode = -1 for (i in lists.indices) { @@ -495,27 +532,68 @@ class Solution { minNode = i } } - + if (minNode == -1) { break } - + cur.next = lists[minNode] lists[minNode] = lists[minNode]!!.next cur = cur.next!! } - + return res.next } } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func mergeKLists(_ lists: [ListNode?]) -> ListNode? { + var lists = lists + let dummy = ListNode(0) + var cur = dummy + + while true { + var minNodeIndex: Int? = nil + for i in 0.. Where $k$ is the total number of lists and $n$ is the total number of nodes across $k$ lists. @@ -532,14 +610,14 @@ class Solution { # self.val = val # self.next = next -class Solution: +class Solution: def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: if len(lists) == 0: return None for i in range(1, len(lists)): lists[i] = self.mergeList(lists[i - 1], lists[i]) - + return lists[-1] def mergeList(self, l1, l2): @@ -775,7 +853,7 @@ public class Solution { func mergeList(l1 *ListNode, l2 *ListNode) *ListNode { dummy := &ListNode{} tail := dummy - + for l1 != nil && l2 != nil { if l1.Val < l2.Val { tail.Next = l1 @@ -786,14 +864,14 @@ func mergeList(l1 *ListNode, l2 *ListNode) *ListNode { } tail = tail.Next } - + if l1 != nil { tail.Next = l1 } if l2 != nil { tail.Next = l2 } - + return dummy.Next } @@ -801,11 +879,11 @@ func mergeKLists(lists []*ListNode) *ListNode { if len(lists) == 0 { return nil } - + for i := 1; i < len(lists); i++ { lists[i] = mergeList(lists[i-1], lists[i]) } - + return lists[len(lists)-1] } ``` @@ -826,7 +904,7 @@ class Solution { var tail = dummy var first = l1 var second = l2 - + while (first != null && second != null) { if (first.`val` < second.`val`) { tail.next = first @@ -837,37 +915,90 @@ class Solution { } tail = tail.next!! } - + if (first != null) { tail.next = first } if (second != null) { tail.next = second } - + return dummy.next } - + fun mergeKLists(lists: Array): ListNode? { if (lists.isEmpty()) { return null } - + for (i in 1 until lists.size) { lists[i] = mergeList(lists[i-1], lists[i]) } - + return lists.last() } } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func mergeKLists(_ lists: [ListNode?]) -> ListNode? { + if lists.isEmpty { + return nil + } + + var lists = lists + for i in 1.. ListNode? { + let dummy = ListNode(0) + var tail = dummy + var l1 = l1, l2 = l2 + + while l1 != nil && l2 != nil { + if l1!.val < l2!.val { + tail.next = l1 + l1 = l1?.next + } else { + tail.next = l2 + l2 = l2?.next + } + tail = tail.next! + } + + if l1 != nil { + tail.next = l1 + } + if l2 != nil { + tail.next = l2 + } + + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * k)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n * k)$ +- Space complexity: $O(1)$ > Where $k$ is the total number of lists and $n$ is the total number of nodes across $k$ lists. @@ -891,7 +1022,7 @@ class NodeWrapper: def __lt__(self, other): return self.node.val < other.node.val -class Solution: +class Solution: def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: if len(lists) == 0: return None @@ -908,10 +1039,10 @@ class Solution: node_wrapper = heapq.heappop(minHeap) cur.next = node_wrapper.node cur = cur.next - + if node_wrapper.node.next: heapq.heappush(minHeap, NodeWrapper(node_wrapper.node.next)) - + return res.next ``` @@ -930,7 +1061,7 @@ class Solution: class Solution { public ListNode mergeKLists(ListNode[] lists) { if (lists.length == 0) return null; - + PriorityQueue minHeap = new PriorityQueue<>((a, b) -> a.val - b.val); for (ListNode list : lists) { if (list != null) { @@ -974,7 +1105,7 @@ public: auto cmp = [](ListNode* a, ListNode* b) { return a->val > b->val; }; priority_queue, decltype(cmp)> minHeap(cmp); - + for (ListNode* list : lists) { if (list != nullptr) { minHeap.push(list); @@ -1017,10 +1148,9 @@ class Solution { */ mergeKLists(lists) { if (lists.length === 0) return null; - const minHeap = new MinPriorityQueue(x => x.val); + const minHeap = new MinPriorityQueue((x) => x.val); for (let list of lists) { - if (list != null) - minHeap.enqueue(list); + if (list != null) minHeap.enqueue(list); } let res = new ListNode(0); @@ -1093,30 +1223,30 @@ func mergeKLists(lists []*ListNode) *ListNode { if len(lists) == 0 { return nil } - + minHeap := priorityqueue.NewWith(func(a, b interface{}) int { return a.(*ListNode).Val - b.(*ListNode).Val }) - + for _, list := range lists { if list != nil { minHeap.Enqueue(list) } } - + res := &ListNode{Val: 0} cur := res - + for !minHeap.Empty() { node, _ := minHeap.Dequeue() cur.Next = node.(*ListNode) cur = cur.Next - + if cur.Next != nil { minHeap.Enqueue(cur.Next) } } - + return res.Next } ``` @@ -1134,35 +1264,89 @@ func mergeKLists(lists []*ListNode) *ListNode { class Solution { fun mergeKLists(lists: Array): ListNode? { if (lists.isEmpty()) return null - + val minHeap = PriorityQueue(compareBy { it.`val` }) - + for (list in lists) { list?.let { minHeap.offer(it) } } - + val res = ListNode(0) var cur = res - + while (minHeap.isNotEmpty()) { val node = minHeap.poll() cur.next = node cur = cur.next!! - + node.next?.let { minHeap.offer(it) } } - + return res.next } } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +struct NodeWrapper: Comparable { + let node: ListNode + + init(_ node: ListNode) { + self.node = node + } + + static func < (lhs: NodeWrapper, rhs: NodeWrapper) -> Bool { + return lhs.node.val < rhs.node.val + } + + static func == (lhs: NodeWrapper, rhs: NodeWrapper) -> Bool { + return lhs.node.val == rhs.node.val + } +} + +class Solution { + func mergeKLists(_ lists: [ListNode?]) -> ListNode? { + var heap = Heap() + + for list in lists { + if let node = list { + heap.insert(NodeWrapper(node)) + } + } + + let dummy = ListNode(0) + var tail = dummy + + while let wrapper = heap.popMin() { + tail.next = wrapper.node + tail = tail.next! + + if let next = wrapper.node.next { + heap.insert(NodeWrapper(next)) + } + } + + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log k)$ -* Space complexity: $O(k)$ +- Time complexity: $O(n \log k)$ +- Space complexity: $O(k)$ > Where $k$ is the total number of lists and $n$ is the total number of nodes across $k$ lists. @@ -1190,14 +1374,17 @@ class Solution: return None if l == r: return lists[l] + mid = l + (r - l) // 2 left = self.divide(lists, l, mid) right = self.divide(lists, mid + 1, r) + return self.conquer(left, right) def conquer(self, l1, l2): dummy = ListNode(0) curr = dummy + while l1 and l2: if l1.val <= l2.val: curr.next = l1 @@ -1206,10 +1393,12 @@ class Solution: curr.next = l2 l2 = l2.next curr = curr.next + if l1: curr.next = l1 else: curr.next = l2 + return dummy.next ``` @@ -1234,15 +1423,17 @@ class Solution { } private ListNode divide(ListNode[] lists, int l, int r) { - if (l > r) { + if (l > r) { return null; } if (l == r) { return lists[l]; } - int mid = l + (r - l) / 2; + + int mid = l + (r - l) / 2; ListNode left = divide(lists, l, mid); ListNode right = divide(lists, mid + 1, r); + return conquer(left, right); } @@ -1302,15 +1493,18 @@ private: if (l == r) { return lists[l]; } + int mid = l + (r - l) / 2; ListNode* left = divide(lists, l, mid); ListNode* right = divide(lists, mid + 1, r); + return conquer(left, right); } ListNode* conquer(ListNode* l1, ListNode* l2) { ListNode dummy(0); ListNode* curr = &dummy; + while (l1 && l2) { if (l1->val <= l2->val) { curr->next = l1; @@ -1321,11 +1515,13 @@ private: } curr = curr->next; } + if (l1) { curr->next = l1; } else { curr->next = l2; } + return dummy.next; } }; @@ -1367,9 +1563,11 @@ class Solution { if (l === r) { return lists[l]; } + const mid = Math.floor(l + (r - l) / 2); const left = this.divide(lists, l, mid); const right = this.divide(lists, mid + 1, r); + return this.conquer(left, right); } @@ -1381,6 +1579,7 @@ class Solution { conquer(l1, l2) { const dummy = new ListNode(0); let curr = dummy; + while (l1 && l2) { if (l1.val <= l2.val) { curr.next = l1; @@ -1391,6 +1590,7 @@ class Solution { } curr = curr.next; } + curr.next = l1 ? l1 : l2; return dummy.next; } @@ -1425,9 +1625,11 @@ public class Solution { if (l == r) { return lists[l]; } + int mid = l + (r - l) / 2; ListNode left = Divide(lists, l, mid); ListNode right = Divide(lists, mid + 1, r); + return Conquer(left, right); } @@ -1479,15 +1681,18 @@ func divide(lists []*ListNode, left, right int) *ListNode { if left == right { return lists[left] } + mid := left + (right-left)/2 l1 := divide(lists, left, mid) l2 := divide(lists, mid+1, right) + return conquer(l1, l2) } func conquer(l1, l2 *ListNode) *ListNode { dummy := &ListNode{} curr := dummy + for l1 != nil && l2 != nil { if l1.Val <= l2.Val { curr.Next = l1 @@ -1498,11 +1703,13 @@ func conquer(l1, l2 *ListNode) *ListNode { } curr = curr.Next } + if l1 != nil { curr.Next = l1 } else { curr.Next = l2 } + return dummy.Next } ``` @@ -1526,9 +1733,11 @@ class Solution { private fun divide(lists: Array, left: Int, right: Int): ListNode? { if (left > right) return null if (left == right) return lists[left] + val mid = left + (right - left) / 2 val l1 = divide(lists, left, mid) val l2 = divide(lists, mid + 1, right) + return conquer(l1, l2) } @@ -1537,6 +1746,7 @@ class Solution { var curr = dummy var list1 = l1 var list2 = l2 + while (list1 != null && list2 != null) { if (list1.`val` <= list2.`val`) { curr.next = list1 @@ -1547,18 +1757,74 @@ class Solution { } curr = curr.next!! } + curr.next = list1 ?: list2 return dummy.next } } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func mergeKLists(_ lists: [ListNode?]) -> ListNode? { + if lists.isEmpty { + return nil + } + return divide(lists, 0, lists.count - 1) + } + + private func divide(_ lists: [ListNode?], _ l: Int, _ r: Int) -> ListNode? { + if l > r { + return nil + } + if l == r { + return lists[l] + } + + let mid = l + (r - l) / 2 + let left = divide(lists, l, mid) + let right = divide(lists, mid + 1, r) + return conquer(left, right) + } + + private func conquer(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { + let dummy = ListNode(0) + var curr = dummy + var l1 = l1, l2 = l2 + + while let node1 = l1, let node2 = l2 { + if node1.val <= node2.val { + curr.next = node1 + l1 = node1.next + } else { + curr.next = node2 + l2 = node2.next + } + curr = curr.next! + } + + curr.next = l1 ?? l2 + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log k)$ -* Space complexity: $O(\log k)$ +- Time complexity: $O(n \log k)$ +- Space complexity: $O(\log k)$ > Where $k$ is the total number of lists and $n$ is the total number of nodes across $k$ lists. @@ -1576,7 +1842,7 @@ class Solution { # self.next = next class Solution: - + def mergeKLists(self, lists: List[Optional[ListNode]]) -> Optional[ListNode]: if not lists or len(lists) == 0: return None @@ -1602,10 +1868,12 @@ class Solution: tail.next = l2 l2 = l2.next tail = tail.next + if l1: tail.next = l1 if l2: tail.next = l2 + return dummy.next ``` @@ -1653,12 +1921,14 @@ public class Solution { } tail = tail.next; } + if (l1 != null) { tail.next = l1; } if (l2 != null) { tail.next = l2; } + return dummy.next; } } @@ -1710,12 +1980,14 @@ private: } tail = tail->next; } + if (l1) { tail->next = l1; } if (l2) { tail->next = l2; } + return dummy.next; } }; @@ -1746,7 +2018,7 @@ class Solution { const mergedLists = []; for (let i = 0; i < lists.length; i += 2) { const l1 = lists[i]; - const l2 = (i + 1) < lists.length ? lists[i + 1] : null; + const l2 = i + 1 < lists.length ? lists[i + 1] : null; mergedLists.push(this.mergeList(l1, l2)); } lists = mergedLists; @@ -1762,6 +2034,7 @@ class Solution { mergeList(l1, l2) { const dummy = new ListNode(0); let curr = dummy; + while (l1 && l2) { if (l1.val <= l2.val) { curr.next = l1; @@ -1772,6 +2045,7 @@ class Solution { } curr = curr.next; } + curr.next = l1 ? l1 : l2; return dummy.next; } @@ -1823,12 +2097,14 @@ public class Solution { } tail = tail.next; } + if (l1 != null) { tail.next = l1; } if (l2 != null) { tail.next = l2; } + return dummy.next; } } @@ -1876,11 +2152,13 @@ func mergeList(l1, l2 *ListNode) *ListNode { } tail = tail.Next } + if l1 != nil { tail.Next = l1 } else { tail.Next = l2 } + return dummy.Next } ``` @@ -1928,17 +2206,74 @@ class Solution { } tail = tail.next!! } + tail.next = list1 ?: list2 return dummy.next } } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func mergeKLists(_ lists: [ListNode?]) -> ListNode? { + if lists.isEmpty { + return nil + } + + var lists = lists + + while lists.count > 1 { + var mergedLists: [ListNode?] = [] + + for i in stride(from: 0, to: lists.count, by: 2) { + let l1 = lists[i] + let l2 = i + 1 < lists.count ? lists[i + 1] : nil + mergedLists.append(mergeList(l1, l2)) + } + + lists = mergedLists + } + + return lists[0] + } + + private func mergeList(_ l1: ListNode?, _ l2: ListNode?) -> ListNode? { + let dummy = ListNode(0) + var tail = dummy + var l1 = l1, l2 = l2 + + while let node1 = l1, let node2 = l2 { + if node1.val < node2.val { + tail.next = node1 + l1 = node1.next + } else { + tail.next = node2 + l2 = node2.next + } + tail = tail.next! + } + + tail.next = l1 ?? l2 + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log k)$ -* Space complexity: $O(k)$ +- Time complexity: $O(n \log k)$ +- Space complexity: $O(k)$ -> Where $k$ is the total number of lists and $n$ is the total number of nodes across $k$ lists. \ No newline at end of file +> Where $k$ is the total number of lists and $n$ is the total number of nodes across $k$ lists. diff --git a/articles/merge-sorted-array.md b/articles/merge-sorted-array.md index aab35dc73..c5721d231 100644 --- a/articles/merge-sorted-array.md +++ b/articles/merge-sorted-array.md @@ -53,12 +53,23 @@ class Solution { } ``` +```csharp +public class Solution { + public void Merge(int[] nums1, int m, int[] nums2, int n) { + for (int i = 0; i < n; i++) { + nums1[i + m] = nums2[i]; + } + Array.Sort(nums1); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O((m + n) \log (m + n))$ -* Space complexity: $O(1)$ or $O(m + n)$ depending on the sorting algorithm. +- Time complexity: $O((m + n) \log (m + n))$ +- Space complexity: $O(1)$ or $O(m + n)$ depending on the sorting algorithm. > Where $m$ and $n$ represent the number of elements in the arrays $nums1$ and $nums2$, respectively. @@ -92,7 +103,7 @@ public class Solution { public void merge(int[] nums1, int m, int[] nums2, int n) { int[] nums1Copy = Arrays.copyOf(nums1, m); int idx = 0, i = 0, j = 0; - + while (idx < m + n) { if (j >= n || (i < m && nums1Copy[i] <= nums2[j])) { nums1[idx++] = nums1Copy[i++]; @@ -110,7 +121,7 @@ public: void merge(vector& nums1, int m, vector& nums2, int n) { vector nums1Copy(nums1.begin(), nums1.begin() + m); int idx = 0, i = 0, j = 0; - + while (idx < m + n) { if (j >= n || (i < m && nums1Copy[i] <= nums2[j])) { nums1[idx++] = nums1Copy[i++]; @@ -133,7 +144,28 @@ class Solution { */ merge(nums1, m, nums2, n) { const nums1Copy = nums1.slice(0, m); - let idx = 0, i = 0, j = 0; + let idx = 0, + i = 0, + j = 0; + + while (idx < m + n) { + if (j >= n || (i < m && nums1Copy[i] <= nums2[j])) { + nums1[idx++] = nums1Copy[i++]; + } else { + nums1[idx++] = nums2[j++]; + } + } + } +} +``` + +```csharp +public class Solution { + public void Merge(int[] nums1, int m, int[] nums2, int n) { + int[] nums1Copy = new int[m]; + Array.Copy(nums1, nums1Copy, m); + + int idx = 0, i = 0, j = 0; while (idx < m + n) { if (j >= n || (i < m && nums1Copy[i] <= nums2[j])) { @@ -150,8 +182,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m + n)$ -* Space complexity: $O(m)$ +- Time complexity: $O(m + n)$ +- Space complexity: $O(m)$ > Where $m$ and $n$ represent the number of elements in the arrays $nums1$ and $nums2$, respectively. @@ -270,12 +302,39 @@ class Solution { } ``` +```csharp +public class Solution { + public void Merge(int[] nums1, int m, int[] nums2, int n) { + int last = m + n - 1; + + // Merge in reverse order + while (m > 0 && n > 0) { + if (nums1[m - 1] > nums2[n - 1]) { + nums1[last] = nums1[m - 1]; + m--; + } else { + nums1[last] = nums2[n - 1]; + n--; + } + last--; + } + + // Fill nums1 with leftover nums2 elements + while (n > 0) { + nums1[last] = nums2[n - 1]; + n--; + last--; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(m + n)$ +- Space complexity: $O(1)$ extra space. > Where $m$ and $n$ represent the number of elements in the arrays $nums1$ and $nums2$, respectively. @@ -301,8 +360,8 @@ class Solution: else: nums1[last] = nums2[j] j -= 1 - - last -= 1 + + last -= 1 ``` ```java @@ -351,7 +410,25 @@ class Solution { */ merge(nums1, m, nums2, n) { let last = m + n - 1; - let i = m - 1, j = n - 1; + let i = m - 1, + j = n - 1; + + while (j >= 0) { + if (i >= 0 && nums1[i] > nums2[j]) { + nums1[last--] = nums1[i--]; + } else { + nums1[last--] = nums2[j--]; + } + } + } +} +``` + +```csharp +public class Solution { + public void Merge(int[] nums1, int m, int[] nums2, int n) { + int last = m + n - 1; + int i = m - 1, j = n - 1; while (j >= 0) { if (i >= 0 && nums1[i] > nums2[j]) { @@ -368,7 +445,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m + n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(m + n)$ +- Space complexity: $O(1)$ extra space. -> Where $m$ and $n$ represent the number of elements in the arrays $nums1$ and $nums2$, respectively. \ No newline at end of file +> Where $m$ and $n$ represent the number of elements in the arrays $nums1$ and $nums2$, respectively. diff --git a/articles/merge-strings-alternately.md b/articles/merge-strings-alternately.md index 04d95926d..7e3b7582b 100644 --- a/articles/merge-strings-alternately.md +++ b/articles/merge-strings-alternately.md @@ -59,13 +59,35 @@ class Solution { */ mergeAlternately(word1, word2) { let res = []; - let i = 0, j = 0; + let i = 0, + j = 0; while (i < word1.length && j < word2.length) { res.push(word1[i++], word2[j++]); } res.push(word1.slice(i)); res.push(word2.slice(j)); - return res.join(""); + return res.join(''); + } +} +``` + +```csharp +public class Solution { + public string MergeAlternately(string word1, string word2) { + int i = 0, j = 0; + StringBuilder res = new StringBuilder(); + + while (i < word1.Length && j < word2.Length) { + res.Append(word1[i]); + res.Append(word2[j]); + i++; + j++; + } + + res.Append(word1.Substring(i)); + res.Append(word2.Substring(j)); + + return res.ToString(); } } ``` @@ -74,8 +96,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n + m)$ for the output string. +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ for the output string. > Where $n$ and $m$ are the lengths of the strings $word1$ and $word2$ respectively. @@ -140,14 +162,39 @@ class Solution { * @return {string} */ mergeAlternately(word1, word2) { - const n = word1.length, m = word2.length; + const n = word1.length, + m = word2.length; const res = []; - let i = 0, j = 0; + let i = 0, + j = 0; while (i < n || j < m) { if (i < n) res.push(word1[i++]); if (j < m) res.push(word2[j++]); } - return res.join(""); + return res.join(''); + } +} +``` + +```csharp +public class Solution { + public string MergeAlternately(string word1, string word2) { + int n = word1.Length, m = word2.Length; + int i = 0, j = 0; + StringBuilder res = new StringBuilder(); + + while (i < n || j < m) { + if (i < n) { + res.Append(word1[i]); + } + if (j < m) { + res.Append(word2[j]); + } + i++; + j++; + } + + return res.ToString(); } } ``` @@ -156,8 +203,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n + m)$ for the output string. +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ for the output string. > Where $n$ and $m$ are the lengths of the strings $word1$ and $word2$ respectively. @@ -225,7 +272,8 @@ class Solution { * @return {string} */ mergeAlternately(word1, word2) { - const n = word1.length, m = word2.length; + const n = word1.length, + m = word2.length; const res = []; for (let i = 0; i < m || i < n; i++) { if (i < n) { @@ -235,7 +283,27 @@ class Solution { res.push(word2.charAt(i)); } } - return res.join(""); + return res.join(''); + } +} +``` + +```csharp +public class Solution { + public string MergeAlternately(string word1, string word2) { + int n = word1.Length, m = word2.Length; + StringBuilder res = new StringBuilder(); + + for (int i = 0; i < Math.Max(n, m); i++) { + if (i < n) { + res.Append(word1[i]); + } + if (i < m) { + res.Append(word2[i]); + } + } + + return res.ToString(); } } ``` @@ -244,7 +312,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n + m)$ for the output string. +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ for the output string. -> Where $n$ and $m$ are the lengths of the strings $word1$ and $word2$ respectively. \ No newline at end of file +> Where $n$ and $m$ are the lengths of the strings $word1$ and $word2$ respectively. diff --git a/articles/merge-triplets-to-form-target.md b/articles/merge-triplets-to-form-target.md index 4fe080b4c..09ea587fd 100644 --- a/articles/merge-triplets-to-form-target.md +++ b/articles/merge-triplets-to-form-target.md @@ -138,12 +138,33 @@ class Solution { } ``` +```swift +class Solution { + func mergeTriplets(_ triplets: [[Int]], _ target: [Int]) -> Bool { + var good = Set() + + for t in triplets { + if t[0] > target[0] || t[1] > target[1] || t[2] > target[2] { + continue + } + for (i, v) in t.enumerated() { + if v == target[i] { + good.insert(i) + } + } + } + + return good.count == 3 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -205,11 +226,13 @@ class Solution { * @return {boolean} */ mergeTriplets(triplets, target) { - let x = false, y = false, z = false; + let x = false, + y = false, + z = false; for (let t of triplets) { - x |= (t[0] === target[0] && t[1] <= target[1] && t[2] <= target[2]); - y |= (t[0] <= target[0] && t[1] === target[1] && t[2] <= target[2]); - z |= (t[0] <= target[0] && t[1] <= target[1] && t[2] === target[2]); + x |= t[0] === target[0] && t[1] <= target[1] && t[2] <= target[2]; + y |= t[0] <= target[0] && t[1] === target[1] && t[2] <= target[2]; + z |= t[0] <= target[0] && t[1] <= target[1] && t[2] === target[2]; if (x && y && z) return true; } return false; @@ -240,7 +263,7 @@ func mergeTriplets(triplets [][]int, target []int) bool { x = x || (t[0] == target[0] && t[1] <= target[1] && t[2] <= target[2]) y = y || (t[0] <= target[0] && t[1] == target[1] && t[2] <= target[2]) z = z || (t[0] <= target[0] && t[1] <= target[1] && t[2] == target[2]) - + if x && y && z { return true } @@ -268,9 +291,31 @@ class Solution { } ``` +```swift +class Solution { + func mergeTriplets(_ triplets: [[Int]], _ target: [Int]) -> Bool { + var x = false, y = false, z = false + + for t in triplets { + if t[0] <= target[0] && t[1] <= target[1] && t[2] <= target[2] { + if t[0] == target[0] { x = true } + if t[1] == target[1] { y = true } + if t[2] == target[2] { z = true } + } + + if x && y && z { + return true + } + } + + return false + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/merge-two-binary-trees.md b/articles/merge-two-binary-trees.md new file mode 100644 index 000000000..d0811dfb2 --- /dev/null +++ b/articles/merge-two-binary-trees.md @@ -0,0 +1,665 @@ +## 1. Depth First Search (Creating New Tree) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: + if not root1 and not root2: + return None + + v1 = root1.val if root1 else 0 + v2 = root2.val if root2 else 0 + root = TreeNode(v1 + v2) + + root.left = self.mergeTrees(root1.left if root1 else None, root2.left if root2 else None) + root.right = self.mergeTrees(root1.right if root1 else None, root2.right if root2 else None) + + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 == null) { + return null; + } + + int v1 = (root1 != null) ? root1.val : 0; + int v2 = (root2 != null) ? root2.val : 0; + TreeNode root = new TreeNode(v1 + v2); + + root.left = mergeTrees( + (root1 != null) ? root1.left : null, (root2 != null) ? root2.left : null + ); + root.right = mergeTrees( + (root1 != null) ? root1.right : null, (root2 != null) ? root2.right : null + ); + + return root; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) { + if (!root1 && !root2) { + return nullptr; + } + + int v1 = root1 ? root1->val : 0; + int v2 = root2 ? root2->val : 0; + TreeNode* root = new TreeNode(v1 + v2); + + root->left = mergeTrees(root1 ? root1->left : nullptr, root2 ? root2->left : nullptr); + root->right = mergeTrees(root1 ? root1->right : nullptr, root2 ? root2->right : nullptr); + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root1 + * @param {TreeNode} root2 + * @return {TreeNode} + */ + mergeTrees(root1, root2) { + if (!root1 && !root2) { + return null; + } + + const v1 = root1 ? root1.val : 0; + const v2 = root2 ? root2.val : 0; + const root = new TreeNode(v1 + v2); + + root.left = this.mergeTrees( + root1 ? root1.left : null, + root2 ? root2.left : null, + ); + root.right = this.mergeTrees( + root1 ? root1.right : null, + root2 ? root2.right : null, + ); + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m + n)$ +- Space complexity: + - $O(m + n)$ space for recursion stack. + - $O(m + n)$ space for the output. + +> Where $m$ and $n$ are the number of nodes in the given trees. + +--- + +## 2. Depth First Search (In Place) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: + if not root1: + return root2 + if not root2: + return root1 + + root1.val += root2.val + root1.left = self.mergeTrees(root1.left, root2.left) + root1.right = self.mergeTrees(root1.right, root2.right) + return root1 +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { + if (root1 == null) return root2; + if (root2 == null) return root1; + + root1.val += root2.val; + root1.left = mergeTrees(root1.left, root2.left); + root1.right = mergeTrees(root1.right, root2.right); + return root1; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) { + if (!root1) return root2; + if (!root2) return root1; + + root1->val += root2->val; + root1->left = mergeTrees(root1->left, root2->left); + root1->right = mergeTrees(root1->right, root2->right); + return root1; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root1 + * @param {TreeNode} root2 + * @return {TreeNode} + */ + mergeTrees(root1, root2) { + if (!root1) return root2; + if (!root2) return root1; + + root1.val += root2.val; + root1.left = this.mergeTrees(root1.left, root2.left); + root1.right = this.mergeTrees(root1.right, root2.right); + return root1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(min(m, n))$ +- Space complexity: $O(min(m, n))$ for recursion stack. + +> Where $m$ and $n$ are the number of nodes in the given trees. + +--- + +## 3. Iterative DFS (Creating New Tree) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: + if not root1: + return root2 + if not root2: + return root1 + + root = TreeNode(root1.val + root2.val) + stack = [(root1, root2, root)] + + while stack: + node1, node2, node = stack.pop() + + if node1.left and node2.left: + node.left = TreeNode(node1.left.val + node2.left.val) + stack.append((node1.left, node2.left, node.left)) + elif not node1.left: + node.left = node2.left + else: + node.left = node1.left + + if node1.right and node2.right: + node.right = TreeNode(node1.right.val + node2.right.val) + stack.append((node1.right, node2.right, node.right)) + elif not node1.right: + node.right = node2.right + else: + node.right = node1.right + + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { + if (root1 == null && root2 == null) return null; + + int val = (root1 != null ? root1.val : 0) + (root2 != null ? root2.val : 0); + TreeNode root = new TreeNode(val); + Stack stack = new Stack<>(); + stack.push(new TreeNode[]{root1, root2, root}); + + while (!stack.isEmpty()) { + TreeNode[] nodes = stack.pop(); + TreeNode node1 = nodes[0], node2 = nodes[1], node = nodes[2]; + + TreeNode left1 = node1 != null ? node1.left : null; + TreeNode left2 = node2 != null ? node2.left : null; + if (left1 != null || left2 != null) { + int leftVal = (left1 != null ? left1.val : 0) + (left2 != null ? left2.val : 0); + node.left = new TreeNode(leftVal); + stack.push(new TreeNode[]{left1, left2, node.left}); + } + + TreeNode right1 = node1 != null ? node1.right : null; + TreeNode right2 = node2 != null ? node2.right : null; + if (right1 != null || right2 != null) { + int rightVal = (right1 != null ? right1.val : 0) + (right2 != null ? right2.val : 0); + node.right = new TreeNode(rightVal); + stack.push(new TreeNode[]{right1, right2, node.right}); + } + } + + return root; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) { + if (!root1 && !root2) return nullptr; + + int val = (root1 ? root1->val : 0) + (root2 ? root2->val : 0); + TreeNode* root = new TreeNode(val); + stack> st; + st.push({root1, root2, root}); + + while (!st.empty()) { + auto [node1, node2, node] = st.top(); + st.pop(); + + TreeNode* left1 = node1 ? node1->left : nullptr; + TreeNode* left2 = node2 ? node2->left : nullptr; + if (left1 || left2) { + int leftVal = (left1 ? left1->val : 0) + (left2 ? left2->val : 0); + node->left = new TreeNode(leftVal); + st.push({left1, left2, node->left}); + } + + TreeNode* right1 = node1 ? node1->right : nullptr; + TreeNode* right2 = node2 ? node2->right : nullptr; + if (right1 || right2) { + int rightVal = (right1 ? right1->val : 0) + (right2 ? right2->val : 0); + node->right = new TreeNode(rightVal); + st.push({right1, right2, node->right}); + } + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root1 + * @param {TreeNode} root2 + * @return {TreeNode} + */ + mergeTrees(root1, root2) { + if (!root1 && !root2) return null; + + let val = (root1 ? root1.val : 0) + (root2 ? root2.val : 0); + let root = new TreeNode(val); + let stack = [[root1, root2, root]]; + + while (stack.length) { + let [node1, node2, node] = stack.pop(); + + let left1 = node1 ? node1.left : null; + let left2 = node2 ? node2.left : null; + if (left1 || left2) { + let leftVal = (left1 ? left1.val : 0) + (left2 ? left2.val : 0); + node.left = new TreeNode(leftVal); + stack.push([left1, left2, node.left]); + } + + let right1 = node1 ? node1.right : null; + let right2 = node2 ? node2.right : null; + if (right1 || right2) { + let rightVal = + (right1 ? right1.val : 0) + (right2 ? right2.val : 0); + node.right = new TreeNode(rightVal); + stack.push([right1, right2, node.right]); + } + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m + n)$ +- Space complexity: + - $O(m + n)$ space for the stack. + - $O(m + n)$ space for the output. + +> Where $m$ and $n$ are the number of nodes in the given trees. + +--- + +## 4. Iterative DFS (In Place) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def mergeTrees(self, root1: Optional[TreeNode], root2: Optional[TreeNode]) -> Optional[TreeNode]: + if not root1: + return root2 + if not root2: + return root1 + + stack = [(root1, root2)] + + while stack: + node1, node2 = stack.pop() + if not node1 or not node2: + continue + + node1.val += node2.val + + if node1.left and node2.left: + stack.append((node1.left, node2.left)) + elif not node1.left: + node1.left = node2.left + + if node1.right and node2.right: + stack.append((node1.right, node2.right)) + elif not node1.right: + node1.right = node2.right + + return root1 +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode mergeTrees(TreeNode root1, TreeNode root2) { + if (root1 == null) return root2; + if (root2 == null) return root1; + + Stack stack = new Stack<>(); + stack.push(new TreeNode[] { root1, root2 }); + + while (!stack.isEmpty()) { + TreeNode[] nodes = stack.pop(); + TreeNode node1 = nodes[0]; + TreeNode node2 = nodes[1]; + + if (node2 == null) continue; + + node1.val += node2.val; + + if (node1.left == null) { + node1.left = node2.left; + } else { + stack.push(new TreeNode[] { node1.left, node2.left }); + } + + if (node1.right == null) { + node1.right = node2.right; + } else { + stack.push(new TreeNode[] { node1.right, node2.right }); + } + } + + return root1; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* mergeTrees(TreeNode* root1, TreeNode* root2) { + if (!root1) return root2; + if (!root2) return root1; + + stack> stk; + stk.push({root1, root2}); + + while (!stk.empty()) { + auto [node1, node2] = stk.top(); + stk.pop(); + + if (!node2) continue; + + node1->val += node2->val; + + if (!node1->left) { + node1->left = node2->left; + } else { + stk.push({node1->left, node2->left}); + } + + if (!node1->right) { + node1->right = node2->right; + } else { + stk.push({node1->right, node2->right}); + } + } + + return root1; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root1 + * @param {TreeNode} root2 + * @return {TreeNode} + */ + mergeTrees(root1, root2) { + if (!root1) return root2; + if (!root2) return root1; + + let stack = [[root1, root2]]; + + while (stack.length) { + let [node1, node2] = stack.pop(); + if (!node1 || !node2) continue; + + node1.val += node2.val; + + if (node1.left && node2.left) { + stack.push([node1.left, node2.left]); + } else if (!node1.left) { + node1.left = node2.left; + } + + if (node1.right && node2.right) { + stack.push([node1.right, node2.right]); + } else if (!node1.right) { + node1.right = node2.right; + } + } + + return root1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(min(m, n))$ +- Space complexity: $O(min(m, n))$ for the stack. + +> Where $m$ and $n$ are the number of nodes in the given trees. diff --git a/articles/merge-two-sorted-linked-lists.md b/articles/merge-two-sorted-linked-lists.md index bffc3e16f..c2419b978 100644 --- a/articles/merge-two-sorted-linked-lists.md +++ b/articles/merge-two-sorted-linked-lists.md @@ -133,7 +133,7 @@ class Solution { * } * } */ - + public class Solution { public ListNode MergeTwoLists(ListNode list1, ListNode list2) { if (list1 == null) { @@ -191,7 +191,7 @@ class Solution { fun mergeTwoLists(list1: ListNode?, list2: ListNode?): ListNode? { if (list1 == null) return list2 if (list2 == null) return list1 - + return if (list1.`val` <= list2.`val`) { list1.next = mergeTwoLists(list1.next, list2) list1 @@ -203,12 +203,42 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func mergeTwoLists(_ list1: ListNode?, _ list2: ListNode?) -> ListNode? { + if list1 == nil { + return list2 + } + if list2 == nil { + return list1 + } + if list1!.val <= list2!.val { + list1!.next = mergeTwoLists(list1!.next, list2) + return list1 + } else { + list2!.next = mergeTwoLists(list1, list2!.next) + return list2 + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ > Where $n$ is the length of $list1$ and $m$ is the length of $list2$. @@ -377,7 +407,7 @@ class Solution { * } * } */ - + public class Solution { public ListNode MergeTwoLists(ListNode list1, ListNode list2) { ListNode dummy = new ListNode(0); @@ -473,11 +503,47 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func mergeTwoLists(_ list1: ListNode?, _ list2: ListNode?) -> ListNode? { + let dummy = ListNode(0) + var node = dummy + var l1 = list1 + var l2 = list2 + + while l1 != nil && l2 != nil { + if l1!.val < l2!.val { + node.next = l1 + l1 = l1?.next + } else { + node.next = l2 + l2 = l2?.next + } + node = node.next! + } + + node.next = l1 ?? l2 + + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(1)$ -> Where $n$ is the length of $list1$ and $m$ is the length of $list2$. \ No newline at end of file +> Where $n$ is the length of $list1$ and $m$ is the length of $list2$. diff --git a/articles/middle-of-the-linked-list.md b/articles/middle-of-the-linked-list.md index 935efc3d4..9d1f36d04 100644 --- a/articles/middle-of-the-linked-list.md +++ b/articles/middle-of-the-linked-list.md @@ -98,8 +98,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -119,7 +119,7 @@ class Solution: while cur: cur = cur.next n += 1 - + n //= 2 cur = head while n: @@ -229,8 +229,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -320,7 +320,8 @@ class Solution { * @return {ListNode} */ middleNode(head) { - let slow = head, fast = head; + let slow = head, + fast = head; while (fast && fast.next) { slow = slow.next; @@ -335,5 +336,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/min-cost-climbing-stairs.md b/articles/min-cost-climbing-stairs.md index 3c7139726..edfedb3da 100644 --- a/articles/min-cost-climbing-stairs.md +++ b/articles/min-cost-climbing-stairs.md @@ -5,22 +5,22 @@ ```python class Solution: def minCostClimbingStairs(self, cost: List[int]) -> int: - + def dfs(i): if i >= len(cost): return 0 return cost[i] + min(dfs(i + 1), dfs(i + 2)) - + return min(dfs(0), dfs(1)) ``` ```java public class Solution { public int minCostClimbingStairs(int[] cost) { - + return Math.min(dfs(cost, 0), dfs(cost, 1)); } - + private int dfs(int[] cost, int i) { if (i >= cost.length) { return 0; @@ -37,7 +37,7 @@ public: int minCostClimbingStairs(vector& cost) { return min(dfs(cost, 0), dfs(cost, 1)); } - + int dfs(vector& cost, int i) { if (i >= cost.size()) { return 0; @@ -60,7 +60,7 @@ class Solution { return 0; } return cost[i] + Math.min(dfs(i + 1), dfs(i + 2)); - } + }; return Math.min(dfs(0), dfs(1)); } } @@ -71,7 +71,7 @@ public class Solution { public int MinCostClimbingStairs(int[] cost) { return Math.Min(Dfs(cost, 0), Dfs(cost, 1)); } - + private int Dfs(int[] cost, int i) { if (i >= cost.Length) { return 0; @@ -91,7 +91,7 @@ func minCostClimbingStairs(cost []int) int { } return cost[i] + min(dfs(i+1), dfs(i+2)) } - + return min(dfs(0), dfs(1)) } @@ -112,18 +112,33 @@ class Solution { } return cost[i] + minOf(dfs(i + 1), dfs(i + 2)) } - + return minOf(dfs(0), dfs(1)) } } ``` +```swift +class Solution { + func minCostClimbingStairs(_ cost: [Int]) -> Int { + func dfs(_ i: Int) -> Int { + if i >= cost.count { + return 0 + } + return cost[i] + min(dfs(i + 1), dfs(i + 2)) + } + + return min(dfs(0), dfs(1)) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -135,7 +150,7 @@ class Solution { class Solution: def minCostClimbingStairs(self, cost: List[int]) -> int: memo = [-1] * len(cost) - + def dfs(i): if i >= len(cost): return 0 @@ -143,20 +158,20 @@ class Solution: return memo[i] memo[i] = cost[i] + min(dfs(i + 1), dfs(i + 2)) return memo[i] - + return min(dfs(0), dfs(1)) ``` ```java public class Solution { int[] memo; - + public int minCostClimbingStairs(int[] cost) { memo = new int[cost.length]; Arrays.fill(memo, -1); return Math.min(dfs(cost, 0), dfs(cost, 1)); } - + private int dfs(int[] cost, int i) { if (i >= cost.length) { return 0; @@ -175,12 +190,12 @@ public class Solution { class Solution { public: vector memo; - + int minCostClimbingStairs(vector& cost) { memo.resize(cost.size(), -1); return min(dfs(cost, 0), dfs(cost, 1)); } - + int dfs(vector& cost, int i) { if (i >= cost.size()) { return 0; @@ -210,10 +225,9 @@ class Solution { if (memo[i] !== -1) { return memo[i]; } - memo[i] = cost[i] + Math.min(dfs(i + 1), - dfs(i + 2)); + memo[i] = cost[i] + Math.min(dfs(i + 1), dfs(i + 2)); return memo[i]; - } + }; return Math.min(dfs(0), dfs(1)); } } @@ -222,13 +236,13 @@ class Solution { ```csharp public class Solution { int[] memo; - + public int MinCostClimbingStairs(int[] cost) { memo = new int[cost.Length]; Array.Fill(memo, -1); return Math.Min(Dfs(cost, 0), Dfs(cost, 1)); } - + private int Dfs(int[] cost, int i) { if (i >= cost.Length) { return 0; @@ -261,7 +275,7 @@ func minCostClimbingStairs(cost []int) int { memo[i] = cost[i] + min(dfs(i+1), dfs(i+2)) return memo[i] } - + return min(dfs(0), dfs(1)) } @@ -285,18 +299,39 @@ class Solution { memo[i] = cost[i] + minOf(dfs(i + 1), dfs(i + 2)) return memo[i] } - + return minOf(dfs(0), dfs(1)) } } ``` +```swift +class Solution { + func minCostClimbingStairs(_ cost: [Int]) -> Int { + var memo = Array(repeating: -1, count: cost.count) + + func dfs(_ i: Int) -> Int { + if i >= cost.count { + return 0 + } + if memo[i] != -1 { + return memo[i] + } + memo[i] = cost[i] + min(dfs(i + 1), dfs(i + 2)) + return memo[i] + } + + return min(dfs(0), dfs(1)) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -309,11 +344,11 @@ class Solution: def minCostClimbingStairs(self, cost: List[int]) -> int: n = len(cost) dp = [0] * (n + 1) - + for i in range(2, n + 1): dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]) - + return dp[n] ``` @@ -322,12 +357,12 @@ public class Solution { public int minCostClimbingStairs(int[] cost) { int n = cost.length; int[] dp = new int[n + 1]; - + for (int i = 2; i <= n; i++) { dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]); } - + return dp[n]; } } @@ -339,12 +374,12 @@ public: int minCostClimbingStairs(vector& cost) { int n = cost.size(); vector dp(n + 1); - + for (int i = 2; i <= n; i++) { dp[i] = min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]); } - + return dp[n]; } }; @@ -359,12 +394,11 @@ class Solution { minCostClimbingStairs(cost) { const n = cost.length; const dp = new Array(n + 1).fill(0); - + for (let i = 2; i <= n; i++) { - dp[i] = Math.min(dp[i - 1] + cost[i - 1], - dp[i - 2] + cost[i - 2]); + dp[i] = Math.min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]); } - + return dp[n]; } } @@ -375,12 +409,12 @@ public class Solution { public int MinCostClimbingStairs(int[] cost) { int n = cost.Length; int[] dp = new int[n + 1]; - + for (int i = 2; i <= n; i++) { dp[i] = Math.Min(dp[i - 1] + cost[i - 1], dp[i - 2] + cost[i - 2]); } - + return dp[n]; } } @@ -423,12 +457,28 @@ class Solution { } ``` +```swift +class Solution { + func minCostClimbingStairs(_ cost: [Int]) -> Int { + let n = cost.count + var dp = Array(repeating: 0, count: n + 1) + + for i in 2...n { + dp[i] = min(dp[i - 1] + cost[i - 1], + dp[i - 2] + cost[i - 2]) + } + + return dp[n] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -523,9 +573,20 @@ class Solution { } ``` +```swift +class Solution { + func minCostClimbingStairs(_ cost: inout [Int]) -> Int { + for i in stride(from: cost.count - 3, through: 0, by: -1) { + cost[i] += min(cost[i + 1], cost[i + 2]) + } + return min(cost[0], cost[1]) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/min-cost-to-connect-points.md b/articles/min-cost-to-connect-points.md index 8e9e5226a..624ac66da 100644 --- a/articles/min-cost-to-connect-points.md +++ b/articles/min-cost-to-connect-points.md @@ -35,7 +35,7 @@ class Solution: x2, y2 = points[j] dist = abs(x1 - x2) + abs(y1 - y2) edges.append((dist, i, j)) - + edges.sort() res = 0 for dist, u, v in edges: @@ -45,7 +45,7 @@ class Solution: ``` ```java -public class DSU { +class DSU { int[] Parent, Size; public DSU(int n) { @@ -84,12 +84,12 @@ public class Solution { for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { - int dist = Math.abs(points[i][0] - points[j][0]) + + int dist = Math.abs(points[i][0] - points[j][0]) + Math.abs(points[i][1] - points[j][1]); edges.add(new int[] {dist, i, j}); } } - + edges.sort((a, b) -> Integer.compare(a[0], b[0])); int res = 0; @@ -107,7 +107,7 @@ public class Solution { class DSU { public: vector Parent, Size; - + DSU(int n) : Parent(n + 1), Size(n + 1, 1) { for (int i = 0; i <= n; ++i) Parent[i] = i; } @@ -138,7 +138,7 @@ public: for (int i = 0; i < n; ++i) { for (int j = i + 1; j < n; ++j) { - int dist = abs(points[i][0] - points[j][0]) + + int dist = abs(points[i][0] - points[j][0]) + abs(points[i][1] - points[j][1]); edges.push_back({dist, i, j}); } @@ -181,7 +181,8 @@ class DSU { * @return {boolean} */ union(u, v) { - let pu = this.find(u), pv = this.find(v); + let pu = this.find(u), + pv = this.find(v); if (pu === pv) return false; if (this.Size[pu] < this.Size[pv]) [pu, pv] = [pv, pu]; this.Size[pu] += this.Size[pv]; @@ -202,8 +203,9 @@ class Solution { for (let i = 0; i < n; i++) { for (let j = i + 1; j < n; j++) { - const dist = Math.abs(points[i][0] - points[j][0]) + - Math.abs(points[i][1] - points[j][1]); + const dist = + Math.abs(points[i][0] - points[j][0]) + + Math.abs(points[i][1] - points[j][1]); edges.push([dist, i, j]); } } @@ -224,7 +226,7 @@ class Solution { ```csharp public class DSU { public int[] Parent, Size; - + public DSU(int n) { Parent = new int[n + 1]; Size = new int[n + 1]; @@ -261,7 +263,7 @@ public class Solution { for (int i = 0; i < n; i++) { for (int j = i + 1; j < n; j++) { - int dist = Math.Abs(points[i][0] - points[j][0]) + + int dist = Math.Abs(points[i][0] - points[j][0]) + Math.Abs(points[i][1] - points[j][1]); edges.Add((dist, i, j)); } @@ -398,12 +400,74 @@ class Solution { } ``` +```swift +class DSU { + private var parent: [Int] + private var size: [Int] + + init(_ n: Int) { + parent = Array(0...n) + size = Array(repeating: 1, count: n + 1) + } + + func find(_ node: Int) -> Int { + if parent[node] != node { + parent[node] = find(parent[node]) + } + return parent[node] + } + + func union(_ u: Int, _ v: Int) -> Bool { + let pu = find(u) + let pv = find(v) + if pu == pv { + return false + } + if size[pu] < size[pv] { + parent[pu] = pv + size[pv] += size[pu] + } else { + parent[pv] = pu + size[pu] += size[pv] + } + return true + } +} + +class Solution { + func minCostConnectPoints(_ points: [[Int]]) -> Int { + let n = points.count + let dsu = DSU(n) + var edges = [(Int, Int, Int)]() + + for i in 0.. visit; - priority_queue, vector>, + priority_queue, vector>, greater>> minH; minH.push({0, 0}); while (visit.size() < N) { @@ -553,7 +617,7 @@ class Solution { let res = 0; const visit = new Set(); - const minHeap = new MinPriorityQueue(entry => entry[0]); + const minHeap = new MinPriorityQueue((entry) => entry[0]); minHeap.push([0, 0]); while (visit.size < N) { @@ -596,8 +660,8 @@ public class Solution { int res = 0; var visit = new HashSet(); - var pq = new PriorityQueue(); - pq.Enqueue(0, 0); + var pq = new PriorityQueue(); + pq.Enqueue(0, 0); while (visit.Count < N && pq.Count > 0) { if (pq.TryPeek(out int i, out int cost)) { @@ -676,7 +740,7 @@ class Solution { fun minCostConnectPoints(points: Array): Int { val n = points.size val adj = HashMap>>() - + for (i in 0 until n) { val (x1, y1) = points[i] for (j in i + 1 until n) { @@ -690,9 +754,9 @@ class Solution { var res = 0 val visited = mutableSetOf() val minHeap = PriorityQueue(compareBy> { it.first }) - - minHeap.add(0 to 0) - + + minHeap.add(0 to 0) + while (visited.size < n) { val (cost, point) = minHeap.poll() if (point in visited) continue @@ -710,12 +774,68 @@ class Solution { } ``` +```swift +struct Item: Comparable { + let cost: Int + let node: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.cost < rhs.cost + } +} + +class Solution { + func minCostConnectPoints(_ points: [[Int]]) -> Int { + let N = points.count + var adj = [Int: [(Int, Int)]]() + + for i in 0..() + var minHeap = Heap() + minHeap.insert(Item(cost: 0, node: 0)) + + while visit.count < N { + guard let item = minHeap.popMin() else { break } + let cost = item.cost + let i = item.node + + if visit.contains(i) { + continue + } + + res += cost + visit.insert(i) + + if let neighbors = adj[i] { + for (neiCost, nei) in neighbors { + if !visit.contains(nei) { + minHeap.insert(Item(cost: neiCost, node: nei)) + } + } + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2 \log n)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2 \log n)$ +- Space complexity: $O(n ^ 2)$ --- @@ -737,12 +857,12 @@ class Solution: for i in range(n): if visit[i]: continue - curDist = (abs(points[i][0] - points[node][0]) + + curDist = (abs(points[i][0] - points[node][0]) + abs(points[i][1] - points[node][1])) dist[i] = min(dist[i], curDist) if nextNode == -1 or dist[i] < dist[nextNode]: nextNode = i - + res += dist[nextNode] node = nextNode edges += 1 @@ -764,7 +884,7 @@ public class Solution { int nextNode = -1; for (int i = 0; i < n; i++) { if (visit[i]) continue; - int curDist = Math.abs(points[i][0] - points[node][0]) + + int curDist = Math.abs(points[i][0] - points[node][0]) + Math.abs(points[i][1] - points[node][1]); dist[i] = Math.min(dist[i], curDist); if (nextNode == -1 || dist[i] < dist[nextNode]) { @@ -794,7 +914,7 @@ public: int nextNode = -1; for (int i = 0; i < n; i++) { if (visit[i]) continue; - int curDist = abs(points[i][0] - points[node][0]) + + int curDist = abs(points[i][0] - points[node][0]) + abs(points[i][1] - points[node][1]); dist[i] = min(dist[i], curDist); if (nextNode == -1 || dist[i] < dist[nextNode]) { @@ -821,15 +941,17 @@ class Solution { let node = 0; const dist = new Array(n).fill(100000000); const visit = new Array(n).fill(false); - let edges = 0, res = 0; + let edges = 0, + res = 0; while (edges < n - 1) { visit[node] = true; let nextNode = -1; for (let i = 0; i < n; i++) { if (visit[i]) continue; - const curDist = Math.abs(points[i][0] - points[node][0]) + - Math.abs(points[i][1] - points[node][1]); + const curDist = + Math.abs(points[i][0] - points[node][0]) + + Math.abs(points[i][1] - points[node][1]); dist[i] = Math.min(dist[i], curDist); if (nextNode === -1 || dist[i] < dist[nextNode]) { nextNode = i; @@ -858,7 +980,7 @@ public class Solution { int nextNode = -1; for (int i = 0; i < n; i++) { if (visit[i]) continue; - int curDist = Math.Abs(points[i][0] - points[node][0]) + + int curDist = Math.Abs(points[i][0] - points[node][0]) + Math.Abs(points[i][1] - points[node][1]); dist[i] = Math.Min(dist[i], curDist); if (nextNode == -1 || dist[i] < dist[nextNode]) { @@ -892,7 +1014,7 @@ func minCostConnectPoints(points [][]int) int { if visit[i] { continue } - curDist := int(math.Abs(float64(points[i][0]-points[node][0])) + + curDist := int(math.Abs(float64(points[i][0]-points[node][0])) + math.Abs(float64(points[i][1]-points[node][1]))) if curDist < dist[i] { dist[i] = curDist @@ -924,7 +1046,7 @@ class Solution { var nextNode = -1 for (i in 0 until n) { if (visit[i]) continue - val curDist = abs(points[i][0] - points[node][0]) + + val curDist = abs(points[i][0] - points[node][0]) + abs(points[i][1] - points[node][1]) dist[i] = minOf(dist[i], curDist) if (nextNode == -1 || dist[i] < dist[nextNode]) { @@ -940,9 +1062,45 @@ class Solution { } ``` +```swift +class Solution { + func minCostConnectPoints(_ points: [[Int]]) -> Int { + let n = points.count + var node = 0 + var dist = Array(repeating: 100000000, count: n) + var visit = Array(repeating: false, count: n) + var edges = 0 + var res = 0 + + while edges < n - 1 { + visit[node] = true + var nextNode = -1 + + for i in 0.. int: + n = len(nums) + arr = [] + for i, num in enumerate(nums): + if num & 1: + arr.append((num, i)) + arr.append((num * 2, i)) + else: + while num % 2 == 0: + arr.append((num, i)) + num //= 2 + arr.append((num, i)) + + arr.sort() + res = float("inf") + + seen = [0] * n + count = i = 0 + for j in range(len(arr)): + seen[arr[j][1]] += 1 + if seen[arr[j][1]] == 1: + count += 1 + while count == n: + res = min(res, arr[j][0] - arr[i][0]) + seen[arr[i][1]] -= 1 + if seen[arr[i][1]] == 0: + count -= 1 + i += 1 + + return res +``` + +```java +public class Solution { + public int minimumDeviation(int[] nums) { + int n = nums.length; + List arr = new ArrayList<>(); + + for (int i = 0; i < n; i++) { + int num = nums[i]; + if (num % 2 == 1) { + arr.add(new int[]{num, i}); + arr.add(new int[]{num * 2, i}); + } else { + while (num % 2 == 0) { + arr.add(new int[]{num, i}); + num /= 2; + } + arr.add(new int[]{num, i}); + } + } + + arr.sort(Comparator.comparingInt(a -> a[0])); + int res = Integer.MAX_VALUE; + + int[] seen = new int[n]; + int count = 0, i = 0; + + for (int j = 0; j < arr.size(); j++) { + seen[arr.get(j)[1]]++; + if (seen[arr.get(j)[1]] == 1) { + count++; + while (count == n) { + res = Math.min(res, arr.get(j)[0] - arr.get(i)[0]); + seen[arr.get(i)[1]]--; + if (seen[arr.get(i)[1]] == 0) { + count--; + } + i++; + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minimumDeviation(vector& nums) { + int n = nums.size(); + vector> arr; + + for (int i = 0; i < n; i++) { + int num = nums[i]; + if (num % 2 == 1) { + arr.emplace_back(num, i); + arr.emplace_back(num * 2, i); + } else { + while (num % 2 == 0) { + arr.emplace_back(num, i); + num /= 2; + } + arr.emplace_back(num, i); + } + } + + sort(arr.begin(), arr.end()); + int res = INT_MAX; + + vector seen(n, 0); + int count = 0, i = 0; + + for (int j = 0; j < arr.size(); j++) { + seen[arr[j].second]++; + if (seen[arr[j].second] == 1) { + count++; + while (count == n) { + res = min(res, arr[j].first - arr[i].first); + seen[arr[i].second]--; + if (seen[arr[i].second] == 0) { + count--; + } + i++; + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimumDeviation(nums) { + let n = nums.length; + let arr = []; + + for (let i = 0; i < n; i++) { + let num = nums[i]; + if (num % 2 === 1) { + arr.push([num, i]); + arr.push([num * 2, i]); + } else { + while (num % 2 === 0) { + arr.push([num, i]); + num /= 2; + } + arr.push([num, i]); + } + } + + arr.sort((a, b) => a[0] - b[0]); + let res = Infinity; + + let seen = new Array(n).fill(0); + let count = 0, + i = 0; + + for (let j = 0; j < arr.length; j++) { + seen[arr[j][1]]++; + if (seen[arr[j][1]] === 1) { + count++; + while (count === n) { + res = Math.min(res, arr[j][0] - arr[i][0]); + seen[arr[i][1]]--; + if (seen[arr[i][1]] === 0) { + count--; + } + i++; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O((n \log m) * \log (n \log m))$ +- Space complexity: $O(n \log m)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in $nums$. + +--- + +## 2. Min-Heap + +::tabs-start + +```python +class Solution: + def minimumDeviation(self, nums: List[int]) -> int: + minHeap, heapMax = [], 0 + + for n in nums: + tmp = n + while n % 2 == 0: + n //= 2 + minHeap.append((n, max(tmp, 2 * n))) + heapMax = max(heapMax, n) + + res = float("inf") + heapq.heapify(minHeap) + + while len(minHeap) == len(nums): + n, nMax = heapq.heappop(minHeap) + res = min(res, heapMax - n) + + if n < nMax: + heapq.heappush(minHeap, (n * 2, nMax)) + heapMax = max(heapMax, n * 2) + + return res +``` + +```java +public class Solution { + public int minimumDeviation(int[] nums) { + PriorityQueue minHeap = new PriorityQueue<>((a, b) -> a[0] - b[0]); + int heapMax = 0; + + for (int num : nums) { + int tmp = num; + while (num % 2 == 0) { + num /= 2; + } + minHeap.offer(new int[]{num, Math.max(tmp, 2 * num)}); + heapMax = Math.max(heapMax, num); + } + + int res = Integer.MAX_VALUE; + + while (minHeap.size() == nums.length) { + int[] minElement = minHeap.poll(); + int n = minElement[0], nMax = minElement[1]; + res = Math.min(res, heapMax - n); + + if (n < nMax) { + minHeap.offer(new int[]{n * 2, nMax}); + heapMax = Math.max(heapMax, n * 2); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minimumDeviation(vector& nums) { + priority_queue, vector>, greater<>> minHeap; + int heapMax = 0; + + for (int num : nums) { + int tmp = num; + while (num % 2 == 0) { + num /= 2; + } + minHeap.push({num, max(tmp, 2 * num)}); + heapMax = max(heapMax, num); + } + + int res = INT_MAX; + + while (minHeap.size() == nums.size()) { + auto [n, nMax] = minHeap.top(); + minHeap.pop(); + res = min(res, heapMax - n); + + if (n < nMax) { + minHeap.push({n * 2, nMax}); + heapMax = max(heapMax, n * 2); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimumDeviation(nums) { + const minHeap = new MinPriorityQueue((x) => x[0]); + let heapMax = 0; + + for (let num of nums) { + let tmp = num; + while (num % 2 === 0) { + num /= 2; + } + minHeap.enqueue([num, Math.max(tmp, num * 2)]); + heapMax = Math.max(heapMax, num); + } + + let res = Infinity; + + while (minHeap.size() === nums.length) { + let [n, nMax] = minHeap.dequeue(); + res = Math.min(res, heapMax - n); + + if (n < nMax) { + minHeap.enqueue([n * 2, nMax]); + heapMax = Math.max(heapMax, n * 2); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n *\log n * \log m)$ +- Space complexity: $O(n)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in $nums$. + +--- + +## 3. Max-Heap + +::tabs-start + +```python +class Solution: + def minimumDeviation(self, nums: List[int]) -> int: + maxHeap = [] + minVal = float("inf") + + for num in nums: + if num % 2 == 1: + num *= 2 + heapq.heappush(maxHeap, -num) + minVal = min(minVal, num) + + res = float("inf") + + while maxHeap: + maxVal = -heapq.heappop(maxHeap) + res = min(res, maxVal - minVal) + if maxVal % 2 == 1: + break + + nextVal = maxVal // 2 + heapq.heappush(maxHeap, -nextVal) + minVal = min(minVal, nextVal) + + return res +``` + +```java +public class Solution { + public int minimumDeviation(int[] nums) { + PriorityQueue maxHeap = new PriorityQueue<>((a, b) -> b - a); + int minVal = Integer.MAX_VALUE; + + for (int num : nums) { + if (num % 2 == 1) num *= 2; + maxHeap.offer(num); + minVal = Math.min(minVal, num); + } + + int res = Integer.MAX_VALUE; + + while (!maxHeap.isEmpty()) { + int maxVal = maxHeap.poll(); + res = Math.min(res, maxVal - minVal); + + if (maxVal % 2 == 1) break; + + int nextVal = maxVal / 2; + maxHeap.offer(nextVal); + minVal = Math.min(minVal, nextVal); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minimumDeviation(vector& nums) { + priority_queue maxHeap; + int minVal = INT_MAX; + + for (int num : nums) { + if (num % 2 == 1) num *= 2; + maxHeap.push(num); + minVal = min(minVal, num); + } + + int res = INT_MAX; + + while (!maxHeap.empty()) { + int maxVal = maxHeap.top(); + maxHeap.pop(); + res = min(res, maxVal - minVal); + + if (maxVal % 2 == 1) break; + + int nextVal = maxVal / 2; + maxHeap.push(nextVal); + minVal = min(minVal, nextVal); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimumDeviation(nums) { + const maxHeap = new MaxPriorityQueue(); + let minVal = Infinity; + + for (let num of nums) { + if (num % 2 === 1) num *= 2; + maxHeap.enqueue(num); + minVal = Math.min(minVal, num); + } + + let res = Infinity; + + while (!maxHeap.isEmpty()) { + let maxVal = maxHeap.dequeue(); + res = Math.min(res, maxVal - minVal); + + if (maxVal % 2 === 1) break; + + let nextVal = maxVal / 2; + maxHeap.enqueue(nextVal); + minVal = Math.min(minVal, nextVal); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n *\log n * \log m)$ +- Space complexity: $O(n)$ + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum element in $nums$. diff --git a/articles/minimize-maximum-of-array.md b/articles/minimize-maximum-of-array.md new file mode 100644 index 000000000..a6fa25980 --- /dev/null +++ b/articles/minimize-maximum-of-array.md @@ -0,0 +1,211 @@ +## 1. Binary Search + +::tabs-start + +```python +class Solution: + def minimizeArrayValue(self, nums: List[int]) -> int: + def isValid(maxVal): + prefix_sum = 0 + for i in range(len(nums)): + prefix_sum += nums[i] + if prefix_sum > maxVal * (i + 1): + return False + return True + + left, right = 0, max(nums) + while left < right: + mid = left + (right - left) // 2 + if isValid(mid): + right = mid + else: + left = mid + 1 + + return left +``` + +```java +public class Solution { + public int minimizeArrayValue(int[] nums) { + int left = 0, right = 0; + for (int num : nums) { + right = Math.max(right, num); + } + + while (left < right) { + int mid = left + (right - left) / 2; + if (isValid(nums, mid)) { + right = mid; + } else { + left = mid + 1; + } + } + + return left; + } + + private boolean isValid(int[] nums, int maxVal) { + long prefixSum = 0; + for (int i = 0; i < nums.length; i++) { + prefixSum += nums[i]; + if (prefixSum > (long) maxVal * (i + 1)) { + return false; + } + } + return true; + } +} +``` + +```cpp +class Solution { +public: + int minimizeArrayValue(vector& nums) { + int left = 0, right = *max_element(nums.begin(), nums.end()); + + while (left < right) { + int mid = left + (right - left) / 2; + if (isValid(nums, mid)) { + right = mid; + } else { + left = mid + 1; + } + } + + return left; + } + +private: + bool isValid(vector& nums, int maxVal) { + long long prefixSum = 0; + for (int i = 0; i < nums.size(); i++) { + prefixSum += nums[i]; + if (prefixSum > (long long)maxVal * (i + 1)) { + return false; + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimizeArrayValue(nums) { + const isValid = (maxVal) => { + let prefixSum = 0; + for (let i = 0; i < nums.length; i++) { + prefixSum += nums[i]; + if (prefixSum > maxVal * (i + 1)) { + return false; + } + } + return true; + }; + + let left = 0, + right = Math.max(...nums); + while (left < right) { + let mid = left + Math.floor((right - left) / 2); + if (isValid(mid)) { + right = mid; + } else { + left = mid + 1; + } + } + + return left; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log m)$ +- Space complexity: $O(1)$ extra space. + +> Where $n$ is the size of the array $nums$ and $m$ is the maximum value in the array. + +--- + +## 2. Prefix Sum + Greedy + +::tabs-start + +```python +class Solution: + def minimizeArrayValue(self, nums: List[int]) -> int: + res = total = nums[0] + + for i in range(1, len(nums)): + total += nums[i] + res = max(res, math.ceil(total / (i + 1))) + + return res +``` + +```java +public class Solution { + public int minimizeArrayValue(int[] nums) { + int res = nums[0]; + long total = nums[0]; + + for (int i = 1; i < nums.length; i++) { + total += nums[i]; + res = Math.max(res, (int) Math.ceil((double) total / (i + 1))); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minimizeArrayValue(vector& nums) { + int res = nums[0]; + long long total = nums[0]; + + for (int i = 1; i < nums.size(); i++) { + total += nums[i]; + res = max(res, (int)ceil((double)total / (i + 1))); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimizeArrayValue(nums) { + let res = nums[0]; + let total = nums[0]; + + for (let i = 1; i < nums.length; i++) { + total += nums[i]; + res = Math.max(res, Math.ceil(total / (i + 1))); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/minimize-the-maximum-difference-of-pairs.md b/articles/minimize-the-maximum-difference-of-pairs.md new file mode 100644 index 000000000..04d2f5cd7 --- /dev/null +++ b/articles/minimize-the-maximum-difference-of-pairs.md @@ -0,0 +1,567 @@ +## 1. Greedy + Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def minimizeMax(self, nums: List[int], p: int) -> int: + n = len(nums) + nums.sort() + dp = {} + + def dfs(i, pairs): + if pairs == p: + return 0 + if i >= n - 1: + return float('inf') + if (i, pairs) in dp: + return dp[(i, pairs)] + + take = max(nums[i + 1] - nums[i], dfs(i + 2, pairs + 1)) + skip = dfs(i + 1, pairs) + dp[(i, pairs)] = min(take, skip) + return dp[(i, pairs)] + + return dfs(0, 0) +``` + +```java +public class Solution { + private Map dp; + + public int minimizeMax(int[] nums, int p) { + Arrays.sort(nums); + dp = new HashMap<>(); + return dfs(0, 0, nums, p); + } + + private int dfs(int i, int pairs, int[] nums, int p) { + if (pairs == p) return 0; + if (i >= nums.length - 1) return Integer.MAX_VALUE; + + String key = i + "," + pairs; + if (dp.containsKey(key)) return dp.get(key); + + int take = Math.max(nums[i + 1] - nums[i], dfs(i + 2, pairs + 1, nums, p)); + int skip = dfs(i + 1, pairs, nums, p); + + int res = Math.min(take, skip); + dp.put(key, res); + return res; + } +} +``` + +```cpp +class Solution { + unordered_map dp; + +public: + int minimizeMax(vector& nums, int p) { + int n = nums.size(); + sort(nums.begin(), nums.end()); + return dfs(0, 0, nums, p); + } + +private: + int dfs(int i, int pairs, vector& nums, int p) { + if (pairs == p) return 0; + if (i >= nums.size() - 1) return INT_MAX; + long long key = i; + key = (key << 31) | pairs; + if (dp.count(key)) return dp[key]; + + int take = max(nums[i + 1] - nums[i], dfs(i + 2, pairs + 1, nums, p)); + int skip = dfs(i + 1, pairs, nums, p); + + return dp[key] = min(take, skip); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ + minimizeMax(nums, p) { + nums.sort((a, b) => a - b); + const dp = new Map(); + + const dfs = (i, pairs) => { + if (pairs === p) return 0; + if (i >= nums.length - 1) return Infinity; + + let key = `${i},${pairs}`; + if (dp.has(key)) return dp.get(key); + + let take = Math.max(nums[i + 1] - nums[i], dfs(i + 2, pairs + 1)); + let skip = dfs(i + 1, pairs); + + let result = Math.min(take, skip); + dp.set(key, result); + return result; + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * p)$ +- Space complexity: $O(n * p)$ + +> Where $n$ is the size of the input array and $p$ is the number of pairs to select. + +--- + +## 2. Greesy + Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def minimizeMax(self, nums: List[int], p: int) -> int: + n = len(nums) + nums.sort() + + dp = [[float('inf')] * (p + 1) for _ in range(n + 1)] + for i in range(n + 1): + dp[i][0] = 0 + + for i in range(n - 2, -1, -1): + for pairs in range(1, p + 1): + take = float('inf') + if i + 1 < n: + take = max(nums[i + 1] - nums[i], dp[i + 2][pairs - 1]) + + skip = dp[i + 1][pairs] + dp[i][pairs] = min(take, skip) + + return dp[0][p] +``` + +```java +public class Solution { + public int minimizeMax(int[] nums, int p) { + int n = nums.length; + Arrays.sort(nums); + + int[][] dp = new int[n + 1][p + 1]; + for (int i = 0; i <= n; i++) { + Arrays.fill(dp[i], Integer.MAX_VALUE); + dp[i][0] = 0; + } + + for (int i = n - 2; i >= 0; i--) { + for (int pairs = 1; pairs <= p; pairs++) { + int take = Integer.MAX_VALUE; + if (i + 1 < n) { + take = Math.max(nums[i + 1] - nums[i], dp[i + 2][pairs - 1]); + } + int skip = dp[i + 1][pairs]; + dp[i][pairs] = Math.min(take, skip); + } + } + + return dp[0][p]; + } +} +``` + +```cpp +class Solution { +public: + int minimizeMax(vector& nums, int p) { + int n = nums.size(); + sort(nums.begin(), nums.end()); + + vector> dp(n + 1, vector(p + 1, INT_MAX)); + for (int i = 0; i <= n; i++) { + dp[i][0] = 0; + } + + for (int i = n - 2; i >= 0; i--) { + for (int pairs = 1; pairs <= p; pairs++) { + int take = INT_MAX; + if (i + 1 < n) { + take = max(nums[i + 1] - nums[i], dp[i + 2][pairs - 1]); + } + int skip = dp[i + 1][pairs]; + dp[i][pairs] = min(take, skip); + } + } + + return dp[0][p]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ + minimizeMax(nums, p) { + const n = nums.length; + nums.sort((a, b) => a - b); + + const dp = Array.from({ length: n + 1 }, () => + new Array(p + 1).fill(Infinity), + ); + for (let i = 0; i <= n; i++) { + dp[i][0] = 0; + } + + for (let i = n - 2; i >= 0; i--) { + for (let pairs = 1; pairs <= p; pairs++) { + let take = Infinity; + if (i + 1 < n) { + take = Math.max( + nums[i + 1] - nums[i], + dp[i + 2][pairs - 1], + ); + } + const skip = dp[i + 1][pairs]; + dp[i][pairs] = Math.min(take, skip); + } + } + + return dp[0][p]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * p)$ +- Space complexity: $O(n * p)$ + +> Where $n$ is the size of the input array and $p$ is the number of pairs to select. + +--- + +## 3. Greesy + Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def minimizeMax(self, nums: List[int], p: int) -> int: + n = len(nums) + nums.sort() + + dp = [float('inf')] * (p + 1) + dp1 = [float('inf')] * (p + 1) + dp2 = [float('inf')] * (p + 1) + + dp[0] = dp1[0] = dp2[0] = 0 + for i in range(n - 1, -1, -1): + for pairs in range(1, p + 1): + take = float('inf') + if i + 1 < n: + take = max(nums[i + 1] - nums[i], dp2[pairs - 1]) + skip = dp1[pairs] + dp[pairs] = min(take, skip) + + dp2 = dp1[:] + dp1 = dp[:] + dp = [float('inf')] * (p + 1) + dp[0] = 0 + + return dp1[p] +``` + +```java +public class Solution { + public int minimizeMax(int[] nums, int p) { + int n = nums.length; + Arrays.sort(nums); + + int[] dp = new int[p + 1]; + int[] dp1 = new int[p + 1]; + int[] dp2 = new int[p + 1]; + Arrays.fill(dp, Integer.MAX_VALUE); + Arrays.fill(dp1, Integer.MAX_VALUE); + Arrays.fill(dp2, Integer.MAX_VALUE); + dp[0] = dp1[0] = dp2[0] = 0; + + for (int i = n - 1; i >= 0; i--) { + for (int pairs = 1; pairs <= p; pairs++) { + int take = Integer.MAX_VALUE; + if (i + 1 < n) { + take = Math.max(nums[i + 1] - nums[i], dp2[pairs - 1]); + } + int skip = dp1[pairs]; + dp[pairs] = Math.min(take, skip); + } + dp2 = dp1.clone(); + dp1 = dp.clone(); + Arrays.fill(dp, Integer.MAX_VALUE); + dp[0] = 0; + } + + return dp1[p]; + } +} +``` + +```cpp +class Solution { +public: + int minimizeMax(vector& nums, int p) { + int n = nums.size(); + sort(nums.begin(), nums.end()); + + vector dp(p + 1, INT_MAX); + vector dp1(p + 1, INT_MAX); + vector dp2(p + 1, INT_MAX); + + dp[0] = dp1[0] = dp2[0] = 0; + + for (int i = n - 1; i >= 0; i--) { + for (int pairs = 1; pairs <= p; pairs++) { + int take = INT_MAX; + if (i + 1 < n) { + take = max(nums[i + 1] - nums[i], dp2[pairs - 1]); + } + int skip = dp1[pairs]; + dp[pairs] = min(take, skip); + } + dp2 = dp1; + dp1 = dp; + fill(dp.begin(), dp.end(), INT_MAX); + dp[0] = 0; + } + + return dp1[p]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ + minimizeMax(nums, p) { + const n = nums.length; + nums.sort((a, b) => a - b); + + let dp = new Array(p + 1).fill(Infinity); + let dp1 = new Array(p + 1).fill(Infinity); + let dp2 = new Array(p + 1).fill(Infinity); + + dp[0] = dp1[0] = dp2[0] = 0; + + for (let i = n - 1; i >= 0; i--) { + for (let pairs = 1; pairs <= p; pairs++) { + let take = Infinity; + if (i + 1 < n) { + take = Math.max(nums[i + 1] - nums[i], dp2[pairs - 1]); + } + let skip = dp1[pairs]; + dp[pairs] = Math.min(take, skip); + } + dp2 = dp1.slice(); + dp1 = dp.slice(); + dp.fill(Infinity); + dp[0] = 0; + } + + return dp1[p]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * p)$ +- Space complexity: $O(p)$ + +> Where $n$ is the size of the input array and $p$ is the number of pairs to select. + +--- + +## 4. Greedy + Binary Search + +::tabs-start + +```python +class Solution: + def minimizeMax(self, nums: List[int], p: int) -> int: + if p == 0: + return 0 + + def isValid(threshold): + i, cnt = 0, 0 + while i < len(nums) - 1: + if abs(nums[i] - nums[i + 1]) <= threshold: + cnt += 1 + i += 2 + else: + i += 1 + if cnt == p: + return True + return False + + nums.sort() + l, r = 0, nums[-1] - nums[0] + res = nums[-1] - nums[0] + + while l <= r: + m = l + (r - l) // 2 + if isValid(m): + res = m + r = m - 1 + else: + l = m + 1 + + return res +``` + +```java +public class Solution { + public int minimizeMax(int[] nums, int p) { + if (p == 0) return 0; + + Arrays.sort(nums); + int left = 0, right = nums[nums.length - 1] - nums[0]; + int result = right; + + while (left <= right) { + int mid = left + (right - left) / 2; + if (isValid(nums, mid, p)) { + result = mid; + right = mid - 1; + } else { + left = mid + 1; + } + } + + return result; + } + + private boolean isValid(int[] nums, int threshold, int p) { + int i = 0, count = 0; + while (i < nums.length - 1) { + if (Math.abs(nums[i] - nums[i + 1]) <= threshold) { + count++; + i += 2; + } else { + i++; + } + if (count == p) return true; + } + return false; + } +} +``` + +```cpp +class Solution { +public: + int minimizeMax(vector& nums, int p) { + if (p == 0) return 0; + + sort(nums.begin(), nums.end()); + int left = 0, right = nums.back() - nums[0]; + int result = right; + + while (left <= right) { + int mid = left + (right - left) / 2; + if (isValid(nums, mid, p)) { + result = mid; + right = mid - 1; + } else { + left = mid + 1; + } + } + + return result; + } + +private: + bool isValid(vector& nums, int threshold, int p) { + int i = 0, count = 0; + while (i < nums.size() - 1) { + if (abs(nums[i] - nums[i + 1]) <= threshold) { + count++; + i += 2; + } else { + i++; + } + if (count == p) return true; + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} p + * @return {number} + */ + minimizeMax(nums, p) { + if (p === 0) return 0; + + nums.sort((a, b) => a - b); + let l = 0, + r = nums[nums.length - 1] - nums[0], + res = r; + + const isValid = (threshold) => { + let i = 0, + cnt = 0; + while (i < nums.length - 1) { + if (Math.abs(nums[i] - nums[i + 1]) <= threshold) { + cnt++; + i += 2; + } else { + i++; + } + if (cnt === p) return true; + } + return false; + }; + + while (l <= r) { + let m = Math.floor(l + (r - l) / 2); + if (isValid(m)) { + res = m; + r = m - 1; + } else { + l = m + 1; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n\log n + n\log m)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +> Where $n$ is the size of the input array and $m$ is the maximum value in the array. diff --git a/articles/minimum-array-end.md b/articles/minimum-array-end.md index 2aba4edba..1c9894d1b 100644 --- a/articles/minimum-array-end.md +++ b/articles/minimum-array-end.md @@ -53,12 +53,24 @@ class Solution { } ``` +```csharp +public class Solution { + public long MinEnd(int n, int x) { + long res = x; + for (int i = 0; i < n - 1; i++) { + res = (res + 1) | x; + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -209,12 +221,49 @@ class Solution { } ``` +```csharp +public class Solution { + public long MinEnd(int n, int x) { + long res = 0; + n -= 1; + + int[] x_bin = new int[64]; + int[] n_bin = new int[64]; + + for (int i = 0; i < 32; i++) { + x_bin[i] = (x >> i) & 1; + n_bin[i] = (n >> i) & 1; + } + + int i_x = 0; + int i_n = 0; + + while (i_x < 63) { + while (i_x < 63 && x_bin[i_x] != 0) { + i_x++; + } + x_bin[i_x] = n_bin[i_n]; + i_x++; + i_n++; + } + + for (int i = 0; i < 64; i++) { + if (x_bin[i] == 1) { + res += 1L << i; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(\log n)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(\log n)$ --- @@ -312,9 +361,32 @@ class Solution { } ``` +```csharp +public class Solution { + public long MinEnd(int n, int x) { + long res = x; + long i_x = 1; + long i_n = 1; + long n_minus_1 = n - 1; + + while (i_n <= n_minus_1) { + if ((i_x & x) == 0) { + if ((i_n & n_minus_1) != 0) { + res |= i_x; + } + i_n <<= 1; + } + i_x <<= 1; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/minimum-changes-to-make-alternating-binary-string.md b/articles/minimum-changes-to-make-alternating-binary-string.md index 05b5629b5..3aeb66a56 100644 --- a/articles/minimum-changes-to-make-alternating-binary-string.md +++ b/articles/minimum-changes-to-make-alternating-binary-string.md @@ -1,4 +1,4 @@ -## 1. Start with Zero and One +## 1. Start with Zero and One ::tabs-start @@ -10,14 +10,14 @@ class Solution: if int(c) != cur: cnt1 += 1 cur ^= 1 - + cur = 1 cnt2 = 0 for c in s: if int(c) != cur: cnt2 += 1 cur ^= 1 - + return min(cnt1, cnt2) ``` @@ -79,7 +79,8 @@ class Solution { * @return {number} */ minOperations(s) { - let cur = 0, cnt1 = 0; + let cur = 0, + cnt1 = 0; for (let c of s) { if (parseInt(c) !== cur) { cnt1++; @@ -105,8 +106,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -124,7 +125,7 @@ class Solution: count += 1 if s[i] == '0' else 0 else: count += 1 if s[i] == '1' else 0 - + return min(count, len(s) - count) ``` @@ -203,5 +204,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/minimum-cost-for-tickets.md b/articles/minimum-cost-for-tickets.md index 1b32c8980..c7ccc7e12 100644 --- a/articles/minimum-cost-for-tickets.md +++ b/articles/minimum-cost-for-tickets.md @@ -11,19 +11,19 @@ class Solution: if i == n: return 0 - res = costs[0] + dfs(i + 1) + res = costs[0] + dfs(i + 1) j = i while j < n and days[j] < days[i] + 7: j += 1 res = min(res, costs[1] + dfs(j)) - + j = i while j < n and days[j] < days[i] + 30: j += 1 res = min(res, costs[2] + dfs(j)) return res - + return dfs(0) ``` @@ -124,8 +124,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(3 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(3 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -252,8 +252,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -266,7 +266,7 @@ class Solution: def mincostTickets(self, days: List[int], costs: List[int]) -> int: n = len(days) dp = [0] * (n + 1) - + for i in range(n - 1, -1, -1): dp[i] = float('inf') j = i @@ -274,7 +274,7 @@ class Solution: while j < n and days[j] < days[i] + d: j += 1 dp[i] = min(dp[i], c + dp[j]) - + return dp[0] ``` @@ -283,7 +283,7 @@ public class Solution { public int mincostTickets(int[] days, int[] costs) { int n = days.length; int[] dp = new int[n + 1]; - + for (int i = n - 1; i >= 0; i--) { dp[i] = Integer.MAX_VALUE; int idx = 0, j = i; @@ -295,7 +295,7 @@ public class Solution { idx++; } } - + return dp[0]; } } @@ -355,8 +355,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -453,7 +453,8 @@ class Solution { days.push(days[days.length - 1] + 30); const n = days.length; const dp = new Array(n).fill(0); - let last7 = n, last30 = n; + let last7 = n, + last30 = n; for (let i = n - 2; i >= 0; i--) { dp[i] = dp[i + 1] + costs[0]; @@ -478,8 +479,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -496,14 +497,14 @@ class Solution: for d in days: while dp7 and dp7[0][0] + 7 <= d: dp7.popleft() - + while dp30 and dp30[0][0] + 30 <= d: dp30.popleft() - + dp7.append([d, dp + costs[1]]) dp30.append([d, dp + costs[2]]) dp = min(dp + costs[0], dp7[0][1], dp30[0][1]) - + return dp ``` @@ -567,8 +568,8 @@ class Solution { * @return {number} */ mincostTickets(days, costs) { - const dp7 = new Queue; - const dp30 = new Queue; + const dp7 = new Queue(); + const dp30 = new Queue(); let dp = 0; for (const d of days) { @@ -595,8 +596,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since we keep at most $30$ values in the queue. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we keep at most $30$ values in the queue. --- @@ -695,7 +696,9 @@ class Solution { mincostTickets(days, costs) { const dp7 = new Deque(); const dp30 = new Deque(); - let dp = 0, last7 = 0, last30 = 0; + let dp = 0, + last7 = 0, + last30 = 0; for (let i = days.length - 1; i >= 0; i--) { dp += costs[0]; @@ -722,8 +725,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since we keep at most $30$ values in the deque. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we keep at most $30$ values in the deque. --- @@ -836,9 +839,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since the size of the $dp$ array is $366$. - +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since the size of the $dp$ array is $366$. --- @@ -855,7 +857,7 @@ class Solution: for d in range(1, 366): if i >= len(days): break - + dp[d % 31] = dp[(d - 1) % 31] if d == days[i]: @@ -934,8 +936,14 @@ class Solution { if (d === days[i]) { dp[d % 31] += costs[0]; - dp[d % 31] = Math.min(dp[d % 31], costs[1] + dp[Math.max(0, d - 7) % 31]); - dp[d % 31] = Math.min(dp[d % 31], costs[2] + dp[Math.max(0, d - 30) % 31]); + dp[d % 31] = Math.min( + dp[d % 31], + costs[1] + dp[Math.max(0, d - 7) % 31], + ); + dp[d % 31] = Math.min( + dp[d % 31], + costs[2] + dp[Math.max(0, d - 30) % 31], + ); i++; } } @@ -949,5 +957,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since the size of the $dp$ array is $31$. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since the size of the $dp$ array is $31$. diff --git a/articles/minimum-cost-to-cut-a-stick.md b/articles/minimum-cost-to-cut-a-stick.md index 0ef0f2484..1504ae10f 100644 --- a/articles/minimum-cost-to-cut-a-stick.md +++ b/articles/minimum-cost-to-cut-a-stick.md @@ -77,7 +77,7 @@ class Solution { let res = Infinity; for (const c of cuts) { if (l < c && c < r) { - res = Math.min(res, (r - l) + dfs(l, c) + dfs(c, r)); + res = Math.min(res, r - l + dfs(l, c) + dfs(c, r)); } } return res === Infinity ? 0 : res; @@ -92,8 +92,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m ^ N)$ -* Space complexity: $O(N)$ for recursion stack. +- Time complexity: $O(m ^ N)$ +- Space complexity: $O(N)$ for recursion stack. > Where $m$ is the size of the $cuts$ array, $n$ is the length of the stick, and $N = min(n, m)$. @@ -210,7 +210,7 @@ class Solution { let res = Infinity; for (const c of cuts) { if (l < c && c < r) { - res = Math.min(res, (r - l) + dfs(l, c) + dfs(c, r)); + res = Math.min(res, r - l + dfs(l, c) + dfs(c, r)); } } res = res === Infinity ? 0 : res; @@ -227,8 +227,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * N ^ 2)$ -* Space complexity: $O(N ^ 2)$ +- Time complexity: $O(m * N ^ 2)$ +- Space complexity: $O(N ^ 2)$ > Where $m$ is the size of the $cuts$ array, $n$ is the length of the stick, and $N = min(n, m)$. @@ -342,7 +342,11 @@ class Solution { let res = Infinity; for (let mid = i; mid <= j; mid++) { - const cur = (r - l) + dfs(l, cuts[mid], i, mid - 1) + dfs(cuts[mid], r, mid + 1, j); + const cur = + r - + l + + dfs(l, cuts[mid], i, mid - 1) + + dfs(cuts[mid], r, mid + 1, j); res = Math.min(res, cur); } @@ -359,8 +363,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m\log m + m ^ 3)$ -* Space complexity: $O(m ^ 2)$ +- Time complexity: $O(m\log m + m ^ 3)$ +- Space complexity: $O(m ^ 2)$ > Where $m$ is the size of the $cuts$ array and $n$ is the length of the stick. @@ -383,7 +387,7 @@ class Solution: dp[i][j] = float("inf") for mid in range(i + 1, j): dp[i][j] = min( - dp[i][j], + dp[i][j], cuts[j] - cuts[i] + dp[i][mid] + dp[mid][j] ) @@ -407,7 +411,7 @@ public class Solution { int j = i + length; dp[i][j] = Integer.MAX_VALUE; for (int mid = i + 1; mid < j; mid++) { - dp[i][j] = Math.min(dp[i][j], + dp[i][j] = Math.min(dp[i][j], newCuts[j] - newCuts[i] + dp[i][mid] + dp[mid][j]); } } @@ -434,7 +438,7 @@ public: int j = i + length; dp[i][j] = INT_MAX; for (int mid = i + 1; mid < j; mid++) { - dp[i][j] = min(dp[i][j], + dp[i][j] = min(dp[i][j], cuts[j] - cuts[i] + dp[i][mid] + dp[mid][j]); } } @@ -464,7 +468,7 @@ class Solution { for (let mid = i + 1; mid < j; mid++) { dp[i][j] = Math.min( dp[i][j], - cuts[j] - cuts[i] + dp[i][mid] + dp[mid][j] + cuts[j] - cuts[i] + dp[i][mid] + dp[mid][j], ); } } @@ -479,7 +483,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m\log m + m ^ 3)$ -* Space complexity: $O(m ^ 2)$ +- Time complexity: $O(m\log m + m ^ 3)$ +- Space complexity: $O(m ^ 2)$ -> Where $m$ is the size of the $cuts$ array and $n$ is the length of the stick. \ No newline at end of file +> Where $m$ is the size of the $cuts$ array and $n$ is the length of the stick. diff --git a/articles/minimum-cost-to-hire-k-workers.md b/articles/minimum-cost-to-hire-k-workers.md new file mode 100644 index 000000000..46e0ba222 --- /dev/null +++ b/articles/minimum-cost-to-hire-k-workers.md @@ -0,0 +1,145 @@ +## 1. Greedy + Max-Heap + +::tabs-start + +```python +class Solution: + def mincostToHireWorkers(self, quality: List[int], wage: List[int], k: int) -> float: + pairs = sorted([(w / q, q) for q, w in zip(quality, wage)], key=lambda p: p[0]) + + maxHeap = [] + total_quality = 0 + res = float("inf") + + for rate, q in pairs: + heapq.heappush(maxHeap, -q) + total_quality += q + + if len(maxHeap) > k: + total_quality += heapq.heappop(maxHeap) + + if len(maxHeap) == k: + res = min(res, total_quality * rate) + + return res +``` + +```java +public class Solution { + public double mincostToHireWorkers(int[] quality, int[] wage, int k) { + int n = quality.length; + double res = Double.MAX_VALUE; + double totalQuality = 0; + + double[][] workers = new double[n][2]; + for (int i = 0; i < n; i++) { + workers[i] = new double[]{ + (double) wage[i] / quality[i], (double) quality[i] + }; + } + + Arrays.sort(workers, Comparator.comparingDouble(a -> a[0])); + PriorityQueue maxHeap = new PriorityQueue<>(Collections.reverseOrder()); + + for (double[] worker : workers) { + double ratio = worker[0]; + int q = (int) worker[1]; + + maxHeap.add(q); + totalQuality += q; + + if (maxHeap.size() > k) { + totalQuality -= maxHeap.poll(); + } + + if (maxHeap.size() == k) { + res = Math.min(res, totalQuality * ratio); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + double mincostToHireWorkers(vector& quality, vector& wage, int k) { + int n = quality.size(); + vector> workers(n); + for (int i = 0; i < n; i++) { + workers[i] = { (double)wage[i] / quality[i], quality[i] }; + } + + sort(workers.begin(), workers.end()); + priority_queue maxHeap; + double totalQuality = 0, res = DBL_MAX; + + for (auto& worker : workers) { + double ratio = worker.first; + int q = worker.second; + maxHeap.push(q); + totalQuality += q; + + if (maxHeap.size() > k) { + totalQuality -= maxHeap.top(); + maxHeap.pop(); + } + + if (maxHeap.size() == k) { + res = min(res, totalQuality * ratio); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} quality + * @param {number[]} wage + * @param {number} k + * @return {number} + */ + mincostToHireWorkers(quality, wage, k) { + const n = quality.length; + const workers = []; + for (let i = 0; i < n; i++) { + workers.push([wage[i] / quality[i], quality[i]]); + } + + workers.sort((a, b) => a[0] - b[0]); + const maxHeap = new MaxPriorityQueue(); + let totalQuality = 0, + res = Number.MAX_VALUE; + + for (let [ratio, q] of workers) { + maxHeap.enqueue(q); + totalQuality += q; + + if (maxHeap.size() > k) { + totalQuality -= maxHeap.dequeue(); + } + + if (maxHeap.size() === k) { + res = Math.min(res, totalQuality * ratio); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * (\log n + \log k))$ +- Space complexity: $O(n)$ + +> Where $n$ is the number of workers, and $k$ is the number of workers to be hired. diff --git a/articles/minimum-deletions-to-make-character-frequencies-unique.md b/articles/minimum-deletions-to-make-character-frequencies-unique.md new file mode 100644 index 000000000..f9ba829b4 --- /dev/null +++ b/articles/minimum-deletions-to-make-character-frequencies-unique.md @@ -0,0 +1,348 @@ +## 1. Hash Set + +::tabs-start + +```python +class Solution: + def minDeletions(self, s: str) -> int: + count = [0] * 26 + for c in s: + count[ord(c) - ord('a')] += 1 + + used_freq = set() + res = 0 + for freq in count: + while freq > 0 and freq in used_freq: + freq -= 1 + res += 1 + used_freq.add(freq) + + return res +``` + +```java +class Solution { + public int minDeletions(String s) { + int[] count = new int[26]; + for (int i = 0; i < s.length(); i++) { + count[s.charAt(i) - 'a']++; + } + + Set usedFreq = new HashSet<>(); + int res = 0; + + for (int freq : count) { + while (freq > 0 && usedFreq.contains(freq)) { + freq--; + res++; + } + usedFreq.add(freq); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minDeletions(string s) { + vector count(26, 0); + for (char& c : s) { + count[c - 'a']++; + } + + unordered_set usedFreq; + int res = 0; + + for (int& freq : count) { + while (freq > 0 && usedFreq.count(freq)) { + freq--; + res++; + } + usedFreq.insert(freq); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + minDeletions(s) { + let count = new Array(26).fill(0); + for (let c of s) { + count[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + let usedFreq = new Set(); + let res = 0; + + for (let freq of count) { + while (freq > 0 && usedFreq.has(freq)) { + freq--; + res++; + } + usedFreq.add(freq); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m ^ 2)$ +- Space complexity: $O(m)$ + +> Where $n$ is the length of the string $s$ and $m$ is the total number of unique frequncies possible. + +--- + +## 2. Max-Heap + +::tabs-start + +```python +class Solution: + def minDeletions(self, s: str) -> int: + freq = Counter(s) + maxHeap = [-f for f in freq.values()] + heapq.heapify(maxHeap) + + res = 0 + while len(maxHeap) > 1: + top = -heapq.heappop(maxHeap) + if top == -maxHeap[0]: + if top - 1 > 0: + heapq.heappush(maxHeap, -(top - 1)) + res += 1 + + return res +``` + +```java +public class Solution { + public int minDeletions(String s) { + Map freq = new HashMap<>(); + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + freq.put(c, freq.getOrDefault(c, 0) + 1); + } + + PriorityQueue maxHeap = new PriorityQueue<>((a, b) -> b - a); + maxHeap.addAll(freq.values()); + + int res = 0; + while (maxHeap.size() > 1) { + int top = maxHeap.poll(); + if (top == maxHeap.peek()) { + if (top - 1 > 0) { + maxHeap.add(top - 1); + } + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minDeletions(string s) { + unordered_map freq; + for (char& c : s) { + freq[c]++; + } + + priority_queue maxHeap; + for (auto& f : freq) { + maxHeap.push(f.second); + } + + int res = 0; + while (maxHeap.size() > 1) { + int top = maxHeap.top(); + maxHeap.pop(); + if (top == maxHeap.top()) { + if (top - 1 > 0) { + maxHeap.push(top - 1); + } + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + minDeletions(s) { + let freq = new Map(); + for (let c of s) { + freq.set(c, (freq.get(c) || 0) + 1); + } + + const maxHeap = new MaxPriorityQueue(); + for (let value of freq.values()) { + maxHeap.enqueue(value); + } + + let res = 0; + while (maxHeap.size() > 1) { + let top = maxHeap.dequeue().element; + if (maxHeap.front().element === top) { + if (top - 1 > 0) { + maxHeap.enqueue(top - 1); + } + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m ^ 2 \log m)$ +- Space complexity: $O(m)$ + +> Where $n$ is the length of the string $s$ and $m$ is the total number of unique frequncies possible. + +--- + +## 3. Sorting + +::tabs-start + +```python +class Solution: + def minDeletions(self, s: str) -> int: + count = [0] * 26 + for c in s: + count[ord(c) - ord('a')] += 1 + + count.sort(reverse=True) + res = 0 + maxAllowedFreq = count[0] + + for freq in count: + if freq > maxAllowedFreq: + res += freq - maxAllowedFreq + freq = maxAllowedFreq + maxAllowedFreq = max(0, freq - 1) + + return res +``` + +```java +public class Solution { + public int minDeletions(String s) { + int[] count = new int[26]; + for (int i = 0; i < s.length(); i++) { + count[s.charAt(i) - 'a']++; + } + + Arrays.sort(count); + int res = 0; + int maxAllowedFreq = count[25]; + + for (int i = 25; i >= 0; i--) { + if (count[i] > maxAllowedFreq) { + res += count[i] - maxAllowedFreq; + count[i] = maxAllowedFreq; + } + maxAllowedFreq = Math.max(0, count[i] - 1); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minDeletions(string s) { + vector count(26, 0); + for (char& c : s) { + count[c - 'a']++; + } + + sort(count.begin(), count.end(), greater()); + int res = 0; + int maxAllowedFreq = count[0]; + + for (int& freq : count) { + if (freq > maxAllowedFreq) { + res += freq - maxAllowedFreq; + freq = maxAllowedFreq; + } + maxAllowedFreq = max(0, freq - 1); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + minDeletions(s) { + let count = new Array(26).fill(0); + for (let c of s) { + count[c.charCodeAt(0) - 'a'.charCodeAt(0)]++; + } + + count.sort((a, b) => b - a); + + let res = 0; + let maxAllowedFreq = count[0]; + + for (let i = 0; i < 26; i++) { + if (count[i] > maxAllowedFreq) { + res += count[i] - maxAllowedFreq; + count[i] = maxAllowedFreq; + } + maxAllowedFreq = Math.max(0, count[i] - 1); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m \log m)$ +- Space complexity: $O(m)$ + +> Where $n$ is the length of the string $s$ and $m$ is the total number of unique frequncies possible. diff --git a/articles/minimum-difference-between-highest-and-lowest-of-k-scores.md b/articles/minimum-difference-between-highest-and-lowest-of-k-scores.md index de7c35615..71cd5c4d5 100644 --- a/articles/minimum-difference-between-highest-and-lowest-of-k-scores.md +++ b/articles/minimum-difference-between-highest-and-lowest-of-k-scores.md @@ -55,7 +55,9 @@ class Solution { */ minimumDifference(nums, k) { nums.sort((a, b) => a - b); - let l = 0, r = k - 1, res = Infinity; + let l = 0, + r = k - 1, + res = Infinity; while (r < nums.length) { res = Math.min(res, nums[r] - nums[l]); l++; @@ -66,9 +68,27 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinimumDifference(int[] nums, int k) { + Array.Sort(nums); + int l = 0, r = k - 1; + int res = int.MaxValue; + + while (r < nums.Length) { + res = Math.Min(res, nums[r] - nums[l]); + l++; + r++; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. \ No newline at end of file +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. diff --git a/articles/minimum-difficulty-of-a-job-schedule.md b/articles/minimum-difficulty-of-a-job-schedule.md index 5738623eb..f2d9962f8 100644 --- a/articles/minimum-difficulty-of-a-job-schedule.md +++ b/articles/minimum-difficulty-of-a-job-schedule.md @@ -7,7 +7,7 @@ class Solution: def minDifficulty(self, jobDifficulty: List[int], d: int) -> int: if len(jobDifficulty) < d: return -1 - + n = len(jobDifficulty) dp = {} @@ -116,7 +116,7 @@ class Solution { } const dp = Array.from({ length: n }, () => - Array.from({ length: d + 1 }, () => Array(m + 5).fill(-1)) + Array.from({ length: d + 1 }, () => Array(m + 5).fill(-1)), ); const dfs = (i, d, curMax) => { @@ -127,7 +127,7 @@ class Solution { const maxSoFar = Math.max(curMax, jobDifficulty[i]); const res = Math.min( dfs(i + 1, d, maxSoFar), - maxSoFar + dfs(i + 1, d - 1, -1) + maxSoFar + dfs(i + 1, d - 1, -1), ); dp[i][d][curMax + 1] = res; @@ -143,8 +143,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * d * m)$ -* Space complexity: $O(n * d * m)$ +- Time complexity: $O(n * d * m)$ +- Space complexity: $O(n * d * m)$ > Where $n$ is the number of jobs, $d$ is the number of days, and $m$ is the maximum difficulty value among all the job difficulties. @@ -305,8 +305,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2 * d)$ -* Space complexity: $O(n * d)$ +- Time complexity: $O(n ^ 2 * d)$ +- Space complexity: $O(n * d)$ > Where $n$ is the number of jobs and $d$ is the number of days. @@ -397,7 +397,9 @@ class Solution { const n = jobDifficulty.length; if (n < d) return -1; - const dp = Array.from({ length: n + 1 }, () => Array(d + 1).fill(Infinity)); + const dp = Array.from({ length: n + 1 }, () => + Array(d + 1).fill(Infinity), + ); dp[n][0] = 0; for (let day = 1; day <= d; day++) { @@ -405,7 +407,10 @@ class Solution { let maxi = 0; for (let j = i; j <= n - day; j++) { maxi = Math.max(maxi, jobDifficulty[j]); - dp[i][day] = Math.min(dp[i][day], maxi + dp[j + 1][day - 1]); + dp[i][day] = Math.min( + dp[i][day], + maxi + dp[j + 1][day - 1], + ); } } } @@ -419,8 +424,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2 * d)$ -* Space complexity: $O(n * d)$ +- Time complexity: $O(n ^ 2 * d)$ +- Space complexity: $O(n * d)$ > Where $n$ is the number of jobs and $d$ is the number of days. @@ -539,8 +544,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2 * d)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2 * d)$ +- Space complexity: $O(n)$ > Where $n$ is the number of jobs and $d$ is the number of days. @@ -655,12 +660,21 @@ class Solution { const stack = []; for (let i = day - 1; i < n; i++) { nextDp[i] = (i > 0 ? dp[i - 1] : 0) + jobDifficulty[i]; - while (stack.length > 0 && jobDifficulty[stack[stack.length - 1]] <= jobDifficulty[i]) { + while ( + stack.length > 0 && + jobDifficulty[stack[stack.length - 1]] <= jobDifficulty[i] + ) { const j = stack.pop(); - nextDp[i] = Math.min(nextDp[i], nextDp[j] - jobDifficulty[j] + jobDifficulty[i]); + nextDp[i] = Math.min( + nextDp[i], + nextDp[j] - jobDifficulty[j] + jobDifficulty[i], + ); } if (stack.length > 0) { - nextDp[i] = Math.min(nextDp[i], nextDp[stack[stack.length - 1]]); + nextDp[i] = Math.min( + nextDp[i], + nextDp[stack[stack.length - 1]], + ); } stack.push(i); } @@ -676,7 +690,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * d)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * d)$ +- Space complexity: $O(n)$ -> Where $n$ is the number of jobs and $d$ is the number of days. \ No newline at end of file +> Where $n$ is the number of jobs and $d$ is the number of days. diff --git a/articles/minimum-distance-between-bst-nodes.md b/articles/minimum-distance-between-bst-nodes.md new file mode 100644 index 000000000..1c9e31cb8 --- /dev/null +++ b/articles/minimum-distance-between-bst-nodes.md @@ -0,0 +1,841 @@ +## 1. Brute Force (DFS) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def minDiffInBST(self, root: Optional[TreeNode]) -> int: + def dfs(node): + if not node: + return float("inf") + res = dfs1(root, node) + res = min(res, dfs(node.left)) + res = min(res, dfs(node.right)) + return res + + def dfs1(root, node): + if not root: + return float("inf") + + res = float("inf") + if root != node: + res = abs(root.val - node.val) + res = min(res, dfs1(root.left, node)) + res = min(res, dfs1(root.right, node)) + return res + + return dfs(root) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int minDiffInBST(TreeNode root) { + return dfs(root, root); + } + + private int dfs(TreeNode root, TreeNode node) { + if (node == null) { + return Integer.MAX_VALUE; + } + int res = dfs1(root, node); + res = Math.min(res, dfs(root, node.left)); + res = Math.min(res, dfs(root, node.right)); + return res; + } + + private int dfs1(TreeNode root, TreeNode node) { + if (root == null) { + return Integer.MAX_VALUE; + } + int res = Integer.MAX_VALUE; + if (root != node) { + res = Math.abs(root.val - node.val); + } + res = Math.min(res, dfs1(root.left, node)); + res = Math.min(res, dfs1(root.right, node)); + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int minDiffInBST(TreeNode* root) { + return dfs(root, root); + } + +private: + int dfs(TreeNode* root, TreeNode* node) { + if (!node) { + return INT_MAX; + } + int res = dfs1(root, node); + res = min(res, dfs(root, node->left)); + res = min(res, dfs(root, node->right)); + return res; + } + + int dfs1(TreeNode* root, TreeNode* node) { + if (!root) { + return INT_MAX; + } + int res = INT_MAX; + if (root != node) { + res = abs(root->val - node->val); + } + res = min(res, dfs1(root->left, node)); + res = min(res, dfs1(root->right, node)); + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + minDiffInBST(root) { + const dfs = (node) => { + if (!node) { + return Infinity; + } + let res = dfs1(root, node); + res = Math.min(res, dfs(node.left)); + res = Math.min(res, dfs(node.right)); + return res; + }; + + const dfs1 = (root, node) => { + if (!root) { + return Infinity; + } + let res = Infinity; + if (root !== node) { + res = Math.abs(root.val - node.val); + } + res = Math.min(res, dfs1(root.left, node)); + res = Math.min(res, dfs1(root.right, node)); + return res; + }; + + return dfs(root); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 2. Inorder Traversal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def minDiffInBST(self, root: Optional[TreeNode]) -> int: + arr = [] + + def dfs(node): + if not node: + return + dfs(node.left) + arr.append(node.val) + dfs(node.right) + + dfs(root) + res = arr[1] - arr[0] + for i in range(2, len(arr)): + res = min(res, arr[i] - arr[i - 1]) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int minDiffInBST(TreeNode root) { + List arr = new ArrayList<>(); + + dfs(root, arr); + int res = arr.get(1) - arr.get(0); + for (int i = 2; i < arr.size(); i++) { + res = Math.min(res, arr.get(i) - arr.get(i - 1)); + } + return res; + } + + private void dfs(TreeNode node, List arr) { + if (node == null) { + return; + } + dfs(node.left, arr); + arr.add(node.val); + dfs(node.right, arr); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int minDiffInBST(TreeNode* root) { + vector arr; + dfs(root, arr); + + int res = arr[1] - arr[0]; + for (int i = 2; i < arr.size(); i++) { + res = min(res, arr[i] - arr[i - 1]); + } + return res; + } + +private: + void dfs(TreeNode* node, vector& arr) { + if (!node) return; + dfs(node->left, arr); + arr.push_back(node->val); + dfs(node->right, arr); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + minDiffInBST(root) { + const arr = []; + + const dfs = (node) => { + if (!node) return; + dfs(node.left); + arr.push(node.val); + dfs(node.right); + }; + + dfs(root); + let res = arr[1] - arr[0]; + for (let i = 2; i < arr.length; i++) { + res = Math.min(res, arr[i] - arr[i - 1]); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Inorder Traversal (Space Optimized) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def minDiffInBST(self, root: Optional[TreeNode]) -> int: + prev, res = None, float("inf") + + def dfs(node): + nonlocal prev, res + if not node: + return + + dfs(node.left) + if prev: + res = min(res, node.val - prev.val) + prev = node + dfs(node.right) + + dfs(root) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private TreeNode prev = null; + private int res = Integer.MAX_VALUE; + + public int minDiffInBST(TreeNode root) { + dfs(root); + return res; + } + + private void dfs(TreeNode node) { + if (node == null) return; + + dfs(node.left); + if (prev != null) { + res = Math.min(res, node.val - prev.val); + } + prev = node; + dfs(node.right); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int minDiffInBST(TreeNode* root) { + TreeNode* prev = nullptr; + int res = INT_MAX; + + dfs(root, prev, res); + return res; + } + +private: + void dfs(TreeNode* node, TreeNode*& prev, int& res) { + if (!node) return; + + dfs(node->left, prev, res); + if (prev) { + res = min(res, node->val - prev->val); + } + prev = node; + dfs(node->right, prev, res); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + minDiffInBST(root) { + let prev = null; + let res = Infinity; + + const dfs = (node) => { + if (!node) return; + + dfs(node.left); + if (prev !== null) { + res = Math.min(res, node.val - prev.val); + } + prev = node; + dfs(node.right); + }; + + dfs(root); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 4. Iterative DFS (Inorder Traversal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def minDiffInBST(self, root: Optional[TreeNode]) -> int: + stack, prev, res = [], None, float("inf") + cur = root + + while stack or cur: + while cur: + stack.append(cur) + cur = cur.left + + cur = stack.pop() + if prev: + res = min(res, cur.val - prev.val) + prev = cur + cur = cur.right + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int minDiffInBST(TreeNode root) { + Stack stack = new Stack<>(); + TreeNode prev = null; + int res = Integer.MAX_VALUE; + TreeNode cur = root; + + while (!stack.isEmpty() || cur != null) { + while (cur != null) { + stack.push(cur); + cur = cur.left; + } + + cur = stack.pop(); + if (prev != null) { + res = Math.min(res, cur.val - prev.val); + } + prev = cur; + cur = cur.right; + } + + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int minDiffInBST(TreeNode* root) { + stack st; + TreeNode* prev = nullptr; + TreeNode* cur = root; + int res = INT_MAX; + + while (!st.empty() || cur) { + while (cur) { + st.push(cur); + cur = cur->left; + } + + cur = st.top(); + st.pop(); + if (prev) { + res = min(res, cur->val - prev->val); + } + prev = cur; + cur = cur->right; + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + minDiffInBST(root) { + let stack = []; + let prev = null; + let res = Infinity; + let cur = root; + + while (stack.length > 0 || cur !== null) { + while (cur !== null) { + stack.push(cur); + cur = cur.left; + } + + cur = stack.pop(); + if (prev !== null) { + res = Math.min(res, cur.val - prev.val); + } + prev = cur; + cur = cur.right; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 5. Morris Traversal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def minDiffInBST(self, root: Optional[TreeNode]) -> int: + prevVal = res = float("inf") + cur = root + + while cur: + if not cur.left: + if prevVal != float("inf"): + res = min(res, cur.val - prevVal) + prevVal = cur.val + cur = cur.right + else: + prev = cur.left + while prev.right and prev.right != cur: + prev = prev.right + + if not prev.right: + prev.right = cur + cur = cur.left + else: + prev.right = None + if prevVal != float("inf"): + res = min(res, cur.val - prevVal) + prevVal = cur.val + cur = cur.right + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int minDiffInBST(TreeNode root) { + int prevVal = Integer.MAX_VALUE, res = Integer.MAX_VALUE; + TreeNode cur = root; + + while (cur != null) { + if (cur.left == null) { + if (prevVal != Integer.MAX_VALUE) { + res = Math.min(res, cur.val - prevVal); + } + prevVal = cur.val; + cur = cur.right; + } else { + TreeNode prev = cur.left; + while (prev.right != null && prev.right != cur) { + prev = prev.right; + } + + if (prev.right == null) { + prev.right = cur; + cur = cur.left; + } else { + prev.right = null; + if (prevVal != Integer.MAX_VALUE) { + res = Math.min(res, cur.val - prevVal); + } + prevVal = cur.val; + cur = cur.right; + } + } + } + + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int minDiffInBST(TreeNode* root) { + int prevVal = INT_MAX, res = INT_MAX; + TreeNode* cur = root; + + while (cur) { + if (!cur->left) { + if (prevVal != INT_MAX) { + res = min(res, cur->val - prevVal); + } + prevVal = cur->val; + cur = cur->right; + } else { + TreeNode* prev = cur->left; + while (prev->right && prev->right != cur) { + prev = prev->right; + } + + if (!prev->right) { + prev->right = cur; + cur = cur->left; + } else { + prev->right = nullptr; + if (prevVal != INT_MAX) { + res = min(res, cur->val - prevVal); + } + prevVal = cur->val; + cur = cur->right; + } + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + minDiffInBST(root) { + let prevVal = Infinity, + res = Infinity; + let cur = root; + + while (cur !== null) { + if (cur.left === null) { + if (prevVal !== Infinity) { + res = Math.min(res, cur.val - prevVal); + } + prevVal = cur.val; + cur = cur.right; + } else { + let prev = cur.left; + while (prev.right !== null && prev.right !== cur) { + prev = prev.right; + } + + if (prev.right === null) { + prev.right = cur; + cur = cur.left; + } else { + prev.right = null; + if (prevVal !== Infinity) { + res = Math.min(res, cur.val - prevVal); + } + prevVal = cur.val; + cur = cur.right; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/minimum-falling-path-sum-ii.md b/articles/minimum-falling-path-sum-ii.md index b43db319c..1ba118d7d 100644 --- a/articles/minimum-falling-path-sum-ii.md +++ b/articles/minimum-falling-path-sum-ii.md @@ -110,8 +110,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -130,7 +130,7 @@ class Solution: return grid[r][c] if (r, c) in cache: return cache[(r, c)] - + res = float("inf") for next_col in range(N): if c != next_col: @@ -253,8 +253,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n ^ 2)$ --- @@ -267,7 +267,7 @@ class Solution: def minFallingPathSum(self, grid: List[List[int]]) -> int: N = len(grid) dp = [[float("inf")] * N for _ in range(N)] - + for c in range(N): dp[N - 1][c] = grid[N - 1][c] @@ -276,7 +276,7 @@ class Solution: for next_col in range(N): if c != next_col: dp[r][c] = min(dp[r][c], grid[r][c] + dp[r + 1][next_col]) - + return min(dp[0]) ``` @@ -285,11 +285,11 @@ public class Solution { public int minFallingPathSum(int[][] grid) { int N = grid.length; int[][] dp = new int[N][N]; - + for (int c = 0; c < N; c++) { dp[N - 1][c] = grid[N - 1][c]; } - + for (int r = N - 2; r >= 0; r--) { for (int c = 0; c < N; c++) { dp[r][c] = Integer.MAX_VALUE; @@ -300,7 +300,7 @@ public class Solution { } } } - + int res = Integer.MAX_VALUE; for (int c = 0; c < N; c++) { res = Math.min(res, dp[0][c]); @@ -350,7 +350,7 @@ class Solution { minFallingPathSum(grid) { const N = grid.length; const dp = Array.from({ length: N }, () => Array(N).fill(Infinity)); - + for (let c = 0; c < N; c++) { dp[N - 1][c] = grid[N - 1][c]; } @@ -359,7 +359,10 @@ class Solution { for (let c = 0; c < N; c++) { for (let nextCol = 0; nextCol < N; nextCol++) { if (c !== nextCol) { - dp[r][c] = Math.min(dp[r][c], grid[r][c] + dp[r + 1][nextCol]); + dp[r][c] = Math.min( + dp[r][c], + grid[r][c] + dp[r + 1][nextCol], + ); } } } @@ -374,8 +377,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n ^ 2)$ --- @@ -477,7 +480,7 @@ class Solution { if (prevC !== currC) { nextDp[currC] = Math.min( nextDp[currC], - grid[r][currC] + dp[prevC] + grid[r][currC] + dp[prevC], ); } } @@ -494,8 +497,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n)$ --- @@ -682,8 +685,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -697,7 +700,7 @@ class Solution: n = len(grid) if n == 1: return grid[0][0] - + dp_idx1 = dp_idx2 = -1 dp_val1 = dp_val2 = 0 @@ -813,15 +816,19 @@ class Solution { const n = grid.length; if (n === 1) return grid[0][0]; - let dpIdx1 = -1, dpIdx2 = -1; - let dpVal1 = 0, dpVal2 = 0; + let dpIdx1 = -1, + dpIdx2 = -1; + let dpVal1 = 0, + dpVal2 = 0; for (let i = 0; i < n; i++) { - let nextDpIdx1 = -1, nextDpIdx2 = -1; - let nextDpVal1 = Infinity, nextDpVal2 = Infinity; + let nextDpIdx1 = -1, + nextDpIdx2 = -1; + let nextDpVal1 = Infinity, + nextDpVal2 = Infinity; for (let j = 0; j < n; j++) { - let cur = (j !== dpIdx1) ? dpVal1 : dpVal2; + let cur = j !== dpIdx1 ? dpVal1 : dpVal2; cur += grid[i][j]; if (nextDpIdx1 === -1 || cur < nextDpVal1) { @@ -850,5 +857,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/minimum-falling-path-sum.md b/articles/minimum-falling-path-sum.md index c12290d15..c275985e0 100644 --- a/articles/minimum-falling-path-sum.md +++ b/articles/minimum-falling-path-sum.md @@ -83,10 +83,9 @@ class Solution { const dfs = (r, c) => { if (r === N) return 0; if (c < 0 || c >= N) return Infinity; - return matrix[r][c] + Math.min( - dfs(r + 1, c - 1), - dfs(r + 1, c), - dfs(r + 1, c + 1) + return ( + matrix[r][c] + + Math.min(dfs(r + 1, c - 1), dfs(r + 1, c), dfs(r + 1, c + 1)) ); }; @@ -103,8 +102,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(3 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(3 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -217,11 +216,9 @@ class Solution { if (c < 0 || c >= N) return Infinity; if (cache[r][c] !== null) return cache[r][c]; - cache[r][c] = matrix[r][c] + Math.min( - dfs(r + 1, c - 1), - dfs(r + 1, c), - dfs(r + 1, c + 1) - ); + cache[r][c] = + matrix[r][c] + + Math.min(dfs(r + 1, c - 1), dfs(r + 1, c), dfs(r + 1, c + 1)); return cache[r][c]; }; @@ -238,8 +235,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * n)$ -* Space complexity: $O(n * n)$ +- Time complexity: $O(n * n)$ +- Space complexity: $O(n * n)$ --- @@ -298,7 +295,7 @@ public: int minFallingPathSum(vector>& matrix) { int N = matrix.size(); vector dp(N); - + for (int c = 0; c < N; c++) { dp[c] = matrix[0][c]; } @@ -336,7 +333,7 @@ class Solution { let leftUp = Infinity; for (let c = 0; c < N; c++) { const midUp = dp[c]; - const rightUp = (c < N - 1) ? dp[c + 1] : Infinity; + const rightUp = c < N - 1 ? dp[c + 1] : Infinity; dp[c] = matrix[r][c] + Math.min(midUp, leftUp, rightUp); leftUp = midUp; } @@ -351,8 +348,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -445,5 +442,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/minimum-fuel-cost-to-report-to-the-capital.md b/articles/minimum-fuel-cost-to-report-to-the-capital.md new file mode 100644 index 000000000..bd67d1dea --- /dev/null +++ b/articles/minimum-fuel-cost-to-report-to-the-capital.md @@ -0,0 +1,299 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def minimumFuelCost(self, roads: list[list[int]], seats: int) -> int: + adj = defaultdict(list) + for src, dst in roads: + adj[src].append(dst) + adj[dst].append(src) + + res = 0 + def dfs(node, parent): + nonlocal res + passengers = 0 + for child in adj[node]: + if child != parent: + p = dfs(child, node) + passengers += p + res += ceil(p / seats) + return passengers + 1 + + dfs(0, -1) + return res +``` + +```java +public class Solution { + private List[] adj; + private long res = 0; + + public long minimumFuelCost(int[][] roads, int seats) { + int n = roads.length + 1; + adj = new ArrayList[n]; + + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + + for (int[] road : roads) { + adj[road[0]].add(road[1]); + adj[road[1]].add(road[0]); + } + + dfs(0, -1, seats); + return res; + } + + private int dfs(int node, int parent, int seats) { + int passengers = 0; + for (int child : adj[node]) { + if (child != parent) { + int p = dfs(child, node, seats); + passengers += p; + res += Math.ceil((double) p / seats); + } + } + return passengers + 1; + } +} +``` + +```cpp +class Solution { +private: + vector> adj; + long long res = 0; + +public: + long long minimumFuelCost(vector>& roads, int seats) { + int n = roads.size() + 1; + adj.resize(n); + + for (auto& road : roads) { + adj[road[0]].push_back(road[1]); + adj[road[1]].push_back(road[0]); + } + + dfs(0, -1, seats); + return res; + } + +private: + int dfs(int node, int parent, int seats) { + int passengers = 0; + for (int child : adj[node]) { + if (child != parent) { + int p = dfs(child, node, seats); + passengers += p; + res += ceil((double) p / seats); + } + } + return passengers + 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} roads + * @param {number} seats + * @return {number} + */ + minimumFuelCost(roads, seats) { + const n = roads.length + 1; + const adj = Array.from({ length: n }, () => []); + let res = 0; + + for (const [src, dst] of roads) { + adj[src].push(dst); + adj[dst].push(src); + } + + const dfs = (node, parent) => { + let passengers = 0; + for (const child of adj[node]) { + if (child !== parent) { + let p = dfs(child, node); + passengers += p; + res += Math.ceil(p / seats); + } + } + return passengers + 1; + }; + + dfs(0, -1); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Topological Sort (Kahn's Algorithm) + +::tabs-start + +```python +class Solution: + def minimumFuelCost(self, roads: list[list[int]], seats: int) -> int: + n = len(roads) + 1 + adj = [[] for _ in range(n)] + indegree = [0] * n + passengers = [1] * n + res = 0 + + for src, dst in roads: + adj[src].append(dst) + adj[dst].append(src) + indegree[src] += 1 + indegree[dst] += 1 + + q = deque() + for i in range(1, n): + if indegree[i] == 1: + q.append(i) + + while q: + node = q.popleft() + res += math.ceil(passengers[node] / seats) + for parent in adj[node]: + indegree[parent] -= 1 + if indegree[parent] == 1 and parent != 0: + q.append(parent) + passengers[parent] += passengers[node] + + return res +``` + +```java +public class Solution { + public long minimumFuelCost(int[][] roads, int seats) { + int n = roads.length + 1; + List[] adj = new ArrayList[n]; + int[] indegree = new int[n]; + int[] passengers = new int[n]; + Arrays.fill(passengers, 1); + long res = 0; + + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + + for (int[] road : roads) { + int src = road[0], dst = road[1]; + adj[src].add(dst); + adj[dst].add(src); + indegree[src]++; + indegree[dst]++; + } + + Queue q = new LinkedList<>(); + for (int i = 1; i < n; i++) { + if (indegree[i] == 1) q.offer(i); + } + + while (!q.isEmpty()) { + int node = q.poll(); + res += (int) Math.ceil((double) passengers[node] / seats); + for (int parent : adj[node]) { + if (--indegree[parent] == 1 && parent != 0) q.offer(parent); + passengers[parent] += passengers[node]; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long minimumFuelCost(vector>& roads, int seats) { + int n = roads.size() + 1; + vector> adj(n); + vector indegree(n, 0), passengers(n, 1); + long long res = 0; + + for (auto& road : roads) { + int src = road[0], dst = road[1]; + adj[src].push_back(dst); + adj[dst].push_back(src); + indegree[src]++; + indegree[dst]++; + } + + queue q; + for (int i = 1; i < n; i++) { + if (indegree[i] == 1) q.push(i); + } + + while (!q.empty()) { + int node = q.front();q.pop(); + res += ceil((double) passengers[node] / seats); + for (int parent : adj[node]) { + if (--indegree[parent] == 1 && parent != 0) q.push(parent); + passengers[parent] += passengers[node]; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} roads + * @param {number} seats + * @return {number} + */ + minimumFuelCost(roads, seats) { + const n = roads.length + 1; + const adj = Array.from({ length: n }, () => []); + const indegree = new Array(n).fill(0); + const passengers = new Array(n).fill(1); + let res = 0; + + for (const [src, dst] of roads) { + adj[src].push(dst); + adj[dst].push(src); + indegree[src] += 1; + indegree[dst] += 1; + } + + const q = new Queue(); + for (let i = 1; i < n; i++) { + if (indegree[i] === 1) q.push(i); + } + + while (!q.isEmpty()) { + const node = q.pop(); + res += Math.ceil(passengers[node] / seats); + for (const parent of adj[node]) { + if (--indegree[parent] === 1 && parent !== 0) q.push(parent); + passengers[parent] += passengers[node]; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/minimum-height-trees.md b/articles/minimum-height-trees.md index 19f63684e..215681564 100644 --- a/articles/minimum-height-trees.md +++ b/articles/minimum-height-trees.md @@ -9,7 +9,7 @@ class Solution: for u, v in edges: adj[u].append(v) adj[v].append(u) - + def dfs(node, parent): hgt = 0 for nei in adj[node]: @@ -17,7 +17,7 @@ class Solution: continue hgt = max(hgt, 1 + dfs(nei, node)) return hgt - + minHgt = n res = [] for i in range(n): @@ -27,7 +27,7 @@ class Solution: elif curHgt < minHgt: res = [i] minHgt = curHgt - + return res ``` @@ -152,12 +152,51 @@ class Solution { } ``` +```csharp +public class Solution { + private List> adj; + + public List FindMinHeightTrees(int n, int[][] edges) { + adj = new List>(); + for (int i = 0; i < n; i++) { + adj.Add(new List()); + } + foreach (var edge in edges) { + adj[edge[0]].Add(edge[1]); + adj[edge[1]].Add(edge[0]); + } + + int minHgt = n; + List result = new List(); + for (int i = 0; i < n; i++) { + int curHgt = Dfs(i, -1); + if (curHgt == minHgt) { + result.Add(i); + } else if (curHgt < minHgt) { + result = new List { i }; + minHgt = curHgt; + } + } + return result; + } + + private int Dfs(int node, int parent) { + int hgt = 0; + foreach (int nei in adj[node]) { + if (nei == parent) continue; + hgt = Math.Max(hgt, 1 + Dfs(nei, node)); + } + return hgt; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V * (V + E))$ -* Space complexity: $O(V)$ +- Time complexity: $O(V * (V + E))$ +- Space complexity: $O(V)$ > Where $V$ is the number of vertices and $E$ is the number of edges. @@ -174,7 +213,7 @@ class Solution: for u, v in edges: adj[u].append(v) adj[v].append(u) - + dp = [[0] * 2 for _ in range(n)] # top two heights for each node def dfs(node, parent): @@ -201,7 +240,7 @@ class Solution: continue toChild = 1 + (dp[node][1] if dp[node][0] == 1 + dp[nei][0] else dp[node][0]) dfs1(nei, node, toChild) - + dfs(0, -1) dfs1(0, -1, 0) @@ -380,7 +419,11 @@ class Solution { for (const nei of adj[node]) { if (nei === parent) continue; - const toChild = 1 + ((dp[node][0] === 1 + dp[nei][0]) ? dp[node][1] : dp[node][0]); + const toChild = + 1 + + (dp[node][0] === 1 + dp[nei][0] + ? dp[node][1] + : dp[node][0]); dfs1(nei, node, toChild); } }; @@ -403,12 +446,80 @@ class Solution { } ``` +```csharp +public class Solution { + private List> adj; + private int[][] dp; + + public List FindMinHeightTrees(int n, int[][] edges) { + adj = new List>(); + for (int i = 0; i < n; i++) { + adj.Add(new List()); + } + + foreach (var edge in edges) { + adj[edge[0]].Add(edge[1]); + adj[edge[1]].Add(edge[0]); + } + + dp = new int[n][]; + for (int i = 0; i < n; i++) { + dp[i] = new int[2]; // top two heights + } + + Dfs(0, -1); + Dfs1(0, -1, 0); + + int minHgt = n; + List res = new List(); + for (int i = 0; i < n; i++) { + minHgt = Math.Min(minHgt, dp[i][0]); + } + for (int i = 0; i < n; i++) { + if (dp[i][0] == minHgt) { + res.Add(i); + } + } + return res; + } + + private void Dfs(int node, int parent) { + foreach (int nei in adj[node]) { + if (nei == parent) continue; + Dfs(nei, node); + int curHgt = 1 + dp[nei][0]; + if (curHgt > dp[node][0]) { + dp[node][1] = dp[node][0]; + dp[node][0] = curHgt; + } else if (curHgt > dp[node][1]) { + dp[node][1] = curHgt; + } + } + } + + private void Dfs1(int node, int parent, int topHgt) { + if (topHgt > dp[node][0]) { + dp[node][1] = dp[node][0]; + dp[node][0] = topHgt; + } else if (topHgt > dp[node][1]) { + dp[node][1] = topHgt; + } + + foreach (int nei in adj[node]) { + if (nei == parent) continue; + int toChild = 1 + ((dp[node][0] == 1 + dp[nei][0]) ? dp[node][1] : dp[node][0]); + Dfs1(nei, node, toChild); + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V + E)$ -* Space complexity: $O(V)$ +- Time complexity: $O(V + E)$ +- Space complexity: $O(V)$ > Where $V$ is the number of vertices and $E$ is the number of edges. @@ -538,7 +649,7 @@ public: vector findMinHeightTrees(int n, vector>& edges) { if (n == 1) return {0}; - + adj.resize(n); for (const auto& edge : edges) { adj[edge[0]].push_back(edge[1]); @@ -654,12 +765,79 @@ class Solution { } ``` +```csharp +public class Solution { + private List[] adj; + private int nodeB; + private List centroids; + + public List FindMinHeightTrees(int n, int[][] edges) { + if (n == 1) return new List { 0 }; + + adj = new List[n]; + for (int i = 0; i < n; i++) adj[i] = new List(); + + foreach (var edge in edges) { + adj[edge[0]].Add(edge[1]); + adj[edge[1]].Add(edge[0]); + } + + var nodeA = Dfs(0, -1).Item1; + var dfsRes = Dfs(nodeA, -1); + nodeB = dfsRes.Item1; + int diameter = dfsRes.Item2; + + centroids = new List(); + FindCentroids(nodeA, -1); + + int L = centroids.Count; + if (diameter % 2 == 0) { + return new List { centroids[L / 2] }; + } else { + return new List { centroids[L / 2 - 1], centroids[L / 2] }; + } + } + + private (int, int) Dfs(int node, int parent) { + int farthestNode = node; + int maxDistance = 0; + + foreach (int nei in adj[node]) { + if (nei == parent) continue; + var (neiNode, neiDist) = Dfs(nei, node); + if (neiDist + 1 > maxDistance) { + maxDistance = neiDist + 1; + farthestNode = neiNode; + } + } + + return (farthestNode, maxDistance); + } + + private bool FindCentroids(int node, int parent) { + if (node == nodeB) { + centroids.Add(node); + return true; + } + + foreach (int nei in adj[node]) { + if (nei == parent) continue; + if (FindCentroids(nei, node)) { + centroids.Add(node); + return true; + } + } + return false; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V + E)$ -* Space complexity: $O(V)$ +- Time complexity: $O(V + E)$ +- Space complexity: $O(V)$ > Where $V$ is the number of vertices and $E$ is the number of edges. @@ -837,11 +1015,57 @@ class Solution { } ``` +```csharp +public class Solution { + public List FindMinHeightTrees(int n, int[][] edges) { + if (n == 1) return new List { 0 }; + + var adj = new Dictionary>(); + for (int i = 0; i < n; i++) { + adj[i] = new List(); + } + + foreach (var edge in edges) { + adj[edge[0]].Add(edge[1]); + adj[edge[1]].Add(edge[0]); + } + + var edgeCnt = new Dictionary(); + var leaves = new Queue(); + + foreach (var kvp in adj) { + edgeCnt[kvp.Key] = kvp.Value.Count; + if (kvp.Value.Count == 1) { + leaves.Enqueue(kvp.Key); + } + } + + while (leaves.Count > 0) { + if (n <= 2) return new List(leaves); + + int sz = leaves.Count; + for (int i = 0; i < sz; i++) { + int node = leaves.Dequeue(); + n--; + foreach (int nei in adj[node]) { + edgeCnt[nei]--; + if (edgeCnt[nei] == 1) { + leaves.Enqueue(nei); + } + } + } + } + + return new List(); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V + E)$ -* Space complexity: $O(V)$ +- Time complexity: $O(V + E)$ +- Space complexity: $O(V)$ -> Where $V$ is the number of vertices and $E$ is the number of edges. \ No newline at end of file +> Where $V$ is the number of vertices and $E$ is the number of edges. diff --git a/articles/minimum-index-of-a-valid-split.md b/articles/minimum-index-of-a-valid-split.md new file mode 100644 index 000000000..f877fc5a5 --- /dev/null +++ b/articles/minimum-index-of-a-valid-split.md @@ -0,0 +1,388 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def minimumIndex(self, nums: List[int]) -> int: + n = len(nums) + + for i in range(n - 1): + left_cnt = defaultdict(int) + for l in range(i + 1): + left_cnt[nums[l]] += 1 + + right_cnt = defaultdict(int) + for r in range(i + 1, n): + right_cnt[nums[r]] += 1 + + for num in left_cnt: + if left_cnt[num] > (i + 1) // 2 and right_cnt[num] > (n - i - 1) // 2: + return i + + return -1 +``` + +```java +public class Solution { + public int minimumIndex(List nums) { + int n = nums.size(); + + for (int i = 0; i < n - 1; i++) { + Map leftCnt = new HashMap<>(); + for (int l = 0; l <= i; l++) { + int val = nums.get(l); + leftCnt.put(val, leftCnt.getOrDefault(val, 0) + 1); + } + + Map rightCnt = new HashMap<>(); + for (int r = i + 1; r < n; r++) { + int val = nums.get(r); + rightCnt.put(val, rightCnt.getOrDefault(val, 0) + 1); + } + + for (int num : leftCnt.keySet()) { + if (leftCnt.get(num) > (i + 1) / 2 && rightCnt.getOrDefault(num, 0) > (n - i - 1) / 2) { + return i; + } + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int minimumIndex(vector& nums) { + int n = nums.size(); + + for (int i = 0; i < n - 1; i++) { + unordered_map leftCnt, rightCnt; + for (int l = 0; l <= i; l++) { + leftCnt[nums[l]]++; + } + for (int r = i + 1; r < n; r++) { + rightCnt[nums[r]]++; + } + + for (auto& [num, cnt] : leftCnt) { + if (cnt > (i + 1) / 2 && rightCnt[num] > (n - i - 1) / 2) { + return i; + } + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimumIndex(nums) { + const n = nums.length; + + for (let i = 0; i < n - 1; i++) { + const leftCnt = {}; + for (let l = 0; l <= i; l++) { + leftCnt[nums[l]] = (leftCnt[nums[l]] || 0) + 1; + } + + const rightCnt = {}; + for (let r = i + 1; r < n; r++) { + rightCnt[nums[r]] = (rightCnt[nums[r]] || 0) + 1; + } + + for (const num in leftCnt) { + if ( + leftCnt[num] > Math.floor((i + 1) / 2) && + (rightCnt[num] || 0) > Math.floor((n - i - 1) / 2) + ) { + return i; + } + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 2. Hash Map + +::tabs-start + +```python +class Solution: + def minimumIndex(self, nums: List[int]) -> int: + left = defaultdict(int) + right = Counter(nums) + + for i in range(len(nums)): + left[nums[i]] += 1 + right[nums[i]] -= 1 + + left_len = i + 1 + right_len = len(nums) - i - 1 + + if 2 * left[nums[i]] > left_len and 2 * right[nums[i]] > right_len: + return i + + return -1 +``` + +```java +public class Solution { + public int minimumIndex(List nums) { + Map left = new HashMap<>(); + Map right = new HashMap<>(); + int n = nums.size(); + + for (int num : nums) { + right.put(num, right.getOrDefault(num, 0) + 1); + } + + for (int i = 0; i < n; i++) { + int num = nums.get(i); + left.put(num, left.getOrDefault(num, 0) + 1); + right.put(num, right.get(num) - 1); + + int leftLen = i + 1; + int rightLen = n - i - 1; + + if (2 * left.get(num) > leftLen && 2 * right.get(num) > rightLen) { + return i; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int minimumIndex(vector& nums) { + unordered_map left, right; + int n = nums.size(); + + for (int num : nums) { + right[num]++; + } + + for (int i = 0; i < n; i++) { + int num = nums[i]; + left[num]++; + right[num]--; + + int leftLen = i + 1; + int rightLen = n - i - 1; + + if (2 * left[num] > leftLen && 2 * right[num] > rightLen) { + return i; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimumIndex(nums) { + const left = {}; + const right = {}; + const n = nums.length; + + for (const num of nums) { + right[num] = (right[num] || 0) + 1; + } + + for (let i = 0; i < n; i++) { + const num = nums[i]; + left[num] = (left[num] || 0) + 1; + right[num] -= 1; + + const leftLen = i + 1; + const rightLen = n - i - 1; + + if (2 * left[num] > leftLen && 2 * right[num] > rightLen) { + return i; + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Boyer-Moore Voting Algorithm + +::tabs-start + +```python +class Solution: + def minimumIndex(self, nums: List[int]) -> int: + majority = count = 0 + for num in nums: + if count == 0: + majority = num + count += (1 if majority == num else -1) + + left_cnt, right_cnt = 0, nums.count(majority) + + for i in range(len(nums)): + if nums[i] == majority: + left_cnt += 1 + right_cnt -= 1 + + left_len = i + 1 + right_len = len(nums) - i - 1 + + if 2 * left_cnt > left_len and 2 * right_cnt > right_len: + return i + + return -1 +``` + +```java +public class Solution { + public int minimumIndex(List nums) { + int majority = 0, count = 0; + for (int num : nums) { + if (count == 0) majority = num; + count += (majority == num) ? 1 : -1; + } + + int leftCnt = 0, rightCnt = 0; + for (int num : nums) { + if (num == majority) rightCnt++; + } + + int n = nums.size(); + for (int i = 0; i < n; i++) { + if (nums.get(i) == majority) { + leftCnt++; + rightCnt--; + } + + int leftLen = i + 1; + int rightLen = n - i - 1; + + if (2 * leftCnt > leftLen && 2 * rightCnt > rightLen) { + return i; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int minimumIndex(vector& nums) { + int majority = 0, count = 0; + for (int num : nums) { + if (count == 0) majority = num; + count += (num == majority ? 1 : -1); + } + + int leftCnt = 0, rightCnt = count_if(nums.begin(), nums.end(), + [&](int x) { return x == majority; }); + + int n = nums.size(); + for (int i = 0; i < n; i++) { + if (nums[i] == majority) { + leftCnt++; + rightCnt--; + } + + int leftLen = i + 1; + int rightLen = n - i - 1; + + if (2 * leftCnt > leftLen && 2 * rightCnt > rightLen) { + return i; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minimumIndex(nums) { + let majority = 0, + count = 0; + for (let num of nums) { + if (count === 0) majority = num; + count += num === majority ? 1 : -1; + } + + let leftCnt = 0; + let rightCnt = nums.filter((x) => x === majority).length; + const n = nums.length; + + for (let i = 0; i < n; i++) { + if (nums[i] === majority) { + leftCnt++; + rightCnt--; + } + + let leftLen = i + 1; + let rightLen = n - i - 1; + + if (2 * leftCnt > leftLen && 2 * rightCnt > rightLen) { + return i; + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/minimum-interval-including-query.md b/articles/minimum-interval-including-query.md index cd76921c2..2d705b5d3 100644 --- a/articles/minimum-interval-including-query.md +++ b/articles/minimum-interval-including-query.md @@ -74,7 +74,7 @@ class Solution { let cur = -1; for (const [l, r] of intervals) { if (l <= q && q <= r) { - if (cur === -1 || (r - l + 1) < cur) { + if (cur === -1 || r - l + 1 < cur) { cur = r - l + 1; } } @@ -149,12 +149,39 @@ class Solution { } ``` +```swift +class Solution { + func minInterval(_ intervals: [[Int]], _ queries: [Int]) -> [Int] { + var res = [Int]() + + for q in queries { + var cur = -1 + for interval in intervals { + let l = interval[0] + let r = interval[1] + + if l <= q && q <= r { + if cur == -1 || (r - l + 1) < cur { + cur = r - l + 1 + } + } + } + res.append(cur) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(m * n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(m)$ space for the output array. > Where $m$ is the length of the array $queries$ and $n$ is the length of the array $intervals$. @@ -170,21 +197,21 @@ class Solution: events = [] # Create events for intervals for idx, (start, end) in enumerate(intervals): - events.append((start, 0, end - start + 1, idx)) - events.append((end, 2, end - start + 1, idx)) - + events.append((start, 0, end - start + 1, idx)) + events.append((end, 2, end - start + 1, idx)) + # Create events for queries for i, q in enumerate(queries): events.append((q, 1, i)) - + # Sort by time and type (end before query) events.sort(key=lambda x: (x[0], x[1])) - + # Min heap storing [size, index] - sizes = [] + sizes = [] ans = [-1] * len(queries) inactive = [False] * len(intervals) - + for time, type, *rest in events: if type == 0: # Interval start interval_size, idx = rest @@ -198,7 +225,7 @@ class Solution: heapq.heappop(sizes) if sizes: ans[query_idx] = sizes[0][0] - + return ans ``` @@ -208,32 +235,32 @@ public class Solution { List events = new ArrayList<>(); for (int i = 0; i < intervals.length; i++) { events.add(new int[]{intervals[i][0], 0, intervals[i][1] - intervals[i][0] + 1, i}); - events.add(new int[]{intervals[i][1], 2, intervals[i][1] - intervals[i][0] + 1, i}); + events.add(new int[]{intervals[i][1], 2, intervals[i][1] - intervals[i][0] + 1, i}); } - + for (int i = 0; i < queries.length; i++) { events.add(new int[]{queries[i], 1, i}); } - + // Sort by time and type (end before query) - events.sort((a, b) -> a[0] != b[0] ? - Integer.compare(a[0], b[0]) : + events.sort((a, b) -> a[0] != b[0] ? + Integer.compare(a[0], b[0]) : Integer.compare(a[1], b[1])); - + int[] ans = new int[queries.length]; Arrays.fill(ans, -1); - + // Min heap storing [size, index] PriorityQueue pq = new PriorityQueue<>((a, b) -> Integer.compare(a[0], b[0])); boolean[] inactive = new boolean[intervals.length]; - + for (int[] event : events) { if (event[1] == 0) { // Interval start pq.offer(new int[]{event[2], event[3]}); - } + } else if (event[1] == 2) { // Interval end inactive[event[3]] = true; - } + } else { // Query while (!pq.isEmpty() && inactive[pq.peek()[1]]) { pq.poll(); @@ -243,7 +270,7 @@ public class Solution { } } } - + return ans; } } @@ -259,22 +286,22 @@ public: events.push_back({intervals[i][0], 0, intervals[i][1] - intervals[i][0] + 1, i}); events.push_back({intervals[i][1], 2, intervals[i][1] - intervals[i][0] + 1, i}); } - + // Create events for queries for (int i = 0; i < queries.size(); i++) { events.push_back({queries[i], 1, i}); } - + // Sort by time and type (end before query) sort(events.begin(), events.end(), [](const vector& a, const vector& b) { return a[0] == b[0] ? a[1] < b[1] : a[0] < b[0]; }); - + vector ans(queries.size(), -1); // Min heap storing [size, index] priority_queue, vector>, greater>> pq; vector inactive(intervals.size(), false); - + for (const auto& event : events) { if (event[1] == 0) { // Interval start pq.push({event[2], event[3]}); @@ -290,7 +317,7 @@ public: } } } - + return ans; } }; @@ -325,11 +352,14 @@ class Solution { const inactive = Array(intervals.length).fill(false); for (const [time, type, ...rest] of events) { - if (type === 0) { // Interval start + if (type === 0) { + // Interval start pq.push([rest[0], rest[1]]); - } else if (type === 2) { // Interval end + } else if (type === 2) { + // Interval end inactive[rest[1]] = true; - } else { // Query + } else { + // Query while (!pq.isEmpty() && inactive[pq.front()[1]]) { pq.pop(); } @@ -338,7 +368,7 @@ class Solution { } } } - + return ans; } } @@ -353,20 +383,20 @@ public class Solution { events.Add(new int[] { intervals[i][0], 0, intervals[i][1] - intervals[i][0] + 1, i }); events.Add(new int[] { intervals[i][1], 2, intervals[i][1] - intervals[i][0] + 1, i }); } - + // Create events for queries for (int i = 0; i < queries.Length; i++) { events.Add(new int[] { queries[i], 1, i }); } // Sort by time and type (end before query) events.Sort((a, b) => a[0] == b[0] ? a[1].CompareTo(b[1]) : a[0].CompareTo(b[0])); - + int[] ans = new int[queries.Length]; Array.Fill(ans, -1); // Min heap storing [size, index] var pq = new PriorityQueue<(int size, int idx), int>(); var inactive = new bool[intervals.Length]; - + foreach (var e in events) { if (e[1] == 0) { // Interval start pq.Enqueue((e[2], e[3]), e[2]); @@ -382,7 +412,7 @@ public class Solution { } } } - + return ans; } } @@ -398,7 +428,7 @@ type Event struct { func minInterval(intervals [][]int, queries []int) []int { events := []Event{} - + // Create events for intervals for idx, interval := range intervals { start, end := interval[0], interval[1] @@ -406,12 +436,12 @@ func minInterval(intervals [][]int, queries []int) []int { events = append(events, Event{start, 0, size, idx}) events = append(events, Event{end, 2, size, idx}) } - + // Create events for queries for i, q := range queries { events = append(events, Event{q, 1, i, -1}) } - + // Sort events by time and type sort.Slice(events, func(i, j int) bool { if events[i].time == events[j].time { @@ -429,7 +459,7 @@ func minInterval(intervals [][]int, queries []int) []int { ans[i] = -1 } inactive := make([]bool, len(intervals)) - + for _, event := range events { switch event.typ { case 0: // Interval start @@ -462,7 +492,7 @@ data class Event(val time: Int, val type: Int, val sizeOrQueryIndex: Int, val id class Solution { fun minInterval(intervals: Array, queries: IntArray): IntArray { val events = mutableListOf() - + // Create events for intervals for ((idx, interval) in intervals.withIndex()) { val (start, end) = interval @@ -470,19 +500,19 @@ class Solution { events.add(Event(start, 0, size, idx)) events.add(Event(end, 2, size, idx)) } - + // Create events for queries for ((i, q) in queries.withIndex()) { events.add(Event(q, 1, i, -1)) } - + // Sort events by time and type events.sortWith(compareBy({ it.time }, { it.type })) - + val sizes = PriorityQueue>(compareBy { it.first }) val ans = IntArray(queries.size) { -1 } val inactive = BooleanArray(intervals.size) - + for (event in events) { when (event.type) { 0 -> { // Interval start @@ -502,7 +532,79 @@ class Solution { } } } - + + return ans + } +} +``` + +```swift +struct Event { + let time: Int + let type: Int // 0: interval start, 1: query, 2: interval end + let size: Int? // interval size for start/end events + let idx: Int? // index for interval (for start/end) or query index (for query) +} + +struct Item: Comparable { + let size: Int + let idx: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.size < rhs.size + } +} + +class Solution { + func minInterval(_ intervals: [[Int]], _ queries: [Int]) -> [Int] { + var events = [Event]() + + // Create events for intervals + for (idx, interval) in intervals.enumerated() { + let start = interval[0] + let end = interval[1] + let intervalSize = end - start + 1 + events.append(Event(time: start, type: 0, size: intervalSize, idx: idx)) + events.append(Event(time: end, type: 2, size: intervalSize, idx: idx)) + } + + // Create events for queries + for (i, q) in queries.enumerated() { + events.append(Event(time: q, type: 1, size: nil, idx: i)) + } + + // Sort by time and type (end before query) + events.sort { (a, b) in + if a.time != b.time { + return a.time < b.time + } + return a.type < b.type + } + + // Min heap storing [size, index] + var sizes = Heap() + var ans = Array(repeating: -1, count: queries.count) + var inactive = Array(repeating: false, count: intervals.count) + + for event in events { + if event.type == 0 { // Interval start + let intervalSize = event.size! + let idx = event.idx! + sizes.insert(Item(size: intervalSize, idx: idx)) + } else if event.type == 2 { // Interval end + let idx = event.idx! + inactive[idx] = true + } else { // Query + let queryIdx = event.idx! + while !sizes.isEmpty, inactive[sizes.min!.idx] { + sizes.removeMin() + } + if !sizes.isEmpty { + ans[queryIdx] = sizes.min!.size + } + } + } + return ans } } @@ -512,8 +614,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O((n + m) \log (n + m))$ -* Space complexity: $O(n + m)$ +- Time complexity: $O((n + m) \log (n + m))$ +- Space complexity: $O(n + m)$ > Where $m$ is the length of the array $queries$ and $n$ is the length of the array $intervals$. @@ -627,7 +729,7 @@ class Solution { */ minInterval(intervals, queries) { intervals.sort((a, b) => a[0] - b[0]); - const minHeap = new MinPriorityQueue(entry => entry[0]); + const minHeap = new MinPriorityQueue((entry) => entry[0]); const res = {}; let i = 0; @@ -647,7 +749,7 @@ class Solution { res[q] = !minHeap.isEmpty() ? minHeap.front()[0] : -1; } - return queries.map(q => res[q]); + return queries.map((q) => res[q]); } } ``` @@ -692,7 +794,7 @@ func minInterval(intervals [][]int, queries []int) []int { sort.Slice(intervals, func(i, j int) bool { return intervals[i][0] < intervals[j][0] }) - + queriesWithIdx := make([][2]int, len(queries)) for i, q := range queries { queriesWithIdx[i] = [2]int{q, i} @@ -700,7 +802,7 @@ func minInterval(intervals [][]int, queries []int) []int { sort.Slice(queriesWithIdx, func(i, j int) bool { return queriesWithIdx[i][0] < queriesWithIdx[j][0] }) - + comparator := func(a, b interface{}) int { pair1 := a.([2]int) pair2 := b.([2]int) @@ -712,20 +814,20 @@ func minInterval(intervals [][]int, queries []int) []int { } return 0 } - + pq := priorityqueue.NewWith(comparator) res := make([]int, len(queries)) i := 0 - + for _, qPair := range queriesWithIdx { q, originalIdx := qPair[0], qPair[1] - + for i < len(intervals) && intervals[i][0] <= q { size := intervals[i][1] - intervals[i][0] + 1 pq.Enqueue([2]int{size, intervals[i][1]}) i++ } - + for !pq.Empty() { if top, _ := pq.Peek(); top.([2]int)[1] < q { pq.Dequeue() @@ -733,7 +835,7 @@ func minInterval(intervals [][]int, queries []int) []int { break } } - + if !pq.Empty() { if top, _ := pq.Peek(); true { res[originalIdx] = top.([2]int)[0] @@ -742,7 +844,7 @@ func minInterval(intervals [][]int, queries []int) []int { res[originalIdx] = -1 } } - + return res } ``` @@ -751,40 +853,78 @@ func minInterval(intervals [][]int, queries []int) []int { class Solution { fun minInterval(intervals: Array, queries: IntArray): IntArray { intervals.sortBy { it[0] } - + val queriesWithIndex = queries.withIndex() .map { it.value to it.index } .sortedBy { it.first } - + val minHeap = PriorityQueue>(compareBy { it.first }) val result = IntArray(queries.size) var i = 0 - + for ((q, originalIdx) in queriesWithIndex) { while (i < intervals.size && intervals[i][0] <= q) { val size = intervals[i][1] - intervals[i][0] + 1 minHeap.offer(size to intervals[i][1]) i++ } - + while (minHeap.isNotEmpty() && minHeap.peek().second < q) { minHeap.poll() } - + result[originalIdx] = if (minHeap.isNotEmpty()) minHeap.peek().first else -1 } - + return result } } ``` +```swift +struct HeapItem: Comparable { + let size: Int + let end: Int + static func < (lhs: HeapItem, rhs: HeapItem) -> Bool { + if lhs.size == rhs.size { + return lhs.end < rhs.end + } + return lhs.size < rhs.size + } +} + +class Solution { + func minInterval(_ intervals: [[Int]], _ queries: [Int]) -> [Int] { + let sortedIntervals = intervals.sorted { $0[0] < $1[0] } + var minHeap = Heap() + var res = [Int: Int]() + var i = 0 + + for q in queries.sorted() { + while i < sortedIntervals.count && sortedIntervals[i][0] <= q { + let l = sortedIntervals[i][0] + let r = sortedIntervals[i][1] + minHeap.insert(HeapItem(size: r - l + 1, end: r)) + i += 1 + } + + while !minHeap.isEmpty, minHeap.min!.end < q { + minHeap.removeMin() + } + res[q] = minHeap.isEmpty ? -1 : minHeap.min!.size + } + + return queries.map { res[$0] ?? -1 } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n + m \log m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n \log n + m \log m)$ +- Space complexity: $O(n + m)$ > Where $m$ is the length of the array $queries$ and $n$ is the length of the array $intervals$. @@ -863,7 +1003,7 @@ class Solution: ans = [] for q in queries: idx = compress[q] - + # query for minSize res = segTree.query_point(idx) ans.append(res if res != float('inf') else -1) @@ -871,7 +1011,7 @@ class Solution: ``` ```java -public class SegmentTree { +class SegmentTree { int n; int[] tree; int[] lazy; @@ -995,7 +1135,7 @@ public: void update(int treeidx, int lo, int hi, int left, int right, int val) { propagate(treeidx, lo, hi); - + if (lo > right || hi < left) return; if (lo >= left && hi <= right) { @@ -1007,14 +1147,14 @@ public: int mid = (lo + hi) / 2; update(2 * treeidx + 1, lo, mid, left, right, val); update(2 * treeidx + 2, mid + 1, hi, left, right, val); - + tree[treeidx] = min(tree[2 * treeidx + 1], tree[2 * treeidx + 2]); } int query(int treeidx, int lo, int hi, int idx) { propagate(treeidx, lo, hi); if (lo == hi) return tree[treeidx]; - + int mid = (lo + hi) / 2; if (idx <= mid) return query(2 * treeidx + 1, lo, mid, idx); else return query(2 * treeidx + 2, mid + 1, hi, idx); @@ -1088,10 +1228,19 @@ class SegmentTree { */ propagate(treeidx, lo, hi) { if (this.lazy[treeidx] !== Infinity) { - this.tree[treeidx] = Math.min(this.tree[treeidx], this.lazy[treeidx]); + this.tree[treeidx] = Math.min( + this.tree[treeidx], + this.lazy[treeidx], + ); if (lo !== hi) { - this.lazy[2 * treeidx + 1] = Math.min(this.lazy[2 * treeidx + 1], this.lazy[treeidx]); - this.lazy[2 * treeidx + 2] = Math.min(this.lazy[2 * treeidx + 2], this.lazy[treeidx]); + this.lazy[2 * treeidx + 1] = Math.min( + this.lazy[2 * treeidx + 1], + this.lazy[treeidx], + ); + this.lazy[2 * treeidx + 2] = Math.min( + this.lazy[2 * treeidx + 2], + this.lazy[treeidx], + ); } this.lazy[treeidx] = Infinity; } @@ -1117,7 +1266,10 @@ class SegmentTree { const mid = Math.floor((lo + hi) / 2); this.update(2 * treeidx + 1, lo, mid, left, right, val); this.update(2 * treeidx + 2, mid + 1, hi, left, right, val); - this.tree[treeidx] = Math.min(this.tree[2 * treeidx + 1], this.tree[2 * treeidx + 2]); + this.tree[treeidx] = Math.min( + this.tree[2 * treeidx + 1], + this.tree[2 * treeidx + 2], + ); } /** @@ -1355,27 +1507,27 @@ func minInterval(intervals [][]int, queries []int) []int { for _, q := range queries { points[q] = true } - + pointsList := make([]int, 0, len(points)) for point := range points { pointsList = append(pointsList, point) } sort.Ints(pointsList) - + compress := make(map[int]int) for i, point := range pointsList { compress[point] = i } - + segTree := NewSegmentTree(len(pointsList)) - + for _, interval := range intervals { start := compress[interval[0]] end := compress[interval[1]] length := interval[1] - interval[0] + 1 segTree.Update(start, end, length) } - + ans := make([]int, len(queries)) for i, q := range queries { idx := compress[q] @@ -1386,7 +1538,7 @@ func minInterval(intervals [][]int, queries []int) []int { ans[i] = res } } - + return ans } ``` @@ -1395,7 +1547,7 @@ func minInterval(intervals [][]int, queries []int) []int { class SegmentTree(private val n: Int) { private val tree = IntArray(4 * n) { Int.MAX_VALUE } private val lazy = IntArray(4 * n) { Int.MAX_VALUE } - + private fun propagate(treeIdx: Int, lo: Int, hi: Int) { if (lazy[treeIdx] != Int.MAX_VALUE) { tree[treeIdx] = minOf(tree[treeIdx], lazy[treeIdx]) @@ -1406,7 +1558,7 @@ class SegmentTree(private val n: Int) { lazy[treeIdx] = Int.MAX_VALUE } } - + private fun updateRange(treeIdx: Int, lo: Int, hi: Int, left: Int, right: Int, value: Int) { propagate(treeIdx, lo, hi) if (lo > right || hi < left) return @@ -1420,7 +1572,7 @@ class SegmentTree(private val n: Int) { updateRange(2 * treeIdx + 2, mid + 1, hi, left, right, value) tree[treeIdx] = minOf(tree[2 * treeIdx + 1], tree[2 * treeIdx + 2]) } - + private fun queryPoint(treeIdx: Int, lo: Int, hi: Int, idx: Int): Int { propagate(treeIdx, lo, hi) if (lo == hi) return tree[treeIdx] @@ -1431,11 +1583,11 @@ class SegmentTree(private val n: Int) { queryPoint(2 * treeIdx + 2, mid + 1, hi, idx) } } - + fun update(left: Int, right: Int, value: Int) { updateRange(0, 0, n - 1, left, right, value) } - + fun query(idx: Int): Int { return queryPoint(0, 0, n - 1, idx) } @@ -1449,19 +1601,19 @@ class Solution { points.add(interval[1]) } queries.forEach { points.add(it) } - + val pointsList = points.sorted() val compress = pointsList.withIndex().associate { it.value to it.index } - + val segTree = SegmentTree(pointsList.size) - + intervals.forEach { interval -> val start = compress[interval[0]]!! val end = compress[interval[1]]!! val length = interval[1] - interval[0] + 1 segTree.update(start, end, length) } - + return queries.map { q -> val idx = compress[q]!! val res = segTree.query(idx) @@ -1471,11 +1623,120 @@ class Solution { } ``` +```swift +class SegmentTree { + let n: Int + var tree: [Int] + var lazy: [Int] + let INF = Int.max + + init(_ N: Int) { + self.n = N + self.tree = [Int](repeating: INF, count: 4 * N) + self.lazy = [Int](repeating: INF, count: 4 * N) + } + + // Propagate lazy value at tree index over range [lo, hi] + func propagate(_ treeidx: Int, _ lo: Int, _ hi: Int) { + if lazy[treeidx] != INF { + tree[treeidx] = min(tree[treeidx], lazy[treeidx]) + if lo != hi { + lazy[2 * treeidx + 1] = min(lazy[2 * treeidx + 1], lazy[treeidx]) + lazy[2 * treeidx + 2] = min(lazy[2 * treeidx + 2], lazy[treeidx]) + } + lazy[treeidx] = INF + } + } + + // Update the segment tree over range [left, right] with value val + func update(_ treeidx: Int, _ lo: Int, _ hi: Int, _ left: Int, _ right: Int, _ val: Int) { + propagate(treeidx, lo, hi) + if lo > right || hi < left { + return + } + if lo >= left && hi <= right { + lazy[treeidx] = min(lazy[treeidx], val) + propagate(treeidx, lo, hi) + return + } + let mid = (lo + hi) / 2 + update(2 * treeidx + 1, lo, mid, left, right, val) + update(2 * treeidx + 2, mid + 1, hi, left, right, val) + tree[treeidx] = min(tree[2 * treeidx + 1], tree[2 * treeidx + 2]) + } + + // Query the value at index idx in the original array + func query(_ treeidx: Int, _ lo: Int, _ hi: Int, _ idx: Int) -> Int { + propagate(treeidx, lo, hi) + if lo == hi { + return tree[treeidx] + } + let mid = (lo + hi) / 2 + if idx <= mid { + return query(2 * treeidx + 1, lo, mid, idx) + } else { + return query(2 * treeidx + 2, mid + 1, hi, idx) + } + } + + func update_range(_ left: Int, _ right: Int, _ val: Int) { + update(0, 0, n - 1, left, right, val) + } + + func query_point(_ idx: Int) -> Int { + return query(0, 0, n - 1, idx) + } +} + +class Solution { + func minInterval(_ intervals: [[Int]], _ queries: [Int]) -> [Int] { + var points = [Int]() + // Create events for intervals + for interval in intervals { + points.append(interval[0]) + points.append(interval[1]) + } + // Create events for queries + for q in queries { + points.append(q) + } + + // Compress the coordinates + let sortedPoints = Array(Set(points)).sorted() + var compress = [Int: Int]() + for (i, point) in sortedPoints.enumerated() { + compress[point] = i + } + + // Lazy Segment Tree + let segTree = SegmentTree(sortedPoints.count) + + for interval in intervals { + let start = compress[interval[0]]! + let end = compress[interval[1]]! + let length = interval[1] - interval[0] + 1 + segTree.update_range(start, end, length) + } + + var ans = [Int]() + for q in queries { + let idx = compress[q]! + // Query for minSize + let res = segTree.query_point(idx) + ans.append(res == segTree.INF ? -1 : res) + } + return ans + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O((n + m)\log k)$ -* Space complexity: $O(k)$ +- Time complexity: $O((n + m)\log k)$ +- Space complexity: + - $O(k)$ extra space. + - $O(m)$ space for the output array. -> Where $m$ is the length of the array $queries$, $n$ is the length of the array $intervals$ and $k$ is the number of unique points. \ No newline at end of file +> Where $m$ is the length of the array $queries$, $n$ is the length of the array $intervals$ and $k$ is the number of unique points. diff --git a/articles/minimum-length-of-string-after-deleting-similar-ends.md b/articles/minimum-length-of-string-after-deleting-similar-ends.md new file mode 100644 index 000000000..09f9b244d --- /dev/null +++ b/articles/minimum-length-of-string-after-deleting-similar-ends.md @@ -0,0 +1,87 @@ +## 1. Greedy + Two Pointers + +::tabs-start + +```python +class Solution: + def minimumLength(self, s: str) -> int: + l, r = 0, len(s) - 1 + + while l < r and s[l] == s[r]: + tmp = s[l] + while l <= r and s[l] == tmp: + l += 1 + while l <= r and s[r] == tmp: + r -= 1 + return r - l + 1 +``` + +```java +public class Solution { + public int minimumLength(String s) { + int l = 0, r = s.length() - 1; + + while (l < r && s.charAt(l) == s.charAt(r)) { + char tmp = s.charAt(l); + while (l <= r && s.charAt(l) == tmp) { + l++; + } + while (l <= r && s.charAt(r) == tmp) { + r--; + } + } + return r - l + 1; + } +} +``` + +```cpp +class Solution { +public: + int minimumLength(string s) { + int l = 0, r = s.length() - 1; + + while (l < r && s[l] == s[r]) { + char tmp = s[l]; + while (l <= r && s[l] == tmp) { + l++; + } + while (l <= r && s[r] == tmp) { + r--; + } + } + return r - l + 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + minimumLength(s) { + let l = 0, + r = s.length - 1; + + while (l < r && s[l] === s[r]) { + const tmp = s[l]; + while (l <= r && s[l] === tmp) { + l++; + } + while (l <= r && s[r] === tmp) { + r--; + } + } + return r - l + 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/minimum-number-of-arrows-to-burst-balloons.md b/articles/minimum-number-of-arrows-to-burst-balloons.md new file mode 100644 index 000000000..729a95031 --- /dev/null +++ b/articles/minimum-number-of-arrows-to-burst-balloons.md @@ -0,0 +1,185 @@ +## 1. Greedy (Sort By Start Value) + +::tabs-start + +```python +class Solution: + def findMinArrowShots(self, points: List[List[int]]) -> int: + points.sort() + res, prevEnd = len(points), points[0][1] + + for i in range(1, len(points)): + curr = points[i] + if curr[0] <= prevEnd: + res -= 1 + prevEnd = min(curr[1], prevEnd) + else: + prevEnd = curr[1] + + return res +``` + +```java +public class Solution { + public int findMinArrowShots(int[][] points) { + Arrays.sort(points, (a, b) -> Integer.compare(a[0], b[0])); + int res = points.length, prevEnd = points[0][1]; + + for (int i = 1; i < points.length; i++) { + int[] curr = points[i]; + if (curr[0] <= prevEnd) { + res--; + prevEnd = Math.min(curr[1], prevEnd); + } else { + prevEnd = curr[1]; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int findMinArrowShots(vector>& points) { + sort(points.begin(), points.end()); + int res = points.size(), prevEnd = points[0][1]; + + for (int i = 1; i < points.size(); i++) { + vector& curr = points[i]; + if (curr[0] <= prevEnd) { + res--; + prevEnd = min(curr[1], prevEnd); + } else { + prevEnd = curr[1]; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + findMinArrowShots(points) { + points.sort((a, b) => a[0] - b[0]); + let res = points.length, + prevEnd = points[0][1]; + + for (let i = 1; i < points.length; i++) { + let curr = points[i]; + if (curr[0] <= prevEnd) { + res--; + prevEnd = Math.min(curr[1], prevEnd); + } else { + prevEnd = curr[1]; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 2. Greedy (Sort By End Value) + +::tabs-start + +```python +class Solution: + def findMinArrowShots(self, points: List[List[int]]) -> int: + points.sort(key=lambda x: x[1]) + res, prevEnd = 1, points[0][1] + + for i in range(1, len(points)): + if points[i][0] > prevEnd: + prevEnd = points[i][1] + res += 1 + + return res +``` + +```java +public class Solution { + public int findMinArrowShots(int[][] points) { + Arrays.sort(points, (a, b) -> Integer.compare(a[1], b[1])); + int res = 1, prevEnd = points[0][1]; + + for (int i = 1; i < points.length; i++) { + if (points[i][0] > prevEnd) { + prevEnd = points[i][1]; + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int findMinArrowShots(vector>& points) { + sort(points.begin(), points.end(), [](const auto& a, const auto& b) { + return a[1] < b[1]; + }); + int res = 1, prevEnd = points[0][1]; + + for (int i = 1; i < points.size(); i++) { + if (points[i][0] > prevEnd) { + prevEnd = points[i][1]; + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + findMinArrowShots(points) { + points.sort((a, b) => a[1] - b[1]); + let res = 1, + prevEnd = points[0][1]; + + for (let i = 1; i < points.length; i++) { + if (points[i][0] > prevEnd) { + prevEnd = points[i][1]; + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. diff --git a/articles/minimum-number-of-days-to-eat-n-oranges.md b/articles/minimum-number-of-days-to-eat-n-oranges.md new file mode 100644 index 000000000..7ff6b0c81 --- /dev/null +++ b/articles/minimum-number-of-days-to-eat-n-oranges.md @@ -0,0 +1,354 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def minDays(self, n: int) -> int: + dp = {} + + def dfs(n): + if n == 0: + return 0 + if n in dp: + return dp[n] + + res = 1 + dfs(n - 1) + if n % 3 == 0: + res = min(res, 1 + dfs(n // 3)) + if n % 2 == 0: + res = min(res, 1 + dfs(n // 2)) + + dp[n] = res + return res + + return dfs(n) +``` + +```java +public class Solution { + private Map dp = new HashMap<>(); + + public int minDays(int n) { + return dfs(n); + } + + private int dfs(int n) { + if (n == 0) return 0; + if (dp.containsKey(n)) return dp.get(n); + + int res = 1 + dfs(n - 1); + if (n % 3 == 0) res = Math.min(res, 1 + dfs(n / 3)); + if (n % 2 == 0) res = Math.min(res, 1 + dfs(n / 2)); + + dp.put(n, res); + return res; + } +} +``` + +```cpp +class Solution { +public: + unordered_map dp; + + int minDays(int n) { + return dfs(n); + } + + int dfs(int n) { + if (n == 0) return 0; + if (dp.count(n)) return dp[n]; + + int res = 1 + dfs(n - 1); + if (n % 3 == 0) res = min(res, 1 + dfs(n / 3)); + if (n % 2 == 0) res = min(res, 1 + dfs(n / 2)); + + return dp[n] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + minDays(n) { + const dp = new Map(); + + const dfs = (n) => { + if (n === 0) return 0; + if (dp.has(n)) return dp.get(n); + + let res = 1 + dfs(n - 1); + if (n % 3 === 0) res = Math.min(res, 1 + dfs(n / 3)); + if (n % 2 === 0) res = Math.min(res, 1 + dfs(n / 2)); + + dp.set(n, res); + return res; + }; + + return dfs(n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Greedy + Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def minDays(self, n: int) -> int: + dp = {0: 0, 1: 1} + + def dfs(n): + if n in dp: + return dp[n] + + res = 1 + (n % 2) + dfs(n // 2) + res = min(res, 1 + (n % 3) + dfs(n // 3)) + dp[n] = res + return res + + return dfs(n) +``` + +```java +public class Solution { + private Map dp = new HashMap<>(); + + public int minDays(int n) { + dp.put(0, 0); + dp.put(1, 1); + return dfs(n); + } + + private int dfs(int n) { + if (dp.containsKey(n)) return dp.get(n); + + int res = 1 + (n % 2) + dfs(n / 2); + res = Math.min(res, 1 + (n % 3) + dfs(n / 3)); + + dp.put(n, res); + return res; + } +} +``` + +```cpp +class Solution { +public: + unordered_map dp; + + int minDays(int n) { + dp[0] = 0; + dp[1] = 1; + return dfs(n); + } + +private: + int dfs(int n) { + if (dp.count(n)) return dp[n]; + + int res = 1 + (n % 2) + dfs(n / 2); + res = min(res, 1 + (n % 3) + dfs(n / 3)); + + return dp[n] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + minDays(n) { + const dp = new Map(); + dp.set(0, 0); + dp.set(1, 1); + + const dfs = (n) => { + if (dp.has(n)) return dp.get(n); + + let res = 1 + (n % 2) + dfs(Math.floor(n / 2)); + res = Math.min(res, 1 + (n % 3) + dfs(Math.floor(n / 3))); + + dp.set(n, res); + return res; + }; + + return dfs(n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(\log n)$ + +--- + +## 3. Breadth First Search + +::tabs-start + +```python +class Solution: + def minDays(self, n: int) -> int: + q = deque([n]) + visit = set() + res = 0 + + while q: + res += 1 + for _ in range(len(q)): + node = q.popleft() + nei = node - 1 + if nei == 0: + return res + if nei not in visit: + visit.add(nei) + q.append(nei) + for d in range(2, 4): + if node % d == 0: + nei = node // d + if nei == 0: + return res + if nei not in visit: + visit.add(nei) + q.append(nei) + return res +``` + +```java +public class Solution { + public int minDays(int n) { + Queue q = new LinkedList<>(); + Set visit = new HashSet<>(); + q.offer(n); + int res = 0; + + while (!q.isEmpty()) { + res++; + for (int i = q.size(); i > 0; i--) { + int node = q.poll(); + int nei = node - 1; + if (nei == 0) return res; + if (!visit.contains(nei)) { + visit.add(nei); + q.offer(nei); + } + for (int d = 2; d <= 3; d++) { + if (node % d == 0) { + nei = node / d; + if (nei == 0) return res; + if (!visit.contains(nei)) { + visit.add(nei); + q.offer(nei); + } + } + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minDays(int n) { + queue q; + unordered_set visit; + q.push(n); + int res = 0; + + while (!q.empty()) { + res++; + for (int i = q.size(); i > 0; i--) { + int node = q.front(); q.pop(); + int nei = node - 1; + if (nei == 0) return res; + if (visit.find(nei) == visit.end()) { + visit.insert(nei); + q.push(nei); + } + for (int d = 2; d <= 3; d++) { + if (node % d == 0) { + nei = node / d; + if (nei == 0) return res; + if (visit.find(nei) == visit.end()) { + visit.insert(nei); + q.push(nei); + } + } + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + minDays(n) { + const q = new Queue([n]); + const visit = new Set(); + let res = 0; + + while (!q.isEmpty()) { + res++; + for (let i = q.size(); i > 0; i--) { + let node = q.pop(); + let nei = node - 1; + if (nei === 0) return res; + if (!visit.has(nei)) { + visit.add(nei); + q.push(nei); + } + for (let d = 2; d <= 3; d++) { + if (node % d === 0) { + nei = Math.floor(node / d); + if (nei === 0) return res; + if (!visit.has(nei)) { + visit.add(nei); + q.push(nei); + } + } + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(\log n)$ diff --git a/articles/minimum-number-of-flips-to-make-the-binary-string-alternating.md b/articles/minimum-number-of-flips-to-make-the-binary-string-alternating.md index b0afa6412..03398e5ad 100644 --- a/articles/minimum-number-of-flips-to-make-the-binary-string-alternating.md +++ b/articles/minimum-number-of-flips-to-make-the-binary-string-alternating.md @@ -16,7 +16,7 @@ class Solution: for i in range(n): cnt += 1 if (A[i] != B[i]) else 0 return cnt - + for i in range(n): newS = s[i:] + s[:i] res = min(res, min(diff(alt1, newS), diff(alt2, newS))) @@ -93,7 +93,8 @@ class Solution { minFlips(s) { const n = s.length; let res = n; - let alt1 = "", alt2 = ""; + let alt1 = '', + alt2 = ''; for (let i = 0; i < n; i++) { alt1 += i % 2 === 0 ? '0' : '1'; @@ -122,8 +123,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -146,7 +147,7 @@ class Solution: start_0 += 1 if s[j] == c else 0 c = '0' if c == '1' else '1' j = (j + 1) % n - + res = min(res, min(start_1, start_0)) return res ``` @@ -240,8 +241,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. --- @@ -360,14 +361,18 @@ class Solution { minFlips(s) { const n = s.length; s = s + s; - let alt1 = [], alt2 = []; + let alt1 = [], + alt2 = []; for (let i = 0; i < s.length; i++) { - alt1.push(i % 2 === 0 ? "0" : "1"); - alt2.push(i % 2 === 0 ? "1" : "0"); + alt1.push(i % 2 === 0 ? '0' : '1'); + alt2.push(i % 2 === 0 ? '1' : '0'); } - let res = n, diff1 = 0, diff2 = 0, l = 0; + let res = n, + diff1 = 0, + diff2 = 0, + l = 0; for (let r = 0; r < s.length; r++) { if (s[r] !== alt1[r]) diff1++; @@ -393,8 +398,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -423,12 +428,12 @@ class Solution: diff2 -= 1 l += 1 lstart_0 = '1' if lstart_0 == '0' else '0' - + if r - l + 1 == n: res = min(res, diff1, diff2) rstart_0 = '1' if rstart_0 == '0' else '0' - + return res ``` @@ -503,9 +508,13 @@ class Solution { */ minFlips(s) { const n = s.length; - let res = n, diff1 = 0, diff2 = 0, l = 0; + let res = n, + diff1 = 0, + diff2 = 0, + l = 0; - let rstart_0 = '0', lstart_0 = '0'; + let rstart_0 = '0', + lstart_0 = '0'; for (let r = 0; r < 2 * n; r++) { if (s[r % n] !== rstart_0) diff1++; @@ -534,8 +543,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -675,7 +684,8 @@ class Solution { return ans; } - let dp0 = start_0, dp1 = start_1; + let dp0 = start_0, + dp1 = start_1; for (const c of s) { [dp0, dp1] = [dp1, dp0]; if (c === '1') { @@ -697,5 +707,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/minimum-number-of-increments-on-subarrays-to-form-a-target-array.md b/articles/minimum-number-of-increments-on-subarrays-to-form-a-target-array.md new file mode 100644 index 000000000..2fb5136f9 --- /dev/null +++ b/articles/minimum-number-of-increments-on-subarrays-to-form-a-target-array.md @@ -0,0 +1,559 @@ +## 1. Simulation + +::tabs-start + +```python +class Solution: + def minNumberOperations(self, target: List[int]) -> int: + def rec(l, r, h): + if l > r: + return 0 + + minIdx = l + for i in range(l + 1, r + 1): + if target[i] < target[minIdx]: + minIdx = i + + res = target[minIdx] - h + return res + rec(l, minIdx - 1, target[minIdx]) + rec(minIdx + 1, r, target[minIdx]) + + return rec(0, len(target) - 1, 0) +``` + +```java +public class Solution { + public int minNumberOperations(int[] target) { + return rec(target, 0, target.length - 1, 0); + } + + private int rec(int[] target, int l, int r, int h) { + if (l > r) return 0; + + int minIdx = l; + for (int i = l + 1; i <= r; i++) { + if (target[i] < target[minIdx]) { + minIdx = i; + } + } + + int res = target[minIdx] - h; + res += rec(target, l, minIdx - 1, target[minIdx]); + res += rec(target, minIdx + 1, r, target[minIdx]); + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minNumberOperations(vector& target) { + return rec(target, 0, target.size() - 1, 0); + } + +private: + int rec(vector& target, int l, int r, int h) { + if (l > r) return 0; + + int minIdx = l; + for (int i = l + 1; i <= r; i++) { + if (target[i] < target[minIdx]) { + minIdx = i; + } + } + + int res = target[minIdx] - h; + res += rec(target, l, minIdx - 1, target[minIdx]); + res += rec(target, minIdx + 1, r, target[minIdx]); + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} target + * @return {number} + */ + minNumberOperations(target) { + const rec = (l, r, h) => { + if (l > r) return 0; + + let minIdx = l; + for (let i = l + 1; i <= r; i++) { + if (target[i] < target[minIdx]) { + minIdx = i; + } + } + + let res = target[minIdx] - h; + res += rec(l, minIdx - 1, target[minIdx]); + res += rec(minIdx + 1, r, target[minIdx]); + + return res; + }; + + return rec(0, target.length - 1, 0); + } +} +``` + +```csharp +public class Solution { + public int MinNumberOperations(int[] target) { + return Rec(target, 0, target.Length - 1, 0); + } + + private int Rec(int[] target, int l, int r, int h) { + if (l > r) return 0; + + int minIdx = l; + for (int i = l + 1; i <= r; i++) { + if (target[i] < target[minIdx]) { + minIdx = i; + } + } + + int res = target[minIdx] - h; + res += Rec(target, l, minIdx - 1, target[minIdx]); + res += Rec(target, minIdx + 1, r, target[minIdx]); + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Segment Tree + +::tabs-start + +```python +INF = float('inf') + +class SegmentTree: + def __init__(self, A): + self.A = A[:] + self.n = len(A) + while (self.n & (self.n - 1)) != 0: + self.A.append(INF) + self.n += 1 + + self.tree = [0] * (2 * self.n) + self.build() + + def build(self): + for i in range(self.n): + self.tree[self.n + i] = i + for j in range(self.n - 1, 0, -1): + a = self.tree[j << 1] + b = self.tree[(j << 1) | 1] + self.tree[j] = a if self.A[a] <= self.A[b] else b + + def update(self, i, val): + self.A[i] = val + j = (self.n + i) >> 1 + while j >= 1: + a = self.tree[j << 1] + b = self.tree[(j << 1) | 1] + self.tree[j] = a if self.A[a] <= self.A[b] else b + j >>= 1 + + def query(self, ql, qh): + return self._query(1, 0, self.n - 1, ql, qh) + + def _query(self, node, l, h, ql, qh): + if ql > h or qh < l: + return -1 + if l >= ql and h <= qh: + return self.tree[node] + mid = (l + h) >> 1 + a = self._query(node << 1, l, mid, ql, qh) + b = self._query((node << 1) | 1, mid + 1, h, ql, qh) + + if a == -1: return b + if b == -1: return a + return a if self.A[a] <= self.A[b] else b + +class Solution: + def minNumberOperations(self, target: List[int]) -> int: + seg = SegmentTree(target) + stack = [(0, len(target) - 1, 0)] + res = 0 + + while stack: + l, r, h = stack.pop() + if l > r: + continue + minIdx = seg.query(l, r) + res += target[minIdx] - h + stack.append((l, minIdx - 1, target[minIdx])) + stack.append((minIdx + 1, r, target[minIdx])) + + return res +``` + +```java +class SegmentTree { + int[] A; + int[] tree; + int n; + final int INF = Integer.MAX_VALUE; + + SegmentTree(int[] arr) { + int len = arr.length; + int pow2 = 1; + while (pow2 < len) pow2 <<= 1; + n = pow2; + + A = new int[n]; + System.arraycopy(arr, 0, A, 0, arr.length); + for (int i = arr.length; i < n; i++) A[i] = INF; + + tree = new int[2 * n]; + build(); + } + + void build() { + for (int i = 0; i < n; i++) { + tree[n + i] = i; + } + for (int i = n - 1; i > 0; i--) { + int a = tree[i << 1], b = tree[(i << 1) | 1]; + tree[i] = A[a] <= A[b] ? a : b; + } + } + + int query(int ql, int qh) { + return _query(1, 0, n - 1, ql, qh); + } + + int _query(int node, int l, int h, int ql, int qh) { + if (ql > h || qh < l) return -1; + if (ql <= l && h <= qh) return tree[node]; + int mid = (l + h) >> 1; + int left = _query(node << 1, l, mid, ql, qh); + int right = _query((node << 1) | 1, mid + 1, h, ql, qh); + if (left == -1) return right; + if (right == -1) return left; + return A[left] <= A[right] ? left : right; + } +} + +public class Solution { + public int minNumberOperations(int[] target) { + SegmentTree seg = new SegmentTree(target); + return rec(0, target.length - 1, 0, target, seg); + } + + private int rec(int l, int r, int h, int[] target, SegmentTree seg) { + if (l > r) return 0; + int minIdx = seg.query(l, r); + int res = target[minIdx] - h; + res += rec(l, minIdx - 1, target[minIdx], target, seg); + res += rec(minIdx + 1, r, target[minIdx], target, seg); + return res; + } +} +``` + +```cpp +class SegmentTree { +public: + int n; + vector A, tree; + const int INF = INT_MAX; + + SegmentTree(vector& arr) { + A = arr; + n = arr.size(); + while (__builtin_popcount(n) != 1) { + A.push_back(INF); + n++; + } + tree.resize(2 * n); + build(); + } + + void build() { + for (int i = 0; i < n; ++i) { + tree[n + i] = i; + } + for (int j = n - 1; j >= 1; --j) { + int a = tree[j << 1], b = tree[(j << 1) | 1]; + tree[j] = A[a] <= A[b] ? a : b; + } + } + + int query(int ql, int qh) { + return _query(1, 0, n - 1, ql, qh); + } + + int _query(int node, int l, int h, int ql, int qh) { + if (ql > h || qh < l) return -1; + if (l >= ql && h <= qh) return tree[node]; + int mid = (l + h) >> 1; + int a = _query(node << 1, l, mid, ql, qh); + int b = _query((node << 1) | 1, mid + 1, h, ql, qh); + if (a == -1) return b; + if (b == -1) return a; + return A[a] <= A[b] ? a : b; + } +}; + +class Solution { +public: + int minNumberOperations(vector& target) { + SegmentTree seg(target); + return rec(0, target.size() - 1, 0, target, seg); + } + + int rec(int l, int r, int h, vector& target, SegmentTree& seg) { + if (l > r) return 0; + int minIdx = seg.query(l, r); + int res = target[minIdx] - h; + res += rec(l, minIdx - 1, target[minIdx], target, seg); + res += rec(minIdx + 1, r, target[minIdx], target, seg); + return res; + } +}; +``` + +```javascript +class SegmentTree { + constructor(A) { + this.A = [...A]; + this.n = A.length; + this.INF = Number.POSITIVE_INFINITY; + + while ((this.n & (this.n - 1)) !== 0) { + this.A.push(this.INF); + this.n++; + } + + this.tree = Array(2 * this.n).fill(0); + this.build(); + } + + build() { + for (let i = 0; i < this.n; i++) { + this.tree[this.n + i] = i; + } + for (let j = this.n - 1; j >= 1; j--) { + let a = this.tree[j << 1]; + let b = this.tree[(j << 1) | 1]; + this.tree[j] = this.A[a] <= this.A[b] ? a : b; + } + } + + update(i, val) { + this.A[i] = val; + let j = (this.n + i) >> 1; + while (j >= 1) { + let a = this.tree[j << 1]; + let b = this.tree[(j << 1) | 1]; + this.tree[j] = this.A[a] <= this.A[b] ? a : b; + j >>= 1; + } + } + + query(ql, qh) { + return this._query(1, 0, this.n - 1, ql, qh); + } + + _query(node, l, h, ql, qh) { + if (ql > h || qh < l) return -1; + if (l >= ql && h <= qh) return this.tree[node]; + + let mid = (l + h) >> 1; + let a = this._query(node << 1, l, mid, ql, qh); + let b = this._query((node << 1) | 1, mid + 1, h, ql, qh); + + if (a === -1) return b; + if (b === -1) return a; + return this.A[a] <= this.A[b] ? a : b; + } +} + +class Solution { + /** + * @param {number[]} target + * @return {number} + */ + minNumberOperations(target) { + const seg = new SegmentTree(target); + + const rec = (l, r, h) => { + if (l > r) return 0; + + const minIdx = seg.query(l, r); + let res = target[minIdx] - h; + res += rec(l, minIdx - 1, target[minIdx]); + res += rec(minIdx + 1, r, target[minIdx]); + return res; + }; + + return rec(0, target.length - 1, 0); + } +} +``` + +```csharp +public class SegmentTree { + private int[] A; + private int[] tree; + private int n; + private const int INF = int.MaxValue; + + public SegmentTree(int[] arr) { + int len = arr.Length; + int pow2 = 1; + while (pow2 < len) pow2 <<= 1; + n = pow2; + + A = new int[n]; + Array.Copy(arr, A, arr.Length); + for (int i = arr.Length; i < n; i++) A[i] = INF; + + tree = new int[2 * n]; + Build(); + } + + private void Build() { + for (int i = 0; i < n; i++) { + tree[n + i] = i; + } + for (int i = n - 1; i > 0; i--) { + int a = tree[i << 1]; + int b = tree[(i << 1) | 1]; + tree[i] = A[a] <= A[b] ? a : b; + } + } + + public int Query(int ql, int qh) { + return Query(1, 0, n - 1, ql, qh); + } + + private int Query(int node, int l, int h, int ql, int qh) { + if (ql > h || qh < l) return -1; + if (ql <= l && h <= qh) return tree[node]; + + int mid = (l + h) >> 1; + int left = Query(node << 1, l, mid, ql, qh); + int right = Query((node << 1) | 1, mid + 1, h, ql, qh); + + if (left == -1) return right; + if (right == -1) return left; + return A[left] <= A[right] ? left : right; + } +} + +public class Solution { + public int MinNumberOperations(int[] target) { + var seg = new SegmentTree(target); + return Rec(0, target.Length - 1, 0, target, seg); + } + + private int Rec(int l, int r, int h, int[] target, SegmentTree seg) { + if (l > r) return 0; + int minIdx = seg.Query(l, r); + int res = target[minIdx] - h; + res += Rec(l, minIdx - 1, target[minIdx], target, seg); + res += Rec(minIdx + 1, r, target[minIdx], target, seg); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Greedy + +::tabs-start + +```python +class Solution: + def minNumberOperations(self, target: List[int]) -> int: + res = target[0] + for i in range(1, len(target)): + res += max(target[i] - target[i - 1], 0) + return res +``` + +```java +public class Solution { + public int minNumberOperations(int[] target) { + int res = target[0]; + for (int i = 1; i < target.length; i++) { + res += Math.max(target[i] - target[i - 1], 0); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minNumberOperations(vector& target) { + int res = target[0]; + for (int i = 1; i < target.size(); i++) { + res += max(target[i] - target[i - 1], 0); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} target + * @return {number} + */ + minNumberOperations(target) { + let res = target[0]; + for (let i = 1; i < target.length; i++) { + res += Math.max(target[i] - target[i - 1], 0); + } + return res; + } +} +``` + +```csharp +public class Solution { + public int MinNumberOperations(int[] target) { + int res = target[0]; + for (int i = 1; i < target.Length; i++) { + res += Math.Max(target[i] - target[i - 1], 0); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/minimum-number-of-moves-to-seat-everyone.md b/articles/minimum-number-of-moves-to-seat-everyone.md new file mode 100644 index 000000000..e2ed02e82 --- /dev/null +++ b/articles/minimum-number-of-moves-to-seat-everyone.md @@ -0,0 +1,403 @@ +## 1. Greedy + Sorting + +::tabs-start + +```python + +``` + +```java + +``` + +```cpp + +``` + +```javascript +class Solution { + /** + * @param {number[]} seats + * @param {number[]} students + * @return {number} + */ + minMovesToSeat(seats, students) { + + } +} +``` + +```csharp + +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n \log n)$ +* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 2. Counting Sort + +::tabs-start + +```python +class Solution: + def minMovesToSeat(self, seats: List[int], students: List[int]) -> int: + max_index = max(max(seats), max(students)) + 1 + count_seats = [0] * max_index + count_students = [0] * max_index + + for seat in seats: + count_seats[seat] += 1 + for student in students: + count_students[student] += 1 + + i = j = res = 0 + remain = len(seats) + while remain: + if count_seats[i] == 0: + i += 1 + if count_students[j] == 0: + j += 1 + if count_seats[i] and count_students[j]: + res += abs(i - j) + count_seats[i] -= 1 + count_students[j] -= 1 + remain -= 1 + return res +``` + +```java +public class Solution { + public int minMovesToSeat(int[] seats, int[] students) { + int max_index = 0; + for (int s : seats) max_index = Math.max(max_index, s); + for (int s : students) max_index = Math.max(max_index, s); + max_index++; + + int[] count_seats = new int[max_index]; + int[] count_students = new int[max_index]; + + for (int seat : seats) count_seats[seat]++; + for (int student : students) count_students[student]++; + + int i = 0, j = 0, res = 0, remain = seats.length; + while (remain > 0) { + if (count_seats[i] == 0) { + i++; + continue; + } + if (count_students[j] == 0) { + j++; + continue; + } + res += Math.abs(i - j); + count_seats[i]--; + count_students[j]--; + remain--; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minMovesToSeat(vector& seats, vector& students) { + int max_index = 0; + for (int s : seats) max_index = max(max_index, s); + for (int s : students) max_index = max(max_index, s); + max_index++; + + vector count_seats(max_index, 0); + vector count_students(max_index, 0); + + for (int seat : seats) count_seats[seat]++; + for (int student : students) count_students[student]++; + + int i = 0, j = 0, res = 0, remain = seats.size(); + while (remain > 0) { + if (count_seats[i] == 0) { + i++; + continue; + } + if (count_students[j] == 0) { + j++; + continue; + } + res += abs(i - j); + count_seats[i]--; + count_students[j]--; + remain--; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} seats + * @param {number[]} students + * @return {number} + */ + minMovesToSeat(seats, students) { + let max_index = Math.max(...seats, ...students) + 1; + let count_seats = new Array(max_index).fill(0); + let count_students = new Array(max_index).fill(0); + + for (let seat of seats) count_seats[seat]++; + for (let student of students) count_students[student]++; + + let i = 0, j = 0, res = 0, remain = seats.length; + while (remain > 0) { + if (count_seats[i] === 0) { + i++; + continue; + } + if (count_students[j] === 0) { + j++; + continue; + } + res += Math.abs(i - j); + count_seats[i]--; + count_students[j]--; + remain--; + } + return res; + } +} +``` + +```csharp +public class Solution { + public int MinMovesToSeat(int[] seats, int[] students) { + int max_index = 0; + foreach (int s in seats) max_index = Math.Max(max_index, s); + foreach (int s in students) max_index = Math.Max(max_index, s); + max_index++; + + int[] count_seats = new int[max_index]; + int[] count_students = new int[max_index]; + + foreach (int seat in seats) count_seats[seat]++; + foreach (int student in students) count_students[student]++; + + int i = 0, j = 0, res = 0, remain = seats.Length; + while (remain > 0) { + if (count_seats[i] == 0) { + i++; + continue; + } + if (count_students[j] == 0) { + j++; + continue; + } + res += Math.Abs(i - j); + count_seats[i]--; + count_students[j]--; + remain--; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m1 + m2)$ +* Space complexity: $O(m1 + m2)$ + +> Where $n$ is the size of the input arrays, $m1$ is the maximum value in the array $seats$, and $m2$ is the maximum value in the array $students$. + +--- + +## 3. Counting Sort (Optimal) + +::tabs-start + +```python +class Solution: + def minMovesToSeat(self, seats: List[int], students: List[int]) -> int: + count_seats = [0] * (max(seats) + 1) + count_students = [0] * (max(students) + 1) + + def count_sort(arr, count): + for num in arr: + count[num] += 1 + + count_sort(seats, count_seats) + count_sort(students, count_students) + + remain = len(seats) + i = j = res = 0 + while remain: + if count_seats[i] == 0: + i += 1 + if count_students[j] == 0: + j += 1 + if count_seats[i] and count_students[j]: + tmp = min(count_seats[i], count_students[j]) + res += abs(i - j) * tmp + count_seats[i] -= tmp + count_students[j] -= tmp + remain -= tmp + return res +``` + +```java +public class Solution { + public int minMovesToSeat(int[] seats, int[] students) { + int maxSeat = 0, maxStudent = 0; + for (int s : seats) maxSeat = Math.max(maxSeat, s); + for (int s : students) maxStudent = Math.max(maxStudent, s); + + int[] count_seats = new int[maxSeat + 1]; + int[] count_students = new int[maxStudent + 1]; + + for (int s : seats) count_seats[s]++; + for (int s : students) count_students[s]++; + + int remain = seats.length, i = 0, j = 0, res = 0; + while (remain > 0) { + if (count_seats[i] == 0) { + i++; + continue; + } + if (count_students[j] == 0) { + j++; + continue; + } + int tmp = Math.min(count_seats[i], count_students[j]); + res += Math.abs(i - j) * tmp; + count_seats[i] -= tmp; + count_students[j] -= tmp; + remain -= tmp; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minMovesToSeat(vector& seats, vector& students) { + int maxSeat = *max_element(seats.begin(), seats.end()); + int maxStudent = *max_element(students.begin(), students.end()); + + vector count_seats(maxSeat + 1, 0); + vector count_students(maxStudent + 1, 0); + + for (int s : seats) count_seats[s]++; + for (int s : students) count_students[s]++; + + int remain = seats.size(), i = 0, j = 0, res = 0; + while (remain > 0) { + if (count_seats[i] == 0) { + i++; + continue; + } + if (count_students[j] == 0) { + j++; + continue; + } + int tmp = min(count_seats[i], count_students[j]); + res += abs(i - j) * tmp; + count_seats[i] -= tmp; + count_students[j] -= tmp; + remain -= tmp; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} seats + * @param {number[]} students + * @return {number} + */ + minMovesToSeat(seats, students) { + let maxSeat = Math.max(...seats); + let maxStudent = Math.max(...students); + + let count_seats = new Array(maxSeat + 1).fill(0); + let count_students = new Array(maxStudent + 1).fill(0); + + for (let s of seats) count_seats[s]++; + for (let s of students) count_students[s]++; + + let remain = seats.length, i = 0, j = 0, res = 0; + while (remain > 0) { + if (count_seats[i] === 0) { + i++; + continue; + } + if (count_students[j] === 0) { + j++; + continue; + } + let tmp = Math.min(count_seats[i], count_students[j]); + res += Math.abs(i - j) * tmp; + count_seats[i] -= tmp; + count_students[j] -= tmp; + remain -= tmp; + } + return res; + } +} +``` + +```csharp +public class Solution { + public int MinMovesToSeat(int[] seats, int[] students) { + int maxSeat = 0, maxStudent = 0; + foreach (int s in seats) maxSeat = Math.Max(maxSeat, s); + foreach (int s in students) maxStudent = Math.Max(maxStudent, s); + + int[] count_seats = new int[maxSeat + 1]; + int[] count_students = new int[maxStudent + 1]; + + foreach (int s in seats) count_seats[s]++; + foreach (int s in students) count_students[s]++; + + int remain = seats.Length, i = 0, j = 0, res = 0; + while (remain > 0) { + if (count_seats[i] == 0) { + i++; + continue; + } + if (count_students[j] == 0) { + j++; + continue; + } + int tmp = Math.Min(count_seats[i], count_students[j]); + res += Math.Abs(i - j) * tmp; + count_seats[i] -= tmp; + count_students[j] -= tmp; + remain -= tmp; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n + m1 + m2)$ +* Space complexity: $O(m1 + m2)$ + +> Where $n$ is the size of the input arrays, $m1$ is the maximum value in the array $seats$, and $m2$ is the maximum value in the array $students$. \ No newline at end of file diff --git a/articles/minimum-number-of-operations-to-make-array-continuous.md b/articles/minimum-number-of-operations-to-make-array-continuous.md new file mode 100644 index 000000000..bfdf2e87d --- /dev/null +++ b/articles/minimum-number-of-operations-to-make-array-continuous.md @@ -0,0 +1,454 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def minOperations(self, nums: List[int]) -> int: + N = len(nums) + res = float("inf") + nums = sorted(set(nums)) + n = len(nums) + + for i in range(n): + noChange = 1 + for j in range(i + 1, n): + if nums[i] < nums[j] < nums[i] + N: + noChange += 1 + res = min(res, N - noChange) + + return res +``` + +```java +public class Solution { + public int minOperations(int[] nums) { + int N = nums.length; + int res = Integer.MAX_VALUE; + TreeSet set = new TreeSet<>(); + for (int num : nums) { + set.add(num); + } + Integer[] sortedNums = set.toArray(new Integer[0]); + int n = sortedNums.length; + + for (int i = 0; i < n; i++) { + int noChange = 1; + for (int j = i + 1; j < n; j++) { + if (sortedNums[j] < sortedNums[i] + N) { + noChange++; + } + } + res = Math.min(res, N - noChange); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minOperations(vector& nums) { + int N = nums.size(); + int res = INT_MAX; + set uniqueNums(nums.begin(), nums.end()); + vector sortedNums(uniqueNums.begin(), uniqueNums.end()); + int n = sortedNums.size(); + + for (int i = 0; i < n; i++) { + int noChange = 1; + for (int j = i + 1; j < n; j++) { + if (sortedNums[j] < sortedNums[i] + N) { + noChange++; + } + } + res = min(res, N - noChange); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minOperations(nums) { + const N = nums.length; + let res = Infinity; + const uniqueNums = Array.from(new Set(nums)).sort((a, b) => a - b); + const n = uniqueNums.length; + + for (let i = 0; i < n; i++) { + let noChange = 1; + for (let j = i + 1; j < n; j++) { + if (uniqueNums[j] < uniqueNums[i] + N) { + noChange++; + } + } + res = Math.min(res, N - noChange); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 2. Binary Search + +::tabs-start + +```python +class Solution: + def minOperations(self, nums: List[int]) -> int: + N = len(nums) + res = float("inf") + nums = sorted(set(nums)) + n = len(nums) + + for i in range(n): + l, r = i, n + while l < r: + mid = (l + r) // 2 + if nums[mid] < nums[i] + N: + l = mid + 1 + else: + r = mid + noChange = l - i + res = min(res, N - noChange) + + return res +``` + +```java +public class Solution { + public int minOperations(int[] nums) { + int N = nums.length; + int res = Integer.MAX_VALUE; + TreeSet set = new TreeSet<>(); + for (int num : nums) { + set.add(num); + } + Integer[] sortedNums = set.toArray(new Integer[0]); + int n = sortedNums.length; + + for (int i = 0; i < n; i++) { + int l = i, r = n; + while (l < r) { + int mid = l + (r - l) / 2; + if (sortedNums[mid] < sortedNums[i] + N) { + l = mid + 1; + } else { + r = mid; + } + } + int noChange = l - i; + res = Math.min(res, N - noChange); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minOperations(vector& nums) { + int N = nums.size(); + int res = INT_MAX; + set uniqueNums(nums.begin(), nums.end()); + vector sortedNums(uniqueNums.begin(), uniqueNums.end()); + int n = sortedNums.size(); + + for (int i = 0; i < n; i++) { + int l = i, r = n; + while (l < r) { + int mid = l + (r - l) / 2; + if (sortedNums[mid] < sortedNums[i] + N) { + l = mid + 1; + } else { + r = mid; + } + } + int noChange = l - i; + res = min(res, N - noChange); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minOperations(nums) { + const N = nums.length; + let res = Infinity; + const uniqueNums = Array.from(new Set(nums)).sort((a, b) => a - b); + const n = uniqueNums.length; + + for (let i = 0; i < n; i++) { + let l = i, + r = n; + while (l < r) { + const mid = Math.floor((l + r) / 2); + if (uniqueNums[mid] < uniqueNums[i] + N) { + l = mid + 1; + } else { + r = mid; + } + } + const noChange = l - i; + res = Math.min(res, N - noChange); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Sliding Window + +::tabs-start + +```python +class Solution: + def minOperations(self, nums: List[int]) -> int: + length = len(nums) + nums = sorted(set(nums)) + res = length + r = 0 + + for l in range(len(nums)): + while r < len(nums) and nums[r] < nums[l] + length: + r += 1 + window = r - l + res = min(res, length - window) + + return res +``` + +```java +public class Solution { + public int minOperations(int[] nums) { + int length = nums.length; + TreeSet set = new TreeSet<>(); + for (int num : nums) { + set.add(num); + } + List sortedNums = new ArrayList<>(set); + int res = length, r = 0; + + for (int l = 0; l < sortedNums.size(); l++) { + while (r < sortedNums.size() && sortedNums.get(r) < sortedNums.get(l) + length) { + r++; + } + int window = r - l; + res = Math.min(res, length - window); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minOperations(vector& nums) { + int length = nums.size(); + set uniqueNums(nums.begin(), nums.end()); + vector sortedNums(uniqueNums.begin(), uniqueNums.end()); + int res = length, r = 0; + + for (int l = 0; l < sortedNums.size(); l++) { + while (r < sortedNums.size() && sortedNums[r] < sortedNums[l] + length) { + r++; + } + int window = r - l; + res = min(res, length - window); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minOperations(nums) { + const length = nums.length; + const uniqueNums = Array.from(new Set(nums)).sort((a, b) => a - b); + let res = length, + r = 0; + + for (let l = 0; l < uniqueNums.length; l++) { + while ( + r < uniqueNums.length && + uniqueNums[r] < uniqueNums[l] + length + ) { + r++; + } + const window = r - l; + res = Math.min(res, length - window); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Sliding Window (Optimal) + +::tabs-start + +```python +class Solution: + def minOperations(self, nums: List[int]) -> int: + length = len(nums) + nums.sort() + res = length + n = 1 + + for i in range(1, length): + if nums[i] != nums[i - 1]: + nums[n] = nums[i] + n += 1 + + l = 0 + for r in range(n): + l += (nums[r] - nums[l] > length - 1) + + return length - (n - l) +``` + +```java +public class Solution { + public int minOperations(int[] nums) { + int length = nums.length; + Arrays.sort(nums); + int n = 1; + + for (int i = 1; i < length; i++) { + if (nums[i] != nums[i - 1]) { + nums[n] = nums[i]; + n++; + } + } + + int l = 0; + for (int r = 0; r < n; r++) { + if (nums[r] - nums[l] > length - 1) { + l++; + } + } + + return length - (n - l); + } +} +``` + +```cpp +class Solution { +public: + int minOperations(vector& nums) { + int length = nums.size(); + sort(nums.begin(), nums.end()); + int n = 1; + + for (int i = 1; i < length; i++) { + if (nums[i] != nums[i - 1]) { + nums[n] = nums[i]; + n++; + } + } + + int l = 0; + for (int r = 0; r < n; r++) { + if (nums[r] - nums[l] > length - 1) { + l++; + } + } + + return length - (n - l); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + minOperations(nums) { + const length = nums.length; + nums.sort((a, b) => a - b); + let n = 1; + + for (let i = 1; i < length; i++) { + if (nums[i] !== nums[i - 1]) { + nums[n] = nums[i]; + n++; + } + } + + let l = 0; + for (let r = 0; r < n; r++) { + if (nums[r] - nums[l] > length - 1) { + l++; + } + } + + return length - (n - l); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. diff --git a/articles/minimum-number-of-operations-to-make-array-empty.md b/articles/minimum-number-of-operations-to-make-array-empty.md index fbb2aa367..f0cd1394b 100644 --- a/articles/minimum-number-of-operations-to-make-array-empty.md +++ b/articles/minimum-number-of-operations-to-make-array-empty.md @@ -10,10 +10,10 @@ class Solution: return float('inf') if cur == 0: return 0 - + ops = min(dfs(cur - 2), dfs(cur - 3)) return 1 + ops - + count = Counter(nums) res = 0 for num, cnt in count.items(): @@ -21,7 +21,7 @@ class Solution: if op == float("inf"): return -1 res += op - + return res ``` @@ -137,8 +137,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n * 2 ^ m)$ +- Space complexity: $O(n + m)$ > Where $n$ is the size of the array $nums$ and $m$ is the average frequency of the array elements. @@ -160,7 +160,7 @@ class Solution: return 1 if num in cache: return cache[num] - + res = min(dfs(num - 2), dfs(num - 3)) cache[num] = res + 1 return cache[num] @@ -172,14 +172,14 @@ class Solution: if op == float("inf"): return -1 res += op - + return res ``` ```java public class Solution { private Map cache; - + public int minOperations(int[] nums) { Map count = new HashMap<>(); for (int num : nums) { @@ -281,7 +281,7 @@ class Solution { cache.set(cur, isFinite(res) ? 1 + res : res); return cache.get(cur); }; - + const count = new Map(); for (const num of nums) { count.set(num, (count.get(num) || 0) + 1); @@ -305,8 +305,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ > Where $n$ is the size of the array $nums$ and $m$ is the average frequency of the array elements. @@ -462,8 +462,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ > Where $n$ is the size of the array $nums$ and $m$ is the average frequency of the array elements. @@ -478,12 +478,12 @@ class Solution: def minOperations(self, nums: List[int]) -> int: count = Counter(nums) res = 0 - + for num, cnt in count.items(): if cnt == 1: return -1 res += math.ceil(cnt / 3) - + return res ``` @@ -559,5 +559,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/minimum-number-of-operations-to-move-all-balls-to-each-box.md b/articles/minimum-number-of-operations-to-move-all-balls-to-each-box.md new file mode 100644 index 000000000..31cc68370 --- /dev/null +++ b/articles/minimum-number-of-operations-to-move-all-balls-to-each-box.md @@ -0,0 +1,326 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def minOperations(self, boxes: str) -> List[int]: + n = len(boxes) + res = [0] * n + + for pos in range(n): + for i in range(n): + if boxes[i] == '1': + res[pos] += abs(pos - i) + + return res +``` + +```java +public class Solution { + public int[] minOperations(String boxes) { + int n = boxes.length(); + int[] res = new int[n]; + + for (int pos = 0; pos < n; pos++) { + for (int i = 0; i < n; i++) { + if (boxes.charAt(i) == '1') { + res[pos] += Math.abs(pos - i); + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector minOperations(string boxes) { + int n = boxes.size(); + vector res(n, 0); + + for (int pos = 0; pos < n; pos++) { + for (int i = 0; i < n; i++) { + if (boxes[i] == '1') { + res[pos] += abs(pos - i); + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} boxes + * @return {number[]} + */ + minOperations(boxes) { + const n = boxes.length; + const res = new Array(n).fill(0); + + for (let pos = 0; pos < n; pos++) { + for (let i = 0; i < n; i++) { + if (boxes[i] === '1') { + res[pos] += Math.abs(pos - i); + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output list. + +--- + +## 2. Prefix Sum + +::tabs-start + +```python +class Solution: + def minOperations(self, boxes: str) -> List[int]: + n = len(boxes) + res = [0] * n + + prefix_count = [0] * (n + 1) + index_sum = [0] * (n + 1) + for i in range(n): + prefix_count[i + 1] = prefix_count[i] + (boxes[i] == '1') + index_sum[i + 1] = index_sum[i] + (i if boxes[i] == '1' else 0) + + for i in range(n): + left = prefix_count[i] + left_sum = index_sum[i] + + right = prefix_count[n] - prefix_count[i + 1] + right_sum = index_sum[n] - index_sum[i + 1] + + res[i] = (i * left - left_sum) + (right_sum - i * right) + + return res +``` + +```java +public class Solution { + public int[] minOperations(String boxes) { + int n = boxes.length(); + int[] res = new int[n]; + int[] prefixCount = new int[n + 1]; + int[] indexSum = new int[n + 1]; + + for (int i = 0; i < n; i++) { + prefixCount[i + 1] = prefixCount[i] + (boxes.charAt(i) == '1' ? 1 : 0); + indexSum[i + 1] = indexSum[i] + (boxes.charAt(i) == '1' ? i : 0); + } + + for (int i = 0; i < n; i++) { + int left = prefixCount[i]; + int leftSum = indexSum[i]; + + int right = prefixCount[n] - prefixCount[i + 1]; + int rightSum = indexSum[n] - indexSum[i + 1]; + + res[i] = i * left - leftSum + (rightSum - i * right); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector minOperations(string boxes) { + int n = boxes.size(); + vector res(n), prefixCount(n + 1, 0), indexSum(n + 1, 0); + + for (int i = 0; i < n; i++) { + prefixCount[i + 1] = prefixCount[i] + (boxes[i] == '1' ? 1 : 0); + indexSum[i + 1] = indexSum[i] + (boxes[i] == '1' ? i : 0); + } + + for (int i = 0; i < n; i++) { + int left = prefixCount[i]; + int leftSum = indexSum[i]; + int right = prefixCount[n] - prefixCount[i + 1]; + int rightSum = indexSum[n] - indexSum[i + 1]; + res[i] = i * left - leftSum + (rightSum - i * right); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} boxes + * @return {number[]} + */ + minOperations(boxes) { + const n = boxes.length; + const res = new Array(n).fill(0); + const prefixCount = new Array(n + 1).fill(0); + const indexSum = new Array(n + 1).fill(0); + + for (let i = 0; i < n; i++) { + prefixCount[i + 1] = prefixCount[i] + (boxes[i] === '1' ? 1 : 0); + indexSum[i + 1] = indexSum[i] + (boxes[i] === '1' ? i : 0); + } + + for (let i = 0; i < n; i++) { + const left = prefixCount[i]; + const leftSum = indexSum[i]; + const right = prefixCount[n] - prefixCount[i + 1]; + const rightSum = indexSum[n] - indexSum[i + 1]; + + res[i] = i * left - leftSum + (rightSum - i * right); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Prefix Sum (Optimal) + +::tabs-start + +```python +class Solution: + def minOperations(self, boxes: str) -> List[int]: + n = len(boxes) + res = [0] * n + + balls = moves = 0 + for i in range(n): + res[i] = balls + moves + moves += balls + balls += int(boxes[i]) + + balls = moves = 0 + for i in range(n - 1, -1, -1): + res[i] += balls + moves + moves += balls + balls += int(boxes[i]) + + return res +``` + +```java +public class Solution { + public int[] minOperations(String boxes) { + int n = boxes.length(); + int[] res = new int[n]; + + int balls = 0, moves = 0; + for (int i = 0; i < n; i++) { + res[i] = balls + moves; + moves += balls; + balls += boxes.charAt(i) - '0'; + } + + balls = moves = 0; + for (int i = n - 1; i >= 0; i--) { + res[i] += balls + moves; + moves += balls; + balls += boxes.charAt(i) - '0'; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector minOperations(string boxes) { + int n = boxes.size(); + vector res(n, 0); + + int balls = 0, moves = 0; + for (int i = 0; i < n; i++) { + res[i] = balls + moves; + moves += balls; + balls += boxes[i] - '0'; + } + + balls = moves = 0; + for (int i = n - 1; i >= 0; i--) { + res[i] += balls + moves; + moves += balls; + balls += boxes[i] - '0'; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} boxes + * @return {number[]} + */ + minOperations(boxes) { + const n = boxes.length; + const res = new Array(n).fill(0); + + let balls = 0, + moves = 0; + for (let i = 0; i < n; i++) { + res[i] = balls + moves; + moves += balls; + balls += Number(boxes[i]); + } + + balls = moves = 0; + for (let i = n - 1; i >= 0; i--) { + res[i] += balls + moves; + moves += balls; + balls += Number(boxes[i]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output list. diff --git a/articles/minimum-number-of-swaps-to-make-the-string-balanced.md b/articles/minimum-number-of-swaps-to-make-the-string-balanced.md index 8c18a3ae2..9f3c6aaa8 100644 --- a/articles/minimum-number-of-swaps-to-make-the-string-balanced.md +++ b/articles/minimum-number-of-swaps-to-make-the-string-balanced.md @@ -71,8 +71,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -91,7 +91,7 @@ class Solution: else: close += 1 maxClose = max(maxClose, close) - + return (maxClose + 1) // 2 ``` @@ -131,7 +131,8 @@ class Solution { * @return {number} */ minSwaps(s) { - let close = 0, maxClose = 0; + let close = 0, + maxClose = 0; for (let i = 0; i < s.length; i++) { if (s.charAt(i) == '[') close--; else close++; @@ -146,8 +147,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -215,5 +216,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/minimum-number-of-vertices-to-reach-all-nodes.md b/articles/minimum-number-of-vertices-to-reach-all-nodes.md new file mode 100644 index 000000000..3952cd31b --- /dev/null +++ b/articles/minimum-number-of-vertices-to-reach-all-nodes.md @@ -0,0 +1,465 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]: + adj = [[] for _ in range(n)] + for u, v in edges: + adj[u].append(v) + + res = set(range(n)) + visited = [False] * n + + def dfs(node): + visited[node] = True + for nei in adj[node]: + if not visited[nei]: + dfs(nei) + res.discard(nei) + + for i in range(n): + if not visited[i]: + dfs(i) + return list(res) +``` + +```java +public class Solution { + public List findSmallestSetOfVertices(int n, List> edges) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + for (List edge : edges) { + adj[edge.get(0)].add(edge.get(1)); + } + + Set res = new HashSet<>(); + for (int i = 0; i < n; i++) { + res.add(i); + } + + boolean[] visited = new boolean[n]; + for (int i = 0; i < n; i++) { + dfs(i, adj, visited, res); + } + return new ArrayList<>(res); + } + + private void dfs(int node, List[] adj, boolean[] visited, Set res) { + visited[node] = true; + for (int nei : adj[node]) { + if (!visited[nei]) dfs(nei, adj, visited, res); + res.remove(nei); + } + } +} +``` + +```cpp +class Solution { +public: + vector findSmallestSetOfVertices(int n, vector>& edges) { + vector> adj(n); + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + } + + unordered_set res; + vector visited(n, false); + for (int i = 0; i < n; i++) res.insert(i); + + function dfs = [&](int node) { + visited[node] = true; + for (int& nei : adj[node]) { + if (!visited[nei]) dfs(nei); + res.erase(nei); + } + }; + + for (int i = 0; i < n; i++) { + if (!visited[i]) dfs(i); + } + return vector(res.begin(), res.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ + findSmallestSetOfVertices(n, edges) { + const adj = Array.from({ length: n }, () => []); + for (const [u, v] of edges) { + adj[u].push(v); + } + + const res = new Set(Array.from({ length: n }, (_, i) => i)); + const visited = new Array(n).fill(false); + + const dfs = (node) => { + visited[node] = true; + for (const nei of adj[node]) { + if (!visited[nei]) dfs(nei); + res.delete(nei); + } + }; + + for (let i = 0; i < n; i++) { + if (!visited[i]) dfs(i); + } + + return Array.from(res); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 2. Iterative DFS + +::tabs-start + +```python +class Solution: + def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]: + adj = [[] for _ in range(n)] + for u, v in edges: + adj[u].append(v) + + res = [True] * n + visited = [False] * n + stack = [] + + for i in range(n): + if not visited[i]: + stack.append(i) + while stack: + node = stack.pop() + if visited[node]: + continue + visited[node] = True + for nei in adj[node]: + if not visited[nei]: + stack.append(nei) + res[nei] = False + + return [i for i in range(n) if res[i]] +``` + +```java +public class Solution { + public List findSmallestSetOfVertices(int n, List> edges) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (List edge : edges) { + adj[edge.get(0)].add(edge.get(1)); + } + + boolean[] res = new boolean[n]; + Arrays.fill(res, true); + boolean[] visited = new boolean[n]; + Stack stack = new Stack<>(); + + for (int i = 0; i < n; i++) { + if (!visited[i]) { + stack.push(i); + while (!stack.isEmpty()) { + int node = stack.pop(); + if (visited[node]) continue; + visited[node] = true; + for (int nei : adj[node]) { + if (!visited[nei]) stack.push(nei); + res[nei] = false; + } + } + } + } + + List result = new ArrayList<>(); + for (int i = 0; i < n; i++) { + if (res[i]) result.add(i); + } + return result; + } +} +``` + +```cpp +class Solution { +public: + vector findSmallestSetOfVertices(int n, vector>& edges) { + vector> adj(n); + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + } + + vector res(n, true), visited(n, false); + stack stack; + + for (int i = 0; i < n; i++) { + if (!visited[i]) { + stack.push(i); + while (!stack.empty()) { + int node = stack.top(); + stack.pop(); + if (visited[node]) continue; + visited[node] = true; + for (int nei : adj[node]) { + if (!visited[nei]) stack.push(nei); + res[nei] = false; + } + } + } + } + + vector result; + for (int i = 0; i < n; i++) { + if (res[i]) result.push_back(i); + } + return result; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ + findSmallestSetOfVertices(n, edges) { + const adj = Array.from({ length: n }, () => []); + for (const [u, v] of edges) { + adj[u].push(v); + } + + const res = Array(n).fill(true); + const visited = Array(n).fill(false); + const stack = []; + + for (let i = 0; i < n; i++) { + if (!visited[i]) { + stack.push(i); + while (stack.length) { + const node = stack.pop(); + if (visited[node]) continue; + visited[node] = true; + for (const nei of adj[node]) { + if (!visited[nei]) stack.push(nei); + res[nei] = false; + } + } + } + } + + return res.map((val, i) => (val ? i : -1)).filter((i) => i !== -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 3. Indegree Count + +::tabs-start + +```python +class Solution: + def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]: + incoming = collections.defaultdict(list) + for src, dst in edges: + incoming[dst].append(src) + + res = [] + for i in range(n): + if not incoming[i]: + res.append(i) + return res +``` + +```java +public class Solution { + public List findSmallestSetOfVertices(int n, List> edges) { + List[] incoming = new ArrayList[n]; + for (int i = 0; i < n; i++) { + incoming[i] = new ArrayList<>(); + } + for (List edge : edges) { + incoming[edge.get(1)].add(edge.get(0)); + } + + List res = new ArrayList<>(); + for (int i = 0; i < n; i++) { + if (incoming[i].isEmpty()) { + res.add(i); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findSmallestSetOfVertices(int n, vector>& edges) { + vector> incoming(n); + for (auto& edge : edges) { + incoming[edge[1]].push_back(edge[0]); + } + + vector res; + for (int i = 0; i < n; i++) { + if (incoming[i].empty()) { + res.push_back(i); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ + findSmallestSetOfVertices(n, edges) { + const incoming = Array.from({ length: n }, () => []); + + for (const [src, dst] of edges) { + incoming[dst].push(src); + } + + const res = []; + for (let i = 0; i < n; i++) { + if (incoming[i].length === 0) { + res.push(i); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 4. Indegree Count + +::tabs-start + +```python +class Solution: + def findSmallestSetOfVertices(self, n: int, edges: List[List[int]]) -> List[int]: + indegree = [False] * n + for src, dst in edges: + indegree[dst] = True + return [i for i in range(n) if not indegree[i]] +``` + +```java +public class Solution { + public List findSmallestSetOfVertices(int n, List> edges) { + boolean[] indegree = new boolean[n]; + for (List edge : edges) { + indegree[edge.get(1)] = true; + } + + List res = new ArrayList<>(); + for (int i = 0; i < n; i++) { + if (!indegree[i]) { + res.add(i); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector findSmallestSetOfVertices(int n, vector>& edges) { + vector indegree(n, false); + for (const auto& edge : edges) { + indegree[edge[1]] = true; + } + + vector res; + for (int i = 0; i < n; i++) { + if (!indegree[i]) { + res.push_back(i); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @return {number[]} + */ + findSmallestSetOfVertices(n, edges) { + const indegree = new Array(n).fill(false); + for (const [src, dst] of edges) { + indegree[dst] = true; + } + + let res = []; + for (let i = 0; i < n; i++) { + if (!indegree[i]) res.push(i); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. diff --git a/articles/minimum-one-bit-operations-to-make-integers-zero.md b/articles/minimum-one-bit-operations-to-make-integers-zero.md new file mode 100644 index 000000000..9d3dc8766 --- /dev/null +++ b/articles/minimum-one-bit-operations-to-make-integers-zero.md @@ -0,0 +1,316 @@ +## 1. Math (Recursion) + +::tabs-start + +```python +class Solution: + def minimumOneBitOperations(self, n: int) -> int: + if n == 0: + return 0 + + k = 1 + while (k << 1) <= n: + k <<= 1 + + return (k << 1) - 1 - self.minimumOneBitOperations(k ^ n) +``` + +```java +public class Solution { + public int minimumOneBitOperations(int n) { + if (n == 0) { + return 0; + } + + int k = 1; + while ((k << 1) <= n) { + k <<= 1; + } + + return (k << 1) - 1 - minimumOneBitOperations(k ^ n); + } +} +``` + +```cpp +class Solution { +public: + int minimumOneBitOperations(int n) { + if (n == 0) { + return 0; + } + + int k = 1; + while ((k << 1) <= n) { + k <<= 1; + } + + return (k << 1) - 1 - minimumOneBitOperations(k ^ n); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + minimumOneBitOperations(n) { + if (n === 0) { + return 0; + } + + let k = 1; + while (k << 1 <= n) { + k <<= 1; + } + + return (k << 1) - 1 - this.minimumOneBitOperations(k ^ n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(\log n)$ for recursion stack. + +--- + +## 2. Math (Iteration) - I + +::tabs-start + +```python +class Solution: + def minimumOneBitOperations(self, n: int) -> int: + res = 0 + k = 1 << 30 + sign = 1 + + while n: + while k > n: + k >>= 1 + + res += (sign * ((k << 1) - 1)) + sign *= -1 + n ^= k + + return res +``` + +```java +public class Solution { + public int minimumOneBitOperations(int n) { + int res = 0, k = 1 << 30, sign = 1; + + while (n != 0) { + while (k > n) { + k >>= 1; + } + + res += (sign * ((k << 1) - 1)); + sign *= -1; + n ^= k; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minimumOneBitOperations(int n) { + int res = 0, k = 1 << 30, sign = 1; + + while (n != 0) { + while (k > n) { + k >>= 1; + } + + res += sign * ((k << 1) - 1); + sign *= -1; + n ^= k; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + minimumOneBitOperations(n) { + let res = 0, + k = 1 << 30, + sign = 1; + + while (n !== 0) { + while (k > n) { + k >>= 1; + } + + res += sign * ((k << 1) - 1); + sign *= -1; + n ^= k; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ + +--- + +## 3. Math (Iteration) - II + +::tabs-start + +```python +class Solution: + def minimumOneBitOperations(self, n: int) -> int: + res, sign = 0, 1 + while n: + res += sign * (n ^ (n - 1)) + n &= (n - 1) + sign *= -1 + return abs(res) +``` + +```java +public class Solution { + public int minimumOneBitOperations(int n) { + int res = 0, sign = 1; + while (n != 0) { + res += sign * (n ^ (n - 1)); + n &= (n - 1); + sign *= -1; + } + return Math.abs(res); + } +} +``` + +```cpp +class Solution { +public: + int minimumOneBitOperations(int n) { + int res = 0, sign = 1; + while (n != 0) { + res += sign * (n ^ (n - 1)); + n &= (n - 1); + sign *= -1; + } + return abs(res); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + minimumOneBitOperations(n) { + let res = 0, + sign = 1; + while (n !== 0) { + res += sign * (n ^ (n - 1)); + n &= n - 1; + sign *= -1; + } + return Math.abs(res); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ + +--- + +## 4. Math (Grey Code) + +::tabs-start + +```python +class Solution: + def minimumOneBitOperations(self, n: int) -> int: + res = n + while n: + n >>= 1 + res ^= n + return res +``` + +```java +public class Solution { + public int minimumOneBitOperations(int n) { + int res = n; + while (n != 0) { + n >>= 1; + res ^= n; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minimumOneBitOperations(int n) { + int res = n; + while (n != 0) { + n >>= 1; + res ^= n; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + minimumOneBitOperations(n) { + let res = n; + while (n !== 0) { + n >>= 1; + res ^= n; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/minimum-operations-to-reduce-x-to-zero.md b/articles/minimum-operations-to-reduce-x-to-zero.md new file mode 100644 index 000000000..f9f19b49e --- /dev/null +++ b/articles/minimum-operations-to-reduce-x-to-zero.md @@ -0,0 +1,583 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def minOperations(self, nums: List[int], x: int) -> int: + n = len(nums) + res = n + 1 + suffixSum = prefixSum = 0 + + for i in range(n - 1, -1, -1): + suffixSum += nums[i] + if suffixSum == x: + res = min(res, n - i) + + for i in range(n): + prefixSum += nums[i] + suffixSum = 0 + if prefixSum == x: + res = min(res, i + 1) + + for j in range(n - 1, i, -1): + suffixSum += nums[j] + if prefixSum + suffixSum == x: + res = min(res, i + 1 + n - j) + + return -1 if res == n + 1 else res +``` + +```java +public class Solution { + public int minOperations(int[] nums, int x) { + int n = nums.length; + int res = n + 1; + int suffixSum = 0, prefixSum = 0; + + for (int i = n - 1; i >= 0; i--) { + suffixSum += nums[i]; + if (suffixSum == x) { + res = Math.min(res, n - i); + } + } + + for (int i = 0; i < n; i++) { + prefixSum += nums[i]; + suffixSum = 0; + if (prefixSum == x) { + res = Math.min(res, i + 1); + } + + for (int j = n - 1; j > i; j--) { + suffixSum += nums[j]; + if (prefixSum + suffixSum == x) { + res = Math.min(res, i + 1 + n - j); + } + } + } + + return res == n + 1 ? -1 : res; + } +} +``` + +```cpp +class Solution { +public: + int minOperations(vector& nums, int x) { + int n = nums.size(); + int res = n + 1, suffixSum = 0, prefixSum = 0; + + for (int i = n - 1; i >= 0; i--) { + suffixSum += nums[i]; + if (suffixSum == x) { + res = min(res, n - i); + } + } + + for (int i = 0; i < n; i++) { + prefixSum += nums[i]; + suffixSum = 0; + if (prefixSum == x) { + res = min(res, i + 1); + } + + for (int j = n - 1; j > i; j--) { + suffixSum += nums[j]; + if (prefixSum + suffixSum == x) { + res = min(res, i + 1 + n - j); + } + } + } + + return res == n + 1 ? -1 : res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} x + * @return {number} + */ + minOperations(nums, x) { + const n = nums.length; + let res = n + 1, + suffixSum = 0, + prefixSum = 0; + + for (let i = n - 1; i >= 0; i--) { + suffixSum += nums[i]; + if (suffixSum === x) { + res = Math.min(res, n - i); + } + } + + for (let i = 0; i < n; i++) { + prefixSum += nums[i]; + suffixSum = 0; + if (prefixSum === x) { + res = Math.min(res, i + 1); + } + + for (let j = n - 1; j > i; j--) { + suffixSum += nums[j]; + if (prefixSum + suffixSum === x) { + res = Math.min(res, i + 1 + n - j); + } + } + } + + return res === n + 1 ? -1 : res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 2. Prefix Sum + Binary Search + +::tabs-start + +```python +class Solution: + def minOperations(self, nums: List[int], x: int) -> int: + n = len(nums) + prefixSum = [0] * (n + 1) + for i in range(n): + prefixSum[i + 1] = prefixSum[i] + nums[i] + + if x > prefixSum[n]: + return -1 + + def binarySearch(target, m): + l, r = 1, m + index = n + 1 + + while l <= r: + mid = (l + r) >> 1 + if prefixSum[mid] >= target: + if prefixSum[mid] == target: + index = mid + r = mid - 1 + else: + l = mid + 1 + + return index + + res = binarySearch(x, n) + suffixSum = 0 + for i in range(n - 1, 0, -1): + suffixSum += nums[i] + if suffixSum == x: + res = min(res, n - i) + break + if suffixSum > x: break + res = min(res, binarySearch(x - suffixSum, i) + n - i) + + return -1 if res == n + 1 else res +``` + +```java +public class Solution { + public int minOperations(int[] nums, int x) { + int n = nums.length; + int[] prefixSum = new int[n + 1]; + for (int i = 0; i < n; i++) { + prefixSum[i + 1] = prefixSum[i] + nums[i]; + } + + if (x > prefixSum[n]) { + return -1; + } + + int res = binarySearch(prefixSum, x, n); + int suffixSum = 0; + for (int i = n - 1; i > 0; i--) { + suffixSum += nums[i]; + if (suffixSum == x) { + res = Math.min(res, n - i); + break; + } + if (suffixSum > x) break; + res = Math.min(res, binarySearch(prefixSum, x - suffixSum, i) + n - i); + } + + return res == n + 1 ? -1 : res; + } + + private int binarySearch(int[] prefixSum, int target, int m) { + int l = 1, r = m; + int index = prefixSum.length; + + while (l <= r) { + int mid = (l + r) / 2; + if (prefixSum[mid] >= target) { + if (prefixSum[mid] == target) { + index = mid; + } + r = mid - 1; + } else { + l = mid + 1; + } + } + return index; + } +} +``` + +```cpp +class Solution { +public: + int minOperations(vector& nums, int x) { + int n = nums.size(); + vector prefixSum(n + 1, 0); + for (int i = 0; i < n; i++) { + prefixSum[i + 1] = prefixSum[i] + nums[i]; + } + + if (x > prefixSum[n]) { + return -1; + } + + auto binarySearch = [&](int target, int m) { + int l = 1, r = m, index = n + 1; + while (l <= r) { + int mid = (l + r) / 2; + if (prefixSum[mid] >= target) { + if (prefixSum[mid] == target) { + index = mid; + } + r = mid - 1; + } else { + l = mid + 1; + } + } + return index; + }; + + int res = binarySearch(x, n); + int suffixSum = 0; + for (int i = n - 1; i > 0; i--) { + suffixSum += nums[i]; + if (suffixSum == x) { + res = min(res, n - i); + break; + } + if (suffixSum > x) break; + res = min(res, binarySearch(x - suffixSum, i) + n - i); + } + + return res == n + 1 ? -1 : res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} x + * @return {number} + */ + minOperations(nums, x) { + const n = nums.length; + const prefixSum = new Array(n + 1).fill(0); + for (let i = 0; i < n; i++) { + prefixSum[i + 1] = prefixSum[i] + nums[i]; + } + + if (x > prefixSum[n]) return -1; + + const binarySearch = (target, m) => { + let l = 1, + r = m; + let index = n + 1; + while (l <= r) { + let mid = Math.floor((l + r) / 2); + if (prefixSum[mid] >= target) { + if (prefixSum[mid] === target) { + index = mid; + } + r = mid - 1; + } else { + l = mid + 1; + } + } + return index; + }; + + let res = binarySearch(x, n); + let suffixSum = 0; + for (let i = n - 1; i > 0; i--) { + suffixSum += nums[i]; + if (suffixSum === x) { + res = Math.min(res, n - i); + break; + } + if (suffixSum > x) break; + res = Math.min(res, binarySearch(x - suffixSum, i) + n - i); + } + + return res === n + 1 ? -1 : res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Prefix Sum + Hash Map + +::tabs-start + +```python +class Solution: + def minOperations(self, nums: List[int], x: int) -> int: + total = sum(nums) + if total == x: + return len(nums) + + target = total - x + if target < 0: + return -1 + + res = -1 + prefixSum = 0 + prefixMap = {0: -1} # prefixSum -> index + + for i, num in enumerate(nums): + prefixSum += num + if prefixSum - target in prefixMap: + res = max(res, i - prefixMap[prefixSum - target]) + prefixMap[prefixSum] = i + + return len(nums) - res if res != -1 else -1 +``` + +```java +public class Solution { + public int minOperations(int[] nums, int x) { + int total = 0; + for (int num : nums) total += num; + if (total == x) return nums.length; + + int target = total - x; + if (target < 0) return -1; + + Map prefixMap = new HashMap<>(); + prefixMap.put(0, -1); + int prefixSum = 0, res = -1; + + for (int i = 0; i < nums.length; i++) { + prefixSum += nums[i]; + if (prefixMap.containsKey(prefixSum - target)) { + res = Math.max(res, i - prefixMap.get(prefixSum - target)); + } + prefixMap.put(prefixSum, i); + } + + return res == -1 ? -1 : nums.length - res; + } +} +``` + +```cpp +class Solution { +public: + int minOperations(vector& nums, int x) { + int total = 0; + for (int& num : nums) total += num; + if (total == x) return nums.size(); + + int target = total - x; + if (target < 0) return -1; + + unordered_map prefixMap; + prefixMap[0] = -1; + int prefixSum = 0, res = -1; + + for (int i = 0; i < nums.size(); i++) { + prefixSum += nums[i]; + if (prefixMap.count(prefixSum - target)) { + res = max(res, i - prefixMap[prefixSum - target]); + } + prefixMap[prefixSum] = i; + } + + return res == -1 ? -1 : nums.size() - res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} x + * @return {number} + */ + minOperations(nums, x) { + const total = nums.reduce((acc, num) => acc + num, 0); + if (total === x) return nums.length; + + const target = total - x; + if (target < 0) return -1; + + const prefixMap = new Map(); + prefixMap.set(0, -1); + let prefixSum = 0, + res = -1; + + for (let i = 0; i < nums.length; i++) { + prefixSum += nums[i]; + if (prefixMap.has(prefixSum - target)) { + res = Math.max(res, i - prefixMap.get(prefixSum - target)); + } + prefixMap.set(prefixSum, i); + } + + return res === -1 ? -1 : nums.length - res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Sliding Window + +::tabs-start + +```python +class Solution: + def minOperations(self, nums: List[int], x: int) -> int: + target = sum(nums) - x + cur_sum = 0 + max_window = -1 + l = 0 + + for r in range(len(nums)): + cur_sum += nums[r] + + while l <= r and cur_sum > target: + cur_sum -= nums[l] + l += 1 + + if cur_sum == target: + max_window = max(max_window, r - l + 1) + + return -1 if max_window == -1 else len(nums) - max_window +``` + +```java +public class Solution { + public int minOperations(int[] nums, int x) { + int target = 0; + for (int num : nums) target += num; + target -= x; + + int curSum = 0, maxWindow = -1, l = 0; + + for (int r = 0; r < nums.length; r++) { + curSum += nums[r]; + + while (l <= r && curSum > target) { + curSum -= nums[l]; + l++; + } + + if (curSum == target) { + maxWindow = Math.max(maxWindow, r - l + 1); + } + } + + return maxWindow == -1 ? -1 : nums.length - maxWindow; + } +} +``` + +```cpp +class Solution { +public: + int minOperations(vector& nums, int x) { + int target = accumulate(nums.begin(), nums.end(), 0) - x; + int curSum = 0, maxWindow = -1, l = 0; + + for (int r = 0; r < nums.size(); r++) { + curSum += nums[r]; + + while (l <= r && curSum > target) { + curSum -= nums[l]; + l++; + } + + if (curSum == target) { + maxWindow = max(maxWindow, r - l + 1); + } + } + + return maxWindow == -1 ? -1 : nums.size() - maxWindow; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} x + * @return {number} + */ + minOperations(nums, x) { + const target = nums.reduce((acc, num) => acc + num, 0) - x; + let curSum = 0, + maxWindow = -1, + l = 0; + + for (let r = 0; r < nums.length; r++) { + curSum += nums[r]; + + while (l <= r && curSum > target) { + curSum -= nums[l]; + l++; + } + + if (curSum === target) { + maxWindow = Math.max(maxWindow, r - l + 1); + } + } + + return maxWindow === -1 ? -1 : nums.length - maxWindow; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/minimum-path-sum.md b/articles/minimum-path-sum.md index 37968cf67..c05fa7f62 100644 --- a/articles/minimum-path-sum.md +++ b/articles/minimum-path-sum.md @@ -74,12 +74,33 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinPathSum(int[][] grid) { + return Dfs(0, 0, grid); + } + + public int Dfs(int r, int c, int[][] grid) { + int M = grid.Length, N = grid[0].Length; + + if (r == M - 1 && c == N - 1) { + return grid[r][c]; + } + if (r == M || c == N) { + return int.MaxValue; + } + + return grid[r][c] + Math.Min(Dfs(r + 1, c, grid), Dfs(r, c + 1, grid)); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ {m + n})$ -* Space complexity: $O(m + n)$ for recursion stack. +- Time complexity: $O(2 ^ {m + n})$ +- Space complexity: $O(m + n)$ for recursion stack. > Where $m$ is the number of rows and $n$ is the number of columns. @@ -177,7 +198,8 @@ class Solution { * @return {number} */ minPathSum(grid) { - const m = grid.length, n = grid[0].length; + const m = grid.length, + n = grid[0].length; const dp = Array.from({ length: m }, () => Array(n).fill(-1)); const dfs = (r, c) => { @@ -200,12 +222,46 @@ class Solution { } ``` +```csharp +public class Solution { + private int[,] dp; + + public int MinPathSum(int[][] grid) { + int m = grid.Length, n = grid[0].Length; + dp = new int[m, n]; + for (int i = 0; i < m; i++) { + for (int j = 0; j < n; j++) { + dp[i, j] = -1; + } + } + return Dfs(0, 0, grid); + } + + private int Dfs(int r, int c, int[][] grid) { + int m = grid.Length, n = grid[0].Length; + + if (r == m - 1 && c == n - 1) { + return grid[r][c]; + } + if (r == m || c == n) { + return int.MaxValue; + } + if (dp[r, c] != -1) { + return dp[r, c]; + } + + dp[r, c] = grid[r][c] + Math.Min(Dfs(r + 1, c, grid), Dfs(r, c + 1, grid)); + return dp[r, c]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns. @@ -279,8 +335,11 @@ class Solution { * @return {number} */ minPathSum(grid) { - const ROWS = grid.length, COLS = grid[0].length; - const dp = Array.from({ length: ROWS + 1 }, () => Array(COLS + 1).fill(Infinity)); + const ROWS = grid.length, + COLS = grid[0].length; + const dp = Array.from({ length: ROWS + 1 }, () => + Array(COLS + 1).fill(Infinity), + ); dp[ROWS - 1][COLS] = 0; for (let r = ROWS - 1; r >= 0; r--) { @@ -294,12 +353,37 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinPathSum(int[][] grid) { + int ROWS = grid.Length, COLS = grid[0].Length; + int[,] dp = new int[ROWS + 1, COLS + 1]; + + for (int r = 0; r <= ROWS; r++) { + for (int c = 0; c <= COLS; c++) { + dp[r, c] = int.MaxValue; + } + } + + dp[ROWS - 1, COLS] = 0; + + for (int r = ROWS - 1; r >= 0; r--) { + for (int c = COLS - 1; c >= 0; c--) { + dp[r, c] = grid[r][c] + Math.Min(dp[r + 1, c], dp[r, c + 1]); + } + } + + return dp[0, 0]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns. @@ -370,7 +454,8 @@ class Solution { * @return {number} */ minPathSum(grid) { - const ROWS = grid.length, COLS = grid[0].length; + const ROWS = grid.length, + COLS = grid[0].length; const dp = new Array(COLS + 1).fill(Infinity); dp[COLS - 1] = 0; @@ -385,11 +470,32 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinPathSum(int[][] grid) { + int ROWS = grid.Length, COLS = grid[0].Length; + int[] dp = new int[COLS + 1]; + for (int c = 0; c <= COLS; c++) { + dp[c] = int.MaxValue; + } + dp[COLS - 1] = 0; + + for (int r = ROWS - 1; r >= 0; r--) { + for (int c = COLS - 1; c >= 0; c--) { + dp[c] = grid[r][c] + Math.Min(dp[c], dp[c + 1]); + } + } + + return dp[0]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(n)$ -> Where $m$ is the number of rows and $n$ is the number of columns. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns. diff --git a/articles/minimum-penalty-for-a-shop.md b/articles/minimum-penalty-for-a-shop.md index a3e506a88..5494b6bf6 100644 --- a/articles/minimum-penalty-for-a-shop.md +++ b/articles/minimum-penalty-for-a-shop.md @@ -17,7 +17,7 @@ class Solution: for j in range(i, n): if customers[j] == 'Y': penalty += 1 - + if penalty < minPenalty: minPenalty = penalty res = i @@ -49,7 +49,7 @@ public class Solution { res = i; } } - + return res; } } @@ -74,7 +74,7 @@ public: penalty++; } } - + if (penalty < minPenalty) { minPenalty = penalty; res = i; @@ -94,7 +94,8 @@ class Solution { */ bestClosingTime(customers) { const n = customers.length; - let res = n, minPenalty = n; + let res = n, + minPenalty = n; for (let i = 0; i <= n; i++) { let penalty = 0; @@ -124,8 +125,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -145,13 +146,13 @@ class Solution: if c == 'N': cnt += 1 prefixN.append(cnt) - + suffixY = [0] * (n + 1) for i in range(n - 1, -1, -1): suffixY[i] = suffixY[i + 1] if customers[i] == 'Y': suffixY[i] += 1 - + res = n minPenalty = n for i in range(n + 1): @@ -159,7 +160,7 @@ class Solution: if penalty < minPenalty: minPenalty = penalty res = i - + return res ``` @@ -264,7 +265,8 @@ class Solution { } } - let res = n, minPenalty = n; + let res = n, + minPenalty = n; for (let i = 0; i <= n; i++) { const penalty = prefixN[i] + suffixY[i]; if (penalty < minPenalty) { @@ -282,8 +284,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -345,7 +347,7 @@ class Solution { public: int bestClosingTime(string customers) { int cntY = count(customers.begin(), customers.end(), 'Y'); - + int minPenalty = cntY, res = 0, cntN = 0; for (int i = 0; i < customers.size(); i++) { if (customers[i] == 'Y') { @@ -378,7 +380,9 @@ class Solution { if (c === 'Y') cntY++; } - let minPenalty = cntY, res = 0, cntN = 0; + let minPenalty = cntY, + res = 0, + cntN = 0; for (let i = 0; i < customers.length; i++) { if (customers[i] === 'Y') { cntY--; @@ -402,8 +406,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -473,7 +477,9 @@ class Solution { * @return {number} */ bestClosingTime(customers) { - let res = 0, minPenalty = 0, penalty = 0; + let res = 0, + minPenalty = 0, + penalty = 0; for (let i = 0; i < customers.length; i++) { penalty += customers[i] === 'Y' ? 1 : -1; @@ -493,5 +499,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/minimum-recolors-to-get-k-consecutive-black-blocks.md b/articles/minimum-recolors-to-get-k-consecutive-black-blocks.md new file mode 100644 index 000000000..29e674c7f --- /dev/null +++ b/articles/minimum-recolors-to-get-k-consecutive-black-blocks.md @@ -0,0 +1,240 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def minimumRecolors(self, blocks: str, k: int) -> int: + res = len(blocks) + for i in range(len(blocks) - k + 1): + count_w = 0 + for j in range(i, i + k): + if blocks[j] == 'W': + count_w += 1 + res = min(res, count_w) + return res +``` + +```java +public class Solution { + public int minimumRecolors(String blocks, int k) { + int res = blocks.length(); + for (int i = 0; i <= blocks.length() - k; i++) { + int count_w = 0; + for (int j = i; j < i + k; j++) { + if (blocks.charAt(j) == 'W') { + count_w++; + } + } + res = Math.min(res, count_w); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minimumRecolors(string blocks, int k) { + int res = blocks.length(); + for (int i = 0; i <= blocks.length() - k; i++) { + int count_w = 0; + for (int j = i; j < i + k; j++) { + if (blocks[j] == 'W') { + count_w++; + } + } + res = min(res, count_w); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} blocks + * @param {number} k + * @return {number} + */ + minimumRecolors(blocks, k) { + let res = blocks.length; + for (let i = 0; i <= blocks.length - k; i++) { + let count_w = 0; + for (let j = i; j < i + k; j++) { + if (blocks[j] === 'W') { + count_w++; + } + } + res = Math.min(res, count_w); + } + return res; + } +} +``` + +```csharp +public class Solution { + public int MinimumRecolors(string blocks, int k) { + int res = blocks.Length; + for (int i = 0; i <= blocks.Length - k; i++) { + int count_w = 0; + for (int j = i; j < i + k; j++) { + if (blocks[j] == 'W') { + count_w++; + } + } + res = Math.Min(res, count_w); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * k)$ +* Space complexity: $O(1)$ + +--- + +## 2. Sliding Window + +::tabs-start + +```python +class Solution: + def minimumRecolors(self, blocks: str, k: int) -> int: + count_w = 0 + for i in range(k): + if blocks[i] == 'W': + count_w += 1 + + res = count_w + for i in range(k, len(blocks)): + if blocks[i - k] == 'W': + count_w -= 1 + if blocks[i] == 'W': + count_w += 1 + res = min(res, count_w) + return res +``` + +```java +public class Solution { + public int minimumRecolors(String blocks, int k) { + int count_w = 0; + for (int i = 0; i < k; i++) { + if (blocks.charAt(i) == 'W') { + count_w++; + } + } + + int res = count_w; + for (int i = k; i < blocks.length(); i++) { + if (blocks.charAt(i - k) == 'W') { + count_w--; + } + if (blocks.charAt(i) == 'W') { + count_w++; + } + res = Math.min(res, count_w); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minimumRecolors(string blocks, int k) { + int count_w = 0; + for (int i = 0; i < k; i++) { + if (blocks[i] == 'W') { + count_w++; + } + } + + int res = count_w; + for (int i = k; i < blocks.size(); i++) { + if (blocks[i - k] == 'W') { + count_w--; + } + if (blocks[i] == 'W') { + count_w++; + } + res = min(res, count_w); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} blocks + * @param {number} k + * @return {number} + */ + minimumRecolors(blocks, k) { + let count_w = 0; + for (let i = 0; i < k; i++) { + if (blocks[i] === 'W') { + count_w++; + } + } + + let res = count_w; + for (let i = k; i < blocks.length; i++) { + if (blocks[i - k] === 'W') { + count_w--; + } + if (blocks[i] === 'W') { + count_w++; + } + res = Math.min(res, count_w); + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int MinimumRecolors(string blocks, int k) { + int count_w = 0; + for (int i = 0; i < k; i++) { + if (blocks[i] == 'W') { + count_w++; + } + } + + int res = count_w; + for (int i = k; i < blocks.Length; i++) { + if (blocks[i - k] == 'W') { + count_w--; + } + if (blocks[i] == 'W') { + count_w++; + } + res = Math.Min(res, count_w); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/minimum-remove-to-make-valid-parentheses.md b/articles/minimum-remove-to-make-valid-parentheses.md new file mode 100644 index 000000000..bf7e8b5b0 --- /dev/null +++ b/articles/minimum-remove-to-make-valid-parentheses.md @@ -0,0 +1,647 @@ +## 1. Stack + +::tabs-start + +```python +class Solution: + def minRemoveToMakeValid(self, s: str) -> str: + res = [] + cnt = 0 # extra ( parentheses + for c in s: + if c == "(": + res.append(c) + cnt += 1 + elif c == ")" and cnt > 0: + res.append(c) + cnt -= 1 + elif c != ")": + res.append(c) + + filtered = [] + for c in reversed(res): + if c == "(" and cnt > 0: + cnt -= 1 + else: + filtered.append(c) + return "".join(reversed(filtered)) +``` + +```java +public class Solution { + public String minRemoveToMakeValid(String s) { + StringBuilder res = new StringBuilder(); + int cnt = 0; + + for (char c : s.toCharArray()) { + if (c == '(') { + res.append(c); + cnt++; + } else if (c == ')' && cnt > 0) { + res.append(c); + cnt--; + } else if (c != ')') { + res.append(c); + } + } + + StringBuilder filtered = new StringBuilder(); + for (int i = res.length() - 1; i >= 0; i--) { + char c = res.charAt(i); + if (c == '(' && cnt > 0) { + cnt--; + } else { + filtered.append(c); + } + } + return filtered.reverse().toString(); + } +} +``` + +```cpp +class Solution { +public: + string minRemoveToMakeValid(string s) { + string res; + int cnt = 0; + + for (char c : s) { + if (c == '(') { + res.push_back(c); + cnt++; + } else if (c == ')' && cnt > 0) { + res.push_back(c); + cnt--; + } else if (c != ')') { + res.push_back(c); + } + } + + string filtered; + for (int i = res.size() - 1; i >= 0; i--) { + char c = res[i]; + if (c == '(' && cnt > 0) { + cnt--; + } else { + filtered.push_back(c); + } + } + reverse(filtered.begin(), filtered.end()); + return filtered; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + minRemoveToMakeValid(s) { + let res = []; + let cnt = 0; + + for (let c of s) { + if (c === '(') { + res.push(c); + cnt++; + } else if (c === ')' && cnt > 0) { + res.push(c); + cnt--; + } else if (c !== ')') { + res.push(c); + } + } + + let filtered = []; + for (let i = res.length - 1; i >= 0; i--) { + let c = res[i]; + if (c === '(' && cnt > 0) { + cnt--; + } else { + filtered.push(c); + } + } + return filtered.reverse().join(''); + } +} +``` + +```csharp +public class Solution { + public string MinRemoveToMakeValid(string s) { + List res = new List(); + int cnt = 0; + + foreach (char c in s) { + if (c == '(') { + res.Add(c); + cnt++; + } else if (c == ')' && cnt > 0) { + res.Add(c); + cnt--; + } else if (c != ')') { + res.Add(c); + } + } + + List filtered = new List(); + for (int i = res.Count - 1; i >= 0; i--) { + if (res[i] == '(' && cnt > 0) { + cnt--; + } else { + filtered.Add(res[i]); + } + } + + filtered.Reverse(); + return new string(filtered.ToArray()); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Without Stack + +::tabs-start + +```python +class Solution: + def minRemoveToMakeValid(self, s: str) -> str: + arr = list(s) + cnt = 0 # extra ( parentheses + for i, c in enumerate(s): + if c == "(": + cnt += 1 + elif c == ")" and cnt > 0: + cnt -= 1 + elif c == ")": + arr[i] = '' + + res = [] + for c in reversed(arr): + if c == '(' and cnt > 0: + cnt -= 1 + else: + res.append(c) + + return ''.join(reversed(res)) +``` + +```java +public class Solution { + public String minRemoveToMakeValid(String s) { + char[] arr = s.toCharArray(); + int cnt = 0; + + for (int i = 0; i < s.length(); i++) { + char c = s.charAt(i); + if (c == '(') { + cnt++; + } else if (c == ')' && cnt > 0) { + cnt--; + } else if (c == ')') { + arr[i] = '\0'; + } + } + + StringBuilder res = new StringBuilder(); + for (int i = arr.length - 1; i >= 0; i--) { + char c = arr[i]; + if (c == '(' && cnt > 0) { + cnt--; + } else if (c != '\0') { + res.append(c); + } + } + + return res.reverse().toString(); + } +} +``` + +```cpp +class Solution { +public: + string minRemoveToMakeValid(string s) { + vector arr(s.begin(), s.end()); + int cnt = 0; + + for (int i = 0; i < s.size(); i++) { + if (s[i] == '(') { + cnt++; + } else if (s[i] == ')' && cnt > 0) { + cnt--; + } else if (s[i] == ')') { + arr[i] = '\0'; + } + } + + string res; + for (int i = arr.size() - 1; i >= 0; i--) { + if (arr[i] == '(' && cnt > 0) { + cnt--; + } else if (arr[i] != '\0') { + res.push_back(arr[i]); + } + } + + reverse(res.begin(), res.end()); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + minRemoveToMakeValid(s) { + let arr = [...s]; + let cnt = 0; + + for (let i = 0; i < s.length; i++) { + let c = s[i]; + if (c === '(') { + cnt++; + } else if (c === ')' && cnt > 0) { + cnt--; + } else if (c === ')') { + arr[i] = ''; + } + } + + let res = []; + for (let i = arr.length - 1; i >= 0; i--) { + let c = arr[i]; + if (c === '(' && cnt > 0) { + cnt--; + } else if (c !== '') { + res.push(c); + } + } + + return res.reverse().join(''); + } +} +``` + +```csharp +public class Solution { + public string MinRemoveToMakeValid(string s) { + char[] arr = s.ToCharArray(); + int cnt = 0; + + for (int i = 0; i < s.Length; i++) { + if (s[i] == '(') { + cnt++; + } else if (s[i] == ')' && cnt > 0) { + cnt--; + } else if (s[i] == ')') { + arr[i] = '\0'; // mark invalid ')' + } + } + + List res = new List(); + for (int i = arr.Length - 1; i >= 0; i--) { + if (arr[i] == '(' && cnt > 0) { + cnt--; + } else if (arr[i] != '\0') { + res.Add(arr[i]); + } + } + + res.Reverse(); + return new string(res.ToArray()); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Stack (Optimal) + +::tabs-start + +```python +class Solution: + def minRemoveToMakeValid(self, s: str) -> str: + s = list(s) + stack = [] + for i, c in enumerate(s): + if c == '(': + stack.append(i) + elif c == ')': + if stack: + stack.pop() + else: + s[i] = '' + + while stack: + s[stack.pop()] = '' + return ''.join(s) +``` + +```java +public class Solution { + public String minRemoveToMakeValid(String s) { + StringBuilder sb = new StringBuilder(s); + Stack stack = new Stack<>(); + + for (int i = 0; i < sb.length(); i++) { + if (sb.charAt(i) == '(') { + stack.push(i); + } else if (sb.charAt(i) == ')') { + if (!stack.isEmpty()) { + stack.pop(); + } else { + sb.setCharAt(i, '\0'); + } + } + } + + while (!stack.isEmpty()) { + sb.setCharAt(stack.pop(), '\0'); + } + + StringBuilder result = new StringBuilder(); + for (int i = 0; i < sb.length(); i++) { + if (sb.charAt(i) != '\0') { + result.append(sb.charAt(i)); + } + } + return result.toString(); + } +} +``` + +```cpp +class Solution { +public: + string minRemoveToMakeValid(string s) { + stack stack; + for (int i = 0; i < s.size(); i++) { + if (s[i] == '(') { + stack.push(i); + } else if (s[i] == ')') { + if (!stack.empty()) { + stack.pop(); + } else { + s[i] = '\0'; + } + } + } + + while (!stack.empty()) { + s[stack.top()] = '\0'; + stack.pop(); + } + + string result; + for (char& c : s) { + if (c != '\0') { + result += c; + } + } + return result; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + minRemoveToMakeValid(s) { + const arr = [...s]; + const stack = []; + + for (let i = 0; i < arr.length; i++) { + if (arr[i] === '(') { + stack.push(i); + } else if (arr[i] === ')') { + if (stack.length > 0) { + stack.pop(); + } else { + arr[i] = ''; + } + } + } + + while (stack.length > 0) { + arr[stack.pop()] = ''; + } + + return arr.join(''); + } +} +``` + +```csharp +public class Solution { + public string MinRemoveToMakeValid(string s) { + char[] arr = s.ToCharArray(); + Stack stack = new Stack(); + + for (int i = 0; i < arr.Length; i++) { + if (arr[i] == '(') { + stack.Push(i); + } else if (arr[i] == ')') { + if (stack.Count > 0) { + stack.Pop(); + } else { + arr[i] = '\0'; + } + } + } + + while (stack.Count > 0) { + arr[stack.Pop()] = '\0'; + } + + StringBuilder result = new StringBuilder(); + foreach (char c in arr) { + if (c != '\0') { + result.Append(c); + } + } + + return result.ToString(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Without Stack (Optimal) + +::tabs-start + +```python +class Solution: + def minRemoveToMakeValid(self, s: str) -> str: + openCnt = closeCnt = 0 + for c in s: + closeCnt += c == ')' + + res = [] + for c in s: + if c == '(': + if openCnt == closeCnt: + continue + openCnt += 1 + elif c == ')': + closeCnt -= 1 + if openCnt == 0: + continue + openCnt -= 1 + res.append(c) + + return ''.join(res) +``` + +```java +public class Solution { + public String minRemoveToMakeValid(String s) { + int openCnt = 0, closeCnt = 0; + for (char c : s.toCharArray()) { + if (c == ')') closeCnt++; + } + + StringBuilder res = new StringBuilder(); + for (char c : s.toCharArray()) { + if (c == '(') { + if (openCnt == closeCnt) continue; + openCnt++; + } else if (c == ')') { + closeCnt--; + if (openCnt == 0) continue; + openCnt--; + } + res.append(c); + } + + return res.toString(); + } +} +``` + +```cpp +class Solution { +public: + string minRemoveToMakeValid(string s) { + int openCnt = 0, closeCnt = 0; + for (char& c : s) { + if (c == ')') closeCnt++; + } + + string res; + for (char& c : s) { + if (c == '(') { + if (openCnt == closeCnt) continue; + openCnt++; + } else if (c == ')') { + closeCnt--; + if (openCnt == 0) continue; + openCnt--; + } + res.push_back(c); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + minRemoveToMakeValid(s) { + let openCnt = 0, + closeCnt = 0; + for (const c of s) { + if (c === ')') closeCnt++; + } + + let res = []; + for (const c of s) { + if (c === '(') { + if (openCnt === closeCnt) continue; + openCnt++; + } else if (c === ')') { + closeCnt--; + if (openCnt === 0) continue; + openCnt--; + } + res.push(c); + } + + return res.join(''); + } +} +``` + +```csharp +public class Solution { + public string MinRemoveToMakeValid(string s) { + int openCnt = 0, closeCnt = 0; + foreach (char c in s) { + if (c == ')') closeCnt++; + } + + StringBuilder res = new StringBuilder(); + foreach (char c in s) { + if (c == '(') { + if (openCnt == closeCnt) continue; + openCnt++; + } else if (c == ')') { + closeCnt--; + if (openCnt == 0) continue; + openCnt--; + } + res.Append(c); + } + + return res.ToString(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output string. diff --git a/articles/minimum-score-of-a-path-between-two-cities.md b/articles/minimum-score-of-a-path-between-two-cities.md new file mode 100644 index 000000000..24edf9c0b --- /dev/null +++ b/articles/minimum-score-of-a-path-between-two-cities.md @@ -0,0 +1,647 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def minScore(self, n: int, roads: list[list[int]]) -> int: + adj = defaultdict(list) + for src, dst, dist in roads: + adj[src].append((dst, dist)) + adj[dst].append((src, dist)) + + res = float("inf") + visit = set() + + def dfs(node): + nonlocal res + if node in visit: + return + visit.add(node) + for nei, dist in adj[node]: + res = min(res, dist) + dfs(nei) + + dfs(1) + return res +``` + +```java +public class Solution { + private List[] adj; + private boolean[] visit; + private int res; + + public int minScore(int n, int[][] roads) { + adj = new ArrayList[n + 1]; + visit = new boolean[n + 1]; + res = Integer.MAX_VALUE; + + for (int i = 0; i <= n; i++) { + adj[i] = new ArrayList<>(); + } + + for (int[] road : roads) { + adj[road[0]].add(new int[]{road[1], road[2]}); + adj[road[1]].add(new int[]{road[0], road[2]}); + } + + dfs(1); + return res; + } + + private void dfs(int node) { + if (visit[node]) return; + visit[node] = true; + + for (int[] edge : adj[node]) { + res = Math.min(res, edge[1]); + dfs(edge[0]); + } + } +} +``` + +```cpp +class Solution { +public: + vector>> adj; + vector visit; + int res; + + int minScore(int n, vector>& roads) { + adj.resize(n + 1); + visit.resize(n + 1, false); + res = INT_MAX; + + for (auto& road : roads) { + adj[road[0]].push_back({road[1], road[2]}); + adj[road[1]].push_back({road[0], road[2]}); + } + + dfs(1); + return res; + } + + void dfs(int node) { + if (visit[node]) return; + visit[node] = true; + + for (auto& edge : adj[node]) { + res = min(res, edge.second); + dfs(edge.first); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} roads + * @return {number} + */ + minScore(n, roads) { + const adj = Array.from({ length: n + 1 }, () => []); + for (const [src, dst, dist] of roads) { + adj[src].push([dst, dist]); + adj[dst].push([src, dist]); + } + + let res = Infinity; + const visit = new Array(n + 1).fill(false); + + const dfs = (node) => { + if (visit[node]) return; + visit[node] = true; + + for (const [nei, dist] of adj[node]) { + res = Math.min(res, dist); + dfs(nei); + } + }; + + dfs(1); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class Solution: + def minScore(self, n: int, roads: list[list[int]]) -> int: + adj = [[] for _ in range(n + 1)] + for src, dst, dist in roads: + adj[src].append((dst, dist)) + adj[dst].append((src, dist)) + + res = float("inf") + visit = [False] * (n + 1) + q = deque([1]) + visit[1] = True + + while q: + node = q.popleft() + for nei, dist in adj[node]: + res = min(res, dist) + if not visit[nei]: + visit[nei] = True + q.append(nei) + + return res +``` + +```java +public class Solution { + public int minScore(int n, int[][] roads) { + List[] adj = new ArrayList[n + 1]; + for (int i = 0; i <= n; i++) adj[i] = new ArrayList<>(); + + for (int[] road : roads) { + adj[road[0]].add(new int[]{road[1], road[2]}); + adj[road[1]].add(new int[]{road[0], road[2]}); + } + + int res = Integer.MAX_VALUE; + boolean[] visit = new boolean[n + 1]; + Queue q = new LinkedList<>(); + q.offer(1); + visit[1] = true; + + while (!q.isEmpty()) { + int node = q.poll(); + for (int[] edge : adj[node]) { + int nei = edge[0], dist = edge[1]; + res = Math.min(res, dist); + if (!visit[nei]) { + visit[nei] = true; + q.offer(nei); + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minScore(int n, vector>& roads) { + vector>> adj(n + 1); + for (auto& road : roads) { + adj[road[0]].emplace_back(road[1], road[2]); + adj[road[1]].emplace_back(road[0], road[2]); + } + + int res = INT_MAX; + vector visit(n + 1, false); + queue q; + q.push(1); + visit[1] = true; + + while (!q.empty()) { + int node = q.front();q.pop(); + for (auto& [nei, dist] : adj[node]) { + res = min(res, dist); + if (!visit[nei]) { + visit[nei] = true; + q.push(nei); + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} roads + * @return {number} + */ + minScore(n, roads) { + const adj = Array.from({ length: n + 1 }, () => []); + for (const [src, dst, dist] of roads) { + adj[src].push([dst, dist]); + adj[dst].push([src, dist]); + } + + let res = Infinity; + const visit = new Array(n + 1).fill(false); + const q = new Queue([1]); + visit[1] = true; + + while (!q.isEmpty()) { + const node = q.pop(); + for (const [nei, dist] of adj[node]) { + res = Math.min(res, dist); + if (!visit[nei]) { + visit[nei] = true; + q.push(nei); + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +class Solution: + def minScore(self, n: int, roads: list[list[int]]) -> int: + adj = [[] for _ in range(n + 1)] + for src, dst, dist in roads: + adj[src].append((dst, dist)) + adj[dst].append((src, dist)) + + res = float("inf") + visit = [False] * (n + 1) + stack = [1] + visit[1] = True + + while stack: + node = stack.pop() + for nei, dist in adj[node]: + res = min(res, dist) + if not visit[nei]: + visit[nei] = True + stack.append(nei) + + return res +``` + +```java +public class Solution { + public int minScore(int n, int[][] roads) { + List[] adj = new ArrayList[n + 1]; + for (int i = 0; i <= n; i++) adj[i] = new ArrayList<>(); + + for (int[] road : roads) { + adj[road[0]].add(new int[]{road[1], road[2]}); + adj[road[1]].add(new int[]{road[0], road[2]}); + } + + int res = Integer.MAX_VALUE; + boolean[] visit = new boolean[n + 1]; + Stack stack = new Stack<>(); + stack.push(1); + visit[1] = true; + + while (!stack.isEmpty()) { + int node = stack.pop(); + for (int[] edge : adj[node]) { + int nei = edge[0], dist = edge[1]; + res = Math.min(res, dist); + if (!visit[nei]) { + visit[nei] = true; + stack.push(nei); + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int minScore(int n, vector>& roads) { + vector>> adj(n + 1); + for (auto& road : roads) { + adj[road[0]].emplace_back(road[1], road[2]); + adj[road[1]].emplace_back(road[0], road[2]); + } + + int res = INT_MAX; + vector visit(n + 1, false); + stack stk; + stk.push(1); + visit[1] = true; + + while (!stk.empty()) { + int node = stk.top();stk.pop(); + for (auto& [nei, dist] : adj[node]) { + res = min(res, dist); + if (!visit[nei]) { + visit[nei] = true; + stk.push(nei); + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} roads + * @return {number} + */ + minScore(n, roads) { + const adj = Array.from({ length: n + 1 }, () => []); + for (const [src, dst, dist] of roads) { + adj[src].push([dst, dist]); + adj[dst].push([src, dist]); + } + + let res = Infinity; + const visit = new Array(n + 1).fill(false); + const stack = [1]; + visit[1] = true; + + while (stack.length) { + const node = stack.pop(); + for (const [nei, dist] of adj[node]) { + res = Math.min(res, dist); + if (!visit[nei]) { + visit[nei] = true; + stack.push(nei); + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 4. Disjoint Set Union + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.Parent = list(range(n + 1)) + self.Size = [1] * (n + 1) + + def find(self, node): + if self.Parent[node] != node: + self.Parent[node] = self.find(self.Parent[node]) + return self.Parent[node] + + def union(self, u, v): + pu, pv = self.find(u), self.find(v) + if pu == pv: + return False + if self.Size[pu] >= self.Size[pv]: + self.Size[pu] += self.Size[pv] + self.Parent[pv] = pu + else: + self.Size[pv] += self.Size[pu] + self.Parent[pu] = pv + return True + +class Solution: + def minScore(self, n: int, roads: list[list[int]]) -> int: + dsu = DSU(n) + for src, dst, _ in roads: + dsu.union(src, dst) + + res = float("inf") + root = dsu.find(1) + for src, dst, dist in roads: + if dsu.find(src) == root: + res = min(res, dist) + + return res +``` + +```java +class DSU { + int[] parent, size; + + public DSU(int n) { + parent = new int[n + 1]; + size = new int[n + 1]; + for (int i = 0; i <= n; i++) { + parent[i] = i; + size[i] = 1; + } + } + + public int find(int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + public boolean union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (size[pu] >= size[pv]) { + size[pu] += size[pv]; + parent[pv] = pu; + } else { + size[pv] += size[pu]; + parent[pu] = pv; + } + return true; + } +} + +public class Solution { + public int minScore(int n, int[][] roads) { + DSU dsu = new DSU(n); + for (int[] road : roads) { + dsu.union(road[0], road[1]); + } + + int res = Integer.MAX_VALUE; + int root = dsu.find(1); + for (int[] road : roads) { + if (dsu.find(road[0]) == root) { + res = Math.min(res, road[2]); + } + } + + return res; + } +} +``` + +```cpp +class DSU { +public: + vector parent, size; + + DSU(int n) { + parent.resize(n + 1); + size.resize(n + 1, 1); + for (int i = 0; i <= n; i++) { + parent[i] = i; + } + } + + int find(int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + bool unionSets(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (size[pu] >= size[pv]) { + size[pu] += size[pv]; + parent[pv] = pu; + } else { + size[pv] += size[pu]; + parent[pu] = pv; + } + return true; + } +}; + +class Solution { +public: + int minScore(int n, vector>& roads) { + DSU dsu(n); + for (auto& road : roads) { + dsu.unionSets(road[0], road[1]); + } + + int res = INT_MAX; + int root = dsu.find(1); + for (auto& road : roads) { + if (dsu.find(road[0]) == root) { + res = min(res, road[2]); + } + } + + return res; + } +}; +``` + +```javascript +class DSU { + /** + * @constructor + * @param {number} n + */ + constructor(n) { + this.parent = Array.from({ length: n + 1 }, (_, i) => i); + this.size = new Array(n + 1).fill(1); + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.parent[node] !== node) { + this.parent[node] = this.find(this.parent[node]); + } + return this.parent[node]; + } + + /** + * @param {number} u + * @param {number} u=v + * @return {boolean} + */ + union(u, v) { + let pu = this.find(u), + pv = this.find(v); + if (pu === pv) return false; + if (this.size[pu] >= this.size[pv]) { + this.size[pu] += this.size[pv]; + this.parent[pv] = pu; + } else { + this.size[pv] += this.size[pu]; + this.parent[pu] = pv; + } + return true; + } +} + +class Solution { + /** + * @param {number} n + * @param {number[][]} roads + * @return {number} + */ + minScore(n, roads) { + const dsu = new DSU(n); + for (const [src, dst] of roads) { + dsu.union(src, dst); + } + + let res = Infinity; + const root = dsu.find(1); + for (const [src, dst, dist] of roads) { + if (dsu.find(src) === root) { + res = Math.min(res, dist); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + (E * α(V)))$ +- Space complexity: $O(V)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges in the graph. $α()$ is used for amortized complexity. diff --git a/articles/minimum-size-subarray-sum.md b/articles/minimum-size-subarray-sum.md index 74be08d78..0c56b14b5 100644 --- a/articles/minimum-size-subarray-sum.md +++ b/articles/minimum-size-subarray-sum.md @@ -15,7 +15,7 @@ class Solution: if curSum >= target: res = min(res, j - i + 1) break - + return 0 if res == float("inf") else res ``` @@ -24,7 +24,7 @@ public class Solution { public int minSubArrayLen(int target, int[] nums) { int n = nums.length; int res = Integer.MAX_VALUE; - + for (int i = 0; i < n; i++) { int curSum = 0, j = i; while (j < n) { @@ -36,7 +36,7 @@ public class Solution { j++; } } - + return res == Integer.MAX_VALUE ? 0 : res; } } @@ -48,7 +48,7 @@ public: int minSubArrayLen(int target, vector& nums) { int n = nums.size(); int res = INT_MAX; - + for (int i = 0; i < n; i++) { int curSum = 0, j = i; while (j < n) { @@ -60,7 +60,7 @@ public: j++; } } - + return res == INT_MAX ? 0 : res; } }; @@ -75,10 +75,11 @@ class Solution { */ minSubArrayLen(target, nums) { let n = nums.length; - let res = Infinity; - + let res = Infinity; + for (let i = 0; i < n; i++) { - let curSum = 0, j = i; + let curSum = 0, + j = i; while (j < n) { curSum += nums[j]; if (curSum >= target) { @@ -88,18 +89,40 @@ class Solution { j++; } } - + return res == Infinity ? 0 : res; } } ``` +```csharp +public class Solution { + public int MinSubArrayLen(int target, int[] nums) { + int n = nums.Length; + int res = int.MaxValue; + + for (int i = 0; i < n; i++) { + int curSum = 0; + for (int j = i; j < n; j++) { + curSum += nums[j]; + if (curSum >= target) { + res = Math.Min(res, j - i + 1); + break; + } + } + } + + return res == int.MaxValue ? 0 : res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. --- @@ -171,7 +194,8 @@ class Solution { * @return {number} */ minSubArrayLen(target, nums) { - let l = 0, total = 0; + let l = 0, + total = 0; let res = Infinity; for (let r = 0; r < nums.length; r++) { @@ -188,12 +212,33 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinSubArrayLen(int target, int[] nums) { + int l = 0, total = 0; + int res = int.MaxValue; + + for (int r = 0; r < nums.Length; r++) { + total += nums[r]; + + while (total >= target) { + res = Math.Min(res, r - l + 1); + total -= nums[l]; + l++; + } + } + + return res == int.MaxValue ? 0 : res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -208,7 +253,7 @@ class Solution: prefixSum = [0] * (n + 1) for i in range(n): prefixSum[i + 1] = prefixSum[i] + nums[i] - + res = n + 1 for i in range(n): l, r = i, n @@ -233,7 +278,7 @@ public class Solution { for (int i = 0; i < n; i++) { prefixSum[i + 1] = prefixSum[i] + nums[i]; } - + int res = n + 1; for (int i = 0; i < n; i++) { int l = i, r = n; @@ -265,7 +310,7 @@ public: for (int i = 0; i < n; i++) { prefixSum[i + 1] = prefixSum[i] + nums[i]; } - + int res = n + 1; for (int i = 0; i < n; i++) { int l = i, r = n; @@ -301,10 +346,11 @@ class Solution { for (let i = 0; i < n; i++) { prefixSum[i + 1] = prefixSum[i] + nums[i]; } - + let res = n + 1; for (let i = 0; i < n; i++) { - let l = i, r = n; + let l = i, + r = n; while (l < r) { const mid = Math.floor((l + r) / 2); const curSum = prefixSum[mid + 1] - prefixSum[i]; @@ -324,9 +370,42 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinSubArrayLen(int target, int[] nums) { + int n = nums.Length; + int[] prefixSum = new int[n + 1]; + + for (int i = 0; i < n; i++) { + prefixSum[i + 1] = prefixSum[i] + nums[i]; + } + + int res = n + 1; + + for (int i = 0; i < n; i++) { + int l = i, r = n; + while (l < r) { + int mid = (l + r) / 2; + int curSum = prefixSum[mid + 1] - prefixSum[i]; + if (curSum >= target) { + r = mid; + } else { + l = mid + 1; + } + } + if (l != n) { + res = Math.Min(res, l - i + 1); + } + } + + return res % (n + 1); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/minimum-stack.md b/articles/minimum-stack.md index 28527e995..5fa5c90e5 100644 --- a/articles/minimum-stack.md +++ b/articles/minimum-stack.md @@ -24,10 +24,10 @@ class MinStack: while len(self.stack): mini = min(mini, self.stack[-1]) tmp.append(self.stack.pop()) - + while len(tmp): self.stack.append(tmp.pop()) - + return mini ``` @@ -39,19 +39,19 @@ class MinStack { public MinStack() { stack = new Stack<>(); } - + public void push(int val) { stack.push(val); } - + public void pop() { stack.pop(); } - + public int top() { return stack.peek(); } - + public int getMin() { Stack tmp = new Stack<>(); int mini = stack.peek(); @@ -60,11 +60,11 @@ class MinStack { mini = Math.min(mini, stack.peek()); tmp.push(stack.pop()); } - + while (!tmp.isEmpty()) { stack.push(tmp.pop()); } - + return mini; } } @@ -75,21 +75,21 @@ class MinStack { public: stack stk; MinStack() { - + } - + void push(int val) { stk.push(val); } - + void pop() { stk.pop(); } - + int top() { return stk.top(); } - + int getMin() { stack tmp; int mini = stk.top(); @@ -165,19 +165,19 @@ public class MinStack { public MinStack() { stack = new Stack(); } - + public void Push(int val) { stack.Push(val); } - + public void Pop() { stack.Pop(); } - + public int Top() { return stack.Peek(); } - + public int GetMin() { Stack tmp = new Stack(); int mini = stack.Peek(); @@ -186,11 +186,11 @@ public class MinStack { mini = System.Math.Min(mini, stack.Peek()); tmp.Push(stack.Pop()); } - + while (tmp.Count > 0) { stack.Push(tmp.Pop()); } - + return mini; } } @@ -278,12 +278,48 @@ class MinStack() { } ``` +```swift +class MinStack { + private var stack: [Int] = [] + + init() {} + + func push(_ val: Int) { + stack.append(val) + } + + func pop() { + stack.popLast() + } + + func top() -> Int { + return stack.last! + } + + func getMin() -> Int { + var tmp = [Int]() + var mini = stack.last! + + while !stack.isEmpty { + mini = min(mini, stack.last!) + tmp.append(stack.removeLast()) + } + + while !tmp.isEmpty { + stack.append(tmp.removeLast()) + } + + return mini + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ for $getMin()$ and $O(1)$ for other operations. -* Space complexity: $O(n)$ for $getMin()$ and $O(1)$ for other operations. +- Time complexity: $O(n)$ for $getMin()$ and $O(1)$ for other operations. +- Space complexity: $O(n)$ for $getMin()$ and $O(1)$ for other operations. --- @@ -322,14 +358,14 @@ public class MinStack { stack = new Stack<>(); minStack = new Stack<>(); } - + public void push(int val) { stack.push(val); if (minStack.isEmpty() || val <= minStack.peek()) { minStack.push(val); } } - + public void pop() { if (stack.isEmpty()) return; int top = stack.pop(); @@ -337,11 +373,11 @@ public class MinStack { minStack.pop(); } } - + public int top() { return stack.peek(); } - + public int getMin() { return minStack.peek(); } @@ -426,7 +462,7 @@ class MinStack { ```csharp public class MinStack { - + private Stack stack; private Stack minStack; @@ -524,12 +560,40 @@ class MinStack() { } ``` +```swift +class MinStack { + private var stack: [Int] = [] + private var minStack: [Int] = [] + + init() {} + + func push(_ val: Int) { + stack.append(val) + let minVal = min(val, minStack.last ?? val) + minStack.append(minVal) + } + + func pop() { + stack.popLast() + minStack.popLast() + } + + func top() -> Int { + return stack.last! + } + + func getMin() -> Int { + return minStack.last! + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ for all operations. -* Space complexity: $O(n)$ +- Time complexity: $O(1)$ for all operations. +- Space complexity: $O(n)$ --- @@ -543,21 +607,21 @@ class MinStack: self.min = float('inf') self.stack = [] - def push(self, x: int) -> None: + def push(self, val: int) -> None: if not self.stack: self.stack.append(0) - self.min = x + self.min = val else: - self.stack.append(x - self.min) - if x < self.min: - self.min = x + self.stack.append(val - self.min) + if val < self.min: + self.min = val def pop(self) -> None: if not self.stack: return - + pop = self.stack.pop() - + if pop < 0: self.min = self.min - pop @@ -580,22 +644,22 @@ public class MinStack { public MinStack() { stack = new Stack<>(); } - - public void push(int x) { + + public void push(int val) { if (stack.isEmpty()) { stack.push(0L); - min = x; + min = val; } else { - stack.push(x - min); - if (x < min) min = x; + stack.push(val - min); + if (val < min) min = val; } } public void pop() { if (stack.isEmpty()) return; - + long pop = stack.pop(); - + if (pop < 0) min = min - pop; } @@ -621,10 +685,8 @@ private: std::stack stack; public: - MinStack() { - - } - + MinStack() {} + void push(int val) { if (stack.empty()) { stack.push(0); @@ -634,21 +696,21 @@ public: if (val < min) min = val; } } - + void pop() { if (stack.empty()) return; - + long pop = stack.top(); stack.pop(); - + if (pop < 0) min = min - pop; } - + int top() { long top = stack.top(); return (top > 0) ? (top + min) : (int)min; } - + int getMin() { return (int)min; } @@ -755,14 +817,14 @@ func Constructor() MinStack { } } -func (this *MinStack) Push(x int) { +func (this *MinStack) Push(val int) { if len(this.stack) == 0 { this.stack = append(this.stack, 0) - this.min = x + this.min = val } else { - this.stack = append(this.stack, x - this.min) - if x < this.min { - this.min = x + this.stack = append(this.stack, val - this.min) + if val < this.min { + this.min = val } } } @@ -796,8 +858,8 @@ class MinStack() { private var min: Long = Long.MAX_VALUE private val stack = ArrayDeque() - fun push(x: Int) { - val valAsLong = x.toLong() + fun push(`val`: Int) { + val valAsLong = `val`.toLong() if (stack.isEmpty()) { stack.addLast(0L) min = valAsLong @@ -828,9 +890,51 @@ class MinStack() { } ``` +```swift +class MinStack { + private var minVal: Int = Int.max + private var stack: [Int] = [] + + init() {} + + func push(_ val: Int) { + if stack.isEmpty { + stack.append(0) + minVal = val + } else { + stack.append(val - minVal) + if val < minVal { + minVal = val + } + } + } + + func pop() { + if stack.isEmpty { + return + } + + let pop = stack.removeLast() + + if pop < 0 { + minVal -= pop + } + } + + func top() -> Int { + let top = stack.last! + return top > 0 ? top + minVal : minVal + } + + func getMin() -> Int { + return minVal + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ for all operations. -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(1)$ for all operations. +- Space complexity: $O(n)$ diff --git a/articles/minimum-time-to-collect-all-apples-in-a-tree.md b/articles/minimum-time-to-collect-all-apples-in-a-tree.md new file mode 100644 index 000000000..8ad4a4804 --- /dev/null +++ b/articles/minimum-time-to-collect-all-apples-in-a-tree.md @@ -0,0 +1,312 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def minTime(self, n: int, edges: List[List[int]], hasApple: List[bool]) -> int: + adj = {i: [] for i in range(n)} + for par, child in edges: + adj[par].append(child) + adj[child].append(par) + + def dfs(cur, par): + time = 0 + for child in adj[cur]: + if child == par: + continue + childTime = dfs(child, cur) + if childTime > 0 or hasApple[child]: + time += 2 + childTime + return time + + return dfs(0, -1) +``` + +```java +public class Solution { + public int minTime(int n, int[][] edges, List hasApple) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + adj[edge[1]].add(edge[0]); + } + + return dfs(0, -1, adj, hasApple); + } + + private int dfs(int cur, int parent, List[] adj, List hasApple) { + int time = 0; + for (int child : adj[cur]) { + if (child == parent) continue; + int childTime = dfs(child, cur, adj, hasApple); + if (childTime > 0 || hasApple.get(child)) { + time += 2 + childTime; + } + } + return time; + } +} +``` + +```cpp +class Solution { +public: + int minTime(int n, vector>& edges, vector& hasApple) { + vector> adj(n); + for (const auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + adj[edge[1]].push_back(edge[0]); + } + + return dfs(0, -1, adj, hasApple); + } + +private: + int dfs(int cur, int parent, vector>& adj, vector& hasApple) { + int time = 0; + for (int child : adj[cur]) { + if (child == parent) continue; + int childTime = dfs(child, cur, adj, hasApple); + if (childTime > 0 || hasApple[child]) { + time += 2 + childTime; + } + } + return time; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @param {boolean[]} hasApple + * @return {number} + */ + minTime(n, edges, hasApple) { + const adj = Array.from({ length: n }, () => []); + for (const [parent, child] of edges) { + adj[parent].push(child); + adj[child].push(parent); + } + + const dfs = (cur, parent) => { + let time = 0; + for (const child of adj[cur]) { + if (child === parent) continue; + const childTime = dfs(child, cur); + if (childTime > 0 || hasApple[child]) { + time += 2 + childTime; + } + } + return time; + }; + + return dfs(0, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 2. Topological Sort (Kahn's Algorithm) + +::tabs-start + +```python +class Solution: + def minTime(self, n: int, edges: List[List[int]], hasApple: List[bool]) -> int: + adj = defaultdict(list) + indegree = [0] * n + for u, v in edges: + adj[u].append(v) + adj[v].append(u) + indegree[u] += 1 + indegree[v] += 1 + + queue = deque() + for i in range(1, n): + if indegree[i] == 1: + queue.append(i) + indegree[i] = 0 + + time = [0] * n + while queue: + node = queue.popleft() + for nei in adj[node]: + if indegree[nei] <= 0: + continue + + indegree[nei] -= 1 + if hasApple[node] or time[node] > 0: + time[nei] += time[node] + 2 + if indegree[nei] == 1 and nei != 0: + queue.append(nei) + + return time[0] +``` + +```java +public class Solution { + public int minTime(int n, int[][] edges, List hasApple) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + int[] indegree = new int[n]; + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + adj[edge[1]].add(edge[0]); + indegree[edge[0]]++; + indegree[edge[1]]++; + } + + Queue queue = new LinkedList<>(); + for (int i = 1; i < n; i++) { + if (indegree[i] == 1) { + queue.offer(i); + indegree[i] = 0; + } + } + + int[] time = new int[n]; + while (!queue.isEmpty()) { + int node = queue.poll(); + for (int neighbor : adj[node]) { + if (indegree[neighbor] <= 0) { + continue; + } + + indegree[neighbor]--; + if (hasApple.get(node) || time[node] > 0) { + time[neighbor] += time[node] + 2; + } + if (indegree[neighbor] == 1 && neighbor != 0) { + queue.offer(neighbor); + } + } + } + + return time[0]; + } +} +``` + +```cpp +class Solution { +public: + int minTime(int n, vector>& edges, vector& hasApple) { + vector> adj(n); + vector indegree(n, 0); + + for (const auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + adj[edge[1]].push_back(edge[0]); + indegree[edge[0]]++; + indegree[edge[1]]++; + } + + queue q; + for (int i = 1; i < n; ++i) { + if (indegree[i] == 1) { + q.push(i); + indegree[i] = 0; + } + } + + vector time(n, 0); + while (!q.empty()) { + int node = q.front(); + q.pop(); + for (int neighbor : adj[node]) { + if (indegree[neighbor] <= 0) { + continue; + } + + indegree[neighbor]--; + if (hasApple[node] || time[node] > 0) { + time[neighbor] += time[node] + 2; + } + if (indegree[neighbor] == 1 && neighbor != 0) { + q.push(neighbor); + } + } + } + + return time[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @param {boolean[]} hasApple + * @return {number} + */ + minTime(n, edges, hasApple) { + const adj = Array.from({ length: n }, () => []); + const indegree = Array(n).fill(0); + + for (const [u, v] of edges) { + adj[u].push(v); + adj[v].push(u); + indegree[u]++; + indegree[v]++; + } + + const queue = new Queue(); + for (let i = 1; i < n; i++) { + if (indegree[i] === 1) { + queue.push(i); + indegree[i] = 0; + } + } + + const time = Array(n).fill(0); + while (!queue.isEmpty()) { + const node = queue.pop(); + for (const neighbor of adj[node]) { + if (indegree[neighbor] <= 0) { + continue; + } + + indegree[neighbor]--; + if (hasApple[node] || time[node] > 0) { + time[neighbor] += time[node] + 2; + } + if (indegree[neighbor] === 1 && neighbor !== 0) { + queue.push(neighbor); + } + } + } + + return time[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. diff --git a/articles/minimum-time-to-make-rope-colorful.md b/articles/minimum-time-to-make-rope-colorful.md new file mode 100644 index 000000000..785132df6 --- /dev/null +++ b/articles/minimum-time-to-make-rope-colorful.md @@ -0,0 +1,275 @@ +## 1. Two Pointers - I + +::tabs-start + +```python +class Solution: + def minCost(self, colors: str, neededTime: List[int]) -> int: + n = len(neededTime) + res = i = 0 + while i < n: + j = i + maxi = curr = 0 + while j < n and colors[j] == colors[i]: + maxi = max(maxi, neededTime[j]) + curr += neededTime[j] + j += 1 + res += curr - maxi + i = j + return res +``` + +```java +public class Solution { + public int minCost(String colors, int[] neededTime) { + int n = neededTime.length; + int res = 0, i = 0; + while (i < n) { + int j = i, maxi = 0, curr = 0; + while (j < n && colors.charAt(j) == colors.charAt(i)) { + maxi = Math.max(maxi, neededTime[j]); + curr += neededTime[j]; + j++; + } + res += curr - maxi; + i = j; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minCost(string colors, vector& neededTime) { + int n = neededTime.size(); + int res = 0, i = 0; + while (i < n) { + int j = i, maxi = 0, curr = 0; + while (j < n && colors[j] == colors[i]) { + maxi = max(maxi, neededTime[j]); + curr += neededTime[j]; + j++; + } + res += curr - maxi; + i = j; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @param {number[]} neededTime + * @return {number} + */ + minCost(colors, neededTime) { + const n = neededTime.length; + let res = 0, + i = 0; + while (i < n) { + let j = i, + maxi = 0, + curr = 0; + while (j < n && colors[j] === colors[i]) { + maxi = Math.max(maxi, neededTime[j]); + curr += neededTime[j]; + j++; + } + res += curr - maxi; + i = j; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 2. Two Pointers - II + +::tabs-start + +```python +class Solution: + def minCost(self, colors: str, neededTime: List[int]) -> int: + l, res = 0, 0 + for r in range(1, len(colors)): + if colors[l] == colors[r]: + if neededTime[l] < neededTime[r]: + res += neededTime[l] + l = r + else: + res += neededTime[r] + else: + l = r + return res +``` + +```java +public class Solution { + public int minCost(String colors, int[] neededTime) { + int l = 0, res = 0; + for (int r = 1; r < colors.length(); r++) { + if (colors.charAt(l) == colors.charAt(r)) { + if (neededTime[l] < neededTime[r]) { + res += neededTime[l]; + l = r; + } else { + res += neededTime[r]; + } + } else { + l = r; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minCost(string colors, vector& neededTime) { + int l = 0, res = 0; + for (int r = 1; r < colors.size(); r++) { + if (colors[l] == colors[r]) { + if (neededTime[l] < neededTime[r]) { + res += neededTime[l]; + l = r; + } else { + res += neededTime[r]; + } + } else { + l = r; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @param {number[]} neededTime + * @return {number} + */ + minCost(colors, neededTime) { + let l = 0, + res = 0; + for (let r = 1; r < colors.length; r++) { + if (colors[l] === colors[r]) { + if (neededTime[l] < neededTime[r]) { + res += neededTime[l]; + l = r; + } else { + res += neededTime[r]; + } + } else { + l = r; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 3. Two Pointers - III + +::tabs-start + +```python +class Solution: + def minCost(self, colors: str, neededTime: List[int]) -> int: + res = maxi = 0 + for i in range(len(colors)): + if i and colors[i] != colors[i - 1]: + maxi = 0 + res += min(maxi, neededTime[i]) + maxi = max(maxi, neededTime[i]) + return res +``` + +```java +public class Solution { + public int minCost(String colors, int[] neededTime) { + int res = 0, maxi = 0; + for (int i = 0; i < colors.length(); i++) { + if (i > 0 && colors.charAt(i) != colors.charAt(i - 1)) { + maxi = 0; + } + res += Math.min(maxi, neededTime[i]); + maxi = Math.max(maxi, neededTime[i]); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int minCost(string colors, vector& neededTime) { + int res = 0, maxi = 0; + for (int i = 0; i < colors.size(); i++) { + if (i > 0 && colors[i] != colors[i - 1]) { + maxi = 0; + } + res += min(maxi, neededTime[i]); + maxi = max(maxi, neededTime[i]); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @param {number[]} neededTime + * @return {number} + */ + minCost(colors, neededTime) { + let res = 0, + maxi = 0; + for (let i = 0; i < colors.length; i++) { + if (i > 0 && colors[i] !== colors[i - 1]) { + maxi = 0; + } + res += Math.min(maxi, neededTime[i]); + maxi = Math.max(maxi, neededTime[i]); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/minimum-window-with-characters.md b/articles/minimum-window-with-characters.md index 9e0b36005..36dfc746e 100644 --- a/articles/minimum-window-with-characters.md +++ b/articles/minimum-window-with-characters.md @@ -23,7 +23,7 @@ class Solution: if countT[c] > countS.get(c, 0): flag = False break - + if flag and (j - i + 1) < resLen: resLen = j - i + 1 res = [i, j] @@ -118,7 +118,7 @@ class Solution { * @return {string} */ minWindow(s, t) { - if (t === "") return ""; + if (t === '') return ''; let countT = {}; for (let c of t) { @@ -141,14 +141,14 @@ class Solution { } } - if (flag && (j - i + 1) < resLen) { + if (flag && j - i + 1 < resLen) { resLen = j - i + 1; res = [i, j]; } } } - return resLen === Infinity ? "" : s.slice(res[0], res[1] + 1); + return resLen === Infinity ? '' : s.slice(res[0], res[1] + 1); } } ``` @@ -212,7 +212,7 @@ func minWindow(s string, t string) string { } res := []int{-1, -1} - resLen := int(^uint(0) >> 1) + resLen := int(^uint(0) >> 1) for i := 0; i < len(s); i++ { countS := make(map[rune]int) for j := i; j < len(s); j++ { @@ -252,7 +252,7 @@ class Solution { var res = IntArray(2) {-1} var resLen = Int.MAX_VALUE - + for (i in s.indices) { val countS = HashMap() for (j in i until s.length) { @@ -279,12 +279,54 @@ class Solution { } ``` +```swift +class Solution { + func minWindow(_ s: String, _ t: String) -> String { + if t.isEmpty { + return "" + } + + var countT = [Character: Int]() + for c in t { + countT[c, default: 0] += 1 + } + + var res = [-1, -1] + var resLen = Int.max + let chars = Array(s) + + for i in 0.. countS[c, default: 0] { + flag = false + break + } + } + + if flag && (j - i + 1) < resLen { + resLen = j - i + 1 + res = [i, j] + } + } + } + + let (l, r) = (res[0], res[1]) + return resLen != Int.max ? String(chars[l...r]) : "" + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n ^ 2 * m)$ +- Space complexity: $O(m)$ > Where $n$ is the length of the string $s$ and $m$ is the total number of unique characters in the strings $t$ and $s$. @@ -318,7 +360,7 @@ class Solution: if (r - l + 1) < resLen: res = [l, r] resLen = r - l + 1 - + window[s[l]] -= 1 if s[l] in countT and window[s[l]] < countT[s[l]]: have -= 1 @@ -423,7 +465,7 @@ class Solution { * @return {string} */ minWindow(s, t) { - if (t === "") return ""; + if (t === '') return ''; let countT = {}; let window = {}; @@ -431,7 +473,8 @@ class Solution { countT[c] = (countT[c] || 0) + 1; } - let have = 0, need = Object.keys(countT).length; + let have = 0, + need = Object.keys(countT).length; let res = [-1, -1]; let resLen = Infinity; let l = 0; @@ -445,7 +488,7 @@ class Solution { } while (have === need) { - if ((r - l + 1) < resLen) { + if (r - l + 1 < resLen) { resLen = r - l + 1; res = [l, r]; } @@ -458,7 +501,7 @@ class Solution { } } - return resLen === Infinity ? "" : s.slice(res[0], res[1] + 1); + return resLen === Infinity ? '' : s.slice(res[0], res[1] + 1); } } ``` @@ -608,11 +651,58 @@ class Solution { } ``` +```swift +class Solution { + func minWindow(_ s: String, _ t: String) -> String { + if t.isEmpty { + return "" + } + + var countT = [Character: Int]() + var window = [Character: Int]() + for c in t { + countT[c, default: 0] += 1 + } + + var have = 0, need = countT.count + var res = [-1, -1], resLen = Int.max + let chars = Array(s) + var l = 0 + + for r in 0.. Where $n$ is the length of the string $s$ and $m$ is the total number of unique characters in the strings $t$ and $s$. \ No newline at end of file +> Where $n$ is the length of the string $s$ and $m$ is the total number of unique characters in the strings $t$ and $s$. diff --git a/articles/missing-number.md b/articles/missing-number.md index 0ddb891db..1034fab68 100644 --- a/articles/missing-number.md +++ b/articles/missing-number.md @@ -106,12 +106,27 @@ class Solution { } ``` +```swift +class Solution { + func missingNumber(_ nums: [Int]) -> Int { + var nums = nums.sorted() + let n = nums.count + for i in 0.. Int { + let numSet = Set(nums) + let n = nums.count + for i in 0...n { + if !numSet.contains(i) { + return i + } + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -244,7 +274,7 @@ class Solution { class Solution: def missingNumber(self, nums: List[int]) -> int: n = len(nums) - xorr = n + xorr = n for i in range(n): xorr ^= i ^ nums[i] return xorr @@ -254,7 +284,7 @@ class Solution: public class Solution { public int missingNumber(int[] nums) { int n = nums.length; - int xorr = n; + int xorr = n; for (int i = 0; i < n; i++) { xorr ^= i ^ nums[i]; } @@ -268,7 +298,7 @@ class Solution { public: int missingNumber(vector& nums) { int n = nums.size(); - int xorr = n; + int xorr = n; for (int i = 0; i < n; i++) { xorr ^= i ^ nums[i]; } @@ -285,7 +315,7 @@ class Solution { */ missingNumber(nums) { let n = nums.length; - let xorr = n; + let xorr = n; for (let i = 0; i < n; i++) { xorr ^= i ^ nums[i]; } @@ -298,7 +328,7 @@ class Solution { public class Solution { public int MissingNumber(int[] nums) { int n = nums.Length; - int xorr = n; + int xorr = n; for (int i = 0; i < n; i++) { xorr ^= i ^ nums[i]; } @@ -331,12 +361,27 @@ class Solution { } ``` +```swift +class Solution { + func missingNumber(_ nums: [Int]) -> Int { + let n = nums.count + var xorr = n + + for i in 0.. Int { + var res = nums.count + + for i in 0..(); + foreach (var num in nums) { + if (num != 0) { + tmp.Add(num); + } + } + for (int i = 0; i < nums.Length; i++) { + if (i < tmp.Count) { + nums[i] = tmp[i]; + } else { + nums[i] = 0; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- ## 2. Two Pointers (Two Pass) + ::tabs-start ```python @@ -111,7 +132,7 @@ class Solution: if nums[r] != 0: nums[l] = nums[r] l += 1 - + while l < len(nums): nums[l] = 0 l += 1 @@ -173,12 +194,30 @@ class Solution { } ``` +```csharp +public class Solution { + public void MoveZeroes(int[] nums) { + int l = 0; + for (int r = 0; r < nums.Length; r++) { + if (nums[r] != 0) { + nums[l] = nums[r]; + l++; + } + } + while (l < nums.Length) { + nums[l] = 0; + l++; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -210,7 +249,7 @@ public class Solution { nums[r] = temp; l++; } - } + } } } ``` @@ -245,9 +284,25 @@ class Solution { } ``` +```csharp +public class Solution { + public void MoveZeroes(int[] nums) { + int l = 0; + for (int r = 0; r < nums.Length; r++) { + if (nums[r] != 0) { + int temp = nums[l]; + nums[l] = nums[r]; + nums[r] = temp; + l++; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/multiply-strings.md b/articles/multiply-strings.md index e47825f08..19fc7cd99 100644 --- a/articles/multiply-strings.md +++ b/articles/multiply-strings.md @@ -7,18 +7,18 @@ class Solution: def multiply(self, num1: str, num2: str) -> str: if num1 == "0" or num2 == "0": return "0" - + if len(num1) < len(num2): return self.multiply(num2, num1) - + res, zero = "", 0 for i in range(len(num2) - 1, -1, -1): cur = self.mul(num1, num2[i], zero) res = self.add(res, cur) zero += 1 - + return res - + def mul(self, s: str, d: str, zero: int) -> str: i, carry = len(s) - 1, 0 d = int(d) @@ -30,7 +30,7 @@ class Solution: cur.append(str(prod % 10)) carry = prod // 10 i -= 1 - + return ''.join(cur[::-1]) + '0' * zero def add(self, num1: str, num2: str) -> str: @@ -45,7 +45,7 @@ class Solution: carry = total // 10 i -= 1 j -= 1 - + return ''.join(res[::-1]) ``` @@ -57,7 +57,7 @@ public class Solution { if (num1.length() < num2.length()) { return multiply(num2, num1); } - + String res = ""; int zero = 0; for (int i = num2.length() - 1; i >= 0; i--) { @@ -65,10 +65,10 @@ public class Solution { res = add(res, cur); zero++; } - + return res; } - + private String mul(String s, char d, int zero) { int i = s.length() - 1, carry = 0; int digit = d - '0'; @@ -81,7 +81,7 @@ public class Solution { carry = prod / 10; i--; } - + return cur.reverse().toString() + "0".repeat(zero); } @@ -98,7 +98,7 @@ public class Solution { i--; j--; } - + return res.reverse().toString(); } } @@ -109,11 +109,11 @@ class Solution { public: string multiply(string num1, string num2) { if (num1 == "0" || num2 == "0") return "0"; - + if (num1.size() < num2.size()) { return multiply(num2, num1); } - + string res = ""; int zero = 0; for (int i = num2.size() - 1; i >= 0; --i) { @@ -121,10 +121,10 @@ public: res = add(res, cur); zero++; } - + return res; } - + string mul(string s, char d, int zero) { int i = s.size() - 1, carry = 0; int digit = d - '0'; @@ -137,7 +137,7 @@ public: carry = prod / 10; i--; } - + reverse(cur.begin(), cur.end()); return cur + string(zero, '0'); } @@ -155,7 +155,7 @@ public: i--; j--; } - + reverse(res.begin(), res.end()); return res; } @@ -170,23 +170,23 @@ class Solution { * @return {string} */ multiply(num1, num2) { - if (num1 === "0" || num2 === "0") return "0"; + if (num1 === '0' || num2 === '0') return '0'; if (num1.length < num2.length) { return this.multiply(num2, num1); } - - let res = ""; + + let res = ''; let zero = 0; for (let i = num2.length - 1; i >= 0; i--) { const cur = this.mul(num1, num2[i], zero); res = this.add(res, cur); zero++; } - + return res; } - + /** * @param {string} s * @param {Character} d @@ -197,7 +197,7 @@ class Solution { let i = s.length - 1; let carry = 0; const digit = Number(d); - let cur = ""; + let cur = ''; while (i >= 0 || carry) { const n = i >= 0 ? Number(s[i]) : 0; @@ -206,8 +206,8 @@ class Solution { carry = Math.floor(prod / 10); i--; } - - return cur + "0".repeat(zero); + + return cur + '0'.repeat(zero); } /** @@ -216,8 +216,10 @@ class Solution { * @return {string} */ add(num1, num2) { - let i = num1.length - 1, j = num2.length - 1, carry = 0; - let res = ""; + let i = num1.length - 1, + j = num2.length - 1, + carry = 0; + let res = ''; while (i >= 0 || j >= 0 || carry) { const n1 = i >= 0 ? Number(num1[i]) : 0; @@ -228,7 +230,7 @@ class Solution { i--; j--; } - + return res; } } @@ -242,7 +244,7 @@ public class Solution { if (num1.Length < num2.Length) { return Multiply(num2, num1); } - + string res = ""; int zero = 0; for (int i = num2.Length - 1; i >= 0; i--) { @@ -250,10 +252,10 @@ public class Solution { res = Add(res, cur); zero++; } - + return res; } - + private string Mul(string s, char d, int zero) { int i = s.Length - 1, carry = 0; int digit = d - '0'; @@ -266,7 +268,7 @@ public class Solution { carry = prod / 10; i--; } - + cur.Reverse(); return new string(cur.ToArray()) + new string('0', zero); } @@ -284,7 +286,7 @@ public class Solution { i--; j--; } - + res.Reverse(); return new string(res.ToArray()); } @@ -296,18 +298,18 @@ func multiply(num1 string, num2 string) string { if num1 == "0" || num2 == "0" { return "0" } - + if len(num1) < len(num2) { return multiply(num2, num1) } - + res, zero := "", 0 for i := len(num2) - 1; i >= 0; i-- { cur := mul(num1, num2[i], zero) res = add(res, cur) zero++ } - + return res } @@ -315,7 +317,7 @@ func mul(s string, d byte, zero int) string { i, carry := len(s)-1, 0 d = d - '0' cur := make([]byte, 0) - + for i >= 0 || carry > 0 { var n int if i >= 0 { @@ -326,11 +328,11 @@ func mul(s string, d byte, zero int) string { carry = prod / 10 i-- } - + for i := 0; i < len(cur)/2; i++ { cur[i], cur[len(cur)-1-i] = cur[len(cur)-1-i], cur[i] } - + result := string(cur) for i := 0; i < zero; i++ { result += "0" @@ -341,7 +343,7 @@ func mul(s string, d byte, zero int) string { func add(num1 string, num2 string) string { i, j, carry := len(num1)-1, len(num2)-1, 0 res := make([]byte, 0) - + for i >= 0 || j >= 0 || carry > 0 { var n1, n2 int if i >= 0 { @@ -356,11 +358,11 @@ func add(num1 string, num2 string) string { i-- j-- } - + for i := 0; i < len(res)/2; i++ { res[i], res[len(res)-1-i] = res[len(res)-1-i], res[i] } - + return string(res) } ``` @@ -371,11 +373,11 @@ class Solution { if (num1 == "0" || num2 == "0") { return "0" } - + if (num1.length < num2.length) { return multiply(num2, num1) } - + var res = "" var zero = 0 for (i in num2.length - 1 downTo 0) { @@ -383,16 +385,16 @@ class Solution { res = add(res, cur) zero++ } - + return res } - + private fun mul(s: String, d: Char, zero: Int): String { var i = s.length - 1 var carry = 0 val dInt = d - '0' val cur = mutableListOf() - + while (i >= 0 || carry > 0) { val n = if (i >= 0) s[i] - '0' else 0 val prod = n * dInt + carry @@ -400,16 +402,16 @@ class Solution { carry = prod / 10 i-- } - + return cur.reversed().joinToString("") + "0".repeat(zero) } - + private fun add(num1: String, num2: String): String { var i = num1.length - 1 var j = num2.length - 1 var carry = 0 val res = mutableListOf() - + while (i >= 0 || j >= 0 || carry > 0) { val n1 = if (i >= 0) num1[i] - '0' else 0 val n2 = if (j >= 0) num2[j] - '0' else 0 @@ -419,18 +421,84 @@ class Solution { i-- j-- } - + return res.reversed().joinToString("") } } ``` +```swift +class Solution { + func multiply(_ num1: String, _ num2: String) -> String { + if num1 == "0" || num2 == "0" { + return "0" + } + if num1.count < num2.count { + return multiply(num2, num1) + } + + var res = "" + var zero = 0 + let num2Arr = Array(num2) + + for i in stride(from: num2Arr.count - 1, through: 0, by: -1) { + let cur = mul(num1, num2Arr[i], zero) + res = add(res, cur) + zero += 1 + } + + return res + } + + func mul(_ s: String, _ d: Character, _ zero: Int) -> String { + var i = s.count - 1 + var carry = 0 + let dInt = Int(String(d))! + let sArr = Array(s) + var cur = [String]() + + while i >= 0 || carry > 0 { + let n = i >= 0 ? Int(String(sArr[i]))! : 0 + let prod = n * dInt + carry + cur.append(String(prod % 10)) + carry = prod / 10 + i -= 1 + } + + let prodStr = cur.reversed().joined() + let zeros = String(repeating: "0", count: zero) + return prodStr + zeros + } + + func add(_ num1: String, _ num2: String) -> String { + let s1 = Array(num1) + let s2 = Array(num2) + var i = s1.count - 1 + var j = s2.count - 1 + var carry = 0 + var res = [String]() + + while i >= 0 || j >= 0 || carry > 0 { + let n1 = i >= 0 ? Int(String(s1[i]))! : 0 + let n2 = j >= 0 ? Int(String(s2[j]))! : 0 + let total = n1 + n2 + carry + res.append(String(total % 10)) + carry = total / 10 + i -= 1 + j -= 1 + } + + return res.reversed().joined() + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(min(m, n) * (m + n))$ -* Space complexity: $O(m + n)$ +- Time complexity: $O(min(m, n) * (m + n))$ +- Space complexity: $O(m + n)$ > Where $m$ is the length of the string $num1$ and $n$ is the length of the string $num2$. @@ -600,19 +668,19 @@ func multiply(num1 string, num2 string) string { if num1 == "0" || num2 == "0" { return "0" } - + res := make([]int, len(num1)+len(num2)) for i1 := len(num1) - 1; i1 >= 0; i1-- { for i2 := len(num2) - 1; i2 >= 0; i2-- { pos := len(num1) - 1 - i1 + len(num2) - 1 - i2 digit := int(num1[i1]-'0') * int(num2[i2]-'0') - + res[pos] += digit res[pos+1] += res[pos] / 10 res[pos] = res[pos] % 10 } } - + var result strings.Builder start := len(res) - 1 for start >= 0 && res[start] == 0 { @@ -621,11 +689,11 @@ func multiply(num1 string, num2 string) string { if start < 0 { return "0" } - + for i := start; i >= 0; i-- { result.WriteString(strconv.Itoa(res[i])) } - + return result.String() } ``` @@ -636,28 +704,28 @@ class Solution { if ("0" in listOf(num1, num2)) { return "0" } - + val res = IntArray(num1.length + num2.length) for (i1 in num1.indices.reversed()) { for (i2 in num2.indices.reversed()) { val pos = (num1.length - 1 - i1) + (num2.length - 1 - i2) val digit = (num1[i1] - '0') * (num2[i2] - '0') - + res[pos] += digit res[pos + 1] += res[pos] / 10 res[pos] = res[pos] % 10 } } - + var start = res.size - 1 while (start >= 0 && res[start] == 0) { start-- } - + if (start < 0) { return "0" } - + return buildString { for (i in start downTo 0) { append(res[i]) @@ -667,11 +735,42 @@ class Solution { } ``` +```swift +class Solution { + func multiply(_ num1: String, _ num2: String) -> String { + if num1 == "0" || num2 == "0" { + return "0" + } + + let n1 = Array(num1.reversed()).map { Int(String($0))! } + let n2 = Array(num2.reversed()).map { Int(String($0))! } + var res = [Int](repeating: 0, count: num1.count + num2.count) + + for i1 in 0.. Where $m$ is the length of the string $num1$ and $n$ is the length of the string $num2$. \ No newline at end of file +> Where $m$ is the length of the string $num1$ and $n$ is the length of the string $num2$. diff --git a/articles/my-calendar-i.md b/articles/my-calendar-i.md new file mode 100644 index 000000000..e7f218291 --- /dev/null +++ b/articles/my-calendar-i.md @@ -0,0 +1,406 @@ +## 1. Iteration + +::tabs-start + +```python +class MyCalendar: + + def __init__(self): + self.events = [] + + def book(self, startTime: int, endTime: int) -> bool: + for start, end in self.events: + if startTime < end and start < endTime: + return False + + self.events.append((startTime, endTime)) + return True +``` + +```java +public class MyCalendar { + private List events; + + public MyCalendar() { + events = new ArrayList<>(); + } + + public boolean book(int startTime, int endTime) { + for (int[] event : events) { + if (startTime < event[1] && event[0] < endTime) { + return false; + } + } + events.add(new int[]{startTime, endTime}); + return true; + } +} +``` + +```cpp +class MyCalendar { +private: + vector> events; + +public: + MyCalendar() {} + + bool book(int startTime, int endTime) { + for (const auto& event : events) { + if (startTime < event.second && event.first < endTime) { + return false; + } + } + events.push_back({startTime, endTime}); + return true; + } +}; +``` + +```javascript +class MyCalendar { + constructor() { + this.events = []; + } + + /** + * @param {number} startTime + * @param {number} endTime + * @return {boolean} + */ + book(startTime, endTime) { + for (const [start, end] of this.events) { + if (startTime < end && start < endTime) { + return false; + } + } + this.events.push([startTime, endTime]); + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ for each $book()$ function call. +- Space complexity: $O(n)$ + +--- + +## 2. Binary Search Tree + +::tabs-start + +```python +class TreeNode: + def __init__(self, start: int, end: int): + self.start = start + self.end = end + self.left = None + self.right = None + +class MyCalendar: + + def __init__(self): + self.root = None + + def _insert(self, node: TreeNode, start: int, end: int) -> bool: + if end <= node.start: + if not node.left: + node.left = TreeNode(start, end) + return True + return self._insert(node.left, start, end) + elif start >= node.end: + if not node.right: + node.right = TreeNode(start, end) + return True + return self._insert(node.right, start, end) + else: + return False + + def book(self, startTime: int, endTime: int) -> bool: + if not self.root: + self.root = TreeNode(startTime, endTime) + return True + return self._insert(self.root, startTime, endTime) +``` + +```java +class TreeNode { + int start, end; + TreeNode left, right; + + TreeNode(int start, int end) { + this.start = start; + this.end = end; + this.left = null; + this.right = null; + } +} + +public class MyCalendar { + private TreeNode root; + + public MyCalendar() { + root = null; + } + + private boolean insert(TreeNode node, int start, int end) { + if (end <= node.start) { + if (node.left == null) { + node.left = new TreeNode(start, end); + return true; + } + return insert(node.left, start, end); + } else if (start >= node.end) { + if (node.right == null) { + node.right = new TreeNode(start, end); + return true; + } + return insert(node.right, start, end); + } + return false; + } + + public boolean book(int startTime, int endTime) { + if (root == null) { + root = new TreeNode(startTime, endTime); + return true; + } + return insert(root, startTime, endTime); + } +} +``` + +```cpp +class MyCalendar { +private: + struct TreeNode { + int start, end; + TreeNode *left, *right; + + TreeNode(int start, int end) : start(start), end(end), left(nullptr), right(nullptr) {} + }; + TreeNode *root; + + bool insert(TreeNode *node, int start, int end) { + if (end <= node->start) { + if (!node->left) { + node->left = new TreeNode(start, end); + return true; + } + return insert(node->left, start, end); + } else if (start >= node->end) { + if (!node->right) { + node->right = new TreeNode(start, end); + return true; + } + return insert(node->right, start, end); + } + return false; + } + +public: + MyCalendar() : root(nullptr) {} + + bool book(int startTime, int endTime) { + if (!root) { + root = new TreeNode(startTime, endTime); + return true; + } + return insert(root, startTime, endTime); + } +}; +``` + +```javascript +class TreeNode { + /** + * @constructor + * @param {number} start + * @param {number} end + */ + constructor(start, end) { + this.start = start; + this.end = end; + this.left = null; + this.right = null; + } +} + +class MyCalendar { + constructor() { + this.root = null; + } + + /** + * @param {TreeNode} node + * @param {number} start + * @param {number} end + * @return {boolean} + */ + insert(node, start, end) { + if (end <= node.start) { + if (!node.left) { + node.left = new TreeNode(start, end); + return true; + } + return this.insert(node.left, start, end); + } else if (start >= node.end) { + if (!node.right) { + node.right = new TreeNode(start, end); + return true; + } + return this.insert(node.right, start, end); + } + return false; + } + + /** + * @param {number} startTime + * @param {number} endTime + * @return {boolean} + */ + book(startTime, endTIme) { + if (!this.root) { + this.root = new TreeNode(startTime, endTime); + return true; + } + return this.insert(this.root, startTime, endTime); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ in average case, $O(n)$ in worst case for each $book()$ function call. +- Space complexity: $O(n)$ + +--- + +## 3. Binary Search + Ordered Set + +::tabs-start + +```python +class MyCalendar: + + def __init__(self): + self.events = SortedList() + + def book(self, startTime: int, endTime: int) -> bool: + idx = self.events.bisect_left((startTime, endTime)) + if idx > 0 and self.events[idx - 1][1] > startTime: + return False + if idx < len(self.events) and self.events[idx][0] < endTime: + return False + self.events.add((startTime, endTime)) + return True +``` + +```java +public class MyCalendar { + private TreeSet events; + + public MyCalendar() { + events = new TreeSet<>((a, b) -> a[0] - b[0]); + } + + public boolean book(int startTime, int endTime) { + int[] event = new int[]{startTime, endTime}; + int[] prev = events.floor(event); + int[] next = events.ceiling(event); + + if ((prev != null && prev[1] > startTime) || (next != null && next[0] < endTime)) { + return false; + } + events.add(event); + return true; + } +} +``` + +```cpp +class MyCalendar { +private: + set> events; + +public: + MyCalendar() {} + + bool book(int startTime, int endTime) { + if (startTime >= endTime) { + return false; + } + + auto next = events.lower_bound({startTime, startTime}); + if (next != events.end() && next->first < endTime) { + return false; + } + if (next != events.begin()) { + auto prev = std::prev(next); + if (prev->second > startTime) { + return false; + } + } + + events.insert({startTime, endTime}); + return true; + } +}; +``` + +```javascript +class MyCalendar { + constructor() { + this.events = []; + } + + /** + * @param {number} startTime + * @param {number} endTime + * @return {boolean} + */ + book(startTime, endTIme) { + if (startTime >= endTime) { + return false; + } + + const binarySearch = (target) => { + let left = 0, + right = this.events.length; + + while (left < right) { + let mid = Math.floor((left + right) / 2); + if (this.events[mid][0] < target) { + left = mid + 1; + } else { + right = mid; + } + } + return left; + }; + + const idx = binarySearch(startTime); + if (idx > 0 && this.events[idx - 1][1] > startTime) { + return false; + } + if (idx < this.events.length && this.events[idx][0] < endTime) { + return false; + } + this.events.splice(idx, 0, [startTime, endTime]); + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ for each $book()$ function call. +- Space complexity: $O(n)$ diff --git a/articles/n-ary-tree-postorder-traversal.md b/articles/n-ary-tree-postorder-traversal.md new file mode 100644 index 000000000..e2c1d2f13 --- /dev/null +++ b/articles/n-ary-tree-postorder-traversal.md @@ -0,0 +1,405 @@ +## 1. Depth First Search + +::tabs-start + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val: Optional[int] = None, children: Optional[List['Node']] = None): + self.val = val + self.children = children +""" + +class Solution: + def postorder(self, root: 'Node') -> List[int]: + res = [] + + def dfs(node): + if not node: + return + + for child in node.children: + dfs(child) + res.append(node.val) + + dfs(root) + return res +``` + +```java +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +} +*/ + +public class Solution { + public List postorder(Node root) { + List res = new ArrayList<>(); + + dfs(root, res); + return res; + } + + private void dfs(Node node, List res) { + if (node == null) { + return; + } + for (Node child : node.children) { + dfs(child, res); + } + res.add(node.val); + } +} +``` + +```cpp +/* +// Definition for a Node. +class Node { +public: + int val; + vector children; + + Node() {} + + Node(int _val) { + val = _val; + } + + Node(int _val, vector _children) { + val = _val; + children = _children; + } +}; +*/ + +class Solution { +public: + vector postorder(Node* root) { + vector res; + dfs(root, res); + return res; + } + + void dfs(Node* node, vector& res) { + if (!node) return; + for (auto child : node->children) { + dfs(child, res); + } + res.push_back(node->val); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class Node { + * constructor(val = 0, children = []) { + * this.val = val; + * this.children = children; + * } + * } + */ +class Solution { + /** + * @param {Node|null} root + * @return {number[]} + */ + postorder(root) { + const res = []; + + const dfs = (node) => { + if (!node) return; + for (let child of node.children) { + dfs(child); + } + res.push(node.val); + }; + + dfs(root); + return res; + } +} +``` + +```csharp +/* +// Definition for a Node. +public class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, IList _children) { + val = _val; + children = _children; + } +} +*/ + +public class Solution { + public List Postorder(Node root) { + List res = new List(); + Dfs(root, res); + return res; + } + + private void Dfs(Node node, List res) { + if (node == null) return; + foreach (var child in node.children) { + Dfs(child, res); + } + res.Add(node.val); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ for the recursion stack. + +--- + +## 2. Iterative DFS + +::tabs-start + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val: Optional[int] = None, children: Optional[List['Node']] = None): + self.val = val + self.children = children +""" + +class Solution: + def postorder(self, root: 'Node') -> List[int]: + res = [] + if not root: + return res + + stack = [(root, False)] + while stack: + node, visited = stack.pop() + if visited: + res.append(node.val) + else: + stack.append((node, True)) + for child in reversed(node.children): + stack.append((child, False)) + return res +``` + +```java +/* +// Definition for a Node. +class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, List _children) { + val = _val; + children = _children; + } +} +*/ + +public class Solution { + public List postorder(Node root) { + List res = new ArrayList<>(); + if (root == null) return res; + + Stack> stack = new Stack<>(); + stack.push(new Pair<>(root, false)); + + while (!stack.isEmpty()) { + Pair p = stack.pop(); + Node node = p.getKey(); + boolean visited = p.getValue(); + + if (visited) { + res.add(node.val); + } else { + stack.push(new Pair<>(node, true)); + for (int i = node.children.size() - 1; i >= 0; i--) { + stack.push(new Pair<>(node.children.get(i), false)); + } + } + } + + return res; + } +} +``` + +```cpp +/* +// Definition for a Node. +class Node { +public: + int val; + vector children; + + Node() {} + + Node(int _val) { + val = _val; + } + + Node(int _val, vector _children) { + val = _val; + children = _children; + } +}; +*/ + +class Solution { +public: + vector postorder(Node* root) { + vector res; + if (!root) return res; + + stack> st; + st.push({root, false}); + + while (!st.empty()) { + auto [node, visited] = st.top(); + st.pop(); + + if (visited) { + res.push_back(node->val); + } else { + st.push({node, true}); + for (int i = (int)node->children.size() - 1; i >= 0; i--) { + st.push({node->children[i], false}); + } + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class Node { + * constructor(val = 0, children = []) { + * this.val = val; + * this.children = children; + * } + * } + */ +class Solution { + /** + * @param {Node|null} root + * @return {number[]} + */ + postorder(root) { + const res = []; + if (!root) return res; + + const stack = [[root, false]]; + + while (stack.length) { + const [node, visited] = stack.pop(); + + if (visited) { + res.push(node.val); + } else { + stack.push([node, true]); + for (let i = node.children.length - 1; i >= 0; i--) { + stack.push([node.children[i], false]); + } + } + } + + return res; + } +} +``` + +```csharp +/* +// Definition for a Node. +public class Node { + public int val; + public List children; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, IList _children) { + val = _val; + children = _children; + } +} +*/ + +public class Solution { + public List Postorder(Node root) { + List res = new List(); + if (root == null) return res; + + Stack<(Node, bool)> stack = new Stack<(Node, bool)>(); + stack.Push((root, false)); + + while (stack.Count > 0) { + var (node, visited) = stack.Pop(); + + if (visited) { + res.Add(node.val); + } else { + stack.Push((node, true)); + for (int i = node.children.Count - 1; i >= 0; i--) { + stack.Push((node.children[i], false)); + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/n-queens-ii.md b/articles/n-queens-ii.md index 1e123c887..c29e85b70 100644 --- a/articles/n-queens-ii.md +++ b/articles/n-queens-ii.md @@ -21,14 +21,14 @@ class Solution: backtrack(0) return res - + def isSafe(self, r: int, c: int, board): row = r - 1 while row >= 0: if board[row][c] == "Q": return False row -= 1 - + row, col = r - 1, c - 1 while row >= 0 and col >= 0: if board[row][col] == "Q": @@ -137,8 +137,8 @@ class Solution { */ totalNQueens(n) { let res = 0; - let board = Array.from({length: n}, () => Array(n).fill('.')); - + let board = Array.from({ length: n }, () => Array(n).fill('.')); + const backtrack = (r) => { if (r === n) { res++; @@ -151,8 +151,8 @@ class Solution { board[r][c] = '.'; } } - } - + }; + backtrack(0); return res; } @@ -178,12 +178,63 @@ class Solution { } ``` +```csharp +public class Solution { + private int res = 0; + + public int TotalNQueens(int n) { + res = 0; + char[][] board = new char[n][]; + for (int i = 0; i < n; i++) { + board[i] = Enumerable.Repeat('.', n).ToArray(); + } + + Backtrack(0, board, n); + return res; + } + + private void Backtrack(int r, char[][] board, int n) { + if (r == n) { + res++; + return; + } + + for (int c = 0; c < n; c++) { + if (IsSafe(r, c, board)) { + board[r][c] = 'Q'; + Backtrack(r + 1, board, n); + board[r][c] = '.'; + } + } + } + + private bool IsSafe(int r, int c, char[][] board) { + // Check column + for (int row = r - 1; row >= 0; row--) { + if (board[row][c] == 'Q') return false; + } + + // Check top-left diagonal + for (int row = r - 1, col = c - 1; row >= 0 && col >= 0; row--, col--) { + if (board[row][col] == 'Q') return false; + } + + // Check top-right diagonal + for (int row = r - 1, col = c + 1; row >= 0 && col < board.Length; row--, col++) { + if (board[row][col] == 'Q') return false; + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n!)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n!)$ +- Space complexity: $O(n ^ 2)$ --- @@ -229,7 +280,7 @@ public class Solution { Set posDiag = new HashSet<>(); Set negDiag = new HashSet<>(); int res; - + public int totalNQueens(int n) { res = 0; backtrack(0, n); @@ -323,8 +374,7 @@ class Solution { } for (let c = 0; c < n; c++) { - if (col.has(c) || posDiag.has(r + c) || - negDiag.has(r - c)) { + if (col.has(c) || posDiag.has(r + c) || negDiag.has(r - c)) { continue; } @@ -346,12 +396,49 @@ class Solution { } ``` +```csharp +public class Solution { + private HashSet col = new HashSet(); + private HashSet posDiag = new HashSet(); // r + c + private HashSet negDiag = new HashSet(); // r - c + private int res = 0; + + public int TotalNQueens(int n) { + res = 0; + Backtrack(0, n); + return res; + } + + private void Backtrack(int r, int n) { + if (r == n) { + res++; + return; + } + + for (int c = 0; c < n; c++) { + if (col.Contains(c) || posDiag.Contains(r + c) || negDiag.Contains(r - c)) + continue; + + col.Add(c); + posDiag.Add(r + c); + negDiag.Add(r - c); + + Backtrack(r + 1, n); + + col.Remove(c); + posDiag.Remove(r + c); + negDiag.Remove(r - c); + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n!)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n!)$ +- Space complexity: $O(n)$ --- @@ -399,7 +486,7 @@ public class Solution { posDiag = new boolean[2 * n]; negDiag = new boolean[2 * n]; res = 0; - + backtrack(0, n); return res; } @@ -490,13 +577,13 @@ class Solution { for (let c = 0; c < n; c++) { if (col[c] || posDiag[r + c] || negDiag[r - c + n]) { continue; - } + } col[c] = true; posDiag[r + c] = true; negDiag[r - c + n] = true; backtrack(r + 1); - + col[c] = false; posDiag[r + c] = false; negDiag[r - c + n] = false; @@ -509,12 +596,48 @@ class Solution { } ``` +```csharp +public class Solution { + public int TotalNQueens(int n) { + bool[] col = new bool[n]; + bool[] posDiag = new bool[2 * n]; + bool[] negDiag = new bool[2 * n]; + int res = 0; + + void Backtrack(int r) { + if (r == n) { + res++; + return; + } + + for (int c = 0; c < n; c++) { + if (col[c] || posDiag[r + c] || negDiag[r - c + n]) + continue; + + col[c] = true; + posDiag[r + c] = true; + negDiag[r - c + n] = true; + + Backtrack(r + 1); + + col[c] = false; + posDiag[r + c] = false; + negDiag[r - c + n] = false; + } + } + + Backtrack(0); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n!)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n!)$ +- Space complexity: $O(n)$ --- @@ -536,7 +659,7 @@ class Solution: res += 1 return for c in range(n): - if ((col & (1 << c)) or (posDiag & (1 << (r + c))) + if ((col & (1 << c)) or (posDiag & (1 << (r + c))) or (negDiag & (1 << (r - c + n)))): continue col ^= (1 << c) @@ -569,7 +692,7 @@ public class Solution { return; } for (int c = 0; c < n; c++) { - if ((col & (1 << c)) > 0 || (posDiag & (1 << (r + c))) > 0 || + if ((col & (1 << c)) > 0 || (posDiag & (1 << (r + c))) > 0 || (negDiag & (1 << (r - c + n))) > 0) { continue; } @@ -605,7 +728,7 @@ public: return; } for (int c = 0; c < n; c++) { - if ((col & (1 << c)) || (posDiag & (1 << (r + c))) || + if ((col & (1 << c)) || (posDiag & (1 << (r + c))) || (negDiag & (1 << (r - c + n)))) { continue; } @@ -630,7 +753,10 @@ class Solution { * @return {number} */ totalNQueens(n) { - let col = 0, posDiag = 0, negDiag = 0, res = 0; + let col = 0, + posDiag = 0, + negDiag = 0, + res = 0; /** * @param {number} r @@ -642,23 +768,64 @@ class Solution { return; } for (let c = 0; c < n; c++) { - if ((col & (1 << c)) > 0 || (posDiag & (1 << (r + c))) > 0 || - (negDiag & (1 << (r - c + n))) > 0) { + if ( + (col & (1 << c)) > 0 || + (posDiag & (1 << (r + c))) > 0 || + (negDiag & (1 << (r - c + n))) > 0 + ) { continue; } + col ^= 1 << c; + posDiag ^= 1 << (r + c); + negDiag ^= 1 << (r - c + n); + + backtrack(r + 1); + + col ^= 1 << c; + posDiag ^= 1 << (r + c); + negDiag ^= 1 << (r - c + n); + } + } + + backtrack(0); + return res; + } +} +``` + +```csharp +public class Solution { + public int TotalNQueens(int n) { + int col = 0; + int posDiag = 0; + int negDiag = 0; + int res = 0; + + void Backtrack(int r) { + if (r == n) { + res++; + return; + } + + for (int c = 0; c < n; c++) { + if (((col & (1 << c)) != 0) || + ((posDiag & (1 << (r + c))) != 0) || + ((negDiag & (1 << (r - c + n))) != 0)) + continue; + col ^= (1 << c); posDiag ^= (1 << (r + c)); negDiag ^= (1 << (r - c + n)); - backtrack(r + 1); - + Backtrack(r + 1); + col ^= (1 << c); posDiag ^= (1 << (r + c)); negDiag ^= (1 << (r - c + n)); } } - backtrack(0); + Backtrack(0); return res; } } @@ -668,5 +835,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n!)$ -* Space complexity: $O(n)$ for recursion stack. \ No newline at end of file +- Time complexity: $O(n!)$ +- Space complexity: $O(n)$ for recursion stack. diff --git a/articles/n-queens.md b/articles/n-queens.md index 523b992a6..690ca72f2 100644 --- a/articles/n-queens.md +++ b/articles/n-queens.md @@ -28,7 +28,7 @@ class Solution: if board[row][c] == "Q": return False row -= 1 - + row, col = r - 1, c - 1 while row >= 0 and col >= 0: if board[row][col] == "Q": @@ -139,11 +139,11 @@ class Solution { */ solveNQueens(n) { let res = []; - let board = Array.from({length: n}, () => Array(n).fill('.')); - + let board = Array.from({ length: n }, () => Array(n).fill('.')); + const backtrack = (r) => { if (r === n) { - res.push(board.map(row => row.join(''))); + res.push(board.map((row) => row.join(''))); return; } for (let c = 0; c < n; c++) { @@ -153,8 +153,8 @@ class Solution { board[r][c] = '.'; } } - } - + }; + backtrack(0); return res; } @@ -334,12 +334,63 @@ class Solution { } ``` +```swift +class Solution { + func solveNQueens(_ n: Int) -> [[String]] { + var res = [[String]]() + var board = Array(repeating: Array(repeating: ".", count: n), count: n) + + func backtrack(_ r: Int) { + if r == n { + let copy = board.map { $0.joined() } + res.append(copy) + return + } + for c in 0.. Bool { + var row = r - 1 + while row >= 0 { + if board[row][c] == "Q" { return false } + row -= 1 + } + + var row1 = r - 1, col1 = c - 1 + while row1 >= 0, col1 >= 0 { + if board[row1][col1] == "Q" { return false } + row1 -= 1 + col1 -= 1 + } + + var row2 = r - 1, col2 = c + 1 + while row2 >= 0, col2 < board.count { + if board[row2][col2] == "Q" { return false } + row2 -= 1 + col2 += 1 + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n!)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n!)$ +- Space complexity: $O(n ^ 2)$ --- @@ -389,7 +440,7 @@ public class Solution { Set posDiag = new HashSet<>(); Set negDiag = new HashSet<>(); List> res = new ArrayList<>(); - + public List> solveNQueens(int n) { char[][] board = new char[n][n]; for (char[] row : board) { @@ -411,7 +462,7 @@ public class Solution { } for (int c = 0; c < n; c++) { - if (col.contains(c) || posDiag.contains(r + c) + if (col.contains(c) || posDiag.contains(r + c) || negDiag.contains(r - c)) { continue; } @@ -455,7 +506,7 @@ private: } for (int c = 0; c < n; c++) { - if (col.count(c) || posDiag.count(r + c) || + if (col.count(c) || posDiag.count(r + c) || negDiag.count(r - c)) { continue; } @@ -488,8 +539,7 @@ class Solution { const negDiag = new Set(); const res = []; - const board = Array.from({ length: n }, - () => Array(n).fill('.')); + const board = Array.from({ length: n }, () => Array(n).fill('.')); /** * @param {number} r @@ -497,13 +547,12 @@ class Solution { */ function backtrack(r) { if (r === n) { - res.push(board.map(row => row.join(''))); + res.push(board.map((row) => row.join(''))); return; } for (let c = 0; c < n; c++) { - if (col.has(c) || posDiag.has(r + c) || - negDiag.has(r - c)) { + if (col.has(c) || posDiag.has(r + c) || negDiag.has(r - c)) { continue; } @@ -533,7 +582,7 @@ public class Solution { HashSet posDiag = new HashSet(); HashSet negDiag = new HashSet(); List> res = new List>(); - + public List> SolveNQueens(int n) { char[][] board = new char[n][]; for (int i = 0; i < n; i++) { @@ -666,12 +715,53 @@ class Solution { } ``` +```swift +class Solution { + func solveNQueens(_ n: Int) -> [[String]] { + var col = Set() + var posDiag = Set() + var negDiag = Set() + var res = [[String]]() + var board = Array(repeating: Array(repeating: ".", count: n), count: n) + + func backtrack(_ r: Int) { + if r == n { + let copy = board.map { $0.joined() } + res.append(copy) + return + } + + for c in 0.. Array(n).fill('.')); + const board = Array.from({ length: n }, () => Array(n).fill('.')); /** * @param {number} r @@ -824,20 +913,20 @@ class Solution { */ function backtrack(r) { if (r === n) { - res.push(board.map(row => row.join(''))); + res.push(board.map((row) => row.join(''))); return; } for (let c = 0; c < n; c++) { if (col[c] || posDiag[r + c] || negDiag[r - c + n]) { continue; - } + } col[c] = true; posDiag[r + c] = true; negDiag[r - c + n] = true; board[r][c] = 'Q'; backtrack(r + 1); - + col[c] = false; posDiag[r + c] = false; negDiag[r - c + n] = false; @@ -882,7 +971,7 @@ public class Solution { for (int c = 0; c < n; c++) { if (col[c] || posDiag[r + c] || negDiag[r - c + n]) { continue; - } + } col[c] = true; posDiag[r + c] = true; negDiag[r - c + n] = true; @@ -986,12 +1075,53 @@ class Solution { } ``` +```swift +class Solution { + func solveNQueens(_ n: Int) -> [[String]] { + var col = Array(repeating: false, count: n) + var posDiag = Array(repeating: false, count: 2 * n) + var negDiag = Array(repeating: false, count: 2 * n) + var res = [[String]]() + var board = Array(repeating: Array(repeating: ".", count: n), count: n) + + func backtrack(_ r: Int) { + if r == n { + let copy = board.map { $0.joined() } + res.append(copy) + return + } + + for c in 0..> solveNQueens(int n) { board.resize(n, string(n, '.')); - + backtrack(0, n); return res; } @@ -1129,10 +1259,11 @@ class Solution { * @return {string[][]} */ solveNQueens(n) { - let col = 0, posDiag = 0, negDiag = 0; + let col = 0, + posDiag = 0, + negDiag = 0; const res = []; - const board = Array.from({ length: n }, - () => Array(n).fill('.')); + const board = Array.from({ length: n }, () => Array(n).fill('.')); /** * @param {number} r @@ -1140,24 +1271,27 @@ class Solution { */ function backtrack(r) { if (r === n) { - res.push(board.map(row => row.join(''))); + res.push(board.map((row) => row.join(''))); return; } for (let c = 0; c < n; c++) { - if ((col & (1 << c)) > 0 || (posDiag & (1 << (r + c))) > 0 - || (negDiag & (1 << (r - c + n))) > 0) { + if ( + (col & (1 << c)) > 0 || + (posDiag & (1 << (r + c))) > 0 || + (negDiag & (1 << (r - c + n))) > 0 + ) { continue; } - col ^= (1 << c); - posDiag ^= (1 << (r + c)); - negDiag ^= (1 << (r - c + n)); + col ^= 1 << c; + posDiag ^= 1 << (r + c); + negDiag ^= 1 << (r - c + n); board[r][c] = 'Q'; backtrack(r + 1); - - col ^= (1 << c); - posDiag ^= (1 << (r + c)); - negDiag ^= (1 << (r - c + n)); + + col ^= 1 << c; + posDiag ^= 1 << (r + c); + negDiag ^= 1 << (r - c + n); board[r][c] = '.'; } } @@ -1237,7 +1371,7 @@ func solveNQueens(n int) [][]string { } for c := 0; c < n; c++ { - if (col&(1< [[String]] { + var col = 0 + var posDiag = 0 + var negDiag = 0 + var res = [[String]]() + var board = Array(repeating: Array(repeating: ".", count: n), count: n) + + func backtrack(_ r: Int) { + if r == n { + let copy = board.map { $0.joined() } + res.append(copy) + return + } + + for c in 0.. dp = new Dictionary(); + + public int Tribonacci(int n) { + if (n == 0) return 0; + if (n <= 2) return 1; + if (dp.ContainsKey(n)) return dp[n]; + + dp[n] = Tribonacci(n - 1) + Tribonacci(n - 2) + Tribonacci(n - 3); + return dp[n]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -220,12 +252,31 @@ class Solution { } ``` +```csharp +public class Solution { + public int Tribonacci(int n) { + if (n == 0) return 0; + if (n <= 2) return 1; + + int[] dp = new int[n + 1]; + dp[0] = 0; + dp[1] = dp[2] = 1; + + for (int i = 3; i <= n; i++) { + dp[i] = dp[i - 1] + dp[i - 2] + dp[i - 3]; + } + + return dp[n]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -240,7 +291,7 @@ class Solution: if n < 3: return t[n] - + for i in range(3, n + 1): t[i % 3] = sum(t) return t[n % 3] @@ -282,7 +333,7 @@ class Solution { * @return {number} */ tribonacci(n) { - const t = [0, 1, 1] + const t = [0, 1, 1]; if (n < 3) return t[n]; for (let i = 3; i <= n; ++i) { @@ -293,9 +344,24 @@ class Solution { } ``` +```csharp +public class Solution { + public int Tribonacci(int n) { + int[] t = {0, 1, 1}; + if (n < 3) return t[n]; + + for (int i = 3; i <= n; i++) { + t[i % 3] = t[0] + t[1] + t[2]; + } + + return t[n % 3]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/naming-a-company.md b/articles/naming-a-company.md new file mode 100644 index 000000000..6b0def987 --- /dev/null +++ b/articles/naming-a-company.md @@ -0,0 +1,498 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def distinctNames(self, ideas: List[str]) -> int: + n = len(ideas) + res = set() + ideasSet = set(ideas) + + for i in range(n): + for j in range(i + 1, n): + A, B = ideas[j][0] + ideas[i][1:], ideas[i][0] + ideas[j][1:] + if A not in ideasSet and B not in ideasSet: + res.add(A + ' ' + B) + res.add(B + ' ' + A) + + return len(res) +``` + +```java +public class Solution { + public long distinctNames(String[] ideas) { + int n = ideas.length; + Set res = new HashSet<>(); + Set ideasSet = new HashSet<>(Arrays.asList(ideas)); + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + String A = ideas[j].charAt(0) + ideas[i].substring(1); + String B = ideas[i].charAt(0) + ideas[j].substring(1); + + if (!ideasSet.contains(A) && !ideasSet.contains(B)) { + res.add(A + " " + B); + res.add(B + " " + A); + } + } + } + + return res.size(); + } +} +``` + +```cpp +class Solution { +public: + long long distinctNames(vector& ideas) { + int n = ideas.size(); + unordered_set res; + unordered_set ideasSet(ideas.begin(), ideas.end()); + + for (int i = 0; i < n; i++) { + for (int j = i + 1; j < n; j++) { + string A = ideas[j][0] + ideas[i].substr(1); + string B = ideas[i][0] + ideas[j].substr(1); + + if (!ideasSet.count(A) && !ideasSet.count(B)) { + res.insert(A + " " + B); + res.insert(B + " " + A); + } + } + } + + return res.size(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} ideas + * @return {number} + */ + distinctNames(ideas) { + let n = ideas.length; + let res = new Set(); + let ideasSet = new Set(ideas); + + for (let i = 0; i < n; i++) { + for (let j = i + 1; j < n; j++) { + let A = ideas[j][0] + ideas[i].slice(1); + let B = ideas[i][0] + ideas[j].slice(1); + + if (!ideasSet.has(A) && !ideasSet.has(B)) { + res.add(A + ' ' + B); + res.add(B + ' ' + A); + } + } + } + + return res.size; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n ^ 2)$ +- Space complexity: $O(m * n ^ 2)$ + +> Where $n$ is the size of the array $ideas$ and $m$ is the average length of the strings. + +--- + +## 2. Group By First Letter (Hash Map) + +::tabs-start + +```python +class Solution: + def distinctNames(self, ideas: List[str]) -> int: + wordMap = collections.defaultdict(set) + for w in ideas: + wordMap[w[0]].add(w[1:]) + + res = 0 + for char1 in wordMap: + for char2 in wordMap: + if char1 == char2: + continue + + intersect = sum(1 for w in wordMap[char1] if w in wordMap[char2]) + distinct1 = len(wordMap[char1]) - intersect + distinct2 = len(wordMap[char2]) - intersect + res += distinct1 * distinct2 + + return res +``` + +```java +public class Solution { + public long distinctNames(String[] ideas) { + Map> wordMap = new HashMap<>(); + for (String word : ideas) { + wordMap.computeIfAbsent( + word.charAt(0), k -> new HashSet<>()).add(word.substring(1) + ); + } + + long res = 0; + for (char char1 : wordMap.keySet()) { + for (char char2 : wordMap.keySet()) { + if (char1 == char2) continue; + + int intersect = 0; + for (String w : wordMap.get(char1)) { + if (wordMap.get(char2).contains(w)) { + intersect++; + } + } + + int distinct1 = wordMap.get(char1).size() - intersect; + int distinct2 = wordMap.get(char2).size() - intersect; + res += distinct1 * 1L * distinct2; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + long long distinctNames(vector& ideas) { + unordered_map> wordMap; + for (const string& word : ideas) { + wordMap[word[0]].insert(word.substr(1)); + } + + long long res = 0; + for (auto& [char1, set1] : wordMap) { + for (auto& [char2, set2] : wordMap) { + if (char1 == char2) continue; + + int intersect = 0; + for (const string& w : set1) { + if (set2.count(w)) { + intersect++; + } + } + + int distinct1 = set1.size() - intersect; + int distinct2 = set2.size() - intersect; + res += distinct1 * 1LL * distinct2; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} ideas + * @return {number} + */ + distinctNames(ideas) { + const wordMap = new Map(); + for (let word of ideas) { + let key = word[0]; + if (!wordMap.has(key)) { + wordMap.set(key, new Set()); + } + wordMap.get(key).add(word.slice(1)); + } + + let res = 0; + for (let [char1, set1] of wordMap) { + for (let [char2, set2] of wordMap) { + if (char1 === char2) continue; + + let intersect = 0; + for (let w of set1) { + if (set2.has(w)) { + intersect++; + } + } + + let distinct1 = set1.size - intersect; + let distinct2 = set2.size - intersect; + res += distinct1 * distinct2; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ + +> Where $n$ is the size of the array $ideas$ and $m$ is the average length of the strings. + +--- + +## 3. Group By First Letter (Array) + +::tabs-start + +```python +class Solution: + def distinctNames(self, ideas: List[str]) -> int: + suffixes = [set() for _ in range(26)] + for w in ideas: + suffixes[ord(w[0]) - ord('a')].add(w[1:]) + + res = 0 + for i in range(26): + for j in range(i + 1, 26): + intersect = len(suffixes[i] & suffixes[j]) + res += 2 * (len(suffixes[i]) - intersect) * (len(suffixes[j]) - intersect) + + return res +``` + +```java +public class Solution { + public long distinctNames(String[] ideas) { + Set[] suffixes = new HashSet[26]; + for (int i = 0; i < 26; i++) { + suffixes[i] = new HashSet<>(); + } + for (String w : ideas) { + suffixes[w.charAt(0) - 'a'].add(w.substring(1)); + } + + long res = 0; + for (int i = 0; i < 26; i++) { + for (int j = i + 1; j < 26; j++) { + int intersect = 0; + for (String s : suffixes[i]) { + if (suffixes[j].contains(s)) { + intersect++; + } + } + res += 2L * (suffixes[i].size() - intersect) * (suffixes[j].size() - intersect); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + long long distinctNames(vector& ideas) { + unordered_set suffixes[26]; + for (const string& w : ideas) { + suffixes[w[0] - 'a'].insert(w.substr(1)); + } + + long long res = 0; + for (int i = 0; i < 26; i++) { + for (int j = i + 1; j < 26; j++) { + int intersect = 0; + for (const string& s : suffixes[i]) { + if (suffixes[j].count(s)) { + intersect++; + } + } + res += 2LL * (suffixes[i].size() - intersect) * (suffixes[j].size() - intersect); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} ideas + * @return {number} + */ + distinctNames(ideas) { + const suffixes = Array.from({ length: 26 }, () => new Set()); + for (let w of ideas) { + suffixes[w.charCodeAt(0) - 97].add(w.slice(1)); + } + + let res = 0; + for (let i = 0; i < 26; i++) { + for (let j = i + 1; j < 26; j++) { + let intersect = 0; + for (let s of suffixes[i]) { + if (suffixes[j].has(s)) { + intersect++; + } + } + res += + 2 * + (suffixes[i].size - intersect) * + (suffixes[j].size - intersect); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ + +> Where $n$ is the size of the array $ideas$ and $m$ is the average length of the strings. + +--- + +## 4. Counting + +::tabs-start + +```python +class Solution: + def distinctNames(self, ideas: List[str]) -> int: + mp = defaultdict(lambda: [False] * 26) + count = [[0] * 26 for _ in range(26)] + res = 0 + + for s in ideas: + first_char = ord(s[0]) - ord('a') + suffix = s[1:] + mp[suffix][first_char] = True + + for suffix, arr in mp.items(): + for i in range(26): + if arr[i]: + for j in range(26): + if not arr[j]: + count[i][j] += 1 + res += count[j][i] + + return 2 * res +``` + +```java +public class Solution { + public long distinctNames(String[] ideas) { + Map mp = new HashMap<>(); + int[][] count = new int[26][26]; + long res = 0; + + for (String s : ideas) { + int firstChar = s.charAt(0) - 'a'; + String suffix = s.substring(1); + mp.putIfAbsent(suffix, new boolean[26]); + mp.get(suffix)[firstChar] = true; + } + + for (boolean[] arr : mp.values()) { + for (int i = 0; i < 26; i++) { + if (arr[i]) { + for (int j = 0; j < 26; j++) { + if (!arr[j]) { + count[i][j]++; + res += count[j][i]; + } + } + } + } + } + return 2 * res; + } +} +``` + +```cpp +class Solution { +public: + long long distinctNames(vector& ideas) { + unordered_map> mp; + long long count[26][26] = {}; + long long res = 0; + + for (const string& s : ideas) { + int firstChar = s[0] - 'a'; + string suffix = s.substr(1); + mp[suffix][firstChar] = true; + } + + for (auto& [suffix, arr] : mp) { + for (int i = 0; i < 26; i++) { + if (arr[i]) { + for (int j = 0; j < 26; j++) { + if (!arr[j]) { + count[i][j]++; + res += count[j][i]; + } + } + } + } + } + return 2 * res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} ideas + * @return {number} + */ + distinctNames(ideas) { + const mp = new Map(); + const count = Array.from({ length: 26 }, () => Array(26).fill(0)); + let res = 0; + + for (const s of ideas) { + const firstChar = s.charCodeAt(0) - 97; + const suffix = s.slice(1); + if (!mp.has(suffix)) mp.set(suffix, new Array(26).fill(false)); + mp.get(suffix)[firstChar] = true; + } + + for (const arr of mp.values()) { + for (let i = 0; i < 26; i++) { + if (arr[i]) { + for (let j = 0; j < 26; j++) { + if (!arr[j]) { + count[i][j]++; + res += count[j][i]; + } + } + } + } + } + return 2 * res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ + +> Where $n$ is the size of the array $ideas$ and $m$ is the average length of the strings. diff --git a/articles/network-delay-time.md b/articles/network-delay-time.md index 1a9aa0afb..c9e76d51f 100644 --- a/articles/network-delay-time.md +++ b/articles/network-delay-time.md @@ -8,17 +8,17 @@ class Solution: adj = defaultdict(list) for u, v, w in times: adj[u].append((v, w)) - + dist = {node: float("inf") for node in range(1, n + 1)} def dfs(node, time): if time >= dist[node]: return - + dist[node] = time for nei, w in adj[node]: dfs(nei, time + w) - + dfs(k, 0) res = max(dist.values()) return res if res < float('inf') else -1 @@ -29,7 +29,7 @@ public class Solution { public int networkDelayTime(int[][] times, int n, int k) { Map> adj = new HashMap<>(); for (int[] time : times) { - adj.computeIfAbsent(time[0], + adj.computeIfAbsent(time[0], x -> new ArrayList<>()).add(new int[]{time[1], time[2]}); } @@ -41,8 +41,8 @@ public class Solution { return res == Integer.MAX_VALUE ? -1 : res; } - private void dfs(int node, int time, - Map> adj, + private void dfs(int node, int time, + Map> adj, Map dist) { if (time >= dist.get(node)) return; dist.put(node, time); @@ -65,14 +65,14 @@ public: vector dist(n + 1, INT_MAX); dfs(k, 0, adj, dist); - + int res = *max_element(dist.begin() + 1, dist.end()); return res == INT_MAX ? -1 : res; } private: - void dfs(int node, int time, - unordered_map>>& adj, + void dfs(int node, int time, + unordered_map>>& adj, vector& dist) { if (time >= dist[node]) return; dist[node] = time; @@ -106,7 +106,7 @@ class Solution { for (const [nei, w] of adj[node]) { dfs(nei, time + w); } - } + }; dfs(k, 0); const res = Math.max(...dist.slice(1)); @@ -134,8 +134,8 @@ public class Solution { return res == int.MaxValue ? -1 : res; } - private void Dfs(int node, int time, - Dictionary> adj, + private void Dfs(int node, int time, + Dictionary> adj, Dictionary dist) { if (time >= dist[node]) return; dist[node] = time; @@ -216,12 +216,46 @@ class Solution { } ``` +```swift +class Solution { + func networkDelayTime(_ times: [[Int]], _ n: Int, _ k: Int) -> Int { + var adj = [Int: [(Int, Int)]]() + for time in times { + let u = time[0], v = time[1], w = time[2] + adj[u, default: []].append((v, w)) + } + + var dist = [Int: Int]() + for node in 1...n { + dist[node] = Int.max + } + + func dfs(_ node: Int, _ time: Int) { + if time >= dist[node]! { + return + } + + dist[node] = time + if let neighbors = adj[node] { + for (nei, w) in neighbors { + dfs(nei, time + w) + } + } + } + + dfs(k, 0) + let res = dist.values.max()! + return res == Int.max ? -1 : res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V * E)$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(V * E)$ +- Space complexity: $O(V + E)$ > Where $V$ is the number of vertices and $E$ is the number of edges. @@ -236,17 +270,17 @@ class Solution: def networkDelayTime(self, times: List[List[int]], n: int, k: int) -> int: inf = float('inf') dist = [[inf] * n for _ in range(n)] - + for u, v, w in times: dist[u-1][v-1] = w for i in range(n): dist[i][i] = 0 - + for mid in range(n): for i in range(n): for j in range(n): dist[i][j] = min(dist[i][j], dist[i][mid] + dist[mid][j]) - + res = max(dist[k-1]) return res if res < inf else -1 ``` @@ -256,23 +290,23 @@ public class Solution { public int networkDelayTime(int[][] times, int n, int k) { int inf = Integer.MAX_VALUE / 2; int[][] dist = new int[n][n]; - + for (int i = 0; i < n; i++) { Arrays.fill(dist[i], inf); dist[i][i] = 0; } - + for (int[] time : times) { int u = time[0] - 1, v = time[1] - 1, w = time[2]; dist[u][v] = w; } - + for (int mid = 0; mid < n; mid++) for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) - dist[i][j] = Math.min(dist[i][j], + dist[i][j] = Math.min(dist[i][j], dist[i][mid] + dist[mid][j]); - + int res = Arrays.stream(dist[k-1]).max().getAsInt(); return res == inf ? -1 : res; } @@ -285,21 +319,21 @@ public: int networkDelayTime(vector>& times, int n, int k) { int inf = INT_MAX / 2; vector> dist(n, vector(n, inf)); - + for (int i = 0; i < n; i++) dist[i][i] = 0; - + for (auto& time : times) { int u = time[0] - 1, v = time[1] - 1, w = time[2]; dist[u][v] = w; } - + for (int mid = 0; mid < n; mid++) for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) - dist[i][j] = min(dist[i][j], + dist[i][j] = min(dist[i][j], dist[i][mid] + dist[mid][j]); - + int res = *max_element(dist[k-1].begin(), dist[k-1].end()); return res == inf ? -1 : res; } @@ -316,23 +350,24 @@ class Solution { */ networkDelayTime(times, n, k) { const inf = Infinity; - const dist = Array.from({ length: n }, () => - Array(n).fill(inf)); - + const dist = Array.from({ length: n }, () => Array(n).fill(inf)); + for (let i = 0; i < n; i++) { dist[i][i] = 0; } - + for (const [u, v, w] of times) { dist[u - 1][v - 1] = w; } - + for (let mid = 0; mid < n; mid++) for (let i = 0; i < n; i++) for (let j = 0; j < n; j++) - dist[i][j] = Math.min(dist[i][j], - dist[i][mid] + dist[mid][j]); - + dist[i][j] = Math.min( + dist[i][j], + dist[i][mid] + dist[mid][j], + ); + const res = Math.max(...dist[k - 1]); return res === inf ? -1 : res; } @@ -344,24 +379,24 @@ public class Solution { public int NetworkDelayTime(int[][] times, int n, int k) { int inf = int.MaxValue / 2; int[,] dist = new int[n, n]; - + for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { dist[i, j] = i == j ? 0 : inf; } } - + foreach (var time in times) { int u = time[0] - 1, v = time[1] - 1, w = time[2]; dist[u, v] = w; } - + for (int mid = 0; mid < n; mid++) for (int i = 0; i < n; i++) for (int j = 0; j < n; j++) - dist[i, j] = Math.Min(dist[i, j], + dist[i, j] = Math.Min(dist[i, j], dist[i, mid] + dist[mid, j]); - + int res = Enumerable.Range(0, n).Select(i => dist[k-1, i]).Max(); return res == inf ? -1 : res; } @@ -450,12 +485,40 @@ class Solution { } ``` +```swift +class Solution { + func networkDelayTime(_ times: [[Int]], _ n: Int, _ k: Int) -> Int { + let inf = Int.max / 2 + var dist = Array(repeating: Array(repeating: inf, count: n), count: n) + + for time in times { + let u = time[0] - 1, v = time[1] - 1, w = time[2] + dist[u][v] = w + } + for i in 0..= inf ? -1 : res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V ^ 3)$ -* Space complexity: $O(V ^ 2)$ +- Time complexity: $O(V ^ 3)$ +- Space complexity: $O(V ^ 2)$ > Where $V$ is the number of vertices. @@ -573,7 +636,7 @@ public class Solution { func networkDelayTime(times [][]int, n int, k int) int { dist := make([]int, n) for i := range dist { - dist[i] = 1 << 31 - 1 + dist[i] = 1 << 31 - 1 } dist[k-1] = 0 @@ -621,12 +684,38 @@ class Solution { } ``` +```swift +class Solution { + func networkDelayTime(_ times: [[Int]], _ n: Int, _ k: Int) -> Int { + var dist = Array(repeating: Int.max, count: n) + dist[k - 1] = 0 + + for _ in 0.. Where $V$ is the number of vertices and $E$ is the number of edges. @@ -642,7 +731,7 @@ class Solution: adj = defaultdict(list) for u, v, w in times: adj[u].append((v, w)) - + dist = {node: float("inf") for node in range(1, n + 1)} q = deque([(k, 0)]) dist[k] = 0 @@ -671,7 +760,7 @@ public class Solution { Map dist = new HashMap<>(); for (int i = 1; i <= n; i++) dist.put(i, Integer.MAX_VALUE); dist.put(k, 0); - + Queue q = new LinkedList<>(); q.offer(new int[] {k, 0}); @@ -704,7 +793,7 @@ public: for (const auto& time : times) { adj[time[0]].emplace_back(time[1], time[2]); } - + unordered_map dist; for (int i = 1; i <= n; ++i) dist[i] = INT_MAX; dist[k] = 0; @@ -779,7 +868,7 @@ public class Solution { foreach (var time in times) { adj[time[0]].Add(new int[] {time[1], time[2]}); } - + var dist = new Dictionary(); for (int i = 1; i <= n; i++) dist[i] = int.MaxValue; dist[k] = 0; @@ -801,7 +890,7 @@ public class Solution { } int res = 0; - foreach (var time in dist.Values) { + foreach (var time in dist.Values) { res = Math.Max(res, time); } return res == int.MaxValue ? -1 : res; @@ -886,12 +975,51 @@ class Solution { } ``` +```swift +class Solution { + func networkDelayTime(_ times: [[Int]], _ n: Int, _ k: Int) -> Int { + var adj = [Int: [(Int, Int)]]() + for time in times { + let u = time[0], v = time[1], w = time[2] + adj[u, default: []].append((v, w)) + } + + var dist = [Int: Int]() + for node in 1...n { + dist[node] = Int.max + } + dist[k] = 0 + + var queue = Deque<(Int, Int)>() + queue.append((k, 0)) + + while !queue.isEmpty { + let (node, time) = queue.popFirst()! + if dist[node]! < time { + continue + } + if let neighbors = adj[node] { + for (nei, w) in neighbors { + if time + w < dist[nei]! { + dist[nei] = time + w + queue.append((nei, time + w)) + } + } + } + } + + let res = dist.values.max()! + return res == Int.max ? -1 : res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V + E)$ in average case, $O(V * E)$ in worst case. -* Space complexity: $O(V + E)$ +- Time complexity: $O(V + E)$ in average case, $O(V * E)$ in worst case. +- Space complexity: $O(V + E)$ > Where $V$ is the number of vertices and $E$ is the number of edges. @@ -929,7 +1057,7 @@ public class Solution { public int networkDelayTime(int[][] times, int n, int k) { Map> edges = new HashMap<>(); for (int[] time : times) { - edges.computeIfAbsent(time[0], + edges.computeIfAbsent(time[0], key -> new ArrayList<>()).add(new int[]{time[1], time[2]}); } @@ -1023,7 +1151,7 @@ class Solution { edges.get(u).push([v, w]); } - const minHeap = new MinPriorityQueue(entry => entry[0]); + const minHeap = new MinPriorityQueue((entry) => entry[0]); minHeap.enqueue([0, k]); const visit = new Set(); @@ -1175,11 +1303,58 @@ class Solution { } ``` +```swift +struct Item: Comparable { + let weight: Int + let node: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.weight < rhs.weight + } +} + +class Solution { + func networkDelayTime(_ times: [[Int]], _ n: Int, _ k: Int) -> Int { + var edges = [Int: [(Int, Int)]]() + for time in times { + let u = time[0], v = time[1], w = time[2] + edges[u, default: []].append((v, w)) + } + + var minHeap = Heap() + minHeap.insert(Item(weight: 0, node: k)) + var visit = Set() + var t = 0 + + while !minHeap.isEmpty { + let item = minHeap.removeMin() + let w1 = item.weight + let n1 = item.node + + if visit.contains(n1) { + continue + } + visit.insert(n1) + t = w1 + + if let neighbors = edges[n1] { + for (n2, w2) in neighbors { + if !visit.contains(n2) { + minHeap.insert(Item(weight: w1 + w2, node: n2)) + } + } + } + } + return visit.count == n ? t : -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(E \log V)$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(E \log V)$ +- Space complexity: $O(V + E)$ -> Where $V$ is the number of vertices and $E$ is the number of edges. \ No newline at end of file +> Where $V$ is the number of vertices and $E$ is the number of edges. diff --git a/articles/new-21-game.md b/articles/new-21-game.md index e65fcd1da..5d0bb1eb2 100644 --- a/articles/new-21-game.md +++ b/articles/new-21-game.md @@ -6,20 +6,20 @@ class Solution: def new21Game(self, n: int, k: int, maxPts: int) -> float: cache = {} - + def dfs(score): if score >= k: return 1 if score <= n else 0 if score in cache: return cache[score] - + prob = 0 for i in range(1, maxPts + 1): prob += dfs(score + i) cache[score] = prob / maxPts return cache[score] - + return dfs(0) ``` @@ -120,8 +120,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(k * m)$ -* Space complexity: $O(k)$ +- Time complexity: $O(k * m)$ +- Space complexity: $O(k)$ > Where $k$ is the threshold score, $m$ is the maximum points per draw and $n$ is the upper bound on score. @@ -135,7 +135,7 @@ class Solution { class Solution: def new21Game(self, n: int, k: int, maxPts: int) -> float: cache = {} - + def dfs(score): if score == k - 1: return min(n - k + 1, maxPts) / maxPts @@ -143,14 +143,14 @@ class Solution: return 0 if score >= k: return 1.0 - + if score in cache: return cache[score] - + cache[score] = dfs(score + 1) cache[score] -= (dfs(score + 1 + maxPts) - dfs(score + 1)) / maxPts return cache[score] - + return dfs(0) ``` @@ -257,8 +257,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(k + m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(k + m)$ +- Space complexity: $O(n)$ > Where $k$ is the threshold score, $m$ is the maximum points per draw and $n$ is the upper bound on score. @@ -365,8 +365,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n)$ > Where $k$ is the threshold score, $m$ is the maximum points per draw and $n$ is the upper bound on score. @@ -381,11 +381,11 @@ class Solution: def new21Game(self, n: int, k: int, maxPts: int) -> float: if k == 0: return 1.0 - + windowSum = 0 for i in range(k, k + maxPts): windowSum += 1 if i <= n else 0 - + dp = {} for i in range(k - 1, -1, -1): dp[i] = windowSum / maxPts @@ -459,14 +459,14 @@ class Solution { } let windowSum = 0.0; for (let i = k; i < k + maxPts; i++) { - windowSum += (i <= n) ? 1.0 : 0.0; + windowSum += i <= n ? 1.0 : 0.0; } let dp = {}; for (let i = k - 1; i >= 0; i--) { dp[i] = windowSum / maxPts; let remove = 0.0; if (i + maxPts <= n) { - remove = (dp[i + maxPts] !== undefined) ? dp[i + maxPts] : 1.0; + remove = dp[i + maxPts] !== undefined ? dp[i + maxPts] : 1.0; } windowSum += dp[i] - remove; } @@ -479,7 +479,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(k + m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(k + m)$ +- Space complexity: $O(n)$ -> Where $k$ is the threshold score, $m$ is the maximum points per draw and $n$ is the upper bound on score. \ No newline at end of file +> Where $k$ is the threshold score, $m$ is the maximum points per draw and $n$ is the upper bound on score. diff --git a/articles/next-greater-element-i.md b/articles/next-greater-element-i.md index b81ca977a..0fb180779 100644 --- a/articles/next-greater-element-i.md +++ b/articles/next-greater-element-i.md @@ -87,12 +87,35 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] NextGreaterElement(int[] nums1, int[] nums2) { + int n = nums2.Length; + int[] res = new int[nums1.Length]; + + for (int i = 0; i < nums1.Length; i++) { + int nextGreater = -1; + for (int j = n - 1; j >= 0; j--) { + if (nums2[j] > nums1[i]) { + nextGreater = nums2[j]; + } else if (nums2[j] == nums1[i]) { + break; + } + } + res[i] = nextGreater; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(1)$ > Where $m$ is the size of the array $nums1$ and $n$ is the size of the array $nums2$. @@ -126,7 +149,7 @@ public class Solution { for (int i = 0; i < nums1.length; i++) { nums1Idx.put(nums1[i], i); } - + int[] res = new int[nums1.length]; Arrays.fill(res, -1); @@ -185,7 +208,7 @@ class Solution { nextGreaterElement(nums1, nums2) { const nums1Idx = new Map(); nums1.forEach((num, i) => nums1Idx.set(num, i)); - + const res = new Array(nums1.length).fill(-1); for (let i = 0; i < nums2.length; i++) { @@ -205,12 +228,42 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] NextGreaterElement(int[] nums1, int[] nums2) { + Dictionary nums1Idx = new Dictionary(); + for (int i = 0; i < nums1.Length; i++) { + nums1Idx[nums1[i]] = i; + } + + int[] res = new int[nums1.Length]; + Array.Fill(res, -1); + + for (int i = 0; i < nums2.Length; i++) { + if (!nums1Idx.ContainsKey(nums2[i])) { + continue; + } + + for (int j = i + 1; j < nums2.Length; j++) { + if (nums2[j] > nums2[i]) { + int idx = nums1Idx[nums2[i]]; + res[idx] = nums2[j]; + break; + } + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m)$ > Where $m$ is the size of the array $nums1$ and $n$ is the size of the array $nums2$. @@ -278,7 +331,7 @@ public: vector res(nums1.size(), -1); stack stack; - + for (int num : nums2) { while (!stack.empty() && num > stack.top()) { int val = stack.top(); @@ -305,7 +358,7 @@ class Solution { nextGreaterElement(nums1, nums2) { const nums1Idx = new Map(); nums1.forEach((num, i) => nums1Idx.set(num, i)); - + const res = new Array(nums1.length).fill(-1); const stack = []; @@ -324,11 +377,43 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] NextGreaterElement(int[] nums1, int[] nums2) { + Dictionary nums1Idx = new Dictionary(); + for (int i = 0; i < nums1.Length; i++) { + nums1Idx[nums1[i]] = i; + } + + int[] res = new int[nums1.Length]; + for (int i = 0; i < res.Length; i++) { + res[i] = -1; + } + + Stack stack = new Stack(); + foreach (int num in nums2) { + while (stack.Count > 0 && num > stack.Peek()) { + int val = stack.Pop(); + if (nums1Idx.ContainsKey(val)) { + int idx = nums1Idx[val]; + res[idx] = num; + } + } + if (nums1Idx.ContainsKey(num)) { + stack.Push(num); + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n)$ -* Space complexity: $O(m)$ +- Time complexity: $O(m + n)$ +- Space complexity: $O(m)$ -> Where $m$ is the size of the array $nums1$ and $n$ is the size of the array $nums2$. \ No newline at end of file +> Where $m$ is the size of the array $nums1$ and $n$ is the size of the array $nums2$. diff --git a/articles/next-permutation.md b/articles/next-permutation.md new file mode 100644 index 000000000..664cf3c25 --- /dev/null +++ b/articles/next-permutation.md @@ -0,0 +1,401 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def nextPermutation(self, nums: List[int]) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + permutations = self.permute(nums[:]) + permutations.sort() + for i, p in enumerate(permutations): + if p == nums: + nextP = permutations[(i + 1) % len(permutations)] + for j in range(len(nums)): + nums[j] = nextP[j] + break + + + def permute(self, nums: List[int]) -> List[List[int]]: + res = [] + + def dfs(i): + if i == len(nums): + res.append(nums.copy()) + return + + for j in range(i, len(nums)): + if j > i and nums[i] == nums[j]: + continue + + nums[i], nums[j] = nums[j], nums[i] + dfs(i + 1) + + for j in range(len(nums) - 1, i, -1): + nums[j], nums[i] = nums[i], nums[j] + + nums.sort() + dfs(0) + return res +``` + +```java +public class Solution { + public void nextPermutation(int[] nums) { + List> perms = permute(nums.clone()); + Collections.sort(perms, (a, b) -> { + for (int i = 0; i < a.size(); i++) { + int diff = a.get(i) - b.get(i); + if (diff != 0) return diff; + } + return 0; + }); + for (int i = 0; i < perms.size(); i++) { + List p = perms.get(i); + boolean match = true; + for (int j = 0; j < nums.length; j++) { + if (p.get(j) != nums[j]) { match = false; break; } + } + if (match) { + List next = perms.get((i + 1) % perms.size()); + for (int j = 0; j < nums.length; j++) { + nums[j] = next.get(j); + } + return; + } + } + } + + private List> permute(int[] nums) { + List> res = new ArrayList<>(); + Arrays.sort(nums); + boolean[] used = new boolean[nums.length]; + List path = new ArrayList<>(); + dfs(nums, used, path, res); + return res; + } + + private void dfs(int[] nums, boolean[] used, List path, List> res) { + if (path.size() == nums.length) { + res.add(new ArrayList<>(path)); + return; + } + for (int i = 0; i < nums.length; i++) { + if (used[i]) continue; + if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) continue; + used[i] = true; + path.add(nums[i]); + dfs(nums, used, path, res); + path.remove(path.size() - 1); + used[i] = false; + } + } +} +``` + +```cpp +class Solution { +public: + void nextPermutation(vector& nums) { + auto perms = permute(nums); + sort(perms.begin(), perms.end()); + for (int i = 0; i < perms.size(); i++) { + if (perms[i] == nums) { + auto& next = perms[(i + 1) % perms.size()]; + nums = next; + return; + } + } + } + +private: + vector> permute(vector nums) { + sort(nums.begin(), nums.end()); + vector> res; + vector path; + vector used(nums.size(), false); + function dfs = [&]() { + if (path.size() == nums.size()) { + res.push_back(path); + return; + } + for (int i = 0; i < nums.size(); i++) { + if (used[i]) continue; + if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) continue; + used[i] = true; + path.push_back(nums[i]); + dfs(); + path.pop_back(); + used[i] = false; + } + }; + dfs(); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + */ + nextPermutation(nums) { + const permute = (arr) => { + const res = []; + arr.sort((a, b) => a - b); + const used = Array(arr.length).fill(false); + const path = []; + const dfs = () => { + if (path.length === arr.length) { + res.push([...path]); + return; + } + for (let i = 0; i < arr.length; i++) { + if (used[i]) continue; + if (i > 0 && arr[i] === arr[i - 1] && !used[i - 1]) + continue; + used[i] = true; + path.push(arr[i]); + dfs(); + path.pop(); + used[i] = false; + } + }; + dfs(); + return res; + }; + + const perms = permute([...nums]); + perms.sort((a, b) => { + for (let i = 0; i < a.length; i++) { + if (a[i] !== b[i]) return a[i] - b[i]; + } + return 0; + }); + + for (let i = 0; i < perms.length; i++) { + const p = perms[i]; + if (p.every((v, j) => v === nums[j])) { + const next = perms[(i + 1) % perms.length]; + for (let j = 0; j < nums.length; j++) { + nums[j] = next[j]; + } + break; + } + } + } +} +``` + +```csharp +public class Solution { + public void NextPermutation(int[] nums) { + var perms = Permute((int[])nums.Clone()); + perms.Sort((a, b) => { + for (int i = 0; i < a.Count; i++) { + int diff = a[i] - b[i]; + if (diff != 0) return diff; + } + return 0; + }); + for (int i = 0; i < perms.Count; i++) { + var p = perms[i]; + bool match = true; + for (int j = 0; j < nums.Length; j++) { + if (p[j] != nums[j]) { match = false; break; } + } + if (match) { + var next = perms[(i + 1) % perms.Count]; + for (int j = 0; j < nums.Length; j++) { + nums[j] = next[j]; + } + return; + } + } + } + + private List> Permute(int[] nums) { + Array.Sort(nums); + var res = new List>(); + var used = new bool[nums.Length]; + var path = new List(); + void Dfs() { + if (path.Count == nums.Length) { + res.Add(new List(path)); + return; + } + for (int i = 0; i < nums.Length; i++) { + if (used[i]) continue; + if (i > 0 && nums[i] == nums[i - 1] && !used[i - 1]) continue; + used[i] = true; + path.Add(nums[i]); + Dfs(); + path.RemoveAt(path.Count - 1); + used[i] = false; + } + } + Dfs(); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n! * n)$ +- Space complexity: $O(n! * n)$ + +--- + +## 2. Greedy + +::tabs-start + +```python +class Solution: + def nextPermutation(self, nums: list[int]) -> None: + """ + Do not return anything, modify nums in-place instead. + """ + n = len(nums) + i = n - 2 + while i >= 0 and nums[i] >= nums[i + 1]: + i -= 1 + + if i >= 0: + j = n - 1 + while nums[j] <= nums[i]: + j -= 1 + nums[i], nums[j] = nums[j], nums[i] + + l, r = i + 1, n - 1 + while l < r: + nums[l], nums[r] = nums[r], nums[l] + l += 1 + r -= 1 +``` + +```java +public class Solution { + public void nextPermutation(int[] nums) { + int n = nums.length; + int i = n - 2; + while (i >= 0 && nums[i] >= nums[i + 1]) { + i--; + } + if (i >= 0) { + int j = n - 1; + while (nums[j] <= nums[i]) { + j--; + } + swap(nums, i, j); + } + int l = i + 1, r = n - 1; + while (l < r) { + swap(nums, l++, r--); + } + } + + private void swap(int[] nums, int i, int j) { + int tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; + } +} +``` + +```cpp +class Solution { +public: + void nextPermutation(vector& nums) { + int n = nums.size(); + int i = n - 2; + while (i >= 0 && nums[i] >= nums[i + 1]) { + i--; + } + if (i >= 0) { + int j = n - 1; + while (nums[j] <= nums[i]) { + j--; + } + swap(nums[i], nums[j]); + } + int l = i + 1, r = n - 1; + while (l < r) { + swap(nums[l++], nums[r--]); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {void} Do not return anything, modify nums in-place instead. + */ + nextPermutation(nums) { + const n = nums.length; + let i = n - 2; + while (i >= 0 && nums[i] >= nums[i + 1]) { + i--; + } + if (i >= 0) { + let j = n - 1; + while (nums[j] <= nums[i]) { + j--; + } + [nums[i], nums[j]] = [nums[j], nums[i]]; + } + let l = i + 1, + r = n - 1; + while (l < r) { + [nums[l], nums[r]] = [nums[r], nums[l]]; + l++; + r--; + } + } +} +``` + +```csharp +public class Solution { + public void NextPermutation(int[] nums) { + int n = nums.Length; + int i = n - 2; + while (i >= 0 && nums[i] >= nums[i + 1]) { + i--; + } + if (i >= 0) { + int j = n - 1; + while (nums[j] <= nums[i]) { + j--; + } + Swap(nums, i, j); + } + int l = i + 1, r = n - 1; + while (l < r) { + Swap(nums, l++, r--); + } + } + + private void Swap(int[] nums, int i, int j) { + int tmp = nums[i]; + nums[i] = nums[j]; + nums[j] = tmp; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/non-cyclical-number.md b/articles/non-cyclical-number.md index 5290a69a7..272eed2ca 100644 --- a/articles/non-cyclical-number.md +++ b/articles/non-cyclical-number.md @@ -206,12 +206,42 @@ class Solution { } ``` +```swift +class Solution { + func isHappy(_ n: Int) -> Bool { + var visit = Set() + var num = n + + while !visit.contains(num) { + visit.insert(num) + num = sumOfSquares(num) + if num == 1 { + return true + } + } + return false + } + + private func sumOfSquares(_ n: Int) -> Int { + var num = n + var output = 0 + + while num > 0 { + let digit = num % 10 + output += digit * digit + num /= 10 + } + return output + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(\log n)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(\log n)$ --- @@ -229,7 +259,7 @@ class Solution: fast = self.sumOfSquares(fast) slow = self.sumOfSquares(slow) return True if fast == 1 else False - + def sumOfSquares(self, n: int) -> int: output = 0 @@ -404,12 +434,40 @@ class Solution { } ``` +```swift +class Solution { + func isHappy(_ n: Int) -> Bool { + var slow = n + var fast = sumOfSquares(n) + + while slow != fast { + fast = sumOfSquares(fast) + fast = sumOfSquares(fast) + slow = sumOfSquares(slow) + } + return fast == 1 + } + + private func sumOfSquares(_ n: Int) -> Int { + var num = n + var output = 0 + + while num > 0 { + let digit = num % 10 + output += digit * digit + num /= 10 + } + return output + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ --- @@ -422,7 +480,7 @@ class Solution: def isHappy(self, n: int) -> bool: slow, fast = n, self.sumOfSquares(n) power = lam = 1 - + while slow != fast: if power == lam: slow = fast @@ -431,7 +489,7 @@ class Solution: fast = self.sumOfSquares(fast) lam += 1 return True if fast == 1 else False - + def sumOfSquares(self, n: int) -> int: output = 0 @@ -513,7 +571,8 @@ class Solution { isHappy(n) { let slow = n; let fast = this.sumOfSquares(n); - let power = 1, lam = 1; + let power = 1, + lam = 1; while (slow !== fast) { if (power === lam) { @@ -636,9 +695,43 @@ class Solution { } ``` +```swift +class Solution { + func isHappy(_ n: Int) -> Bool { + var slow = n + var fast = sumOfSquares(n) + var power = 1 + var lam = 1 + + while slow != fast { + if power == lam { + slow = fast + power *= 2 + lam = 0 + } + fast = sumOfSquares(fast) + lam += 1 + } + return fast == 1 + } + + private func sumOfSquares(_ n: Int) -> Int { + var num = n + var output = 0 + + while num > 0 { + let digit = num % 10 + output += digit * digit + num /= 10 + } + return output + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/non-decreasing-array.md b/articles/non-decreasing-array.md index aed007f6c..abdc4ad99 100644 --- a/articles/non-decreasing-array.md +++ b/articles/non-decreasing-array.md @@ -101,5 +101,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/non-overlapping-intervals.md b/articles/non-overlapping-intervals.md index 7970155cb..3833dfe87 100644 --- a/articles/non-overlapping-intervals.md +++ b/articles/non-overlapping-intervals.md @@ -6,7 +6,7 @@ class Solution: def eraseOverlapIntervals(self, intervals: List[List[int]]) -> int: intervals.sort() - + def dfs(i, prev): if i == len(intervals): return 0 @@ -14,7 +14,7 @@ class Solution: if prev == -1 or intervals[prev][1] <= intervals[i][0]: res = max(res, 1 + dfs(i + 1, i)) return res - + return len(intervals) - dfs(0, -1) ``` @@ -64,7 +64,7 @@ class Solution { */ eraseOverlapIntervals(intervals) { intervals.sort((a, b) => a[0] - b[0]); - + const dfs = (i, prev) => { if (i === intervals.length) return 0; let res = dfs(i + 1, prev); @@ -147,12 +147,34 @@ class Solution { } ``` +```swift +class Solution { + func eraseOverlapIntervals(_ intervals: [[Int]]) -> Int { + var intervals = intervals + intervals.sort { $0[0] < $1[0] } + + func dfs(_ i: Int, _ prev: Int) -> Int { + if i == intervals.count { + return 0 + } + var res = dfs(i + 1, prev) + if prev == -1 || intervals[prev][1] <= intervals[i][0] { + res = max(res, 1 + dfs(i + 1, i)) + } + return res + } + + return intervals.count - dfs(0, -1) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -188,9 +210,9 @@ public class Solution { public int eraseOverlapIntervals(int[][] intervals) { Arrays.sort(intervals, (a, b) -> Integer.compare(a[1], b[1])); int n = intervals.length; - memo = new int[n]; + memo = new int[n]; Arrays.fill(memo, -1); - + int maxNonOverlapping = dfs(intervals, 0); return n - maxNonOverlapping; } @@ -219,7 +241,7 @@ public: return a[1] < b[1]; }); int n = intervals.size(); - vector memo(n, -1); + vector memo(n, -1); int maxNonOverlapping = dfs(intervals, 0, memo); return n - maxNonOverlapping; @@ -251,7 +273,7 @@ class Solution { eraseOverlapIntervals(intervals) { intervals.sort((a, b) => a[1] - b[1]); const n = intervals.length; - let memo = new Array(n).fill(-1); + let memo = new Array(n).fill(-1); const dfs = (i) => { if (i >= n) return 0; @@ -280,7 +302,7 @@ public class Solution { public int EraseOverlapIntervals(int[][] intervals) { Array.Sort(intervals, (a, b) => a[1].CompareTo(b[1])); int n = intervals.Length; - memo = new int[n]; + memo = new int[n]; Array.Fill(memo, -1); int maxNonOverlapping = Dfs(intervals, 0); @@ -365,12 +387,40 @@ class Solution { } ``` +```swift +class Solution { + func eraseOverlapIntervals(_ intervals: [[Int]]) -> Int { + var intervals = intervals + intervals.sort { $0[1] < $1[1] } + let n = intervals.count + var memo = [Int: Int]() + + func dfs(_ i: Int) -> Int { + if let result = memo[i] { + return result + } + + var res = 1 + for j in i + 1.. int: intervals.sort(key=lambda x: x[1]) n = len(intervals) - dp = [0] * n + dp = [0] * n for i in range(n): - dp[i] = 1 + dp[i] = 1 for j in range(i): - if intervals[j][1] <= intervals[i][0]: + if intervals[j][1] <= intervals[i][0]: dp[i] = max(dp[i], 1 + dp[j]) - max_non_overlapping = max(dp) + max_non_overlapping = max(dp) return n - max_non_overlapping ``` @@ -400,18 +450,18 @@ public class Solution { public int eraseOverlapIntervals(int[][] intervals) { Arrays.sort(intervals, (a, b) -> Integer.compare(a[1], b[1])); int n = intervals.length; - int[] dp = new int[n]; + int[] dp = new int[n]; for (int i = 0; i < n; i++) { - dp[i] = 1; + dp[i] = 1; for (int j = 0; j < i; j++) { - if (intervals[j][1] <= intervals[i][0]) { + if (intervals[j][1] <= intervals[i][0]) { dp[i] = Math.max(dp[i], 1 + dp[j]); } } } - int maxNonOverlapping = Arrays.stream(dp).max().getAsInt(); + int maxNonOverlapping = Arrays.stream(dp).max().getAsInt(); return n - maxNonOverlapping; } } @@ -425,18 +475,18 @@ public: return a[1] < b[1]; }); int n = intervals.size(); - vector dp(n, 0); + vector dp(n, 0); for (int i = 0; i < n; i++) { - dp[i] = 1; + dp[i] = 1; for (int j = 0; j < i; j++) { - if (intervals[j][1] <= intervals[i][0]) { + if (intervals[j][1] <= intervals[i][0]) { dp[i] = max(dp[i], 1 + dp[j]); } } } - int maxNonOverlapping = *max_element(dp.begin(), dp.end()); + int maxNonOverlapping = *max_element(dp.begin(), dp.end()); return n - maxNonOverlapping; } }; @@ -451,18 +501,18 @@ class Solution { eraseOverlapIntervals(intervals) { intervals.sort((a, b) => a[1] - b[1]); const n = intervals.length; - const dp = new Array(n).fill(0); + const dp = new Array(n).fill(0); for (let i = 0; i < n; i++) { - dp[i] = 1; + dp[i] = 1; for (let j = 0; j < i; j++) { - if (intervals[j][1] <= intervals[i][0]) { + if (intervals[j][1] <= intervals[i][0]) { dp[i] = Math.max(dp[i], 1 + dp[j]); } } } - const maxNonOverlapping = Math.max(...dp); + const maxNonOverlapping = Math.max(...dp); return n - maxNonOverlapping; } } @@ -473,12 +523,12 @@ public class Solution { public int EraseOverlapIntervals(int[][] intervals) { Array.Sort(intervals, (a, b) => a[1].CompareTo(b[1])); int n = intervals.Length; - int[] dp = new int[n]; + int[] dp = new int[n]; for (int i = 0; i < n; i++) { - dp[i] = 1; + dp[i] = 1; for (int j = 0; j < i; j++) { - if (intervals[j][1] <= intervals[i][0]) { + if (intervals[j][1] <= intervals[i][0]) { dp[i] = Math.Max(dp[i], 1 + dp[j]); } } @@ -487,7 +537,7 @@ public class Solution { int maxNonOverlapping = 0; foreach (var count in dp) { maxNonOverlapping = Math.Max(maxNonOverlapping, count); - } + } return n - maxNonOverlapping; } } @@ -549,12 +599,35 @@ class Solution { } ``` +```swift +class Solution { + func eraseOverlapIntervals(_ intervals: [[Int]]) -> Int { + var intervals = intervals + intervals.sort { $0[1] < $1[1] } + let n = intervals.count + var dp = [Int](repeating: 0, count: n) + + for i in 0.. Int { + var intervals = intervals + intervals.sort { $0[1] < $1[1] } + let n = intervals.count + var dp = [Int](repeating: 0, count: n) + dp[0] = 1 + + func bs(_ r: Int, _ target: Int) -> Int { + var l = 0 + var r = r + while l < r { + let m = (l + r) >> 1 + if intervals[m][1] <= target { + l = m + 1 + } else { + r = m + } + } + return l + } + + for i in 1..= prevEnd: prevEnd = end @@ -843,7 +952,7 @@ public class Solution { Arrays.sort(intervals, (a, b) -> Integer.compare(a[0], b[0])); int res = 0; int prevEnd = intervals[0][1]; - + for (int i = 1; i < intervals.length; i++) { int start = intervals[i][0]; int end = intervals[i][1]; @@ -914,7 +1023,7 @@ public class Solution { Array.Sort(intervals, (a, b) => a[0].CompareTo(b[0])); int res = 0; int prevEnd = intervals[0][1]; - + for (int i = 1; i < intervals.Length; i++) { int start = intervals[i][0]; int end = intervals[i][1]; @@ -981,12 +1090,36 @@ class Solution { } ``` +```swift +class Solution { + func eraseOverlapIntervals(_ intervals: [[Int]]) -> Int { + var intervals = intervals + intervals.sort { $0[0] < $1[0] } + + var res = 0 + var prevEnd = intervals[0][1] + + for i in 1..= prevEnd { + prevEnd = end + } else { + res += 1 + prevEnd = min(end, prevEnd) + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -1007,7 +1140,7 @@ class Solution: else: prevEnd = intervals[i][1] - + return res ``` @@ -1017,7 +1150,7 @@ public class Solution { Arrays.sort(intervals, (a, b) -> Integer.compare(a[1], b[1])); int res = 0; int prevEnd = intervals[0][1]; - + for (int i = 1; i < intervals.length; i++) { int start = intervals[i][0]; int end = intervals[i][1]; @@ -1087,7 +1220,7 @@ public class Solution { Array.Sort(intervals, (a, b) => a[1].CompareTo(b[1])); int res = 0; int prevEnd = intervals[0][1]; - + for (int i = 1; i < intervals.Length; i++) { int start = intervals[i][0]; int end = intervals[i][1]; @@ -1142,9 +1275,31 @@ class Solution { } ``` +```swift +class Solution { + func eraseOverlapIntervals(_ intervals: [[Int]]) -> Int { + var intervals = intervals + intervals.sort { $0[1] < $1[1] } + + var prevEnd = intervals[0][1] + var res = 0 + + for i in 1.. intervals[i][0] { + res += 1 + } else { + prevEnd = intervals[i][1] + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. \ No newline at end of file +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. diff --git a/articles/number-of-closed-islands.md b/articles/number-of-closed-islands.md new file mode 100644 index 000000000..27bcab713 --- /dev/null +++ b/articles/number-of-closed-islands.md @@ -0,0 +1,854 @@ +## 1. Depth First Search - I + +::tabs-start + +```python +class Solution: + def closedIsland(self, grid: List[List[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + directions = [[0, 1], [0, -1], [1, 0], [-1, 0]] + visit = set() + + def dfs(r, c): + if r < 0 or c < 0 or r == ROWS or c == COLS: + return 0 # False + if grid[r][c] == 1 or (r, c) in visit: + return 1 # True + + visit.add((r, c)) + res = True + for dx, dy in directions: + if not dfs(r + dx, c + dy): + res = False + return res + + res = 0 + for r in range(ROWS): + for c in range(COLS): + if not grid[r][c] and (r, c) not in visit: + res += dfs(r, c) + + return res +``` + +```java +public class Solution { + private int[][] directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + private boolean[][] visit; + private int ROWS, COLS; + + public int closedIsland(int[][] grid) { + ROWS = grid.length; + COLS = grid[0].length; + visit = new boolean[ROWS][COLS]; + + int res = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] == 0 && !visit[r][c]) { + if (dfs(grid, r, c)) { + res++; + } + } + } + } + return res; + } + + private boolean dfs(int[][] grid, int r, int c) { + if (r < 0 || c < 0 || r == ROWS || c == COLS) { + return false; + } + if (grid[r][c] == 1 || visit[r][c]) { + return true; + } + + visit[r][c] = true; + boolean res = true; + for (int[] d : directions) { + if (!dfs(grid, r + d[0], c + d[1])) { + res = false; + } + } + return res; + } +} +``` + +```cpp +class Solution { + int ROWS, COLS; + vector> directions; + vector> visit; + +public: + int closedIsland(vector>& grid) { + ROWS = grid.size(); + COLS = grid[0].size(); + directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + visit.assign(ROWS, vector(COLS, false)); + + int res = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] == 0 && !visit[r][c]) { + if (dfs(grid, r, c)) { + res++; + } + } + } + } + return res; + } + +private: + bool dfs(vector>& grid, int r, int c) { + if (r < 0 || c < 0 || r == ROWS || c == COLS) { + return false; + } + if (grid[r][c] == 1 || visit[r][c]) { + return true; + } + + visit[r][c] = true; + bool res = true; + for (auto& d : directions) { + if (!dfs(grid, r + d[0], c + d[1])) { + res = false; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + closedIsland(grid) { + const ROWS = grid.length, + COLS = grid[0].length; + const directions = [0, 1, 0, -1, 0]; + const visit = Array.from({ length: ROWS }, () => + Array(COLS).fill(false), + ); + + const dfs = (r, c) => { + if (r < 0 || c < 0 || r === ROWS || c === COLS) return false; + if (grid[r][c] === 1 || visit[r][c]) return true; + + visit[r][c] = true; + let res = true; + for (let d = 0; d < 4; d++) { + if (!dfs(r + directions[d], c + directions[d + 1])) { + res = false; + } + } + return res; + }; + + let res = 0; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] === 0 && !visit[r][c]) { + if (dfs(r, c)) res++; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns in the given grid. + +--- + +## 2. Depth First Search - II + +::tabs-start + +```python +class Solution: + def closedIsland(self, grid: list[list[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + directions = [0, 1, 0, -1, 0] + + def dfs(r, c): + if r < 0 or c < 0 or r == ROWS or c == COLS or grid[r][c] == 1: + return + grid[r][c] = 1 + for d in range(4): + dfs(r + directions[d], c + directions[d + 1]) + + for r in range(ROWS): + dfs(r, 0) + dfs(r, COLS - 1) + for c in range(COLS): + dfs(0, c) + dfs(ROWS - 1, c) + + res = 0 + for r in range(1, ROWS - 1): + for c in range(1, COLS - 1): + if grid[r][c] == 0: + dfs(r, c) + res += 1 + return res +``` + +```java +public class Solution { + private int ROWS, COLS; + private int[] directions = {0, 1, 0, -1, 0}; + + public int closedIsland(int[][] grid) { + ROWS = grid.length; + COLS = grid[0].length; + + for (int r = 0; r < ROWS; r++) { + dfs(grid, r, 0); + dfs(grid, r, COLS - 1); + } + for (int c = 0; c < COLS; c++) { + dfs(grid, 0, c); + dfs(grid, ROWS - 1, c); + } + + int res = 0; + for (int r = 1; r < ROWS - 1; r++) { + for (int c = 1; c < COLS - 1; c++) { + if (grid[r][c] == 0) { + dfs(grid, r, c); + res++; + } + } + } + return res; + } + + private void dfs(int[][] grid, int r, int c) { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == 1) { + return; + } + grid[r][c] = 1; + for (int d = 0; d < 4; d++) { + dfs(grid, r + directions[d], c + directions[d + 1]); + } + } +} +``` + +```cpp +class Solution { + const int directions[5] = {0, 1, 0, -1, 0}; + int ROWS, COLS; + +public: + int closedIsland(vector>& grid) { + ROWS = grid.size(); + COLS = grid[0].size(); + + for (int r = 0; r < ROWS; r++) { + dfs(grid, r, 0); + dfs(grid, r, COLS - 1); + } + for (int c = 0; c < COLS; c++) { + dfs(grid, 0, c); + dfs(grid, ROWS - 1, c); + } + + int res = 0; + for (int r = 1; r < ROWS - 1; r++) { + for (int c = 1; c < COLS - 1; c++) { + if (grid[r][c] == 0) { + dfs(grid, r, c); + res++; + } + } + } + return res; + } + +private: + void dfs(vector>& grid, int r, int c) { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == 1) { + return; + } + grid[r][c] = 1; + for (int d = 0; d < 4; d++) { + dfs(grid, r + directions[d], c + directions[d + 1]); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + closedIsland(grid) { + const ROWS = grid.length, + COLS = grid[0].length; + const directions = [0, 1, 0, -1, 0]; + + const dfs = (r, c) => { + if (r < 0 || c < 0 || r === ROWS || c === COLS || grid[r][c] === 1) + return; + grid[r][c] = 1; + for (let d = 0; d < 4; d++) { + dfs(r + directions[d], c + directions[d + 1]); + } + }; + + for (let r = 0; r < ROWS; r++) { + dfs(r, 0); + dfs(r, COLS - 1); + } + for (let c = 0; c < COLS; c++) { + dfs(0, c); + dfs(ROWS - 1, c); + } + + let res = 0; + for (let r = 1; r < ROWS - 1; r++) { + for (let c = 1; c < COLS - 1; c++) { + if (grid[r][c] === 0) { + dfs(r, c); + res++; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns in the given grid. + +--- + +## 3. Breadth First Search + +::tabs-start + +```python +class Solution: + def closedIsland(self, grid: list[list[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + directions = [[0, 1], [0, -1], [1, 0], [-1, 0]] + visit = set() + res = 0 + + def bfs(r, c): + q = deque([(r, c)]) + visit.add((r, c)) + is_closed = True + + while q: + x, y = q.popleft() + for dx, dy in directions: + nx, ny = x + dx, y + dy + if nx < 0 or ny < 0 or nx >= ROWS or ny >= COLS: + is_closed = False + continue + if grid[nx][ny] == 1 or (nx, ny) in visit: + continue + visit.add((nx, ny)) + q.append((nx, ny)) + + return is_closed + + for r in range(ROWS): + for c in range(COLS): + if grid[r][c] == 0 and (r, c) not in visit: + res += bfs(r, c) + + return res +``` + +```java +public class Solution { + private int[][] directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + private int ROWS, COLS; + private boolean[][] visit; + + public int closedIsland(int[][] grid) { + ROWS = grid.length; + COLS = grid[0].length; + visit = new boolean[ROWS][COLS]; + int res = 0; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] == 0 && !visit[r][c]) { + if (bfs(grid, r, c)) res++; + } + } + } + return res; + } + + private boolean bfs(int[][] grid, int r, int c) { + Queue q = new LinkedList<>(); + q.offer(new int[]{r, c}); + visit[r][c] = true; + boolean isClosed = true; + + while (!q.isEmpty()) { + int[] cell = q.poll(); + int x = cell[0], y = cell[1]; + + for (int[] d : directions) { + int nx = x + d[0], ny = y + d[1]; + if (nx < 0 || ny < 0 || nx >= ROWS || ny >= COLS) { + isClosed = false; + continue; + } + if (grid[nx][ny] == 1 || visit[nx][ny]) continue; + visit[nx][ny] = true; + q.offer(new int[]{nx, ny}); + } + } + return isClosed; + } +} +``` + +```cpp +class Solution { + int directions[4][2] = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + int ROWS, COLS; + vector> visit; + +public: + int closedIsland(vector>& grid) { + ROWS = grid.size(); + COLS = grid[0].size(); + visit.assign(ROWS, vector(COLS, false)); + int res = 0; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] == 0 && !visit[r][c]) { + if (bfs(grid, r, c)) res++; + } + } + } + return res; + } + +private: + bool bfs(vector>& grid, int r, int c) { + queue> q; + q.push({r, c}); + visit[r][c] = true; + bool isClosed = true; + + while (!q.empty()) { + auto [x, y] = q.front();q.pop(); + for (auto& d : directions) { + int nx = x + d[0], ny = y + d[1]; + if (nx < 0 || ny < 0 || nx >= ROWS || ny >= COLS) { + isClosed = false; + continue; + } + if (grid[nx][ny] == 1 || visit[nx][ny]) continue; + visit[nx][ny] = true; + q.push({nx, ny}); + } + } + return isClosed; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + closedIsland(grid) { + const ROWS = grid.length, + COLS = grid[0].length; + const directions = [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ]; + const visit = Array.from({ length: ROWS }, () => + Array(COLS).fill(false), + ); + let res = 0; + + const bfs = (r, c) => { + const q = new Queue([[r, c]]); + visit[r][c] = true; + let isClosed = true; + + while (!q.isEmpty()) { + const [x, y] = q.pop(); + for (const [dx, dy] of directions) { + const nx = x + dx, + ny = y + dy; + if (nx < 0 || ny < 0 || nx >= ROWS || ny >= COLS) { + isClosed = false; + continue; + } + if (grid[nx][ny] === 1 || visit[nx][ny]) continue; + visit[nx][ny] = true; + q.push([nx, ny]); + } + } + return isClosed; + }; + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] === 0 && !visit[r][c]) { + if (bfs(r, c)) res++; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns in the given grid. + +--- + +## 4. Disjoint Set Union + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.Parent = list(range(n + 1)) + self.Size = [1] * (n + 1) + + def find(self, node): + if self.Parent[node] != node: + self.Parent[node] = self.find(self.Parent[node]) + return self.Parent[node] + + def union(self, u, v): + pu, pv = self.find(u), self.find(v) + if pu == pv: + return False + if self.Size[pu] >= self.Size[pv]: + self.Size[pu] += self.Size[pv] + self.Parent[pv] = pu + else: + self.Size[pv] += self.Size[pu] + self.Parent[pu] = pv + return True + +class Solution: + def closedIsland(self, grid: List[List[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + N = ROWS * COLS + def index(r, c): + return r * COLS + c + + dsu = DSU(N) + directions = [0, 1, 0, -1, 0] + for r in range(ROWS): + for c in range(COLS): + if grid[r][c] == 0: + for d in range(4): + nr, nc = r + directions[d], c + directions[d + 1] + if min(nr, nc) < 0 or nr == ROWS or nc == COLS: + dsu.union(N, index(r, c)) + elif grid[nr][nc] == 0: + dsu.union(index(r, c), index(nr, nc)) + + res = 0 + rootN = dsu.find(N) + for r in range(ROWS): + for c in range(COLS): + if grid[r][c] == 1: + continue + node = index(r, c) + root = dsu.find(node) + if root == node and root != rootN: + res += 1 + return res +``` + +```java +class DSU { + int[] Parent, Size; + + public DSU(int n) { + Parent = new int[n + 1]; + Size = new int[n + 1]; + for (int i = 0; i <= n; i++) { + Parent[i] = i; + Size[i] = 1; + } + } + + public int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + public boolean union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (Size[pu] >= Size[pv]) { + Size[pu] += Size[pv]; + Parent[pv] = pu; + } else { + Size[pv] += Size[pu]; + Parent[pu] = pv; + } + return true; + } +} + +public class Solution { + public int closedIsland(int[][] grid) { + int ROWS = grid.length, COLS = grid[0].length; + int N = ROWS * COLS; + + DSU dsu = new DSU(N); + int[] directions = {0, 1, 0, -1, 0}; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] == 0) { + for (int d = 0; d < 4; d++) { + int nr = r + directions[d], nc = c + directions[d + 1]; + if (nr < 0 || nc < 0 || nr == ROWS || nc == COLS) { + dsu.union(N, r * COLS + c); + } else if (grid[nr][nc] == 0) { + dsu.union(r * COLS + c, nr * COLS + nc); + } + } + } + } + } + + int res = 0, rootN = dsu.find(N); + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] == 0) { + int node = r * COLS + c; + int root = dsu.find(node); + if (root == node && root != rootN) { + res++; + } + } + } + } + return res; + } +} +``` + +```cpp +class DSU { +public: + vector Parent, Size; + + DSU(int n) { + Parent.resize(n + 1); + Size.resize(n + 1, 1); + for (int i = 0; i <= n; i++) { + Parent[i] = i; + } + } + + int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + bool unionSets(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (Size[pu] >= Size[pv]) { + Size[pu] += Size[pv]; + Parent[pv] = pu; + } else { + Size[pv] += Size[pu]; + Parent[pu] = pv; + } + return true; + } +}; + +class Solution { +public: + int closedIsland(vector>& grid) { + int ROWS = grid.size(), COLS = grid[0].size(); + int N = ROWS * COLS; + + DSU dsu(N); + int directions[5] = {0, 1, 0, -1, 0}; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] == 0) { + for (int d = 0; d < 4; d++) { + int nr = r + directions[d], nc = c + directions[d + 1]; + if (nr < 0 || nc < 0 || nr == ROWS || nc == COLS) { + dsu.unionSets(N, r * COLS + c); + } else if (grid[nr][nc] == 0) { + dsu.unionSets(r * COLS + c, nr * COLS + nc); + } + } + } + } + } + + int res = 0, rootN = dsu.find(N); + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] == 0) { + int node = r * COLS + c; + int root = dsu.find(node); + if (root == node && root != rootN) { + res++; + } + } + } + } + return res; + } +}; +``` + +```javascript +class DSU { + /** + * @constructor + * @param {number} n + */ + constructor(n) { + this.parent = Array.from({ length: n + 1 }, (_, i) => i); + this.size = new Array(n + 1).fill(1); + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.parent[node] !== node) { + this.parent[node] = this.find(this.parent[node]); + } + return this.parent[node]; + } + + /** + * @param {number} u + * @param {number} u=v + * @return {boolean} + */ + union(u, v) { + let pu = this.find(u), + pv = this.find(v); + if (pu === pv) return false; + if (this.size[pu] >= this.size[pv]) { + this.size[pu] += this.size[pv]; + this.parent[pv] = pu; + } else { + this.size[pv] += this.size[pu]; + this.parent[pu] = pv; + } + return true; + } +} + +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + closedIsland(grid) { + const ROWS = grid.length, + COLS = grid[0].length; + const N = ROWS * COLS; + + const dsu = new DSU(N); + const directions = [0, 1, 0, -1, 0]; + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] === 0) { + for (let d = 0; d < 4; d++) { + let nr = r + directions[d], + nc = c + directions[d + 1]; + if (nr < 0 || nc < 0 || nr === ROWS || nc === COLS) { + dsu.union(N, r * COLS + c); + } else if (grid[nr][nc] === 0) { + dsu.union(r * COLS + c, nr * COLS + nc); + } + } + } + } + } + + let res = 0, + rootN = dsu.find(N); + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] === 0) { + let node = r * COLS + c; + let root = dsu.find(node); + if (root === node && root !== rootN) { + res++; + } + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns in the given grid. diff --git a/articles/number-of-dice-rolls-with-target-sum.md b/articles/number-of-dice-rolls-with-target-sum.md index 442065a4a..e5dda8bfe 100644 --- a/articles/number-of-dice-rolls-with-target-sum.md +++ b/articles/number-of-dice-rolls-with-target-sum.md @@ -109,8 +109,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(k ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(k ^ n)$ +- Space complexity: $O(n)$ > Where $n$ is the number of dices, $k$ is the number of faces each dice have, and $t$ is the target value. @@ -224,7 +224,9 @@ class Solution { */ numRollsToTarget(n, k, target) { const MOD = 1e9 + 7; - const dp = Array.from({ length: n + 1 }, () => Array(target + 1).fill(-1)); + const dp = Array.from({ length: n + 1 }, () => + Array(target + 1).fill(-1), + ); const count = (n, target) => { if (n === 0) { @@ -253,8 +255,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * t * k)$ -* Space complexity: $O(n * t)$ +- Time complexity: $O(n * t * k)$ +- Space complexity: $O(n * t)$ > Where $n$ is the number of dices, $k$ is the number of faces each dice have, and $t$ is the target value. @@ -330,7 +332,9 @@ class Solution { */ numRollsToTarget(n, k, target) { const MOD = 1e9 + 7; - const dp = Array.from({ length: n + 1 }, () => Array(target + 1).fill(0)); + const dp = Array.from({ length: n + 1 }, () => + Array(target + 1).fill(0), + ); dp[0][0] = 1; for (let i = 1; i <= n; i++) { @@ -350,8 +354,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * t * k)$ -* Space complexity: $O(n * t)$ +- Time complexity: $O(n * t * k)$ +- Space complexity: $O(n * t)$ > Where $n$ is the number of dices, $k$ is the number of faces each dice have, and $t$ is the target value. @@ -455,8 +459,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * t * k)$ -* Space complexity: $O(t)$ +- Time complexity: $O(n * t * k)$ +- Space complexity: $O(t)$ > Where $n$ is the number of dices, $k$ is the number of faces each dice have, and $t$ is the target value. @@ -567,7 +571,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * t * k)$ -* Space complexity: $O(t)$ +- Time complexity: $O(n * t * k)$ +- Space complexity: $O(t)$ -> Where $n$ is the number of dices, $k$ is the number of faces each dice have, and $t$ is the target value. \ No newline at end of file +> Where $n$ is the number of dices, $k$ is the number of faces each dice have, and $t$ is the target value. diff --git a/articles/number-of-enclaves.md b/articles/number-of-enclaves.md new file mode 100644 index 000000000..8d7123b25 --- /dev/null +++ b/articles/number-of-enclaves.md @@ -0,0 +1,781 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def numEnclaves(self, grid: List[List[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + direct = [[0, 1], [0, -1], [1, 0], [-1, 0]] + + # Return num of land cells + def dfs(r, c): + if (r < 0 or c < 0 or + r == ROWS or c == COLS or + not grid[r][c] or (r, c) in visit): + return 0 + visit.add((r, c)) + res = 1 + for dr, dc in direct: + res += dfs(r + dr, c + dc) + return res + + visit = set() + land, borderLand = 0, 0 + for r in range(ROWS): + for c in range(COLS): + land += grid[r][c] + if (grid[r][c] and (r, c) not in visit and + (c in [0, COLS - 1] or r in [0, ROWS - 1])): + borderLand += dfs(r, c) + + return land - borderLand +``` + +```java +public class Solution { + private int ROWS, COLS; + private boolean[][] visit; + private int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + public int numEnclaves(int[][] grid) { + this.ROWS = grid.length; + this.COLS = grid[0].length; + this.visit = new boolean[ROWS][COLS]; + + int land = 0, borderLand = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + land += grid[r][c]; + if (grid[r][c] == 1 && !visit[r][c] && + (r == 0 || r == ROWS - 1 || c == 0 || c == COLS - 1)) { + borderLand += dfs(r, c, grid); + } + } + } + return land - borderLand; + } + + private int dfs(int r, int c, int[][] grid) { + if (r < 0 || c < 0 || r == ROWS || c == COLS || + grid[r][c] == 0 || visit[r][c]) { + return 0; + } + visit[r][c] = true; + int res = 1; + for (int[] d : direct) { + res += dfs(r + d[0], c + d[1], grid); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int ROWS, COLS; + vector> visit; + vector> direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + int numEnclaves(vector>& grid) { + this->ROWS = grid.size(); + this->COLS = grid[0].size(); + this->visit = vector>(ROWS, vector(COLS, false)); + + int land = 0, borderLand = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + land += grid[r][c]; + if (grid[r][c] == 1 && !visit[r][c] && + (r == 0 || r == ROWS - 1 || c == 0 || c == COLS - 1)) { + borderLand += dfs(r, c, grid); + } + } + } + return land - borderLand; + } + +private: + int dfs(int r, int c, vector>& grid) { + if (r < 0 || c < 0 || r == ROWS || c == COLS || + grid[r][c] == 0 || visit[r][c]) { + return 0; + } + visit[r][c] = true; + int res = 1; + for (auto& d : direct) { + res += dfs(r + d[0], c + d[1], grid); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + numEnclaves(grid) { + const ROWS = grid.length, + COLS = grid[0].length; + const visit = Array.from({ length: ROWS }, () => + Array(COLS).fill(false), + ); + const direct = [0, 1, 0, -1, 0]; + + const dfs = (r, c) => { + if ( + r < 0 || + c < 0 || + r === ROWS || + c === COLS || + grid[r][c] === 0 || + visit[r][c] + ) { + return 0; + } + visit[r][c] = true; + let res = 1; + for (let d = 0; d < 4; d++) { + res += dfs(r + direct[d], c + direct[d + 1]); + } + return res; + }; + + let land = 0, + borderLand = 0; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + land += grid[r][c]; + if ( + grid[r][c] === 1 && + !visit[r][c] && + (r === 0 || r === ROWS - 1 || c === 0 || c === COLS - 1) + ) { + borderLand += dfs(r, c); + } + } + } + return land - borderLand; + } +} +``` + +```csharp +public class Solution { + public int NumEnclaves(int[][] grid) { + int ROWS = grid.Length, COLS = grid[0].Length; + bool[][] visit = new bool[ROWS][]; + for (int i = 0; i < ROWS; i++) visit[i] = new bool[COLS]; + int[][] direct = new int[][] { + new int[] { 0, 1 }, new int[] { 0, -1 }, + new int[] { 1, 0 }, new int[] { -1, 0 } + }; + + int Dfs(int r, int c) { + if (r < 0 || c < 0 || r == ROWS || c == COLS || grid[r][c] == 0 || visit[r][c]) + return 0; + + visit[r][c] = true; + int res = 1; + foreach (var d in direct) { + res += Dfs(r + d[0], c + d[1]); + } + return res; + } + + int land = 0, borderLand = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + land += grid[r][c]; + if (grid[r][c] == 1 && !visit[r][c] && + (r == 0 || r == ROWS - 1 || c == 0 || c == COLS - 1)) { + borderLand += Dfs(r, c); + } + } + } + + return land - borderLand; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns in the given grid. + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class Solution: + def numEnclaves(self, grid: list[list[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + direct = [[0, 1], [0, -1], [1, 0], [-1, 0]] + visit = [[False] * COLS for _ in range(ROWS)] + q = deque() + + land, borderLand = 0, 0 + for r in range(ROWS): + for c in range(COLS): + land += grid[r][c] + if (grid[r][c] == 1 and + (r in [0, ROWS - 1] or c in [0, COLS - 1]) + ): + q.append((r, c)) + visit[r][c] = True + + while q: + r, c = q.popleft() + borderLand += 1 + for dr, dc in direct: + nr, nc = r + dr, c + dc + if (0 <= nr < ROWS and 0 <= nc < COLS and + grid[nr][nc] == 1 and not visit[nr][nc] + ): + q.append((nr, nc)) + visit[nr][nc] = True + + return land - borderLand +``` + +```java +public class Solution { + public int numEnclaves(int[][] grid) { + int ROWS = grid.length, COLS = grid[0].length; + int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + boolean[][] visit = new boolean[ROWS][COLS]; + Queue q = new LinkedList<>(); + + int land = 0, borderLand = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + land += grid[r][c]; + if (grid[r][c] == 1 && (r == 0 || r == ROWS - 1 || + c == 0 || c == COLS - 1)) { + q.offer(new int[]{r, c}); + visit[r][c] = true; + } + } + } + + while (!q.isEmpty()) { + int[] cell = q.poll(); + int r = cell[0], c = cell[1]; + borderLand++; + + for (int[] d : direct) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS && + grid[nr][nc] == 1 && !visit[nr][nc]) { + q.offer(new int[]{nr, nc}); + visit[nr][nc] = true; + } + } + } + + return land - borderLand; + } +} +``` + +```cpp +class Solution { +public: + int ROWS, COLS; + vector> visit; + vector> direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + int numEnclaves(vector>& grid) { + this->ROWS = grid.size(); + this->COLS = grid[0].size(); + this->visit = vector>(ROWS, vector(COLS, false)); + + int land = 0, borderLand = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + land += grid[r][c]; + if (grid[r][c] == 1 && !visit[r][c] && + (r == 0 || r == ROWS - 1 || c == 0 || c == COLS - 1)) { + borderLand += dfs(r, c, grid); + } + } + } + return land - borderLand; + } + +private: + int dfs(int r, int c, vector>& grid) { + if (r < 0 || c < 0 || r == ROWS || c == COLS || + grid[r][c] == 0 || visit[r][c]) { + return 0; + } + visit[r][c] = true; + int res = 1; + for (auto& d : direct) { + res += dfs(r + d[0], c + d[1], grid); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + numEnclaves(grid) { + const ROWS = grid.length, + COLS = grid[0].length; + const direct = [0, 1, 0, -1, 0]; + const visit = Array.from({ length: ROWS }, () => + Array(COLS).fill(false), + ); + const q = new Queue(); + + let land = 0, + borderLand = 0; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + land += grid[r][c]; + if ( + grid[r][c] === 1 && + (r === 0 || r === ROWS - 1 || c === 0 || c === COLS - 1) + ) { + q.push([r, c]); + visit[r][c] = true; + } + } + } + + while (!q.isEmpty()) { + let [r, c] = q.pop(); + borderLand++; + for (let d = 0; d < 4; d++) { + let nr = r + direct[d], + nc = c + direct[d + 1]; + if ( + nr >= 0 && + nc >= 0 && + nr < ROWS && + nc < COLS && + grid[nr][nc] === 1 && + !visit[nr][nc] + ) { + q.push([nr, nc]); + visit[nr][nc] = true; + } + } + } + + return land - borderLand; + } +} +``` + +```csharp +public class Solution { + public int NumEnclaves(int[][] grid) { + int ROWS = grid.Length, COLS = grid[0].Length; + int[][] direct = new int[][] { + new int[] {0, 1}, new int[] {0, -1}, + new int[] {1, 0}, new int[] {-1, 0} + }; + + bool[][] visit = new bool[ROWS][]; + for (int i = 0; i < ROWS; i++) visit[i] = new bool[COLS]; + + Queue q = new Queue(); + int land = 0, borderLand = 0; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + land += grid[r][c]; + if (grid[r][c] == 1 && (r == 0 || r == ROWS - 1 || c == 0 || c == COLS - 1)) { + q.Enqueue(new int[] { r, c }); + visit[r][c] = true; + } + } + } + + while (q.Count > 0) { + var cell = q.Dequeue(); + int r = cell[0], c = cell[1]; + borderLand++; + + foreach (var d in direct) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS && + grid[nr][nc] == 1 && !visit[nr][nc]) { + q.Enqueue(new int[] { nr, nc }); + visit[nr][nc] = true; + } + } + } + + return land - borderLand; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns in the given grid. + +--- + +## 3. Disjoint Set Union + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.Parent = list(range(n + 1)) + self.Size = [1] * (n + 1) + + def find(self, node): + if self.Parent[node] != node: + self.Parent[node] = self.find(self.Parent[node]) + return self.Parent[node] + + def union(self, u, v): + pu, pv = self.find(u), self.find(v) + if pu == pv: + return False + if self.Size[pu] >= self.Size[pv]: + self.Size[pu] += self.Size[pv] + self.Parent[pv] = pu + else: + self.Size[pv] += self.Size[pu] + self.Parent[pu] = pv + return True + +class Solution: + def numEnclaves(self, grid: list[list[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + N = ROWS * COLS + def index(r, c): + return r * COLS + c + + dsu = DSU(N) + directions = [0, 1, 0, -1, 0] + land = 0 + for r in range(ROWS): + for c in range(COLS): + if grid[r][c] == 0: + continue + land += 1 + for d in range(4): + nr, nc = r + directions[d], c + directions[d + 1] + if 0 <= nr < ROWS and 0 <= nc < COLS: + if grid[nr][nc] == 1: + dsu.union(index(r, c), index(nr, nc)) + else: + dsu.union(N, index(r, c)) + + borderLand = dsu.Size[dsu.find(N)] + return land - borderLand + 1 +``` + +```java +class DSU { + int[] Parent, Size; + + public DSU(int n) { + Parent = new int[n + 1]; + Size = new int[n + 1]; + for (int i = 0; i <= n; i++) { + Parent[i] = i; + Size[i] = 1; + } + } + + public int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + public boolean union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (Size[pu] >= Size[pv]) { + Size[pu] += Size[pv]; + Parent[pv] = pu; + } else { + Size[pv] += Size[pu]; + Parent[pu] = pv; + } + return true; + } +} + +public class Solution { + public int numEnclaves(int[][] grid) { + int ROWS = grid.length, COLS = grid[0].length; + int N = ROWS * COLS; + DSU dsu = new DSU(N); + int[] directions = {0, 1, 0, -1, 0}; + int land = 0; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] == 0) continue; + land++; + for (int d = 0; d < 4; d++) { + int nr = r + directions[d], nc = c + directions[d + 1]; + if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS) { + if (grid[nr][nc] == 1) { + dsu.union(r * COLS + c, nr * COLS + nc); + } + } else { + dsu.union(N, r * COLS + c); + } + } + } + } + + int borderLand = dsu.Size[dsu.find(N)]; + return land - borderLand + 1; + } +} +``` + +```cpp +class DSU { +public: + vector Parent, Size; + + DSU(int n) { + Parent.resize(n + 1); + Size.resize(n + 1, 1); + for (int i = 0; i <= n; i++) { + Parent[i] = i; + } + } + + int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + bool unionSets(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (Size[pu] >= Size[pv]) { + Size[pu] += Size[pv]; + Parent[pv] = pu; + } else { + Size[pv] += Size[pu]; + Parent[pu] = pv; + } + return true; + } +}; + +class Solution { +public: + int numEnclaves(vector>& grid) { + int ROWS = grid.size(), COLS = grid[0].size(); + int N = ROWS * COLS; + DSU dsu(N); + vector directions = {0, 1, 0, -1, 0}; + int land = 0; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] == 0) continue; + land++; + for (int d = 0; d < 4; d++) { + int nr = r + directions[d], nc = c + directions[d + 1]; + if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS) { + if (grid[nr][nc] == 1) { + dsu.unionSets(r * COLS + c, nr * COLS + nc); + } + } else { + dsu.unionSets(N, r * COLS + c); + } + } + } + } + + int borderLand = dsu.Size[dsu.find(N)]; + return land - borderLand + 1; + } +}; +``` + +```javascript +class DSU { + /** + * @constructor + * @param {number} n + */ + constructor(n) { + this.parent = Array.from({ length: n + 1 }, (_, i) => i); + this.size = new Array(n + 1).fill(1); + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.parent[node] !== node) { + this.parent[node] = this.find(this.parent[node]); + } + return this.parent[node]; + } + + /** + * @param {number} u + * @param {number} u=v + * @return {boolean} + */ + union(u, v) { + let pu = this.find(u), + pv = this.find(v); + if (pu === pv) return false; + if (this.size[pu] >= this.size[pv]) { + this.size[pu] += this.size[pv]; + this.parent[pv] = pu; + } else { + this.size[pv] += this.size[pu]; + this.parent[pu] = pv; + } + return true; + } +} + +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + numEnclaves(grid) { + const ROWS = grid.length, + COLS = grid[0].length; + const N = ROWS * COLS; + const dsu = new DSU(N); + const directions = [0, 1, 0, -1, 0]; + let land = 0; + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] === 0) continue; + land++; + for (let d = 0; d < 4; d++) { + let nr = r + directions[d], + nc = c + directions[d + 1]; + if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS) { + if (grid[nr][nc] === 1) { + dsu.union(r * COLS + c, nr * COLS + nc); + } + } else { + dsu.union(N, r * COLS + c); + } + } + } + } + + const borderLand = dsu.size[dsu.find(N)]; + return land - borderLand + 1; + } +} +``` + +```csharp +public class DSU { + public int[] Parent, Size; + + public DSU(int n) { + Parent = new int[n + 1]; + Size = new int[n + 1]; + for (int i = 0; i <= n; i++) { + Parent[i] = i; + Size[i] = 1; + } + } + + public int Find(int node) { + if (Parent[node] != node) { + Parent[node] = Find(Parent[node]); + } + return Parent[node]; + } + + public bool Union(int u, int v) { + int pu = Find(u), pv = Find(v); + if (pu == pv) return false; + if (Size[pu] >= Size[pv]) { + Size[pu] += Size[pv]; + Parent[pv] = pu; + } else { + Size[pv] += Size[pu]; + Parent[pu] = pv; + } + return true; + } +} + +public class Solution { + public int NumEnclaves(int[][] grid) { + int ROWS = grid.Length, COLS = grid[0].Length; + int N = ROWS * COLS; + DSU dsu = new DSU(N); + int[] directions = new int[] { 0, 1, 0, -1, 0 }; + int land = 0; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] == 0) continue; + land++; + for (int d = 0; d < 4; d++) { + int nr = r + directions[d], nc = c + directions[d + 1]; + if (nr >= 0 && nc >= 0 && nr < ROWS && nc < COLS) { + if (grid[nr][nc] == 1) { + dsu.Union(r * COLS + c, nr * COLS + nc); + } + } else { + dsu.Union(N, r * COLS + c); + } + } + } + } + + int borderLand = dsu.Size[dsu.Find(N)]; + return land - borderLand + 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns in the given grid. diff --git a/articles/number-of-flowers-in-full-bloom.md b/articles/number-of-flowers-in-full-bloom.md new file mode 100644 index 000000000..f11f87559 --- /dev/null +++ b/articles/number-of-flowers-in-full-bloom.md @@ -0,0 +1,680 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def fullBloomFlowers(self, flowers: List[List[int]], people: List[int]) -> List[int]: + res = [] + + for time in people: + cnt = 0 + for start, end in flowers: + if start <= time <= end: + cnt += 1 + res.append(cnt) + + return res +``` + +```java +public class Solution { + public int[] fullBloomFlowers(int[][] flowers, int[] people) { + int m = people.length; + int[] res = new int[m]; + + for (int i = 0; i < m; i++) { + int count = 0; + for (int[] flower : flowers) { + if (flower[0] <= people[i] && people[i] <= flower[1]) { + count++; + } + } + res[i] = count; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector fullBloomFlowers(vector>& flowers, vector& people) { + int m = people.size(); + vector res(m); + + for (int i = 0; i < m; i++) { + int count = 0; + for (auto& flower : flowers) { + if (flower[0] <= people[i] && people[i] <= flower[1]) { + count++; + } + } + res[i] = count; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} flowers + * @param {number[]} people + * @return {number[]} + */ + fullBloomFlowers(flowers, people) { + let res = new Array(people.length).fill(0); + + for (let i = 0; i < people.length; i++) { + let count = 0; + for (let [start, end] of flowers) { + if (start <= people[i] && people[i] <= end) { + count++; + } + } + res[i] = count; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m)$ for the output array. + +> Where $n$ is the size of the array $flowers$, and $m$ is the size of the array $people$. + +--- + +## 2. Two Min-Heaps + +::tabs-start + +```python +class Solution: + def fullBloomFlowers(self, flowers: List[List[int]], people: List[int]) -> List[int]: + people = sorted((p, i) for i, p in enumerate(people)) + res = [0] * len(people) + count = 0 + + start = [f[0] for f in flowers] + end = [f[1] for f in flowers] + + heapq.heapify(start) + heapq.heapify(end) + + for p, i in people: + while start and start[0] <= p: + heapq.heappop(start) + count += 1 + while end and end[0] < p: + heapq.heappop(end) + count -= 1 + res[i] = count + + return res +``` + +```java +public class Solution { + public int[] fullBloomFlowers(int[][] flowers, int[] people) { + int m = people.length; + int[] res = new int[m]; + + List sortedPeople = new ArrayList<>(); + for (int i = 0; i < m; i++) { + sortedPeople.add(new int[]{people[i], i}); + } + sortedPeople.sort(Comparator.comparingInt(a -> a[0])); + + PriorityQueue startHeap = new PriorityQueue<>(); + PriorityQueue endHeap = new PriorityQueue<>(); + for (int[] f : flowers) { + startHeap.offer(f[0]); + endHeap.offer(f[1]); + } + + int count = 0; + for (int[] person : sortedPeople) { + int p = person[0], index = person[1]; + + while (!startHeap.isEmpty() && startHeap.peek() <= p) { + startHeap.poll(); + count++; + } + while (!endHeap.isEmpty() && endHeap.peek() < p) { + endHeap.poll(); + count--; + } + + res[index] = count; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector fullBloomFlowers(vector>& flowers, vector& people) { + int m = people.size(); + vector res(m); + + vector> sortedPeople; + for (int i = 0; i < m; i++) { + sortedPeople.push_back({people[i], i}); + } + sort(sortedPeople.begin(), sortedPeople.end()); + + priority_queue, greater> startHeap, endHeap; + for (const auto& f : flowers) { + startHeap.push(f[0]); + endHeap.push(f[1]); + } + + int count = 0; + for (const auto& person : sortedPeople) { + int p = person.first, index = person.second; + + while (!startHeap.empty() && startHeap.top() <= p) { + startHeap.pop(); + count++; + } + while (!endHeap.empty() && endHeap.top() < p) { + endHeap.pop(); + count--; + } + + res[index] = count; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} flowers + * @param {number[]} people + * @return {number[]} + */ + fullBloomFlowers(flowers, people) { + const m = people.length; + const res = new Array(m).fill(0); + + const sortedPeople = people.map((p, i) => [p, i]); + sortedPeople.sort((a, b) => a[0] - b[0]); + + const startHeap = new MinPriorityQueue(); + const endHeap = new MinPriorityQueue(); + for (const [s, e] of flowers) { + startHeap.enqueue(s); + endHeap.enqueue(e); + } + + let count = 0; + for (const [p, index] of sortedPeople) { + while (!startHeap.isEmpty() && startHeap.front() <= p) { + startHeap.dequeue(); + count++; + } + while (!endHeap.isEmpty() && endHeap.front() < p) { + endHeap.dequeue(); + count--; + } + res[index] = count; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m \log m + n \log n)$ +- Space complexity: $O(m + n)$ + +> Where $n$ is the size of the array $flowers$, and $m$ is the size of the array $people$. + +--- + +## 3. Min-Heap + +::tabs-start + +```python +class Solution: + def fullBloomFlowers(self, flowers: List[List[int]], people: List[int]) -> List[int]: + people = sorted((p, i) for i, p in enumerate(people)) + res = [0] * len(people) + flowers.sort() + end = [] + + j = 0 + for p, i in people: + while j < len(flowers) and flowers[j][0] <= p: + heapq.heappush(end, flowers[j][1]) + j += 1 + while end and end[0] < p: + heapq.heappop(end) + res[i] = len(end) + + return res +``` + +```java +public class Solution { + public int[] fullBloomFlowers(int[][] flowers, int[] people) { + int m = people.length; + int[] res = new int[m]; + int[][] indexedPeople = new int[m][2]; + + for (int i = 0; i < m; i++) { + indexedPeople[i] = new int[]{people[i], i}; + } + Arrays.sort(indexedPeople, Comparator.comparingInt(a -> a[0])); + Arrays.sort(flowers, Comparator.comparingInt(a -> a[0])); + + PriorityQueue endHeap = new PriorityQueue<>(); + int j = 0, n = flowers.length; + + for (int[] person : indexedPeople) { + int p = person[0], index = person[1]; + + while (j < n && flowers[j][0] <= p) { + endHeap.offer(flowers[j][1]); + j++; + } + while (!endHeap.isEmpty() && endHeap.peek() < p) { + endHeap.poll(); + } + res[index] = endHeap.size(); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector fullBloomFlowers(vector>& flowers, vector& people) { + int m = people.size(); + vector res(m); + vector> indexedPeople; + + for (int i = 0; i < m; i++) { + indexedPeople.emplace_back(people[i], i); + } + sort(indexedPeople.begin(), indexedPeople.end()); + sort(flowers.begin(), flowers.end()); + + priority_queue, greater> endHeap; + int j = 0, n = flowers.size(); + + for (auto [p, index] : indexedPeople) { + while (j < n && flowers[j][0] <= p) { + endHeap.push(flowers[j][1]); + j++; + } + while (!endHeap.empty() && endHeap.top() < p) { + endHeap.pop(); + } + res[index] = endHeap.size(); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} flowers + * @param {number[]} people + * @return {number[]} + */ + fullBloomFlowers(flowers, people) { + const m = people.length; + const res = new Array(m).fill(0); + const indexedPeople = people.map((p, i) => [p, i]); + + indexedPeople.sort((a, b) => a[0] - b[0]); + flowers.sort((a, b) => a[0] - b[0]); + + const endHeap = new MinPriorityQueue(); + let j = 0, + n = flowers.length; + + for (const [p, index] of indexedPeople) { + while (j < n && flowers[j][0] <= p) { + endHeap.enqueue(flowers[j][1]); + j++; + } + while (!endHeap.isEmpty() && endHeap.front() < p) { + endHeap.dequeue(); + } + res[index] = endHeap.size(); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m \log m + n \log n)$ +- Space complexity: $O(m + n)$ + +> Where $n$ is the size of the array $flowers$, and $m$ is the size of the array $people$. + +--- + +## 4. Sorting + Two Pointers + +::tabs-start + +```python +class Solution: + def fullBloomFlowers(self, flowers: List[List[int]], people: List[int]) -> List[int]: + start = sorted(f[0] for f in flowers) + end = sorted(f[1] for f in flowers) + + res = [0] * len(people) + peopleIndex = sorted((p, i) for i, p in enumerate(people)) + + i = j = count = 0 + for p, index in peopleIndex: + while i < len(start) and start[i] <= p: + count += 1 + i += 1 + while j < len(end) and end[j] < p: + count -= 1 + j += 1 + res[index] = count + + return res +``` + +```java +public class Solution { + public int[] fullBloomFlowers(int[][] flowers, int[] people) { + int m = people.length; + int[] res = new int[m]; + List start = new ArrayList<>(), end = new ArrayList<>(); + for (int[] f : flowers) { + start.add(f[0]); + end.add(f[1]); + } + + Collections.sort(start); + Collections.sort(end); + + int count = 0, i = 0, j = 0; + List peopleIndex = new ArrayList<>(); + for (int k = 0; k < m; k++) { + peopleIndex.add(new int[]{people[k], k}); + } + peopleIndex.sort(Comparator.comparingInt(a -> a[0])); + + for (int[] p : peopleIndex) { + int time = p[0], index = p[1]; + + while (i < start.size() && start.get(i) <= time) { + count++; + i++; + } + while (j < end.size() && end.get(j) < time) { + count--; + j++; + } + res[index] = count; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector fullBloomFlowers(vector>& flowers, vector& people) { + int m = people.size(); + vector res(m), start, end; + for (auto& f : flowers) { + start.push_back(f[0]); + end.push_back(f[1]); + } + + sort(start.begin(), start.end()); + sort(end.begin(), end.end()); + + int count = 0, i = 0, j = 0; + vector> peopleIndex; + for (int k = 0; k < m; k++) { + peopleIndex.emplace_back(people[k], k); + } + sort(peopleIndex.begin(), peopleIndex.end()); + + for (auto& [p, index] : peopleIndex) { + while (i < start.size() && start[i] <= p) { + count++; + i++; + } + while (j < end.size() && end[j] < p) { + count--; + j++; + } + res[index] = count; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} flowers + * @param {number[]} people + * @return {number[]} + */ + fullBloomFlowers(flowers, people) { + const start = [], + end = []; + for (let f of flowers) { + start.push(f[0]); + end.push(f[1]); + } + + start.sort((a, b) => a - b); + end.sort((a, b) => a - b); + + let count = 0, + i = 0, + j = 0; + const peopleIndex = people.map((p, idx) => [p, idx]); + peopleIndex.sort((a, b) => a[0] - b[0]); + + const res = new Array(people.length); + + for (let [p, index] of peopleIndex) { + while (i < start.length && start[i] <= p) { + count++; + i++; + } + while (j < end.length && end[j] < p) { + count--; + j++; + } + res[index] = count; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m \log m + n \log n)$ +- Space complexity: $O(m + n)$ + +> Where $n$ is the size of the array $flowers$, and $m$ is the size of the array $people$. + +--- + +## 5. Line Sweep + +::tabs-start + +```python +class Solution: + def fullBloomFlowers(self, flowers: List[List[int]], people: List[int]) -> List[int]: + events = [] + for start, end in flowers: + events.append((start, 1)) + events.append((end + 1, -1)) + + events.sort() + queries = sorted((p, i) for i, p in enumerate(people)) + res = [0] * len(people) + + count = j = 0 + for time, index in queries: + while j < len(events) and events[j][0] <= time: + count += events[j][1] + j += 1 + res[index] = count + + return res +``` + +```java +public class Solution { + public int[] fullBloomFlowers(int[][] flowers, int[] people) { + List events = new ArrayList<>(); + for (int[] f : flowers) { + events.add(new int[]{f[0], 1}); + events.add(new int[]{f[1] + 1, -1}); + } + + Collections.sort(events, (a, b) -> a[0] - b[0]); + int[][] queries = new int[people.length][2]; + for (int i = 0; i < people.length; i++) { + queries[i] = new int[]{people[i], i}; + } + Arrays.sort(queries, (a, b) -> Integer.compare(a[0], b[0])); + + int[] res = new int[people.length]; + int count = 0, j = 0; + for (int[] query : queries) { + int time = query[0], index = query[1]; + while (j < events.size() && events.get(j)[0] <= time) { + count += events.get(j)[1]; + j++; + } + res[index] = count; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector fullBloomFlowers(vector>& flowers, vector& people) { + vector> events; + for (auto& f : flowers) { + events.emplace_back(f[0], 1); + events.emplace_back(f[1] + 1, -1); + } + + sort(events.begin(), events.end()); + vector> queries; + for (int i = 0; i < people.size(); i++) { + queries.emplace_back(people[i], i); + } + + sort(queries.begin(), queries.end()); + vector res(people.size()); + int count = 0, j = 0; + + for (auto& [time, index] : queries) { + while (j < events.size() && events[j].first <= time) { + count += events[j++].second; + } + res[index] = count; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} flowers + * @param {number[]} people + * @return {number[]} + */ + fullBloomFlowers(flowers, people) { + let events = []; + for (let [start, end] of flowers) { + events.push([start, 1]); + events.push([end + 1, -1]); + } + + events.sort((a, b) => a[0] - b[0]); + let queries = people.map((p, i) => [p, i]).sort((a, b) => a[0] - b[0]); + let res = new Array(people.length).fill(0); + + let count = 0, + j = 0; + for (let [time, index] of queries) { + while (j < events.length && events[j][0] <= time) { + count += events[j][1]; + j++; + } + res[index] = count; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m \log m + n \log n)$ +- Space complexity: $O(m + n)$ + +> Where $n$ is the size of the array $flowers$, and $m$ is the size of the array $people$. diff --git a/articles/number-of-good-pairs.md b/articles/number-of-good-pairs.md index ea3e819e8..e19097222 100644 --- a/articles/number-of-good-pairs.md +++ b/articles/number-of-good-pairs.md @@ -70,8 +70,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -135,7 +135,7 @@ class Solution { count[num] = (count[num] || 0) + 1; } for (const c of Object.values(count)) { - res += c * (c - 1) / 2; + res += (c * (c - 1)) / 2; } return res; } @@ -146,8 +146,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -217,5 +217,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/number-of-good-paths.md b/articles/number-of-good-paths.md new file mode 100644 index 000000000..2ec0e10ee --- /dev/null +++ b/articles/number-of-good-paths.md @@ -0,0 +1,869 @@ +## 1. Brute Force (DFS) + +::tabs-start + +```python +class Solution: + def numberOfGoodPaths(self, vals: List[int], edges: List[List[int]]) -> int: + n = len(vals) + adj = [[] for _ in range(n)] + for u, v in edges: + adj[u].append(v) + adj[v].append(u) + + def dfs(node, startNode, parent): + if vals[node] > vals[startNode]: + return 0 + + res = 0 + if vals[node] == vals[startNode] and node >= startNode: + res += 1 + + for child in adj[node]: + if child == parent: + continue + res += dfs(child, startNode, node) + + return res + + + res = 0 + for node in range(n): + res += dfs(node, node, -1) + return res +``` + +```java +public class Solution { + public int numberOfGoodPaths(int[] vals, int[][] edges) { + int n = vals.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + adj[edge[1]].add(edge[0]); + } + + int res = 0; + for (int node = 0; node < n; node++) { + res += dfs(node, node, -1, vals, adj); + } + return res; + } + + private int dfs(int node, int startNode, int parent, int[] vals, List[] adj) { + if (vals[node] > vals[startNode]) { + return 0; + } + + int res = 0; + if (vals[node] == vals[startNode] && node >= startNode) { + res += 1; + } + + for (int child : adj[node]) { + if (child == parent) { + continue; + } + res += dfs(child, startNode, node, vals, adj); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numberOfGoodPaths(vector& vals, vector>& edges) { + int n = vals.size(); + vector> adj(n); + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + adj[edge[1]].push_back(edge[0]); + } + + int res = 0; + for (int node = 0; node < n; node++) { + res += dfs(node, node, -1, vals, adj); + } + return res; + } + +private: + int dfs(int node, int startNode, int parent, vector& vals, vector>& adj) { + if (vals[node] > vals[startNode]) { + return 0; + } + + int res = 0; + if (vals[node] == vals[startNode] && node >= startNode) { + res += 1; + } + + for (int child : adj[node]) { + if (child == parent) { + continue; + } + res += dfs(child, startNode, node, vals, adj); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} vals + * @param {number[][]} edges + * @return {number} + */ + numberOfGoodPaths(vals, edges) { + const n = vals.length; + const adj = Array.from({ length: n }, () => []); + + for (const [u, v] of edges) { + adj[u].push(v); + adj[v].push(u); + } + + const dfs = (node, startNode, parent) => { + if (vals[node] > vals[startNode]) { + return 0; + } + + let res = 0; + if (vals[node] === vals[startNode] && node >= startNode) { + res += 1; + } + + for (const child of adj[node]) { + if (child === parent) continue; + res += dfs(child, startNode, node); + } + return res; + }; + + let res = 0; + for (let node = 0; node < n; node++) { + res += dfs(node, node, -1); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Brute Force (BFS) + +::tabs-start + +```python +class Solution: + def numberOfGoodPaths(self, vals, edges): + n = len(vals) + adj = [[] for _ in range(n)] + for u, v in edges: + adj[u].append(v) + adj[v].append(u) + + res = 0 + for startNode in range(n): + q = deque([startNode]) + visited = set([startNode]) + count = 0 + + while q: + node = q.popleft() + if vals[node] == vals[startNode] and node >= startNode: + count += 1 + + for child in adj[node]: + if child not in visited and vals[child] <= vals[startNode]: + visited.add(child) + q.append(child) + + res += count + + return res +``` + +```java +public class Solution { + public int numberOfGoodPaths(int[] vals, int[][] edges) { + int n = vals.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + adj[edge[1]].add(edge[0]); + } + + int res = 0; + for (int startNode = 0; startNode < n; startNode++) { + Queue q = new LinkedList<>(); + Set visited = new HashSet<>(); + q.offer(startNode); + visited.add(startNode); + int count = 0; + + while (!q.isEmpty()) { + int node = q.poll(); + if (vals[node] == vals[startNode] && node >= startNode) { + count++; + } + + for (int child : adj[node]) { + if (!visited.contains(child) && vals[child] <= vals[startNode]) { + visited.add(child); + q.offer(child); + } + } + } + + res += count; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numberOfGoodPaths(vector& vals, vector>& edges) { + int n = vals.size(); + vector> adj(n); + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + adj[edge[1]].push_back(edge[0]); + } + + int res = 0; + for (int startNode = 0; startNode < n; startNode++) { + queue q; + unordered_set visited; + q.push(startNode); + visited.insert(startNode); + int count = 0; + + while (!q.empty()) { + int node = q.front(); + q.pop(); + if (vals[node] == vals[startNode] && node >= startNode) { + count++; + } + + for (int child : adj[node]) { + if (visited.find(child) == visited.end() && vals[child] <= vals[startNode]) { + visited.insert(child); + q.push(child); + } + } + } + + res += count; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} vals + * @param {number[][]} edges + * @return {number} + */ + numberOfGoodPaths(vals, edges) { + const n = vals.length; + const adj = Array.from({ length: n }, () => []); + + for (const [u, v] of edges) { + adj[u].push(v); + adj[v].push(u); + } + + let res = 0; + for (let startNode = 0; startNode < n; startNode++) { + const q = new Queue([startNode]); + const visited = new Set([startNode]); + let count = 0; + + while (q.length) { + let node = q.shift(); + if (vals[node] === vals[startNode] && node >= startNode) { + count++; + } + + for (const child of adj[node]) { + if (!visited.has(child) && vals[child] <= vals[startNode]) { + visited.add(child); + q.push(child); + } + } + } + + res += count; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 3. Disjoint Set Union + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.Parent = list(range(n + 1)) + self.Size = [1] * (n + 1) + + def find(self, node): + if self.Parent[node] != node: + self.Parent[node] = self.find(self.Parent[node]) + return self.Parent[node] + + def union(self, u, v): + pu, pv = self.find(u), self.find(v) + if pu == pv: + return False + if self.Size[pu] >= self.Size[pv]: + self.Size[pu] += self.Size[pv] + self.Parent[pv] = pu + else: + self.Size[pv] += self.Size[pu] + self.Parent[pu] = pv + return True + +class Solution: + def numberOfGoodPaths(self, vals: List[int], edges: List[List[int]]) -> int: + adj = collections.defaultdict(list) + for a, b in edges: + adj[a].append(b) + adj[b].append(a) + + valToIndex = collections.defaultdict(list) + for i, val in enumerate(vals): + valToIndex[val].append(i) + + res = 0 + uf = DSU(len(vals)) + + for val in sorted(valToIndex.keys()): + for i in valToIndex[val]: + for nei in adj[i]: + if vals[nei] <= vals[i]: + uf.union(nei, i) + + count = collections.defaultdict(int) + for i in valToIndex[val]: + count[uf.find(i)] += 1 + res += count[uf.find(i)] + + return res +``` + +```java +class DSU { + private int[] parent, size; + + public DSU(int n) { + parent = new int[n + 1]; + size = new int[n + 1]; + for (int i = 0; i <= n; i++) { + parent[i] = i; + size[i] = 1; + } + } + + public int find(int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + public boolean union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (size[pu] >= size[pv]) { + size[pu] += size[pv]; + parent[pv] = pu; + } else { + size[pv] += size[pu]; + parent[pu] = pv; + } + return true; + } +} + +public class Solution { + public int numberOfGoodPaths(int[] vals, int[][] edges) { + int n = vals.length; + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + adj[edge[1]].add(edge[0]); + } + + TreeMap> valToIndex = new TreeMap<>(); + for (int i = 0; i < n; i++) { + valToIndex.putIfAbsent(vals[i], new ArrayList<>()); + valToIndex.get(vals[i]).add(i); + } + + DSU dsu = new DSU(n); + int res = 0; + + for (int val : valToIndex.keySet()) { + for (int i : valToIndex.get(val)) { + for (int nei : adj[i]) { + if (vals[nei] <= vals[i]) dsu.union(nei, i); + } + } + + Map count = new HashMap<>(); + for (int i : valToIndex.get(val)) { + int root = dsu.find(i); + count.put(root, count.getOrDefault(root, 0) + 1); + res += count.get(root); + } + } + return res; + } +} +``` + +```cpp +class DSU { +public: + vector parent, size; + + DSU(int n) { + parent.resize(n + 1); + size.resize(n + 1, 1); + for (int i = 0; i <= n; i++) parent[i] = i; + } + + int find(int node) { + if (parent[node] != node) parent[node] = find(parent[node]); + return parent[node]; + } + + bool unite(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (size[pu] >= size[pv]) { + size[pu] += size[pv]; + parent[pv] = pu; + } else { + size[pv] += size[pu]; + parent[pu] = pv; + } + return true; + } +}; + +class Solution { +public: + int numberOfGoodPaths(vector& vals, vector>& edges) { + int n = vals.size(); + vector> adj(n); + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + adj[edge[1]].push_back(edge[0]); + } + + map> valToIndex; + for (int i = 0; i < n; i++) valToIndex[vals[i]].push_back(i); + + DSU dsu(n); + int res = 0; + + for (auto& [val, nodes] : valToIndex) { + for (int& i : nodes) { + for (int& nei : adj[i]) { + if (vals[nei] <= vals[i]) dsu.unite(nei, i); + } + } + + unordered_map count; + for (int& i : nodes) { + int root = dsu.find(i); + count[root]++; + res += count[root]; + } + } + return res; + } +}; +``` + +```javascript +class DSU { + /** + * @constructor + * @param {number} n + */ + constructor(n) { + this.parent = Array.from({ length: n + 1 }, (_, i) => i); + this.size = new Array(n + 1).fill(1); + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.parent[node] !== node) { + this.parent[node] = this.find(this.parent[node]); + } + return this.parent[node]; + } + + /** + * @param {number} u + * @param {number} u=v + * @return {boolean} + */ + union(u, v) { + let pu = this.find(u), + pv = this.find(v); + if (pu === pv) return false; + if (this.size[pu] >= this.size[pv]) { + this.size[pu] += this.size[pv]; + this.parent[pv] = pu; + } else { + this.size[pv] += this.size[pu]; + this.parent[pu] = pv; + } + return true; + } +} + +class Solution { + /** + * @param {number[]} vals + * @param {number[][]} edges + * @return {number} + */ + numberOfGoodPaths(vals, edges) { + const n = vals.length; + const adj = Array.from({ length: n }, () => []); + + for (const [u, v] of edges) { + adj[u].push(v); + adj[v].push(u); + } + + const valToIndex = new Map(); + for (let i = 0; i < n; i++) { + if (!valToIndex.has(vals[i])) valToIndex.set(vals[i], []); + valToIndex.get(vals[i]).push(i); + } + + const dsu = new DSU(n); + let res = 0; + + for (const [val, nodes] of [...valToIndex.entries()].sort( + (a, b) => a[0] - b[0], + )) { + for (const i of nodes) { + for (const nei of adj[i]) { + if (vals[nei] <= vals[i]) dsu.union(nei, i); + } + } + + const count = new Map(); + for (const i of nodes) { + const root = dsu.find(i); + count.set(root, (count.get(root) || 0) + 1); + res += count.get(root); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Disjoint Set Union (Union By Value) + +::tabs-start + +```python +class DSU: + def __init__(self, n, vals): + self.parent = list(range(n)) + self.vals = vals + self.count = [1] * n # count of nodes with max value of the component + + def find(self, node): + if self.parent[node] != node: + self.parent[node] = self.find(self.parent[node]) + return self.parent[node] + + def union(self, u, v): + pu, pv = self.find(u), self.find(v) + if pu == pv: + return 0 + if self.vals[pu] < self.vals[pv]: + self.parent[pu] = pv + elif self.vals[pu] > self.vals[pv]: + self.parent[pv] = pu + else: + self.parent[pv] = pu + result = self.count[pu] * self.count[pv] + self.count[pu] += self.count[pv] + return result + + return 0 + + +class Solution: + def numberOfGoodPaths(self, vals: List[int], edges: List[List[int]]) -> int: + n = len(vals) + dsu = DSU(n, vals) + + # Sort edges based on max value of the two nodes + edges.sort(key=lambda edge: max(vals[edge[0]], vals[edge[1]])) + + res = n # Each node alone is a good path + for u, v in edges: + res += dsu.union(u, v) + return res +``` + +```java +class DSU { + private int[] parent, count, vals; + + public DSU(int n, int[] vals) { + this.parent = new int[n]; + this.vals = vals; + this.count = new int[n]; // count of nodes with max value of the component + Arrays.fill(count, 1); + + for (int i = 0; i < n; i++) { + parent[i] = i; + } + } + + public int find(int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + public int union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) { + return 0; + } + if (vals[pu] < vals[pv]) { + parent[pu] = pv; + } else if (vals[pu] > vals[pv]) { + parent[pv] = pu; + } else { + parent[pv] = pu; + int result = count[pu] * count[pv]; + count[pu] += count[pv]; + return result; + } + return 0; + } +} + +public class Solution { + public int numberOfGoodPaths(int[] vals, int[][] edges) { + int n = vals.length; + DSU dsu = new DSU(n, vals); + + // Sort edges based on max value of the two nodes + Arrays.sort(edges, + Comparator.comparingInt(edge -> Math.max(vals[edge[0]], vals[edge[1]])) + ); + + int res = n; // Each node alone is a good path + for (int[] edge : edges) { + res += dsu.union(edge[0], edge[1]); + } + return res; + } +} +``` + +```cpp +class DSU { + vector parent, count, vals; + +public: + DSU(int n, vector& vals) : vals(vals), parent(n), count(n, 1) { + for (int i = 0; i < n; i++) parent[i] = i; + } + + int find(int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + int unionNodes(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) { + return 0; + } + if (vals[pu] < vals[pv]) { + parent[pu] = pv; + } else if (vals[pu] > vals[pv]) { + parent[pv] = pu; + } else { + parent[pv] = pu; + int result = count[pu] * count[pv]; + count[pu] += count[pv]; + return result; + } + return 0; + } +}; + +class Solution { +public: + int numberOfGoodPaths(vector& vals, vector>& edges) { + int n = vals.size(); + DSU dsu(n, vals); + + // Sort edges based on max value of the two nodes + sort(edges.begin(), edges.end(), [&](auto& a, auto& b) { + return max(vals[a[0]], vals[a[1]]) < max(vals[b[0]], vals[b[1]]); + }); + + int res = n; // Each node alone is a good path + for (auto& edge : edges) { + res += dsu.unionNodes(edge[0], edge[1]); + } + return res; + } +}; +``` + +```javascript +class DSU { + /** + * @param {number} n + * @param {number[]} vals + */ + constructor(n, vals) { + this.parent = Array(n) + .fill(0) + .map((_, i) => i); + this.vals = vals; + this.count = Array(n).fill(1); // count of nodes with max value of the component + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.parent[node] !== node) { + this.parent[node] = this.find(this.parent[node]); + } + return this.parent[node]; + } + + /** + * @param {number} u + * @param {number} v + * @return {number} + */ + union(u, v) { + let pu = this.find(u), + pv = this.find(v); + if (pu === pv) { + return 0; + } + if (this.vals[pu] < this.vals[pv]) { + this.parent[pu] = pv; + } else if (this.vals[pu] > this.vals[pv]) { + this.parent[pv] = pu; + } else { + this.parent[pv] = pu; + let result = this.count[pu] * this.count[pv]; + this.count[pu] += this.count[pv]; + return result; + } + return 0; + } +} + +class Solution { + /** + * @param {number[]} vals + * @param {number[][]} edges + * @return {number} + */ + numberOfGoodPaths(vals, edges) { + let n = vals.length; + let dsu = new DSU(n, vals); + + // Sort edges based on max value of the two nodes + edges.sort( + (a, b) => + Math.max(vals[a[0]], vals[a[1]]) - + Math.max(vals[b[0]], vals[b[1]]), + ); + + let res = n; // Each node alone is a good path + for (let [u, v] of edges) { + res += dsu.union(u, v); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n\log n)$ +- Space complexity: $O(n)$ diff --git a/articles/number-of-laser-beams-in-a-bank.md b/articles/number-of-laser-beams-in-a-bank.md new file mode 100644 index 000000000..f5d2bd0a8 --- /dev/null +++ b/articles/number-of-laser-beams-in-a-bank.md @@ -0,0 +1,110 @@ +## 1. Counting + +::tabs-start + +```python +class Solution: + def numberOfBeams(self, bank: List[str]) -> int: + prev = bank[0].count("1") + res = 0 + + for i in range(1, len(bank)): + curr = bank[i].count("1") + if curr: + res += prev * curr + prev = curr + + return res +``` + +```java +public class Solution { + public int numberOfBeams(String[] bank) { + int prev = countOnes(bank[0]); + int res = 0; + + for (int i = 1; i < bank.length; i++) { + int curr = countOnes(bank[i]); + if (curr > 0) { + res += prev * curr; + prev = curr; + } + } + + return res; + } + + private int countOnes(String s) { + int count = 0; + for (int i = 0; i < s.length(); i++) { + if (s.charAt(i) == '1') count++; + } + return count; + } +} +``` + +```cpp +class Solution { +public: + int numberOfBeams(vector& bank) { + int prev = countOnes(bank[0]); + int res = 0; + + for (int i = 1; i < bank.size(); i++) { + int curr = countOnes(bank[i]); + if (curr > 0) { + res += prev * curr; + prev = curr; + } + } + + return res; + } + +private: + int countOnes(const string& s) { + return count(s.begin(), s.end(), '1'); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} bank + * @return {number} + */ + numberOfBeams(bank) { + const countOnes = (s) => { + let cnt = 0; + for (let c of s) { + if (c === '1') cnt += 1; + } + return cnt; + }; + + let prev = countOnes(bank[0]); + let res = 0; + + for (let i = 1; i < bank.length; i++) { + let curr = countOnes(bank[i]); + if (curr > 0) { + res += prev * curr; + prev = curr; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(1)$ extra space. + +> Where $m$ is the number of rows and $n$ is the number of columns. diff --git a/articles/number-of-longest-increasing-subsequence.md b/articles/number-of-longest-increasing-subsequence.md index f11ef6599..5a23a7430 100644 --- a/articles/number-of-longest-increasing-subsequence.md +++ b/articles/number-of-longest-increasing-subsequence.md @@ -20,7 +20,7 @@ class Solution: if nums[j] <= nums[i]: continue dfs(j, length + 1) - + for i in range(len(nums)): dfs(i, 1) return res @@ -123,8 +123,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ n)$ +- Space complexity: $O(n)$ --- @@ -208,7 +208,7 @@ public class Solution { } } } - + dp[i] = new int[]{maxLen, maxCnt}; } } @@ -273,7 +273,8 @@ class Solution { const dfs = (i) => { if (dp.has(i)) return; - let maxLen = 1, maxCnt = 1; + let maxLen = 1, + maxCnt = 1; for (let j = i + 1; j < nums.length; j++) { if (nums[j] > nums[i]) { dfs(j); @@ -289,7 +290,8 @@ class Solution { dp.set(i, [maxLen, maxCnt]); }; - let lenLIS = 0, res = 0; + let lenLIS = 0, + res = 0; for (let i = 0; i < nums.length; i++) { dfs(i); const [maxLen, maxCnt] = dp.get(i); @@ -309,8 +311,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -426,10 +428,12 @@ class Solution { findNumberOfLIS(nums) { const n = nums.length; const dp = Array.from({ length: n }, () => [0, 0]); - let lenLIS = 0, res = 0; + let lenLIS = 0, + res = 0; for (let i = n - 1; i >= 0; i--) { - let maxLen = 1, maxCnt = 1; + let maxLen = 1, + maxCnt = 1; for (let j = i + 1; j < n; j++) { if (nums[j] > nums[i]) { const [length, count] = dp[j]; @@ -459,8 +463,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -641,11 +645,18 @@ class Solution { * @return {number} */ findNumberOfLIS(nums) { - const dp = [[[0, 0], [nums[0], 1]]]; + const dp = [ + [ + [0, 0], + [nums[0], 1], + ], + ]; let LIS = 1; const bs1 = (num) => { - let l = 0, r = dp.length - 1, j = dp.length - 1; + let l = 0, + r = dp.length - 1, + j = dp.length - 1; while (l <= r) { const mid = Math.floor((l + r) / 2); if (dp[mid][dp[mid].length - 1][0] < num) { @@ -660,7 +671,9 @@ class Solution { const bs2 = (i, num) => { if (i < 0) return 1; - let l = 1, r = dp[i].length - 1, j = 0; + let l = 1, + r = dp[i].length - 1, + j = 0; while (l <= r) { const mid = Math.floor((l + r) / 2); if (dp[i][mid][0] >= num) { @@ -677,7 +690,10 @@ class Solution { const num = nums[i]; if (num > dp[dp.length - 1][dp[dp.length - 1].length - 1][0]) { const count = bs2(LIS - 1, num); - dp.push([[0, 0], [num, count]]); + dp.push([ + [0, 0], + [num, count], + ]); LIS++; } else { const j = bs1(num); @@ -695,5 +711,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n\log n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n\log n)$ +- Space complexity: $O(n)$ diff --git a/articles/number-of-music-playlists.md b/articles/number-of-music-playlists.md index 284e35bae..70dfcabaf 100644 --- a/articles/number-of-music-playlists.md +++ b/articles/number-of-music-playlists.md @@ -90,7 +90,9 @@ class Solution { */ numMusicPlaylists(n, goal, k) { const MOD = 1e9 + 7; - const dp = Array.from({ length: goal + 1 }, () => Array(n + 1).fill(-1)); + const dp = Array.from({ length: goal + 1 }, () => + Array(n + 1).fill(-1), + ); const count = (curGoal, oldSongs) => { if (curGoal === 0 && oldSongs === n) return 1; @@ -99,7 +101,11 @@ class Solution { let res = ((n - oldSongs) * count(curGoal - 1, oldSongs + 1)) % MOD; if (oldSongs > k) { - res = (res + ((oldSongs - k) * count(curGoal - 1, oldSongs)) % MOD) % MOD; + res = + (res + + (((oldSongs - k) * count(curGoal - 1, oldSongs)) % + MOD)) % + MOD; } dp[curGoal][oldSongs] = res; return res; @@ -114,8 +120,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(g * n)$ -* Space complexity: $O(g * n)$ +- Time complexity: $O(g * n)$ +- Space complexity: $O(g * n)$ > Where $g$ is the number of songs to listen and $n$ is the number of different songs. @@ -205,9 +211,12 @@ class Solution { for (let curGoal = 1; curGoal <= goal; curGoal++) { for (let oldSongs = 1; oldSongs <= n; oldSongs++) { - let res = (dp[curGoal - 1][oldSongs - 1] * (n - oldSongs + 1)) % MOD; + let res = + (dp[curGoal - 1][oldSongs - 1] * (n - oldSongs + 1)) % MOD; if (oldSongs > k) { - res = (res + dp[curGoal - 1][oldSongs] * (oldSongs - k)) % MOD; + res = + (res + dp[curGoal - 1][oldSongs] * (oldSongs - k)) % + MOD; } dp[curGoal][oldSongs] = res; } @@ -222,8 +231,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(g * n)$ -* Space complexity: $O(g * n)$ +- Time complexity: $O(g * n)$ +- Space complexity: $O(g * n)$ > Where $g$ is the number of songs to listen and $n$ is the number of different songs. @@ -334,7 +343,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(g * n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(g * n)$ +- Space complexity: $O(n)$ -> Where $g$ is the number of songs to listen and $n$ is the number of different songs. \ No newline at end of file +> Where $g$ is the number of songs to listen and $n$ is the number of different songs. diff --git a/articles/number-of-one-bits.md b/articles/number-of-one-bits.md index 9468bf89b..7cab4d38a 100644 --- a/articles/number-of-one-bits.md +++ b/articles/number-of-one-bits.md @@ -99,12 +99,26 @@ class Solution { } ``` +```swift +class Solution { + func hammingWeight(_ n: Int) -> Int { + var res = 0 + for i in 0..<32 { + if (1 << i) & n != 0 { + res += 1 + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ --- @@ -159,7 +173,7 @@ class Solution { let res = 0; while (n !== 0) { res += (n & 1) === 1 ? 1 : 0; - n >>= 1; + n >>= 1; } return res; } @@ -208,12 +222,26 @@ class Solution { } ``` +```swift +class Solution { + func hammingWeight(_ n: Int) -> Int { + var n = n + var res = 0 + while n != 0 { + res += (n & 1) != 0 ? 1 : 0 + n >>= 1 + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ --- @@ -313,12 +341,26 @@ class Solution { } ``` +```swift +class Solution { + func hammingWeight(_ n: Int) -> Int { + var n = n + var res = 0 + while n != 0 { + n &= (n - 1) + res += 1 + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ --- @@ -383,9 +425,17 @@ class Solution { } ``` +```swift +class Solution { + func hammingWeight(_ n: Int) -> Int { + return n.nonzeroBitCount + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ diff --git a/articles/number-of-pairs-of-interchangeable-rectangles.md b/articles/number-of-pairs-of-interchangeable-rectangles.md index bbb73e152..03c2d7c30 100644 --- a/articles/number-of-pairs-of-interchangeable-rectangles.md +++ b/articles/number-of-pairs-of-interchangeable-rectangles.md @@ -56,7 +56,10 @@ class Solution { let res = 0; for (let i = 1; i < rectangles.length; i++) { for (let j = 0; j < i; j++) { - if (rectangles[i][0] / rectangles[i][1] === rectangles[j][0] / rectangles[j][1]) { + if ( + rectangles[i][0] / rectangles[i][1] === + rectangles[j][0] / rectangles[j][1] + ) { res++; } } @@ -70,8 +73,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -101,7 +104,7 @@ public class Solution { double ratio = (double) rect[0] / rect[1]; count.put(ratio, count.getOrDefault(ratio, 0) + 1); } - + long res = 0; for (int c : count.values()) { if (c > 1) { @@ -162,8 +165,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -224,7 +227,7 @@ class Solution { let res = 0; for (const [w, h] of rectangles) { const ratio = w / h; - res += count.get(ratio) || 0 + res += count.get(ratio) || 0; count.set(ratio, (count.get(ratio) || 0) + 1); } return res; @@ -236,8 +239,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -251,7 +254,7 @@ class Solution: mask = a mask |= (b << 31) return mask - + def interchangeableRectangles(self, rectangles: List[List[int]]) -> int: res = 0 count = {} @@ -270,7 +273,7 @@ public class Solution { mask |= ((long)b << 31); return mask; } - + public long interchangeableRectangles(int[][] rectangles) { long res = 0; Map count = new HashMap<>(); @@ -282,7 +285,7 @@ public class Solution { } return res; } - + private int gcd(int a, int b) { while (b != 0) { a %= b; @@ -303,7 +306,7 @@ public: mask |= ((long long)b << 31); return mask; } - + long long interchangeableRectangles(vector>& rectangles) { long long res = 0; unordered_map count; @@ -336,18 +339,21 @@ class Solution { interchangeableRectangles(rectangles) { let res = 0; const count = new Map(); - + const gcd = (a, b) => { while (b !== 0) { a %= b; - [a, b] = [b, a] + [a, b] = [b, a]; } return a; }; - + for (const rect of rectangles) { const g = gcd(rect[0], rect[1]); - const key = this.hash(Math.floor(rect[0] / g), Math.floor(rect[1] / g)); + const key = this.hash( + Math.floor(rect[0] / g), + Math.floor(rect[1] / g), + ); res += count.get(key) || 0; count.set(key, (count.get(key) || 0) + 1); } @@ -360,5 +366,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/number-of-provinces.md b/articles/number-of-provinces.md new file mode 100644 index 000000000..9cd1d8d74 --- /dev/null +++ b/articles/number-of-provinces.md @@ -0,0 +1,739 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def findCircleNum(self, isConnected: List[List[int]]) -> int: + n = len(isConnected) + res = 0 + visited = [False] * n + + def dfs(node): + visited[node] = True + for nei in range(n): + if isConnected[node][nei] and not visited[nei]: + dfs(nei) + + for i in range(n): + if not visited[i]: + dfs(i) + res += 1 + + return res +``` + +```java +public class Solution { + public int findCircleNum(int[][] isConnected) { + int n = isConnected.length; + boolean[] visited = new boolean[n]; + int res = 0; + + for (int i = 0; i < n; i++) { + if (!visited[i]) { + dfs(i, isConnected, visited, n); + res++; + } + } + return res; + } + + private void dfs(int node, int[][] isConnected, boolean[] visited, int n) { + visited[node] = true; + for (int nei = 0; nei < n; nei++) { + if (isConnected[node][nei] == 1 && !visited[nei]) { + dfs(nei, isConnected, visited, n); + } + } + } +} +``` + +```cpp +class Solution { +public: + int findCircleNum(vector>& isConnected) { + int n = isConnected.size(); + vector visited(n, false); + int res = 0; + + for (int i = 0; i < n; i++) { + if (!visited[i]) { + dfs(i, isConnected, visited, n); + res++; + } + } + return res; + } + + void dfs(int node, vector>& isConnected, vector& visited, int n) { + visited[node] = true; + for (int nei = 0; nei < n; nei++) { + if (isConnected[node][nei] == 1 && !visited[nei]) { + dfs(nei, isConnected, visited, n); + } + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} isConnected + * @return {number} + */ + findCircleNum(isConnected) { + const n = isConnected.length; + const visited = new Array(n).fill(false); + let res = 0; + + const dfs = (node) => { + visited[node] = true; + for (let nei = 0; nei < n; nei++) { + if (isConnected[node][nei] === 1 && !visited[nei]) { + dfs(nei); + } + } + }; + + for (let i = 0; i < n; i++) { + if (!visited[i]) { + dfs(i); + res++; + } + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int FindCircleNum(int[][] isConnected) { + int n = isConnected.Length; + bool[] visited = new bool[n]; + int res = 0; + + for (int i = 0; i < n; i++) { + if (!visited[i]) { + Dfs(i, isConnected, visited, n); + res++; + } + } + return res; + } + + private void Dfs(int node, int[][] isConnected, bool[] visited, int n) { + visited[node] = true; + for (int nei = 0; nei < n; nei++) { + if (isConnected[node][nei] == 1 && !visited[nei]) { + Dfs(nei, isConnected, visited, n); + } + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 2. Depth First Search (Modifying Input) + +::tabs-start + +```python +class Solution: + def findCircleNum(self, isConnected: List[List[int]]) -> int: + n = len(isConnected) + res = 0 + + def dfs(node): + isConnected[node][node] = 0 + for nei in range(n): + if node != nei and isConnected[node][nei] and isConnected[nei][nei]: + dfs(nei) + + for i in range(n): + if isConnected[i][i]: + dfs(i) + res += 1 + + return res +``` + +```java +public class Solution { + public int findCircleNum(int[][] isConnected) { + int n = isConnected.length; + int res = 0; + + for (int i = 0; i < n; i++) { + if (isConnected[i][i] == 1) { + dfs(i, isConnected, n); + res++; + } + } + return res; + } + + private void dfs(int node, int[][] isConnected, int n) { + isConnected[node][node] = 0; + for (int nei = 0; nei < n; nei++) { + if (node != nei && isConnected[node][nei] == 1 && isConnected[nei][nei] == 1) { + dfs(nei, isConnected, n); + } + } + } +} +``` + +```cpp +class Solution { +public: + int findCircleNum(vector>& isConnected) { + int n = isConnected.size(); + int res = 0; + + for (int i = 0; i < n; i++) { + if (isConnected[i][i] == 1) { + dfs(i, isConnected, n); + res++; + } + } + return res; + } + + void dfs(int node, vector>& isConnected, int n) { + isConnected[node][node] = 0; + for (int nei = 0; nei < n; nei++) { + if (node != nei && isConnected[node][nei] == 1 && isConnected[nei][nei] == 1) { + dfs(nei, isConnected, n); + } + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} isConnected + * @return {number} + */ + findCircleNum(isConnected) { + const n = isConnected.length; + let res = 0; + + const dfs = (node) => { + isConnected[node][node] = 0; + for (let nei = 0; nei < n; nei++) { + if (node !== nei && isConnected[node][nei] === 1 && isConnected[nei][nei] === 1) { + dfs(nei); + } + } + }; + + for (let i = 0; i < n; i++) { + if (isConnected[i][i] === 1) { + dfs(i); + res++; + } + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int FindCircleNum(int[][] isConnected) { + int n = isConnected.Length; + int res = 0; + + for (int i = 0; i < n; i++) { + if (isConnected[i][i] == 1) { + Dfs(i, isConnected, n); + res++; + } + } + + return res; + } + + private void Dfs(int node, int[][] isConnected, int n) { + isConnected[node][node] = 0; + for (int nei = 0; nei < n; nei++) { + if (node != nei && isConnected[node][nei] == 1 && isConnected[nei][nei] == 1) { + Dfs(nei, isConnected, n); + } + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Breadth First Search + +::tabs-start + +```python +class Solution: + def findCircleNum(self, isConnected: List[List[int]]) -> int: + n = len(isConnected) + visited = [False] * n + res = 0 + q = deque() + + for i in range(n): + if not visited[i]: + res += 1 + visited[i] = True + q.append(i) + while q: + node = q.popleft() + for nei in range(n): + if isConnected[node][nei] and not visited[nei]: + visited[nei] = True + q.append(nei) + + return res +``` + +```java +public class Solution { + public int findCircleNum(int[][] isConnected) { + int n = isConnected.length; + boolean[] visited = new boolean[n]; + Queue q = new LinkedList<>(); + int res = 0; + + for (int i = 0; i < n; i++) { + if (!visited[i]) { + res++; + visited[i] = true; + q.add(i); + while (!q.isEmpty()) { + int node = q.poll(); + for (int nei = 0; nei < n; nei++) { + if (isConnected[node][nei] == 1 && !visited[nei]) { + visited[nei] = true; + q.add(nei); + } + } + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int findCircleNum(vector>& isConnected) { + int n = isConnected.size(); + vector visited(n, false); + queue q; + int res = 0; + + for (int i = 0; i < n; i++) { + if (!visited[i]) { + res++; + visited[i] = true; + q.push(i); + while (!q.empty()) { + int node = q.front(); q.pop(); + for (int nei = 0; nei < n; nei++) { + if (isConnected[node][nei] && !visited[nei]) { + visited[nei] = true; + q.push(nei); + } + } + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} isConnected + * @return {number} + */ + findCircleNum(isConnected) { + const n = isConnected.length; + const visited = new Array(n).fill(false); + const q = new Queue(); + let res = 0; + + for (let i = 0; i < n; i++) { + if (!visited[i]) { + res++; + visited[i] = true; + q.enqueue(i); + while (!q.isEmpty()) { + const node = q.dequeue(); + for (let nei = 0; nei < n; nei++) { + if (isConnected[node][nei] && !visited[nei]) { + visited[nei] = true; + q.enqueue(nei); + } + } + } + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public int FindCircleNum(int[][] isConnected) { + int n = isConnected.Length; + bool[] visited = new bool[n]; + Queue q = new Queue(); + int res = 0; + + for (int i = 0; i < n; i++) { + if (!visited[i]) { + res++; + visited[i] = true; + q.Enqueue(i); + while (q.Count > 0) { + int node = q.Dequeue(); + for (int nei = 0; nei < n; nei++) { + if (isConnected[node][nei] == 1 && !visited[nei]) { + visited[nei] = true; + q.Enqueue(nei); + } + } + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 4. Disjoint Set Union + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.Parent = list(range(n + 1)) + self.Size = [1] * (n + 1) + self.components = n + + def find(self, node): + if self.Parent[node] != node: + self.Parent[node] = self.find(self.Parent[node]) + return self.Parent[node] + + def union(self, u, v): + pu = self.find(u) + pv = self.find(v) + if pu == pv: + return False + + self.components -= 1 + if self.Size[pu] >= self.Size[pv]: + self.Size[pu] += self.Size[pv] + self.Parent[pv] = pu + else: + self.Size[pv] += self.Size[pu] + self.Parent[pu] = pv + return True + + def numOfComps(self): + return self.components + +class Solution: + def findCircleNum(self, isConnected: List[List[int]]) -> int: + n = len(isConnected) + dsu = DSU(n) + + for i in range(n): + for j in range(n): + if isConnected[i][j]: + dsu.union(i, j) + + return dsu.numOfComps() +``` + +```java +class DSU { + int[] Parent, Size; + int components; + + public DSU(int n) { + Parent = new int[n]; + Size = new int[n]; + components = n; + for (int i = 0; i < n; i++) { + Parent[i] = i; + Size[i] = 1; + } + } + + public int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + public boolean union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + + components--; + if (Size[pu] >= Size[pv]) { + Size[pu] += Size[pv]; + Parent[pv] = pu; + } else { + Size[pv] += Size[pu]; + Parent[pu] = pv; + } + return true; + } + + public int numOfComps() { + return components; + } +} + +public class Solution { + public int findCircleNum(int[][] isConnected) { + int n = isConnected.length; + DSU dsu = new DSU(n); + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (isConnected[i][j] == 1) { + dsu.union(i, j); + } + } + } + return dsu.numOfComps(); + } +} +``` + +```cpp +class DSU { +public: + vector Parent, Size; + int components; + + DSU(int n) { + Parent.resize(n); + Size.assign(n, 1); + components = n; + for (int i = 0; i < n; ++i) Parent[i] = i; + } + + int find(int node) { + if (Parent[node] != node) + Parent[node] = find(Parent[node]); + return Parent[node]; + } + + bool unionSet(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + + components--; + if (Size[pu] >= Size[pv]) { + Size[pu] += Size[pv]; + Parent[pv] = pu; + } else { + Size[pv] += Size[pu]; + Parent[pu] = pv; + } + return true; + } + + int numOfComps() { + return components; + } +}; + +class Solution { +public: + int findCircleNum(vector>& isConnected) { + int n = isConnected.size(); + DSU dsu(n); + for (int i = 0; i < n; ++i) + for (int j = 0; j < n; ++j) + if (isConnected[i][j]) + dsu.unionSet(i, j); + return dsu.numOfComps(); + } +}; +``` + +```javascript +class DSU { + constructor(n) { + this.Parent = Array(n + 1).fill(0).map((_, i) => i); + this.Size = Array(n + 1).fill(1); + this.components = n; + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.Parent[node] !== node) { + this.Parent[node] = this.find(this.Parent[node]); + } + return this.Parent[node]; + } + + /** + * @param {number} u + * @param {number} v + * @return {boolean} + */ + union(u, v) { + let pu = this.find(u); + let pv = this.find(v); + if (pu === pv) return false; + + this.components--; + if (this.Size[pu] >= this.Size[pv]) { + this.Size[pu] += this.Size[pv]; + this.Parent[pv] = pu; + } else { + this.Size[pv] += this.Size[pu]; + this.Parent[pu] = pv; + } + return true; + } + + /** + * @param {number} u + * @param {number} v + * @return {boolean} + */ + numOfComps() { + return this.components; + } +} + +class Solution { + /** + * @param {number[][]} isConnected + * @return {number} + */ + findCircleNum(isConnected) { + const n = isConnected.length; + const dsu = new DSU(n); + + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if (isConnected[i][j]) { + dsu.union(i, j); + } + } + } + return dsu.numOfComps(); + } +} +``` + +```csharp +public class DSU { + private int[] Parent, Size; + private int components; + + public DSU(int n) { + Parent = new int[n]; + Size = new int[n]; + components = n; + for (int i = 0; i < n; i++) { + Parent[i] = i; + Size[i] = 1; + } + } + + public int Find(int node) { + if (Parent[node] != node) + Parent[node] = Find(Parent[node]); + return Parent[node]; + } + + public bool Union(int u, int v) { + int pu = Find(u), pv = Find(v); + if (pu == pv) return false; + + components--; + if (Size[pu] >= Size[pv]) { + Size[pu] += Size[pv]; + Parent[pv] = pu; + } else { + Size[pv] += Size[pu]; + Parent[pu] = pv; + } + return true; + } + + public int NumOfComps() { + return components; + } +} + +public class Solution { + public int FindCircleNum(int[][] isConnected) { + int n = isConnected.Length; + var dsu = new DSU(n); + for (int i = 0; i < n; i++) + for (int j = 0; j < n; j++) + if (isConnected[i][j] == 1) + dsu.Union(i, j); + return dsu.NumOfComps(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/number-of-senior-citizens.md b/articles/number-of-senior-citizens.md new file mode 100644 index 000000000..d0a647cbd --- /dev/null +++ b/articles/number-of-senior-citizens.md @@ -0,0 +1,149 @@ +## 1. String Parsing + +::tabs-start + +```python +class Solution: + def countSeniors(self, details: List[str]) -> int: + res = 0 + for d in details: + if int(d[11:13]) > 60: + res += 1 + return res +``` + +```java +public class Solution { + public int countSeniors(String[] details) { + int res = 0; + for (String d : details) { + if (Integer.parseInt(d.substring(11, 13)) > 60) { + res++; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int countSeniors(vector& details) { + int res = 0; + for (const string& d : details) { + if (stoi(d.substr(11, 2)) > 60) { + res++; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} details + * @return {number} + */ + countSeniors(details) { + let res = 0; + for (let d of details) { + if (parseInt(d.slice(11, 13)) > 60) { + res++; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 2. Character-Based Extraction + +::tabs-start + +```python +class Solution: + def countSeniors(self, details: List[str]) -> int: + res = 0 + for d in details: + ten = ord(d[11]) - ord("0") + one = ord(d[12]) - ord("0") + age = one + 10 * ten + if age > 60: + res += 1 + return res +``` + +```java +public class Solution { + public int countSeniors(String[] details) { + int res = 0; + for (String d : details) { + int ten = d.charAt(11) - '0'; + int one = d.charAt(12) - '0'; + int age = one + 10 * ten; + if (age > 60) { + res++; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int countSeniors(vector& details) { + int res = 0; + for (const string& d : details) { + int ten = d[11] - '0'; + int one = d[12] - '0'; + int age = one + 10 * ten; + if (age > 60) { + res++; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} details + * @return {number} + */ + countSeniors(details) { + let res = 0; + for (let d of details) { + let ten = d.charCodeAt(11) - 48; + let one = d.charCodeAt(12) - 48; + let age = one + 10 * ten; + if (age > 60) { + res++; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/number-of-students-unable-to-eat-lunch.md b/articles/number-of-students-unable-to-eat-lunch.md index 6ccf1609d..32b33514b 100644 --- a/articles/number-of-students-unable-to-eat-lunch.md +++ b/articles/number-of-students-unable-to-eat-lunch.md @@ -58,7 +58,7 @@ public: int countStudents(vector& students, vector& sandwiches) { int n = students.size(); queue q; - + for (int student : students) { q.push(student); } @@ -121,8 +121,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -241,8 +241,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -262,7 +262,7 @@ class Solution: cnt[s] -= 1 else: break - + return res ``` @@ -344,5 +344,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold.md b/articles/number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold.md index f99cc6f13..f224678ac 100644 --- a/articles/number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold.md +++ b/articles/number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold.md @@ -7,16 +7,16 @@ class Solution: def numOfSubarrays(self, arr: List[int], k: int, threshold: int) -> int: res = 0 l = 0 - + for r in range(k - 1, len(arr)): sum_ = 0 for i in range(l, r + 1): sum_ += arr[i] - + if sum_ / k >= threshold: res += 1 l += 1 - + return res ``` @@ -70,7 +70,8 @@ class Solution { * @return {number} */ numOfSubarrays(arr, k, threshold) { - let res = 0, l = 0; + let res = 0, + l = 0; for (let r = k - 1; r < arr.length; r++) { let sum = 0; @@ -87,12 +88,35 @@ class Solution { } ``` +```csharp +public class Solution { + public int NumOfSubarrays(int[] arr, int k, int threshold) { + int res = 0; + int l = 0; + + for (int r = k - 1; r < arr.Length; r++) { + int sum = 0; + for (int i = l; i <= r; i++) { + sum += arr[i]; + } + + if (sum / k >= threshold) { + res++; + } + l++; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * k)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n * k)$ +- Space complexity: $O(1)$ > Where $n$ is the size of the array $arr$ and $k$ is the size of the sub-array. @@ -115,7 +139,7 @@ class Solution: if sum_ / k >= threshold: res += 1 l += 1 - + return res ``` @@ -176,7 +200,8 @@ class Solution { prefixSum[i + 1] += prefixSum[i] + arr[i]; } - let res = 0, l = 0; + let res = 0, + l = 0; for (let r = k - 1; r < arr.length; r++) { const sum = prefixSum[r + 1] - prefixSum[l]; if (sum / k >= threshold) { @@ -189,12 +214,34 @@ class Solution { } ``` +```csharp +public class Solution { + public int NumOfSubarrays(int[] arr, int k, int threshold) { + int[] prefixSum = new int[arr.Length + 1]; + for (int i = 0; i < arr.Length; i++) { + prefixSum[i + 1] = prefixSum[i] + arr[i]; + } + + int res = 0, l = 0; + for (int r = k - 1; r < arr.Length; r++) { + int sum = prefixSum[r + 1] - prefixSum[l]; + if (sum / k >= threshold) { + res++; + } + l++; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ > Where $n$ is the size of the array $arr$ and $k$ is the size of the sub-array. @@ -282,7 +329,30 @@ class Solution { for (let L = 0; L <= arr.length - k; L++) { curSum += arr[L + k - 1]; - if ((curSum / k) >= threshold) { + if (curSum / k >= threshold) { + res++; + } + curSum -= arr[L]; + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int NumOfSubarrays(int[] arr, int k, int threshold) { + int res = 0; + int curSum = 0; + + for (int i = 0; i < k - 1; i++) { + curSum += arr[i]; + } + + for (int L = 0; L <= arr.Length - k; L++) { + curSum += arr[L + k - 1]; + if (curSum / k >= threshold) { res++; } curSum -= arr[L]; @@ -297,8 +367,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. > Where $n$ is the size of the array $arr$ and $k$ is the size of the sub-array. @@ -372,7 +442,8 @@ class Solution { */ numOfSubarrays(arr, k, threshold) { threshold *= k; - let res = 0, curSum = 0; + let res = 0, + curSum = 0; for (let R = 0; R < arr.length; R++) { curSum += arr[R]; @@ -388,11 +459,32 @@ class Solution { } ``` +```csharp +public class Solution { + public int NumOfSubarrays(int[] arr, int k, int threshold) { + threshold *= k; + int res = 0, curSum = 0; + + for (int r = 0; r < arr.Length; r++) { + curSum += arr[r]; + if (r >= k - 1) { + if (curSum >= threshold) { + res++; + } + curSum -= arr[r - k + 1]; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. -> Where $n$ is the size of the array $arr$ and $k$ is the size of the sub-array. \ No newline at end of file +> Where $n$ is the size of the array $arr$ and $k$ is the size of the sub-array. diff --git a/articles/number-of-sub-arrays-with-odd-sum.md b/articles/number-of-sub-arrays-with-odd-sum.md new file mode 100644 index 000000000..b1af4583c --- /dev/null +++ b/articles/number-of-sub-arrays-with-odd-sum.md @@ -0,0 +1,525 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def numOfSubarrays(self, arr: List[int]) -> int: + n, res = len(arr), 0 + mod = int(1e9 + 7) + + for i in range(n): + curSum = 0 + for j in range(i, n): + curSum += arr[j] + if curSum % 2: + res = (res + 1) % mod + + return res +``` + +```java +public class Solution { + public int numOfSubarrays(int[] arr) { + int n = arr.length, res = 0; + int mod = (int)1e9 + 7; + + for (int i = 0; i < n; i++) { + int curSum = 0; + for (int j = i; j < n; j++) { + curSum += arr[j]; + if (curSum % 2 != 0) { + res = (res + 1) % mod; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int numOfSubarrays(vector& arr) { + int n = arr.size(), res = 0; + int mod = 1e9 + 7; + + for (int i = 0; i < n; i++) { + int curSum = 0; + for (int j = i; j < n; j++) { + curSum += arr[j]; + if (curSum % 2 != 0) { + res = (res + 1) % mod; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + numOfSubarrays(arr) { + const n = arr.length; + let res = 0; + const mod = 1e9 + 7; + + for (let i = 0; i < n; i++) { + let curSum = 0; + for (let j = i; j < n; j++) { + curSum += arr[j]; + if (curSum % 2 !== 0) { + res = (res + 1) % mod; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def numOfSubarrays(self, arr: List[int]) -> int: + mod = 10**9 + 7 + n = len(arr) + memo = {} + + def dp(i: int, parity: int) -> int: + if i == n: + return 0 + + if (i, parity) in memo: + return memo[(i, parity)] + + new_parity = (parity + arr[i]) % 2 + res = new_parity + dp(i + 1, new_parity) + memo[(i, parity)] = res % mod + return memo[(i, parity)] + + ans = 0 + for i in range(n): + ans = (ans + dp(i, 0)) % mod + + return ans +``` + +```java +public class Solution { + int[][] memo; + int[] arr; + int mod = (int)1e9 + 7; + + public int numOfSubarrays(int[] arr) { + int n = arr.length; + this.arr = arr; + memo = new int[n][2]; + for (int i = 0; i < n; i++) { + memo[i][0] = -1; + memo[i][1] = -1; + } + + int res = 0; + for (int i = 0; i < n; i++) { + res = (res + dp(i, 0)) % mod; + } + return res; + } + + private int dp(int i, int parity) { + if (i == arr.length) return 0; + if (memo[i][parity] != -1) return memo[i][parity]; + + int newParity = (parity + arr[i]) % 2; + int res = newParity + dp(i + 1, newParity); + return memo[i][parity] = res % mod; + } +} +``` + +```cpp +class Solution { +public: + int mod = 1e9 + 7; + vector> memo; + vector arr; + + int numOfSubarrays(vector& arr) { + this->arr = arr; + int n = arr.size(); + memo.assign(n, vector(2, -1)); + + int res = 0; + for (int i = 0; i < n; i++) { + res = (res + dp(i, 0)) % mod; + } + return res; + } + + int dp(int i, int parity) { + if (i == arr.size()) return 0; + if (memo[i][parity] != -1) return memo[i][parity]; + + int newParity = (parity + arr[i]) % 2; + int res = newParity + dp(i + 1, newParity); + return memo[i][parity] = res % mod; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + numOfSubarrays(arr) { + const mod = 1e9 + 7; + const n = arr.length; + const memo = Array.from({ length: n }, () => Array(2).fill(-1)); + + const dp = (i, parity) => { + if (i === n) return 0; + if (memo[i][parity] !== -1) return memo[i][parity]; + + const newParity = (parity + arr[i]) % 2; + const res = newParity + dp(i + 1, newParity); + return (memo[i][parity] = res % mod); + }; + + let res = 0; + for (let i = 0; i < n; i++) { + res = (res + dp(i, 0)) % mod; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def numOfSubarrays(self, arr: List[int]) -> int: + n = len(arr) + mod = 10**9 + 7 + dp = [[0] * 2 for _ in range(n + 1)] + + for i in range(n - 1, -1, -1): + for parity in range(2): + new_parity = (parity + arr[i]) % 2 + dp[i][parity] = (new_parity + dp[i + 1][new_parity]) % mod + + res = 0 + for i in range(n): + res = (res + dp[i][0]) % mod + return res +``` + +```java +public class Solution { + public int numOfSubarrays(int[] arr) { + int n = arr.length; + int mod = (int)1e9 + 7; + int[][] dp = new int[n + 1][2]; + + for (int i = n - 1; i >= 0; i--) { + for (int parity = 0; parity <= 1; parity++) { + int newParity = (parity + arr[i]) % 2; + dp[i][parity] = (newParity + dp[i + 1][newParity]) % mod; + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + res = (res + dp[i][0]) % mod; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numOfSubarrays(vector& arr) { + int n = arr.size(), mod = 1e9 + 7; + vector> dp(n + 1, vector(2, 0)); + + for (int i = n - 1; i >= 0; i--) { + for (int parity = 0; parity <= 1; parity++) { + int newParity = (parity + arr[i]) % 2; + dp[i][parity] = (newParity + dp[i + 1][newParity]) % mod; + } + } + + int res = 0; + for (int i = 0; i < n; i++) { + res = (res + dp[i][0]) % mod; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + numOfSubarrays(arr) { + const n = arr.length; + const mod = 1e9 + 7; + const dp = Array.from({ length: n + 1 }, () => [0, 0]); + + for (let i = n - 1; i >= 0; i--) { + for (let parity = 0; parity <= 1; parity++) { + const newParity = (parity + arr[i]) % 2; + dp[i][parity] = (newParity + dp[i + 1][newParity]) % mod; + } + } + + let res = 0; + for (let i = 0; i < n; i++) { + res = (res + dp[i][0]) % mod; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Prefix Sum - I + +::tabs-start + +```python +class Solution: + def numOfSubarrays(self, arr: List[int]) -> int: + cur_sum = odd_cnt = even_cnt = res = 0 + MOD = 10**9 + 7 + + for n in arr: + cur_sum += n + if cur_sum % 2: + res = (res + 1 + even_cnt) % MOD + odd_cnt += 1 + else: + res = (res + odd_cnt) % MOD + even_cnt += 1 + + return res +``` + +```java +public class Solution { + public int numOfSubarrays(int[] arr) { + int curSum = 0, oddCnt = 0, evenCnt = 0, res = 0; + int MOD = (int)1e9 + 7; + + for (int n : arr) { + curSum += n; + if (curSum % 2 != 0) { + res = (res + 1 + evenCnt) % MOD; + oddCnt++; + } else { + res = (res + oddCnt) % MOD; + evenCnt++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int numOfSubarrays(vector& arr) { + long long curSum = 0, oddCnt = 0, evenCnt = 0, res = 0; + const int MOD = 1e9 + 7; + + for (int n : arr) { + curSum += n; + if (curSum % 2 != 0) { + res = (res + 1 + evenCnt) % MOD; + oddCnt++; + } else { + res = (res + oddCnt) % MOD; + evenCnt++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + numOfSubarrays(arr) { + let curSum = 0, + oddCnt = 0, + evenCnt = 0, + res = 0; + const MOD = 1e9 + 7; + + for (let n of arr) { + curSum += n; + if (curSum % 2 !== 0) { + res = (res + 1 + evenCnt) % MOD; + oddCnt++; + } else { + res = (res + oddCnt) % MOD; + evenCnt++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 5. Prefix Sum - II + +::tabs-start + +```python +class Solution: + def numOfSubarrays(self, arr: List[int]) -> int: + count = [1, 0] + prefix = res = 0 + MOD = 10**9 + 7 + + for num in arr: + prefix = (prefix + num) % 2 + res = (res + count[1 - prefix]) % MOD + count[prefix] += 1 + + return res +``` + +```java +public class Solution { + public int numOfSubarrays(int[] arr) { + int[] count = {1, 0}; + int prefix = 0, res = 0; + int MOD = (int)1e9 + 7; + + for (int num : arr) { + prefix = (prefix + num) % 2; + res = (res + count[1 - prefix]) % MOD; + count[prefix]++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int numOfSubarrays(vector& arr) { + int count[2] = {1, 0}; + int prefix = 0, res = 0; + const int MOD = 1e9 + 7; + + for (int num : arr) { + prefix = (prefix + num) % 2; + res = (res + count[1 - prefix]) % MOD; + count[prefix]++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + numOfSubarrays(arr) { + const count = [1, 0]; + let prefix = 0, + res = 0; + const MOD = 1e9 + 7; + + for (const num of arr) { + prefix = (prefix + num) % 2; + res = (res + count[1 - prefix]) % MOD; + count[prefix]++; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/number-of-submatrices-that-sum-to-target.md b/articles/number-of-submatrices-that-sum-to-target.md new file mode 100644 index 000000000..4f99367e1 --- /dev/null +++ b/articles/number-of-submatrices-that-sum-to-target.md @@ -0,0 +1,556 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + res = 0 + + for r1 in range(ROWS): + for r2 in range(r1, ROWS): + for c1 in range(COLS): + for c2 in range(c1, COLS): + subSum = 0 + for r in range(r1, r2 + 1): + for c in range(c1, c2 + 1): + subSum += matrix[r][c] + + if subSum == target: + res += 1 + + return res +``` + +```java +public class Solution { + public int numSubmatrixSumTarget(int[][] matrix, int target) { + int ROWS = matrix.length, COLS = matrix[0].length; + int res = 0; + + for (int r1 = 0; r1 < ROWS; r1++) { + for (int r2 = r1; r2 < ROWS; r2++) { + for (int c1 = 0; c1 < COLS; c1++) { + for (int c2 = c1; c2 < COLS; c2++) { + int subSum = 0; + for (int r = r1; r <= r2; r++) { + for (int c = c1; c <= c2; c++) { + subSum += matrix[r][c]; + } + } + if (subSum == target) { + res++; + } + } + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubmatrixSumTarget(vector>& matrix, int target) { + int ROWS = matrix.size(), COLS = matrix[0].size(); + int res = 0; + + for (int r1 = 0; r1 < ROWS; r1++) { + for (int r2 = r1; r2 < ROWS; r2++) { + for (int c1 = 0; c1 < COLS; c1++) { + for (int c2 = c1; c2 < COLS; c2++) { + int subSum = 0; + for (int r = r1; r <= r2; r++) { + for (int c = c1; c <= c2; c++) { + subSum += matrix[r][c]; + } + } + if (subSum == target) { + res++; + } + } + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @param {number} target + * @return {number} + */ + numSubmatrixSumTarget(matrix, target) { + const ROWS = matrix.length, + COLS = matrix[0].length; + let res = 0; + + for (let r1 = 0; r1 < ROWS; r1++) { + for (let r2 = r1; r2 < ROWS; r2++) { + for (let c1 = 0; c1 < COLS; c1++) { + for (let c2 = c1; c2 < COLS; c2++) { + let subSum = 0; + for (let r = r1; r <= r2; r++) { + for (let c = c1; c <= c2; c++) { + subSum += matrix[r][c]; + } + } + if (subSum === target) { + res++; + } + } + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m ^ 3 * n ^ 3)$ +- Space complexity: $O(1)$ extra space. + +> Where $m$ is the number of rows and $n$ is the number of columns of the given matrix. + +--- + +## 2. Two Dimensional Prefix Sum + +::tabs-start + +```python +class Solution: + def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + sub_sum = [[0] * COLS for _ in range(ROWS)] + + for r in range(ROWS): + for c in range(COLS): + top = sub_sum[r - 1][c] if r > 0 else 0 + left = sub_sum[r][c - 1] if c > 0 else 0 + top_left = sub_sum[r - 1][c - 1] if min(r, c) > 0 else 0 + sub_sum[r][c] = matrix[r][c] + top + left - top_left + + res = 0 + for r1 in range(ROWS): + for r2 in range(r1, ROWS): + for c1 in range(COLS): + for c2 in range(c1, COLS): + top = sub_sum[r1 - 1][c2] if r1 > 0 else 0 + left = sub_sum[r2][c1 - 1] if c1 > 0 else 0 + top_left = sub_sum[r1 - 1][c1 - 1] if min(r1, c1) > 0 else 0 + cur_sum = sub_sum[r2][c2] - top - left + top_left + if cur_sum == target: + res += 1 + return res +``` + +```java +public class Solution { + public int numSubmatrixSumTarget(int[][] matrix, int target) { + int ROWS = matrix.length, COLS = matrix[0].length; + int[][] subSum = new int[ROWS][COLS]; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int top = (r > 0) ? subSum[r - 1][c] : 0; + int left = (c > 0) ? subSum[r][c - 1] : 0; + int topLeft = (Math.min(r, c) > 0) ? subSum[r - 1][c - 1] : 0; + subSum[r][c] = matrix[r][c] + top + left - topLeft; + } + } + + int res = 0; + for (int r1 = 0; r1 < ROWS; r1++) { + for (int r2 = r1; r2 < ROWS; r2++) { + for (int c1 = 0; c1 < COLS; c1++) { + for (int c2 = c1; c2 < COLS; c2++) { + int top = (r1 > 0) ? subSum[r1 - 1][c2] : 0; + int left = (c1 > 0) ? subSum[r2][c1 - 1] : 0; + int topLeft = (Math.min(r1, c1) > 0) ? subSum[r1 - 1][c1 - 1] : 0; + int curSum = subSum[r2][c2] - top - left + topLeft; + if (curSum == target) { + res++; + } + } + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubmatrixSumTarget(vector>& matrix, int target) { + int ROWS = matrix.size(), COLS = matrix[0].size(); + vector> subSum(ROWS, vector(COLS, 0)); + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int top = (r > 0) ? subSum[r - 1][c] : 0; + int left = (c > 0) ? subSum[r][c - 1] : 0; + int topLeft = (min(r, c) > 0) ? subSum[r - 1][c - 1] : 0; + subSum[r][c] = matrix[r][c] + top + left - topLeft; + } + } + + int res = 0; + for (int r1 = 0; r1 < ROWS; r1++) { + for (int r2 = r1; r2 < ROWS; r2++) { + for (int c1 = 0; c1 < COLS; c1++) { + for (int c2 = c1; c2 < COLS; c2++) { + int top = (r1 > 0) ? subSum[r1 - 1][c2] : 0; + int left = (c1 > 0) ? subSum[r2][c1 - 1] : 0; + int topLeft = (min(r1, c1) > 0) ? subSum[r1 - 1][c1 - 1] : 0; + int curSum = subSum[r2][c2] - top - left + topLeft; + if (curSum == target) { + res++; + } + } + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @param {number} target + * @return {number} + */ + numSubmatrixSumTarget(matrix, target) { + const ROWS = matrix.length, + COLS = matrix[0].length; + const subSum = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + let top = r > 0 ? subSum[r - 1][c] : 0; + let left = c > 0 ? subSum[r][c - 1] : 0; + let topLeft = Math.min(r, c) > 0 ? subSum[r - 1][c - 1] : 0; + subSum[r][c] = matrix[r][c] + top + left - topLeft; + } + } + + let res = 0; + for (let r1 = 0; r1 < ROWS; r1++) { + for (let r2 = r1; r2 < ROWS; r2++) { + for (let c1 = 0; c1 < COLS; c1++) { + for (let c2 = c1; c2 < COLS; c2++) { + let top = r1 > 0 ? subSum[r1 - 1][c2] : 0; + let left = c1 > 0 ? subSum[r2][c1 - 1] : 0; + let topLeft = + Math.min(r1, c1) > 0 ? subSum[r1 - 1][c1 - 1] : 0; + let curSum = subSum[r2][c2] - top - left + topLeft; + if (curSum === target) { + res++; + } + } + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m ^ 2 * n ^ 2)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns of the given matrix. + +--- + +## 3. Horizontal 1D Prefix Sum + +::tabs-start + +```python +class Solution: + def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + sub_sum = [[0] * COLS for _ in range(ROWS)] + + for r in range(ROWS): + for c in range(COLS): + top = sub_sum[r - 1][c] if r > 0 else 0 + left = sub_sum[r][c - 1] if c > 0 else 0 + top_left = sub_sum[r - 1][c - 1] if min(r, c) > 0 else 0 + sub_sum[r][c] = matrix[r][c] + top + left - top_left + + res = 0 + for r1 in range(ROWS): + for r2 in range(r1, ROWS): + count = defaultdict(int) + count[0] = 1 + for c in range(COLS): + cur_sum = sub_sum[r2][c] - (sub_sum[r1 - 1][c] if r1 > 0 else 0) + res += count[cur_sum - target] + count[cur_sum] += 1 + + return res +``` + +```java +public class Solution { + public int numSubmatrixSumTarget(int[][] matrix, int target) { + int ROWS = matrix.length, COLS = matrix[0].length; + int[][] subSum = new int[ROWS][COLS]; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int top = (r > 0) ? subSum[r - 1][c] : 0; + int left = (c > 0) ? subSum[r][c - 1] : 0; + int topLeft = (Math.min(r, c) > 0) ? subSum[r - 1][c - 1] : 0; + subSum[r][c] = matrix[r][c] + top + left - topLeft; + } + } + + int res = 0; + for (int r1 = 0; r1 < ROWS; r1++) { + for (int r2 = r1; r2 < ROWS; r2++) { + Map count = new HashMap<>(); + count.put(0, 1); + for (int c = 0; c < COLS; c++) { + int curSum = subSum[r2][c] - (r1 > 0 ? subSum[r1 - 1][c] : 0); + res += count.getOrDefault(curSum - target, 0); + count.put(curSum, count.getOrDefault(curSum, 0) + 1); + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubmatrixSumTarget(vector>& matrix, int target) { + int ROWS = matrix.size(), COLS = matrix[0].size(); + vector> subSum(ROWS, vector(COLS, 0)); + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + int top = (r > 0) ? subSum[r - 1][c] : 0; + int left = (c > 0) ? subSum[r][c - 1] : 0; + int topLeft = (min(r, c) > 0) ? subSum[r - 1][c - 1] : 0; + subSum[r][c] = matrix[r][c] + top + left - topLeft; + } + } + + int res = 0; + for (int r1 = 0; r1 < ROWS; r1++) { + for (int r2 = r1; r2 < ROWS; r2++) { + unordered_map count; + count[0] = 1; + for (int c = 0; c < COLS; c++) { + int curSum = subSum[r2][c] - (r1 > 0 ? subSum[r1 - 1][c] : 0); + res += count[curSum - target]; + count[curSum]++; + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @param {number} target + * @return {number} + */ + numSubmatrixSumTarget(matrix, target) { + let ROWS = matrix.length, + COLS = matrix[0].length; + let subSum = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + let top = r > 0 ? subSum[r - 1][c] : 0; + let left = c > 0 ? subSum[r][c - 1] : 0; + let topLeft = Math.min(r, c) > 0 ? subSum[r - 1][c - 1] : 0; + subSum[r][c] = matrix[r][c] + top + left - topLeft; + } + } + + let res = 0; + for (let r1 = 0; r1 < ROWS; r1++) { + for (let r2 = r1; r2 < ROWS; r2++) { + let count = new Map(); + count.set(0, 1); + for (let c = 0; c < COLS; c++) { + let curSum = + subSum[r2][c] - (r1 > 0 ? subSum[r1 - 1][c] : 0); + res += count.get(curSum - target) || 0; + count.set(curSum, (count.get(curSum) || 0) + 1); + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m ^ 2 * n)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns of the given matrix. + +--- + +## 4. Vertical 1D Prefix Sum + +::tabs-start + +```python +class Solution: + def numSubmatrixSumTarget(self, matrix: List[List[int]], target: int) -> int: + ROWS, COLS = len(matrix), len(matrix[0]) + res = 0 + + for c1 in range(COLS): + row_prefix = [0] * ROWS + for c2 in range(c1, COLS): + for r in range(ROWS): + row_prefix[r] += matrix[r][c2] + + count = defaultdict(int) + count[0] = 1 + cur_sum = 0 + for r in range(ROWS): + cur_sum += row_prefix[r] + res += count[cur_sum - target] + count[cur_sum] += 1 + + return res +``` + +```java +public class Solution { + public int numSubmatrixSumTarget(int[][] matrix, int target) { + int ROWS = matrix.length, COLS = matrix[0].length, res = 0; + + for (int c1 = 0; c1 < COLS; c1++) { + int[] rowPrefix = new int[ROWS]; + for (int c2 = c1; c2 < COLS; c2++) { + for (int r = 0; r < ROWS; r++) { + rowPrefix[r] += matrix[r][c2]; + } + + Map count = new HashMap<>(); + count.put(0, 1); + int curSum = 0; + + for (int r = 0; r < ROWS; r++) { + curSum += rowPrefix[r]; + res += count.getOrDefault(curSum - target, 0); + count.put(curSum, count.getOrDefault(curSum, 0) + 1); + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubmatrixSumTarget(vector>& matrix, int target) { + int ROWS = matrix.size(), COLS = matrix[0].size(), res = 0; + + for (int c1 = 0; c1 < COLS; c1++) { + vector rowPrefix(ROWS, 0); + for (int c2 = c1; c2 < COLS; c2++) { + for (int r = 0; r < ROWS; r++) { + rowPrefix[r] += matrix[r][c2]; + } + + unordered_map count; + count[0] = 1; + int curSum = 0; + for (int r = 0; r < ROWS; r++) { + curSum += rowPrefix[r]; + res += count[curSum - target]; + count[curSum]++; + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} matrix + * @param {number} target + * @return {number} + */ + numSubmatrixSumTarget(matrix, target) { + let ROWS = matrix.length, + COLS = matrix[0].length, + res = 0; + + for (let c1 = 0; c1 < COLS; c1++) { + let rowPrefix = new Array(ROWS).fill(0); + for (let c2 = c1; c2 < COLS; c2++) { + for (let r = 0; r < ROWS; r++) { + rowPrefix[r] += matrix[r][c2]; + } + + let count = new Map(); + count.set(0, 1); + let curSum = 0; + + for (let r = 0; r < ROWS; r++) { + curSum += rowPrefix[r]; + res += count.get(curSum - target) || 0; + count.set(curSum, (count.get(curSum) || 0) + 1); + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n ^ 2)$ +- Space complexity: $O(m)$ + +> Where $m$ is the number of rows and $n$ is the number of columns of the given matrix. diff --git a/articles/number-of-subsequences-that-satisfy-the-given-sum-condition.md b/articles/number-of-subsequences-that-satisfy-the-given-sum-condition.md new file mode 100644 index 000000000..d54c5e2c2 --- /dev/null +++ b/articles/number-of-subsequences-that-satisfy-the-given-sum-condition.md @@ -0,0 +1,523 @@ +## 1. Brute Force (Recursion) + +::tabs-start + +```python +class Solution: + def numSubseq(self, nums: List[int], target: int) -> int: + MOD = 1000000007 + + def dfs(maxi, mini, i): + if i == len(nums): + if mini != float("inf") and (maxi + mini) <= target: + return 1 + return 0 + + skip = dfs(maxi, mini, i + 1) + include = dfs(max(maxi, nums[i]), min(mini, nums[i]), i + 1) + return (skip + include) % MOD + + return dfs(float("-inf"), float("inf"), 0) +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + + public int numSubseq(int[] nums, int target) { + return dfs(nums, Integer.MIN_VALUE, Integer.MAX_VALUE, 0, target); + } + + private int dfs(int[] nums, int maxi, int mini, int i, int target) { + if (i == nums.length) { + if (mini != Integer.MAX_VALUE && (maxi + mini) <= target) { + return 1; + } + return 0; + } + + int skip = dfs(nums, maxi, mini, i + 1, target); + int include = dfs(nums, Math.max(maxi, nums[i]), Math.min(mini, nums[i]), i + 1, target); + return (skip + include) % MOD; + } +} +``` + +```cpp +class Solution { +public: + const int MOD = 1e9 + 7; + + int numSubseq(vector& nums, int target) { + return dfs(nums, INT_MIN, INT_MAX, 0, target); + } + +private: + int dfs(vector& nums, int maxi, int mini, int i, int target) { + if (i == nums.size()) { + if (mini != INT_MAX && (maxi + mini) <= target) { + return 1; + } + return 0; + } + + int skip = dfs(nums, maxi, mini, i + 1, target); + int include = dfs(nums, max(maxi, nums[i]), min(mini, nums[i]), i + 1, target); + return (skip + include) % MOD; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ + numSubseq(nums, target) { + const MOD = 1000000007; + + const dfs = (maxi, mini, i) => { + if (i === nums.length) { + if (mini !== Infinity && maxi + mini <= target) { + return 1; + } + return 0; + } + + const skip = dfs(maxi, mini, i + 1); + const include = dfs( + Math.max(maxi, nums[i]), + Math.min(mini, nums[i]), + i + 1, + ); + return (skip + include) % MOD; + }; + + return dfs(-Infinity, Infinity, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Binary Search + +::tabs-start + +```python +class Solution: + def numSubseq(self, nums: List[int], target: int) -> int: + nums.sort() + MOD = 1000000007 + res = 0 + + for i in range(len(nums)): + if nums[i] * 2 > target: + break + + l, r = i, len(nums) - 1 + while l <= r: + mid = (l + r) // 2 + if nums[i] + nums[mid] <= target: + l = mid + 1 + else: + r = mid - 1 + + count = pow(2, r - i, MOD) + res = (res + count) % MOD + + return res +``` + +```java +public class Solution { + public int numSubseq(int[] nums, int target) { + Arrays.sort(nums); + int MOD = 1000000007; + int res = 0; + + for (int i = 0; i < nums.length; i++) { + if (nums[i] * 2 > target) break; + + int l = i, r = nums.length - 1; + while (l <= r) { + int mid = l + (r - l) / 2; + if (nums[i] + nums[mid] <= target) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + long count = pow(2, r - i, MOD); + res = (int) ((res + count) % MOD); + } + return res; + } + + private long pow(int base, int exp, int mod) { + long result = 1; + long b = base; + while (exp > 0) { + if ((exp & 1) == 1) result = (result * b) % mod; + b = (b * b) % mod; + exp >>= 1; + } + return result; + } +} +``` + +```cpp +class Solution { +public: + int numSubseq(vector& nums, int target) { + sort(nums.begin(), nums.end()); + int MOD = 1000000007; + int res = 0; + + for (int i = 0; i < nums.size(); i++) { + if (nums[i] * 2 > target) break; + + int l = i, r = nums.size() - 1; + while (l <= r) { + int mid = l + (r - l) / 2; + if (nums[i] + nums[mid] <= target) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + long long count = powMod(2, r - i, MOD); + res = (res + count) % MOD; + } + return res; + } + +private: + long long powMod(int base, int exp, int mod) { + long long result = 1, b = base; + while (exp > 0) { + if (exp & 1) result = (result * b) % mod; + b = (b * b) % mod; + exp >>= 1; + } + return result; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ + numSubseq(nums, target) { + nums.sort((a, b) => a - b); + const MOD = BigInt(1000000007); + let res = 0n; + + const powerMod = (base, exp, mod) => { + let result = 1n, + b = BigInt(base); + while (exp > 0) { + if (exp & 1) result = (result * b) % mod; + b = (b * b) % mod; + exp >>= 1; + } + return result; + }; + + for (let i = 0; i < nums.length; i++) { + if (nums[i] * 2 > target) break; + + let l = i, + r = nums.length - 1; + while (l <= r) { + const mid = Math.floor((l + r) / 2); + if (nums[i] + nums[mid] <= target) { + l = mid + 1; + } else { + r = mid - 1; + } + } + + const count = powerMod(2, r - i, MOD); + res = (res + count) % MOD; + } + + return Number(res); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 3. Two Pointers + +::tabs-start + +```python +class Solution: + def numSubseq(self, nums: List[int], target: int) -> int: + nums.sort() + res = 0 + mod = 10**9 + 7 + + r = len(nums) - 1 + for i, left in enumerate(nums): + while i <= r and left + nums[r] > target: + r -= 1 + if i <= r: + res += pow(2, r - i, mod) + res %= mod + + return res +``` + +```java +public class Solution { + public int numSubseq(int[] nums, int target) { + Arrays.sort(nums); + int res = 0, mod = 1000000007; + int r = nums.length - 1; + + for (int i = 0; i < nums.length; i++) { + while (i <= r && nums[i] + nums[r] > target) { + r--; + } + if (i <= r) { + res = (res + power(2, r - i, mod)) % mod; + } + } + return res; + } + + private int power(int base, int exp, int mod) { + long result = 1, b = base; + while (exp > 0) { + if ((exp & 1) == 1) result = (result * b) % mod; + b = (b * b) % mod; + exp >>= 1; + } + return (int) result; + } +} +``` + +```cpp +class Solution { +public: + int numSubseq(vector& nums, int target) { + sort(nums.begin(), nums.end()); + int res = 0, mod = 1000000007; + int r = nums.size() - 1; + + for (int i = 0; i < nums.size(); i++) { + while (i <= r && nums[i] + nums[r] > target) { + r--; + } + if (i <= r) { + res = (res + power(2, r - i, mod)) % mod; + } + } + return res; + } + +private: + long long power(int base, int exp, int mod) { + long long result = 1, b = base; + while (exp > 0) { + if (exp & 1) result = (result * b) % mod; + b = (b * b) % mod; + exp >>= 1; + } + return result; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ + numSubseq(nums, target) { + nums.sort((a, b) => a - b); + const mod = BigInt(1000000007); + let res = 0n; + + const power = (base, exp, mod) => { + let result = 1n, + b = BigInt(base); + while (exp > 0) { + if (exp & 1) result = (result * b) % mod; + b = (b * b) % mod; + exp >>= 1; + } + return result; + }; + + for (let i = 0, r = nums.length - 1; i < nums.length; i++) { + while (nums[i] + nums[r] > target && i <= r) { + r--; + } + if (i <= r) { + res = (res + power(2, r - i, mod)) % mod; + } + } + + return Number(res); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 4. Two Pointers (Optimal) + +::tabs-start + +```python +class Solution: + def numSubseq(self, nums: List[int], target: int) -> int: + nums.sort() + MOD = 1000000007 + res = 0 + l, r = 0, len(nums) - 1 + power = [1] * len(nums) + + for i in range(1, len(nums)): + power[i] = (power[i - 1] * 2) % MOD + + while l <= r: + if nums[l] + nums[r] <= target: + res = (res + power[r - l]) % MOD + l += 1 + else: + r -= 1 + + return res +``` + +```java +public class Solution { + public int numSubseq(int[] nums, int target) { + Arrays.sort(nums); + int MOD = 1000000007; + int res = 0, l = 0, r = nums.length - 1; + int[] power = new int[nums.length]; + power[0] = 1; + + for (int i = 1; i < nums.length; i++) { + power[i] = (power[i - 1] * 2) % MOD; + } + + while (l <= r) { + if (nums[l] + nums[r] <= target) { + res = (res + power[r - l]) % MOD; + l++; + } else { + r--; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubseq(vector& nums, int target) { + sort(nums.begin(), nums.end()); + int MOD = 1000000007; + int res = 0, l = 0, r = nums.size() - 1; + vector power(nums.size(), 1); + + for (int i = 1; i < nums.size(); i++) { + power[i] = (power[i - 1] * 2) % MOD; + } + + while (l <= r) { + if (nums[l] + nums[r] <= target) { + res = (res + power[r - l]) % MOD; + l++; + } else { + r--; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} target + * @return {number} + */ + numSubseq(nums, target) { + nums.sort((a, b) => a - b); + const MOD = 1000000007; + let res = 0, + l = 0, + r = nums.length - 1; + const power = Array(nums.length).fill(1); + + for (let i = 1; i < nums.length; i++) { + power[i] = (power[i - 1] * 2) % MOD; + } + + while (l <= r) { + if (nums[l] + nums[r] <= target) { + res = (res + power[r - l]) % MOD; + l++; + } else { + r--; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/number-of-visible-people-in-a-queue.md b/articles/number-of-visible-people-in-a-queue.md new file mode 100644 index 000000000..6a10f8212 --- /dev/null +++ b/articles/number-of-visible-people-in-a-queue.md @@ -0,0 +1,359 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def canSeePersonsCount(self, heights: List[int]) -> List[int]: + n = len(heights) + res = [] + + for i in range(n): + maxi = cnt = 0 + for j in range(i + 1, n): + if min(heights[i], heights[j]) > maxi: + cnt += 1 + maxi = max(maxi, heights[j]) + + res.append(cnt) + + return res +``` + +```java +public class Solution { + public int[] canSeePersonsCount(int[] heights) { + int n = heights.length; + int[] res = new int[n]; + for (int i = 0; i < n; i++) { + int maxi = 0, cnt = 0; + for (int j = i + 1; j < n; j++) { + if (Math.min(heights[i], heights[j]) > maxi) { + cnt++; + } + maxi = Math.max(maxi, heights[j]); + } + res[i] = cnt; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector canSeePersonsCount(vector& heights) { + int n = heights.size(); + vector res(n); + for (int i = 0; i < n; i++) { + int maxi = 0, cnt = 0; + for (int j = i + 1; j < n; j++) { + if (min(heights[i], heights[j]) > maxi) { + cnt++; + } + maxi = max(maxi, heights[j]); + } + res[i] = cnt; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @return {number[]} + */ + canSeePersonsCount(heights) { + const n = heights.length; + const res = []; + for (let i = 0; i < n; i++) { + let maxi = 0, + cnt = 0; + for (let j = i + 1; j < n; j++) { + if (Math.min(heights[i], heights[j]) > maxi) { + cnt++; + } + maxi = Math.max(maxi, heights[j]); + } + res.push(cnt); + } + return res; + } +} +``` + +```csharp +public class Solution { + public int[] CanSeePersonsCount(int[] heights) { + int n = heights.Length; + int[] res = new int[n]; + for (int i = 0; i < n; i++) { + int maxi = 0, cnt = 0; + for (int j = i + 1; j < n; j++) { + if (Math.Min(heights[i], heights[j]) > maxi) { + cnt++; + } + maxi = Math.Max(maxi, heights[j]); + } + res[i] = cnt; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ for the output array. + +--- + +## 2. Stack - I + +::tabs-start + +```python +class Solution: + def canSeePersonsCount(self, heights: List[int]) -> List[int]: + n = len(heights) + res = [0] * n + stack = [] + + for i, h in enumerate(heights): + while stack and heights[stack[-1]] < h: + res[stack.pop()] += 1 + if stack: + res[stack[-1]] += 1 + stack.append(i) + + return res +``` + +```java +public class Solution { + public int[] canSeePersonsCount(int[] heights) { + int n = heights.length; + int[] res = new int[n]; + Stack stack = new Stack<>(); + for (int i = 0; i < n; i++) { + int h = heights[i]; + while (!stack.isEmpty() && heights[stack.peek()] < h) { + res[stack.pop()]++; + } + if (!stack.isEmpty()) { + res[stack.peek()]++; + } + stack.push(i); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector canSeePersonsCount(vector& heights) { + int n = heights.size(); + vector res(n); + stack st; + for (int i = 0; i < n; i++) { + int h = heights[i]; + while (!st.empty() && heights[st.top()] < h) { + res[st.top()]++; + st.pop(); + } + if (!st.empty()) { + res[st.top()]++; + } + st.push(i); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @return {number[]} + */ + canSeePersonsCount(heights) { + const n = heights.length; + const res = Array(n).fill(0); + const stack = []; + for (let i = 0; i < n; i++) { + const h = heights[i]; + while (stack.length && heights[stack[stack.length - 1]] < h) { + res[stack.pop()]++; + } + if (stack.length) { + res[stack[stack.length - 1]]++; + } + stack.push(i); + } + return res; + } +} +``` + +```csharp +public class Solution { + public int[] CanSeePersonsCount(int[] heights) { + int n = heights.Length; + int[] res = new int[n]; + var stack = new Stack(); + for (int i = 0; i < n; i++) { + int h = heights[i]; + while (stack.Count > 0 && heights[stack.Peek()] < h) { + res[stack.Pop()]++; + } + if (stack.Count > 0) { + res[stack.Peek()]++; + } + stack.Push(i); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Stack - II + +::tabs-start + +```python +class Solution: + def canSeePersonsCount(self, heights: List[int]) -> List[int]: + n = len(heights) + res = [0] * n + stack = [] + + for i in range(n - 1, -1, -1): + while stack and stack[-1] < heights[i]: + stack.pop() + res[i] += 1 + + if stack: + res[i] += 1 + stack.append(heights[i]) + + return res +``` + +```java +public class Solution { + public int[] canSeePersonsCount(int[] heights) { + int n = heights.length; + int[] res = new int[n]; + Stack stack = new Stack<>(); + + for (int i = n - 1; i >= 0; i--) { + while (!stack.isEmpty() && stack.peek() < heights[i]) { + stack.pop(); + res[i]++; + } + if (!stack.isEmpty()) { + res[i]++; + } + stack.push(heights[i]); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector canSeePersonsCount(vector& heights) { + int n = heights.size(); + vector res(n, 0); + stack st; + + for (int i = n - 1; i >= 0; --i) { + while (!st.empty() && st.top() < heights[i]) { + st.pop(); + res[i]++; + } + if (!st.empty()) { + res[i]++; + } + st.push(heights[i]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} heights + * @return {number[]} + */ + canSeePersonsCount(heights) { + const n = heights.length; + const res = new Array(n).fill(0); + const stack = []; + for (let i = n - 1; i >= 0; i--) { + while (stack.length && stack[stack.length - 1] < heights[i]) { + stack.pop(); + res[i]++; + } + if (stack.length) { + res[i]++; + } + stack.push(heights[i]); + } + return res; + } +} +``` + +```csharp +public class Solution { + public int[] CanSeePersonsCount(int[] heights) { + int n = heights.Length; + int[] res = new int[n]; + var stack = new Stack(); + for (int i = n - 1; i >= 0; i--) { + while (stack.Count > 0 && stack.Peek() < heights[i]) { + stack.Pop(); + res[i]++; + } + if (stack.Count > 0) { + res[i]++; + } + stack.Push(heights[i]); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/number-of-ways-to-divide-a-long-corridor.md b/articles/number-of-ways-to-divide-a-long-corridor.md new file mode 100644 index 000000000..36a9c7d81 --- /dev/null +++ b/articles/number-of-ways-to-divide-a-long-corridor.md @@ -0,0 +1,612 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def numberOfWays(self, corridor: str) -> int: + mod = 10**9 + 7 + cache = [[-1] * 3 for i in range(len(corridor))] # (i, seats) -> count + + def dfs(i, seats): + if i == len(corridor): + return 1 if seats == 2 else 0 + if cache[i][seats] != -1: + return cache[i][seats] + + res = 0 + if seats == 2: + if corridor[i] == "S": + res = dfs(i + 1, 1) + else: + res = (dfs(i + 1, 0) + dfs(i + 1, 2)) % mod + else: + if corridor[i] == "S": + res = dfs(i + 1, seats + 1) + else: + res = dfs(i + 1, seats) + + cache[i][seats] = res + return res + + return dfs(0, 0) +``` + +```java +public class Solution { + private static final int MOD = 1_000_000_007; + private int[][] dp; + + public int numberOfWays(String corridor) { + int n = corridor.length(); + dp = new int[n][3]; + for (int i = 0; i < n; i++) { + Arrays.fill(dp[i], -1); + } + return dfs(0, 0, corridor); + } + + private int dfs(int i, int seats, String corridor) { + if (i == corridor.length()) { + return seats == 2 ? 1 : 0; + } + if (dp[i][seats] != -1) { + return dp[i][seats]; + } + + int res = 0; + if (seats == 2) { + if (corridor.charAt(i) == 'S') { + res = dfs(i + 1, 1, corridor); + } else { + res = (dfs(i + 1, 0, corridor) + dfs(i + 1, 2, corridor)) % MOD; + } + } else { + if (corridor.charAt(i) == 'S') { + res = dfs(i + 1, seats + 1, corridor); + } else { + res = dfs(i + 1, seats, corridor); + } + } + + return dp[i][seats] = res; + } +} +``` + +```cpp +class Solution { +public: + static constexpr int MOD = 1'000'000'007; + vector> dp; + + int numberOfWays(string corridor) { + int n = corridor.size(); + dp.assign(n, vector(3, -1)); + return dfs(0, 0, corridor); + } + + int dfs(int i, int seats, string& corridor) { + if (i == corridor.size()) { + return seats == 2 ? 1 : 0; + } + if (dp[i][seats] != -1) { + return dp[i][seats]; + } + + int res = 0; + if (seats == 2) { + if (corridor[i] == 'S') { + res = dfs(i + 1, 1, corridor); + } else { + res = (dfs(i + 1, 0, corridor) + dfs(i + 1, 2, corridor)) % MOD; + } + } else { + if (corridor[i] == 'S') { + res = dfs(i + 1, seats + 1, corridor); + } else { + res = dfs(i + 1, seats, corridor); + } + } + + return dp[i][seats] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} corridor + * @return {number} + */ + numberOfWays(corridor) { + const MOD = 1_000_000_007; + const n = corridor.length; + const dp = Array.from({ length: n }, () => Array(3).fill(-1)); + + const dfs = (i, seats) => { + if (i === n) return seats === 2 ? 1 : 0; + if (dp[i][seats] !== -1) return dp[i][seats]; + + let res = 0; + if (seats === 2) { + if (corridor[i] === 'S') { + res = dfs(i + 1, 1); + } else { + res = (dfs(i + 1, 0) + dfs(i + 1, 2)) % MOD; + } + } else { + if (corridor[i] === 'S') { + res = dfs(i + 1, seats + 1); + } else { + res = dfs(i + 1, seats); + } + } + + return (dp[i][seats] = res); + }; + + return dfs(0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def numberOfWays(self, corridor: str) -> int: + MOD = 1000000007 + n = len(corridor) + dp = [[0] * 3 for _ in range(n + 1)] + dp[n][2] = 1 + + for i in range(n - 1, -1, -1): + for seats in range(3): + if seats == 2: + if corridor[i] == 'S': + dp[i][seats] = dp[i + 1][1] + else: + dp[i][seats] = (dp[i + 1][0] + dp[i + 1][2]) % MOD + else: + if corridor[i] == 'S': + dp[i][seats] = dp[i + 1][seats + 1] + else: + dp[i][seats] = dp[i + 1][seats] + + return dp[0][0] +``` + +```java +public class Solution { + public int numberOfWays(String corridor) { + int MOD = 1000000007; + int n = corridor.length(); + int[][] dp = new int[n + 1][3]; + dp[n][2] = 1; + + for (int i = n - 1; i >= 0; i--) { + for (int seats = 0; seats < 3; seats++) { + if (seats == 2) { + if (corridor.charAt(i) == 'S') { + dp[i][seats] = dp[i + 1][1]; + } else { + dp[i][seats] = (dp[i + 1][0] + dp[i + 1][2]) % MOD; + } + } else { + if (corridor.charAt(i) == 'S') { + dp[i][seats] = dp[i + 1][seats + 1]; + } else { + dp[i][seats] = dp[i + 1][seats]; + } + } + } + } + return dp[0][0]; + } +} +``` + +```cpp +class Solution { +public: + int numberOfWays(string corridor) { + int MOD = 1000000007; + int n = corridor.size(); + vector> dp(n + 1, vector(3, 0)); + dp[n][2] = 1; + + for (int i = n - 1; i >= 0; i--) { + for (int seats = 0; seats < 3; seats++) { + if (seats == 2) { + if (corridor[i] == 'S') { + dp[i][seats] = dp[i + 1][1]; + } else { + dp[i][seats] = (dp[i + 1][0] + dp[i + 1][2]) % MOD; + } + } else { + if (corridor[i] == 'S') { + dp[i][seats] = dp[i + 1][seats + 1]; + } else { + dp[i][seats] = dp[i + 1][seats]; + } + } + } + } + return dp[0][0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} corridor + * @return {number} + */ + numberOfWays(corridor) { + const MOD = 1000000007; + const n = corridor.length; + let dp = Array.from({ length: n + 1 }, () => Array(3).fill(0)); + dp[n][2] = 1; + + for (let i = n - 1; i >= 0; i--) { + for (let seats = 0; seats < 3; seats++) { + if (seats === 2) { + if (corridor[i] === 'S') { + dp[i][seats] = dp[i + 1][1]; + } else { + dp[i][seats] = (dp[i + 1][0] + dp[i + 1][2]) % MOD; + } + } else { + if (corridor[i] === 'S') { + dp[i][seats] = dp[i + 1][seats + 1]; + } else { + dp[i][seats] = dp[i + 1][seats]; + } + } + } + } + return dp[0][0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def numberOfWays(self, corridor: str) -> int: + MOD = 1000000007 + dp = [0, 0, 1] + + for i in reversed(corridor): + new_dp = [0] * 3 + for seats in range(3): + if seats == 2: + new_dp[seats] = dp[1] if i == 'S' else (dp[0] + dp[2]) % MOD + else: + new_dp[seats] = dp[seats + 1] if i == 'S' else dp[seats] + dp = new_dp + + return dp[0] +``` + +```java +public class Solution { + public int numberOfWays(String corridor) { + int MOD = 1000000007; + int[] dp = {0, 0, 1}; + + for (int i = corridor.length() - 1; i >= 0; i--) { + int[] new_dp = new int[3]; + for (int seats = 0; seats < 3; seats++) { + if (seats == 2) { + new_dp[seats] = corridor.charAt(i) == 'S' ? dp[1] : (dp[0] + dp[2]) % MOD; + } else { + new_dp[seats] = corridor.charAt(i) == 'S' ? dp[seats + 1] : dp[seats]; + } + } + dp = new_dp; + } + return dp[0]; + } +} +``` + +```cpp +class Solution { +public: + int numberOfWays(string corridor) { + const int MOD = 1000000007; + vector dp = {0, 0, 1}; + + for (int i = corridor.length() - 1; i >= 0; i--) { + vector new_dp(3, 0); + for (int seats = 0; seats < 3; seats++) { + if (seats == 2) { + new_dp[seats] = (corridor[i] == 'S') ? dp[1] : (dp[0] + dp[2]) % MOD; + } else { + new_dp[seats] = (corridor[i] == 'S') ? dp[seats + 1] : dp[seats]; + } + } + dp = new_dp; + } + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} corridor + * @return {number} + */ + numberOfWays(corridor) { + const MOD = 1000000007; + let dp = [0, 0, 1]; + + for (let i = corridor.length - 1; i >= 0; i--) { + let new_dp = [0, 0, 0]; + for (let seats = 0; seats < 3; seats++) { + if (seats === 2) { + new_dp[seats] = + corridor[i] === 'S' ? dp[1] : (dp[0] + dp[2]) % MOD; + } else { + new_dp[seats] = + corridor[i] === 'S' ? dp[seats + 1] : dp[seats]; + } + } + dp = new_dp; + } + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 4. Combinatorics + +::tabs-start + +```python +class Solution: + def numberOfWays(self, corridor: str) -> int: + mod = 10**9 + 7 + seats = [i for i, c in enumerate(corridor) if c == "S"] + + length = len(seats) + if length < 2 or length % 2 == 1: + return 0 + + res = 1 + for i in range(1, length - 1, 2): + res = (res * (seats[i + 1] - seats[i])) % mod + + return res +``` + +```java +public class Solution { + public int numberOfWays(String corridor) { + int mod = 1_000_000_007; + List seats = new ArrayList<>(); + + for (int i = 0; i < corridor.length(); i++) { + if (corridor.charAt(i) == 'S') { + seats.add(i); + } + } + + int length = seats.size(); + if (length < 2 || length % 2 == 1) { + return 0; + } + + long res = 1; + for (int i = 1; i < length - 1; i += 2) { + res = (res * (seats.get(i + 1) - seats.get(i))) % mod; + } + + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int numberOfWays(string corridor) { + int mod = 1'000'000'007; + vector seats; + + for (int i = 0; i < corridor.size(); i++) { + if (corridor[i] == 'S') { + seats.push_back(i); + } + } + + int length = seats.size(); + if (length < 2 || length % 2 == 1) { + return 0; + } + + long long res = 1; + for (int i = 1; i < length - 1; i += 2) { + res = (res * (seats[i + 1] - seats[i])) % mod; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} corridor + * @return {number} + */ + numberOfWays(corridor) { + const mod = 1_000_000_007; + const seats = []; + + for (let i = 0; i < corridor.length; i++) { + if (corridor[i] === 'S') { + seats.push(i); + } + } + + const length = seats.length; + if (length < 2 || length % 2 === 1) { + return 0; + } + + let res = 1; + for (let i = 1; i < length - 1; i += 2) { + res = (res * (seats[i + 1] - seats[i])) % mod; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 5. Combinatorics (Optimal) + +::tabs-start + +```python +class Solution: + def numberOfWays(self, corridor: str) -> int: + mod = 1_000_000_007 + count = 0 + res = 1 + prev = -1 + + for i, c in enumerate(corridor): + if c == 'S': + count += 1 + if count > 2 and count % 2 == 1: + res = (res * (i - prev)) % mod + prev = i + + return res if count >= 2 and count % 2 == 0 else 0 +``` + +```java +public class Solution { + public int numberOfWays(String corridor) { + int mod = 1_000_000_007; + int count = 0, res = 1, prev = -1; + + for (int i = 0; i < corridor.length(); i++) { + if (corridor.charAt(i) == 'S') { + count++; + if (count > 2 && count % 2 == 1) { + res = (int)((res * (long)(i - prev)) % mod); + } + prev = i; + } + } + + return (count >= 2 && count % 2 == 0) ? res : 0; + } +} +``` + +```cpp +class Solution { +public: + int numberOfWays(string corridor) { + int mod = 1'000'000'007, count = 0, res = 1, prev = -1; + + for (int i = 0; i < corridor.size(); i++) { + if (corridor[i] == 'S') { + count++; + if (count > 2 && count % 2 == 1) { + res = (1LL * res * (i - prev)) % mod; + } + prev = i; + } + } + + return (count >= 2 && count % 2 == 0) ? res : 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} corridor + * @return {number} + */ + numberOfWays(corridor) { + const mod = 1_000_000_007; + let count = 0, + res = 1, + prev = -1; + + for (let i = 0; i < corridor.length; i++) { + if (corridor[i] === 'S') { + count++; + if (count > 2 && count % 2 === 1) { + res = (res * (i - prev)) % mod; + } + prev = i; + } + } + + return count >= 2 && count % 2 === 0 ? res : 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/number-of-ways-to-form-a-target-string-given-a-dictionary.md b/articles/number-of-ways-to-form-a-target-string-given-a-dictionary.md index 878690a7c..042982ad9 100644 --- a/articles/number-of-ways-to-form-a-target-string-given-a-dictionary.md +++ b/articles/number-of-ways-to-form-a-target-string-given-a-dictionary.md @@ -13,14 +13,14 @@ class Solution: return 1 if k == m: return 0 - + res = dfs(i, k + 1) for w in words: if w[k] != target[i]: continue res = (res + dfs(i + 1, k + 1)) % mod return res - + return dfs(0, 0) ``` @@ -112,8 +112,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(N ^ m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(N ^ m)$ +- Space complexity: $O(m)$ > Where $N$ is the number of words, $m$ is the length of each word, and $n$ is the length of the $target$ string. @@ -233,7 +233,8 @@ class Solution { */ numWays(words, target) { const MOD = 1e9 + 7; - const n = target.length, m = words[0].length; + const n = target.length, + m = words[0].length; const cnt = Array.from({ length: m }, () => Array(26).fill(0)); for (const word of words) { @@ -250,7 +251,7 @@ class Solution { if (dp[i][k] !== -1) return dp[i][k]; const c = target.charCodeAt(i) - 97; - dp[i][k] = dfs(i, k + 1); // Skip k position + dp[i][k] = dfs(i, k + 1); // Skip k position dp[i][k] = (dp[i][k] + cnt[k][c] * dfs(i + 1, k + 1)) % MOD; return dp[i][k]; }; @@ -264,8 +265,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * (n + N))$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(m * (n + N))$ +- Space complexity: $O(n * m)$ > Where $N$ is the number of words, $m$ is the length of each word, and $n$ is the length of the $target$ string. @@ -374,7 +375,8 @@ class Solution { */ numWays(words, target) { const MOD = 1e9 + 7; - const n = target.length, m = words[0].length; + const n = target.length, + m = words[0].length; const cnt = Array.from({ length: m }, () => Array(26).fill(0)); for (const word of words) { @@ -405,8 +407,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * (n + N))$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(m * (n + N))$ +- Space complexity: $O(n * m)$ > Where $N$ is the number of words, $m$ is the length of each word, and $n$ is the length of the $target$ string. @@ -440,7 +442,7 @@ class Solution: dp[k] = (dp[k] + cnt[k][c] * nxt) % MOD nxt = cur dp[m] = 0 - + return dp[0] ``` @@ -527,7 +529,8 @@ class Solution { */ numWays(words, target) { const MOD = 1e9 + 7; - const n = target.length, m = words[0].length; + const n = target.length, + m = words[0].length; const cnt = Array.from({ length: m }, () => Array(26).fill(0)); for (const word of words) { @@ -562,7 +565,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * (n + N))$ -* Space complexity: $O(m)$ +- Time complexity: $O(m * (n + N))$ +- Space complexity: $O(m)$ -> Where $N$ is the number of words, $m$ is the length of each word, and $n$ is the length of the $target$ string. \ No newline at end of file +> Where $N$ is the number of words, $m$ is the length of each word, and $n$ is the length of the $target$ string. diff --git a/articles/number-of-ways-to-rearrange-sticks-with-k-sticks-visible.md b/articles/number-of-ways-to-rearrange-sticks-with-k-sticks-visible.md index d192c77b6..ede051484 100644 --- a/articles/number-of-ways-to-rearrange-sticks-with-k-sticks-visible.md +++ b/articles/number-of-ways-to-rearrange-sticks-with-k-sticks-visible.md @@ -76,8 +76,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -177,8 +177,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * k)$ -* Space complexity: $O(n * k)$ +- Time complexity: $O(n * k)$ +- Space complexity: $O(n * k)$ > Where $n$ represents the total number of sticks, and $k$ denotes the number of sticks that must be visible from the left side. @@ -267,8 +267,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * k)$ -* Space complexity: $O(n * k)$ +- Time complexity: $O(n * k)$ +- Space complexity: $O(n * k)$ > Where $n$ represents the total number of sticks, and $k$ denotes the number of sticks that must be visible from the left side. @@ -369,7 +369,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * k)$ -* Space complexity: $O(k)$ +- Time complexity: $O(n * k)$ +- Space complexity: $O(k)$ -> Where $n$ represents the total number of sticks, and $k$ denotes the number of sticks that must be visible from the left side. \ No newline at end of file +> Where $n$ represents the total number of sticks, and $k$ denotes the number of sticks that must be visible from the left side. diff --git a/articles/number-of-ways-to-split-array.md b/articles/number-of-ways-to-split-array.md new file mode 100644 index 000000000..ee5a68257 --- /dev/null +++ b/articles/number-of-ways-to-split-array.md @@ -0,0 +1,321 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def waysToSplitArray(self, nums: List[int]) -> int: + n = len(nums) + res = 0 + + for i in range(n - 1): + leftSum = 0 + for j in range(i + 1): + leftSum += nums[j] + + rightSum = 0 + for j in range(i + 1, n): + rightSum += nums[j] + + res += (1 if leftSum >= rightSum else 0) + + return res +``` + +```java +public class Solution { + public int waysToSplitArray(int[] nums) { + int n = nums.length; + int res = 0; + + for (int i = 0; i < n - 1; i++) { + long leftSum = 0; + for (int j = 0; j <= i; j++) { + leftSum += nums[j]; + } + + long rightSum = 0; + for (int j = i + 1; j < n; j++) { + rightSum += nums[j]; + } + + if (leftSum >= rightSum) { + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int waysToSplitArray(vector& nums) { + int n = nums.size(); + int res = 0; + + for (int i = 0; i < n - 1; i++) { + long long leftSum = 0; + for (int j = 0; j <= i; j++) { + leftSum += nums[j]; + } + + long long rightSum = 0; + for (int j = i + 1; j < n; j++) { + rightSum += nums[j]; + } + + if (leftSum >= rightSum) { + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + waysToSplitArray(nums) { + let n = nums.length; + let res = 0; + + for (let i = 0; i < n - 1; i++) { + let leftSum = 0; + for (let j = 0; j <= i; j++) { + leftSum += nums[j]; + } + + let rightSum = 0; + for (let j = i + 1; j < n; j++) { + rightSum += nums[j]; + } + + if (leftSum >= rightSum) { + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Prefix Sum + +::tabs-start + +```python +class Solution: + def waysToSplitArray(self, nums: List[int]) -> int: + n = len(nums) + prefix = [0] * (n + 1) + + for i in range(n): + prefix[i + 1] = prefix[i] + nums[i] + + res = 0 + for i in range(1, n): + left = prefix[i] + right = prefix[n] - prefix[i] + if left >= right: + res += 1 + + return res +``` + +```java +public class Solution { + public int waysToSplitArray(int[] nums) { + int n = nums.length; + long[] prefix = new long[n + 1]; + + for (int i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + nums[i]; + } + + int res = 0; + for (int i = 1; i < n; i++) { + long left = prefix[i]; + long right = prefix[n] - prefix[i]; + if (left >= right) { + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int waysToSplitArray(vector& nums) { + int n = nums.size(); + vector prefix(n + 1, 0); + + for (int i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + nums[i]; + } + + int res = 0; + for (int i = 1; i < n; i++) { + long long left = prefix[i]; + long long right = prefix[n] - prefix[i]; + if (left >= right) { + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + waysToSplitArray(nums) { + const n = nums.length; + const prefix = Array(n + 1).fill(0); + + for (let i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + nums[i]; + } + + let res = 0; + for (let i = 1; i < n; i++) { + const left = prefix[i]; + const right = prefix[n] - prefix[i]; + if (left >= right) { + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Prefix Sum (Optimal) + +::tabs-start + +```python +class Solution: + def waysToSplitArray(self, nums: List[int]) -> int: + right = sum(nums) + left = res = 0 + + for i in range(len(nums) - 1): + left += nums[i] + right -= nums[i] + res += 1 if left >= right else 0 + + return res +``` + +```java +public class Solution { + public int waysToSplitArray(int[] nums) { + long right = 0, left = 0; + for (int num : nums) { + right += num; + } + + int res = 0; + for (int i = 0; i < nums.length - 1; i++) { + left += nums[i]; + right -= nums[i]; + if (left >= right) { + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int waysToSplitArray(vector& nums) { + long long right = 0, left = 0; + for (int num : nums) { + right += num; + } + + int res = 0; + for (int i = 0; i < nums.size() - 1; i++) { + left += nums[i]; + right -= nums[i]; + if (left >= right) { + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + waysToSplitArray(nums) { + let right = nums.reduce((a, b) => a + b, 0); + let left = 0, + res = 0; + + for (let i = 0; i < nums.length - 1; i++) { + left += nums[i]; + right -= nums[i]; + if (left >= right) { + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/number-of-ways-to-stay-in-the-same-place-after-some-steps.md b/articles/number-of-ways-to-stay-in-the-same-place-after-some-steps.md index 2c9577d2a..4a6961689 100644 --- a/articles/number-of-ways-to-stay-in-the-same-place-after-some-steps.md +++ b/articles/number-of-ways-to-stay-in-the-same-place-after-some-steps.md @@ -110,7 +110,9 @@ class Solution { numWays(steps, arrLen) { const MOD = 1e9 + 7; const maxPos = Math.min(steps, arrLen); - const dp = Array.from({ length: maxPos + 1 }, () => Array(steps + 1).fill(-1)); + const dp = Array.from({ length: maxPos + 1 }, () => + Array(steps + 1).fill(-1), + ); const dfs = (i, steps) => { if (steps === 0) return i === 0 ? 1 : 0; @@ -133,8 +135,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * min(n, m))$ -* Space complexity: $O(n * min(n, m))$ +- Time complexity: $O(n * min(n, m))$ +- Space complexity: $O(n * min(n, m))$ > Where $n$ is the number of steps and $m$ is the size of the array. @@ -227,7 +229,9 @@ class Solution { numWays(steps, arrLen) { const MOD = 1e9 + 7; arrLen = Math.min(arrLen, steps); - const dp = Array.from({ length: steps + 1 }, () => Array(arrLen + 1).fill(0)); + const dp = Array.from({ length: steps + 1 }, () => + Array(arrLen + 1).fill(0), + ); dp[0][0] = 1; for (let step = 1; step <= steps; step++) { @@ -252,8 +256,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * min(n, m))$ -* Space complexity: $O(n * min(n, m))$ +- Time complexity: $O(n * min(n, m))$ +- Space complexity: $O(n * min(n, m))$ > Where $n$ is the number of steps and $m$ is the size of the array. @@ -375,8 +379,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * min(n, m))$ -* Space complexity: $O(min(n, m))$ +- Time complexity: $O(n * min(n, m))$ +- Space complexity: $O(min(n, m))$ > Where $n$ is the number of steps and $m$ is the size of the array. @@ -497,7 +501,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * min(n, m))$ -* Space complexity: $O(min(n, m))$ +- Time complexity: $O(n * min(n, m))$ +- Space complexity: $O(min(n, m))$ -> Where $n$ is the number of steps and $m$ is the size of the array. \ No newline at end of file +> Where $n$ is the number of steps and $m$ is the size of the array. diff --git a/articles/number-of-zero-filled-subarrays.md b/articles/number-of-zero-filled-subarrays.md index 266353c04..b57e7262b 100644 --- a/articles/number-of-zero-filled-subarrays.md +++ b/articles/number-of-zero-filled-subarrays.md @@ -68,8 +68,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -137,7 +137,8 @@ class Solution { * @return {number} */ zeroFilledSubarray(nums) { - let res = 0, i = 0; + let res = 0, + i = 0; while (i < nums.length) { let count = 0; while (i < nums.length && nums[i] === 0) { @@ -156,8 +157,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -176,7 +177,7 @@ class Solution: else: count = 0 res += count - + return res ``` @@ -228,7 +229,8 @@ class Solution { * @return {number} */ zeroFilledSubarray(nums) { - let res = 0, count = 0; + let res = 0, + count = 0; for (let num of nums) { if (num === 0) { @@ -248,8 +250,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -315,7 +317,8 @@ class Solution { * @return {number} */ zeroFilledSubarray(nums) { - let res = 0, count = 0; + let res = 0, + count = 0; for (let num of nums) { if (num === 0) { count++; @@ -334,5 +337,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/ones-and-zeroes.md b/articles/ones-and-zeroes.md index 4d3e53b4d..88a3268d7 100644 --- a/articles/ones-and-zeroes.md +++ b/articles/ones-and-zeroes.md @@ -9,16 +9,16 @@ class Solution: for i, s in enumerate(strs): for c in s: arr[i][ord(c) - ord('0')] += 1 - + def dfs(i, m, n): if i == len(strs): return 0 - + res = dfs(i + 1, m, n) if m >= arr[i][0] and n >= arr[i][1]: res = max(res, 1 + dfs(i + 1, m - arr[i][0], n - arr[i][1])) return res - + return dfs(0, m, n) ``` @@ -89,7 +89,7 @@ class Solution { const arr = Array.from({ length: strs.length }, () => [0, 0]); for (let i = 0; i < strs.length; i++) { for (const c of strs[i]) { - arr[i][c - "0"]++; + arr[i][c - '0']++; } } @@ -100,7 +100,10 @@ class Solution { let res = dfs(i + 1, m, n); if (m >= arr[i][0] && n >= arr[i][1]) { - res = Math.max(res, 1 + dfs(i + 1, m - arr[i][0], n - arr[i][1])); + res = Math.max( + res, + 1 + dfs(i + 1, m - arr[i][0], n - arr[i][1]), + ); } return res; }; @@ -114,8 +117,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ N)$ -* Space complexity: $O(N)$ for recursion stack. +- Time complexity: $O(2 ^ N)$ +- Space complexity: $O(N)$ for recursion stack. > Where $N$ represents the number of binary strings, and $m$ and $n$ are the maximum allowable counts of zeros and ones, respectively. @@ -251,12 +254,12 @@ class Solution { const arr = Array.from({ length: strs.length }, () => [0, 0]); for (let i = 0; i < strs.length; i++) { for (const c of strs[i]) { - arr[i][c - "0"]++; + arr[i][c - '0']++; } } const dp = Array.from({ length: strs.length }, () => - Array.from({ length: m + 1 }, () => Array(n + 1).fill(-1)) + Array.from({ length: m + 1 }, () => Array(n + 1).fill(-1)), ); const dfs = (i, m, n) => { @@ -266,7 +269,10 @@ class Solution { let res = dfs(i + 1, m, n); if (m >= arr[i][0] && n >= arr[i][1]) { - res = Math.max(res, 1 + dfs(i + 1, m - arr[i][0], n - arr[i][1])); + res = Math.max( + res, + 1 + dfs(i + 1, m - arr[i][0], n - arr[i][1]), + ); } dp[i][m][n] = res; return res; @@ -281,8 +287,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n * N)$ -* Space complexity: $O(m * n * N)$ +- Time complexity: $O(m * n * N)$ +- Space complexity: $O(m * n * N)$ > Where $N$ represents the number of binary strings, and $m$ and $n$ are the maximum allowable counts of zeros and ones, respectively. @@ -378,14 +384,14 @@ class Solution { * @return {number} */ findMaxForm(strs, m, n) { - const arr = strs.map(s => { - const zeros = s.split('').filter(c => c === '0').length; + const arr = strs.map((s) => { + const zeros = s.split('').filter((c) => c === '0').length; const ones = s.length - zeros; return [zeros, ones]; }); const dp = Array.from({ length: strs.length + 1 }, () => - Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)) + Array.from({ length: m + 1 }, () => Array(n + 1).fill(0)), ); for (let i = 1; i <= strs.length; i++) { @@ -393,7 +399,10 @@ class Solution { for (let k = 0; k <= n; k++) { dp[i][j][k] = dp[i - 1][j][k]; if (j >= arr[i - 1][0] && k >= arr[i - 1][1]) { - dp[i][j][k] = Math.max(dp[i][j][k], 1 + dp[i - 1][j - arr[i - 1][0]][k - arr[i - 1][1]]); + dp[i][j][k] = Math.max( + dp[i][j][k], + 1 + dp[i - 1][j - arr[i - 1][0]][k - arr[i - 1][1]], + ); } } } @@ -408,8 +417,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n * N)$ -* Space complexity: $O(m * n * N)$ +- Time complexity: $O(m * n * N)$ +- Space complexity: $O(m * n * N)$ > Where $N$ represents the number of binary strings, and $m$ and $n$ are the maximum allowable counts of zeros and ones, respectively. @@ -426,14 +435,14 @@ class Solution: for i, s in enumerate(strs): for c in s: arr[i][ord(c) - ord('0')] += 1 - + dp = [[0] * (n + 1) for _ in range(m + 1)] - + for zeros, ones in arr: for j in range(m, zeros - 1, -1): for k in range(n, ones - 1, -1): dp[j][k] = max(dp[j][k], 1 + dp[j - zeros][k - ones]) - + return dp[m][n] ``` @@ -502,7 +511,7 @@ class Solution { const arr = Array.from({ length: strs.length }, () => [0, 0]); for (let i = 0; i < strs.length; i++) { for (const c of strs[i]) { - arr[i][c - "0"]++; + arr[i][c - '0']++; } } @@ -525,7 +534,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n * N)$ -* Space complexity: $O(m * n + N)$ +- Time complexity: $O(m * n * N)$ +- Space complexity: $O(m * n + N)$ -> Where $N$ represents the number of binary strings, and $m$ and $n$ are the maximum allowable counts of zeros and ones, respectively. \ No newline at end of file +> Where $N$ represents the number of binary strings, and $m$ and $n$ are the maximum allowable counts of zeros and ones, respectively. diff --git a/articles/online-stock-span.md b/articles/online-stock-span.md index 9419b89b6..5127d99ae 100644 --- a/articles/online-stock-span.md +++ b/articles/online-stock-span.md @@ -74,12 +74,33 @@ class StockSpanner { } ``` +```csharp +public class StockSpanner { + private List arr; + + public StockSpanner() { + arr = new List(); + } + + public int Next(int price) { + arr.Add(price); + int i = arr.Count - 2; + + while (i >= 0 && arr[i] <= price) { + i--; + } + + return arr.Count - i - 1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ > Where $n$ is the number of function calls. @@ -154,7 +175,10 @@ class StockSpanner { */ next(price) { let span = 1; - while (this.stack.length && this.stack[this.stack.length - 1][0] <= price) { + while ( + this.stack.length && + this.stack[this.stack.length - 1][0] <= price + ) { span += this.stack.pop()[1]; } this.stack.push([price, span]); @@ -163,11 +187,30 @@ class StockSpanner { } ``` +```csharp +public class StockSpanner { + private Stack<(int price, int span)> stack; + + public StockSpanner() { + stack = new Stack<(int price, int span)>(); + } + + public int Next(int price) { + int span = 1; + while (stack.Count > 0 && stack.Peek().price <= price) { + span += stack.Pop().span; + } + stack.Push((price, span)); + return span; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ -> Where $n$ is the number of function calls. \ No newline at end of file +> Where $n$ is the number of function calls. diff --git a/articles/open-the-lock.md b/articles/open-the-lock.md index 6ded4c7ee..e811a94e6 100644 --- a/articles/open-the-lock.md +++ b/articles/open-the-lock.md @@ -109,7 +109,7 @@ private: string next = lock; next[i] = (next[i] - '0' + 1) % 10 + '0'; res.push_back(next); - + next = lock; next[i] = (next[i] - '0' - 1 + 10) % 10 + '0'; res.push_back(next); @@ -128,20 +128,26 @@ class Solution { */ openLock(deadends, target) { const visit = new Set(deadends); - if (visit.has("0000")) return -1; + if (visit.has('0000')) return -1; const children = (lock) => { const res = []; for (let i = 0; i < 4; i++) { - const up = lock.slice(0, i) + ((+lock[i] + 1) % 10) + lock.slice(i + 1); - const down = lock.slice(0, i) + ((+lock[i] - 1 + 10) % 10) + lock.slice(i + 1); + const up = + lock.slice(0, i) + + ((+lock[i] + 1) % 10) + + lock.slice(i + 1); + const down = + lock.slice(0, i) + + ((+lock[i] - 1 + 10) % 10) + + lock.slice(i + 1); res.push(up, down); } return res; }; - const queue = new Queue([["0000", 0]]); - visit.add("0000"); + const queue = new Queue([['0000', 0]]); + visit.add('0000'); while (!queue.isEmpty()) { const [lock, turns] = queue.pop(); @@ -159,12 +165,50 @@ class Solution { } ``` +```csharp +public class Solution { + public int OpenLock(string[] deadends, string target) { + var dead = new HashSet(deadends); + if (dead.Contains("0000")) return -1; + + List Children(string lockStr) { + var res = new List(); + for (int i = 0; i < 4; i++) { + int digit = lockStr[i] - '0'; + string up = lockStr.Substring(0, i) + ((digit + 1) % 10) + lockStr.Substring(i + 1); + string down = lockStr.Substring(0, i) + ((digit + 9) % 10) + lockStr.Substring(i + 1); + res.Add(up); + res.Add(down); + } + return res; + } + + var q = new Queue<(string, int)>(); + q.Enqueue(("0000", 0)); + var visited = new HashSet(dead); + + while (q.Count > 0) { + var (lockStr, turns) = q.Dequeue(); + if (lockStr == target) return turns; + foreach (var child in Children(lockStr)) { + if (!visited.Contains(child)) { + visited.Add(child); + q.Enqueue((child, turns + 1)); + } + } + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(d ^ n + m)$ -* Space complexity: $O(d ^ n)$ +- Time complexity: $O(d ^ n + m)$ +- Space complexity: $O(d ^ n)$ > Where $d$ is the number of digits $(0 - 9)$, $n$ is the number of wheels $(4)$, and $m$ is the number of deadends. @@ -183,11 +227,11 @@ class Solution: visit = set(deadends) if "0000" in visit: return -1 - + q = deque(["0000"]) visit.add("0000") steps = 0 - + while q: steps += 1 for _ in range(len(q)): @@ -283,13 +327,13 @@ class Solution { * @return {number} */ openLock(deadends, target) { - if (target === "0000") return 0; + if (target === '0000') return 0; const visit = new Set(deadends); - if (visit.has("0000")) return -1; + if (visit.has('0000')) return -1; - const q = new Queue(["0000"]); - visit.add("0000"); + const q = new Queue(['0000']); + visit.add('0000'); let steps = 0; while (!q.isEmpty()) { @@ -299,7 +343,8 @@ class Solution { for (let j = 0; j < 4; j++) { for (let move of [1, -1]) { const digit = (parseInt(lock[j]) + move + 10) % 10; - const nextLock = lock.slice(0, j) + digit + lock.slice(j + 1); + const nextLock = + lock.slice(0, j) + digit + lock.slice(j + 1); if (visit.has(nextLock)) continue; if (nextLock === target) return steps; q.push(nextLock); @@ -313,12 +358,48 @@ class Solution { } ``` +```csharp +public class Solution { + public int OpenLock(string[] deadends, string target) { + if (target == "0000") return 0; + + var visited = new HashSet(deadends); + if (visited.Contains("0000")) return -1; + + var q = new Queue(); + q.Enqueue("0000"); + visited.Add("0000"); + int steps = 0; + + while (q.Count > 0) { + steps++; + int size = q.Count; + for (int i = 0; i < size; i++) { + string lockStr = q.Dequeue(); + for (int j = 0; j < 4; j++) { + foreach (int move in new int[] {1, -1}) { + int digit = (lockStr[j] - '0' + move + 10) % 10; + string nextLock = lockStr.Substring(0, j) + digit.ToString() + lockStr.Substring(j + 1); + if (visited.Contains(nextLock)) continue; + if (nextLock == target) return steps; + q.Enqueue(nextLock); + visited.Add(nextLock); + } + } + } + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(d ^ n + m)$ -* Space complexity: $O(d ^ n)$ +- Time complexity: $O(d ^ n + m)$ +- Space complexity: $O(d ^ n)$ > Where $d$ is the number of digits $(0 - 9)$, $n$ is the number of wheels $(4)$, and $m$ is the number of deadends. @@ -337,7 +418,7 @@ class Solution: visit = set(deadends) if "0000" in visit: return -1 - + begin = {"0000"} end = {target} steps = 0 @@ -345,7 +426,7 @@ class Solution: while begin and end: if len(begin) > len(end): begin, end = end, begin - + steps += 1 temp = set() for lock in begin: @@ -353,7 +434,7 @@ class Solution: for j in [-1, 1]: digit = str((int(lock[i]) + j + 10) % 10) nextLock = lock[:i] + digit + lock[i+1:] - + if nextLock in end: return steps if nextLock in visit: @@ -414,7 +495,7 @@ class Solution { public: int openLock(vector& deadends, string target) { if (target == "0000") return 0; - + unordered_set visit(deadends.begin(), deadends.end()); if (visit.count("0000")) return -1; @@ -455,12 +536,12 @@ class Solution { * @return {number} */ openLock(deadends, target) { - if (target === "0000") return 0; + if (target === '0000') return 0; const visit = new Set(deadends); - if (visit.has("0000")) return -1; + if (visit.has('0000')) return -1; - let begin = new Set(["0000"]); + let begin = new Set(['0000']); let end = new Set([target]); let steps = 0; @@ -474,7 +555,8 @@ class Solution { for (let i = 0; i < 4; i++) { for (const j of [-1, 1]) { const digit = (parseInt(lock[i]) + j + 10) % 10; - const nextLock = lock.slice(0, i) + digit + lock.slice(i + 1); + const nextLock = + lock.slice(0, i) + digit + lock.slice(i + 1); if (end.has(nextLock)) return steps; if (visit.has(nextLock)) continue; @@ -491,11 +573,56 @@ class Solution { } ``` +```csharp +public class Solution { + public int OpenLock(string[] deadends, string target) { + if (target == "0000") return 0; + + var visit = new HashSet(deadends); + if (visit.Contains("0000")) return -1; + + var begin = new HashSet { "0000" }; + var end = new HashSet { target }; + int steps = 0; + + while (begin.Count > 0 && end.Count > 0) { + if (begin.Count > end.Count) { + var tempSet = begin; + begin = end; + end = tempSet; + } + + var temp = new HashSet(); + steps++; + + foreach (var lockStr in begin) { + for (int i = 0; i < 4; i++) { + foreach (int j in new int[] { -1, 1 }) { + int digit = (lockStr[i] - '0' + j + 10) % 10; + string nextLock = lockStr.Substring(0, i) + digit.ToString() + lockStr.Substring(i + 1); + + if (end.Contains(nextLock)) return steps; + if (visit.Contains(nextLock)) continue; + + visit.Add(nextLock); + temp.Add(nextLock); + } + } + } + + begin = temp; + } + + return -1; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(d ^ n + m)$ -* Space complexity: $O(d ^ n)$ +- Time complexity: $O(d ^ n + m)$ +- Space complexity: $O(d ^ n)$ -> Where $d$ is the number of digits $(0 - 9)$, $n$ is the number of wheels $(4)$, and $m$ is the number of deadends. \ No newline at end of file +> Where $d$ is the number of digits $(0 - 9)$, $n$ is the number of wheels $(4)$, and $m$ is the number of deadends. diff --git a/articles/operations-on-tree.md b/articles/operations-on-tree.md new file mode 100644 index 000000000..1cac6f328 --- /dev/null +++ b/articles/operations-on-tree.md @@ -0,0 +1,806 @@ +## 1. Depth First Search + +::tabs-start + +```python +class LockingTree: + + def __init__(self, parent: List[int]): + self.parent = parent + self.child = [[] for _ in range(len(parent))] + self.locked = [0] * len(parent) + for node in range(1, len(parent)): + self.child[parent[node]].append(node) + + def lock(self, num: int, user: int) -> bool: + if self.locked[num]: + return False + self.locked[num] = user + return True + + def unlock(self, num: int, user: int) -> bool: + if self.locked[num] != user: + return False + self.locked[num] = 0 + return True + + def upgrade(self, num: int, user: int) -> bool: + node = num + while node != -1: + if self.locked[node]: + return False + node = self.parent[node] + + def dfs(node): + lockedCount = 0 + if self.locked[node]: + lockedCount += 1 + self.locked[node] = 0 + + for nei in self.child[node]: + lockedCount += dfs(nei) + return lockedCount + + if dfs(num) > 0: + self.locked[num] = user + return True + return False +``` + +```java +public class LockingTree { + private int[] parent; + private List[] child; + private int[] locked; + + public LockingTree(int[] parent) { + this.parent = parent; + int n = parent.length; + child = new ArrayList[n]; + locked = new int[n]; + + for (int i = 0; i < n; i++) { + child[i] = new ArrayList<>(); + } + for (int node = 1; node < n; node++) { + child[parent[node]].add(node); + } + } + + public boolean lock(int num, int user) { + if (locked[num] != 0) { + return false; + } + locked[num] = user; + return true; + } + + public boolean unlock(int num, int user) { + if (locked[num] != user) { + return false; + } + locked[num] = 0; + return true; + } + + public boolean upgrade(int num, int user) { + int node = num; + while (node != -1) { + if (locked[node] != 0) { + return false; + } + node = parent[node]; + } + + int lockedCount = dfs(num); + if (lockedCount > 0) { + locked[num] = user; + return true; + } + return false; + } + + private int dfs(int node) { + int lockedCount = 0; + if (locked[node] != 0) { + lockedCount++; + locked[node] = 0; + } + for (int nei : child[node]) { + lockedCount += dfs(nei); + } + return lockedCount; + } +} +``` + +```cpp +class LockingTree { +private: + vector parent; + vector> child; + vector locked; + +public: + LockingTree(vector& parent) : parent(parent), locked(parent.size()) { + int n = parent.size(); + child.resize(n); + for (int node = 1; node < n; node++) { + child[parent[node]].push_back(node); + } + } + + bool lock(int num, int user) { + if (locked[num]) { + return false; + } + locked[num] = user; + return true; + } + + bool unlock(int num, int user) { + if (locked[num] != user) { + return false; + } + locked[num] = 0; + return true; + } + + bool upgrade(int num, int user) { + int node = num; + while (node != -1) { + if (locked[node]) { + return false; + } + node = parent[node]; + } + + int lockedCount = dfs(num); + if (lockedCount > 0) { + locked[num] = user; + return true; + } + return false; + } + +private: + int dfs(int node) { + int lockedCount = 0; + if (locked[node]) { + lockedCount++; + locked[node] = 0; + } + for (int& nei : child[node]) { + lockedCount += dfs(nei); + } + return lockedCount; + } +}; +``` + +```javascript +class LockingTree { + /** + * @constructor + * @param {number[]} parent + */ + constructor(parent) { + this.parent = parent; + this.child = Array.from({ length: parent.length }, () => []); + this.locked = new Array(parent.length).fill(0); + + for (let node = 1; node < parent.length; node++) { + this.child[parent[node]].push(node); + } + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + lock(num, user) { + if (this.locked[num] !== 0) { + return false; + } + this.locked[num] = user; + return true; + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + unlock(num, user) { + if (this.locked[num] !== user) { + return false; + } + this.locked[num] = 0; + return true; + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + upgrade(num, user) { + let node = num; + while (node !== -1) { + if (this.locked[node] !== 0) { + return false; + } + node = this.parent[node]; + } + + const dfs = (node) => { + let lockedCount = 0; + if (this.locked[node] !== 0) { + lockedCount++; + this.locked[node] = 0; + } + for (let nei of this.child[node]) { + lockedCount += dfs(nei); + } + return lockedCount; + }; + + if (dfs(num) > 0) { + this.locked[num] = user; + return true; + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(n)$ time for initialization. + - $O(1)$ time for each $lock()$ and $unlock()$ function call. + - $O(n)$ time for each $upgrade()$ function call. +- Space complexity: $O(n)$ + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class LockingTree: + + def __init__(self, parent: List[int]): + self.parent = parent + self.child = [[] for _ in range(len(parent))] + self.locked = [0] * len(parent) + for node in range(1, len(parent)): + self.child[parent[node]].append(node) + + def lock(self, num: int, user: int) -> bool: + if self.locked[num]: + return False + self.locked[num] = user + return True + + def unlock(self, num: int, user: int) -> bool: + if self.locked[num] != user: + return False + self.locked[num] = 0 + return True + + def upgrade(self, num: int, user: int) -> bool: + node = num + while node != -1: + if self.locked[node]: + return False + node = self.parent[node] + + lockedCount, q = 0, deque([num]) + while q: + node = q.popleft() + if self.locked[node]: + self.locked[node] = 0 + lockedCount += 1 + q.extend(self.child[node]) + + if lockedCount: + self.locked[num] = user + return True + return False +``` + +```java +public class LockingTree { + private int[] parent; + private List[] child; + private int[] locked; + + public LockingTree(int[] parent) { + this.parent = parent; + int n = parent.length; + child = new ArrayList[n]; + locked = new int[n]; + + for (int i = 0; i < n; i++) { + child[i] = new ArrayList<>(); + } + for (int node = 1; node < n; node++) { + child[parent[node]].add(node); + } + } + + public boolean lock(int num, int user) { + if (locked[num] != 0) { + return false; + } + locked[num] = user; + return true; + } + + public boolean unlock(int num, int user) { + if (locked[num] != user) { + return false; + } + locked[num] = 0; + return true; + } + + public boolean upgrade(int num, int user) { + int node = num; + while (node != -1) { + if (locked[node] != 0) { + return false; + } + node = parent[node]; + } + + int lockedCount = 0; + Queue q = new LinkedList<>(); + q.offer(num); + + while (!q.isEmpty()) { + node = q.poll(); + if (locked[node] != 0) { + locked[node] = 0; + lockedCount++; + } + q.addAll(child[node]); + } + + if (lockedCount > 0) { + locked[num] = user; + return true; + } + return false; + } +} +``` + +```cpp +class LockingTree { +private: + vector parent; + vector> child; + vector locked; + +public: + LockingTree(vector& parent) : parent(parent), locked(parent.size()) { + int n = parent.size(); + child.resize(n); + for (int node = 1; node < n; node++) { + child[parent[node]].push_back(node); + } + } + + bool lock(int num, int user) { + if (locked[num]) { + return false; + } + locked[num] = user; + return true; + } + + bool unlock(int num, int user) { + if (locked[num] != user) { + return false; + } + locked[num] = 0; + return true; + } + + bool upgrade(int num, int user) { + int node = num; + while (node != -1) { + if (locked[node]) { + return false; + } + node = parent[node]; + } + + int lockedCount = 0; + queue q; + q.push(num); + + while (!q.empty()) { + node = q.front(); q.pop(); + if (locked[node]) { + locked[node] = 0; + lockedCount++; + } + for (int nei : child[node]) { + q.push(nei); + } + } + + if (lockedCount > 0) { + locked[num] = user; + return true; + } + return false; + } +}; +``` + +```javascript +class LockingTree { + /** + * @constructor + * @param {number[]} parent + */ + constructor(parent) { + this.parent = parent; + this.child = Array.from({ length: parent.length }, () => []); + this.locked = new Array(parent.length).fill(0); + + for (let node = 1; node < parent.length; node++) { + this.child[parent[node]].push(node); + } + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + lock(num, user) { + if (this.locked[num] !== 0) { + return false; + } + this.locked[num] = user; + return true; + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + unlock(num, user) { + if (this.locked[num] !== user) { + return false; + } + this.locked[num] = 0; + return true; + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + upgrade(num, user) { + let node = num; + while (node !== -1) { + if (this.locked[node] !== 0) { + return false; + } + node = this.parent[node]; + } + + let lockedCount = 0; + const q = new Queue([num]); + + while (!q.isEmpty()) { + node = q.pop(); + if (this.locked[node]) { + this.locked[node] = 0; + lockedCount++; + } + for (let nei of this.child[node]) { + q.push(nei); + } + } + + if (lockedCount > 0) { + this.locked[num] = user; + return true; + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(n)$ time for initialization. + - $O(1)$ time for each $lock()$ and $unlock()$ function call. + - $O(n)$ time for each $upgrade()$ function call. +- Space complexity: $O(n)$ + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +class LockingTree: + + def __init__(self, parent: List[int]): + self.parent = parent + self.child = [[] for _ in range(len(parent))] + self.locked = [0] * len(parent) + for node in range(1, len(parent)): + self.child[parent[node]].append(node) + + def lock(self, num: int, user: int) -> bool: + if self.locked[num]: + return False + self.locked[num] = user + return True + + def unlock(self, num: int, user: int) -> bool: + if self.locked[num] != user: + return False + self.locked[num] = 0 + return True + + def upgrade(self, num: int, user: int) -> bool: + node = num + while node != -1: + if self.locked[node]: + return False + node = self.parent[node] + + lockedCount, stack = 0, [num] + while stack: + node = stack.pop() + if self.locked[node]: + self.locked[node] = 0 + lockedCount += 1 + stack.extend(self.child[node]) + + if lockedCount: + self.locked[num] = user + return True + return False +``` + +```java +public class LockingTree { + private int[] parent; + private List[] child; + private int[] locked; + + public LockingTree(int[] parent) { + this.parent = parent; + int n = parent.length; + child = new ArrayList[n]; + locked = new int[n]; + + for (int i = 0; i < n; i++) { + child[i] = new ArrayList<>(); + } + for (int node = 1; node < n; node++) { + child[parent[node]].add(node); + } + } + + public boolean lock(int num, int user) { + if (locked[num] != 0) { + return false; + } + locked[num] = user; + return true; + } + + public boolean unlock(int num, int user) { + if (locked[num] != user) { + return false; + } + locked[num] = 0; + return true; + } + + public boolean upgrade(int num, int user) { + int node = num; + while (node != -1) { + if (locked[node] != 0) { + return false; + } + node = parent[node]; + } + + int lockedCount = 0; + Stack stack = new Stack<>(); + stack.push(num); + + while (!stack.isEmpty()) { + node = stack.pop(); + if (locked[node] != 0) { + locked[node] = 0; + lockedCount++; + } + for (int nei : child[node]) { + stack.push(nei); + } + } + + if (lockedCount > 0) { + locked[num] = user; + return true; + } + return false; + } +} +``` + +```cpp +class LockingTree { +private: + vector parent; + vector> child; + vector locked; + +public: + LockingTree(vector& parent) : parent(parent), locked(parent.size()) { + int n = parent.size(); + child.resize(n); + for (int node = 1; node < n; node++) { + child[parent[node]].push_back(node); + } + } + + bool lock(int num, int user) { + if (locked[num]) { + return false; + } + locked[num] = user; + return true; + } + + bool unlock(int num, int user) { + if (locked[num] != user) { + return false; + } + locked[num] = 0; + return true; + } + + bool upgrade(int num, int user) { + int node = num; + while (node != -1) { + if (locked[node]) { + return false; + } + node = parent[node]; + } + + int lockedCount = 0; + stack stk; + stk.push(num); + + while (!stk.empty()) { + node = stk.top(); stk.pop(); + if (locked[node]) { + locked[node] = 0; + lockedCount++; + } + for (int& nei : child[node]) { + stk.push(nei); + } + } + + if (lockedCount > 0) { + locked[num] = user; + return true; + } + return false; + } +}; +``` + +```javascript +class LockingTree { + /** + * @constructor + * @param {number[]} parent + */ + constructor(parent) { + this.parent = parent; + this.child = Array.from({ length: parent.length }, () => []); + this.locked = new Array(parent.length).fill(0); + + for (let node = 1; node < parent.length; node++) { + this.child[parent[node]].push(node); + } + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + lock(num, user) { + if (this.locked[num] !== 0) { + return false; + } + this.locked[num] = user; + return true; + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + unlock(num, user) { + if (this.locked[num] !== user) { + return false; + } + this.locked[num] = 0; + return true; + } + + /** + * @param {number} num + * @param {number} user + * @return {boolean} + */ + upgrade(num, user) { + let node = num; + while (node !== -1) { + if (this.locked[node] !== 0) { + return false; + } + node = this.parent[node]; + } + + let lockedCount = 0; + let stack = [num]; + + while (stack.length) { + node = stack.pop(); + if (this.locked[node]) { + this.locked[node] = 0; + lockedCount++; + } + stack.push(...this.child[node]); + } + + if (lockedCount > 0) { + this.locked[num] = user; + return true; + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(n)$ time for initialization. + - $O(1)$ time for each $lock()$ and $unlock()$ function call. + - $O(n)$ time for each $upgrade()$ function call. +- Space complexity: $O(n)$ diff --git a/articles/optimal-partition-of-string.md b/articles/optimal-partition-of-string.md index c4d89ab77..797474a48 100644 --- a/articles/optimal-partition-of-string.md +++ b/articles/optimal-partition-of-string.md @@ -75,8 +75,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. --- @@ -145,7 +145,8 @@ class Solution { */ partitionString(s) { const lastIdx = Array(26).fill(-1); - let res = 1, start = 0; + let res = 1, + start = 0; for (let i = 0; i < s.length; i++) { const j = s.charCodeAt(i) - 97; if (lastIdx[j] >= start) { @@ -163,8 +164,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. --- @@ -228,14 +229,15 @@ class Solution { * @return {number} */ partitionString(s) { - let res = 1, mask = 0; + let res = 1, + mask = 0; for (const c of s) { const i = c.charCodeAt(0) - 97; if (mask & (1 << i)) { mask = 0; res++; } - mask |= (1 << i); + mask |= 1 << i; } return res; } @@ -246,5 +248,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/out-of-boundary-paths.md b/articles/out-of-boundary-paths.md index ced7639b1..5a09fb085 100644 --- a/articles/out-of-boundary-paths.md +++ b/articles/out-of-boundary-paths.md @@ -84,9 +84,11 @@ class Solution { if (moves === 0) return 0; return ( - (dfs(r + 1, c, moves - 1) + dfs(r - 1, c, moves - 1)) % MOD + - (dfs(r, c + 1, moves - 1) + dfs(r, c - 1, moves - 1)) % MOD - ) % MOD; + (((dfs(r + 1, c, moves - 1) + dfs(r - 1, c, moves - 1)) % MOD) + + ((dfs(r, c + 1, moves - 1) + dfs(r, c - 1, moves - 1)) % + MOD)) % + MOD + ); }; return dfs(startRow, startColumn, maxMove); @@ -98,8 +100,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(4 ^ N)$ -* Space complexity: $O(N)$ +- Time complexity: $O(4 ^ N)$ +- Space complexity: $O(N)$ > Where $m$ is the number of rows, $n$ is the number of columns, and $N$ is the maximum number of allowed moves. @@ -202,8 +204,8 @@ class Solution { */ findPaths(m, n, maxMove, startRow, startColumn) { const MOD = 1_000_000_007; - const dp = Array.from({ length: m }, () => - Array.from({ length: n }, () => Array(maxMove + 1).fill(-1)) + const dp = Array.from({ length: m }, () => + Array.from({ length: n }, () => Array(maxMove + 1).fill(-1)), ); const dfs = (r, c, moves) => { @@ -211,10 +213,11 @@ class Solution { if (moves === 0) return 0; if (dp[r][c][moves] !== -1) return dp[r][c][moves]; - dp[r][c][moves] = ( - (dfs(r + 1, c, moves - 1) + dfs(r - 1, c, moves - 1)) % MOD + - (dfs(r, c + 1, moves - 1) + dfs(r, c - 1, moves - 1)) % MOD - ) % MOD; + dp[r][c][moves] = + (((dfs(r + 1, c, moves - 1) + dfs(r - 1, c, moves - 1)) % MOD) + + ((dfs(r, c + 1, moves - 1) + dfs(r, c - 1, moves - 1)) % + MOD)) % + MOD; return dp[r][c][moves]; }; @@ -227,8 +230,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n * N)$ -* Space complexity: $O(m * n * N)$ +- Time complexity: $O(m * n * N)$ +- Space complexity: $O(m * n * N)$ > Where $m$ is the number of rows, $n$ is the number of columns, and $N$ is the maximum number of allowed moves. @@ -319,18 +322,18 @@ class Solution { findPaths(m, n, maxMove, startRow, startColumn) { const MOD = 1_000_000_007; const dp = Array.from({ length: m }, () => - Array.from({ length: n }, () => Array(maxMove + 1).fill(0)) + Array.from({ length: n }, () => Array(maxMove + 1).fill(0)), ); for (let moves = 1; moves <= maxMove; moves++) { for (let r = 0; r < m; r++) { for (let c = 0; c < n; c++) { - dp[r][c][moves] = ( - (r > 0 ? dp[r - 1][c][moves - 1] : 1) + - (r < m - 1 ? dp[r + 1][c][moves - 1] : 1) + - (c > 0 ? dp[r][c - 1][moves - 1] : 1) + - (c < n - 1 ? dp[r][c + 1][moves - 1] : 1) - ) % MOD; + dp[r][c][moves] = + ((r > 0 ? dp[r - 1][c][moves - 1] : 1) + + (r < m - 1 ? dp[r + 1][c][moves - 1] : 1) + + (c > 0 ? dp[r][c - 1][moves - 1] : 1) + + (c < n - 1 ? dp[r][c + 1][moves - 1] : 1)) % + MOD; } } } @@ -344,8 +347,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n * N)$ -* Space complexity: $O(m * n * N)$ +- Time complexity: $O(m * n * N)$ +- Space complexity: $O(m * n * N)$ > Where $m$ is the number of rows, $n$ is the number of columns, and $N$ is the maximum number of allowed moves. @@ -519,7 +522,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n * N)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n * N)$ +- Space complexity: $O(m * n)$ -> Where $m$ is the number of rows, $n$ is the number of columns, and $N$ is the maximum number of allowed moves. \ No newline at end of file +> Where $m$ is the number of rows, $n$ is the number of columns, and $N$ is the maximum number of allowed moves. diff --git a/articles/pacific-atlantic-water-flow.md b/articles/pacific-atlantic-water-flow.md index 1b718571a..a34b84a19 100644 --- a/articles/pacific-atlantic-water-flow.md +++ b/articles/pacific-atlantic-water-flow.md @@ -149,10 +149,17 @@ class Solution { * @return {number[][]} */ pacificAtlantic(heights) { - let ROWS = heights.length, COLS = heights[0].length; - let directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; - - let pacific = false, atlantic = false; + let ROWS = heights.length, + COLS = heights[0].length; + let directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; + + let pacific = false, + atlantic = false; const dfs = (r, c, prevVal) => { if (r < 0 || c < 0) { @@ -252,9 +259,9 @@ func pacificAtlantic(heights [][]int) [][]int { rows, cols := len(heights), len(heights[0]) directions := [][]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}} result := make([][]int, 0) - + var pacific, atlantic bool - + var dfs func(r, c int, prevVal int) dfs = func(r, c int, prevVal int) { if r < 0 || c < 0 { @@ -268,10 +275,10 @@ func pacificAtlantic(heights [][]int) [][]int { if heights[r][c] > prevVal { return } - + tmp := heights[r][c] heights[r][c] = int(^uint(0) >> 1) - + for _, dir := range directions { dfs(r + dir[0], c + dir[1], tmp) if pacific && atlantic { @@ -280,7 +287,7 @@ func pacificAtlantic(heights [][]int) [][]int { } heights[r][c] = tmp } - + for r := 0; r < rows; r++ { for c := 0; c < cols; c++ { pacific = false @@ -291,7 +298,7 @@ func pacificAtlantic(heights [][]int) [][]int { } } } - + return result } ``` @@ -306,12 +313,12 @@ class Solution { intArrayOf(0, 1), intArrayOf(0, -1) ) - + fun pacificAtlantic(heights: Array): List> { val rows = heights.size val cols = heights[0].size val result = mutableListOf>() - + fun dfs(r: Int, c: Int, prevVal: Int) { when { r < 0 || c < 0 -> { @@ -324,17 +331,17 @@ class Solution { } heights[r][c] > prevVal -> return } - + val tmp = heights[r][c] heights[r][c] = Int.MAX_VALUE - + for (dir in directions) { dfs(r + dir[0], c + dir[1], tmp) if (pacific && atlantic) break } heights[r][c] = tmp } - + for (r in 0 until rows) { for (c in 0 until cols) { pacific = false @@ -345,18 +352,69 @@ class Solution { } } } - + return result } } ``` +```swift +class Solution { + func pacificAtlantic(_ heights: [[Int]]) -> [[Int]] { + var heights = heights + let ROWS = heights.count + let COLS = heights[0].count + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + + var pacific = false + var atlantic = false + + func dfs(_ r: Int, _ c: Int, _ prevVal: Int) { + if r < 0 || c < 0 { + pacific = true + return + } + if r >= ROWS || c >= COLS { + atlantic = true + return + } + if heights[r][c] > prevVal { + return + } + + let tmp = heights[r][c] + heights[r][c] = Int.max + for dir in directions { + dfs(r + dir.0, c + dir.1, tmp) + if pacific && atlantic { + break + } + } + heights[r][c] = tmp + } + + var res = [[Int]]() + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns. @@ -373,9 +431,9 @@ class Solution: pac, atl = set(), set() def dfs(r, c, visit, prevHeight): - if ((r, c) in visit or - r < 0 or c < 0 or - r == ROWS or c == COLS or + if ((r, c) in visit or + r < 0 or c < 0 or + r == ROWS or c == COLS or heights[r][c] < prevHeight ): return @@ -403,7 +461,7 @@ class Solution: ```java public class Solution { - private int[][] directions = {{1, 0}, {-1, 0}, + private int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; public List> pacificAtlantic(int[][] heights) { int ROWS = heights.length, COLS = heights[0].length; @@ -434,8 +492,8 @@ public class Solution { ocean[r][c] = true; for (int[] d : directions) { int nr = r + d[0], nc = c + d[1]; - if (nr >= 0 && nr < heights.length && - nc >= 0 && nc < heights[0].length && + if (nr >= 0 && nr < heights.length && + nc >= 0 && nc < heights[0].length && !ocean[nr][nc] && heights[nr][nc] >= heights[r][c]) { dfs(nr, nc, ocean, heights); } @@ -446,7 +504,7 @@ public class Solution { ```cpp class Solution { - vector> directions = {{1, 0}, {-1, 0}, + vector> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; public: vector> pacificAtlantic(vector>& heights) { @@ -479,8 +537,8 @@ private: ocean[r][c] = true; for (auto [dr, dc] : directions) { int nr = r + dr, nc = c + dc; - if (nr >= 0 && nr < heights.size() && - nc >= 0 && nc < heights[0].size() && + if (nr >= 0 && nr < heights.size() && + nc >= 0 && nc < heights[0].size() && !ocean[nr][nc] && heights[nr][nc] >= heights[r][c]) { dfs(nr, nc, ocean, heights); } @@ -496,24 +554,34 @@ class Solution { * @return {number[][]} */ pacificAtlantic(heights) { - let ROWS = heights.length, COLS = heights[0].length; - let pac = Array.from({ length: ROWS }, () => - Array(COLS).fill(false)); - let atl = Array.from({ length: ROWS }, () => - Array(COLS).fill(false)); + let ROWS = heights.length, + COLS = heights[0].length; + let pac = Array.from({ length: ROWS }, () => Array(COLS).fill(false)); + let atl = Array.from({ length: ROWS }, () => Array(COLS).fill(false)); const dfs = (r, c, ocean) => { ocean[r][c] = true; - let directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; + let directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; for (let [dr, dc] of directions) { - let nr = r + dr, nc = c + dc; - if (nr >= 0 && nr < ROWS && nc >= 0 && - nc < COLS && !ocean[nr][nc] && - heights[nr][nc] >= heights[r][c]) { + let nr = r + dr, + nc = c + dc; + if ( + nr >= 0 && + nr < ROWS && + nc >= 0 && + nc < COLS && + !ocean[nr][nc] && + heights[nr][nc] >= heights[r][c] + ) { dfs(nr, nc, ocean); } } - } + }; for (let c = 0; c < COLS; c++) { dfs(0, c, pac); @@ -539,9 +607,9 @@ class Solution { ```csharp public class Solution { - private int[][] directions = new int[][] { - new int[] { 1, 0 }, new int[] { -1, 0 }, - new int[] { 0, 1 }, new int[] { 0, -1 } + private int[][] directions = new int[][] { + new int[] { 1, 0 }, new int[] { -1, 0 }, + new int[] { 0, 1 }, new int[] { 0, -1 } }; public List> PacificAtlantic(int[][] heights) { int ROWS = heights.Length, COLS = heights[0].Length; @@ -572,8 +640,8 @@ public class Solution { ocean[r, c] = true; foreach (var dir in directions) { int nr = r + dir[0], nc = c + dir[1]; - if (nr >= 0 && nr < heights.Length && nc >= 0 && - nc < heights[0].Length && !ocean[nr, nc] && + if (nr >= 0 && nr < heights.Length && nc >= 0 && + nc < heights[0].Length && !ocean[nr, nc] && heights[nr][nc] >= heights[r][c]) { Dfs(nr, nc, ocean, heights); } @@ -587,7 +655,7 @@ func pacificAtlantic(heights [][]int) [][]int { rows, cols := len(heights), len(heights[0]) pac := make(map[[2]int]bool) atl := make(map[[2]int]bool) - + var dfs func(r, c int, visit map[[2]int]bool, prevHeight int) dfs = func(r, c int, visit map[[2]int]bool, prevHeight int) { coord := [2]int{r, c} @@ -597,25 +665,25 @@ func pacificAtlantic(heights [][]int) [][]int { heights[r][c] < prevHeight { return } - + visit[coord] = true - + dfs(r+1, c, visit, heights[r][c]) dfs(r-1, c, visit, heights[r][c]) dfs(r, c+1, visit, heights[r][c]) dfs(r, c-1, visit, heights[r][c]) } - + for c := 0; c < cols; c++ { dfs(0, c, pac, heights[0][c]) dfs(rows-1, c, atl, heights[rows-1][c]) } - + for r := 0; r < rows; r++ { dfs(r, 0, pac, heights[r][0]) dfs(r, cols-1, atl, heights[r][cols-1]) } - + result := make([][]int, 0) for r := 0; r < rows; r++ { for c := 0; c < cols; c++ { @@ -625,7 +693,7 @@ func pacificAtlantic(heights [][]int) [][]int { } } } - + return result } ``` @@ -637,7 +705,7 @@ class Solution { val cols = heights[0].size val pac = HashSet>() val atl = HashSet>() - + fun dfs(r: Int, c: Int, visit: HashSet>, prevHeight: Int) { val coord = r to c if (coord in visit || @@ -647,25 +715,25 @@ class Solution { ) { return } - + visit.add(coord) - + dfs(r + 1, c, visit, heights[r][c]) dfs(r - 1, c, visit, heights[r][c]) dfs(r, c + 1, visit, heights[r][c]) dfs(r, c - 1, visit, heights[r][c]) } - + for (c in 0 until cols) { dfs(0, c, pac, heights[0][c]) dfs(rows - 1, c, atl, heights[rows - 1][c]) } - + for (r in 0 until rows) { dfs(r, 0, pac, heights[r][0]) dfs(r, cols - 1, atl, heights[r][cols - 1]) } - + return (0 until rows).flatMap { r -> (0 until cols).mapNotNull { c -> if ((r to c) in pac && (r to c) in atl) { @@ -677,12 +745,55 @@ class Solution { } ``` +```swift +class Solution { + func pacificAtlantic(_ heights: [[Int]]) -> [[Int]] { + let ROWS = heights.count + let COLS = heights[0].count + var pac = Set<[Int]>() + var atl = Set<[Int]>() + + func dfs(_ r: Int, _ c: Int, _ visit: inout Set<[Int]>, _ prevHeight: Int) { + if (visit.contains([r, c]) || r < 0 || c < 0 || r == ROWS || + c == COLS || heights[r][c] < prevHeight) { + return + } + visit.insert([r, c]) + dfs(r + 1, c, &visit, heights[r][c]) + dfs(r - 1, c, &visit, heights[r][c]) + dfs(r, c + 1, &visit, heights[r][c]) + dfs(r, c - 1, &visit, heights[r][c]) + } + + for c in 0.. Where $m$ is the number of rows and $n$ is the number of columns. @@ -707,8 +818,8 @@ class Solution: ocean[r][c] = True for dr, dc in directions: nr, nc = r + dr, c + dc - if (0 <= nr < ROWS and 0 <= nc < COLS and - not ocean[nr][nc] and + if (0 <= nr < ROWS and 0 <= nc < COLS and + not ocean[nr][nc] and heights[nr][nc] >= heights[r][c] ): q.append((nr, nc)) @@ -722,7 +833,7 @@ class Solution: for r in range(ROWS): pacific.append((r, 0)) atlantic.append((r, COLS - 1)) - + bfs(pacific, pac) bfs(atlantic, atl) @@ -741,10 +852,10 @@ public class Solution { int ROWS = heights.length, COLS = heights[0].length; boolean[][] pac = new boolean[ROWS][COLS]; boolean[][] atl = new boolean[ROWS][COLS]; - + Queue pacQueue = new LinkedList<>(); Queue atlQueue = new LinkedList<>(); - + for (int c = 0; c < COLS; c++) { pacQueue.add(new int[]{0, c}); atlQueue.add(new int[]{ROWS - 1, c}); @@ -753,10 +864,10 @@ public class Solution { pacQueue.add(new int[]{r, 0}); atlQueue.add(new int[]{r, COLS - 1}); } - + bfs(pacQueue, pac, heights); bfs(atlQueue, atl, heights); - + List> res = new ArrayList<>(); for (int r = 0; r < ROWS; r++) { for (int c = 0; c < COLS; c++) { @@ -767,7 +878,7 @@ public class Solution { } return res; } - + private void bfs(Queue q, boolean[][] ocean, int[][] heights) { while (!q.isEmpty()) { int[] cur = q.poll(); @@ -775,8 +886,8 @@ public class Solution { ocean[r][c] = true; for (int[] d : directions) { int nr = r + d[0], nc = c + d[1]; - if (nr >= 0 && nr < heights.length && nc >= 0 && - nc < heights[0].length && !ocean[nr][nc] && + if (nr >= 0 && nr < heights.length && nc >= 0 && + nc < heights[0].length && !ocean[nr][nc] && heights[nr][nc] >= heights[r][c]) { q.add(new int[]{nr, nc}); } @@ -788,16 +899,16 @@ public class Solution { ```cpp class Solution { - vector> directions = {{1, 0}, {-1, 0}, + vector> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; public: vector> pacificAtlantic(vector>& heights) { int ROWS = heights.size(), COLS = heights[0].size(); vector> pac(ROWS, vector(COLS, false)); vector> atl(ROWS, vector(COLS, false)); - + queue> pacQueue, atlQueue; - + for (int c = 0; c < COLS; ++c) { pacQueue.push({0, c}); atlQueue.push({ROWS - 1, c}); @@ -822,15 +933,15 @@ public: } private: - void bfs(queue>& q, vector>& ocean, + void bfs(queue>& q, vector>& ocean, vector>& heights) { while (!q.empty()) { auto [r, c] = q.front(); q.pop(); ocean[r][c] = true; for (auto [dr, dc] : directions) { int nr = r + dr, nc = c + dc; - if (nr >= 0 && nr < heights.size() && nc >= 0 && - nc < heights[0].size() && !ocean[nr][nc] && + if (nr >= 0 && nr < heights.size() && nc >= 0 && + nc < heights[0].size() && !ocean[nr][nc] && heights[nr][nc] >= heights[r][c]) { q.push({nr, nc}); } @@ -847,14 +958,18 @@ class Solution { * @return {number[][]} */ pacificAtlantic(heights) { - let ROWS = heights.length, COLS = heights[0].length; - let directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; - let pac = Array.from({ length: ROWS }, () => - Array(COLS).fill(false)); - let atl = Array.from({ length: ROWS }, () => - Array(COLS).fill(false)); - - let pacQueue = new Queue() + let ROWS = heights.length, + COLS = heights[0].length; + let directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; + let pac = Array.from({ length: ROWS }, () => Array(COLS).fill(false)); + let atl = Array.from({ length: ROWS }, () => Array(COLS).fill(false)); + + let pacQueue = new Queue(); let atlQueue = new Queue(); for (let c = 0; c < COLS; c++) { pacQueue.push([0, c]); @@ -870,15 +985,21 @@ class Solution { let [r, c] = queue.pop(); ocean[r][c] = true; for (let [dr, dc] of directions) { - let nr = r + dr, nc = c + dc; - if (nr >= 0 && nr < ROWS && nc >= 0 && - nc < COLS && !ocean[nr][nc] && - heights[nr][nc] >= heights[r][c]) { + let nr = r + dr, + nc = c + dc; + if ( + nr >= 0 && + nr < ROWS && + nc >= 0 && + nc < COLS && + !ocean[nr][nc] && + heights[nr][nc] >= heights[r][c] + ) { queue.push([nr, nc]); } } } - } + }; bfs(pacQueue, pac, heights); bfs(atlQueue, atl, heights); @@ -897,9 +1018,9 @@ class Solution { ```csharp public class Solution { - private int[][] directions = new int[][] { - new int[] { 1, 0 }, new int[] { -1, 0 }, - new int[] { 0, 1 }, new int[] { 0, -1 } + private int[][] directions = new int[][] { + new int[] { 1, 0 }, new int[] { -1, 0 }, + new int[] { 0, 1 }, new int[] { 0, -1 } }; public List> PacificAtlantic(int[][] heights) { int ROWS = heights.Length, COLS = heights[0].Length; @@ -939,8 +1060,8 @@ public class Solution { ocean[r, c] = true; foreach (var dir in directions) { int nr = r + dir[0], nc = c + dir[1]; - if (nr >= 0 && nr < heights.Length && nc >= 0 && - nc < heights[0].Length && !ocean[nr, nc] && + if (nr >= 0 && nr < heights.Length && nc >= 0 && + nc < heights[0].Length && !ocean[nr, nc] && heights[nr][nc] >= heights[r][c]) { q.Enqueue(new int[] { nr, nc }); } @@ -954,7 +1075,7 @@ public class Solution { func pacificAtlantic(heights [][]int) [][]int { rows, cols := len(heights), len(heights[0]) directions := [][]int{{1, 0}, {-1, 0}, {0, 1}, {0, -1}} - + pac := make([][]bool, rows) atl := make([][]bool, rows) for i := range pac { @@ -1013,11 +1134,11 @@ class Solution { fun pacificAtlantic(heights: Array): List> { val rows = heights.size val cols = heights[0].size - val directions = arrayOf(intArrayOf(1, 0), - intArrayOf(-1, 0), - intArrayOf(0, 1), + val directions = arrayOf(intArrayOf(1, 0), + intArrayOf(-1, 0), + intArrayOf(0, 1), intArrayOf(0, -1)) - + val pac = Array(rows) { BooleanArray(cols) } val atl = Array(rows) { BooleanArray(cols) } @@ -1065,11 +1186,66 @@ class Solution { } ``` +```swift +class Solution { + func pacificAtlantic(_ heights: [[Int]]) -> [[Int]] { + let ROWS = heights.count + let COLS = heights[0].count + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + + var pac = Array(repeating: Array(repeating: false, count: COLS), count: ROWS) + var atl = Array(repeating: Array(repeating: false, count: COLS), count: ROWS) + + func bfs(_ source: [(Int, Int)], _ ocean: inout [[Bool]]) { + var queue = Deque(source) + while !queue.isEmpty { + let (r, c) = queue.popFirst()! + ocean[r][c] = true + for dir in directions { + let nr = r + dir.0 + let nc = c + dir.1 + if nr >= 0, nr < ROWS, nc >= 0, nc < COLS, + !ocean[nr][nc], heights[nr][nc] >= heights[r][c] { + queue.append((nr, nc)) + } + } + } + } + + var pacific: [(Int, Int)] = [] + var atlantic: [(Int, Int)] = [] + + for c in 0.. Where $m$ is the number of rows and $n$ is the number of columns. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns. diff --git a/articles/paint-house.md b/articles/paint-house.md new file mode 100644 index 000000000..9960e4492 --- /dev/null +++ b/articles/paint-house.md @@ -0,0 +1,446 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def min_cost(self, costs: List[List[int]]) -> int: + n = len(costs) + + def dfs(i, prevColor): + if i == n: + return 0 + + res = float("inf") + for c in range(3): + if c == prevColor: + continue + res = min(res, costs[i][c] + dfs(i + 1, c)) + return res + + return dfs(0, -1) +``` + +```java +public class Solution { + private int[][] costs; + private int n; + + public int minCost(int[][] costs) { + this.costs = costs; + this.n = costs.length; + return dfs(0, -1); + } + + private int dfs(int i, int prevColor) { + if (i == n) { + return 0; + } + + int res = Integer.MAX_VALUE; + for (int c = 0; c < 3; c++) { + if (c == prevColor) { + continue; + } + res = Math.min(res, costs[i][c] + dfs(i + 1, c)); + } + return res; + } +} +``` + +```cpp +class Solution { +private: + vector> costs; + int n; + + int dfs(int i, int prevColor) { + if (i == n) { + return 0; + } + + int res = INT_MAX; + for (int c = 0; c < 3; c++) { + if (c == prevColor) { + continue; + } + res = min(res, costs[i][c] + dfs(i + 1, c)); + } + return res; + } + +public: + int minCost(vector>& costs) { + this->costs = costs; + this->n = costs.size(); + return dfs(0, -1); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + minCost(costs) { + const n = costs.length; + + const dfs = (i, prevColor) => { + if (i === n) return 0; + + let res = Infinity; + for (let c = 0; c < 3; c++) { + if (c === prevColor) continue; + res = Math.min(res, costs[i][c] + dfs(i + 1, c)); + } + return res; + }; + + return dfs(0, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def min_cost(self, costs: List[List[int]]) -> int: + n = len(costs) + dp = [[-1] * 4 for _ in range(n)] + + def dfs(i, prevColor): + if i == n: + return 0 + if dp[i][prevColor + 1] != -1: + return dp[i][prevColor + 1] + + res = float("inf") + for c in range(3): + if c == prevColor: + continue + res = min(res, costs[i][c] + dfs(i + 1, c)) + + dp[i][prevColor + 1] = res + return res + + return dfs(0, -1) +``` + +```java +public class Solution { + private int[][] dp; + private int[][] costs; + + public int minCost(int[][] costs) { + int n = costs.length; + this.costs = costs; + this.dp = new int[n][4]; + + for (int i = 0; i < n; i++) { + Arrays.fill(dp[i], -1); + } + + return dfs(0, -1); + } + + private int dfs(int i, int prevColor) { + if (i == costs.length) { + return 0; + } + if (dp[i][prevColor + 1] != -1) { + return dp[i][prevColor + 1]; + } + + int res = Integer.MAX_VALUE; + for (int c = 0; c < 3; c++) { + if (c == prevColor) continue; + res = Math.min(res, costs[i][c] + dfs(i + 1, c)); + } + + return dp[i][prevColor + 1] = res; + } +} +``` + +```cpp +class Solution { +public: + vector> dp; + vector> costs; + + int minCost(vector>& costs) { + int n = costs.size(); + this->costs = costs; + dp.assign(n, vector(4, -1)); + return dfs(0, -1); + } + +private: + int dfs(int i, int prevColor) { + if (i == costs.size()) { + return 0; + } + if (dp[i][prevColor + 1] != -1) { + return dp[i][prevColor + 1]; + } + + int res = INT_MAX; + for (int c = 0; c < 3; c++) { + if (c == prevColor) continue; + res = min(res, costs[i][c] + dfs(i + 1, c)); + } + + return dp[i][prevColor + 1] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + minCost(costs) { + const n = costs.length; + const dp = Array.from({ length: n }, () => Array(4).fill(-1)); + + const dfs = (i, prevColor) => { + if (i === n) { + return 0; + } + if (dp[i][prevColor + 1] !== -1) { + return dp[i][prevColor + 1]; + } + + let res = Infinity; + for (let c = 0; c < 3; c++) { + if (c === prevColor) continue; + res = Math.min(res, costs[i][c] + dfs(i + 1, c)); + } + + return (dp[i][prevColor + 1] = res); + }; + + return dfs(0, -1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def min_cost(self, costs: List[List[int]]) -> int: + n = len(costs) + if n == 0: + return 0 + + dp = [[0] * 3 for _ in range(n)] + for c in range(3): + dp[0][c] = costs[0][c] + + for i in range(1, n): + for c in range(3): + dp[i][c] = ( + costs[i][c] + + min(dp[i - 1][(c + 1) % 3], dp[i - 1][(c + 2) % 3]) + ) + + return min(dp[n - 1]) +``` + +```java +public class Solution { + public int minCost(int[][] costs) { + int n = costs.length; + if (n == 0) return 0; + + int[][] dp = new int[n][3]; + for (int c = 0; c < 3; c++) { + dp[0][c] = costs[0][c]; + } + + for (int i = 1; i < n; i++) { + for (int c = 0; c < 3; c++) { + dp[i][c] = costs[i][c] + + Math.min(dp[i - 1][(c + 1) % 3], dp[i - 1][(c + 2) % 3]); + } + } + + return Math.min(dp[n - 1][0], Math.min(dp[n - 1][1], dp[n - 1][2])); + } +} +``` + +```cpp +class Solution { +public: + int minCost(vector>& costs) { + int n = costs.size(); + if (n == 0) return 0; + + vector> dp(n, vector(3, 0)); + for (int c = 0; c < 3; c++) { + dp[0][c] = costs[0][c]; + } + + for (int i = 1; i < n; i++) { + for (int c = 0; c < 3; c++) { + dp[i][c] = costs[i][c] + + min(dp[i - 1][(c + 1) % 3], dp[i - 1][(c + 2) % 3]); + } + } + + return min({dp[n - 1][0], dp[n - 1][1], dp[n - 1][2]}); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + minCost(costs) { + let n = costs.length; + if (n === 0) return 0; + + let dp = Array.from({ length: n }, () => Array(3).fill(0)); + for (let c = 0; c < 3; c++) { + dp[0][c] = costs[0][c]; + } + + for (let i = 1; i < n; i++) { + for (let c = 0; c < 3; c++) { + dp[i][c] = + costs[i][c] + + Math.min(dp[i - 1][(c + 1) % 3], dp[i - 1][(c + 2) % 3]); + } + } + + return Math.min(dp[n - 1][0], dp[n - 1][1], dp[n - 1][2]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def minCost(self, costs: List[List[int]]) -> int: + dp = [0, 0, 0] + + for i in range(len(costs)): + dp0 = costs[i][0] + min(dp[1], dp[2]) + dp1 = costs[i][1] + min(dp[0], dp[2]) + dp2 = costs[i][2] + min(dp[0], dp[1]) + dp = [dp0, dp1, dp2] + + return min(dp) +``` + +```java +public class Solution { + public int minCost(int[][] costs) { + int dp0 = 0, dp1 = 0, dp2 = 0; + + for (int i = 0; i < costs.length; i++) { + int newDp0 = costs[i][0] + Math.min(dp1, dp2); + int newDp1 = costs[i][1] + Math.min(dp0, dp2); + int newDp2 = costs[i][2] + Math.min(dp0, dp1); + dp0 = newDp0; + dp1 = newDp1; + dp2 = newDp2; + } + + return Math.min(dp0, Math.min(dp1, dp2)); + } +} +``` + +```cpp +class Solution { +public: + int minCost(vector>& costs) { + int dp0 = 0, dp1 = 0, dp2 = 0; + + for (const auto& cost : costs) { + int newDp0 = cost[0] + min(dp1, dp2); + int newDp1 = cost[1] + min(dp0, dp2); + int newDp2 = cost[2] + min(dp0, dp1); + dp0 = newDp0; + dp1 = newDp1; + dp2 = newDp2; + } + + return min({dp0, dp1, dp2}); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + minCost(costs) { + let dp = [0, 0, 0]; + + for (let i = 0; i < costs.length; i++) { + let dp0 = costs[i][0] + Math.min(dp[1], dp[2]); + let dp1 = costs[i][1] + Math.min(dp[0], dp[2]); + let dp2 = costs[i][2] + Math.min(dp[0], dp[1]); + dp = [dp0, dp1, dp2]; + } + + return Math.min(dp[0], dp[1], dp[2]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/painting-the-walls.md b/articles/painting-the-walls.md index 1942d0042..b7ea573e3 100644 --- a/articles/painting-the-walls.md +++ b/articles/painting-the-walls.md @@ -11,7 +11,7 @@ class Solution: return 0 if i == len(cost): return float("inf") - + paint = cost[i] + dfs(i + 1, remain - 1 - time[i]) skip = dfs(i + 1, remain) return min(paint, skip) @@ -59,7 +59,7 @@ private: int paint = dfs(cost, time, i + 1, remain - 1 - time[i]); if (paint != INT_MAX) paint += cost[i]; - + int skip = dfs(cost, time, i + 1, remain); return min(paint, skip); } @@ -96,8 +96,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -117,7 +117,7 @@ class Solution: return float("inf") if (i, remain) in dp: return dp[(i, remain)] - + paint = cost[i] + dfs(i + 1, remain - 1 - time[i]) skip = dfs(i + 1, remain) dp[(i, remain)] = min(paint, skip) @@ -182,7 +182,7 @@ private: int paint = dfs(cost, time, i + 1, remain - 1 - time[i]); if (paint != INT_MAX) paint += cost[i]; - + int skip = dfs(cost, time, i + 1, remain); return dp[i][remain] = min(paint, skip); } @@ -212,7 +212,7 @@ class Solution { const paint = cost[i] + dfs(i + 1, remain - 1 - time[i]); const skip = dfs(i + 1, remain); - return dp[i][remain] = Math.min(paint, skip); + return (dp[i][remain] = Math.min(paint, skip)); }; return dfs(0, cost.length); @@ -224,8 +224,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -246,7 +246,7 @@ class Solution: paint = cost[i] + dp[i + 1][max(remain - 1 - time[i], 0)] skip = dp[i + 1][remain] dp[i][remain] = min(paint, skip) - + return dp[0][n] ``` @@ -263,7 +263,7 @@ public class Solution { for (int remain = 1; remain <= n; remain++) { int paint = dp[i + 1][Math.max(remain - 1 - time[i], 0)]; if (paint != Integer.MAX_VALUE) paint += cost[i]; - + int skip = dp[i + 1][remain]; dp[i][remain] = Math.min(paint, skip); } @@ -289,7 +289,7 @@ public: for (int remain = 1; remain <= n; remain++) { int paint = dp[i + 1][max(remain - 1 - time[i], 0)]; if (paint != INT_MAX) paint += cost[i]; - + int skip = dp[i + 1][remain]; dp[i][remain] = min(paint, skip); } @@ -317,7 +317,8 @@ class Solution { for (let i = n - 1; i >= 0; i--) { for (let remain = 1; remain <= n; remain++) { - const paint = cost[i] + dp[i + 1][Math.max(remain - 1 - time[i], 0)]; + const paint = + cost[i] + dp[i + 1][Math.max(remain - 1 - time[i], 0)]; const skip = dp[i + 1][remain]; dp[i][remain] = Math.min(paint, skip); } @@ -332,8 +333,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -352,7 +353,7 @@ class Solution: for remain in range(n, 0, -1): paint = cost[i] + dp[max(remain - 1 - time[i], 0)] dp[remain] = min(paint, dp[remain]) - + return dp[n] ``` @@ -426,5 +427,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ diff --git a/articles/palindrome-linked-list.md b/articles/palindrome-linked-list.md index f4f73b7bc..b986732d0 100644 --- a/articles/palindrome-linked-list.md +++ b/articles/palindrome-linked-list.md @@ -118,7 +118,8 @@ class Solution { cur = cur.next; } - let l = 0, r = arr.length - 1; + let l = 0, + r = arr.length - 1; while (l < r) { if (arr[l] !== arr[r]) { return false; @@ -132,12 +133,46 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public bool IsPalindrome(ListNode head) { + List arr = new List(); + ListNode cur = head; + while (cur != null) { + arr.Add(cur.val); + cur = cur.next; + } + + int l = 0, r = arr.Count - 1; + while (l < r) { + if (arr[l] != arr[r]) { + return false; + } + l++; + r--; + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -272,12 +307,46 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + private ListNode cur; + + public bool IsPalindrome(ListNode head) { + cur = head; + return Rec(head); + } + + private bool Rec(ListNode node) { + if (node != null) { + if (!Rec(node.next)) { + return false; + } + if (cur.val != node.val) { + return false; + } + cur = cur.next; + } + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -295,15 +364,15 @@ class Solution: def isPalindrome(self, head: Optional[ListNode]) -> bool: stack = [] cur = head - + while cur: stack.append(cur.val) cur = cur.next - + cur = head while cur and cur.val == stack.pop(): cur = cur.next - + return not cur ``` @@ -405,12 +474,43 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public bool IsPalindrome(ListNode head) { + Stack stack = new Stack(); + ListNode cur = head; + + while (cur != null) { + stack.Push(cur.val); + cur = cur.next; + } + + cur = head; + while (cur != null && cur.val == stack.Pop()) { + cur = cur.next; + } + + return cur == null; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -449,7 +549,7 @@ class Solution: return False left = left.next right = right.next - + return True ``` @@ -560,7 +660,8 @@ class Solution { * @return {boolean} */ isPalindrome(head) { - let fast = head, slow = head; + let fast = head, + slow = head; // find middle (slow) while (fast && fast.next) { @@ -578,7 +679,8 @@ class Solution { } // check palindrome - let left = head, right = prev; + let left = head, + right = prev; while (right) { if (left.val !== right.val) { return false; @@ -592,9 +694,51 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public bool IsPalindrome(ListNode head) { + ListNode fast = head, slow = head; + + while (fast != null && fast.next != null) { + fast = fast.next.next; + slow = slow.next; + } + + ListNode prev = null; + while (slow != null) { + ListNode tmp = slow.next; + slow.next = prev; + prev = slow; + slow = tmp; + } + + ListNode left = head, right = prev; + while (right != null) { + if (left.val != right.val) { + return false; + } + left = left.next; + right = right.next; + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/palindrome-number.md b/articles/palindrome-number.md new file mode 100644 index 000000000..ffbebc536 --- /dev/null +++ b/articles/palindrome-number.md @@ -0,0 +1,503 @@ +## 1. Convert to String + +::tabs-start + +```python +class Solution: + def isPalindrome(self, x: int) -> bool: + s = str(x) + return s == s[::-1] +``` + +```java +public class Solution { + public boolean isPalindrome(int x) { + String s = String.valueOf(x); + return s.equals(new StringBuilder(s).reverse().toString()); + } +} +``` + +```cpp +class Solution { +public: + bool isPalindrome(int x) { + string s = to_string(x); + string rev = s; + reverse(rev.begin(), rev.end()); + return s == rev; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} x + * @return {boolean} + */ + isPalindrome(x) { + const s = String(x); + return s === s.split('').reverse().join(''); + } +} +``` + +```csharp +public class Solution { + public bool IsPalindrome(int x) { + string s = x.ToString(); + char[] arr = s.ToCharArray(); + Array.Reverse(arr); + string rev = new string(arr); + return s == rev; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +> Where $n$ is the number of digits in the given integer. + +--- + +## 2. Convert to String (Optimal) + +::tabs-start + +```python +class Solution: + def isPalindrome(self, x: int) -> bool: + s = str(x) + n = len(s) + for i in range(n // 2): + if s[i] != s[n - i - 1]: + return False + return True +``` + +```java +public class Solution { + public boolean isPalindrome(int x) { + String s = String.valueOf(x); + int n = s.length(); + for (int i = 0; i < n / 2; i++) { + if (s.charAt(i) != s.charAt(n - i - 1)) { + return false; + } + } + return true; + } +} +``` + +```cpp +class Solution { +public: + bool isPalindrome(int x) { + string s = to_string(x); + int n = s.length(); + for (int i = 0; i < n / 2; i++) { + if (s[i] != s[n - i - 1]) { + return false; + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} x + * @return {boolean} + */ + isPalindrome(x) { + const s = String(x); + let n = s.length; + for (let i = 0; i < n >> 1; i++) { + if (s.charAt(i) != s.charAt(n - i - 1)) { + return false; + } + } + return true; + } +} +``` + +```csharp +public class Solution { + public bool IsPalindrome(int x) { + string s = x.ToString(); + int n = s.Length; + for (int i = 0; i < n / 2; i++) { + if (s[i] != s[n - i - 1]) { + return false; + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +> Where $n$ is the number of digits in the given integer. + +--- + +## 3. Reverse the Integer + +::tabs-start + +```python +class Solution: + def isPalindrome(self, x: int) -> bool: + if x < 0: + return False + + rev = 0 + num = x + while num: + rev = (rev * 10) + (num % 10) + num //= 10 + + return rev == x +``` + +```java +public class Solution { + public boolean isPalindrome(int x) { + if (x < 0) { + return false; + } + + long rev = 0, num = x; + while (num != 0) { + rev = (rev * 10) + (num % 10); + num /= 10; + } + + return rev == x; + } +} +``` + +```cpp +class Solution { +public: + bool isPalindrome(int x) { + if (x < 0) { + return false; + } + + long long rev = 0, num = x; + while (num != 0) { + rev = (rev * 10) + (num % 10); + num /= 10; + } + + return rev == x; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} x + * @return {boolean} + */ + isPalindrome(x) { + if (x < 0) { + return false; + } + + let rev = 0, + num = x; + while (num !== 0) { + rev = rev * 10 + (num % 10); + num = Math.floor(num / 10); + } + + return rev === x; + } +} +``` + +```csharp +public class Solution { + public bool IsPalindrome(int x) { + if (x < 0) return false; + int rev = 0, num = x; + while (num != 0) { + rev = rev * 10 + num % 10; + num /= 10; + } + return rev == x; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +> Where $n$ is the number of digits in the given integer. + +--- + +## 4. Two Pointers + +::tabs-start + +```python +class Solution: + def isPalindrome(self, x: int) -> bool: + if x < 0: + return False + + div = 1 + while x >= 10 * div: + div *= 10 + + while x: + if x // div != x % 10: + return False + x = (x % div) // 10 + div //= 100 + + return True +``` + +```java +public class Solution { + public boolean isPalindrome(int x) { + if (x < 0) { + return false; + } + + long div = 1; + while (x >= 10 * div) { + div *= 10; + } + + while (x != 0) { + if (x / div != x % 10) { + return false; + } + x = (int) (x % div) / 10; + div /= 100; + } + + return true; + } +} +``` + +```cpp +class Solution { +public: + bool isPalindrome(int x) { + if (x < 0) { + return false; + } + + long long div = 1; + while (x >= 10 * div) { + div *= 10; + } + + while (x != 0) { + if (x / div != x % 10) { + return false; + } + x = (x % div) / 10; + div /= 100; + } + + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} x + * @return {boolean} + */ + isPalindrome(x) { + if (x < 0) { + return false; + } + + let div = 1; + while (x >= 10 * div) { + div *= 10; + } + + while (x !== 0) { + if (Math.floor(x / div) !== x % 10) { + return false; + } + x = Math.floor((x % div) / 10); + div = Math.floor(div / 100); + } + + return true; + } +} +``` + +```csharp +public class Solution { + public bool IsPalindrome(int x) { + if (x < 0) return false; + + int div = 1; + while (x / div >= 10) { + div *= 10; + } + + while (x != 0) { + if (x / div != x % 10) { + return false; + } + x = (x % div) / 10; + div /= 100; + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +> Where $n$ is the number of digits in the given integer. + +--- + +## 5. Reverse Half of the Number + +::tabs-start + +```python +class Solution: + def isPalindrome(self, x: int) -> bool: + if x < 0 or (x != 0 and x % 10 == 0): + return False + + rev = 0 + while x > rev: + rev = (rev * 10) + (x % 10) + x //= 10 + + return x == rev or x == rev // 10 +``` + +```java +public class Solution { + public boolean isPalindrome(int x) { + if (x < 0 || (x != 0 && x % 10 == 0)) { + return false; + } + + int rev = 0; + while (x > rev) { + rev = rev * 10 + x % 10; + x /= 10; + } + + return x == rev || x == rev / 10; + } +} +``` + +```cpp +class Solution { +public: + bool isPalindrome(int x) { + if (x < 0 || (x != 0 && x % 10 == 0)) { + return false; + } + + int rev = 0; + while (x > rev) { + rev = rev * 10 + x % 10; + x /= 10; + } + + return x == rev || x == rev / 10; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} x + * @return {boolean} + */ + isPalindrome(x) { + if (x < 0 || (x !== 0 && x % 10 === 0)) { + return false; + } + + let rev = 0; + while (x > rev) { + rev = rev * 10 + (x % 10); + x = Math.floor(x / 10); + } + + return x === rev || x === Math.floor(rev / 10); + } +} +``` + +```csharp +public class Solution { + public bool IsPalindrome(int x) { + if (x < 0 || (x != 0 && x % 10 == 0)) { + return false; + } + + int rev = 0; + while (x > rev) { + rev = rev * 10 + x % 10; + x /= 10; + } + + return x == rev || x == rev / 10; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +> Where $n$ is the number of digits in the given integer. diff --git a/articles/palindrome-partitioning.md b/articles/palindrome-partitioning.md index 4b954a755..1112bfbb5 100644 --- a/articles/palindrome-partitioning.md +++ b/articles/palindrome-partitioning.md @@ -1,4 +1,4 @@ -## 1. Backtracking (Pick / Not Pick) +## 1. Backtracking - I ::tabs-start @@ -12,14 +12,14 @@ class Solution: if i == j: res.append(part.copy()) return - + if self.isPali(s, j, i): part.append(s[j : i + 1]) dfs(i + 1, i + 1) part.pop() - + dfs(j, i + 1) - + dfs(0, 0) return res @@ -48,13 +48,13 @@ public class Solution { } return; } - + if (isPali(s, j, i)) { part.add(s.substring(j, i + 1)); dfs(i + 1, i + 1, s); part.remove(part.size() - 1); } - + dfs(j, i + 1, s); } @@ -88,13 +88,13 @@ public: } return; } - + if (isPali(s, j, i)) { part.push_back(s.substr(j, i - j + 1)); dfs(i + 1, i + 1, s, part); part.pop_back(); } - + dfs(j, i + 1, s, part); } @@ -282,22 +282,66 @@ class Solution { } ``` +```swift +class Solution { + func partition(_ s: String) -> [[String]] { + var res = [[String]]() + var part = [String]() + let sArray = Array(s) + + func dfs(_ j: Int, _ i: Int) { + if i >= sArray.count { + if i == j { + res.append(part) + } + return + } + + if isPali(sArray, j, i) { + part.append(String(sArray[j...i])) + dfs(i + 1, i + 1) + part.removeLast() + } + + dfs(j, i + 1) + } + + func isPali(_ s: [Character], _ l: Int, _ r: Int) -> Bool { + var l = l, r = r + while l < r { + if s[l] != s[r] { + return false + } + l += 1 + r -= 1 + } + return true + } + + dfs(0, 0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: + - $O(n)$ extra space. + - $O(n * 2 ^ n)$ space for the output list. --- -## 2. Backtracking +## 2. Backtracking - II ::tabs-start ```python class Solution: - + def partition(self, s: str) -> List[List[str]]: res, part = [], [] @@ -324,7 +368,7 @@ class Solution: ```java public class Solution { - + public List> partition(String s) { List> res = new ArrayList<>(); List part = new ArrayList<>(); @@ -452,7 +496,7 @@ class Solution { ```csharp public class Solution { - + public List> Partition(string s) { List> res = new List>(); List part = new List(); @@ -562,12 +606,53 @@ class Solution { } ``` +```swift +class Solution { + func partition(_ s: String) -> [[String]] { + var res = [[String]]() + var part = [String]() + let sArray = Array(s) + + func dfs(_ i: Int) { + if i >= sArray.count { + res.append(part) + return + } + for j in i.. Bool { + var l = l, r = r + while l < r { + if s[l] != s[r] { + return false + } + l += 1 + r -= 1 + } + return true + } + + dfs(0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: + - $O(n)$ extra space. + - $O(n * 2 ^ n)$ space for the output list. --- @@ -577,7 +662,7 @@ class Solution { ```python class Solution: - + def partition(self, s: str) -> List[List[str]]: n = len(s) dp = [[False] * n for _ in range(n)] @@ -610,12 +695,12 @@ public class Solution { dp = new boolean[n][n]; for (int l = 1; l <= n; l++) { for (int i = 0; i <= n - l; i++) { - dp[i][i + l - 1] = (s.charAt(i) == s.charAt(i + l - 1) && - (i + 1 > (i + l - 2) || + dp[i][i + l - 1] = (s.charAt(i) == s.charAt(i + l - 1) && + (i + 1 > (i + l - 2) || dp[i + 1][i + l - 2])); } } - + List> res = new ArrayList<>(); List part = new ArrayList<>(); dfs(0, s, part, res); @@ -647,8 +732,8 @@ public: dp.resize(n, vector(n)); for (int l = 1; l <= n; l++) { for (int i = 0; i <= n - l; i++) { - dp[i][i + l - 1] = (s[i] == s[i + l - 1] && - (i + 1 > (i + l - 2) || + dp[i][i + l - 1] = (s[i] == s[i + l - 1] && + (i + 1 > (i + l - 2) || dp[i + 1][i + l - 2])); } } @@ -687,9 +772,9 @@ class Solution { const dp = Array.from({ length: n }, () => Array(n).fill(false)); for (let l = 1; l <= n; l++) { for (let i = 0; i <= n - l; i++) { - dp[i][i + l - 1] = (s[i] === s[i + l - 1] && - (i + 1 > (i + l - 2) || - dp[i + 1][i + l - 2])); + dp[i][i + l - 1] = + s[i] === s[i + l - 1] && + (i + 1 > i + l - 2 || dp[i + 1][i + l - 2]); } } @@ -707,7 +792,7 @@ class Solution { part.pop(); } } - } + }; dfs(0); return res; } @@ -716,18 +801,18 @@ class Solution { ```csharp public class Solution { - + public List> Partition(string s) { int n = s.Length; bool[,] dp = new bool[n, n]; for (int l = 1; l <= n; l++) { for (int i = 0; i <= n - l; i++) { - dp[i, i + l - 1] = (s[i] == s[i + l - 1] && - (i + 1 > (i + l - 2) || + dp[i, i + l - 1] = (s[i] == s[i + l - 1] && + (i + 1 > (i + l - 2) || dp[i + 1, i + l - 2])); } } - + List> res = new List>(); List part = new List(); Dfs(0, s, part, res, dp); @@ -795,7 +880,7 @@ class Solution { for (l in 1..n) { for (i in 0..n - l) { - dp[i][i + l - 1] = s[i] == s[i + l - 1] && + dp[i][i + l - 1] = s[i] == s[i + l - 1] && (i + 1 > (i + l - 2) || dp[i + 1][i + l - 2]) } } @@ -823,12 +908,51 @@ class Solution { } ``` +```swift +class Solution { + func partition(_ s: String) -> [[String]] { + let n = s.count + let sArray = Array(s) + var dp = Array(repeating: Array(repeating: false, count: n), count: n) + + for l in 1...n { + for i in 0...(n - l) { + dp[i][i + l - 1] = (sArray[i] == sArray[i + l - 1] && + (i + 1 > (i + l - 2) || dp[i + 1][i + l - 2])) + } + } + + var res = [[String]]() + var part = [String]() + + func dfs(_ i: Int) { + if i >= sArray.count { + res.append(part) + return + } + for j in i.. List[List[str]]: n = len(s) dp = [[False] * n for _ in range(n)] @@ -847,37 +971,37 @@ class Solution: dp[i][i + l - 1] = (s[i] == s[i + l - 1] and (i + 1 > (i + l - 2) or dp[i + 1][i + l - 2])) - + def dfs(i): if i >= n: - return [[]] - + return [[]] + ret = [] for j in range(i, n): if dp[i][j]: nxt = dfs(j + 1) for part in nxt: - cur = [s[i : j + 1]] + part + cur = [s[i : j + 1]] + part ret.append(cur) return ret - + return dfs(0) ``` ```java public class Solution { - + public List> partition(String s) { int n = s.length(); boolean[][] dp = new boolean[n][n]; for (int l = 1; l <= n; l++) { for (int i = 0; i <= n - l; i++) { - dp[i][i + l - 1] = (s.charAt(i) == s.charAt(i + l - 1) && - (i + 1 > (i + l - 2) || + dp[i][i + l - 1] = (s.charAt(i) == s.charAt(i + l - 1) && + (i + 1 > (i + l - 2) || dp[i + 1][i + l - 2])); } } - + return dfs(s, dp, 0); } @@ -911,12 +1035,12 @@ public: vector> dp(n, vector(n, false)); for (int l = 1; l <= n; l++) { for (int i = 0; i <= n - l; i++) { - dp[i][i + l - 1] = (s[i] == s[i + l - 1] && - (i + 1 > (i + l - 2) || + dp[i][i + l - 1] = (s[i] == s[i + l - 1] && + (i + 1 > (i + l - 2) || dp[i + 1][i + l - 2])); } } - + return dfs(s, dp, 0); } @@ -953,12 +1077,12 @@ class Solution { const dp = Array.from({ length: n }, () => Array(n).fill(false)); for (let l = 1; l <= n; l++) { for (let i = 0; i <= n - l; i++) { - dp[i][i + l - 1] = (s[i] === s[i + l - 1] && - (i + 1 > (i + l - 2) || - dp[i + 1][i + l - 2])); + dp[i][i + l - 1] = + s[i] === s[i + l - 1] && + (i + 1 > i + l - 2 || dp[i + 1][i + l - 2]); } } - + const dfs = (i) => { if (i >= s.length) { return [[]]; @@ -984,18 +1108,18 @@ class Solution { ```csharp public class Solution { - + public List> Partition(string s) { int n = s.Length; bool[,] dp = new bool[n, n]; for (int l = 1; l <= n; l++) { for (int i = 0; i <= n - l; i++) { - dp[i, i + l - 1] = (s[i] == s[i + l - 1] && - (i + 1 > (i + l - 2) || + dp[i, i + l - 1] = (s[i] == s[i + l - 1] && + (i + 1 > (i + l - 2) || dp[i + 1, i + l - 2])); } } - + return Dfs(s, dp, 0); } @@ -1030,7 +1154,7 @@ func partition(s string) [][]string { for l := 1; l <= n; l++ { for i := 0; i <= n-l; i++ { - dp[i][i+l-1] = (s[i] == s[i+l-1] && + dp[i][i+l-1] = (s[i] == s[i+l-1] && (i+1 > (i+l-2) || dp[i+1][i+l-2])) } } @@ -1066,7 +1190,7 @@ class Solution { for (l in 1..n) { for (i in 0..n - l) { - dp[i][i + l - 1] = s[i] == s[i + l - 1] && + dp[i][i + l - 1] = s[i] == s[i + l - 1] && (i + 1 > (i + l - 2) || dp[i + 1][i + l - 2]) } } @@ -1094,9 +1218,50 @@ class Solution { } ``` +```swift +class Solution { + func partition(_ s: String) -> [[String]] { + let n = s.count + let sArray = Array(s) + var dp = Array(repeating: Array(repeating: false, count: n), count: n) + + for l in 1...n { + for i in 0...(n - l) { + dp[i][i + l - 1] = (sArray[i] == sArray[i + l - 1] && + (i + 1 > (i + l - 2) || dp[i + 1][i + l - 2])) + } + } + + func dfs(_ i: Int) -> [[String]] { + if i >= n { + return [[]] + } + + var ret = [[String]]() + for j in i.. int: res = 0 - + for i in range(len(s)): for j in range(i, len(s)): l, r = i, j @@ -14,7 +14,7 @@ class Solution: l += 1 r -= 1 res += (l >= r) - + return res ``` @@ -72,12 +72,13 @@ class Solution { for (let i = 0; i < s.length; i++) { for (let j = i; j < s.length; j++) { - let l = i, r = j; + let l = i, + r = j; while (l < r && s[l] === s[r]) { l++; r--; } - res += (l >= r) ? 1 : 0; + res += l >= r ? 1 : 0; } } @@ -148,12 +149,36 @@ class Solution { } ``` +```swift +class Solution { + func countSubstrings(_ s: String) -> Int { + let chars = Array(s) + var res = 0 + + for i in 0..= r { + res += 1 + } + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(1)$ --- @@ -184,9 +209,9 @@ public class Solution { for (int i = n - 1; i >= 0; i--) { for (int j = i; j < n; j++) { - if (s.charAt(i) == s.charAt(j) && + if (s.charAt(i) == s.charAt(j) && (j - i <= 2 || dp[i + 1][j - 1])) { - + dp[i][j] = true; res++; } @@ -207,7 +232,7 @@ public: for (int i = n - 1; i >= 0; i--) { for (int j = i; j < n; j++) { - if (s[i] == s[j] && + if (s[i] == s[j] && (j - i <= 2 || dp[i + 1][j - 1])) { dp[i][j] = true; @@ -234,9 +259,7 @@ class Solution { for (let i = n - 1; i >= 0; i--) { for (let j = i; j < n; j++) { - if (s[i] === s[j] && - (j - i <= 2 || dp[i + 1][j - 1])) { - + if (s[i] === s[j] && (j - i <= 2 || dp[i + 1][j - 1])) { dp[i][j] = true; res++; } @@ -256,9 +279,9 @@ public class Solution { for (int i = n - 1; i >= 0; i--) { for (int j = i; j < n; j++) { - if (s[i] == s[j] && + if (s[i] == s[j] && (j - i <= 2 || dp[i + 1, j - 1])) { - + dp[i, j] = true; res++; } @@ -313,12 +336,34 @@ class Solution { } ``` +```swift +class Solution { + func countSubstrings(_ s: String) -> Int { + let n = s.count + var res = 0 + var dp = Array(repeating: Array(repeating: false, count: n), count: n) + let chars = Array(s) + + for i in stride(from: n - 1, through: 0, by: -1) { + for j in i.. int: res = 0 - + for i in range(len(s)): # odd length l, r = i, i @@ -345,7 +390,7 @@ class Solution: res += 1 l -= 1 r += 1 - + return res ``` @@ -353,11 +398,11 @@ class Solution: public class Solution { public int countSubstrings(String s) { int res = 0; - + for (int i = 0; i < s.length(); i++) { // odd length int l = i, r = i; - while (l >= 0 && r < s.length() && + while (l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r)) { res++; l--; @@ -367,7 +412,7 @@ public class Solution { // even length l = i; r = i + 1; - while (l >= 0 && r < s.length() && + while (l >= 0 && r < s.length() && s.charAt(l) == s.charAt(r)) { res++; l--; @@ -420,13 +465,12 @@ class Solution { */ countSubstrings(s) { let res = 0; - + for (let i = 0; i < s.length; i++) { // odd length let l = i; - let r = i; - while (l >= 0 && r < s.length && - s.charAt(l) === s.charAt(r)) { + let r = i; + while (l >= 0 && r < s.length && s.charAt(l) === s.charAt(r)) { res++; l--; r++; @@ -435,8 +479,7 @@ class Solution { // even length l = i; r = i + 1; - while (l >= 0 && r < s.length && - s.charAt(l) === s.charAt(r)) { + while (l >= 0 && r < s.length && s.charAt(l) === s.charAt(r)) { res++; l--; r++; @@ -452,7 +495,7 @@ class Solution { public class Solution { public int CountSubstrings(string s) { int res = 0; - + for (int i = 0; i < s.Length; i++) { // odd length int l = i, r = i; @@ -535,12 +578,42 @@ class Solution { } ``` +```swift +class Solution { + func countSubstrings(_ s: String) -> Int { + let chars = Array(s) + var res = 0 + + for i in 0..= 0 && r < chars.count && chars[l] == chars[r] { + res += 1 + l -= 1 + r += 1 + } + + // Even length palindromes + l = i + r = i + 1 + while l >= 0 && r < chars.count && chars[l] == chars[r] { + res += 1 + l -= 1 + r += 1 + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -550,7 +623,7 @@ class Solution { ```python class Solution: - + def countSubstrings(self, s: str) -> int: res = 0 @@ -570,7 +643,7 @@ class Solution: ```java public class Solution { - + public int countSubstrings(String s) { int res = 0; for (int i = 0; i < s.length(); i++) { @@ -641,8 +714,7 @@ class Solution { */ countPali(s, l, r) { let res = 0; - while (l >= 0 && r < s.length && - s.charAt(l) === s.charAt(r)) { + while (l >= 0 && r < s.length && s.charAt(l) === s.charAt(r)) { res++; l--; r++; @@ -654,7 +726,7 @@ class Solution { ```csharp public class Solution { - + public int CountSubstrings(string s) { int res = 0; for (int i = 0; i < s.Length; i++) { @@ -680,8 +752,8 @@ public class Solution { func countSubstrings(s string) int { res := 0 for i := 0; i < len(s); i++ { - res += countPali(s, i, i) - res += countPali(s, i, i+1) + res += countPali(s, i, i) + res += countPali(s, i, i+1) } return res } @@ -702,8 +774,8 @@ class Solution { fun countSubstrings(s: String): Int { var res = 0 for (i in s.indices) { - res += countPali(s, i, i) - res += countPali(s, i, i + 1) + res += countPali(s, i, i) + res += countPali(s, i, i + 1) } return res } @@ -722,12 +794,39 @@ class Solution { } ``` +```swift +class Solution { + func countSubstrings(_ s: String) -> Int { + var res = 0 + let chars = Array(s) + + for i in 0.. Int { + var res = 0 + var left = l, right = r + + while left >= 0 && right < s.count && s[left] == s[right] { + res += 1 + left -= 1 + right += 1 + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -746,13 +845,13 @@ class Solution: l, r = 0, 0 for i in range(n): p[i] = min(r - i, p[l + (r - i)]) if i < r else 0 - while (i + p[i] + 1 < n and i - p[i] - 1 >= 0 + while (i + p[i] + 1 < n and i - p[i] - 1 >= 0 and t[i + p[i] + 1] == t[i - p[i] - 1]): p[i] += 1 if i + p[i] > r: l, r = i - p[i], i + p[i] return p - + p = manacher(s) res = 0 for i in p: @@ -840,11 +939,15 @@ class Solution { const t = '#' + s.split('').join('#') + '#'; const n = t.length; const p = new Array(n).fill(0); - let l = 0, r = 0; + let l = 0, + r = 0; for (let i = 0; i < n; i++) { - p[i] = (i < r) ? Math.min(r - i, p[l + (r - i)]) : 0; - while (i + p[i] + 1 < n && i - p[i] - 1 >= 0 && - t[i + p[i] + 1] === t[i - p[i] - 1]) { + p[i] = i < r ? Math.min(r - i, p[l + (r - i)]) : 0; + while ( + i + p[i] + 1 < n && + i - p[i] - 1 >= 0 && + t[i + p[i] + 1] === t[i - p[i] - 1] + ) { p[i]++; } if (i + p[i] > r) { @@ -922,7 +1025,7 @@ func countSubstrings(s string) int { } return p } - + p := manacher(s) res := 0 for _, val := range p { @@ -960,7 +1063,7 @@ class Solution { if (i < r) { p[i] = minOf(r - i, p[l + (r - i)]) } - while (i + p[i] + 1 < n && i - p[i] - 1 >= 0 && + while (i + p[i] + 1 < n && i - p[i] - 1 >= 0 && t[i + p[i] + 1] == t[i - p[i] - 1]) { p[i]++ } @@ -982,9 +1085,45 @@ class Solution { } ``` +```swift +class Solution { + func countSubstrings(_ s: String) -> Int { + func manacher(_ s: String) -> [Int] { + let t = "#" + s.map { "\($0)#" }.joined() + let chars = Array(t) + let n = chars.count + var p = Array(repeating: 0, count: n) + var l = 0, r = 0 + + for i in 0..= 0, + chars[i + p[i] + 1] == chars[i - p[i] - 1] { + p[i] += 1 + } + if i + p[i] > r { + l = i - p[i] + r = i + p[i] + } + } + return p + } + + let p = manacher(s) + var res = 0 + for i in p { + res += (i + 1) / 2 + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/parallel-courses-iii.md b/articles/parallel-courses-iii.md new file mode 100644 index 000000000..6e73223d2 --- /dev/null +++ b/articles/parallel-courses-iii.md @@ -0,0 +1,484 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def minimumTime(self, n: int, relations: list[list[int]], time: list[int]) -> int: + adj = defaultdict(list) + for src, dst in relations: + adj[src].append(dst) + + max_time = {} + + def dfs(src): + if src in max_time: + return max_time[src] + res = time[src - 1] + for nei in adj[src]: + res = max(res, time[src - 1] + dfs(nei)) + max_time[src] = res + return res + + for i in range(1, n + 1): + dfs(i) + + return max(max_time.values()) +``` + +```java +public class Solution { + private Map maxTime; + private List[] adj; + private int[] time; + + public int minimumTime(int n, int[][] relations, int[] time) { + this.time = time; + this.maxTime = new HashMap<>(); + this.adj = new ArrayList[n + 1]; + + for (int i = 1; i <= n; i++) { + adj[i] = new ArrayList<>(); + } + for (int[] relation : relations) { + adj[relation[0]].add(relation[1]); + } + + for (int i = 1; i <= n; i++) { + dfs(i); + } + + return Collections.max(maxTime.values()); + } + + private int dfs(int src) { + if (maxTime.containsKey(src)) { + return maxTime.get(src); + } + + int res = time[src - 1]; + for (int nei : adj[src]) { + res = Math.max(res, time[src - 1] + dfs(nei)); + } + maxTime.put(src, res); + return res; + } +} +``` + +```cpp +class Solution { +public: + unordered_map maxTime; + vector> adj; + vector time; + + int minimumTime(int n, vector>& relations, vector& time) { + this->time = time; + adj.resize(n + 1); + + for (auto& relation : relations) { + adj[relation[0]].push_back(relation[1]); + } + + for (int i = 1; i <= n; i++) { + dfs(i); + } + + int res = 0; + for (auto& [key, value] : maxTime) { + res = max(res, value); + } + return res; + } + +private: + int dfs(int src) { + if (maxTime.count(src)) { + return maxTime[src]; + } + + int res = time[src - 1]; + for (int nei : adj[src]) { + res = max(res, time[src - 1] + dfs(nei)); + } + maxTime[src] = res; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} relations + * @param {number[]} time + * @return {number} + */ + minimumTime(n, relations, time) { + let adj = Array.from({ length: n + 1 }, () => []); + let maxTime = new Map(); + + for (let [src, dst] of relations) { + adj[src].push(dst); + } + + const dfs = (src) => { + if (maxTime.has(src)) { + return maxTime.get(src); + } + + let res = time[src - 1]; + for (let nei of adj[src]) { + res = Math.max(res, time[src - 1] + dfs(nei)); + } + maxTime.set(src, res); + return res; + }; + + for (let i = 1; i <= n; i++) { + dfs(i); + } + + return Math.max(...maxTime.values()); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of courses and $E$ is the number of prerequisites. + +--- + +## 2. Iterative DFS + +::tabs-start + +```python +class Solution: + def minimumTime(self, n: int, relations: list[list[int]], time: list[int]) -> int: + adj = [[] for _ in range(n)] + for src, dst in relations: + adj[src - 1].append(dst - 1) + + maxTime = [-1] * n + processed = [False] * n + + for i in range(n): + if maxTime[i] == -1: + stack = [i] + while stack: + node = stack.pop() + if processed[node]: + best = 0 + for nei in adj[node]: + best = max(best, maxTime[nei]) + maxTime[node] = time[node] + best + else: + processed[node] = True + stack.append(node) + for nei in adj[node]: + if maxTime[nei] == -1: + stack.append(nei) + return max(maxTime) +``` + +```java +public class Solution { + public int minimumTime(int n, int[][] relations, int[] time) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + for (int[] rel : relations) { + adj[rel[0] - 1].add(rel[1] - 1); + } + + int[] maxTime = new int[n]; + Arrays.fill(maxTime, -1); + boolean[] processed = new boolean[n]; + + for (int i = 0; i < n; i++) { + if (maxTime[i] == -1) { + Stack stack = new Stack<>(); + stack.push(i); + while (!stack.isEmpty()) { + int node = stack.pop(); + if (processed[node]) { + int best = 0; + for (int nei : adj[node]) { + best = Math.max(best, maxTime[nei]); + } + maxTime[node] = time[node] + best; + } else { + processed[node] = true; + stack.push(node); + for (int nei : adj[node]) { + if (maxTime[nei] == -1) { + stack.push(nei); + } + } + } + } + } + } + return Arrays.stream(maxTime).max().getAsInt(); + } +} +``` + +```cpp +class Solution { +public: + int minimumTime(int n, vector>& relations, vector& time) { + vector> adj(n); + for (auto& rel : relations) { + adj[rel[0] - 1].push_back(rel[1] - 1); + } + + vector maxTime(n, -1); + vector processed(n, false); + + for (int i = 0; i < n; i++) { + if (maxTime[i] == -1) { + stack stk; + stk.push(i); + while (!stk.empty()) { + int node = stk.top(); stk.pop(); + if (processed[node]) { + int best = 0; + for (int nei : adj[node]) { + best = max(best, maxTime[nei]); + } + maxTime[node] = time[node] + best; + } else { + processed[node] = true; + stk.push(node); + for (int nei : adj[node]) { + if (maxTime[nei] == -1) { + stk.push(nei); + } + } + } + } + } + } + return *max_element(maxTime.begin(), maxTime.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} relations + * @param {number[]} time + * @return {number} + */ + minimumTime(n, relations, time) { + let adj = Array.from({ length: n }, () => []); + for (let [src, dst] of relations) { + adj[src - 1].push(dst - 1); + } + + let maxTime = Array(n).fill(-1); + let processed = Array(n).fill(false); + + for (let i = 0; i < n; i++) { + if (maxTime[i] === -1) { + let stack = [i]; + while (stack.length > 0) { + let node = stack.pop(); + if (processed[node]) { + let best = 0; + for (let nei of adj[node]) { + best = Math.max(best, maxTime[nei]); + } + maxTime[node] = time[node] + best; + } else { + processed[node] = true; + stack.push(node); + for (let nei of adj[node]) { + if (maxTime[nei] === -1) { + stack.push(nei); + } + } + } + } + } + } + return Math.max(...maxTime); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of courses and $E$ is the number of prerequisites. + +--- + +## 3. Topological Sort (Kahn's Algorithm) + +::tabs-start + +```python +class Solution: + def minimumTime(self, n: int, relations: list[list[int]], time: list[int]) -> int: + adj = [[] for _ in range(n)] + indegree = [0] * n + maxTime = time[:] + + for src, dst in relations: + adj[src - 1].append(dst - 1) + indegree[dst - 1] += 1 + + queue = deque([i for i in range(n) if indegree[i] == 0]) + while queue: + node = queue.popleft() + for nei in adj[node]: + maxTime[nei] = max(maxTime[nei], maxTime[node] + time[nei]) + indegree[nei] -= 1 + if indegree[nei] == 0: + queue.append(nei) + + return max(maxTime) +``` + +```java +public class Solution { + public int minimumTime(int n, int[][] relations, int[] time) { + List> adj = new ArrayList<>(); + int[] indegree = new int[n]; + int[] maxTime = Arrays.copyOf(time, n); + + for (int i = 0; i < n; i++) { + adj.add(new ArrayList<>()); + } + + for (int[] relation : relations) { + int src = relation[0] - 1, dst = relation[1] - 1; + adj.get(src).add(dst); + indegree[dst]++; + } + + Queue queue = new LinkedList<>(); + for (int i = 0; i < n; i++) { + if (indegree[i] == 0) { + queue.add(i); + } + } + + while (!queue.isEmpty()) { + int node = queue.poll(); + for (int nei : adj.get(node)) { + maxTime[nei] = Math.max(maxTime[nei], maxTime[node] + time[nei]); + if (--indegree[nei] == 0) { + queue.add(nei); + } + } + } + + return Arrays.stream(maxTime).max().getAsInt(); + } +} +``` + +```cpp +class Solution { +public: + int minimumTime(int n, vector>& relations, vector& time) { + vector> adj(n); + vector indegree(n, 0); + vector maxTime(time.begin(), time.end()); + + for (auto& relation : relations) { + int src = relation[0] - 1, dst = relation[1] - 1; + adj[src].push_back(dst); + indegree[dst]++; + } + + queue queue; + for (int i = 0; i < n; i++) { + if (indegree[i] == 0) { + queue.push(i); + } + } + + while (!queue.empty()) { + int node = queue.front(); queue.pop(); + for (int nei : adj[node]) { + maxTime[nei] = max(maxTime[nei], maxTime[node] + time[nei]); + if (--indegree[nei] == 0) { + queue.push(nei); + } + } + } + + return *max_element(maxTime.begin(), maxTime.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} relations + * @param {number[]} time + * @return {number} + */ + minimumTime(n, relations, time) { + let adj = Array.from({ length: n }, () => []); + let indegree = Array(n).fill(0); + let maxTime = [...time]; + + for (let [src, dst] of relations) { + adj[src - 1].push(dst - 1); + indegree[dst - 1]++; + } + + let queue = new Queue(); + for (let i = 0; i < n; i++) { + if (indegree[i] === 0) { + queue.push(i); + } + } + + while (!queue.isEmpty()) { + let node = queue.pop(); + for (let nei of adj[node]) { + maxTime[nei] = Math.max( + maxTime[nei], + maxTime[node] + time[nei], + ); + if (--indegree[nei] === 0) { + queue.push(nei); + } + } + } + + return Math.max(...maxTime); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of courses and $E$ is the number of prerequisites. diff --git a/articles/partition-array-for-maximum-sum.md b/articles/partition-array-for-maximum-sum.md new file mode 100644 index 000000000..5b78a466d --- /dev/null +++ b/articles/partition-array-for-maximum-sum.md @@ -0,0 +1,449 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def maxSumAfterPartitioning(self, arr: List[int], k: int) -> int: + def dfs(i): + if i >= len(arr): + return 0 + + cur_max = 0 + res = 0 + for j in range(i, min(len(arr), i + k)): + cur_max = max(cur_max, arr[j]) + window_size = j - i + 1 + res = max(res, dfs(j + 1) + cur_max * window_size) + + return res + + return dfs(0) +``` + +```java +public class Solution { + public int maxSumAfterPartitioning(int[] arr, int k) { + return dfs(0, arr, k); + } + + private int dfs(int i, int[] arr, int k) { + if (i >= arr.length) { + return 0; + } + + int cur_max = 0; + int res = 0; + for (int j = i; j < Math.min(arr.length, i + k); j++) { + cur_max = Math.max(cur_max, arr[j]); + int window_size = j - i + 1; + res = Math.max(res, dfs(j + 1, arr, k) + cur_max * window_size); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxSumAfterPartitioning(vector& arr, int k) { + return dfs(0, arr, k); + } + +private: + int dfs(int i, vector& arr, int k) { + if (i >= arr.size()) { + return 0; + } + + int cur_max = 0, res = 0; + for (int j = i; j < min((int)arr.size(), i + k); j++) { + cur_max = max(cur_max, arr[j]); + int window_size = j - i + 1; + res = max(res, dfs(j + 1, arr, k) + cur_max * window_size); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ + maxSumAfterPartitioning(arr, k) { + const dfs = (i) => { + if (i >= arr.length) { + return 0; + } + + let cur_max = 0, + res = 0; + for (let j = i; j < Math.min(arr.length, i + k); j++) { + cur_max = Math.max(cur_max, arr[j]); + let window_size = j - i + 1; + res = Math.max(res, dfs(j + 1) + cur_max * window_size); + } + + return res; + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(k ^ n)$ +- Space complexity: $O(n)$ for recursion stack. + +> Where $k$ is the maximum length of the subarray and $n$ is the size of the array $arr$. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def maxSumAfterPartitioning(self, arr: List[int], k: int) -> int: + cache = { len(arr) : 0 } + + def dfs(i): + if i in cache: + return cache[i] + + cur_max = 0 + res = 0 + for j in range(i, min(len(arr), i + k)): + cur_max = max(cur_max, arr[j]) + window_size = j - i + 1 + res = max(res, dfs(j + 1) + cur_max * window_size) + + cache[i] = res + return res + + return dfs(0) +``` + +```java +public class Solution { + public int maxSumAfterPartitioning(int[] arr, int k) { + int[] cache = new int[arr.length + 1]; + Arrays.fill(cache, -1); + cache[arr.length] = 0; + return dfs(0, arr, k, cache); + } + + private int dfs(int i, int[] arr, int k, int[] cache) { + if (cache[i] != -1) { + return cache[i]; + } + + int cur_max = 0, res = 0; + for (int j = i; j < Math.min(arr.length, i + k); j++) { + cur_max = Math.max(cur_max, arr[j]); + int window_size = j - i + 1; + res = Math.max(res, dfs(j + 1, arr, k, cache) + cur_max * window_size); + } + + cache[i] = res; + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxSumAfterPartitioning(vector& arr, int k) { + vector cache(arr.size() + 1, -1); + cache[arr.size()] = 0; + return dfs(0, arr, k, cache); + } + +private: + int dfs(int i, vector& arr, int k, vector& cache) { + if (cache[i] != -1) { + return cache[i]; + } + + int cur_max = 0, res = 0; + for (int j = i; j < min((int)arr.size(), i + k); j++) { + cur_max = max(cur_max, arr[j]); + int window_size = j - i + 1; + res = max(res, dfs(j + 1, arr, k, cache) + cur_max * window_size); + } + + return cache[i] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ + maxSumAfterPartitioning(arr, k) { + const cache = new Array(arr.length + 1).fill(-1); + cache[arr.length] = 0; + + const dfs = (i) => { + if (cache[i] !== -1) { + return cache[i]; + } + + let cur_max = 0, + res = 0; + for (let j = i; j < Math.min(arr.length, i + k); j++) { + cur_max = Math.max(cur_max, arr[j]); + let window_size = j - i + 1; + res = Math.max(res, dfs(j + 1) + cur_max * window_size); + } + + return (cache[i] = res); + }; + + return dfs(0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * k)$ +- Space complexity: $O(n)$ + +> Where $k$ is the maximum length of the subarray and $n$ is the size of the array $arr$. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def maxSumAfterPartitioning(self, arr: List[int], k: int) -> int: + n = len(arr) + dp = [0] * (n + 1) + + for i in range(n - 1, -1, -1): + cur_max = 0 + for j in range(i, min(n, i + k)): + cur_max = max(cur_max, arr[j]) + window_size = j - i + 1 + dp[i] = max(dp[i], dp[j + 1] + cur_max * window_size) + + return dp[0] +``` + +```java +public class Solution { + public int maxSumAfterPartitioning(int[] arr, int k) { + int n = arr.length; + int[] dp = new int[n + 1]; + + for (int i = n - 1; i >= 0; i--) { + int cur_max = 0; + for (int j = i; j < Math.min(n, i + k); j++) { + cur_max = Math.max(cur_max, arr[j]); + int window_size = j - i + 1; + dp[i] = Math.max(dp[i], dp[j + 1] + cur_max * window_size); + } + } + + return dp[0]; + } +} +``` + +```cpp +class Solution { +public: + int maxSumAfterPartitioning(vector& arr, int k) { + int n = arr.size(); + vector dp(n + 1, 0); + + for (int i = n - 1; i >= 0; i--) { + int cur_max = 0; + for (int j = i; j < min(n, i + k); j++) { + cur_max = max(cur_max, arr[j]); + int window_size = j - i + 1; + dp[i] = max(dp[i], dp[j + 1] + cur_max * window_size); + } + } + + return dp[0]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ + maxSumAfterPartitioning(arr, k) { + let n = arr.length; + let dp = new Array(n + 1).fill(0); + + for (let i = n - 1; i >= 0; i--) { + let cur_max = 0; + for (let j = i; j < Math.min(n, i + k); j++) { + cur_max = Math.max(cur_max, arr[j]); + let window_size = j - i + 1; + dp[i] = Math.max(dp[i], dp[j + 1] + cur_max * window_size); + } + } + + return dp[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * k)$ +- Space complexity: $O(n)$ + +> Where $k$ is the maximum length of the subarray and $n$ is the size of the array $arr$. + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def maxSumAfterPartitioning(self, arr: List[int], k: int) -> int: + dp = [0] * k + dp[0] = arr[0] + + for i in range(1, len(arr)): + cur_max = 0 + max_at_i = 0 + for j in range(i, i - k, -1): + if j < 0: + break + cur_max = max(cur_max, arr[j]) + window_size = i - j + 1 + cur_sum = cur_max * window_size + sub_sum = dp[(j - 1) % k] if j > 0 else 0 + max_at_i = max(max_at_i, cur_sum + sub_sum) + + dp[i % k] = max_at_i + + return dp[(len(arr) - 1) % k] +``` + +```java +public class Solution { + public int maxSumAfterPartitioning(int[] arr, int k) { + int n = arr.length; + int[] dp = new int[k]; + dp[0] = arr[0]; + + for (int i = 1; i < n; i++) { + int cur_max = 0, max_at_i = 0; + for (int j = i; j > i - k; j--) { + if (j < 0) break; + cur_max = Math.max(cur_max, arr[j]); + int window_size = i - j + 1; + int cur_sum = cur_max * window_size; + int sub_sum = (j > 0) ? dp[(j - 1) % k] : 0; + max_at_i = Math.max(max_at_i, cur_sum + sub_sum); + } + dp[i % k] = max_at_i; + } + + return dp[(n - 1) % k]; + } +} +``` + +```cpp +class Solution { +public: + int maxSumAfterPartitioning(vector& arr, int k) { + int n = arr.size(); + vector dp(k); + dp[0] = arr[0]; + + for (int i = 1; i < n; i++) { + int cur_max = 0, max_at_i = 0; + for (int j = i; j > i - k; j--) { + if (j < 0) break; + cur_max = max(cur_max, arr[j]); + int window_size = i - j + 1; + int cur_sum = cur_max * window_size; + int sub_sum = (j > 0) ? dp[(j - 1) % k] : 0; + max_at_i = max(max_at_i, cur_sum + sub_sum); + } + dp[i % k] = max_at_i; + } + + return dp[(n - 1) % k]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @param {number} k + * @return {number} + */ + maxSumAfterPartitioning(arr, k) { + const n = arr.length; + const dp = new Array(k).fill(0); + dp[0] = arr[0]; + + for (let i = 1; i < n; i++) { + let cur_max = 0, + max_at_i = 0; + for (let j = i; j > i - k; j--) { + if (j < 0) break; + cur_max = Math.max(cur_max, arr[j]); + let window_size = i - j + 1; + let cur_sum = cur_max * window_size; + let sub_sum = j > 0 ? dp[(j - 1) % k] : 0; + max_at_i = Math.max(max_at_i, cur_sum + sub_sum); + } + dp[i % k] = max_at_i; + } + + return dp[(n - 1) % k]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * k)$ +- Space complexity: $O(k)$ + +> Where $k$ is the maximum length of the subarray and $n$ is the size of the array $arr$. diff --git a/articles/partition-equal-subset-sum.md b/articles/partition-equal-subset-sum.md index d51654692..d95805dc9 100644 --- a/articles/partition-equal-subset-sum.md +++ b/articles/partition-equal-subset-sum.md @@ -7,15 +7,15 @@ class Solution: def canPartition(self, nums: List[int]) -> bool: if sum(nums) % 2: return False - + def dfs(i, target): if i >= len(nums): return target == 0 if target < 0: return False - + return dfs(i + 1, target) or dfs(i + 1, target - nums[i]) - + return dfs(0, sum(nums) // 2) ``` @@ -30,7 +30,7 @@ public class Solution { if (sum % 2 != 0) { return false; } - + return dfs(nums, 0, sum / 2); } @@ -42,7 +42,7 @@ public class Solution { return false; } - return dfs(nums, i + 1, target) || + return dfs(nums, i + 1, target) || dfs(nums, i + 1, target - nums[i]); } } @@ -59,7 +59,7 @@ public: if (sum % 2 != 0) { return false; } - + return dfs(nums, 0, sum / 2); } @@ -71,7 +71,7 @@ public: return false; } - return dfs(nums, i + 1, target) || + return dfs(nums, i + 1, target) || dfs(nums, i + 1, target - nums[i]); } }; @@ -88,7 +88,7 @@ class Solution { if (sum % 2 !== 0) { return false; } - + return this.dfs(nums, 0, sum / 2); } @@ -106,8 +106,10 @@ class Solution { return false; } - return this.dfs(nums, i + 1, target) || - this.dfs(nums, i + 1, target - nums[i]); + return ( + this.dfs(nums, i + 1, target) || + this.dfs(nums, i + 1, target - nums[i]) + ); } } ``` @@ -122,7 +124,7 @@ public class Solution { if (sum % 2 != 0) { return false; } - + return Dfs(nums, 0, sum / 2); } @@ -134,7 +136,7 @@ public class Solution { return false; } - return Dfs(nums, i + 1, target) || + return Dfs(nums, i + 1, target) || Dfs(nums, i + 1, target - nums[i]); } } @@ -149,9 +151,9 @@ func canPartition(nums []int) bool { if sum%2 != 0 { return false } - + target := sum / 2 - + var dfs func(int, int) bool dfs = func(i int, target int) bool { if target == 0 { @@ -160,10 +162,10 @@ func canPartition(nums []int) bool { if i >= len(nums) || target < 0 { return false } - + return dfs(i+1, target) || dfs(i+1, target-nums[i]) } - + return dfs(0, target) } ``` @@ -175,9 +177,9 @@ class Solution { if (sum % 2 != 0) { return false } - + val target = sum / 2 - + fun dfs(i: Int, target: Int): Boolean { if (target == 0) { return true @@ -185,10 +187,37 @@ class Solution { if (i >= nums.size || target < 0) { return false } - + + return dfs(i + 1, target) || dfs(i + 1, target - nums[i]) + } + + return dfs(0, target) + } +} +``` + +```swift +class Solution { + func canPartition(_ nums: [Int]) -> Bool { + let totalSum = nums.reduce(0, +) + if totalSum % 2 != 0 { + return false + } + + let target = totalSum / 2 + let n = nums.count + + func dfs(_ i: Int, _ target: Int) -> Bool { + if i >= n { + return target == 0 + } + if target < 0 { + return false + } + return dfs(i + 1, target) || dfs(i + 1, target - nums[i]) } - + return dfs(0, target) } } @@ -198,8 +227,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -213,7 +242,7 @@ class Solution: total = sum(nums) if total % 2 != 0: return False - + target = total // 2 n = len(nums) memo = [[-1] * (target + 1) for _ in range(n + 1)] @@ -225,8 +254,8 @@ class Solution: return False if memo[i][target] != -1: return memo[i][target] - - memo[i][target] = (dfs(i + 1, target) or + + memo[i][target] = (dfs(i + 1, target) or dfs(i + 1, target - nums[i])) return memo[i][target] @@ -246,7 +275,7 @@ public class Solution { return false; } memo = new Boolean[n][sum / 2 + 1]; - + return dfs(nums, 0, sum / 2); } @@ -261,7 +290,7 @@ public class Solution { return memo[i][target]; } - memo[i][target] = dfs(nums, i + 1, target) || + memo[i][target] = dfs(nums, i + 1, target) || dfs(nums, i + 1, target - nums[i]); return memo[i][target]; } @@ -281,7 +310,7 @@ public: return false; } memo.resize(nums.size(), vector(sum / 2 + 1, -1)); - + return dfs(nums, 0, sum / 2); } @@ -296,7 +325,7 @@ public: return memo[i][target]; } - memo[i][target] = dfs(nums, i + 1, target) || + memo[i][target] = dfs(nums, i + 1, target) || dfs(nums, i + 1, target - nums[i]); return memo[i][target]; } @@ -315,9 +344,10 @@ class Solution { return false; } const n = nums.length; - this.memo = Array.from(Array(n + 1), () => - Array(sum / 2 + 1).fill(null)); - + this.memo = Array.from(Array(n + 1), () => + Array(sum / 2 + 1).fill(null), + ); + return this.dfs(nums, 0, sum / 2); } @@ -338,8 +368,9 @@ class Solution { return this.memo[i][target]; } - this.memo[i][target] = this.dfs(nums, i + 1, target) || - this.dfs(nums, i + 1, target - nums[i]); + this.memo[i][target] = + this.dfs(nums, i + 1, target) || + this.dfs(nums, i + 1, target - nums[i]); return this.memo[i][target]; } } @@ -373,7 +404,7 @@ public class Solution { return memo[i, target] == true; } - bool result = Dfs(nums, i + 1, target) || + bool result = Dfs(nums, i + 1, target) || Dfs(nums, i + 1, target - nums[i]); memo[i, target] = result; @@ -391,7 +422,7 @@ func canPartition(nums []int) bool { if total%2 != 0 { return false } - + target := total / 2 n := len(nums) memo := make([][]int, n+1) @@ -413,14 +444,14 @@ func canPartition(nums []int) bool { if memo[i][target] != -1 { return memo[i][target] == 1 } - + found := dfs(i+1, target) || dfs(i+1, target-nums[i]) if found { memo[i][target] = 1 } else { memo[i][target] = 0 } - + return found } @@ -433,7 +464,7 @@ class Solution { fun canPartition(nums: IntArray): Boolean { val total = nums.sum() if (total % 2 != 0) return false - + val target = total / 2 val n = nums.size val memo = Array(n + 1) { IntArray(target + 1) { -1 } } @@ -442,10 +473,10 @@ class Solution { if (target == 0) return true if (i >= n || target < 0) return false if (memo[i][target] != -1) return memo[i][target] == 1 - + val found = dfs(i + 1, target) || dfs(i + 1, target - nums[i]) memo[i][target] = if (found) 1 else 0 - + return found } @@ -454,12 +485,45 @@ class Solution { } ``` +```swift +class Solution { + func canPartition(_ nums: [Int]) -> Bool { + let total = nums.reduce(0, +) + if total % 2 != 0 { + return false + } + + let target = total / 2 + let n = nums.count + var memo = Array(repeating: Array(repeating: -1, count: target + 1), count: n + 1) + + func dfs(_ i: Int, _ target: Int) -> Bool { + if target == 0 { + return true + } + if i >= n || target < 0 { + return false + } + if memo[i][target] != -1 { + return memo[i][target] == 1 + } + + let result = dfs(i + 1, target) || dfs(i + 1, target - nums[i]) + memo[i][target] = result ? 1 : 0 + return result + } + + return dfs(0, target) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * target)$ -* Space complexity: $O(n * target)$ +- Time complexity: $O(n * target)$ +- Space complexity: $O(n * target)$ > Where $n$ is the length of the array $nums$ and $target$ is the sum of array elements divided by 2. @@ -486,7 +550,7 @@ class Solution: for i in range(1, n + 1): for j in range(1, target + 1): if nums[i - 1] <= j: - dp[i][j] = (dp[i - 1][j] or + dp[i][j] = (dp[i - 1][j] or dp[i - 1][j - nums[i - 1]]) else: dp[i][j] = dp[i - 1][j] @@ -505,7 +569,7 @@ public class Solution { if (sum % 2 != 0) { return false; } - + int target = sum / 2; boolean[][] dp = new boolean[n + 1][target + 1]; @@ -516,7 +580,7 @@ public class Solution { for (int i = 1; i <= n; i++) { for (int j = 1; j <= target; j++) { if (nums[i - 1] <= j) { - dp[i][j] = dp[i - 1][j] || + dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]]; } else { dp[i][j] = dp[i - 1][j]; @@ -540,19 +604,19 @@ public: if (sum % 2 != 0) { return false; } - + int target = sum / 2; int n = nums.size(); vector> dp(n + 1, vector(target + 1, false)); - + for (int i = 0; i <= n; i++) { - dp[i][0] = true; + dp[i][0] = true; } for (int i = 1; i <= n; i++) { for (int j = 1; j <= target; j++) { if (nums[i - 1] <= j) { - dp[i][j] = dp[i - 1][j] || + dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]]; } else { dp[i][j] = dp[i - 1][j]; @@ -579,25 +643,25 @@ class Solution { const target = sum / 2; const n = nums.length; - const dp = Array.from(Array(n + 1), () => - Array(target + 1).fill(false)); + const dp = Array.from(Array(n + 1), () => + Array(target + 1).fill(false), + ); for (let i = 0; i <= n; i++) { - dp[i][0] = true; + dp[i][0] = true; } for (let i = 1; i <= n; i++) { for (let j = 1; j <= target; j++) { if (nums[i - 1] <= j) { - dp[i][j] = dp[i - 1][j] || - dp[i - 1][j - nums[i - 1]]; + dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]]; } else { dp[i][j] = dp[i - 1][j]; } } } - return dp[n][target]; + return dp[n][target]; } } ``` @@ -625,7 +689,7 @@ public class Solution { for (int i = 1; i <= n; i++) { for (int j = 1; j <= target; j++) { if (nums[i - 1] <= j) { - dp[i, j] = dp[i - 1, j] || + dp[i, j] = dp[i - 1, j] || dp[i - 1, j - nums[i - 1]]; } else { dp[i, j] = dp[i - 1, j]; @@ -633,7 +697,7 @@ public class Solution { } } - return dp[n, target]; + return dp[n, target]; } } ``` @@ -702,12 +766,43 @@ class Solution { } ``` +```swift +class Solution { + func canPartition(_ nums: [Int]) -> Bool { + let total = nums.reduce(0, +) + if total % 2 != 0 { + return false + } + + let target = total / 2 + let n = nums.count + var dp = Array(repeating: Array(repeating: false, count: target + 1), count: n + 1) + + for i in 0...n { + dp[i][0] = true + } + + for i in 1...n { + for j in 1...target { + if nums[i - 1] <= j { + dp[i][j] = dp[i - 1][j] || dp[i - 1][j - nums[i - 1]] + } else { + dp[i][j] = dp[i - 1][j] + } + } + } + + return dp[n][target] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * target)$ -* Space complexity: $O(n * target)$ +- Time complexity: $O(n * target)$ +- Space complexity: $O(n * target)$ > Where $n$ is the length of the array $nums$ and $target$ is the sum of array elements divided by 2. @@ -727,7 +822,7 @@ class Solution: dp = [False] * (target + 1) nextDp = [False] * (target + 1) - dp[0] = True + dp[0] = True for i in range(len(nums)): for j in range(1, target + 1): if j >= nums[i]: @@ -735,7 +830,7 @@ class Solution: else: nextDp[j] = dp[j] dp, nextDp = nextDp, dp - + return dp[target] ``` @@ -763,7 +858,7 @@ public class Solution { dp = nextDp; nextDp = temp; } - + return dp[target]; } @@ -800,7 +895,7 @@ public: } swap(dp, nextDp); } - + return dp[target]; } @@ -841,7 +936,7 @@ class Solution { } [dp, nextDp] = [nextDp, dp]; } - + return dp[target]; } } @@ -871,7 +966,7 @@ public class Solution { dp = nextDp; nextDp = temp; } - + return dp[target]; } @@ -940,12 +1035,40 @@ class Solution { } ``` +```swift +class Solution { + func canPartition(_ nums: [Int]) -> Bool { + if nums.reduce(0, +) % 2 != 0 { + return false + } + + let target = nums.reduce(0, +) / 2 + var dp = Array(repeating: false, count: target + 1) + var nextDp = Array(repeating: false, count: target + 1) + + dp[0] = true + for num in nums { + for j in stride(from: target, through: 1, by: -1) { + if j >= num { + nextDp[j] = dp[j] || dp[j - num] + } else { + nextDp[j] = dp[j] + } + } + swap(&dp, &nextDp) + } + + return dp[target] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * target)$ -* Space complexity: $O(target)$ +- Time complexity: $O(n * target)$ +- Space complexity: $O(target)$ > Where $n$ is the length of the array $nums$ and $target$ is the sum of array elements divided by 2. @@ -1147,12 +1270,38 @@ class Solution { } ``` +```swift +class Solution { + func canPartition(_ nums: [Int]) -> Bool { + if nums.reduce(0, +) % 2 != 0 { + return false + } + + var dp: Set = [0] + let target = nums.reduce(0, +) / 2 + + for i in stride(from: nums.count - 1, through: 0, by: -1) { + var nextDP: Set = [] + for t in dp { + if t + nums[i] == target { + return true + } + nextDP.insert(t + nums[i]) + nextDP.insert(t) + } + dp = nextDP + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * target)$ -* Space complexity: $O(target)$ +- Time complexity: $O(n * target)$ +- Space complexity: $O(target)$ > Where $n$ is the length of the array $nums$ and $target$ is the sum of array elements divided by 2. @@ -1175,7 +1324,7 @@ class Solution: for num in nums: for j in range(target, num - 1, -1): dp[j] = dp[j] or dp[j - num] - + return dp[target] ``` @@ -1195,7 +1344,7 @@ public class Solution { dp[j] = dp[j] || dp[j - nums[i]]; } } - + return dp[target]; } @@ -1226,7 +1375,7 @@ public: dp[j] = dp[j] || dp[j - nums[i]]; } } - + return dp[target]; } @@ -1261,7 +1410,7 @@ class Solution { dp[j] = dp[j] || dp[j - nums[i]]; } } - + return dp[target]; } } @@ -1283,7 +1432,7 @@ public class Solution { dp[j] = dp[j] || dp[j - nums[i]]; } } - + return dp[target]; } @@ -1342,12 +1491,34 @@ class Solution { } ``` +```swift +class Solution { + func canPartition(_ nums: [Int]) -> Bool { + if nums.reduce(0, +) % 2 != 0 { + return false + } + + let target = nums.reduce(0, +) / 2 + var dp = Array(repeating: false, count: target + 1) + + dp[0] = true + for num in nums { + for j in stride(from: target, through: num, by: -1) { + dp[j] = dp[j] || dp[j - num] + } + } + + return dp[target] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * target)$ -* Space complexity: $O(target)$ +- Time complexity: $O(n * target)$ +- Space complexity: $O(target)$ > Where $n$ is the length of the array $nums$ and $target$ is the sum of array elements divided by 2. @@ -1366,10 +1537,10 @@ class Solution: target = total // 2 dp = 1 << 0 - + for num in nums: dp |= dp << num - + return (dp & (1 << target)) != 0 ``` @@ -1384,9 +1555,9 @@ public: if (sum % 2 != 0) { return false; } - + int target = sum / 2; - bitset<10001> dp; + bitset<10001> dp; dp[0] = 1; for (int num : nums) { @@ -1402,7 +1573,7 @@ public: ### Time & Space Complexity -* Time complexity: $O(n * target)$ -* Space complexity: $O(target)$ +- Time complexity: $O(n * target)$ +- Space complexity: $O(target)$ -> Where $n$ is the length of the array $nums$ and $target$ is the sum of array elements divided by 2. \ No newline at end of file +> Where $n$ is the length of the array $nums$ and $target$ is the sum of array elements divided by 2. diff --git a/articles/partition-labels.md b/articles/partition-labels.md index 5eb089e85..75d799b9d 100644 --- a/articles/partition-labels.md +++ b/articles/partition-labels.md @@ -8,7 +8,7 @@ class Solution: lastIndex = {} for i, c in enumerate(s): lastIndex[c] = i - + res = [] size = end = 0 for i, c in enumerate(s): @@ -28,7 +28,7 @@ public class Solution { for (int i = 0; i < s.length(); i++) { lastIndex.put(s.charAt(i), i); } - + List res = new ArrayList<>(); int size = 0, end = 0; for (int i = 0; i < s.length(); i++) { @@ -83,7 +83,8 @@ class Solution { } let res = []; - let size = 0, end = 0; + let size = 0, + end = 0; for (let i = 0; i < S.length; i++) { size++; end = Math.max(end, lastIndex[S[i]]); @@ -169,11 +170,36 @@ class Solution { } ``` +```swift +class Solution { + func partitionLabels(_ s: String) -> [Int] { + var lastIndex = [Character: Int]() + for (i, c) in s.enumerated() { + lastIndex[c] = i + } + + var res = [Int]() + var size = 0 + var end = 0 + for (i, c) in s.enumerated() { + size += 1 + end = max(end, lastIndex[c]!) + + if i == end { + res.append(size) + size = 0 + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n)$ +- Space complexity: $O(m)$ -> Where $n$ is the length of the string $s$ and $m$ is the number of unique characters in the string $s$. \ No newline at end of file +> Where $n$ is the length of the string $s$ and $m$ is the number of unique characters in the string $s$. diff --git a/articles/partition-list.md b/articles/partition-list.md new file mode 100644 index 000000000..791ef3c05 --- /dev/null +++ b/articles/partition-list.md @@ -0,0 +1,327 @@ +## 1. Brute Force + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]: + if not head: + return None + + less, greater = [], [] + cur = head + while cur: + if cur.val < x: + less.append(cur.val) + else: + greater.append(cur.val) + cur = cur.next + + cur = head + for val in less: + cur.val = val + cur = cur.next + + for val in greater: + cur.val = val + cur = cur.next + + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode partition(ListNode head, int x) { + if (head == null) { + return null; + } + + List less = new ArrayList<>(); + List greater = new ArrayList<>(); + ListNode cur = head; + + while (cur != null) { + if (cur.val < x) { + less.add(cur.val); + } else { + greater.add(cur.val); + } + cur = cur.next; + } + + cur = head; + for (int val : less) { + cur.val = val; + cur = cur.next; + } + + for (int val : greater) { + cur.val = val; + cur = cur.next; + } + + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* partition(ListNode* head, int x) { + if (!head) return nullptr; + + vector less, greater; + ListNode* cur = head; + + while (cur) { + if (cur->val < x) { + less.push_back(cur->val); + } else { + greater.push_back(cur->val); + } + cur = cur->next; + } + + cur = head; + for (int val : less) { + cur->val = val; + cur = cur->next; + } + + for (int val : greater) { + cur->val = val; + cur = cur->next; + } + + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} x + * @return {ListNode} + */ + partition(head, x) { + if (!head) return null; + + let less = [], + greater = []; + let cur = head; + + while (cur) { + if (cur.val < x) { + less.push(cur.val); + } else { + greater.push(cur.val); + } + cur = cur.next; + } + + cur = head; + for (let val of less) { + cur.val = val; + cur = cur.next; + } + + for (let val of greater) { + cur.val = val; + cur = cur.next; + } + + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Two Pointers + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def partition(self, head: Optional[ListNode], x: int) -> Optional[ListNode]: + left, right = ListNode(), ListNode() + ltail, rtail = left, right + + while head: + if head.val < x: + ltail.next = head + ltail = ltail.next + else: + rtail.next = head + rtail = rtail.next + head = head.next + + ltail.next = right.next + rtail.next = None + return left.next +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode partition(ListNode head, int x) { + ListNode left = new ListNode(0), right = new ListNode(0); + ListNode ltail = left, rtail = right; + + while (head != null) { + if (head.val < x) { + ltail.next = head; + ltail = ltail.next; + } else { + rtail.next = head; + rtail = rtail.next; + } + head = head.next; + } + + ltail.next = right.next; + rtail.next = null; + return left.next; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* partition(ListNode* head, int x) { + ListNode leftDummy(0), rightDummy(0); + ListNode *ltail = &leftDummy, *rtail = &rightDummy; + + while (head) { + if (head->val < x) { + ltail->next = head; + ltail = ltail->next; + } else { + rtail->next = head; + rtail = rtail->next; + } + head = head->next; + } + + ltail->next = rightDummy.next; + rtail->next = nullptr; + return leftDummy.next; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} x + * @return {ListNode} + */ + partition(head, x) { + let left = new ListNode(0), + right = new ListNode(0); + let ltail = left, + rtail = right; + + while (head) { + if (head.val < x) { + ltail.next = head; + ltail = ltail.next; + } else { + rtail.next = head; + rtail = rtail.next; + } + head = head.next; + } + + ltail.next = right.next; + rtail.next = null; + return left.next; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/partition-to-k-equal-sum-subsets.md b/articles/partition-to-k-equal-sum-subsets.md index 260fe7e37..e4311864a 100644 --- a/articles/partition-to-k-equal-sum-subsets.md +++ b/articles/partition-to-k-equal-sum-subsets.md @@ -132,12 +132,44 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanPartitionKSubsets(int[] nums, int k) { + int totalSum = nums.Sum(); + if (totalSum % k != 0) return false; + + int target = totalSum / k; + Array.Sort(nums); + Array.Reverse(nums); + + bool[] used = new bool[nums.Length]; + + bool Backtrack(int i, int kRemaining, int subsetSum) { + if (kRemaining == 0) return true; + if (subsetSum == target) return Backtrack(0, kRemaining - 1, 0); + + for (int j = i; j < nums.Length; j++) { + if (used[j] || subsetSum + nums[j] > target) continue; + + used[j] = true; + if (Backtrack(j + 1, kRemaining, subsetSum + nums[j])) return true; + used[j] = false; + } + + return false; + } + + return Backtrack(0, k, 0); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(k * 2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(k * 2 ^ n)$ +- Space complexity: $O(n)$ > Where $n$ is the size of the array $nums$ and $k$ is the number of subsets. @@ -279,7 +311,8 @@ class Solution { used[j] = true; if (backtrack(j + 1, k, subsetSum + nums[j])) return true; used[j] = false; - if (subsetSum === 0) { // Pruning + if (subsetSum === 0) { + // Pruning return false; } } @@ -291,12 +324,45 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanPartitionKSubsets(int[] nums, int k) { + int total = nums.Sum(); + if (total % k != 0) return false; + + Array.Sort(nums); + Array.Reverse(nums); + int target = total / k; + bool[] used = new bool[nums.Length]; + + bool Backtrack(int i, int kRemaining, int subsetSum) { + if (kRemaining == 0) return true; + if (subsetSum == target) return Backtrack(0, kRemaining - 1, 0); + + for (int j = i; j < nums.Length; j++) { + if (used[j] || subsetSum + nums[j] > target) continue; + + used[j] = true; + if (Backtrack(j + 1, kRemaining, subsetSum + nums[j])) return true; + used[j] = false; + + if (subsetSum == 0) return false; // Pruning + } + + return false; + } + + return Backtrack(0, k, 0); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(k * 2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(k * 2 ^ n)$ +- Space complexity: $O(n)$ > Where $n$ is the size of the array $nums$ and $k$ is the number of subsets. @@ -442,14 +508,46 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanPartitionKSubsets(int[] nums, int k) { + int total = nums.Sum(); + if (total % k != 0) return false; + + Array.Sort(nums); + Array.Reverse(nums); + int target = total / k; + int n = nums.Length; + + bool Backtrack(int i, int kRemaining, int subsetSum, int mask) { + if (kRemaining == 0) return true; + if (subsetSum == target) return Backtrack(0, kRemaining - 1, 0, mask); + + for (int j = i; j < n; j++) { + if ((mask & (1 << j)) == 0 || subsetSum + nums[j] > target) continue; + + if (Backtrack(j + 1, kRemaining, subsetSum + nums[j], mask ^ (1 << j))) + return true; + + if (subsetSum == 0) return false; + } + + return false; + } + + return Backtrack(0, k, 0, (1 << n) - 1); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(k * 2 ^ n)$ -* Space complexity: - * $O(1)$ or $O(n)$ space depending on the sorting algorithm. - * $O(n)$ for the recursion stack. +- Time complexity: $O(k * 2 ^ n)$ +- Space complexity: + - $O(1)$ or $O(n)$ space depending on the sorting algorithm. + - $O(n)$ for the recursion stack. > Where $n$ is the size of the array $nums$ and $k$ is the number of subsets. @@ -641,12 +739,59 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanPartitionKSubsets(int[] nums, int k) { + int total = nums.Sum(); + if (total % k != 0) return false; + + Array.Sort(nums); + Array.Reverse(nums); + + int target = total / k; + int n = nums.Length; + bool?[] dp = new bool?[1 << n]; + + bool Backtrack(int i, int kRemaining, int subsetSum, int mask) { + if (dp[mask].HasValue) return (bool)dp[mask]; + if (kRemaining == 0) { + dp[mask] = true; + return true; + } + if (subsetSum == target) { + dp[mask] = Backtrack(0, kRemaining - 1, 0, mask); + return (bool)dp[mask]; + } + + for (int j = i; j < n; j++) { + if ((mask & (1 << j)) == 0 || subsetSum + nums[j] > target) continue; + + if (Backtrack(j + 1, kRemaining, subsetSum + nums[j], mask ^ (1 << j))) { + dp[mask] = true; + return true; + } + + if (subsetSum == 0) { + dp[mask] = false; + return false; + } + } + + dp[mask] = false; + return false; + } + + return Backtrack(0, k, 0, (1 << n) - 1); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(2 ^ n)$ +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: $O(2 ^ n)$ --- @@ -764,9 +909,38 @@ class Solution { } ``` +```csharp +public class Solution { + public bool CanPartitionKSubsets(int[] nums, int k) { + int total = nums.Sum(); + if (total % k != 0) return false; + + int target = total / k; + int n = nums.Length; + int N = 1 << n; + int[] dp = new int[N]; + for (int i = 1; i < N; i++) { + dp[i] = -1; + } + + for (int mask = 0; mask < N; mask++) { + if (dp[mask] == -1) continue; + for (int i = 0; i < n; i++) { + if ((mask & (1 << i)) == 0 && dp[mask] + nums[i] <= target) { + int nextMask = mask | (1 << i); + dp[nextMask] = (dp[mask] + nums[i]) % target; + } + } + } + + return dp[N - 1] == 0; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(2 ^ n)$ \ No newline at end of file +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: $O(2 ^ n)$ diff --git a/articles/pascals-triangle-ii.md b/articles/pascals-triangle-ii.md index 5a675a025..ffc0c7b7b 100644 --- a/articles/pascals-triangle-ii.md +++ b/articles/pascals-triangle-ii.md @@ -49,7 +49,7 @@ public: curRow.push_back(prevRow[i - 1] + prevRow[i]); } - curRow.push_back(1); + curRow.push_back(1); return curRow; } }; @@ -81,8 +81,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -139,7 +139,9 @@ class Solution { * @return {number[]} */ getRow(rowIndex) { - const res = Array.from({ length: rowIndex + 1 }, (_, i) => Array(i + 1).fill(1)); + const res = Array.from({ length: rowIndex + 1 }, (_, i) => + Array(i + 1).fill(1), + ); for (let i = 2; i <= rowIndex; i++) { for (let j = 1; j < i; j++) { res[i][j] = res[i - 1][j - 1] + res[i - 1][j]; @@ -154,8 +156,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -237,8 +239,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -307,8 +309,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -360,7 +362,9 @@ class Solution { getRow(rowIndex) { const row = [1]; for (let i = 1; i <= rowIndex; i++) { - row.push(Math.floor(row[row.length - 1] * (rowIndex - i + 1) / i)); + row.push( + Math.floor((row[row.length - 1] * (rowIndex - i + 1)) / i), + ); } return row; } @@ -371,5 +375,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/pascals-triangle.md b/articles/pascals-triangle.md index 2254d3bbf..2579a5220 100644 --- a/articles/pascals-triangle.md +++ b/articles/pascals-triangle.md @@ -77,12 +77,30 @@ class Solution { } ``` +```csharp +public class Solution { + public List> Generate(int numRows) { + var res = new List>(); + for (int n = 0; n < numRows; n++) { + var row = new List { 1 }; + int val = 1; + for (int k = 1; k <= n; k++) { + val = val * (n - k + 1) / k; + row.Add(val); + } + res.Add(row); + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -133,7 +151,7 @@ class Solution { public: vector> generate(int numRows) { vector> res = {{1}}; - + for (int i = 0; i < numRows - 1; i++) { vector temp = {0}; temp.insert(temp.end(), res.back().begin(), res.back().end()); @@ -171,12 +189,38 @@ class Solution { } ``` +```csharp +public class Solution { + public List> Generate(int numRows) { + var res = new List>(); + if (numRows <= 0) return res; + + res.Add(new List { 1 }); + + for (int i = 1; i < numRows; i++) { + var prev = res[i - 1]; + var temp = new List(prev); + temp.Insert(0, 0); + temp.Add(0); + + var row = new List(); + for (int j = 0; j < prev.Count + 1; j++) { + row.Add(temp[j] + temp[j + 1]); + } + res.Add(row); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -240,7 +284,9 @@ class Solution { * @return {number[][]} */ generate(numRows) { - let res = Array.from({ length: numRows }, (_, i) => Array(i + 1).fill(1)); + let res = Array.from({ length: numRows }, (_, i) => + Array(i + 1).fill(1), + ); for (let i = 2; i < numRows; i++) { for (let j = 1; j < i; j++) { @@ -252,9 +298,29 @@ class Solution { } ``` +```csharp +public class Solution { + public List> Generate(int numRows) { + var res = new List>(); + for (int i = 0; i < numRows; i++) { + var row = new List(); + for (int j = 0; j <= i; j++) { + if (j == 0 || j == i) { + row.Add(1); + } else { + row.Add(res[i - 1][j - 1] + res[i - 1][j]); + } + } + res.Add(row); + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ \ No newline at end of file +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ diff --git a/articles/path-crossing.md b/articles/path-crossing.md index dd4abbaf2..958c7eb5c 100644 --- a/articles/path-crossing.md +++ b/articles/path-crossing.md @@ -11,7 +11,7 @@ class Solution: 'E': [1, 0], 'W': [-1, 0] } - + visit = set() x, y = 0, 0 @@ -55,18 +55,18 @@ public: unordered_set visit; int x = 0, y = 0; visit.insert(to_string(x) + "," + to_string(y)); - + for (char c : path) { if (c == 'N') y++; else if (c == 'S') y--; else if (c == 'E') x++; else if (c == 'W') x--; - + string pos = to_string(x) + "," + to_string(y); if (visit.count(pos)) return true; visit.insert(pos); } - + return false; } }; @@ -80,7 +80,8 @@ class Solution { */ isPathCrossing(path) { const visit = new Set(); - let x = 0, y = 0; + let x = 0, + y = 0; visit.add(`${x},${y}`); for (const c of path) { @@ -103,8 +104,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -162,7 +163,7 @@ public class Solution { } private long hash(long x, long y) { - return (x << 32) + y; + return (x << 32) + y; } } ``` @@ -206,7 +207,8 @@ class Solution { */ isPathCrossing(path) { const visit = new Set(); - let x = 0, y = 0; + let x = 0, + y = 0; visit.add(this.hash(x, y)); for (const c of path) { @@ -238,5 +240,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/path-sum.md b/articles/path-sum.md new file mode 100644 index 000000000..27da53c1e --- /dev/null +++ b/articles/path-sum.md @@ -0,0 +1,583 @@ +## 1. Depth First Search - I + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: + def dfs(node, curSum): + if not node: + return False + + curSum += node.val + if not node.left and not node.right: + return curSum == targetSum + + return dfs(node.left, curSum) or dfs(node.right, curSum) + + return dfs(root, 0) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean hasPathSum(TreeNode root, int targetSum) { + return dfs(root, 0, targetSum); + } + + private boolean dfs(TreeNode node, int curSum, int targetSum) { + if (node == null) return false; + + curSum += node.val; + if (node.left == null && node.right == null) { + return curSum == targetSum; + } + + return dfs(node.left, curSum, targetSum) || dfs(node.right, curSum, targetSum); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool hasPathSum(TreeNode* root, int targetSum) { + return dfs(root, 0, targetSum); + } + +private: + bool dfs(TreeNode* node, int curSum, int targetSum) { + if (node == nullptr) return false; + + curSum += node->val; + if (node->left == nullptr && node->right == nullptr) { + return curSum == targetSum; + } + + return dfs(node->left, curSum, targetSum) || dfs(node->right, curSum, targetSum); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} targetSum + * @return {boolean} + */ + hasPathSum(root, targetSum) { + const dfs = (node, curSum) => { + if (!node) return false; + + curSum += node.val; + if (!node.left && !node.right) { + return curSum === targetSum; + } + + return dfs(node.left, curSum) || dfs(node.right, curSum); + }; + + return dfs(root, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Depth First Search - II + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: + if not root: + return False + + targetSum -= root.val + return (self.hasPathSum(root.left, targetSum) or + self.hasPathSum(root.right, targetSum) or + (not targetSum and not root.left and not root.right)) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean hasPathSum(TreeNode root, int targetSum) { + if (root == null) return false; + targetSum -= root.val; + return hasPathSum(root.left, targetSum) || + hasPathSum(root.right, targetSum) || + (targetSum == 0 && root.left == null && root.right == null); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool hasPathSum(TreeNode* root, int targetSum) { + if (!root) return false; + targetSum -= root->val; + return hasPathSum(root->left, targetSum) || + hasPathSum(root->right, targetSum) || + (targetSum == 0 && !root->left && !root->right); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} targetSum + * @return {boolean} + */ + hasPathSum(root, targetSum) { + if (!root) return false; + targetSum -= root.val; + return ( + this.hasPathSum(root.left, targetSum) || + this.hasPathSum(root.right, targetSum) || + (targetSum === 0 && !root.left && !root.right) + ); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: + if not root: + return False + + stack = [(root, targetSum - root.val)] + while stack: + node, curr_sum = stack.pop() + if not node.left and not node.right and curr_sum == 0: + return True + if node.right: + stack.append((node.right, curr_sum - node.right.val)) + if node.left: + stack.append((node.left, curr_sum - node.left.val)) + return False +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean hasPathSum(TreeNode root, int targetSum) { + if (root == null) return false; + + Stack stack = new Stack<>(); + Stack sumStack = new Stack<>(); + stack.push(root); + sumStack.push(targetSum - root.val); + + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + int currSum = sumStack.pop(); + + if (node.left == null && node.right == null && currSum == 0) { + return true; + } + + if (node.right != null) { + stack.push(node.right); + sumStack.push(currSum - node.right.val); + } + + if (node.left != null) { + stack.push(node.left); + sumStack.push(currSum - node.left.val); + } + } + + return false; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool hasPathSum(TreeNode* root, int targetSum) { + if (!root) return false; + + stack> s; + s.push({root, targetSum - root->val}); + + while (!s.empty()) { + auto [node, currSum] = s.top(); + s.pop(); + + if (!node->left && !node->right && currSum == 0) { + return true; + } + + if (node->right) { + s.push({node->right, currSum - node->right->val}); + } + + if (node->left) { + s.push({node->left, currSum - node->left->val}); + } + } + + return false; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} targetSum + * @return {boolean} + */ + hasPathSum(root, targetSum) { + if (!root) return false; + + const stack = [[root, targetSum - root.val]]; + while (stack.length) { + const [node, currSum] = stack.pop(); + + if (!node.left && !node.right && currSum === 0) { + return true; + } + + if (node.right) { + stack.push([node.right, currSum - node.right.val]); + } + + if (node.left) { + stack.push([node.left, currSum - node.left.val]); + } + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def hasPathSum(self, root: Optional[TreeNode], targetSum: int) -> bool: + if not root: + return False + + queue = deque([(root, targetSum - root.val)]) + while queue: + node, curr_sum = queue.popleft() + if not node.left and not node.right and curr_sum == 0: + return True + if node.left: + queue.append((node.left, curr_sum - node.left.val)) + if node.right: + queue.append((node.right, curr_sum - node.right.val)) + return False +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean hasPathSum(TreeNode root, int targetSum) { + if (root == null) return false; + + Queue nodeQueue = new LinkedList<>(); + Queue sumQueue = new LinkedList<>(); + nodeQueue.add(root); + sumQueue.add(targetSum - root.val); + + while (!nodeQueue.isEmpty()) { + TreeNode node = nodeQueue.poll(); + int currSum = sumQueue.poll(); + + if (node.left == null && node.right == null && currSum == 0) { + return true; + } + + if (node.left != null) { + nodeQueue.add(node.left); + sumQueue.add(currSum - node.left.val); + } + + if (node.right != null) { + nodeQueue.add(node.right); + sumQueue.add(currSum - node.right.val); + } + } + + return false; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool hasPathSum(TreeNode* root, int targetSum) { + if (!root) return false; + + queue> q; + q.push({root, targetSum - root->val}); + + while (!q.empty()) { + auto [node, currSum] = q.front(); + q.pop(); + + if (!node->left && !node->right && currSum == 0) { + return true; + } + + if (node->left) { + q.push({node->left, currSum - node->left->val}); + } + + if (node->right) { + q.push({node->right, currSum - node->right->val}); + } + } + + return false; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} targetSum + * @return {boolean} + */ + hasPathSum(root, targetSum) { + if (!root) return false; + + const queue = new Queue([[root, targetSum - root.val]]); + while (!queue.isEmpty()) { + const [node, currSum] = queue.pop(); + + if (!node.left && !node.right && currSum === 0) { + return true; + } + + if (node.left) { + queue.push([node.left, currSum - node.left.val]); + } + + if (node.right) { + queue.push([node.right, currSum - node.right.val]); + } + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/path-with-maximum-gold.md b/articles/path-with-maximum-gold.md new file mode 100644 index 000000000..928f239ea --- /dev/null +++ b/articles/path-with-maximum-gold.md @@ -0,0 +1,542 @@ +## 1. Backtracking (DFS) - I + +::tabs-start + +```python +class Solution: + def getMaximumGold(self, grid: list[list[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + + def dfs(r, c, visit): + if min(r, c) < 0 or r == ROWS or c == COLS or grid[r][c] == 0 or (r, c) in visit: + return 0 + + visit.add((r, c)) + res = grid[r][c] + + for dr, dc in directions: + res = max(res, grid[r][c] + dfs(r + dr, c + dc, visit)) + + visit.remove((r, c)) + return res + + res = 0 + for r in range(ROWS): + for c in range(COLS): + if grid[r][c] != 0: + res = max(res, dfs(r, c, set())) + return res +``` + +```java +public class Solution { + private int ROWS, COLS; + private int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + + public int getMaximumGold(int[][] grid) { + ROWS = grid.length; + COLS = grid[0].length; + int res = 0; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] != 0) { + res = Math.max(res, dfs(grid, r, c, new boolean[ROWS][COLS])); + } + } + } + return res; + } + + private int dfs(int[][] grid, int r, int c, boolean[][] visit) { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + grid[r][c] == 0 || visit[r][c]) { + return 0; + } + + visit[r][c] = true; + int res = grid[r][c]; + + for (int[] d : directions) { + res = Math.max(res, grid[r][c] + dfs(grid, r + d[0], c + d[1], visit)); + } + + visit[r][c] = false; + return res; + } +} +``` + +```cpp +class Solution { +public: + int ROWS, COLS; + vector> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + + int getMaximumGold(vector>& grid) { + ROWS = grid.size(); + COLS = grid[0].size(); + int res = 0; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] != 0) { + vector> visit(ROWS, vector(COLS, false)); + res = max(res, dfs(grid, r, c, visit)); + } + } + } + return res; + } + +private: + int dfs(vector>& grid, int r, int c, vector>& visit) { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == 0 || visit[r][c]) { + return 0; + } + + visit[r][c] = true; + int res = grid[r][c]; + + for (auto& d : directions) { + res = max(res, grid[r][c] + dfs(grid, r + d[0], c + d[1], visit)); + } + + visit[r][c] = false; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + getMaximumGold(grid) { + const ROWS = grid.length, + COLS = grid[0].length; + const directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; + + const dfs = (r, c, visit) => { + if ( + r < 0 || + c < 0 || + r >= ROWS || + c >= COLS || + grid[r][c] === 0 || + visit[r][c] + ) { + return 0; + } + + visit[r][c] = true; + let res = grid[r][c]; + + for (const [dr, dc] of directions) { + res = Math.max(res, grid[r][c] + dfs(r + dr, c + dc, visit)); + } + + visit[r][c] = false; + return res; + }; + + let res = 0; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] !== 0) { + let visit = Array.from({ length: ROWS }, () => + Array(COLS).fill(false), + ); + res = Math.max(res, dfs(r, c, visit)); + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(N * 3 ^ N)$ +- Space complexity: $O(N)$ + +> Where $N$ is the number of cells which contain gold. + +--- + +## 2. Backtracking (DFS) - II + +::tabs-start + +```python +class Solution: + def getMaximumGold(self, grid: list[list[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + + def dfs(r, c): + if min(r, c) < 0 or r == ROWS or c == COLS or grid[r][c] == 0: + return 0 + + gold = grid[r][c] + grid[r][c] = 0 + res = 0 + + for dr, dc in directions: + res = max(res, dfs(r + dr, c + dc)) + + grid[r][c] = gold + return gold + res + + res = 0 + for r in range(ROWS): + for c in range(COLS): + if grid[r][c] != 0: + res = max(res, dfs(r, c)) + return res +``` + +```java +public class Solution { + private int ROWS, COLS; + private int[][] directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + + public int getMaximumGold(int[][] grid) { + ROWS = grid.length; + COLS = grid[0].length; + int res = 0; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] != 0) { + res = Math.max(res, dfs(grid, r, c)); + } + } + } + return res; + } + + private int dfs(int[][] grid, int r, int c) { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == 0) { + return 0; + } + + int gold = grid[r][c]; + grid[r][c] = 0; + int res = 0; + + for (int[] d : directions) { + res = Math.max(res, dfs(grid, r + d[0], c + d[1])); + } + + grid[r][c] = gold; + return gold + res; + } +} +``` + +```cpp +class Solution { +public: + int ROWS, COLS; + vector> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; + + int getMaximumGold(vector>& grid) { + ROWS = grid.size(); + COLS = grid[0].size(); + int res = 0; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] != 0) { + res = max(res, dfs(grid, r, c)); + } + } + } + return res; + } + +private: + int dfs(vector>& grid, int r, int c) { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] == 0) { + return 0; + } + + int gold = grid[r][c]; + grid[r][c] = 0; + int res = 0; + + for (auto& d : directions) { + res = max(res, dfs(grid, r + d[0], c + d[1])); + } + + grid[r][c] = gold; + return gold + res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + getMaximumGold(grid) { + const ROWS = grid.length, + COLS = grid[0].length; + const directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; + + const dfs = (r, c) => { + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || grid[r][c] === 0) { + return 0; + } + + let gold = grid[r][c]; + grid[r][c] = 0; + let res = 0; + + for (const [dr, dc] of directions) { + res = Math.max(res, dfs(r + dr, c + dc)); + } + + grid[r][c] = gold; + return gold + res; + }; + + let res = 0; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] !== 0) { + res = Math.max(res, dfs(r, c)); + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(N * 3 ^ N)$ +- Space complexity: $O(N)$ for recursion stack. + +> Where $N$ is the number of cells which contain gold. + +--- + +## 3. Backtracking (BFS) + +::tabs-start + +```python +class Solution: + def getMaximumGold(self, grid: list[list[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + directions = [1, 0, -1, 0, 1] + index = [[0] * COLS for _ in range(ROWS)] + idx = 0 + + for r in range(ROWS): + for c in range(COLS): + if grid[r][c] != 0: + index[r][c] = idx + idx += 1 + + res = 0 + for r in range(ROWS): + for c in range(COLS): + if grid[r][c] > 0: + q = deque([(r, c, grid[r][c], 1 << index[r][c])]) + while q: + row, col, gold, mask = q.popleft() + res = max(res, gold) + + for i in range(4): + nr, nc = row + directions[i], col + directions[i + 1] + if 0 <= nr < ROWS and 0 <= nc < COLS and grid[nr][nc] > 0: + idx = index[nr][nc] + if not (mask & (1 << idx)): + q.append((nr, nc, gold + grid[nr][nc], mask | (1 << idx))) + + return res +``` + +```java +public class Solution { + public int getMaximumGold(int[][] grid) { + int ROWS = grid.length, COLS = grid[0].length; + int[][] index = new int[ROWS][COLS]; + int idx = 0; + int[] directions = {1, 0, -1, 0, 1}; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] != 0) { + index[r][c] = idx++; + } + } + } + + int res = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] > 0) { + Queue q = new LinkedList<>(); + q.offer(new int[]{r, c, grid[r][c], 1 << index[r][c]}); + + while (!q.isEmpty()) { + int[] cur = q.poll(); + int row = cur[0], col = cur[1], gold = cur[2], mask = cur[3]; + res = Math.max(res, gold); + + for (int i = 0; i < 4; i++) { + int nr = row + directions[i], nc = col + directions[i + 1]; + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && grid[nr][nc] > 0) { + int newIdx = index[nr][nc]; + if ((mask & (1 << newIdx)) == 0) { + q.offer(new int[]{nr, nc, gold + grid[nr][nc], mask | (1 << newIdx)}); + } + } + } + } + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int getMaximumGold(vector>& grid) { + int ROWS = grid.size(), COLS = grid[0].size(); + vector> index(ROWS, vector(COLS, 0)); + int idx = 0; + int directions[] = {1, 0, -1, 0, 1}; + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] != 0) { + index[r][c] = idx++; + } + } + } + + int res = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + if (grid[r][c] > 0) { + queue> q; + q.push({r, c, grid[r][c], 1 << index[r][c]}); + + while (!q.empty()) { + auto [row, col, gold, mask] = q.front();q.pop(); + res = max(res, gold); + for (int i = 0; i < 4; i++) { + int nr = row + directions[i], nc = col + directions[i + 1]; + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS && grid[nr][nc] > 0) { + int newIdx = index[nr][nc]; + if ((mask & (1 << newIdx)) == 0) { + q.push({nr, nc, gold + grid[nr][nc], mask | (1 << newIdx)}); + } + } + } + } + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + getMaximumGold(grid) { + const ROWS = grid.length, + COLS = grid[0].length; + const index = Array.from({ length: ROWS }, () => Array(COLS).fill(0)); + let idx = 0; + const directions = [1, 0, -1, 0, 1]; + + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] !== 0) { + index[r][c] = idx++; + } + } + } + + let res = 0; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + if (grid[r][c] > 0) { + const q = new Queue([[r, c, grid[r][c], 1 << index[r][c]]]); + + while (!q.isEmpty()) { + const [row, col, gold, mask] = q.pop(); + res = Math.max(res, gold); + for (let i = 0; i < 4; i++) { + const nr = row + directions[i], + nc = col + directions[i + 1]; + if ( + nr >= 0 && + nr < ROWS && + nc >= 0 && + nc < COLS && + grid[nr][nc] > 0 + ) { + const newIdx = index[nr][nc]; + if (!(mask & (1 << newIdx))) { + q.push([ + nr, + nc, + gold + grid[nr][nc], + mask | (1 << newIdx), + ]); + } + } + } + } + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(N * 3 ^ N)$ +- Space complexity: $O(N)$ + +> Where $N$ is the number of cells which contain gold. diff --git a/articles/path-with-maximum-probability.md b/articles/path-with-maximum-probability.md new file mode 100644 index 000000000..1ab0f16e8 --- /dev/null +++ b/articles/path-with-maximum-probability.md @@ -0,0 +1,632 @@ +## 1. Dijkstra's Algorithm - I + +::tabs-start + +```python +class Solution: + def maxProbability(self, n: int, edges: List[List[int]], succProb: List[float], start_node: int, end_node: int) -> float: + adj = collections.defaultdict(list) + for i in range(len(edges)): + src, dst = edges[i] + adj[src].append((dst, succProb[i])) + adj[dst].append((src, succProb[i])) + + pq = [(-1, start_node)] + visit = set() + + while pq: + prob, cur = heapq.heappop(pq) + visit.add(cur) + + if cur == end_node: + return -prob + + for nei, edgeProb in adj[cur]: + if nei not in visit: + heapq.heappush(pq, (prob * edgeProb, nei)) + + return 0.0 +``` + +```java +public class Solution { + public double maxProbability(int n, int[][] edges, double[] succProb, int start_node, int end_node) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + + for (int i = 0; i < edges.length; i++) { + int src = edges[i][0], dst = edges[i][1]; + adj[src].add(new Pair(dst, succProb[i])); + adj[dst].add(new Pair(src, succProb[i])); + } + + double[] maxProb = new double[n]; + maxProb[start_node] = 1.0; + PriorityQueue pq = new PriorityQueue<>((a, b) -> Double.compare(b.prob, a.prob)); + pq.offer(new Pair(start_node, 1.0)); + + while (!pq.isEmpty()) { + Pair top = pq.poll(); + int node = top.node; + double curr_prob = top.prob; + + if (node == end_node) return curr_prob; + if (curr_prob > maxProb[node]) continue; + + for (Pair nei : adj[node]) { + double new_prob = curr_prob * nei.prob; + if (new_prob > maxProb[nei.node]) { + maxProb[nei.node] = new_prob; + pq.offer(new Pair(nei.node, new_prob)); + } + } + } + + return 0.0; + } + + static class Pair { + int node; + double prob; + + Pair(int node, double prob) { + this.node = node; + this.prob = prob; + } + } +} +``` + +```cpp +class Solution { +public: + double maxProbability(int n, vector>& edges, vector& succProb, int start_node, int end_node) { + vector>> adj(n); + for (int i = 0; i < edges.size(); i++) { + int src = edges[i][0], dst = edges[i][1]; + adj[src].emplace_back(dst, succProb[i]); + adj[dst].emplace_back(src, succProb[i]); + } + + vector maxProb(n, 0.0); + maxProb[start_node] = 1.0; + priority_queue> pq; + pq.emplace(1.0, start_node); + + while (!pq.empty()) { + auto [curr_prob, node] = pq.top(); pq.pop(); + + if (node == end_node) return curr_prob; + if (curr_prob > maxProb[node]) continue; + + for (auto& [nei, edge_prob] : adj[node]) { + double new_prob = curr_prob * edge_prob; + if (new_prob > maxProb[nei]) { + maxProb[nei] = new_prob; + pq.emplace(new_prob, nei); + } + } + } + + return 0.0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} succProb + * @param {number} start_node + * @param {number} end_node + * @return {number} + */ + maxProbability(n, edges, succProb, start_node, end_node) { + let adj = new Map(); + for (let i = 0; i < n; i++) adj.set(i, []); + + for (let i = 0; i < edges.length; i++) { + let [src, dst] = edges[i]; + adj.get(src).push([dst, succProb[i]]); + adj.get(dst).push([src, succProb[i]]); + } + + let pq = new MaxPriorityQueue({ priority: (x) => x[0] }); + pq.enqueue([1.0, start_node]); + let visited = new Set(); + + while (!pq.isEmpty()) { + let [prob, cur] = pq.dequeue().element; + visited.add(cur); + + if (cur === end_node) return prob; + + for (let [nei, edgeProb] of adj.get(cur)) { + if (!visited.has(nei)) { + pq.enqueue([prob * edgeProb, nei]); + } + } + } + + return 0.0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O((V + E) \log V)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number nodes and $E$ is the number of edges. + +--- + +## 2. Dijkstra's Algorithm - II + +::tabs-start + +```python +class Solution: + def maxProbability(self, n: int, edges: List[List[int]], succProb: List[float], start_node: int, end_node: int) -> float: + adj = [[] for _ in range(n)] + for i in range(len(edges)): + src, dst = edges[i] + adj[src].append((dst, succProb[i])) + adj[dst].append((src, succProb[i])) + + maxProb = [0] * n + maxProb[start_node] = 1.0 + pq = [(-1.0, start_node)] + + while pq: + curr_prob, node = heapq.heappop(pq) + curr_prob *= -1 + + if node == end_node: + return curr_prob + if curr_prob > maxProb[node]: + continue + + for nei, edge_prob in adj[node]: + new_prob = curr_prob * edge_prob + if new_prob > maxProb[nei]: + maxProb[nei] = new_prob + heapq.heappush(pq, (-new_prob, nei)) + + return 0.0 +``` + +```java +public class Solution { + public double maxProbability(int n, int[][] edges, double[] succProb, int start_node, int end_node) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + + for (int i = 0; i < edges.length; i++) { + int src = edges[i][0], dst = edges[i][1]; + adj[src].add(new Pair(dst, succProb[i])); + adj[dst].add(new Pair(src, succProb[i])); + } + + double[] maxProb = new double[n]; + maxProb[start_node] = 1.0; + PriorityQueue pq = new PriorityQueue<>((a, b) -> Double.compare(b.prob, a.prob)); + pq.offer(new Pair(start_node, 1.0)); + + while (!pq.isEmpty()) { + Pair top = pq.poll(); + int node = top.node; + double curr_prob = top.prob; + + if (node == end_node) return curr_prob; + if (curr_prob > maxProb[node]) continue; + + for (Pair nei : adj[node]) { + double new_prob = curr_prob * nei.prob; + if (new_prob > maxProb[nei.node]) { + maxProb[nei.node] = new_prob; + pq.offer(new Pair(nei.node, new_prob)); + } + } + } + + return 0.0; + } + + static class Pair { + int node; + double prob; + + Pair(int node, double prob) { + this.node = node; + this.prob = prob; + } + } +} +``` + +```cpp +class Solution { +public: + double maxProbability(int n, vector>& edges, vector& succProb, int start_node, int end_node) { + vector>> adj(n); + for (int i = 0; i < edges.size(); i++) { + int src = edges[i][0], dst = edges[i][1]; + adj[src].emplace_back(dst, succProb[i]); + adj[dst].emplace_back(src, succProb[i]); + } + + vector maxProb(n, 0.0); + maxProb[start_node] = 1.0; + priority_queue> pq; + pq.emplace(1.0, start_node); + + while (!pq.empty()) { + auto [curr_prob, node] = pq.top(); pq.pop(); + + if (node == end_node) return curr_prob; + if (curr_prob > maxProb[node]) continue; + + for (auto& [nei, edge_prob] : adj[node]) { + double new_prob = curr_prob * edge_prob; + if (new_prob > maxProb[nei]) { + maxProb[nei] = new_prob; + pq.emplace(new_prob, nei); + } + } + } + + return 0.0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} succProb + * @param {number} start_node + * @param {number} end_node + * @return {number} + */ + maxProbability(n, edges, succProb, start_node, end_node) { + let adj = Array.from({ length: n }, () => []); + for (let i = 0; i < edges.length; i++) { + let [src, dst] = edges[i]; + adj[src].push([dst, succProb[i]]); + adj[dst].push([src, succProb[i]]); + } + + let maxProb = Array(n).fill(0); + maxProb[start_node] = 1.0; + let pq = new MaxPriorityQueue({ priority: (x) => x[1] }); + pq.enqueue([start_node, 1.0]); + + while (!pq.isEmpty()) { + let [node, curr_prob] = pq.dequeue().element; + + if (node === end_node) return curr_prob; + if (curr_prob > maxProb[node]) continue; + + for (let [nei, edge_prob] of adj[node]) { + let new_prob = curr_prob * edge_prob; + if (new_prob > maxProb[nei]) { + maxProb[nei] = new_prob; + pq.enqueue([nei, new_prob]); + } + } + } + + return 0.0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O((V + E) \log V)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number nodes and $E$ is the number of edges. + +--- + +## 3. Bellman Ford Algorithm + +::tabs-start + +```python +class Solution: + def maxProbability(self, n: int, edges: List[List[int]], succProb: List[float], start_node: int, end_node: int) -> float: + maxProb = [0.0] * n + maxProb[start_node] = 1.0 + + for i in range(n): + updated = False + for j in range(len(edges)): + src, dst = edges[j] + if maxProb[src] * succProb[j] > maxProb[dst]: + maxProb[dst] = maxProb[src] * succProb[j] + updated = True + + if maxProb[dst] * succProb[j] > maxProb[src]: + maxProb[src] = maxProb[dst] * succProb[j] + updated = True + + if not updated: + break + + return maxProb[end_node] +``` + +```java +public class Solution { + public double maxProbability(int n, int[][] edges, double[] succProb, int start_node, int end_node) { + double[] maxProb = new double[n]; + maxProb[start_node] = 1.0; + + for (int i = 0; i < n; i++) { + boolean updated = false; + for (int j = 0; j < edges.length; j++) { + int src = edges[j][0], dst = edges[j][1]; + + if (maxProb[src] * succProb[j] > maxProb[dst]) { + maxProb[dst] = maxProb[src] * succProb[j]; + updated = true; + } + + if (maxProb[dst] * succProb[j] > maxProb[src]) { + maxProb[src] = maxProb[dst] * succProb[j]; + updated = true; + } + } + if (!updated) break; + } + + return maxProb[end_node]; + } +} +``` + +```cpp +class Solution { +public: + double maxProbability(int n, vector>& edges, vector& succProb, int start_node, int end_node) { + vector maxProb(n, 0.0); + maxProb[start_node] = 1.0; + + for (int i = 0; i < n; i++) { + bool updated = false; + for (int j = 0; j < edges.size(); j++) { + int src = edges[j][0], dst = edges[j][1]; + + if (maxProb[src] * succProb[j] > maxProb[dst]) { + maxProb[dst] = maxProb[src] * succProb[j]; + updated = true; + } + + if (maxProb[dst] * succProb[j] > maxProb[src]) { + maxProb[src] = maxProb[dst] * succProb[j]; + updated = true; + } + } + if (!updated) break; + } + + return maxProb[end_node]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} succProb + * @param {number} start_node + * @param {number} end_node + * @return {number} + */ + maxProbability(n, edges, succProb, start_node, end_node) { + let maxProb = new Array(n).fill(0.0); + maxProb[start_node] = 1.0; + + for (let i = 0; i < n; i++) { + let updated = false; + for (let j = 0; j < edges.length; j++) { + let [src, dst] = edges[j]; + + if (maxProb[src] * succProb[j] > maxProb[dst]) { + maxProb[dst] = maxProb[src] * succProb[j]; + updated = true; + } + + if (maxProb[dst] * succProb[j] > maxProb[src]) { + maxProb[src] = maxProb[dst] * succProb[j]; + updated = true; + } + } + if (!updated) break; + } + + return maxProb[end_node]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V * E)$ +- Space complexity: $O(V)$ + +> Where $V$ is the number nodes and $E$ is the number of edges. + +--- + +## 4. Shortest Path Faster Algorithm + +::tabs-start + +```python +class Solution: + def maxProbability(self, n: int, edges: List[List[int]], succProb: List[float], start_node: int, end_node: int) -> float: + adj = [[] for _ in range(n)] + for i in range(len(edges)): + src, dst = edges[i] + adj[src].append((dst, succProb[i])) + adj[dst].append((src, succProb[i])) + + maxProb = [0.0] * n + maxProb[start_node] = 1.0 + q = deque([start_node]) + + while q: + node = q.popleft() + + for nei, edge_prob in adj[node]: + new_prob = maxProb[node] * edge_prob + if new_prob > maxProb[nei]: + maxProb[nei] = new_prob + q.append(nei) + + return maxProb[end_node] +``` + +```java +public class Solution { + public double maxProbability(int n, int[][] edges, double[] succProb, int start_node, int end_node) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) adj[i] = new ArrayList<>(); + + for (int i = 0; i < edges.length; i++) { + int src = edges[i][0], dst = edges[i][1]; + adj[src].add(new Pair(dst, succProb[i])); + adj[dst].add(new Pair(src, succProb[i])); + } + + double[] maxProb = new double[n]; + maxProb[start_node] = 1.0; + Queue q = new LinkedList<>(); + q.offer(start_node); + + while (!q.isEmpty()) { + int node = q.poll(); + + for (Pair nei : adj[node]) { + double newProb = maxProb[node] * nei.prob; + if (newProb > maxProb[nei.node]) { + maxProb[nei.node] = newProb; + q.offer(nei.node); + } + } + } + + return maxProb[end_node]; + } + + static class Pair { + int node; + double prob; + + Pair(int node, double prob) { + this.node = node; + this.prob = prob; + } + } +} +``` + +```cpp +class Solution { +public: + double maxProbability(int n, vector>& edges, vector& succProb, int start_node, int end_node) { + vector>> adj(n); + + for (int i = 0; i < edges.size(); i++) { + int src = edges[i][0], dst = edges[i][1]; + adj[src].emplace_back(dst, succProb[i]); + adj[dst].emplace_back(src, succProb[i]); + } + + vector maxProb(n, 0.0); + maxProb[start_node] = 1.0; + queue q; + q.push(start_node); + + while (!q.empty()) { + int node = q.front(); + q.pop(); + + for (auto& [nei, edgeProb] : adj[node]) { + double newProb = maxProb[node] * edgeProb; + if (newProb > maxProb[nei]) { + maxProb[nei] = newProb; + q.push(nei); + } + } + } + + return maxProb[end_node]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @param {number[]} succProb + * @param {number} start_node + * @param {number} end_node + * @return {number} + */ + maxProbability(n, edges, succProb, start_node, end_node) { + let adj = Array.from({ length: n }, () => []); + for (let i = 0; i < edges.length; i++) { + let [src, dst] = edges[i]; + adj[src].push([dst, succProb[i]]); + adj[dst].push([src, succProb[i]]); + } + + let maxProb = new Array(n).fill(0.0); + maxProb[start_node] = 1.0; + const q = new Queue([start_node]); + + while (!q.isEmpty()) { + let node = q.pop(); + + for (let [nei, edgeProb] of adj[node]) { + let newProb = maxProb[node] * edgeProb; + if (newProb > maxProb[nei]) { + maxProb[nei] = newProb; + q.push(nei); + } + } + } + + return maxProb[end_node]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V * E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number nodes and $E$ is the number of edges. diff --git a/articles/path-with-minimum-effort.md b/articles/path-with-minimum-effort.md index bccc0e7b9..5e5a6914d 100644 --- a/articles/path-with-minimum-effort.md +++ b/articles/path-with-minimum-effort.md @@ -127,21 +127,23 @@ class Solution { minimumEffortPath(heights) { const rows = heights.length; const cols = heights[0].length; - const dist = Array.from({ length: rows }, () => - Array(cols).fill(Infinity) + const dist = Array.from({ length: rows }, () => + Array(cols).fill(Infinity), ); dist[0][0] = 0; - const minHeap = new MinPriorityQueue({ priority: (a) => a[0] }); + const minHeap = new MinPriorityQueue((a) => a[0]); minHeap.enqueue([0, 0, 0]); // [diff, row, col] const directions = [ - [0, 1], [0, -1], - [1, 0], [-1, 0], + [0, 1], + [0, -1], + [1, 0], + [-1, 0], ]; while (!minHeap.isEmpty()) { - const [diff, r, c] = minHeap.dequeue().element; + const [diff, r, c] = minHeap.dequeue(); if (r === rows - 1 && c === cols - 1) return diff; if (dist[r][c] < diff) continue; @@ -155,7 +157,7 @@ class Solution { const newDiff = Math.max( diff, - Math.abs(heights[r][c] - heights[newR][newC]) + Math.abs(heights[r][c] - heights[newR][newC]), ); if (newDiff < dist[newR][newC]) { dist[newR][newC] = newDiff; @@ -169,12 +171,56 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinimumEffortPath(int[][] heights) { + int rows = heights.Length, cols = heights[0].Length; + var directions = new int[][] { + new int[] { 0, 1 }, + new int[] { 0, -1 }, + new int[] { 1, 0 }, + new int[] { -1, 0 } + }; + + var minHeap = new PriorityQueue<(int diff, int r, int c), int>(); + var visited = new HashSet<(int, int)>(); + minHeap.Enqueue((0, 0, 0), 0); + + while (minHeap.Count > 0) { + var current = minHeap.Dequeue(); + int diff = current.diff, r = current.r, c = current.c; + + if (visited.Contains((r, c))) continue; + visited.Add((r, c)); + + if (r == rows - 1 && c == cols - 1) { + return diff; + } + + foreach (var dir in directions) { + int newR = r + dir[0]; + int newC = c + dir[1]; + + if (newR < 0 || newC < 0 || newR >= rows || newC >= cols || visited.Contains((newR, newC))) { + continue; + } + + int newDiff = Math.Max(diff, Math.Abs(heights[r][c] - heights[newR][newC])); + minHeap.Enqueue((newDiff, newR, newC), newDiff); + } + } + + return 0; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n * \log (m * n))$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n * \log (m * n))$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns in the given matrix. @@ -189,27 +235,27 @@ class Solution: def minimumEffortPath(self, heights: List[List[int]]) -> int: ROWS, COLS = len(heights), len(heights[0]) directions = [[0, 1], [0, -1], [1, 0], [-1, 0]] - + def dfs(r, c, limit, visited): if r == ROWS - 1 and c == COLS - 1: return True - + visited.add((r, c)) for dr, dc in directions: newR, newC = r + dr, c + dc - if (newR < 0 or newC < 0 or - newR >= ROWS or newC >= COLS or + if (newR < 0 or newC < 0 or + newR >= ROWS or newC >= COLS or (newR, newC) in visited or abs(heights[newR][newC] - heights[r][c]) > limit): continue - + if dfs(newR, newC, limit, visited): return True return False - + l, r = 0, 1000000 res = r - + while l <= r: mid = (l + r) // 2 if dfs(0, 0, mid, set()): @@ -217,7 +263,7 @@ class Solution: r = mid - 1 else: l = mid + 1 - + return res ``` @@ -340,11 +386,13 @@ class Solution { const ROWS = heights.length; const COLS = heights[0].length; const directions = [ - [0, 1], [0, -1], - [1, 0], [-1, 0] + [0, 1], + [0, -1], + [1, 0], + [-1, 0], ]; - let visited = Array.from({ length: ROWS }, () => - Array(COLS).fill(false) + let visited = Array.from({ length: ROWS }, () => + Array(COLS).fill(false), ); const dfs = (r, c, limit) => { @@ -357,9 +405,13 @@ class Solution { const newR = r + dr; const newC = c + dc; - if (newR < 0 || newC < 0 || - newR >= ROWS || newC >= COLS || - visited[newR][newC]) { + if ( + newR < 0 || + newC < 0 || + newR >= ROWS || + newC >= COLS || + visited[newR][newC] + ) { continue; } if (Math.abs(heights[newR][newC] - heights[r][c]) > limit) { @@ -372,7 +424,9 @@ class Solution { return false; }; - let l = 0, r = 1_000_000, res = r; + let l = 0, + r = 1_000_000, + res = r; while (l <= r) { const mid = Math.floor((l + r) / 2); for (const row of visited) { @@ -390,12 +444,65 @@ class Solution { } ``` +```csharp +public class Solution { + private int[][] directions = new int[][] { + new int[] { 0, 1 }, + new int[] { 0, -1 }, + new int[] { 1, 0 }, + new int[] { -1, 0 } + }; + + public int MinimumEffortPath(int[][] heights) { + int rows = heights.Length; + int cols = heights[0].Length; + + bool Dfs(int r, int c, int limit, HashSet<(int, int)> visited) { + if (r == rows - 1 && c == cols - 1) + return true; + + visited.Add((r, c)); + + foreach (var dir in directions) { + int newR = r + dir[0]; + int newC = c + dir[1]; + + if (newR < 0 || newC < 0 || newR >= rows || newC >= cols || + visited.Contains((newR, newC)) || + Math.Abs(heights[newR][newC] - heights[r][c]) > limit) + continue; + + if (Dfs(newR, newC, limit, visited)) + return true; + } + + return false; + } + + int left = 0, right = 1000000, res = right; + + while (left <= right) { + int mid = (left + right) / 2; + var visited = new HashSet<(int, int)>(); + if (Dfs(0, 0, mid, visited)) { + res = mid; + right = mid - 1; + } else { + left = mid + 1; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n * \log (m * n))$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n * \log (m * n))$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns in the given matrix. @@ -612,7 +719,8 @@ class DSU { * @return {boolean} */ union(u, v) { - let pu = this.find(u), pv = this.find(v); + let pu = this.find(u), + pv = this.find(v); if (pu === pv) return false; if (this.Size[pu] < this.Size[pv]) [pu, pv] = [pv, pu]; this.Size[pu] += this.Size[pv]; @@ -633,10 +741,18 @@ class Solution { for (let r = 0; r < ROWS; r++) { for (let c = 0; c < COLS; c++) { if (r + 1 < ROWS) { - edges.push([Math.abs(heights[r][c] - heights[r + 1][c]), r * COLS + c, (r + 1) * COLS + c]); + edges.push([ + Math.abs(heights[r][c] - heights[r + 1][c]), + r * COLS + c, + (r + 1) * COLS + c, + ]); } if (c + 1 < COLS) { - edges.push([Math.abs(heights[r][c] - heights[r][c + 1]), r * COLS + c, r * COLS + c + 1]); + edges.push([ + Math.abs(heights[r][c] - heights[r][c + 1]), + r * COLS + c, + r * COLS + c + 1, + ]); } } } @@ -654,12 +770,83 @@ class Solution { } ``` +```csharp +public class DSU { + private int[] parent; + private int[] size; + + public DSU(int n) { + parent = new int[n + 1]; + size = new int[n + 1]; + for (int i = 0; i <= n; i++) { + parent[i] = i; + size[i] = 1; + } + } + + public int Find(int node) { + if (parent[node] != node) { + parent[node] = Find(parent[node]); + } + return parent[node]; + } + + public bool Union(int u, int v) { + int pu = Find(u); + int pv = Find(v); + if (pu == pv) return false; + if (size[pu] < size[pv]) { + (pu, pv) = (pv, pu); + } + size[pu] += size[pv]; + parent[pv] = pu; + return true; + } +} + +public class Solution { + public int MinimumEffortPath(int[][] heights) { + int rows = heights.Length; + int cols = heights[0].Length; + List<(int, int, int)> edges = new List<(int, int, int)>(); + + for (int r = 0; r < rows; r++) { + for (int c = 0; c < cols; c++) { + int id = r * cols + c; + if (r + 1 < rows) { + int downId = (r + 1) * cols + c; + int diff = Math.Abs(heights[r][c] - heights[r + 1][c]); + edges.Add((diff, id, downId)); + } + if (c + 1 < cols) { + int rightId = r * cols + (c + 1); + int diff = Math.Abs(heights[r][c] - heights[r][c + 1]); + edges.Add((diff, id, rightId)); + } + } + } + + edges.Sort((a, b) => a.Item1.CompareTo(b.Item1)); + DSU dsu = new DSU(rows * cols); + + foreach (var (weight, u, v) in edges) { + dsu.Union(u, v); + if (dsu.Find(0) == dsu.Find(rows * cols - 1)) { + return weight; + } + } + + return 0; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n * \log (m * n))$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n * \log (m * n))$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns in the given matrix. @@ -676,10 +863,10 @@ class Solution: dist = [float('inf')] * (ROWS * COLS) dist[0] = 0 in_queue = [False] * (ROWS * COLS) - + def index(r, c): return r * COLS + c - + queue = deque([0]) in_queue[0] = True directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] @@ -700,7 +887,7 @@ class Solution: if not in_queue[v]: queue.append(v) in_queue[v] = True - + return dist[ROWS * COLS - 1] ``` @@ -798,7 +985,8 @@ class Solution { * @return {number} */ minimumEffortPath(heights) { - const ROWS = heights.length, COLS = heights[0].length; + const ROWS = heights.length, + COLS = heights[0].length; const dist = Array(ROWS * COLS).fill(Infinity); dist[0] = 0; @@ -808,20 +996,26 @@ class Solution { inQueue[0] = true; const directions = [ - [0, 1], [0, -1], - [1, 0], [-1, 0] + [0, 1], + [0, -1], + [1, 0], + [-1, 0], ]; while (!queue.isEmpty()) { const u = queue.pop(); inQueue[u] = false; - const r = Math.floor(u / COLS), c = u % COLS; + const r = Math.floor(u / COLS), + c = u % COLS; for (const [dr, dc] of directions) { - const newR = r + dr, newC = c + dc; + const newR = r + dr, + newC = c + dc; if (newR >= 0 && newC >= 0 && newR < ROWS && newC < COLS) { const v = newR * COLS + newC; - const weight = Math.abs(heights[r][c] - heights[newR][newC]); + const weight = Math.abs( + heights[r][c] - heights[newR][newC], + ); const newDist = Math.max(dist[u], weight); if (newDist < dist[v]) { dist[v] = newDist; @@ -839,13 +1033,60 @@ class Solution { } ``` +```csharp +public class Solution { + public int MinimumEffortPath(int[][] heights) { + int rows = heights.Length; + int cols = heights[0].Length; + int[] dist = Enumerable.Repeat(int.MaxValue, rows * cols).ToArray(); + bool[] inQueue = new bool[rows * cols]; + dist[0] = 0; + + int Index(int r, int c) => r * cols + c; + + Queue queue = new Queue(); + queue.Enqueue(0); + inQueue[0] = true; + + int[][] directions = new int[][] { + new int[] {0, 1}, new int[] {0, -1}, + new int[] {1, 0}, new int[] {-1, 0} + }; + + while (queue.Count > 0) { + int u = queue.Dequeue(); + inQueue[u] = false; + int r = u / cols, c = u % cols; + + foreach (var dir in directions) { + int newR = r + dir[0], newC = c + dir[1]; + if (newR >= 0 && newR < rows && newC >= 0 && newC < cols) { + int v = Index(newR, newC); + int weight = Math.Abs(heights[r][c] - heights[newR][newC]); + int newDist = Math.Max(dist[u], weight); + if (newDist < dist[v]) { + dist[v] = newDist; + if (!inQueue[v]) { + queue.Enqueue(v); + inQueue[v] = true; + } + } + } + } + } + + return dist[rows * cols - 1]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: - * $O(m * n)$ time in average case. - * $O(m ^ 2 * n ^ 2)$ time in worst case. -* Space complexity: $O(m * n)$ +- Time complexity: + - $O(m * n)$ time in average case. + - $O(m ^ 2 * n ^ 2)$ time in worst case. +- Space complexity: $O(m * n)$ -> Where $m$ is the number of rows and $n$ is the number of columns in the given matrix. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns in the given matrix. diff --git a/articles/perfect-squares.md b/articles/perfect-squares.md index ce067516a..5af0a5a56 100644 --- a/articles/perfect-squares.md +++ b/articles/perfect-squares.md @@ -8,14 +8,14 @@ class Solution: def dfs(target): if target == 0: return 0 - + res = target for i in range(1, target): if i * i > target: break res = min(res, 1 + dfs(target - i * i)) return res - + return dfs(n) ``` @@ -29,7 +29,7 @@ public class Solution { if (target == 0) { return 0; } - + int res = target; for (int i = 1; i * i <= target; i++) { res = Math.min(res, 1 + dfs(target - i * i)); @@ -51,7 +51,7 @@ private: if (target == 0) { return 0; } - + int res = target; for (int i = 1; i * i <= target; i++) { res = min(res, 1 + dfs(target - i * i)); @@ -83,12 +83,31 @@ class Solution { } ``` +```csharp +public class Solution { + public int NumSquares(int n) { + return Dfs(n); + } + + private int Dfs(int target) { + if (target == 0) return 0; + + int res = target; + for (int i = 1; i * i <= target; i++) { + res = Math.Min(res, 1 + Dfs(target - i * i)); + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ {\sqrt {n}})$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n ^ {\sqrt {n}})$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -115,7 +134,7 @@ class Solution: memo[target] = res return res - + return dfs(n) ``` @@ -173,7 +192,7 @@ class Solution { */ numSquares(n) { const memo = new Map(); - + const dfs = (target) => { if (target === 0) return 0; if (memo.has(target)) { @@ -193,12 +212,35 @@ class Solution { } ``` +```csharp +public class Solution { + private Dictionary memo = new Dictionary(); + + public int NumSquares(int n) { + return Dfs(n); + } + + private int Dfs(int target) { + if (target == 0) return 0; + if (memo.ContainsKey(target)) return memo[target]; + + int res = target; + for (int i = 1; i * i <= target; i++) { + res = Math.Min(res, 1 + Dfs(target - i * i)); + } + + memo[target] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * \sqrt {n})$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * \sqrt {n})$ +- Space complexity: $O(n)$ --- @@ -211,14 +253,14 @@ class Solution: def numSquares(self, n: int) -> int: dp = [n] * (n + 1) dp[0] = 0 - + for target in range(1, n + 1): for s in range(1, target + 1): square = s * s if target - square < 0: break dp[target] = min(dp[target], 1 + dp[target - square]) - + return dp[n] ``` @@ -279,12 +321,31 @@ class Solution { } ``` +```csharp +public class Solution { + public int NumSquares(int n) { + int[] dp = new int[n + 1]; + Array.Fill(dp, n); + dp[0] = 0; + + for (int target = 1; target <= n; target++) { + for (int s = 1; s * s <= target; s++) { + int square = s * s; + dp[target] = Math.Min(dp[target], 1 + dp[target - square]); + } + } + + return dp[n]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * \sqrt {n})$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * \sqrt {n})$ +- Space complexity: $O(n)$ --- @@ -297,7 +358,7 @@ class Solution: def numSquares(self, n: int) -> int: q = deque() seen = set() - + res = 0 q.append(0) while q: @@ -313,7 +374,7 @@ class Solution: seen.add(nxt) q.append(nxt) s += 1 - + return res ``` @@ -379,7 +440,7 @@ class Solution { * @return {number} */ numSquares(n) { - const q = new Queue; + const q = new Queue(); const seen = new Set(); let res = 0; @@ -403,12 +464,46 @@ class Solution { } ``` +```csharp +public class Solution { + public int NumSquares(int n) { + Queue q = new Queue(); + HashSet seen = new HashSet(); + + int res = 0; + q.Enqueue(0); + + while (q.Count > 0) { + res++; + int size = q.Count; + for (int i = 0; i < size; i++) { + int cur = q.Dequeue(); + int s = 1; + while (s * s + cur <= n) { + int nxt = cur + s * s; + if (nxt == n) { + return res; + } + if (!seen.Contains(nxt)) { + seen.Add(nxt); + q.Enqueue(nxt); + } + s++; + } + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * \sqrt {n})$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * \sqrt {n})$ +- Space complexity: $O(n)$ --- @@ -421,23 +516,23 @@ class Solution: def numSquares(self, n: int) -> int: while n % 4 == 0: n //= 4 - + if n % 8 == 7: return 4 - + def isSquareNum(num): s = int(math.sqrt(num)) return s * s == num - + if isSquareNum(n): return 1 - + i = 1 while i * i <= n: if isSquareNum(n - i * i): return 2 i += 1 - + return 3 ``` @@ -447,24 +542,24 @@ public class Solution { while (n % 4 == 0) { n /= 4; } - + if (n % 8 == 7) { return 4; } - + if (isSquareNum(n)) { return 1; } - + for (int i = 1; i * i <= n; i++) { if (isSquareNum(n - i * i)) { return 2; } } - + return 3; } - + private boolean isSquareNum(int num) { int s = (int) Math.sqrt(num); return s * s == num; @@ -479,24 +574,24 @@ public: while (n % 4 == 0) { n /= 4; } - + if (n % 8 == 7) { return 4; } - + if (isSquareNum(n)) { return 1; } - + for (int i = 1; i * i <= n; i++) { if (isSquareNum(n - i * i)) { return 2; } } - + return 3; } - + private: bool isSquareNum(int num) { int s = (int) sqrt(num); @@ -515,26 +610,57 @@ class Solution { while (n % 4 === 0) { n = Math.floor(n / 4); } - + if (n % 8 === 7) { return 4; } - + const isSquareNum = (num) => { const s = Math.floor(Math.sqrt(num)); return s * s === num; }; - + if (isSquareNum(n)) { return 1; } - + for (let i = 1; i * i <= n; i++) { if (isSquareNum(n - i * i)) { return 2; } } - + + return 3; + } +} +``` + +```csharp +public class Solution { + public int NumSquares(int n) { + while (n % 4 == 0) { + n /= 4; + } + + if (n % 8 == 7) { + return 4; + } + + bool IsSquareNum(int num) { + int s = (int)Math.Sqrt(num); + return s * s == num; + } + + if (IsSquareNum(n)) { + return 1; + } + + for (int i = 1; i * i <= n; i++) { + if (IsSquareNum(n - i * i)) { + return 2; + } + } + return 3; } } @@ -544,5 +670,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(\sqrt {n})$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(\sqrt {n})$ +- Space complexity: $O(1)$ diff --git a/articles/permutation-string.md b/articles/permutation-string.md index 07e79c7ef..ee9eabce2 100644 --- a/articles/permutation-string.md +++ b/articles/permutation-string.md @@ -49,7 +49,7 @@ public: for (int j = i; j < s2.length(); j++) { string subStr = s2.substr(i, j - i + 1); sort(subStr.begin(), subStr.end()); - + if (subStr == s1) { return true; } @@ -72,7 +72,11 @@ class Solution { for (let i = 0; i < s2.length; i++) { for (let j = i; j < s2.length; j++) { - let subStr = s2.slice(i, j + 1).split('').sort().join(''); + let subStr = s2 + .slice(i, j + 1) + .split('') + .sort() + .join(''); if (subStr === s1) { return true; } @@ -149,12 +153,31 @@ class Solution { } ``` +```swift +class Solution { + func checkInclusion(_ s1: String, _ s2: String) -> Bool { + let s1Sorted = s1.sorted() + let chars = Array(s2) + + for i in 0.. Bool { + var count1 = [Character: Int]() + for c in s1 { + count1[c, default: 0] += 1 + } + + let need = count1.count + let chars = Array(s2) + + for i in 0.. Where $n$ is the length of the string1 and $m$ is the length of string2. @@ -411,21 +467,21 @@ class Solution: def checkInclusion(self, s1: str, s2: str) -> bool: if len(s1) > len(s2): return False - + s1Count, s2Count = [0] * 26, [0] * 26 for i in range(len(s1)): s1Count[ord(s1[i]) - ord('a')] += 1 s2Count[ord(s2[i]) - ord('a')] += 1 - + matches = 0 for i in range(26): matches += (1 if s1Count[i] == s2Count[i] else 0) - + l = 0 for r in range(len(s1), len(s2)): if matches == 26: return True - + index = ord(s2[r]) - ord('a') s2Count[index] += 1 if s1Count[index] == s2Count[index]: @@ -736,9 +792,64 @@ class Solution { } ``` +```swift +class Solution { + func checkInclusion(_ s1: String, _ s2: String) -> Bool { + if s1.count > s2.count { + return false + } + + var s1Count = [Int](repeating: 0, count: 26) + var s2Count = [Int](repeating: 0, count: 26) + let aAscii = Int(Character("a").asciiValue!) + + let s1Array = Array(s1) + let s2Array = Array(s2) + + for i in 0..> PermuteUnique(int[] nums) { + HashSet resSet = new HashSet(); + List> result = new List>(); + Backtrack(new List(), nums, resSet, result); + return result; + } + + private void Backtrack(List perm, int[] nums, HashSet resSet, List> result) { + if (perm.Count == nums.Length) { + string key = string.Join(",", perm); + if (resSet.Add(key)) { + result.Add(new List(perm)); + } + return; + } + + for (int i = 0; i < nums.Length; i++) { + if (nums[i] != int.MinValue) { + int temp = nums[i]; + perm.Add(temp); + nums[i] = int.MinValue; + Backtrack(perm, nums, resSet, result); + nums[i] = temp; + perm.RemoveAt(perm.Count - 1); + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n! * n)$ -* Space complexity: $O(n! * n)$ for the hash set. +- Time complexity: $O(n! * n)$ +- Space complexity: $O(n! * n)$ for the hash set. --- @@ -147,7 +179,7 @@ class Solution: if len(perm) == len(nums): res.append(perm.copy()) return - + for num in count: if count[num] > 0: perm.append(num) @@ -164,7 +196,7 @@ class Solution: public class Solution { private Map count; private List> res; - + public List> permuteUnique(int[] nums) { res = new ArrayList<>(); count = new HashMap<>(); @@ -201,7 +233,7 @@ public class Solution { class Solution { vector> res; unordered_map count; - + public: vector> permuteUnique(vector& nums) { for (int& num : nums) { @@ -268,12 +300,50 @@ class Solution { } ``` +```csharp +public class Solution { + public List> PermuteUnique(int[] nums) { + var res = new List>(); + var perm = new List(); + var count = new Dictionary(); + + foreach (int num in nums) { + if (!count.ContainsKey(num)) { + count[num] = 0; + } + count[num]++; + } + + void Dfs() { + if (perm.Count == nums.Length) { + res.Add(new List(perm)); + return; + } + + foreach (var kvp in count) { + int num = kvp.Key; + if (count[num] > 0) { + perm.Add(num); + count[num]--; + Dfs(); + count[num]++; + perm.RemoveAt(perm.Count - 1); + } + } + } + + Dfs(); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n! * n)$ -* Space complexity: $O(n! * n)$ for the output list. +- Time complexity: $O(n! * n)$ +- Space complexity: $O(n! * n)$ for the output list. --- @@ -292,11 +362,11 @@ class Solution: if len(perm) == n: res.append(perm.copy()) return - + for i in range(n): if visit[i]: continue - + if i and nums[i] == nums[i - 1] and not visit[i - 1]: continue visit[i] = True @@ -348,7 +418,7 @@ public class Solution { class Solution { vector> res; vector visit; - + public: vector> permuteUnique(vector& nums) { visit.assign(nums.size(), false); @@ -366,7 +436,7 @@ public: for (int i = 0; i < nums.size(); i++) { if (visit[i] || (i > 0 && nums[i] == nums[i - 1] && !visit[i - 1])) continue; - + visit[i] = true; perm.push_back(nums[i]); dfs(nums, perm); @@ -396,9 +466,12 @@ class Solution { } for (let i = 0; i < nums.length; i++) { - if (visit[i] || (i > 0 && nums[i] === nums[i - 1] && !visit[i - 1])) + if ( + visit[i] || + (i > 0 && nums[i] === nums[i - 1] && !visit[i - 1]) + ) continue; - + visit[i] = true; perm.push(nums[i]); dfs(); @@ -413,12 +486,45 @@ class Solution { } ``` +```csharp +public class Solution { + public List> PermuteUnique(int[] nums) { + var res = new List>(); + var perm = new List(); + int n = nums.Length; + bool[] visit = new bool[n]; + Array.Sort(nums); + + void Dfs() { + if (perm.Count == n) { + res.Add(new List(perm)); + return; + } + + for (int i = 0; i < n; i++) { + if (visit[i]) continue; + if (i > 0 && nums[i] == nums[i - 1] && !visit[i - 1]) continue; + + visit[i] = true; + perm.Add(nums[i]); + Dfs(); + perm.RemoveAt(perm.Count - 1); + visit[i] = false; + } + } + + Dfs(); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n! * n)$ -* Space complexity: $O(n! * n)$ for the output list. +- Time complexity: $O(n! * n)$ +- Space complexity: $O(n! * n)$ for the output list. --- @@ -435,14 +541,14 @@ class Solution: if i == len(nums): res.append(nums.copy()) return - + for j in range(i, len(nums)): if j > i and nums[i] == nums[j]: continue - + nums[i], nums[j] = nums[j], nums[i] dfs(i + 1) - + for j in range(len(nums) - 1, i, -1): nums[j], nums[i] = nums[i], nums[j] @@ -480,7 +586,7 @@ public class Solution { swap(nums, i, j); } } - + private void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; @@ -492,7 +598,7 @@ public class Solution { ```cpp class Solution { vector> res; - + public: vector> permuteUnique(vector& nums) { sort(nums.begin(), nums.end()); @@ -511,7 +617,7 @@ public: swap(nums[i], nums[j]); dfs(i + 1, nums); } - + for (int j = nums.size() - 1; j > i; --j) { swap(nums[i], nums[j]); } @@ -552,12 +658,47 @@ class Solution { } ``` +```csharp +public class Solution { + public List> PermuteUnique(int[] nums) { + var res = new List>(); + Array.Sort(nums); + Dfs(0); + return res; + + void Dfs(int i) { + if (i == nums.Length) { + res.Add(new List(nums)); + return; + } + + for (int j = i; j < nums.Length; j++) { + if (j > i && nums[j] == nums[i]) continue; + + Swap(i, j); + Dfs(i + 1); + } + + for (int j = nums.Length - 1; j > i; j--) { + Swap(i, j); + } + } + + void Swap(int a, int b) { + int temp = nums[a]; + nums[a] = nums[b]; + nums[b] = temp; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n! * n)$ -* Space complexity: $O(n! * n)$ for the output list. +- Time complexity: $O(n! * n)$ +- Space complexity: $O(n! * n)$ for the output list. --- @@ -576,22 +717,22 @@ class Solution: i = n - 2 while i >= 0 and nums[i] >= nums[i + 1]: i -= 1 - + if i < 0: break - + j = n - 1 while nums[j] <= nums[i]: - j -= 1 + j -= 1 nums[i], nums[j] = nums[j], nums[i] - + l, r = i + 1, n - 1 while l < r: nums[l], nums[r] = nums[r], nums[l] l, r = l + 1, r - 1 - + res.append(nums.copy()) - + return res ``` @@ -689,7 +830,8 @@ class Solution { [nums[i], nums[j]] = [nums[j], nums[i]]; - let l = i + 1, r = n - 1; + let l = i + 1, + r = n - 1; while (l < r) { [nums[l], nums[r]] = [nums[r], nums[l]]; l++; @@ -704,9 +846,51 @@ class Solution { } ``` +```csharp +public class Solution { + public List> PermuteUnique(int[] nums) { + int n = nums.Length; + Array.Sort(nums); + var res = new List>(); + res.Add(new List(nums)); + + while (true) { + int i = n - 2; + while (i >= 0 && nums[i] >= nums[i + 1]) { + i--; + } + + if (i < 0) break; + + int j = n - 1; + while (nums[j] <= nums[i]) { + j--; + } + + Swap(nums, i, j); + + int left = i + 1, right = n - 1; + while (left < right) { + Swap(nums, left++, right--); + } + + res.Add(new List(nums)); + } + + return res; + } + + private void Swap(int[] nums, int i, int j) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n! * n)$ -* Space complexity: $O(n! * n)$ for the output list. \ No newline at end of file +- Time complexity: $O(n! * n)$ +- Space complexity: $O(n! * n)$ for the output list. diff --git a/articles/permutations.md b/articles/permutations.md index 492290c73..bb7f64f29 100644 --- a/articles/permutations.md +++ b/articles/permutations.md @@ -7,7 +7,7 @@ class Solution: def permute(self, nums: List[int]) -> List[List[int]]: if len(nums) == 0: return [[]] - + perms = self.permute(nums[1:]) res = [] for p in perms: @@ -24,7 +24,7 @@ public class Solution { if (nums.length == 0) { return Arrays.asList(new ArrayList<>()); } - + List> perms = permute(Arrays.copyOfRange(nums, 1, nums.length)); List> res = new ArrayList<>(); for (List p : perms) { @@ -46,7 +46,7 @@ public: if (nums.empty()) { return {{}}; } - + vector tmp = vector(nums.begin() + 1, nums.end()); vector> perms = permute(tmp); vector> res; @@ -93,7 +93,7 @@ public class Solution { if (nums.Length == 0) { return new List> { new List() }; } - + var perms = Permute(nums[1..]); var res = new List>(); foreach (var p in perms) { @@ -113,7 +113,7 @@ func permute(nums []int) [][]int { if len(nums) == 0 { return [][]int{{}} } - + perms := permute(nums[1:]) var res [][]int for _, p := range perms { @@ -131,7 +131,7 @@ func permute(nums []int) [][]int { class Solution { fun permute(nums: IntArray): List> { if (nums.isEmpty()) return listOf(listOf()) - + val perms = permute(nums.sliceArray(1 until nums.size)) val res = mutableListOf>() for (p in perms) { @@ -146,12 +146,35 @@ class Solution { } ``` +```swift +class Solution { + func permute(_ nums: [Int]) -> [[Int]] { + if nums.isEmpty { + return [[]] + } + + let perms = permute(Array(nums.dropFirst())) + var res = [[Int]]() + + for p in perms { + for i in 0...p.count { + var pCopy = p + pCopy.insert(nums[0], at: i) + res.append(pCopy) + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n! * n ^ 2)$ -* Space complexity: $O(n! * n)$ for the output list. +- Time complexity: $O(n! * n ^ 2)$ +- Space complexity: $O(n! * n)$ for the output list. --- @@ -264,7 +287,7 @@ public class Solution { ```go func permute(nums []int) [][]int { perms := [][]int{{}} - + for _, num := range nums { var newPerms [][]int for _, p := range perms { @@ -276,7 +299,7 @@ func permute(nums []int) [][]int { } perms = newPerms } - + return perms } ``` @@ -285,7 +308,7 @@ func permute(nums []int) [][]int { class Solution { fun permute(nums: IntArray): List> { var perms = mutableListOf(listOf()) - + for (num in nums) { val newPerms = mutableListOf>() for (p in perms) { @@ -297,7 +320,29 @@ class Solution { } perms = newPerms } - + + return perms + } +} +``` + +```swift +class Solution { + func permute(_ nums: [Int]) -> [[Int]] { + var perms: [[Int]] = [[]] + + for num in nums { + var newPerms = [[Int]]() + for p in perms { + for i in 0...p.count { + var pCopy = p + pCopy.insert(num, at: i) + newPerms.append(pCopy) + } + } + perms = newPerms + } + return perms } } @@ -307,8 +352,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n! * n ^ 2)$ -* Space complexity: $O(n! * n)$ for the output list. +- Time complexity: $O(n! * n ^ 2)$ +- Space complexity: $O(n! * n)$ for the output list. --- @@ -402,7 +447,7 @@ class Solution { let res = []; backtrack([], nums, new Array(nums.length).fill(false)); return res; - + function backtrack(perm, nums, pick) { if (perm.length === nums.length) { res.push([...perm]); @@ -477,12 +522,12 @@ func backtrack(res *[][]int, perm []int, nums []int, pick []bool) { ```kotlin class Solution { private val res = mutableListOf>() - + fun permute(nums: IntArray): List> { backtrack(mutableListOf(), nums, BooleanArray(nums.size)) return res } - + private fun backtrack(perm: MutableList, nums: IntArray, pick: BooleanArray) { if (perm.size == nums.size) { res.add(ArrayList(perm)) @@ -501,12 +546,41 @@ class Solution { } ``` +```swift +class Solution { + func permute(_ nums: [Int]) -> [[Int]] { + var res = [[Int]]() + var pick = [Bool](repeating: false, count: nums.count) + + func backtrack(_ perm: inout [Int]) { + if perm.count == nums.count { + res.append(perm) + return + } + for i in 0..>() - + fun permute(nums: IntArray): List> { backtrack(mutableListOf(), nums, 0) return res } - + private fun backtrack(perm: MutableList, nums: IntArray, mask: Int) { if (perm.size == nums.size) { res.add(ArrayList(perm)) @@ -691,12 +765,38 @@ class Solution { } ``` +```swift +class Solution { + func permute(_ nums: [Int]) -> [[Int]] { + var res = [[Int]]() + + func backtrack(_ perm: inout [Int], _ mask: Int) { + if perm.count == nums.count { + res.append(perm) + return + } + for i in 0..>() - + fun permute(nums: IntArray): List> { backtrack(nums, 0) return res } - + private fun backtrack(nums: IntArray, idx: Int) { if (idx == nums.size) { res.add(nums.toList()) @@ -880,7 +980,7 @@ class Solution { nums.swap(idx, i) } } - + private fun IntArray.swap(i: Int, j: Int) { val temp = this[i] this[i] = this[j] @@ -889,9 +989,33 @@ class Solution { } ``` +```swift +class Solution { + func permute(_ nums: [Int]) -> [[Int]] { + var res = [[Int]]() + var nums = nums + + func backtrack(_ idx: Int) { + if idx == nums.count { + res.append(nums) + return + } + for i in idx.. [Int] { + if digits.isEmpty { + return [1] + } + + var digits = digits + if digits[digits.count - 1] < 9 { + digits[digits.count - 1] += 1 + return digits + } else { + return plusOne(Array(digits.dropLast())) + [0] + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- -## 2. Iteration +## 2. Iteration - I ::tabs-start @@ -148,7 +166,7 @@ class Solution: def plusOne(self, digits: List[int]) -> List[int]: one = 1 i = 0 - digits = digits[::-1] + digits.reverse() while one: if i < len(digits): @@ -161,7 +179,9 @@ class Solution: digits.append(one) one = 0 i += 1 - return digits[::-1] + + digits.reverse() + return digits ``` ```java @@ -339,16 +359,45 @@ class Solution { } ``` +```swift +class Solution { + func plusOne(_ digits: [Int]) -> [Int] { + var digits = digits + var one = 1 + var i = 0 + digits.reverse() + + while one > 0 { + if i < digits.count { + if digits[i] == 9 { + digits[i] = 0 + } else { + digits[i] += 1 + one = 0 + } + } else { + digits.append(one) + one = 0 + } + i += 1 + } + + digits.reverse() + return digits + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the language. --- -## 3. Iteration (Optimal) +## 3. Iteration - II ::tabs-start @@ -361,7 +410,7 @@ class Solution: digits[i] += 1 return digits digits[i] = 0 - + return [1] + digits ``` @@ -474,9 +523,28 @@ class Solution { } ``` +```swift +class Solution { + func plusOne(_ digits: [Int]) -> [Int] { + var digits = digits + let n = digits.count + + for i in stride(from: n - 1, through: 0, by: -1) { + if digits[i] < 9 { + digits[i] += 1 + return digits + } + digits[i] = 0 + } + + return [1] + digits + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/populating-next-right-pointers-in-each-node.md b/articles/populating-next-right-pointers-in-each-node.md new file mode 100644 index 000000000..facd98067 --- /dev/null +++ b/articles/populating-next-right-pointers-in-each-node.md @@ -0,0 +1,701 @@ +## 1. Breadth First Search + +::tabs-start + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None): + self.val = val + self.left = left + self.right = right + self.next = next +""" + +class Solution: + def connect(self, root: 'Optional[Node]') -> 'Optional[Node]': + if not root: + return None + + q = deque([root]) + while q: + levelSize = len(q) + while levelSize: + node = q.popleft() + if levelSize > 1: + node.next = q[0] + if node.left: + q.append(node.left) + if node.right: + q.append(node.right) + levelSize -= 1 + + return root +``` + +```java +/* +// Definition for a Node. +class Node { + public int val; + public Node left; + public Node right; + public Node next; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, Node _left, Node _right, Node _next) { + val = _val; + left = _left; + right = _right; + next = _next; + } +}; +*/ + +public class Solution { + public Node connect(Node root) { + if (root == null) return null; + + Queue q = new LinkedList<>(); + q.add(root); + + while (!q.isEmpty()) { + int levelSize = q.size(); + while (levelSize > 0) { + Node node = q.poll(); + if (levelSize > 1) { + node.next = q.peek(); + } + if (node.left != null) { + q.add(node.left); + } + if (node.right != null) { + q.add(node.right); + } + levelSize--; + } + } + + return root; + } +} +``` + +```cpp +/* +// Definition for a Node. +class Node { +public: + int val; + Node* left; + Node* right; + Node* next; + + Node() : val(0), left(NULL), right(NULL), next(NULL) {} + + Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {} + + Node(int _val, Node* _left, Node* _right, Node* _next) + : val(_val), left(_left), right(_right), next(_next) {} +}; +*/ + +class Solution { +public: + Node* connect(Node* root) { + if (!root) return nullptr; + + queue q; + q.push(root); + + while (!q.empty()) { + int levelSize = q.size(); + while (levelSize > 0) { + Node* node = q.front(); + q.pop(); + if (levelSize > 1) { + node->next = q.front(); + } + if (node->left) { + q.push(node->left); + } + if (node->right) { + q.push(node->right); + } + levelSize--; + } + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null, next = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * this.next = next; + * } + * } + */ + +class Solution { + /** + * @param {Node} root + * @return {Node} + */ + connect(root) { + if (!root) return null; + + const q = new Queue(); + q.push(root); + + while (!q.isEmpty()) { + let levelSize = q.size(); + while (levelSize > 0) { + let node = q.pop(); + if (levelSize > 1) { + node.next = q.front(); + } + if (node.left) { + q.push(node.left); + } + if (node.right) { + q.push(node.right); + } + levelSize--; + } + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(\log n)$ + +--- + +## 2. Depth First Search + +::tabs-start + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None): + self.val = val + self.left = left + self.right = right + self.next = next +""" + +class Solution: + def connect(self, root: 'Optional[Node]') -> 'Optional[Node]': + mp = {} + + def dfs(node, depth): + if not node: + return + + if depth not in mp: + mp[depth] = node + else: + mp[depth].next = node + mp[depth] = node + + dfs(node.left, depth + 1) + dfs(node.right, depth + 1) + + dfs(root, 0) + return root +``` + +```java +/* +// Definition for a Node. +class Node { + public int val; + public Node left; + public Node right; + public Node next; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, Node _left, Node _right, Node _next) { + val = _val; + left = _left; + right = _right; + next = _next; + } +}; +*/ + +public class Solution { + public Node connect(Node root) { + Map mp = new HashMap<>(); + dfs(root, 0, mp); + return root; + } + + private void dfs(Node node, int depth, Map mp) { + if (node == null) return; + + if (!mp.containsKey(depth)) { + mp.put(depth, node); + } else { + mp.get(depth).next = node; + mp.put(depth, node); + } + + dfs(node.left, depth + 1, mp); + dfs(node.right, depth + 1, mp); + } +} +``` + +```cpp +/* +// Definition for a Node. +class Node { +public: + int val; + Node* left; + Node* right; + Node* next; + + Node() : val(0), left(NULL), right(NULL), next(NULL) {} + + Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {} + + Node(int _val, Node* _left, Node* _right, Node* _next) + : val(_val), left(_left), right(_right), next(_next) {} +}; +*/ + +class Solution { +public: + Node* connect(Node* root) { + unordered_map mp; + dfs(root, 0, mp); + return root; + } + +private: + void dfs(Node* node, int depth, unordered_map& mp) { + if (!node) return; + + if (mp.find(depth) == mp.end()) { + mp[depth] = node; + } else { + mp[depth]->next = node; + mp[depth] = node; + } + + dfs(node->left, depth + 1, mp); + dfs(node->right, depth + 1, mp); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null, next = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * this.next = next; + * } + * } + */ + +class Solution { + /** + * @param {Node} root + * @return {Node} + */ + connect(root) { + let mp = new Map(); + + const dfs = (node, depth) => { + if (!node) return; + + if (!mp.has(depth)) { + mp.set(depth, node); + } else { + mp.get(depth).next = node; + mp.set(depth, node); + } + + dfs(node.left, depth + 1); + dfs(node.right, depth + 1); + }; + + dfs(root, 0); + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(\log n)$ + +--- + +## 3. Depth First Search (Optimal) + +::tabs-start + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None): + self.val = val + self.left = left + self.right = right + self.next = next +""" + +class Solution: + def connect(self, root: 'Optional[Node]') -> 'Optional[Node]': + if not root: + return root + + if root.left: + root.left.next = root.right + if root.next: + root.right.next = root.next.left + + self.connect(root.left) + self.connect(root.right) + + return root +``` + +```java +/* +// Definition for a Node. +class Node { + public int val; + public Node left; + public Node right; + public Node next; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, Node _left, Node _right, Node _next) { + val = _val; + left = _left; + right = _right; + next = _next; + } +}; +*/ + +public class Solution { + public Node connect(Node root) { + if (root == null) return root; + + if (root.left != null) { + root.left.next = root.right; + if (root.next != null) { + root.right.next = root.next.left; + } + + connect(root.left); + connect(root.right); + } + + return root; + } +} +``` + +```cpp +/* +// Definition for a Node. +class Node { +public: + int val; + Node* left; + Node* right; + Node* next; + + Node() : val(0), left(NULL), right(NULL), next(NULL) {} + + Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {} + + Node(int _val, Node* _left, Node* _right, Node* _next) + : val(_val), left(_left), right(_right), next(_next) {} +}; +*/ + +class Solution { +public: + Node* connect(Node* root) { + if (!root) return root; + + if (root->left) { + root->left->next = root->right; + if (root->next) { + root->right->next = root->next->left; + } + + connect(root->left); + connect(root->right); + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null, next = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * this.next = next; + * } + * } + */ + +class Solution { + /** + * @param {Node} root + * @return {Node} + */ + connect(root) { + if (!root) return root; + + if (root.left) { + root.left.next = root.right; + if (root.next) { + root.right.next = root.next.left; + } + + this.connect(root.left); + this.connect(root.right); + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(\log n)$ for the recursion stack. + +--- + +## 4. Breadth First Search (Optimal) + +::tabs-start + +```python +""" +# Definition for a Node. +class Node: + def __init__(self, val: int = 0, left: 'Node' = None, right: 'Node' = None, next: 'Node' = None): + self.val = val + self.left = left + self.right = right + self.next = next +""" + +class Solution: + def connect(self, root: 'Optional[Node]') -> 'Optional[Node]': + cur, nxt = root, root.left if root else None + + while cur and nxt: + cur.left.next = cur.right + if cur.next: + cur.right.next = cur.next.left + + cur = cur.next + if not cur: + cur = nxt + nxt = cur.left + + return root +``` + +```java +/* +// Definition for a Node. +class Node { + public int val; + public Node left; + public Node right; + public Node next; + + public Node() {} + + public Node(int _val) { + val = _val; + } + + public Node(int _val, Node _left, Node _right, Node _next) { + val = _val; + left = _left; + right = _right; + next = _next; + } +}; +*/ + +public class Solution { + public Node connect(Node root) { + if (root == null) return null; + + Node cur = root, nxt = root.left; + + while (cur != null && nxt != null) { + cur.left.next = cur.right; + if (cur.next != null) { + cur.right.next = cur.next.left; + } + + cur = cur.next; + if (cur == null) { + cur = nxt; + nxt = cur.left; + } + } + + return root; + } +} +``` + +```cpp +/* +// Definition for a Node. +class Node { +public: + int val; + Node* left; + Node* right; + Node* next; + + Node() : val(0), left(NULL), right(NULL), next(NULL) {} + + Node(int _val) : val(_val), left(NULL), right(NULL), next(NULL) {} + + Node(int _val, Node* _left, Node* _right, Node* _next) + : val(_val), left(_left), right(_right), next(_next) {} +}; +*/ + +class Solution { +public: + Node* connect(Node* root) { + if (!root) return nullptr; + + Node* cur = root, *nxt = root->left; + + while (cur && nxt) { + cur->left->next = cur->right; + if (cur->next) { + cur->right->next = cur->next->left; + } + + cur = cur->next; + if (!cur) { + cur = nxt; + nxt = cur->left; + } + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null, next = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * this.next = next; + * } + * } + */ + +class Solution { + /** + * @param {Node} root + * @return {Node} + */ + connect(root) { + if (!root) return null; + + let cur = root, + nxt = root.left; + + while (cur && nxt) { + cur.left.next = cur.right; + if (cur.next) { + cur.right.next = cur.next.left; + } + + cur = cur.next; + if (!cur) { + cur = nxt; + nxt = cur.left; + } + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/pow-x-n.md b/articles/pow-x-n.md index 341e3ae9d..95011e6c2 100644 --- a/articles/pow-x-n.md +++ b/articles/pow-x-n.md @@ -139,12 +139,31 @@ class Solution { } ``` +```swift +class Solution { + func myPow(_ x: Double, _ n: Int) -> Double { + if x == 0 { + return 0 + } + if n == 0 { + return 1 + } + + var res: Double = 1 + for _ in 0..= 0 ? res : 1 / res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -320,12 +339,33 @@ class Solution { } ``` +```swift +class Solution { + func myPow(_ x: Double, _ n: Int) -> Double { + func helper(_ x: Double, _ n: Int) -> Double { + if x == 0 { + return 0 + } + if n == 0 { + return 1 + } + + let res = helper(x * x, n / 2) + return n % 2 == 0 ? res : x * res + } + + let res = helper(x, abs(n)) + return n >= 0 ? res : 1 / res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(\log n)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(\log n)$ for recursion stack. --- @@ -340,16 +380,16 @@ class Solution: return 0 if n == 0: return 1 - + res = 1 power = abs(n) - + while power: if power & 1: res *= x x *= x power >>= 1 - + return res if n >= 0 else 1 / res ``` @@ -501,9 +541,36 @@ class Solution { } ``` +```swift +class Solution { + func myPow(_ x: Double, _ n: Int) -> Double { + if x == 0 { + return 0 + } + if n == 0 { + return 1 + } + + var res: Double = 1 + var base = x + var power = abs(n) + + while power > 0 { + if power & 1 == 1 { + res *= base + } + base *= base + power >>= 1 + } + + return n >= 0 ? res : 1 / res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/power-of-four.md b/articles/power-of-four.md new file mode 100644 index 000000000..ef4cb1ed3 --- /dev/null +++ b/articles/power-of-four.md @@ -0,0 +1,367 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def isPowerOfFour(self, n: int) -> bool: + if n == 1: + return True + if n <= 0 or n % 4: + return False + return self.isPowerOfFour(n // 4) +``` + +```java +public class Solution { + public boolean isPowerOfFour(int n) { + if (n == 1) { + return true; + } + if (n <= 0 || n % 4 != 0) { + return false; + } + return isPowerOfFour(n / 4); + } +} +``` + +```cpp +class Solution { +public: + bool isPowerOfFour(int n) { + if (n == 1) { + return true; + } + if (n <= 0 || n % 4 != 0) { + return false; + } + return isPowerOfFour(n / 4); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {boolean} + */ + isPowerOfFour(n) { + if (n === 1) { + return true; + } + if (n <= 0 || n % 4 !== 0) { + return false; + } + return this.isPowerOfFour(Math.floor(n / 4)); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +--- + +## 2. Iteration + +::tabs-start + +```python +class Solution: + def isPowerOfFour(self, n: int) -> bool: + if n < 0: + return False + + while n > 1: + if n % 4: + return False + n //= 4 + + return n == 1 +``` + +```java +public class Solution { + public boolean isPowerOfFour(int n) { + if (n < 0) return false; + + while (n > 1) { + if (n % 4 != 0) return false; + n /= 4; + } + + return n == 1; + } +} +``` + +```cpp +class Solution { +public: + bool isPowerOfFour(int n) { + if (n < 0) return false; + + while (n > 1) { + if (n % 4 != 0) return false; + n /= 4; + } + + return n == 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {boolean} + */ + isPowerOfFour(n) { + if (n < 0) return false; + + while (n > 1) { + if (n % 4 !== 0) return false; + n = Math.floor(n / 4); + } + + return n === 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +--- + +## 3. Math + +::tabs-start + +```python +class Solution: + def isPowerOfFour(self, n: int) -> bool: + return n > 0 and log(n, 4) % 1 == 0 +``` + +```java +public class Solution { + public boolean isPowerOfFour(int n) { + return n > 0 && Math.log(n) / Math.log(4) % 1 == 0; + } +} +``` + +```cpp +class Solution { +public: + bool isPowerOfFour(int n) { + return n > 0 && fmod(log(n) / log(4), 1) == 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {boolean} + */ + isPowerOfFour(n) { + return n > 0 && (Math.log(n) / Math.log(4)) % 1 === 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +--- + +## 4. Bit Manipulation + +::tabs-start + +```python +class Solution: + def isPowerOfFour(self, n: int) -> bool: + if n < 0: + return False + + for i in range(0, 32, 2): + if n == (1 << i): + return True + + return False +``` + +```java +public class Solution { + public boolean isPowerOfFour(int n) { + if (n < 0) return false; + + for (int i = 0; i < 32; i += 2) { + if (n == (1 << i)) { + return true; + } + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool isPowerOfFour(int n) { + if (n < 0) return false; + + for (int i = 0; i < 32; i += 2) { + if (n == (1 << i)) { + return true; + } + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {boolean} + */ + isPowerOfFour(n) { + if (n < 0) return false; + + for (let i = 0; i < 32; i += 2) { + if (n === 1 << i) { + return true; + } + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +--- + +## 5. Bit Mask - I + +::tabs-start + +```python +class Solution: + def isPowerOfFour(self, n: int) -> bool: + return n > 0 and (n & (n - 1)) == 0 and (n & 0x55555555) == n +``` + +```java +public class Solution { + public boolean isPowerOfFour(int n) { + return n > 0 && (n & (n - 1)) == 0 && (n & 0x55555555) == n; + } +} +``` + +```cpp +class Solution { +public: + bool isPowerOfFour(int n) { + return n > 0 && (n & (n - 1)) == 0 && (n & 0x55555555) == n; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {boolean} + */ + isPowerOfFour(n) { + return n > 0 && (n & (n - 1)) === 0 && (n & 0x55555555) === n; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +--- + +## 6. Bit Mask - II + +::tabs-start + +```python +class Solution: + def isPowerOfFour(self, n: int) -> bool: + return n > 0 and (n & (n - 1)) == 0 and (n % 3 == 1) +``` + +```java +public class Solution { + public boolean isPowerOfFour(int n) { + return n > 0 && (n & (n - 1)) == 0 && (n % 3 == 1); + } +} +``` + +```cpp +class Solution { +public: + bool isPowerOfFour(int n) { + return n > 0 && (n & (n - 1)) == 0 && (n % 3 == 1); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {boolean} + */ + isPowerOfFour(n) { + return n > 0 && (n & (n - 1)) === 0 && n % 3 == 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ diff --git a/articles/power-of-two.md b/articles/power-of-two.md new file mode 100644 index 000000000..97b809d7d --- /dev/null +++ b/articles/power-of-two.md @@ -0,0 +1,351 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + if n <= 0: + return False + + x = 1 + while x < n: + x *= 2 + return x == n +``` + +```java +public class Solution { + public boolean isPowerOfTwo(int n) { + if (n <= 0) return false; + + long x = 1; + while (x < n) { + x *= 2; + } + return x == n; + } +} +``` + +```cpp +class Solution { +public: + bool isPowerOfTwo(int n) { + if (n <= 0) return false; + + long long x = 1; + while (x < n) { + x *= 2; + } + return x == n; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {boolean} + */ + isPowerOfTwo(n) { + if (n <= 0) return false; + + let x = 1; + while (x < n) { + x *= 2; + } + return x === n; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ + +--- + +## 2. Recursion + +::tabs-start + +```python +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + if n == 1: + return True + if n <= 0 or n % 2 == 1: + return False + return self.isPowerOfTwo(n // 2) +``` + +```java +public class Solution { + public boolean isPowerOfTwo(int n) { + if (n == 1) { + return true; + } + if (n <= 0 || n % 2 == 1) { + return false; + } + return isPowerOfTwo(n / 2); + } +} +``` + +```cpp +class Solution { +public: + bool isPowerOfTwo(int n) { + if (n == 1) { + return true; + } + if (n <= 0 || n % 2 == 1) { + return false; + } + return isPowerOfTwo(n / 2); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {boolean} + */ + isPowerOfTwo(n) { + if (n === 1) { + return true; + } + if (n <= 0 || n % 2 === 1) { + return false; + } + return this.isPowerOfTwo(Math.floor(n / 2)); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(\log n)$ for recursion stack. + +--- + +## 3. Iteration + +::tabs-start + +```python +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + if n <= 0: + return False + + while n % 2 == 0: + n >>= 1 + return n == 1 +``` + +```java +public class Solution { + public boolean isPowerOfTwo(int n) { + if (n <= 0) return false; + + while (n % 2 == 0) { + n >>= 1; + } + return n == 1; + } +} +``` + +```cpp +class Solution { +public: + bool isPowerOfTwo(int n) { + if (n <= 0) return false; + + while (n % 2 == 0) { + n >>= 1; + } + return n == 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {boolean} + */ + isPowerOfTwo(n) { + if (n <= 0) return 0; + + while (n % 2 === 0) { + n >>= 1; + } + return n === 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ + +--- + +## 4. Bit Manipulation - I + +::tabs-start + +```python +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + return n > 0 and (n & (-n)) == n +``` + +```java +public class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (-n)) == n; + } +} +``` + +```cpp +class Solution { +public: + bool isPowerOfTwo(int n) { + return n > 0 && (n & (-n)) == n; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {boolean} + */ + isPowerOfTwo(n) { + return n > 0 && (n & -n) === n; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +--- + +## 5. Bit Manipulation - II + +::tabs-start + +```python +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + return n > 0 and (n & (n - 1)) == 0 +``` + +```java +public class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +} +``` + +```cpp +class Solution { +public: + bool isPowerOfTwo(int n) { + return n > 0 && (n & (n - 1)) == 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {boolean} + */ + isPowerOfTwo(n) { + return n > 0 && (n & (n - 1)) === 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +--- + +## 6. Math + +::tabs-start + +```python +class Solution: + def isPowerOfTwo(self, n: int) -> bool: + return n > 0 and ((1 << 30) % n) == 0 +``` + +```java +public class Solution { + public boolean isPowerOfTwo(int n) { + return n > 0 && ((1 << 30) % n) == 0; + } +} +``` + +```cpp +class Solution { +public: + bool isPowerOfTwo(int n) { + return n > 0 && ((1 << 30) % n) == 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {boolean} + */ + isPowerOfTwo(n) { + return n > 0 && (1 << 30) % n === 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ diff --git a/articles/prefix-and-suffix-search.md b/articles/prefix-and-suffix-search.md new file mode 100644 index 000000000..acfc3bd51 --- /dev/null +++ b/articles/prefix-and-suffix-search.md @@ -0,0 +1,596 @@ +## 1. Brute Force + +::tabs-start + +```python +class WordFilter: + + def __init__(self, words: List[str]): + self.words = words + + def f(self, pref: str, suff: str) -> int: + for i in range(len(self.words) - 1, -1, -1): + w = self.words[i] + if len(w) < len(pref) or len(w) < len(suff): + continue + + j, flag = 0, True + for c in pref: + if w[j] != c: + flag = False + break + j += 1 + + if not flag: + continue + + j = len(w) - len(suff) + for c in suff: + if w[j] != c: + flag = False + break + j += 1 + + if flag: + return i + + return -1 +``` + +```java +public class WordFilter { + private String[] words; + + public WordFilter(String[] words) { + this.words = words; + } + + public int f(String pref, String suff) { + for (int i = words.length - 1; i >= 0; i--) { + String w = words[i]; + if (w.length() < pref.length() || w.length() < suff.length()) { + continue; + } + + boolean flag = true; + for (int j = 0; j < pref.length(); j++) { + if (w.charAt(j) != pref.charAt(j)) { + flag = false; + break; + } + } + + if (!flag) { + continue; + } + + int j = w.length() - suff.length(); + for (int k = 0; k < suff.length(); k++) { + if (w.charAt(j + k) != suff.charAt(k)) { + flag = false; + break; + } + } + + if (flag) { + return i; + } + } + + return -1; + } +} +``` + +```cpp +class WordFilter { +private: + vector words; + +public: + WordFilter(vector& words) { + this->words = words; + } + + int f(string pref, string suff) { + for (int i = words.size() - 1; i >= 0; i--) { + const string& w = words[i]; + if (w.size() < pref.size() || w.size() < suff.size()) { + continue; + } + + bool flag = true; + for (int j = 0; j < pref.size(); j++) { + if (w[j] != pref[j]) { + flag = false; + break; + } + } + + if (!flag) { + continue; + } + + int j = w.size() - suff.size(); + for (int k = 0; k < suff.size(); k++) { + if (w[j + k] != suff[k]) { + flag = false; + break; + } + } + + if (flag) { + return i; + } + } + + return -1; + } +}; +``` + +```javascript +class WordFilter { + /** + * @constructor + * @param {string[]} words + */ + constructor(words) { + this.words = words; + } + + /** + * @param {string} pref + * @param {string} suff + * @return {number} + */ + f(pref, suff) { + for (let i = this.words.length - 1; i >= 0; i--) { + const w = this.words[i]; + if (w.length < pref.length || w.length < suff.length) { + continue; + } + + let flag = true; + for (let j = 0; j < pref.length; j++) { + if (w[j] !== pref[j]) { + flag = false; + break; + } + } + + if (!flag) { + continue; + } + + let j = w.length - suff.length; + for (let k = 0; k < suff.length; k++) { + if (w[j + k] !== suff[k]) { + flag = false; + break; + } + } + + if (flag) { + return i; + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(N * m * n)$ +- Space complexity: $O(1)$ extra space. + +> Where $N$ is the number $f()$ function calls, $n$ is the number of words, and $m$ is the average length of each word. + +--- + +## 2. Hash Map + +::tabs-start + +```python +class WordFilter: + + def __init__(self, words: List[str]): + self.mp = {} + for i, w in enumerate(words): + for j in range(len(w)): + pref = w[:j + 1] + for k in range(len(w)): + cur = pref + "$" + w[k:] + self.mp[cur] = i + + def f(self, pref: str, suff: str) -> int: + s = pref + "$" + suff + if s not in self.mp: + return -1 + + return self.mp[s] +``` + +```java +public class WordFilter { + private Map mp; + + public WordFilter(String[] words) { + mp = new HashMap<>(); + for (int i = 0; i < words.length; i++) { + String w = words[i]; + for (int j = 0; j < w.length(); j++) { + String pref = w.substring(0, j + 1); + for (int k = 0; k < w.length(); k++) { + String cur = pref + "$" + w.substring(k); + mp.put(cur, i); + } + } + } + } + + public int f(String pref, String suff) { + String s = pref + "$" + suff; + return mp.getOrDefault(s, -1); + } +} +``` + +```cpp +class WordFilter { +private: + unordered_map mp; + +public: + WordFilter(vector& words) { + for (int i = 0; i < words.size(); i++) { + string w = words[i]; + for (int j = 0; j < w.size(); j++) { + string pref = w.substr(0, j + 1); + for (int k = 0; k < w.size(); k++) { + string cur = pref + "$" + w.substr(k); + mp[cur] = i; + } + } + } + } + + int f(string pref, string suff) { + string s = pref + "$" + suff; + if (mp.find(s) == mp.end()) { + return -1; + } + return mp[s]; + } +}; +``` + +```javascript +class WordFilter { + /** + * @constructor + * @param {string[]} words + */ + constructor(words) { + this.mp = new Map(); + for (let i = 0; i < words.length; i++) { + const w = words[i]; + for (let j = 0; j < w.length; j++) { + const pref = w.slice(0, j + 1); + for (let k = 0; k < w.length; k++) { + const cur = pref + '$' + w.slice(k); + this.mp.set(cur, i); + } + } + } + } + + /** + * @param {string} pref + * @param {string} suff + * @return {number} + */ + f(pref, suff) { + const s = pref + '$' + suff; + return this.mp.has(s) ? this.mp.get(s) : -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(n * m ^ 3)$ time for initialization. + - $O(m)$ for each $f()$ function call. +- Space complexity: $O(n * m ^ 3)$ + +> Where $n$ is the number of words and $m$ is the average length of each word. + +--- + +## 3. Trie + +::tabs-start + +```python +class TrieNode: + def __init__(self): + self.children = [None] * 27 + self.index = -1 + +class Trie: + def __init__(self): + self.root = TrieNode() + + def addWord(self, w, i): + cur = self.root + for ch in w: + c = ord(ch) - ord('a') + if not cur.children[c]: + cur.children[c] = TrieNode() + cur = cur.children[c] + cur.index = i + + def search(self, w): + cur = self.root + for ch in w: + c = ord(ch) - ord('a') + if not cur.children[c]: + return -1 + cur = cur.children[c] + return cur.index + +class WordFilter: + def __init__(self, words: List[str]): + self.trie = Trie() + self.CHAR = '{' + for i, w in enumerate(words): + w_len = len(w) + for j in range(w_len): + suffix = w[j:] + for k in range(w_len + 1): + prefix = w[:k] + self.trie.addWord(suffix + self.CHAR + prefix, i) + + def f(self, pref: str, suff: str) -> int: + return self.trie.search(suff + self.CHAR + pref) +``` + +```java +class TrieNode { + TrieNode[] children; + int index; + + TrieNode() { + children = new TrieNode[27]; + index = -1; + } +} + +class Trie { + private TrieNode root; + + Trie() { + root = new TrieNode(); + } + + void addWord(String word, int i) { + TrieNode cur = root; + for (char ch : word.toCharArray()) { + int c = ch == '{' ? 26 : ch - 'a'; + if (cur.children[c] == null) { + cur.children[c] = new TrieNode(); + } + cur = cur.children[c]; + } + cur.index = i; + } + + int search(String word) { + TrieNode cur = root; + for (char ch : word.toCharArray()) { + int c = ch == '{' ? 26 : ch - 'a'; + if (cur.children[c] == null) { + return -1; + } + cur = cur.children[c]; + } + return cur.index; + } +} + +public class WordFilter { + private Trie trie; + private static final char CHAR = '{'; + + public WordFilter(String[] words) { + trie = new Trie(); + for (int i = 0; i < words.length; i++) { + String word = words[i]; + int wLen = word.length(); + for (int j = 0; j < wLen; j++) { + String suffix = word.substring(j); + for (int k = 0; k <= wLen; k++) { + String prefix = word.substring(0, k); + trie.addWord(suffix + CHAR + prefix, i); + } + } + } + } + + public int f(String pref, String suff) { + return trie.search(suff + CHAR + pref); + } +} +``` + +```cpp +class TrieNode { +public: + TrieNode* children[27]; + int index; + + TrieNode() { + for (int i = 0; i < 27; i++) { + children[i] = nullptr; + } + index = -1; + } +}; + +class Trie { +private: + TrieNode* root; + +public: + Trie() { + root = new TrieNode(); + } + + void addWord(const string& word, int i) { + TrieNode* cur = root; + for (char ch : word) { + int c = (ch == '{') ? 26 : (ch - 'a'); + if (cur->children[c] == nullptr) { + cur->children[c] = new TrieNode(); + } + cur = cur->children[c]; + } + cur->index = i; + } + + int search(const string& word) { + TrieNode* cur = root; + for (char ch : word) { + int c = (ch == '{') ? 26 : (ch - 'a'); + if (cur->children[c] == nullptr) { + return -1; + } + cur = cur->children[c]; + } + return cur->index; + } +}; + +class WordFilter { +private: + Trie trie; + const char CHAR = '{'; + +public: + WordFilter(vector& words) { + for (int i = 0; i < words.size(); i++) { + string word = words[i]; + int wLen = word.length(); + for (int j = 0; j < wLen; j++) { + string suffix = word.substr(j); + for (int k = 0; k <= wLen; k++) { + string prefix = word.substr(0, k); + trie.addWord(suffix + CHAR + prefix, i); + } + } + } + } + + int f(string pref, string suff) { + return trie.search(suff + CHAR + pref); + } +}; +``` + +```javascript +class TrieNode { + constructor() { + this.children = Array(27).fill(null); + this.index = -1; + } +} + +class Trie { + constructor() { + this.root = new TrieNode(); + } + + /** + * @param {string} word + * @param {number} i + * @return {void} + */ + addWord(word, i) { + let cur = this.root; + for (const ch of word) { + const c = ch === '{' ? 26 : ch.charCodeAt(0) - 'a'.charCodeAt(0); + if (!cur.children[c]) { + cur.children[c] = new TrieNode(); + } + cur = cur.children[c]; + } + cur.index = i; + } + + /** + * @param {string} word + * @return {number} + */ + search(word) { + let cur = this.root; + for (const ch of word) { + const c = ch === '{' ? 26 : ch.charCodeAt(0) - 'a'.charCodeAt(0); + if (!cur.children[c]) { + return -1; + } + cur = cur.children[c]; + } + return cur.index; + } +} + +class WordFilter { + /** + * @constructor + * @param {string[]} words + */ + constructor(words) { + this.trie = new Trie(); + this.CHAR = '{'; + for (let i = 0; i < words.length; i++) { + const word = words[i]; + const wLen = word.length; + for (let j = 0; j < wLen; j++) { + const suffix = word.substring(j); + for (let k = 0; k <= wLen; k++) { + const prefix = word.substring(0, k); + this.trie.addWord(suffix + this.CHAR + prefix, i); + } + } + } + } + + /** + * @param {string} pref + * @param {string} suff + * @return {number} + */ + f(pref, suff) { + return this.trie.search(suff + this.CHAR + pref); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(n * m ^ 3)$ time for initialization. + - $O(m)$ for each $f()$ function call. +- Space complexity: $O(n * m ^ 3)$ + +> Where $n$ is the number of words and $m$ is the average length of each word. diff --git a/articles/process-tasks-using-servers.md b/articles/process-tasks-using-servers.md new file mode 100644 index 000000000..ecc919621 --- /dev/null +++ b/articles/process-tasks-using-servers.md @@ -0,0 +1,520 @@ +## 1. Brute Force (Simulation) + +::tabs-start + +```python +class Solution: + def assignTasks(self, servers: List[int], tasks: List[int]) -> List[int]: + n, m = len(servers), len(tasks) + available = [True] * n + finishTime = [0] * n + res = [] + time = 0 + + for t in range(m): + time = max(time, t) + + for i in range(n): + if finishTime[i] <= time: + available[i] = True + + if not any(available): + time = min(finishTime) + for i in range(n): + if finishTime[i] <= time: + available[i] = True + + minIdx = -1 + for i in range(n): + if (available[i] and + (minIdx == -1 or servers[i] < servers[minIdx] or + (servers[i] == servers[minIdx] and i < minIdx)) + ): + minIdx = i + + res.append(minIdx) + available[minIdx] = False + finishTime[minIdx] = time + tasks[t] + + return res +``` + +```java +public class Solution { + public int[] assignTasks(int[] servers, int[] tasks) { + int n = servers.length, m = tasks.length; + boolean[] available = new boolean[n]; + Arrays.fill(available, true); + int[] finishTime = new int[n]; + int[] res = new int[m]; + int time = 0; + + for (int t = 0; t < m; t++) { + time = Math.max(time, t); + for (int i = 0; i < n; i++) { + if (finishTime[i] <= time) { + available[i] = true; + } + } + + if (!anyAvailable(available)) { + time = Arrays.stream(finishTime).min().getAsInt(); + for (int i = 0; i < n; i++) { + if (finishTime[i] <= time) { + available[i] = true; + } + } + } + + int minIdx = -1; + for (int i = 0; i < n; i++) { + if (available[i] && (minIdx == -1 || servers[i] < servers[minIdx] || + (servers[i] == servers[minIdx] && i < minIdx))) { + minIdx = i; + } + } + + res[t] = minIdx; + available[minIdx] = false; + finishTime[minIdx] = time + tasks[t]; + } + return res; + } + + private boolean anyAvailable(boolean[] available) { + for (boolean v : available) { + if (v) return true; + } + return false; + } +} +``` + +```cpp +class Solution { +public: + vector assignTasks(vector& servers, vector& tasks) { + int n = servers.size(), m = tasks.size(); + vector available(n, true); + vector finishTime(n, 0), res(m); + int time = 0; + + for (int t = 0; t < m; t++) { + time = max(time, t); + + for (int i = 0; i < n; i++) { + if (finishTime[i] <= time) { + available[i] = true; + } + } + + if (!any_of(available.begin(), available.end(), [](bool v) { return v; })) { + time = *min_element(finishTime.begin(), finishTime.end()); + for (int i = 0; i < n; i++) { + if (finishTime[i] <= time) { + available[i] = true; + } + } + } + + int minIdx = -1; + for (int i = 0; i < n; i++) { + if (available[i] && (minIdx == -1 || servers[i] < servers[minIdx] || + (servers[i] == servers[minIdx] && i < minIdx))) { + minIdx = i; + } + } + + res[t] = minIdx; + available[minIdx] = false; + finishTime[minIdx] = time + tasks[t]; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} servers + * @param {number[]} tasks + * @return {number[]} + */ + assignTasks(servers, tasks) { + const n = servers.length, + m = tasks.length; + const available = Array(n).fill(true); + const finishTime = Array(n).fill(0); + const res = []; + let time = 0; + + for (let t = 0; t < m; t++) { + time = Math.max(time, t); + + for (let i = 0; i < n; i++) { + if (finishTime[i] <= time) { + available[i] = true; + } + } + + if (!available.some((v) => v)) { + time = Math.min(...finishTime); + for (let i = 0; i < n; i++) { + if (finishTime[i] <= time) { + available[i] = true; + } + } + } + + let minIdx = -1; + for (let i = 0; i < n; i++) { + if ( + available[i] && + (minIdx === -1 || + servers[i] < servers[minIdx] || + (servers[i] === servers[minIdx] && i < minIdx)) + ) { + minIdx = i; + } + } + + res.push(minIdx); + available[minIdx] = false; + finishTime[minIdx] = time + tasks[t]; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: + - $O(n)$ extra space. + - $O(m)$ space for the output array. + +> Where $m$ is the number of tasks and $n$ is the number of servers. + +--- + +## 2. Two Min-Heaps - I + +::tabs-start + +```python +class Solution: + def assignTasks(self, servers: List[int], tasks: List[int]) -> List[int]: + res = [0] * len(tasks) + available = [(servers[i], i) for i in range(len(servers))] + heapq.heapify(available) + unavailable = [] + + t = 0 + for i in range(len(tasks)): + t = max(t, i) + + if not available: + t = unavailable[0][0] + + while unavailable and t >= unavailable[0][0]: + timeFree, weight, index = heapq.heappop(unavailable) + heapq.heappush(available, (weight, index)) + + weight, index = heapq.heappop(available) + res[i] = index + heapq.heappush(unavailable, (t + tasks[i], weight, index)) + + return res +``` + +```java +public class Solution { + public int[] assignTasks(int[] servers, int[] tasks) { + int n = servers.length, m = tasks.length; + int[] res = new int[m]; + + PriorityQueue available = new PriorityQueue<>( + (a, b) -> a[0] == b[0] ? Integer.compare(a[1], b[1]) : Integer.compare(a[0], b[0]) + ); + PriorityQueue unavailable = new PriorityQueue<>( + Comparator.comparingInt(a -> a[0]) + ); + + for (int i = 0; i < n; i++) { + available.offer(new int[]{servers[i], i}); + } + + int time = 0; + for (int i = 0; i < m; i++) { + time = Math.max(time, i); + + if (available.isEmpty()) { + time = unavailable.peek()[0]; + } + + while (!unavailable.isEmpty() && unavailable.peek()[0] <= time) { + int[] server = unavailable.poll(); + available.offer(new int[]{server[1], server[2]}); + } + + int[] bestServer = available.poll(); + res[i] = bestServer[1]; + unavailable.offer(new int[]{time + tasks[i], bestServer[0], bestServer[1]}); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector assignTasks(vector& servers, vector& tasks) { + int n = servers.size(), m = tasks.size(); + vector res(m); + + priority_queue, vector>, greater<>> available; + priority_queue, vector>, greater<>> unavailable; + + for (int i = 0; i < n; i++) { + available.emplace(servers[i], i); + } + + int time = 0; + for (int i = 0; i < m; i++) { + time = max(time, i); + + if (available.empty()) { + time = unavailable.top()[0]; + } + + while (!unavailable.empty() && unavailable.top()[0] <= time) { + auto server = unavailable.top(); unavailable.pop(); + available.emplace(server[1], server[2]); + } + + auto [weight, index] = available.top(); available.pop(); + res[i] = index; + unavailable.push({time + tasks[i], weight, index}); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} servers + * @param {number[]} tasks + * @return {number[]} + */ + assignTasks(servers, tasks) { + const n = servers.length; + const available = new PriorityQueue((a, b) => + a[0] === b[0] ? a[1] - b[1] : a[0] - b[0], + ); + const unavailable = new PriorityQueue((a, b) => a[0] - b[0]); + const res = new Array(tasks.length); + + for (let i = 0; i < n; i++) { + available.enqueue([servers[i], i]); + } + + let time = 0; + for (let i = 0; i < tasks.length; i++) { + time = Math.max(time, i); + if (available.isEmpty()) { + time = unavailable.front()[0]; + } + while (!unavailable.isEmpty() && unavailable.front()[0] <= time) { + const [timeFree, weight, index] = unavailable.dequeue(); + available.enqueue([weight, index]); + } + const [weight, index] = available.dequeue(); + res[i] = index; + unavailable.enqueue([time + tasks[i], weight, index]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O((n + m) \log n)$ +- Space complexity: + - $O(n)$ extra space. + - $O(m)$ space for the output array. + +> Where $m$ is the number of tasks and $n$ is the number of servers. + +--- + +## 3. Two Min-Heaps - II + +::tabs-start + +```python +class Solution: + def assignTasks(self, servers: List[int], tasks: List[int]) -> List[int]: + res = [] + available = [[weight, i, 0] for i, weight in enumerate(servers)] + unavailable = [] + heapq.heapify(available) + + for i, task in enumerate(tasks): + while unavailable and unavailable[0][0] <= i or not available: + timeFree, weight, index = heapq.heappop(unavailable) + heapq.heappush(available, [weight, index, timeFree]) + + weight, index, timeFree = heapq.heappop(available) + res.append(index) + heapq.heappush(unavailable, [max(timeFree, i) + task, weight, index]) + + return res +``` + +```java +public class Solution { + public int[] assignTasks(int[] servers, int[] tasks) { + int m = tasks.length, n = servers.length; + int[] res = new int[m]; + + PriorityQueue available = new PriorityQueue<>((a, b) -> { + if(a[0] != b[0]) return Integer.compare(a[0], b[0]); + if(a[1] != b[1]) return Integer.compare(a[1], b[1]); + return Integer.compare(a[2], b[2]); + }); + + PriorityQueue unavailable = new PriorityQueue<>((a, b) -> { + if(a[0] != b[0]) return Integer.compare(a[0], b[0]); + if(a[1] != b[1]) return Integer.compare(a[1], b[1]); + return Integer.compare(a[2], b[2]); + }); + + for (int i = 0; i < n; i++) { + available.offer(new int[]{servers[i], i, 0}); + } + + for (int i = 0; i < m; i++) { + while ((!unavailable.isEmpty() && unavailable.peek()[0] <= i) || + available.isEmpty()) { + int[] server = unavailable.poll(); + available.offer(new int[]{server[1], server[2], server[0]}); + } + int[] server = available.poll(); + res[i] = server[1]; + unavailable.offer(new int[]{ + Math.max(server[2], i) + tasks[i], server[0], server[1]} + ); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector assignTasks(vector& servers, vector& tasks) { + int n = servers.size(), m = tasks.size(); + vector res(m); + + priority_queue, vector>, greater<>> available; + priority_queue, vector>, greater<>> unavailable; + + for (int i = 0; i < n; ++i) { + available.push({servers[i], i, 0}); + } + + for (int i = 0; i < m; ++i) { + while (!unavailable.empty() && (unavailable.top()[0] <= i || + available.empty())) { + auto [timeFree, weight, index] = unavailable.top(); + unavailable.pop(); + available.push({weight, index, timeFree}); + } + + auto [weight, index, timeFree] = available.top(); + available.pop(); + res[i] = index; + unavailable.push({max(timeFree, i) + tasks[i], weight, index}); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} servers + * @param {number[]} tasks + * @return {number[]} + */ + assignTasks(servers, tasks) { + const res = new Array(tasks.length); + const available = new PriorityQueue((a, b) => + a[0] === b[0] + ? a[1] === b[1] + ? a[2] - b[2] + : a[1] - b[1] + : a[0] - b[0], + ); + const unavailable = new PriorityQueue((a, b) => + a[0] === b[0] + ? a[1] === b[1] + ? a[2] - b[2] + : a[1] - b[1] + : a[0] - b[0], + ); + + for (let i = 0; i < servers.length; i++) { + available.enqueue([servers[i], i, 0]); + } + + for (let i = 0; i < tasks.length; i++) { + while ( + (!unavailable.isEmpty() && unavailable.front()[0] <= i) || + available.isEmpty() + ) { + const [timeFree, weight, index] = unavailable.dequeue(); + available.enqueue([weight, index, timeFree]); + } + + const [weight, index, timeFree] = available.dequeue(); + res[i] = index; + unavailable.enqueue([ + Math.max(timeFree, i) + tasks[i], + weight, + index, + ]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O((n + m) \log n)$ +- Space complexity: + - $O(n)$ extra space. + - $O(m)$ space for the output array. + +> Where $m$ is the number of tasks and $n$ is the number of servers. diff --git a/articles/products-of-array-discluding-self.md b/articles/products-of-array-discluding-self.md index 1a74a5c68..c0a836cd5 100644 --- a/articles/products-of-array-discluding-self.md +++ b/articles/products-of-array-discluding-self.md @@ -12,9 +12,9 @@ class Solution: prod = 1 for j in range(n): if i == j: - continue + continue prod *= nums[j] - + res[i] = prod return res ``` @@ -36,7 +36,7 @@ public class Solution { } return res; } -} +} ``` ```cpp @@ -142,12 +142,37 @@ class Solution { } ``` +```swift +class Solution { + func productExceptSelf(_ nums: [Int]) -> [Int] { + let n = nums.count + var res = [Int](repeating: 0, count: n) + + for i in 0.. 1) { - return new int[nums.length]; + return new int[nums.length]; } int[] res = new int[nums.length]; @@ -198,7 +223,7 @@ public class Solution { } return res; } -} +} ``` ```cpp @@ -215,7 +240,7 @@ public: } if (zeroCount > 1) { - return vector(nums.size(), 0); + return vector(nums.size(), 0); } vector res(nums.size()); @@ -249,13 +274,13 @@ class Solution { } if (zeroCount > 1) { - return Array(nums.length).fill(0); + return Array(nums.length).fill(0); } const res = new Array(nums.length); for (let i = 0; i < nums.length; i++) { if (zeroCount > 0) { - res[i] = (nums[i] === 0) ? prod : 0; + res[i] = nums[i] === 0 ? prod : 0; } else { res[i] = prod / nums[i]; } @@ -278,7 +303,7 @@ public class Solution { } if (zeroCount > 1) { - return new int[nums.Length]; + return new int[nums.Length]; } int[] res = new int[nums.Length]; @@ -306,7 +331,7 @@ func productExceptSelf(nums []int) []int { zeroCount++ } } - + res := make([]int, len(nums)) if zeroCount > 1 { return res @@ -340,7 +365,7 @@ class Solution { zeroCount++ } } - + val res = IntArray(nums.size) if (zeroCount > 1) return res @@ -356,16 +381,50 @@ class Solution { } ``` +```swift +class Solution { + func productExceptSelf(_ nums: [Int]) -> [Int] { + var prod = 1 + var zeroCount = 0 + + for num in nums { + if num != 0 { + prod *= num + } else { + zeroCount += 1 + } + } + + if zeroCount > 1 { + return [Int](repeating: 0, count: nums.count) + } + + var res = [Int](repeating: 0, count: nums.count) + for (i, num) in nums.enumerated() { + if zeroCount > 0 { + res[i] = num == 0 ? prod : 0 + } else { + res[i] = prod / num + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since the output array is excluded from space analysis. +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output array. --- -## 3. Prefix & Suffix +## 3. Prefix & Suffix ::tabs-start @@ -383,7 +442,7 @@ class Solution: for i in range(n - 2, -1, -1): suff[i] = nums[i + 1] * suff[i + 1] for i in range(n): - res[i] = pref[i] * suff[i] + res[i] = pref[i] * suff[i] return res ``` @@ -408,7 +467,7 @@ public class Solution { } return res; } -} +} ``` ```cpp @@ -533,16 +592,44 @@ class Solution { } ``` +```swift +class Solution { + func productExceptSelf(_ nums: [Int]) -> [Int] { + let n = nums.count + var res = [Int](repeating: 0, count: n) + var pref = [Int](repeating: 0, count: n) + var suff = [Int](repeating: 0, count: n) + + pref[0] = 1 + suff[n - 1] = 1 + + for i in 1..= 0; i--) { res[i] *= postfix; @@ -580,7 +667,7 @@ public class Solution { } return res; } -} +} ``` ```cpp @@ -593,7 +680,7 @@ public: for (int i = 1; i < n; i++) { res[i] = res[i - 1] * nums[i - 1]; } - + int postfix = 1; for (int i = n - 1; i >= 0; i--) { res[i] *= postfix; @@ -617,7 +704,7 @@ class Solution { for (let i = 1; i < n; i++) { res[i] = res[i - 1] * nums[i - 1]; } - + let postfix = 1; for (let i = n - 1; i >= 0; i--) { res[i] *= postfix; @@ -638,7 +725,7 @@ public class Solution { for (int i = 1; i < n; i++) { res[i] = res[i - 1] * nums[i - 1]; } - + int postfix = 1; for (int i = n - 1; i >= 0; i--) { res[i] *= postfix; @@ -694,9 +781,33 @@ class Solution { } ``` +```swift +class Solution { + func productExceptSelf(_ nums: [Int]) -> [Int] { + var res = [Int](repeating: 1, count: nums.count) + + var prefix = 1 + for i in 0..= minProfit else 0 - + res = dfs(i + 1, n, p) if n - group[i] >= 0: res = (res + dfs(i + 1, n - group[i], p + profit[i])) % mod return res - + return dfs(0, n, 0) ``` @@ -103,8 +103,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ N)$ -* Space complexity: $O(N)$ +- Time complexity: $O(2 ^ N)$ +- Space complexity: $O(N)$ > Where $N$ is the size of the $group$ array. @@ -130,10 +130,10 @@ class Solution: if n - group[i] >= 0: nxtP = min(p + profit[i], minProfit) res = (res + dfs(i + 1, n - group[i], nxtP)) % mod - + dp[(i, n, p)] = res return res - + return dfs(0, n, 0) ``` @@ -217,7 +217,7 @@ class Solution { profitableSchemes(n, minProfit, group, profit) { const MOD = 1e9 + 7; const dp = Array.from({ length: group.length }, () => - Array.from({ length: n + 1 }, () => Array(minProfit + 1).fill(-1)) + Array.from({ length: n + 1 }, () => Array(minProfit + 1).fill(-1)), ); const dfs = (i, n, p) => { @@ -247,8 +247,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(N * m * n)$ -* Space complexity: $O(N * m * n)$ +- Time complexity: $O(N * m * n)$ +- Space complexity: $O(N * m * n)$ > Where $N$ is the size of the $group$ array, $m$ is the given minimum profit, and $n$ is the number of group members. @@ -275,8 +275,8 @@ class Solution: if j >= group[i]: nxtP = min(profit[i] + p, minProfit) res = (res + dp[i + 1][j - group[i]][nxtP]) % mod - dp[i][j][p] = res - + dp[i][j][p] = res + return dp[0][n][0] ``` @@ -356,7 +356,7 @@ class Solution { const N = group.length; const dp = Array.from({ length: N + 1 }, () => - Array.from({ length: n + 2 }, () => Array(minProfit + 1).fill(0)) + Array.from({ length: n + 2 }, () => Array(minProfit + 1).fill(0)), ); for (let j = 0; j <= n; j++) { @@ -385,8 +385,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(N * m * n)$ -* Space complexity: $O(N * m * n)$ +- Time complexity: $O(N * m * n)$ +- Space complexity: $O(N * m * n)$ > Where $N$ is the size of the $group$ array, $m$ is the given minimum profit, and $n$ is the number of group members. @@ -413,8 +413,8 @@ class Solution: if j >= group[i]: nxtP = min(profit[i] + p, minProfit) res = (res + dp[j - group[i]][nxtP]) % mod - dp[j][p] = res - + dp[j][p] = res + return dp[n][0] ``` @@ -493,8 +493,8 @@ class Solution { const MOD = 1e9 + 7; const N = group.length; - const dp = Array.from({ length: n + 2 }, () => - Array(minProfit + 1).fill(0) + const dp = Array.from({ length: n + 2 }, () => + Array(minProfit + 1).fill(0), ); for (let j = 0; j <= n; j++) { @@ -523,7 +523,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(N * m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(N * m * n)$ +- Space complexity: $O(m * n)$ -> Where $N$ is the size of the $group$ array, $m$ is the given minimum profit, and $n$ is the number of group members. \ No newline at end of file +> Where $N$ is the size of the $group$ array, $m$ is the given minimum profit, and $n$ is the number of group members. diff --git a/articles/pseudo-palindromic-paths-in-a-binary-tree.md b/articles/pseudo-palindromic-paths-in-a-binary-tree.md new file mode 100644 index 000000000..be39148af --- /dev/null +++ b/articles/pseudo-palindromic-paths-in-a-binary-tree.md @@ -0,0 +1,808 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def pseudoPalindromicPaths(self, root: Optional[TreeNode]) -> int: + count = defaultdict(int) + odd = 0 + + def dfs(cur): + nonlocal odd + if not cur: + return 0 + + count[cur.val] += 1 + odd_change = 1 if count[cur.val] % 2 == 1 else -1 + odd += odd_change + + if not cur.left and not cur.right: + res = 1 if odd <= 1 else 0 + else: + res = dfs(cur.left) + dfs(cur.right) + + odd -= odd_change + count[cur.val] -= 1 + return res + + return dfs(root) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int pseudoPalindromicPaths(TreeNode root) { + Map count = new HashMap<>(); + int[] odd = new int[1]; + + return dfs(root, count, odd); + } + + private int dfs(TreeNode cur, Map count, int[] odd) { + if (cur == null) return 0; + + count.put(cur.val, count.getOrDefault(cur.val, 0) + 1); + int odd_change = (count.get(cur.val) % 2 == 1) ? 1 : -1; + odd[0] += odd_change; + + int res; + if (cur.left == null && cur.right == null) { + res = (odd[0] <= 1) ? 1 : 0; + } else { + res = dfs(cur.left, count, odd) + dfs(cur.right, count, odd); + } + + odd[0] -= odd_change; + count.put(cur.val, count.get(cur.val) - 1); + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int pseudoPalindromicPaths(TreeNode* root) { + unordered_map count; + int odd = 0; + return dfs(root, count, odd); + } + +private: + int dfs(TreeNode* cur, unordered_map& count, int& odd) { + if (!cur) return 0; + + count[cur->val]++; + int odd_change = (count[cur->val] % 2 == 1) ? 1 : -1; + odd += odd_change; + + int res; + if (!cur->left && !cur->right) { + res = (odd <= 1) ? 1 : 0; + } else { + res = dfs(cur->left, count, odd) + dfs(cur->right, count, odd); + } + + odd -= odd_change; + count[cur->val]--; + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + pseudoPalindromicPaths(root) { + const count = new Map(); + let odd = 0; + + const dfs = (cur) => { + if (!cur) return 0; + + count.set(cur.val, (count.get(cur.val) || 0) + 1); + let odd_change = count.get(cur.val) % 2 === 1 ? 1 : -1; + odd += odd_change; + + let res; + if (!cur.left && !cur.right) { + res = odd <= 1 ? 1 : 0; + } else { + res = dfs(cur.left) + dfs(cur.right); + } + + odd -= odd_change; + count.set(cur.val, count.get(cur.val) - 1); + return res; + }; + + return dfs(root); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(h)$ for recursion stack. + +> Where $n$ is the number of nodes and $h$ is the height of the given tree. + +--- + +## 2. Depth First Search (Using Array) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def pseudoPalindromicPaths(self, root: Optional[TreeNode]) -> int: + count = [0] * 10 + odd = 0 + + def dfs(cur): + nonlocal odd + if not cur: + return 0 + + count[cur.val] ^= 1 + odd += 1 if count[cur.val] else -1 + + if not cur.left and not cur.right and odd <= 1: + res = 1 + else: + res = dfs(cur.left) + dfs(cur.right) + + odd -= 1 if count[cur.val] else -1 + count[cur.val] ^= 1 + + return res + + return dfs(root) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int pseudoPalindromicPaths(TreeNode root) { + int[] count = new int[10]; + return dfs(root, count, 0); + } + + private int dfs(TreeNode cur, int[] count, int odd) { + if (cur == null) return 0; + + count[cur.val] ^= 1; + odd += count[cur.val] == 1 ? 1 : -1; + + int res = (cur.left == null && cur.right == null && odd <= 1) ? 1 + : dfs(cur.left, count, odd) + dfs(cur.right, count, odd); + + odd += count[cur.val] == 1 ? 1 : -1; + count[cur.val] ^= 1; + + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int pseudoPalindromicPaths(TreeNode* root) { + int count[10] = {}; + return dfs(root, count, 0); + } + +private: + int dfs(TreeNode* cur, int count[], int odd) { + if (!cur) return 0; + + count[cur->val] ^= 1; + odd += (count[cur->val] == 1) ? 1 : -1; + + int res = (!cur->left && !cur->right && odd <= 1) ? 1 + : dfs(cur->left, count, odd) + dfs(cur->right, count, odd); + + odd += (count[cur->val] == 1) ? 1 : -1; + count[cur->val] ^= 1; + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + pseudoPalindromicPaths(root) { + const count = new Array(10).fill(0); + + const dfs = (cur, odd) => { + if (!cur) return 0; + + count[cur.val] ^= 1; + odd += count[cur.val] === 1 ? 1 : -1; + + let res = + !cur.left && !cur.right && odd <= 1 + ? 1 + : dfs(cur.left, odd) + dfs(cur.right, odd); + + odd += count[cur.val] === 1 ? 1 : -1; + count[cur.val] ^= 1; + + return res; + }; + + return dfs(root, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(h)$ for recursion stack. + +> Where $n$ is the number of nodes and $h$ is the height of the given tree. + +--- + +## 3. Depth First Search (Bit Mask) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def pseudoPalindromicPaths(self, root: Optional[TreeNode]) -> int: + def dfs(node, path): + if not node: + return 0 + + path ^= 1 << node.val + if not node.left and not node.right: + return 1 if (path & (path - 1)) == 0 else 0 + + return dfs(node.left, path) + dfs(node.right, path) + + return dfs(root, 0) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int pseudoPalindromicPaths(TreeNode root) { + return dfs(root, 0); + } + + private int dfs(TreeNode node, int path) { + if (node == null) return 0; + + path ^= (1 << node.val); + if (node.left == null && node.right == null) { + return (path & (path - 1)) == 0 ? 1 : 0; + } + + return dfs(node.left, path) + dfs(node.right, path); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int pseudoPalindromicPaths(TreeNode* root) { + return dfs(root, 0); + } + +private: + int dfs(TreeNode* node, int path) { + if (!node) return 0; + + path ^= (1 << node->val); + if (!node->left && !node->right) { + return (path & (path - 1)) == 0 ? 1 : 0; + } + + return dfs(node->left, path) + dfs(node->right, path); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + pseudoPalindromicPaths(root) { + const dfs = (node, path) => { + if (!node) return 0; + + path ^= 1 << node.val; + if (!node.left && !node.right) { + return (path & (path - 1)) === 0 ? 1 : 0; + } + + return dfs(node.left, path) + dfs(node.right, path); + }; + + return dfs(root, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(h)$ for recursion stack. + +> Where $n$ is the number of nodes and $h$ is the height of the given tree. + +--- + +## 4. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def pseudoPalindromicPaths(self, root: Optional[TreeNode]) -> int: + res = 0 + q = deque([(root, 0)]) + while q: + node, path = q.popleft() + path ^= 1 << node.val + + if not node.left and not node.right: + if path & (path - 1) == 0: + res += 1 + continue + + if node.left: + q.append((node.left, path)) + if node.right: + q.append((node.right, path)) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int pseudoPalindromicPaths(TreeNode root) { + int count = 0; + Queue q = new LinkedList<>(); + q.offer(new Pair(root, 0)); + while (!q.isEmpty()) { + Pair p = q.poll(); + TreeNode node = p.node; + int path = p.path ^ (1 << node.val); + + if (node.left == null && node.right == null) { + if ((path & (path - 1)) == 0) { + count++; + } + } else { + if (node.left != null) q.offer(new Pair(node.left, path)); + if (node.right != null) q.offer(new Pair(node.right, path)); + } + } + + return count; + } + + private static class Pair { + TreeNode node; + int path; + Pair(TreeNode node, int path) { + this.node = node; + this.path = path; + } + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int pseudoPalindromicPaths(TreeNode* root) { + int res = 0; + queue> q; + q.push({root, 0}); + while (!q.empty()) { + auto [node, path] = q.front();q.pop(); + path ^= (1 << node->val); + + if (!node->left && !node->right) { + if ((path & (path - 1)) == 0) res++; + continue; + } + + if (node->left) q.push({node->left, path}); + if (node->right) q.push({node->right, path}); + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + pseudoPalindromicPaths(root) { + let res = 0; + const q = new Queue([[root, 0]]); + + while (!q.isEmpty()) { + const [node, path] = q.pop(); + const newPath = path ^ (1 << node.val); + + if (!node.left && !node.right) { + if ((newPath & (newPath - 1)) === 0) res++; + continue; + } + + if (node.left) q.push([node.left, newPath]); + if (node.right) q.push([node.right, newPath]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 5. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def pseudoPalindromicPaths(self, root: Optional[TreeNode]) -> int: + count = 0 + stack = [(root, 0)] + while stack: + node, path = stack.pop() + path ^= (1 << node.val) + + if not node.left and not node.right: + if path & (path - 1) == 0: + count += 1 + else: + if node.right: + stack.append((node.right, path)) + if node.left: + stack.append((node.left, path)) + + return count +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int pseudoPalindromicPaths(TreeNode root) { + int count = 0; + Stack stack = new Stack<>(); + stack.push(new Pair(root, 0)); + + while (!stack.isEmpty()) { + Pair p = stack.pop(); + TreeNode node = p.node; + int path = p.path ^ (1 << node.val); + + if (node.left == null && node.right == null) { + if ((path & (path - 1)) == 0) { + count++; + } + } else { + if (node.right != null) stack.push(new Pair(node.right, path)); + if (node.left != null) stack.push(new Pair(node.left, path)); + } + } + return count; + } + + private static class Pair { + TreeNode node; + int path; + Pair(TreeNode node, int path) { + this.node = node; + this.path = path; + } + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int pseudoPalindromicPaths(TreeNode* root) { + stack> s; + s.push({root, 0}); + int count = 0; + + while (!s.empty()) { + auto [node, path] = s.top(); + s.pop(); + path ^= (1 << node->val); + + if (!node->left && !node->right) { + if ((path & (path - 1)) == 0) count++; + } else { + if (node->right) s.push({node->right, path}); + if (node->left) s.push({node->left, path}); + } + } + + return count; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + pseudoPalindromicPaths(root) { + let count = 0; + const stack = [[root, 0]]; + + while (stack.length) { + const [node, path] = stack.pop(); + const newPath = path ^ (1 << node.val); + + if (!node.left && !node.right) { + if ((newPath & (newPath - 1)) === 0) count++; + } else { + if (node.right) stack.push([node.right, newPath]); + if (node.left) stack.push([node.left, newPath]); + } + } + + return count; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(h)$ + +> Where $n$ is the number of nodes and $h$ is the height of the given tree. diff --git a/articles/push-dominoes.md b/articles/push-dominoes.md index efe99877f..043e65116 100644 --- a/articles/push-dominoes.md +++ b/articles/push-dominoes.md @@ -11,15 +11,15 @@ class Solution: for i in range(n): if dominoes[i] != '.': continue - + l, r = i - 1, i + 1 - + while l >= 0 and dominoes[l] == '.': l -= 1 - + while r < n and dominoes[r] == '.': r += 1 - + left_force = dominoes[l] if l >= 0 else None right_force = dominoes[r] if r < n else None @@ -109,30 +109,31 @@ class Solution { */ pushDominoes(dominoes) { const n = dominoes.length; - const res = dominoes.split(""); + const res = dominoes.split(''); for (let i = 0; i < n; i++) { - if (dominoes[i] !== ".") continue; + if (dominoes[i] !== '.') continue; - let l = i - 1, r = i + 1; + let l = i - 1, + r = i + 1; - while (l >= 0 && dominoes[l] === ".") l--; - while (r < n && dominoes[r] === ".") r++; + while (l >= 0 && dominoes[l] === '.') l--; + while (r < n && dominoes[r] === '.') r++; const leftForce = l >= 0 ? dominoes[l] : null; const rightForce = r < n ? dominoes[r] : null; - if (leftForce === "R" && rightForce === "L") { - if ((i - l) < (r - i)) res[i] = "R"; - else if ((r - i) < (i - l)) res[i] = "L"; - } else if (leftForce === "R") { - res[i] = "R"; - } else if (rightForce === "L") { - res[i] = "L"; + if (leftForce === 'R' && rightForce === 'L') { + if (i - l < r - i) res[i] = 'R'; + else if (r - i < i - l) res[i] = 'L'; + } else if (leftForce === 'R') { + res[i] = 'R'; + } else if (rightForce === 'L') { + res[i] = 'L'; } } - return res.join(""); + return res.join(''); } } ``` @@ -141,8 +142,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ for only the output string. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ for only the output string. --- @@ -157,7 +158,7 @@ class Solution: left = [float('inf')] * n right = [float('inf')] * n res = list(dominoes) - + force = float('inf') for i in range(n): if dominoes[i] == 'R': @@ -167,7 +168,7 @@ class Solution: else: force += 1 right[i] = force - + force = float('inf') for i in range(n - 1, -1, -1): if dominoes[i] == 'L': @@ -177,13 +178,13 @@ class Solution: else: force += 1 left[i] = force - + for i in range(n): if left[i] < right[i]: res[i] = 'L' elif right[i] < left[i]: res[i] = 'R' - + return "".join(res) ``` @@ -288,13 +289,13 @@ class Solution { const n = dominoes.length; const left = new Array(n).fill(Infinity); const right = new Array(n).fill(Infinity); - const res = dominoes.split(""); + const res = dominoes.split(''); let force = Infinity; for (let i = 0; i < n; i++) { - if (dominoes[i] === "R") { + if (dominoes[i] === 'R') { force = 0; - } else if (dominoes[i] === "L") { + } else if (dominoes[i] === 'L') { force = Infinity; } else { force = force === Infinity ? Infinity : force + 1; @@ -304,9 +305,9 @@ class Solution { force = Infinity; for (let i = n - 1; i >= 0; i--) { - if (dominoes[i] === "L") { + if (dominoes[i] === 'L') { force = 0; - } else if (dominoes[i] === "R") { + } else if (dominoes[i] === 'R') { force = Infinity; } else { force = force === Infinity ? Infinity : force + 1; @@ -316,13 +317,13 @@ class Solution { for (let i = 0; i < n; i++) { if (left[i] < right[i]) { - res[i] = "L"; + res[i] = 'L'; } else if (right[i] < left[i]) { - res[i] = "R"; + res[i] = 'R'; } } - return res.join(""); + return res.join(''); } } ``` @@ -331,8 +332,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -448,11 +449,11 @@ class Solution { * @return {string} */ pushDominoes(dominoes) { - const dom = dominoes.split(""); + const dom = dominoes.split(''); const q = new Queue(); for (let i = 0; i < dom.length; i++) { - if (dom[i] !== ".") { + if (dom[i] !== '.') { q.push([i, dom[i]]); } } @@ -460,22 +461,22 @@ class Solution { while (!q.isEmpty()) { const [i, d] = q.pop(); - if (d === "L" && i > 0 && dom[i - 1] === ".") { - q.push([i - 1, "L"]); - dom[i - 1] = "L"; - } else if (d === "R") { - if (i + 1 < dom.length && dom[i + 1] === ".") { - if (i + 2 < dom.length && dom[i + 2] === "L") { + if (d === 'L' && i > 0 && dom[i - 1] === '.') { + q.push([i - 1, 'L']); + dom[i - 1] = 'L'; + } else if (d === 'R') { + if (i + 1 < dom.length && dom[i + 1] === '.') { + if (i + 2 < dom.length && dom[i + 2] === 'L') { q.pop(); } else { - q.push([i + 1, "R"]); - dom[i + 1] = "R"; + q.push([i + 1, 'R']); + dom[i + 1] = 'R'; } } } } - return dom.join(""); + return dom.join(''); } } ``` @@ -484,8 +485,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -527,7 +528,7 @@ class Solution: # Append half the dots as 'L'. res.append('L' * (dots // 2)) - + # Append the current 'L'. res.append('L') R, dots = False, 0 @@ -536,14 +537,14 @@ class Solution: # Append 'L' for all the dots and the current 'L'. res.append('L' * (dots + 1)) dots = 0 - + if R: # Trailing dots are affected by the last 'R'. res.append('R' * (dots + 1)) else: # Trailing dots remain unchanged as there is no previous 'R'. res.append('.' * dots) - + return ''.join(res) ``` @@ -745,5 +746,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for only the output string. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for only the output string. diff --git a/articles/put-marbles-in-bags.md b/articles/put-marbles-in-bags.md new file mode 100644 index 000000000..67d8a650a --- /dev/null +++ b/articles/put-marbles-in-bags.md @@ -0,0 +1,503 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def putMarbles(self, weights: List[int], k: int) -> int: + n = len(weights) + cache = {} + + def dfs(i, k): + if (i, k) in cache: + return cache[(i, k)] + if k == 0: + return [0, 0] + if i == n - 1 or n - i - 1 < k: + return [-float("inf"), float("inf")] + + res = [0, float("inf")] # [maxScore, minScore] + + # make partition + cur = dfs(i + 1, k - 1) + res[0] = max(res[0], weights[i] + weights[i + 1] + cur[0]) + res[1] = min(res[1], weights[i] + weights[i + 1] + cur[1]) + + # skip + cur = dfs(i + 1, k) + res[0] = max(res[0], cur[0]) + res[1] = min(res[1], cur[1]) + + cache[(i, k)] = res + return res + + ans = dfs(0, k - 1) + return ans[0] - ans[1] +``` + +```java +public class Solution { + Map cache = new HashMap<>(); + + public long putMarbles(int[] weights, int k) { + int n = weights.length; + long[] ans = dfs(0, k - 1, weights, n); + return ans[0] - ans[1]; + } + + private long[] dfs(int i, int k, int[] weights, int n) { + String key = i + "," + k; + if (cache.containsKey(key)) return cache.get(key); + if (k == 0) return new long[]{0L, 0L}; + if (i == n - 1 || n - i - 1 < k) { + return new long[]{(long)-1e15, (long)1e15}; + } + + long[] res = new long[]{0L, (long)1e15}; + + long[] cur = dfs(i + 1, k - 1, weights, n); + res[0] = Math.max(res[0], weights[i] + weights[i + 1] + cur[0]); + res[1] = Math.min(res[1], weights[i] + weights[i + 1] + cur[1]); + + cur = dfs(i + 1, k, weights, n); + res[0] = Math.max(res[0], cur[0]); + res[1] = Math.min(res[1], cur[1]); + + cache.put(key, res); + return res; + } +} +``` + +```cpp +class Solution { +public: + unordered_map> cache; + + long long putMarbles(vector& weights, int k) { + int n = weights.size(); + auto ans = dfs(0, k - 1, weights, n); + return ans.first - ans.second; + } + + pair dfs(int i, int k, vector& weights, int n) { + string key = to_string(i) + "," + to_string(k); + if (cache.count(key)) return cache[key]; + if (k == 0) return {0LL, 0LL}; + if (i == n - 1 || n - i - 1 < k) { + return {-1000000000000000LL, 1000000000000000LL}; + } + + pair res = {0LL, 1000000000000000LL}; + + auto cur = dfs(i + 1, k - 1, weights, n); + res.first = max(res.first, (long long)weights[i] + weights[i + 1] + cur.first); + res.second = min(res.second, (long long)weights[i] + weights[i + 1] + cur.second); + + cur = dfs(i + 1, k, weights, n); + res.first = max(res.first, cur.first); + res.second = min(res.second, cur.second); + + return cache[key] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} weights + * @param {number} k + * @return {number} + */ + putMarbles(weights, k) { + const n = weights.length; + const cache = new Map(); + + const dfs = (i, k) => { + const key = `${i},${k}`; + if (cache.has(key)) return cache.get(key); + if (k === 0) return [0, 0]; + if (i === n - 1 || n - i - 1 < k) return [-1e15, 1e15]; + + let res = [0, 1e15]; + + let cur = dfs(i + 1, k - 1); + res[0] = Math.max(res[0], weights[i] + weights[i + 1] + cur[0]); + res[1] = Math.min(res[1], weights[i] + weights[i + 1] + cur[1]); + + cur = dfs(i + 1, k); + res[0] = Math.max(res[0], cur[0]); + res[1] = Math.min(res[1], cur[1]); + + cache.set(key, res); + return res; + }; + + const ans = dfs(0, k - 1); + return ans[0] - ans[1]; + } +} +``` + +```csharp +public class Solution { + Dictionary cache = new Dictionary(); + + public long PutMarbles(int[] weights, int k) { + int n = weights.Length; + long[] ans = Dfs(0, k - 1, weights, n); + return (int)(ans[0] - ans[1]); + } + + private long[] Dfs(int i, int k, int[] weights, int n) { + string key = $"{i},{k}"; + if (cache.ContainsKey(key)) return cache[key]; + if (k == 0) return new long[] { 0L, 0L }; + if (i == n - 1 || n - i - 1 < k) { + return new long[] { -1000000000000000L, 1000000000000000L }; + } + + long[] res = new long[] { 0L, 1000000000000000L }; + + long[] cur = Dfs(i + 1, k - 1, weights, n); + res[0] = Math.Max(res[0], weights[i] + weights[i + 1] + cur[0]); + res[1] = Math.Min(res[1], weights[i] + weights[i + 1] + cur[1]); + + cur = Dfs(i + 1, k, weights, n); + res[0] = Math.Max(res[0], cur[0]); + res[1] = Math.Min(res[1], cur[1]); + + cache[key] = res; + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * k)$ +- Space complexity: $O(n * k)$ + +> Where $n$ is the number of marbles, and $k$ is the number of bags. + +--- + +## 2. Greedy + Sorting + +::tabs-start + +```python +class Solution: + def putMarbles(self, weights: List[int], k: int) -> int: + if k == 1: + return 0 + + splits = [] + for i in range(len(weights) - 1): + splits.append(weights[i] + weights[i + 1]) + + splits.sort() + i = k - 1 + + max_score = sum(splits[-i:]) + min_score = sum(splits[:i]) + return max_score - min_score +``` + +```java +public class Solution { + public long putMarbles(int[] weights, int k) { + if (k == 1) return 0L; + + int n = weights.length; + List splits = new ArrayList<>(); + + for (int i = 0; i < n - 1; i++) { + splits.add(weights[i] + weights[i + 1]); + } + + Collections.sort(splits); + int i = k - 1; + long maxScore = 0, minScore = 0; + + for (int j = 0; j < i; j++) minScore += splits.get(j); + for (int j = splits.size() - i; j < splits.size(); j++) { + maxScore += splits.get(j); + } + + return maxScore - minScore; + } +} +``` + +```cpp +class Solution { +public: + long long putMarbles(vector& weights, int k) { + if (k == 1) return 0LL; + + int n = weights.size(); + vector splits; + + for (int i = 0; i < n - 1; ++i) { + splits.push_back(weights[i] + weights[i + 1]); + } + + sort(splits.begin(), splits.end()); + int i = k - 1; + long long minScore = 0, maxScore = 0; + + for (int j = 0; j < i; ++j) minScore += splits[j]; + for (int j = splits.size() - i; j < splits.size(); ++j) { + maxScore += splits[j]; + } + + return maxScore - minScore; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} weights + * @param {number} k + * @return {number} + */ + putMarbles(weights, k) { + if (k === 1) return 0; + + const splits = []; + for (let i = 0; i < weights.length - 1; i++) { + splits.push(weights[i] + weights[i + 1]); + } + + splits.sort((a, b) => a - b); + const i = k - 1; + + let minScore = 0, + maxScore = 0; + for (let j = 0; j < i; j++) minScore += splits[j]; + for (let j = splits.length - i; j < splits.length; j++) { + maxScore += splits[j]; + } + + return maxScore - minScore; + } +} +``` + +```csharp +public class Solution { + public long PutMarbles(int[] weights, int k) { + if (k == 1) return 0L; + + int n = weights.Length; + List splits = new List(); + + for (int i = 0; i < n - 1; i++) { + splits.Add(weights[i] + weights[i + 1]); + } + + splits.Sort(); + int iVal = k - 1; + long minScore = 0, maxScore = 0; + + for (int j = 0; j < iVal; j++) minScore += splits[j]; + for (int j = splits.Count - iVal; j < splits.Count; j++) { + maxScore += splits[j]; + } + + return maxScore - minScore; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +> Where $n$ is the number of marbles, and $k$ is the number of bags. + +--- + +## 3. Heap + +::tabs-start + +```python +class Solution: + def putMarbles(self, weights: List[int], k: int) -> int: + if k == 1: + return 0 + + max_heap = [] + min_heap = [] + + for i in range(len(weights) - 1): + split = weights[i] + weights[i + 1] + + if len(max_heap) < k - 1: + heapq.heappush(max_heap, split) + else: + heapq.heappushpop(max_heap, split) + + if len(min_heap) < k - 1: + heapq.heappush(min_heap, -split) + else: + heapq.heappushpop(min_heap, -split) + + max_score = sum(max_heap) + min_score = -sum(min_heap) + return max_score - min_score +``` + +```java +public class Solution { + public long putMarbles(int[] weights, int k) { + if (k == 1) return 0L; + + PriorityQueue maxHeap = new PriorityQueue<>(); + PriorityQueue minHeap = new PriorityQueue<>(Collections.reverseOrder()); + + for (int i = 0; i < weights.length - 1; i++) { + int split = weights[i] + weights[i + 1]; + + if (maxHeap.size() < k - 1) maxHeap.offer(split); + else if (split > maxHeap.peek()) { + maxHeap.poll(); + maxHeap.offer(split); + } + + if (minHeap.size() < k - 1) minHeap.offer(split); + else if (split < minHeap.peek()) { + minHeap.poll(); + minHeap.offer(split); + } + } + + long maxScore = 0, minScore = 0; + for (int val : maxHeap) maxScore += val; + for (int val : minHeap) minScore += val; + + return maxScore - minScore; + } +} +``` + +```cpp +class Solution { +public: + long long putMarbles(vector& weights, int k) { + if (k == 1) return 0LL; + + priority_queue, greater> maxHeap; + priority_queue minHeap; + + for (int i = 0; i < weights.size() - 1; ++i) { + int split = weights[i] + weights[i + 1]; + + if ((int)maxHeap.size() < k - 1) maxHeap.push(split); + else if (split > maxHeap.top()) { + maxHeap.pop(); + maxHeap.push(split); + } + + if ((int)minHeap.size() < k - 1) minHeap.push(split); + else if (split < minHeap.top()) { + minHeap.pop(); + minHeap.push(split); + } + } + + long long maxScore = 0, minScore = 0; + while (!maxHeap.empty()) { + maxScore += maxHeap.top(); + maxHeap.pop(); + } + while (!minHeap.empty()) { + minScore += minHeap.top(); + minHeap.pop(); + } + + return maxScore - minScore; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} weights + * @param {number} k + * @return {number} + */ + putMarbles(weights, k) { + if (k === 1) return 0; + + const minHeap = new MinPriorityQueue(); + const maxHeap = new MaxPriorityQueue(); + + for (let i = 0; i < weights.length - 1; i++) { + const sum = weights[i] + weights[i + 1]; + + minHeap.enqueue(sum); + if (minHeap.size() > k - 1) minHeap.dequeue(); + + maxHeap.enqueue(sum); + if (maxHeap.size() > k - 1) maxHeap.dequeue(); + } + + let maxScore = 0, + minScore = 0; + while (!minHeap.isEmpty()) maxScore += minHeap.dequeue(); + while (!maxHeap.isEmpty()) minScore += maxHeap.dequeue(); + + return maxScore - minScore; + } +} +``` + +```csharp +public class Solution { + public long PutMarbles(int[] weights, int k) { + if (k == 1) return 0L; + + var maxHeap = new PriorityQueue(); + var minHeap = new PriorityQueue( + Comparer.Create((a, b) => b.CompareTo(a)) + ); + + for (int i = 0; i < weights.Length - 1; i++) { + int split = weights[i] + weights[i + 1]; + + maxHeap.Enqueue(split, split); + if (maxHeap.Count > k - 1) maxHeap.Dequeue(); + + minHeap.Enqueue(split, split); + if (minHeap.Count > k - 1) minHeap.Dequeue(); + } + + long maxScore = 0, minScore = 0; + while (maxHeap.Count > 0) maxScore += maxHeap.Dequeue(); + while (minHeap.Count > 0) minScore += minHeap.Dequeue(); + + return maxScore - minScore; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log k)$ +- Space complexity: $O(k)$ + +> Where $n$ is the number of marbles, and $k$ is the number of bags. diff --git a/articles/queue-reconstruction-by-height.md b/articles/queue-reconstruction-by-height.md index 72dbfcf5c..0829530eb 100644 --- a/articles/queue-reconstruction-by-height.md +++ b/articles/queue-reconstruction-by-height.md @@ -39,33 +39,33 @@ public class Solution { public int[][] reconstructQueue(int[][] people) { int n = people.length; Map> mp = new HashMap<>(); - + for (int[] p : people) { mp.computeIfAbsent(p[1], k -> new ArrayList<>()).add(p[0]); - } + } for (int key : mp.keySet()) { Collections.sort(mp.get(key), Collections.reverseOrder()); } - + List res = new ArrayList<>(); for (int i = 0; i < n; i++) { int mini = -1; for (int k : mp.keySet()) { if (k > i) continue; - + int cnt = 0; for (int j = res.size() - 1; j >= 0; j--) { if (res.get(j)[0] >= mp.get(k).get(mp.get(k).size() - 1)) { cnt++; } } - - if (cnt == k && (mini == -1 || mp.get(k).get(mp.get(k).size() - 1) < + + if (cnt == k && (mini == -1 || mp.get(k).get(mp.get(k).size() - 1) < mp.get(mini).get(mp.get(mini).size() - 1))) { mini = k; } } - + List list = mp.get(mini); res.add(new int[]{list.get(list.size() - 1), mini}); list.remove(list.size() - 1); @@ -73,7 +73,7 @@ public class Solution { mp.remove(mini); } } - + return res.toArray(new int[n][2]); } } @@ -85,40 +85,40 @@ public: vector> reconstructQueue(vector>& people) { int n = people.size(); unordered_map> mp; - + for (const auto& p : people) { mp[p[1]].push_back(p[0]); } for (auto& pair : mp) { sort(pair.second.rbegin(), pair.second.rend()); } - + vector> res; for (int i = 0; i < n; i++) { int mini = -1; for (const auto& pair : mp) { int k = pair.first; if (k > i) continue; - + int cnt = 0; for (int j = res.size() - 1; j >= 0; j--) { if (res[j][0] >= mp[k].back()) { cnt++; } } - + if (cnt == k && (mini == -1 || mp[k].back() < mp[mini].back())) { mini = k; } } - + res.push_back({mp[mini].back(), mini}); mp[mini].pop_back(); if (mp[mini].empty()) { mp.erase(mini); } } - + return res; } }; @@ -153,7 +153,12 @@ class Solution { if (res[j][0] >= heights[heights.length - 1]) cnt++; } - if (cnt === k && (mini === -1 || heights[heights.length - 1] < mp.get(mini)[mp.get(mini).length - 1])) { + if ( + cnt === k && + (mini === -1 || + heights[heights.length - 1] < + mp.get(mini)[mp.get(mini).length - 1]) + ) { mini = k; } } @@ -173,8 +178,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n + n ^ 3)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n + n ^ 3)$ +- Space complexity: $O(n)$ --- @@ -212,14 +217,14 @@ public: sort(people.begin(), people.end(), [](auto& a, auto& b) { return a[0] == b[0] ? a[1] < b[1] : a[0] > b[0]; }); - + list> res; for (const auto& p : people) { auto it = res.begin(); advance(it, p[1]); res.insert(it, p); } - + return vector>(res.begin(), res.end()); } }; @@ -246,8 +251,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n\log n + n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n\log n + n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -271,7 +276,7 @@ class Solution: cnt += 1 i += 1 res[i] = p - + return res ``` @@ -308,7 +313,7 @@ public: sort(people.begin(), people.end(), [](auto& a, auto& b) { return a[0] == b[0] ? a[1] > b[1] : a[0] < b[0]; }); - + vector> res(people.size(), vector()); for (const auto& p : people) { int cnt = 0, i = 0; @@ -321,7 +326,7 @@ public: } res[i] = p; } - + return res; } }; @@ -334,11 +339,12 @@ class Solution { * @return {number[][]} */ reconstructQueue(people) { - people.sort((a, b) => a[0] === b[0] ? b[1] - a[1] : a[0] - b[0]); + people.sort((a, b) => (a[0] === b[0] ? b[1] - a[1] : a[0] - b[0])); const res = Array(people.length).fill(null); for (const p of people) { - let cnt = 0, i = 0; + let cnt = 0, + i = 0; while (i < people.length) { if (res[i] === null) { @@ -359,8 +365,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n\log n + n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n\log n + n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -423,10 +429,10 @@ class Solution: r = mid - 1 else: l = mid + 1 - + res[idx] = p segTree.update(idx, 0) - + return res ``` @@ -548,7 +554,7 @@ public: return a[0] == b[0] ? a[1] > b[1] : a[0] < b[0]; }); vector> res(n, vector()); - + SegmentTree segTree(n); for (const auto& p : people) { int l = 0, r = n - 1, idx = 0; @@ -566,7 +572,7 @@ public: res[idx] = p; segTree.update(idx, 0); } - + return res; } }; @@ -576,7 +582,7 @@ public: class SegmentTree { /** * @constructor - * @param {number} N + * @param {number} N */ constructor(N) { this.n = N; @@ -585,7 +591,7 @@ class SegmentTree { } this.build(N); } - + /** * @param {number} N * @return {void} @@ -596,19 +602,19 @@ class SegmentTree { this.tree[this.n + i] = 1; } for (let i = this.n - 1; i > 0; i--) { - this.tree[i] = this.tree[i << 1] + this.tree[i << 1 | 1]; + this.tree[i] = this.tree[i << 1] + this.tree[(i << 1) | 1]; } } /** - * @param {number} i + * @param {number} i * @param {number} val * @return {void} */ update(i, val) { this.tree[this.n + i] = val; for (let j = (this.n + i) >> 1; j >= 1; j >>= 1) { - this.tree[j] = this.tree[j << 1] + this.tree[j << 1 | 1]; + this.tree[j] = this.tree[j << 1] + this.tree[(j << 1) | 1]; } } @@ -640,12 +646,14 @@ class Solution { */ reconstructQueue(people) { const n = people.length; - people.sort((a, b) => a[0] === b[0] ? b[1] - a[1] : a[0] - b[0]); + people.sort((a, b) => (a[0] === b[0] ? b[1] - a[1] : a[0] - b[0])); const res = Array(n).fill(null); - + const segTree = new SegmentTree(n); for (const p of people) { - let l = 0, r = n - 1, idx = 0; + let l = 0, + r = n - 1, + idx = 0; while (l <= r) { let mid = (l + r) >> 1; let cnt = segTree.query(0, mid); @@ -670,8 +678,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n\log ^ 2 n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n\log ^ 2 n)$ +- Space complexity: $O(n)$ --- @@ -721,10 +729,10 @@ class Solution: r = mid - 1 else: l = mid + 1 - + res[idx] = p bit.update(idx, -1) - + return res ``` @@ -836,7 +844,7 @@ public: return a[0] == b[0] ? a[1] > b[1] : a[0] < b[0]; }); vector> res(n, vector()); - + BIT bit(n); for (const auto& p : people) { int l = 0, r = n - 1, idx = 0; @@ -854,7 +862,7 @@ public: res[idx] = p; bit.update(idx, -1); } - + return res; } }; @@ -874,8 +882,8 @@ class BIT { } } - /** - * @param {number} index + /** + * @param {number} index * @param {number} val * @return {void} */ @@ -887,8 +895,8 @@ class BIT { } } - /** - * @param {number} index + /** + * @param {number} index * @return {number} */ prefixSum(index) { @@ -900,8 +908,8 @@ class BIT { return totalSum; } - /** - * @param {number} left + /** + * @param {number} left * @param {number} right * @return {number} */ @@ -917,12 +925,14 @@ class Solution { */ reconstructQueue(people) { const n = people.length; - people.sort((a, b) => a[0] === b[0] ? b[1] - a[1] : a[0] - b[0]); + people.sort((a, b) => (a[0] === b[0] ? b[1] - a[1] : a[0] - b[0])); const res = Array(n).fill(null); - + const bit = new BIT(n); for (const p of people) { - let l = 0, r = n - 1, idx = 0; + let l = 0, + r = n - 1, + idx = 0; while (l <= r) { let mid = (l + r) >> 1; let cnt = bit.query(0, mid); @@ -947,8 +957,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n\log ^ 2 n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n\log ^ 2 n)$ +- Space complexity: $O(n)$ --- @@ -992,7 +1002,7 @@ class Solution: idx = bit.getIdx(p[1], MSB) res[idx] = p bit.update(idx, -1) - + return res ``` @@ -1094,7 +1104,7 @@ public: return a[0] == b[0] ? a[1] > b[1] : a[0] < b[0]; }); vector> res(n, vector()); - + BIT bit(n); int MSB = 1 << (31 - __builtin_clz(n)); for (const auto& p : people) { @@ -1102,7 +1112,7 @@ public: res[idx] = p; bit.update(idx, -1); } - + return res; } }; @@ -1122,8 +1132,8 @@ class BIT { } } - /** - * @param {number} index + /** + * @param {number} index * @param {number} val * @return {void} */ @@ -1135,8 +1145,8 @@ class BIT { } } - /** - * @param {number} cnt + /** + * @param {number} cnt * @param {number} MSB * @return {number} */ @@ -1161,9 +1171,9 @@ class Solution { */ reconstructQueue(people) { const n = people.length; - people.sort((a, b) => a[0] === b[0] ? b[1] - a[1] : a[0] - b[0]); + people.sort((a, b) => (a[0] === b[0] ? b[1] - a[1] : a[0] - b[0])); const res = Array(n).fill(null); - + const bit = new BIT(n); const MSB = 1 << Math.floor(Math.log2(n)); for (const p of people) { @@ -1181,5 +1191,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n\log n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n\log n)$ +- Space complexity: $O(n)$ diff --git a/articles/random-pick-with-weight.md b/articles/random-pick-with-weight.md new file mode 100644 index 000000000..c9bd815a2 --- /dev/null +++ b/articles/random-pick-with-weight.md @@ -0,0 +1,345 @@ +## 1. Prefix Sum + Linear Search + +::tabs-start + +```python +class Solution: + + def __init__(self, w: List[int]): + self.w = w + self.total = sum(w) + + def pickIndex(self) -> int: + target = self.total * random.random() + curSum = 0 + for i in range(len(self.w)): + curSum += self.w[i] + if curSum > target: + return i + + +# Your Solution object will be instantiated and called as such: +# obj = Solution(w) +# param_1 = obj.pickIndex() +``` + +```java +public class Solution { + int[] w; + int total; + + public Solution(int[] w) { + this.w = w; + for (int weight : w) { + total += weight; + } + } + + public int pickIndex() { + double target = total * Math.random(); + int curSum = 0; + for (int i = 0; i < w.length; i++) { + curSum += w[i]; + if (curSum > target) { + return i; + } + } + return -1; + } +} + + +/** + * Your Solution object will be instantiated and called as such: + * Solution obj = new Solution(w); + * int param_1 = obj.pickIndex(); + */ +``` + +```cpp +class Solution { +public: + vector w; + int total = 0; + + Solution(vector& w) { + this->w = w; + for (int weight : w) { + total += weight; + } + } + + int pickIndex() { + double target = total * ((double) rand() / RAND_MAX); + int curSum = 0; + for (int i = 0; i < w.size(); i++) { + curSum += w[i]; + if (curSum > target) { + return i; + } + } + return -1; + } +}; + + +/** + * Your Solution object will be instantiated and called as such: + * Solution* obj = new Solution(w); + * int param_1 = obj->pickIndex(); + */ +``` + +```javascript +class Solution { + /** + * @param {number[]} w + */ + constructor(w) { + this.w = w; + this.total = w.reduce((a, b) => a + b, 0); + } + + /** + * @return {number} + */ + pickIndex() { + let target = this.total * Math.random(); + let curSum = 0; + for (let i = 0; i < this.w.length; i++) { + curSum += this.w[i]; + if (curSum > target) { + return i; + } + } + return -1; + } +} + + +/** + * Your Solution object will be instantiated and called as such: + * var obj = new Solution(w) + * var param_1 = obj.pickIndex() + */ +``` + +```csharp +public class Solution { + private int[] w; + private int total; + + public Solution(int[] w) { + this.w = w; + foreach (int weight in w) { + total += weight; + } + } + + public int PickIndex() { + double target = total * new Random().NextDouble(); + int curSum = 0; + for (int i = 0; i < w.Length; i++) { + curSum += w[i]; + if (curSum > target) { + return i; + } + } + return -1; + } +} + + +/** + * Your Solution object will be instantiated and called as such: + * Solution obj = new Solution(w); + * int param_1 = obj.PickIndex(); + */ +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ for initializing and $O(n)$ for each $pickIndex()$ function call. +* Space complexity: $O(n)$ + +--- + +## 2. Prefix Sum + Binary Search + +::tabs-start + +```python +class Solution: + + def __init__(self, w: List[int]): + self.prefix = [0] + for wgt in w: + self.prefix.append(self.prefix[-1] + wgt) + + def pickIndex(self) -> int: + target = self.prefix[-1] * random.random() + l, r = 1, len(self.prefix) + while l < r: + mid = (l + r) >> 1 + if self.prefix[mid] <= target: + l = mid + 1 + else: + r = mid + return l - 1 + + +# Your Solution object will be instantiated and called as such: +# obj = Solution(w) +# param_1 = obj.pickIndex() +``` + +```java +public class Solution { + private int[] prefix; + + public Solution(int[] w) { + prefix = new int[w.length + 1]; + for (int i = 0; i < w.length; i++) { + prefix[i + 1] = prefix[i] + w[i]; + } + } + + public int pickIndex() { + double target = prefix[prefix.length - 1] * Math.random(); + int l = 1, r = prefix.length; + while (l < r) { + int mid = (l + r) >> 1; + if (prefix[mid] <= target) { + l = mid + 1; + } else { + r = mid; + } + } + return l - 1; + } +} + + +/** + * Your Solution object will be instantiated and called as such: + * Solution obj = new Solution(w); + * int param_1 = obj.pickIndex(); + */ +``` + +```cpp +class Solution { +public: + vector prefix; + + Solution(vector& w) { + prefix.push_back(0); + for (int wgt : w) { + prefix.push_back(prefix.back() + wgt); + } + } + + int pickIndex() { + double target = prefix.back() * ((double) rand() / RAND_MAX); + int l = 1, r = prefix.size(); + while (l < r) { + int mid = (l + r) >> 1; + if (prefix[mid] <= target) { + l = mid + 1; + } else { + r = mid; + } + } + return l - 1; + } +}; + + +/** + * Your Solution object will be instantiated and called as such: + * Solution* obj = new Solution(w); + * int param_1 = obj->pickIndex(); + */ +``` + +```javascript +class Solution { + /** + * @param {number[]} w + */ + constructor(w) { + this.prefix = [0]; + for (let i = 0; i < w.length; i++) { + this.prefix.push(this.prefix[this.prefix.length - 1] + w[i]); + } + } + + /** + * @return {number} + */ + pickIndex() { + const total = this.prefix[this.prefix.length - 1]; + const target = total * Math.random(); + let l = 1, r = this.prefix.length; + while (l < r) { + const mid = (l + r) >> 1; + if (this.prefix[mid] <= target) { + l = mid + 1; + } else { + r = mid; + } + } + return l - 1; + } +} + + +/** + * Your Solution object will be instantiated and called as such: + * var obj = new Solution(w) + * var param_1 = obj.pickIndex() + */ +``` + +```csharp +public class Solution { + private List prefix; + + public Solution(int[] w) { + prefix = new List { 0 }; + foreach (int wgt in w) { + prefix.Add(prefix[^1] + wgt); + } + } + + public int PickIndex() { + double target = prefix[^1] * new Random().NextDouble(); + int l = 1, r = prefix.Count; + while (l < r) { + int mid = (l + r) >> 1; + if (prefix[mid] <= target) { + l = mid + 1; + } else { + r = mid; + } + } + return l - 1; + } +} + + +/** + * Your Solution object will be instantiated and called as such: + * Solution obj = new Solution(w); + * int param_1 = obj.PickIndex(); + */ +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ for initializing and $O(\log n)$ for each $pickIndex()$ function call. +* Space complexity: $O(n)$ \ No newline at end of file diff --git a/articles/range-sum-of-bst.md b/articles/range-sum-of-bst.md new file mode 100644 index 000000000..dcda43480 --- /dev/null +++ b/articles/range-sum-of-bst.md @@ -0,0 +1,509 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def rangeSumBST(self, root: Optional[TreeNode], low: int, high: int) -> int: + if not root: + return 0 + + res = root.val if low <= root.val <= high else 0 + res += self.rangeSumBST(root.left, low, high) + res += self.rangeSumBST(root.right, low, high) + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int rangeSumBST(TreeNode root, int low, int high) { + if (root == null) return 0; + + int res = (low <= root.val && root.val <= high) ? root.val : 0; + res += rangeSumBST(root.left, low, high); + res += rangeSumBST(root.right, low, high); + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int rangeSumBST(TreeNode* root, int low, int high) { + if (!root) return 0; + + int res = (low <= root->val && root->val <= high) ? root->val : 0; + res += rangeSumBST(root->left, low, high); + res += rangeSumBST(root->right, low, high); + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} low + * @param {number} high + * @return {number} + */ + rangeSumBST(root, low, high) { + if (!root) return 0; + + let res = low <= root.val && root.val <= high ? root.val : 0; + res += this.rangeSumBST(root.left, low, high); + res += this.rangeSumBST(root.right, low, high); + return res; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public int RangeSumBST(TreeNode root, int low, int high) { + if (root == null) return 0; + + int res = (root.val >= low && root.val <= high) ? root.val : 0; + res += RangeSumBST(root.left, low, high); + res += RangeSumBST(root.right, low, high); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Depth First Search (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def rangeSumBST(self, root: Optional[TreeNode], low: int, high: int) -> int: + if not root: + return 0 + + if root.val > high: + return self.rangeSumBST(root.left, low, high) + if root.val < low: + return self.rangeSumBST(root.right, low, high) + + return ( + root.val + + self.rangeSumBST(root.left, low, high) + + self.rangeSumBST(root.right, low, high) + ) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int rangeSumBST(TreeNode root, int low, int high) { + if (root == null) return 0; + + if (root.val > high) { + return rangeSumBST(root.left, low, high); + } + if (root.val < low) { + return rangeSumBST(root.right, low, high); + } + + return root.val + rangeSumBST(root.left, low, high) + + rangeSumBST(root.right, low, high); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int rangeSumBST(TreeNode* root, int low, int high) { + if (!root) return 0; + + if (root->val > high) { + return rangeSumBST(root->left, low, high); + } + if (root->val < low) { + return rangeSumBST(root->right, low, high); + } + + return root->val + rangeSumBST(root->left, low, high) + + rangeSumBST(root->right, low, high); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} low + * @param {number} high + * @return {number} + */ + rangeSumBST(root, low, high) { + if (!root) return 0; + + if (root.val > high) { + return rangeSumBST(root.left, low, high); + } + if (root.val < low) { + return rangeSumBST(root.right, low, high); + } + + return ( + root.val + + this.rangeSumBST(root.left, low, high) + + this.rangeSumBST(root.right, low, high) + ); + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public int RangeSumBST(TreeNode root, int low, int high) { + if (root == null) return 0; + + if (root.val > high) { + return RangeSumBST(root.left, low, high); + } + if (root.val < low) { + return RangeSumBST(root.right, low, high); + } + + return root.val + + RangeSumBST(root.left, low, high) + + RangeSumBST(root.right, low, high); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def rangeSumBST(self, root: Optional[TreeNode], low: int, high: int) -> int: + stack = [root] + res = 0 + + while stack: + node = stack.pop() + if not node: + continue + + if low <= node.val <= high: + res += node.val + if node.val > low: + stack.append(node.left) + if node.val < high: + stack.append(node.right) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int rangeSumBST(TreeNode root, int low, int high) { + int res = 0; + Stack stack = new Stack<>(); + stack.push(root); + + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + if (node == null) continue; + + if (low <= node.val && node.val <= high) { + res += node.val; + } + if (node.val > low) { + stack.push(node.left); + } + if (node.val < high) { + stack.push(node.right); + } + } + + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int rangeSumBST(TreeNode* root, int low, int high) { + int res = 0; + stack stack; + stack.push(root); + + while (!stack.empty()) { + TreeNode* node = stack.top(); + stack.pop(); + if (!node) continue; + + if (low <= node->val && node->val <= high) { + res += node->val; + } + if (node->val > low) { + stack.push(node->left); + } + if (node->val < high) { + stack.push(node->right); + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} low + * @param {number} high + * @return {number} + */ + rangeSumBST(root, low, high) { + let res = 0; + let stack = [root]; + + while (stack.length > 0) { + let node = stack.pop(); + if (!node) continue; + + if (low <= node.val && node.val <= high) { + res += node.val; + } + if (node.val > low) { + stack.push(node.left); + } + if (node.val < high) { + stack.push(node.right); + } + } + + return res; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public int RangeSumBST(TreeNode root, int low, int high) { + var stack = new Stack(); + stack.Push(root); + int res = 0; + + while (stack.Count > 0) { + var node = stack.Pop(); + if (node == null) continue; + + if (node.val >= low && node.val <= high) { + res += node.val; + } + if (node.val > low) { + stack.Push(node.left); + } + if (node.val < high) { + stack.Push(node.right); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/range-sum-query-2d-immutable.md b/articles/range-sum-query-2d-immutable.md index 3d19e47b0..9401b666f 100644 --- a/articles/range-sum-query-2d-immutable.md +++ b/articles/range-sum-query-2d-immutable.md @@ -68,10 +68,10 @@ class NumMatrix { this.matrix = matrix; } - /** - * @param {number} row1 - * @param {number} col1 - * @param {number} row2 + /** + * @param {number} row1 + * @param {number} col1 + * @param {number} row2 * @param {number} col2 * @return {number} */ @@ -87,12 +87,32 @@ class NumMatrix { } ``` +```csharp +public class NumMatrix { + private int[][] matrix; + + public NumMatrix(int[][] matrix) { + this.matrix = matrix; + } + + public int SumRegion(int row1, int col1, int row2, int col2) { + int res = 0; + for (int r = row1; r <= row2; r++) { + for (int c = col1; c <= col2; c++) { + res += matrix[r][c]; + } + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ for each query. -* Space complexity: $O(1)$ +- Time complexity: $O(m * n)$ for each query. +- Space complexity: $O(1)$ > Where $m$ is the number of rows and $n$ is the number of columns in the matrix. @@ -107,7 +127,7 @@ class NumMatrix: def __init__(self, matrix: list[list[int]]): self.prefixSum = [[0] * len(matrix[0]) for _ in range(len(matrix))] - + for row in range(len(matrix)): self.prefixSum[row][0] = matrix[row][0] for col in range(1, len(matrix[0])): @@ -192,20 +212,23 @@ class NumMatrix { * @param {number[][]} matrix */ constructor(matrix) { - this.prefixSum = Array.from({ length: matrix.length }, () => Array(matrix[0].length).fill(0)); + this.prefixSum = Array.from({ length: matrix.length }, () => + Array(matrix[0].length).fill(0), + ); for (let row = 0; row < matrix.length; row++) { this.prefixSum[row][0] = matrix[row][0]; for (let col = 1; col < matrix[0].length; col++) { - this.prefixSum[row][col] = this.prefixSum[row][col - 1] + matrix[row][col]; + this.prefixSum[row][col] = + this.prefixSum[row][col - 1] + matrix[row][col]; } } } - /** - * @param {number} row1 - * @param {number} col1 - * @param {number} row2 + /** + * @param {number} row1 + * @param {number} col1 + * @param {number} row2 * @param {number} col2 * @return {number} */ @@ -213,7 +236,8 @@ class NumMatrix { let res = 0; for (let row = row1; row <= row2; row++) { if (col1 > 0) { - res += this.prefixSum[row][col2] - this.prefixSum[row][col1 - 1]; + res += + this.prefixSum[row][col2] - this.prefixSum[row][col1 - 1]; } else { res += this.prefixSum[row][col2]; } @@ -223,12 +247,44 @@ class NumMatrix { } ``` +```csharp +public class NumMatrix { + private int[][] prefixSum; + + public NumMatrix(int[][] matrix) { + int rows = matrix.Length; + int cols = matrix[0].Length; + prefixSum = new int[rows][]; + + for (int i = 0; i < rows; i++) { + prefixSum[i] = new int[cols]; + prefixSum[i][0] = matrix[i][0]; + for (int j = 1; j < cols; j++) { + prefixSum[i][j] = prefixSum[i][j - 1] + matrix[i][j]; + } + } + } + + public int SumRegion(int row1, int col1, int row2, int col2) { + int res = 0; + for (int row = row1; row <= row2; row++) { + if (col1 > 0) { + res += prefixSum[row][col2] - prefixSum[row][col1 - 1]; + } else { + res += prefixSum[row][col2]; + } + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns in the matrix. @@ -328,8 +384,11 @@ class NumMatrix { * @param {number[][]} matrix */ constructor(matrix) { - const ROWS = matrix.length, COLS = matrix[0].length; - this.sumMat = Array.from({ length: ROWS + 1 }, () => Array(COLS + 1).fill(0)); + const ROWS = matrix.length, + COLS = matrix[0].length; + this.sumMat = Array.from({ length: ROWS + 1 }, () => + Array(COLS + 1).fill(0), + ); for (let r = 0; r < ROWS; r++) { let prefix = 0; @@ -341,15 +400,18 @@ class NumMatrix { } } - /** - * @param {number} row1 - * @param {number} col1 - * @param {number} row2 + /** + * @param {number} row1 + * @param {number} col1 + * @param {number} row2 * @param {number} col2 * @return {number} */ sumRegion(row1, col1, row2, col2) { - row1++; col1++; row2++; col2++; + row1++; + col1++; + row2++; + col2++; const bottomRight = this.sumMat[row2][col2]; const above = this.sumMat[row1 - 1][col2]; const left = this.sumMat[row2][col1 - 1]; @@ -359,11 +421,41 @@ class NumMatrix { } ``` +```csharp +public class NumMatrix { + private int[,] sumMat; + + public NumMatrix(int[][] matrix) { + int ROWS = matrix.Length; + int COLS = matrix[0].Length; + sumMat = new int[ROWS + 1, COLS + 1]; + + for (int r = 0; r < ROWS; r++) { + int prefix = 0; + for (int c = 0; c < COLS; c++) { + prefix += matrix[r][c]; + int above = sumMat[r, c + 1]; + sumMat[r + 1, c + 1] = prefix + above; + } + } + } + + public int SumRegion(int row1, int col1, int row2, int col2) { + row1++; col1++; row2++; col2++; + int bottomRight = sumMat[row2, col2]; + int above = sumMat[row1 - 1, col2]; + int left = sumMat[row2, col1 - 1]; + int topLeft = sumMat[row1 - 1, col1 - 1]; + return bottomRight - above - left + topLeft; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ for each query. -* Space complexity: $O(m * n)$ +- Time complexity: $O(1)$ for each query. +- Space complexity: $O(m * n)$ -> Where $m$ is the number of rows and $n$ is the number of columns in the matrix. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns in the matrix. diff --git a/articles/range-sum-query-immutable.md b/articles/range-sum-query-immutable.md index f53012caa..dec6558e6 100644 --- a/articles/range-sum-query-immutable.md +++ b/articles/range-sum-query-immutable.md @@ -59,8 +59,8 @@ class NumArray { this.nums = nums; } - /** - * @param {number} left + /** + * @param {number} left * @param {number} right * @return {number} */ @@ -78,8 +78,8 @@ class NumArray { ### Time & Space Complexity -* Time complexity: $O(n)$ for each $sumRange()$ query. -* Space complexity: $O(1)$ since we only make a reference to the input array. +- Time complexity: $O(n)$ for each $sumRange()$ query. +- Space complexity: $O(1)$ since we only make a reference to the input array. --- @@ -159,8 +159,8 @@ class NumArray { } } - /** - * @param {number} left + /** + * @param {number} left * @param {number} right * @return {number} */ @@ -176,8 +176,8 @@ class NumArray { ### Time & Space Complexity -* Time complexity: $O(1)$ for each $sumRange()$ query, $O(n)$ for building the prefix sum array. -* Space complexity: $O(n)$ +- Time complexity: $O(1)$ for each $sumRange()$ query, $O(n)$ for building the prefix sum array. +- Space complexity: $O(n)$ --- @@ -191,7 +191,7 @@ class NumArray: self.prefix = [0] * (len(nums) + 1) for i in range(len(nums)): self.prefix[i + 1] = self.prefix[i] + nums[i] - + def sumRange(self, left, right): return self.prefix[right + 1] - self.prefix[left] @@ -245,8 +245,8 @@ class NumArray { } } - /** - * @param {number} left + /** + * @param {number} left * @param {number} right * @return {number} */ @@ -260,8 +260,8 @@ class NumArray { ### Time & Space Complexity -* Time complexity: $O(1)$ for each $sumRange()$ query, $O(n)$ for building the prefix sum array. -* Space complexity: $O(n)$ +- Time complexity: $O(1)$ for each $sumRange()$ query, $O(n)$ for building the prefix sum array. +- Space complexity: $O(n)$ --- @@ -433,8 +433,8 @@ class NumArray { this.segTree = new SegmentTree(nums); } - /** - * @param {number} left + /** + * @param {number} left * @param {number} right * @return {number} */ @@ -448,5 +448,5 @@ class NumArray { ### Time & Space Complexity -* Time complexity: $O(\log n)$ for each $sumRange()$ query, $O(n)$ for building the Segment Tree. -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(\log n)$ for each $sumRange()$ query, $O(n)$ for building the Segment Tree. +- Space complexity: $O(n)$ diff --git a/articles/range-sum-query-mutable.md b/articles/range-sum-query-mutable.md index 358921e03..7d694e093 100644 --- a/articles/range-sum-query-mutable.md +++ b/articles/range-sum-query-mutable.md @@ -73,8 +73,8 @@ class NumArray { this.nums = nums; } - /** - * @param {number} index + /** + * @param {number} index * @param {number} val * @return {void} */ @@ -82,8 +82,8 @@ class NumArray { this.nums[index] = val; } - /** - * @param {number} left + /** + * @param {number} left * @param {number} right * @return {number} */ @@ -101,11 +101,11 @@ class NumArray { ### Time & Space Complexity -* Time complexity: - * $O(n)$ for initializing the input array. - * $O(1)$ for each $update()$ function call. - * $O(n)$ for each $sumRange()$ function call. -* Space complexity: $O(n)$ +- Time complexity: + - $O(n)$ for initializing the input array. + - $O(1)$ for each $update()$ function call. + - $O(n)$ for each $sumRange()$ function call. +- Space complexity: $O(n)$ --- @@ -322,11 +322,11 @@ public: NumArray(vector& nums) { this->segTree = new SegmentTree(nums.size(), nums); } - + void update(int index, int val) { this->segTree->update(index, val); } - + int sumRange(int left, int right) { return this->segTree->query(left, right); } @@ -337,7 +337,7 @@ public: class SegmentTree { /** * @constructor - * @param {number} N + * @param {number} N * @param {number[]} A */ constructor(N, A) { @@ -348,12 +348,12 @@ class SegmentTree { this.tree = new Int32Array(2 * this.n); this.build(0, 0, this.n - 1, A); } - + /** - * @param {number} node - * @param {number} start - * @param {number} end - * @param {number[]} A + * @param {number} node + * @param {number} start + * @param {number} end + * @param {number[]} A */ build(node, start, end, A) { if (start === end) { @@ -389,11 +389,11 @@ class SegmentTree { } /** - * @param {number} node - * @param {number} start - * @param {number} end - * @param {number} l - * @param {number} r + * @param {number} node + * @param {number} start + * @param {number} end + * @param {number} l + * @param {number} r * @return {number} */ _query(node, start, end, l, r) { @@ -419,8 +419,8 @@ class SegmentTree { } /** - * @param {number} l - * @param {number} r + * @param {number} l + * @param {number} r * @return {number} */ query(l, r) { @@ -436,8 +436,8 @@ class NumArray { this.segTree = new SegmentTree(nums.length, nums); } - /** - * @param {number} index + /** + * @param {number} index * @param {number} val * @return {void} */ @@ -445,8 +445,8 @@ class NumArray { this.segTree.update(index, val); } - /** - * @param {number} left + /** + * @param {number} left * @param {number} right * @return {number} */ @@ -460,11 +460,11 @@ class NumArray { ### Time & Space Complexity -* Time complexity: - * $O(n)$ for initializing the input array. - * $O(\log n)$ for each $update()$ function call. - * $O(\log n)$ for each $sumRange()$ function call. -* Space complexity: $O(n)$ +- Time complexity: + - $O(n)$ for initializing the input array. + - $O(\log n)$ for each $update()$ function call. + - $O(\log n)$ for each $sumRange()$ function call. +- Space complexity: $O(n)$ --- @@ -627,11 +627,11 @@ public: NumArray(vector& nums) { this->segTree = new SegmentTree(nums.size(), nums); } - + void update(int index, int val) { this->segTree->update(index, val); } - + int sumRange(int left, int right) { return this->segTree->query(left, right); } @@ -642,7 +642,7 @@ public: class SegmentTree { /** * @constructor - * @param {number} N + * @param {number} N * @param {number[]} A */ constructor(N, A) { @@ -652,9 +652,9 @@ class SegmentTree { } this.build(N, A); } - + /** - * @param {number} N + * @param {number} N * @param {number[]} A * @return {void} */ @@ -664,7 +664,7 @@ class SegmentTree { this.tree[this.n + i] = A[i]; } for (let i = this.n - 1; i > 0; i--) { - this.tree[i] = this.tree[i << 1] + this.tree[i << 1 | 1]; + this.tree[i] = this.tree[i << 1] + this.tree[(i << 1) | 1]; } } @@ -676,7 +676,7 @@ class SegmentTree { update(i, val) { this.tree[this.n + i] = val; for (let j = (this.n + i) >> 1; j >= 1; j >>= 1) { - this.tree[j] = this.tree[j << 1] + this.tree[j << 1 | 1]; + this.tree[j] = this.tree[j << 1] + this.tree[(j << 1) | 1]; } } @@ -709,8 +709,8 @@ class NumArray { this.segTree = new SegmentTree(nums.length, nums); } - /** - * @param {number} index + /** + * @param {number} index * @param {number} val * @return {void} */ @@ -718,8 +718,8 @@ class NumArray { this.segTree.update(index, val); } - /** - * @param {number} left + /** + * @param {number} left * @param {number} right * @return {number} */ @@ -733,11 +733,11 @@ class NumArray { ### Time & Space Complexity -* Time complexity: - * $O(n)$ for initializing the input array. - * $O(\log n)$ for each $update()$ function call. - * $O(\log n)$ for each $sumRange()$ function call. -* Space complexity: $O(n)$ +- Time complexity: + - $O(n)$ for initializing the input array. + - $O(\log n)$ for each $update()$ function call. + - $O(\log n)$ for each $sumRange()$ function call. +- Space complexity: $O(n)$ --- @@ -747,7 +747,7 @@ class NumArray { ```python class SqrtDecomposition: - + def __init__(self, nums): self.A = nums[:] self.n = len(nums) @@ -926,8 +926,8 @@ class SqrtDecomposition { } } - /** - * @param {number} left + /** + * @param {number} left * @param {number} right * @return {number} */ @@ -949,8 +949,8 @@ class SqrtDecomposition { return totalSum; } - /** - * @param {number} index + /** + * @param {number} index * @param {number} val * @return {void} */ @@ -969,8 +969,8 @@ class NumArray { this.sq = new SqrtDecomposition(nums); } - /** - * @param {number} index + /** + * @param {number} index * @param {number} val * @return {void} */ @@ -978,8 +978,8 @@ class NumArray { this.sq.update(index, val); } - /** - * @param {number} left + /** + * @param {number} left * @param {number} right * @return {number} */ @@ -993,11 +993,11 @@ class NumArray { ### Time & Space Complexity -* Time complexity: - * $O(n)$ for initializing the input array. - * $O(1)$ for each $update()$ function call. - * $O(\sqrt {n})$ for each $sumRange()$ function call. -* Space complexity: $O(n)$ +- Time complexity: + - $O(n)$ for initializing the input array. + - $O(1)$ for each $update()$ function call. + - $O(\sqrt {n})$ for each $sumRange()$ function call. +- Space complexity: $O(n)$ --- @@ -1192,16 +1192,25 @@ class SqrtDecomposition { } } - /** - * @param {number} left + /** + * @param {number} left * @param {number} right * @return {number} */ query(left, right) { - let totalSum = (left % this.blockSize !== 0) ? -this.prefixSums[left - 1] : 0; - - while (Math.floor(left / this.blockSize) < Math.floor(right / this.blockSize)) { - const blockEnd = Math.min(this.n - 1, Math.floor(left / this.blockSize) * this.blockSize + this.blockSize - 1); + let totalSum = + left % this.blockSize !== 0 ? -this.prefixSums[left - 1] : 0; + + while ( + Math.floor(left / this.blockSize) < + Math.floor(right / this.blockSize) + ) { + const blockEnd = Math.min( + this.n - 1, + Math.floor(left / this.blockSize) * this.blockSize + + this.blockSize - + 1, + ); totalSum += this.prefixSums[blockEnd]; left = blockEnd + 1; } @@ -1210,8 +1219,8 @@ class SqrtDecomposition { return totalSum; } - /** - * @param {number} index + /** + * @param {number} index * @param {number} val * @return {void} */ @@ -1219,7 +1228,12 @@ class SqrtDecomposition { const diff = val - this.nums[index]; this.nums[index] = val; - const blockEnd = Math.min(this.n - 1, Math.floor(index / this.blockSize) * this.blockSize + this.blockSize - 1); + const blockEnd = Math.min( + this.n - 1, + Math.floor(index / this.blockSize) * this.blockSize + + this.blockSize - + 1, + ); for (let i = index; i <= blockEnd; i++) { this.prefixSums[i] += diff; } @@ -1234,8 +1248,8 @@ class NumArray { this.sq = new SqrtDecomposition(nums); } - /** - * @param {number} index + /** + * @param {number} index * @param {number} val * @return {void} */ @@ -1243,8 +1257,8 @@ class NumArray { this.sq.update(index, val); } - /** - * @param {number} left + /** + * @param {number} left * @param {number} right * @return {number} */ @@ -1258,11 +1272,11 @@ class NumArray { ### Time & Space Complexity -* Time complexity: - * $O(n)$ for initializing the input array. - * $O(\sqrt {n})$ for each $update()$ function call. - * $O(\sqrt {n})$ for each $sumRange()$ function call. -* Space complexity: $O(n)$ +- Time complexity: + - $O(n)$ for initializing the input array. + - $O(\sqrt {n})$ for each $update()$ function call. + - $O(\sqrt {n})$ for each $sumRange()$ function call. +- Space complexity: $O(n)$ --- @@ -1436,8 +1450,8 @@ class BIT { } } - /** - * @param {number} index + /** + * @param {number} index * @param {number} val * @return {void} */ @@ -1451,8 +1465,8 @@ class BIT { } } - /** - * @param {number} index + /** + * @param {number} index * @return {number} */ prefixSum(index) { @@ -1464,8 +1478,8 @@ class BIT { return totalSum; } - /** - * @param {number} left + /** + * @param {number} left * @param {number} right * @return {number} */ @@ -1482,8 +1496,8 @@ class NumArray { this.bit = new BIT(nums); } - /** - * @param {number} index + /** + * @param {number} index * @param {number} val * @return {void} */ @@ -1491,8 +1505,8 @@ class NumArray { this.bit.update(index, val); } - /** - * @param {number} left + /** + * @param {number} left * @param {number} right * @return {number} */ @@ -1506,8 +1520,8 @@ class NumArray { ### Time & Space Complexity -* Time complexity: - * $O(n)$ for initializing the input array. - * $O(\log n)$ for each $update()$ function call. - * $O(\log n)$ for each $sumRange()$ function call. -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: + - $O(n)$ for initializing the input array. + - $O(\log n)$ for each $update()$ function call. + - $O(\log n)$ for each $sumRange()$ function call. +- Space complexity: $O(n)$ diff --git a/articles/ransom-note.md b/articles/ransom-note.md new file mode 100644 index 000000000..d14efd748 --- /dev/null +++ b/articles/ransom-note.md @@ -0,0 +1,319 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def canConstruct(self, ransomNote: str, magazine: str) -> bool: + magazine = list(magazine) + + for c in ransomNote: + if c not in magazine: + return False + else: + magazine.remove(c) + + return True +``` + +```java +public class Solution { + public boolean canConstruct(String ransomNote, String magazine) { + List mag = new ArrayList<>(); + for (char c : magazine.toCharArray()) { + mag.add(c); + } + + for (char c : ransomNote.toCharArray()) { + if (!mag.contains(c)) return false; + mag.remove((Character) c); + } + + return true; + } +} +``` + +```cpp +class Solution { +public: + bool canConstruct(string ransomNote, string magazine) { + vector mag(magazine.begin(), magazine.end()); + + for (char c : ransomNote) { + auto it = find(mag.begin(), mag.end(), c); + if (it == mag.end()) return false; + mag.erase(it); + } + + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} ransomNote + * @param {string} magazine + * @return {boolean} + */ + canConstruct(ransomNote, magazine) { + let mag = magazine.split(""); + + for (let c of ransomNote) { + let idx = mag.indexOf(c); + if (idx === -1) return false; + mag.splice(idx, 1); + } + + return true; + } +} +``` + +```csharp +public class Solution { + public bool CanConstruct(string ransomNote, string magazine) { + List mag = new List(magazine); + + foreach (char c in ransomNote) { + if (!mag.Contains(c)) return false; + mag.Remove(c); + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m * n)$ +* Space complexity: $O(n)$ + +> Where $m$ and $n$ are the lengths of the strings $ransomNote$ and $magazine$, respectively. + +--- + +## 2. Count Frequency + +::tabs-start + +```python +class Solution: + def canConstruct(self, ransomNote: str, magazine: str) -> bool: + countR = Counter(ransomNote) + countM = Counter(magazine) + + for c in countR: + if countM[c] < countR[c]: + return False + + return True +``` + +```java +public class Solution { + public boolean canConstruct(String ransomNote, String magazine) { + int[] countR = new int[26]; + int[] countM = new int[26]; + + for (char c : ransomNote.toCharArray()) { + countR[c - 'a']++; + } + + for (char c : magazine.toCharArray()) { + countM[c - 'a']++; + } + + for (int i = 0; i < 26; i++) { + if (countM[i] < countR[i]) return false; + } + + return true; + } +} +``` + +```cpp +class Solution { +public: + bool canConstruct(string ransomNote, string magazine) { + int countR[26] = {}; + int countM[26] = {}; + + for (char c : ransomNote) { + countR[c - 'a']++; + } + + for (char c : magazine) { + countM[c - 'a']++; + } + + for (int i = 0; i < 26; ++i) { + if (countM[i] < countR[i]) return false; + } + + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} ransomNote + * @param {string} magazine + * @return {boolean} + */ + canConstruct(ransomNote, magazine) { + const countR = Array(26).fill(0); + const countM = Array(26).fill(0); + + for (const c of ransomNote) { + countR[c.charCodeAt(0) - 97]++; + } + + for (const c of magazine) { + countM[c.charCodeAt(0) - 97]++; + } + + for (let i = 0; i < 26; i++) { + if (countM[i] < countR[i]) return false; + } + + return true; + } +} +``` + +```csharp +public class Solution { + public bool CanConstruct(string ransomNote, string magazine) { + int[] countR = new int[26]; + int[] countM = new int[26]; + + foreach (char c in ransomNote) { + countR[c - 'a']++; + } + + foreach (char c in magazine) { + countM[c - 'a']++; + } + + for (int i = 0; i < 26; i++) { + if (countM[i] < countR[i]) return false; + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m + n)$ +* Space complexity: $O(1)$ since we have at most $26$ different characters. + +> Where $m$ and $n$ are the lengths of the strings $ransomNote$ and $magazine$, respectively. + +--- + +## 3. Count Frequency (Optimal) + +::tabs-start + +```python +class Solution: + def canConstruct(self, ransomNote: str, magazine: str) -> bool: + count = [0] * 26 + for c in magazine: + count[ord(c) - ord('a')] += 1 + + for c in ransomNote: + count[ord(c) - ord('a')] -= 1 + if count[ord(c) - ord('a')] < 0: + return False + + return True +``` + +```java +public class Solution { + public boolean canConstruct(String ransomNote, String magazine) { + int[] count = new int[26]; + for (char c : magazine.toCharArray()) { + count[c - 'a']++; + } + for (char c : ransomNote.toCharArray()) { + if (--count[c - 'a'] < 0) return false; + } + return true; + } +} +``` + +```cpp +class Solution { +public: + bool canConstruct(string ransomNote, string magazine) { + int count[26] = {}; + for (char c : magazine) { + count[c - 'a']++; + } + for (char c : ransomNote) { + if (--count[c - 'a'] < 0) return false; + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} ransomNote + * @param {string} magazine + * @return {boolean} + */ + canConstruct(ransomNote, magazine) { + const count = Array(26).fill(0); + for (const c of magazine) { + count[c.charCodeAt(0) - 97]++; + } + for (const c of ransomNote) { + if (--count[c.charCodeAt(0) - 97] < 0) return false; + } + return true; + } +} +``` + +```csharp +public class Solution { + public bool CanConstruct(string ransomNote, string magazine) { + int[] count = new int[26]; + foreach (char c in magazine) { + count[c - 'a']++; + } + foreach (char c in ransomNote) { + if (--count[c - 'a'] < 0) return false; + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(m + n)$ +* Space complexity: $O(1)$ since we have at most $26$ different characters. + +> Where $m$ and $n$ are the lengths of the strings $ransomNote$ and $magazine$, respectively. \ No newline at end of file diff --git a/articles/rearrange-array-elements-by-sign.md b/articles/rearrange-array-elements-by-sign.md new file mode 100644 index 000000000..02e465145 --- /dev/null +++ b/articles/rearrange-array-elements-by-sign.md @@ -0,0 +1,312 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def rearrangeArray(self, nums: List[int]) -> List[int]: + n = len(nums) + for i in range(n): + if ((i % 2 == 0 and nums[i] > 0) or + (i % 2 == 1 and nums[i] < 0)): + continue + + j = i + 1 + while j < n and ((nums[j] > 0) == (nums[i] > 0)): + j += 1 + + tmp = nums[j] + while j > i: + nums[j] = nums[j - 1] + j -= 1 + nums[i] = tmp + return nums +``` + +```java +public class Solution { + public int[] rearrangeArray(int[] nums) { + int n = nums.length; + for (int i = 0; i < n; i++) { + if ((i % 2 == 0 && nums[i] > 0) || (i % 2 == 1 && nums[i] < 0)) { + continue; + } + + int j = i + 1; + while (j < n && ((nums[j] > 0) == (nums[i] > 0))) { + j++; + } + + int temp = nums[j]; + while (j > i) { + nums[j] = nums[j - 1]; + j--; + } + nums[i] = temp; + } + return nums; + } +} +``` + +```cpp +class Solution { +public: + vector rearrangeArray(vector& nums) { + int n = nums.size(); + for (int i = 0; i < n; i++) { + if ((i % 2 == 0 && nums[i] > 0) || (i % 2 == 1 && nums[i] < 0)) { + continue; + } + + int j = i + 1; + while (j < n && ((nums[j] > 0) == (nums[i] > 0))) { + j++; + } + + int temp = nums[j]; + while (j > i) { + nums[j] = nums[j - 1]; + j--; + } + nums[i] = temp; + } + return nums; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + rearrangeArray(nums) { + let n = nums.length; + for (let i = 0; i < n; i++) { + if ((i % 2 === 0 && nums[i] > 0) || (i % 2 === 1 && nums[i] < 0)) { + continue; + } + + let j = i + 1; + while (j < n && nums[j] > 0 === nums[i] > 0) { + j++; + } + + let temp = nums[j]; + while (j > i) { + nums[j] = nums[j - 1]; + j--; + } + nums[i] = temp; + } + return nums; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 2. Group Numbers Into Two Arrays + +::tabs-start + +```python +class Solution: + def rearrangeArray(self, nums: List[int]) -> List[int]: + pos, neg = [], [] + for num in nums: + if num > 0: + pos.append(num) + else: + neg.append(num) + + i = 0 + while 2 * i < len(nums): + nums[2 * i] = pos[i] + nums[2 * i + 1] = neg[i] + i += 1 + return nums +``` + +```java +public class Solution { + public int[] rearrangeArray(int[] nums) { + List pos = new ArrayList<>(); + List neg = new ArrayList<>(); + for (int num : nums) { + if (num > 0) { + pos.add(num); + } else { + neg.add(num); + } + } + + int i = 0; + while (2 * i < nums.length) { + nums[2 * i] = pos.get(i); + nums[2 * i + 1] = neg.get(i); + i++; + } + return nums; + } +} +``` + +```cpp +class Solution { +public: + vector rearrangeArray(vector& nums) { + vector pos, neg; + for (int num : nums) { + if (num > 0) { + pos.push_back(num); + } else { + neg.push_back(num); + } + } + + int i = 0; + while (2 * i < nums.size()) { + nums[2 * i] = pos[i]; + nums[2 * i + 1] = neg[i]; + i++; + } + return nums; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + rearrangeArray(nums) { + const pos = [], + neg = []; + for (const num of nums) { + if (num > 0) { + pos.push(num); + } else { + neg.push(num); + } + } + + let i = 0; + while (2 * i < nums.length) { + nums[2 * i] = pos[i]; + nums[2 * i + 1] = neg[i]; + i++; + } + return nums; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Two Pointers + +::tabs-start + +```python +class Solution: + def rearrangeArray(self, nums: List[int]) -> List[int]: + i, j = 0, 1 + res = [0] * len(nums) + for k in range(len(nums)): + if nums[k] > 0: + res[i] = nums[k] + i += 2 + else: + res[j] = nums[k] + j += 2 + return res +``` + +```java +public class Solution { + public int[] rearrangeArray(int[] nums) { + int i = 0, j = 1; + int[] res = new int[nums.length]; + for (int k = 0; k < nums.length; k++) { + if (nums[k] > 0) { + res[i] = nums[k]; + i += 2; + } else { + res[j] = nums[k]; + j += 2; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector rearrangeArray(vector& nums) { + int i = 0, j = 1; + vector res(nums.size()); + for (int k = 0; k < nums.size(); k++) { + if (nums[k] > 0) { + res[i] = nums[k]; + i += 2; + } else { + res[j] = nums[k]; + j += 2; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + rearrangeArray(nums) { + let i = 0, + j = 1; + const res = new Array(nums.length); + for (let k = 0; k < nums.length; k++) { + if (nums[k] > 0) { + res[i] = nums[k]; + i += 2; + } else { + res[j] = nums[k]; + j += 2; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for the output array. diff --git a/articles/reconstruct-flight-path.md b/articles/reconstruct-flight-path.md index b76aff7a7..571538aea 100644 --- a/articles/reconstruct-flight-path.md +++ b/articles/reconstruct-flight-path.md @@ -25,7 +25,7 @@ class Solution: adj[src].insert(i, v) res.pop() return False - + dfs("JFK") return res ``` @@ -37,31 +37,31 @@ public class Solution { for (List ticket : tickets) { adj.putIfAbsent(ticket.get(0), new ArrayList<>()); } - + tickets.sort((a, b) -> a.get(1).compareTo(b.get(1))); for (List ticket : tickets) { adj.get(ticket.get(0)).add(ticket.get(1)); } - + List res = new ArrayList<>(); res.add("JFK"); - + if (dfs("JFK", res, adj, tickets.size() + 1)) { return res; } return new ArrayList<>(); } - - private boolean dfs(String src, List res, + + private boolean dfs(String src, List res, Map> adj, int targetLen) { if (res.size() == targetLen) { return true; } - + if (!adj.containsKey(src)) { return false; } - + List temp = new ArrayList<>(adj.get(src)); for (int i = 0; i < temp.size(); i++) { String v = temp.get(i); @@ -96,7 +96,7 @@ public: } private: - bool dfs(const string& src, vector& res, + bool dfs(const string& src, vector& res, unordered_map>& adj, int targetLen) { if (res.size() == targetLen) { return true; @@ -137,7 +137,7 @@ class Solution { adj[src].push(dst); } - const res = ["JFK"]; + const res = ['JFK']; const dfs = (src) => { if (res.length === tickets.length + 1) return true; if (!adj[src]) return false; @@ -152,9 +152,9 @@ class Solution { adj[src].splice(i, 0, v); } return false; - } + }; - dfs("JFK"); + dfs('JFK'); return res; } } @@ -180,7 +180,7 @@ public class Solution { return res; } - private bool Dfs(string src, List res, + private bool Dfs(string src, List res, Dictionary> adj, int targetLen) { if (res.Count == targetLen) return true; if (!adj.ContainsKey(src)) return false; @@ -205,41 +205,41 @@ func findItinerary(tickets [][]string) []string { for _, ticket := range tickets { adj[ticket[0]] = append(adj[ticket[0]], ticket[1]) } - + for src := range adj { sort.Strings(adj[src]) } - + res := []string{"JFK"} - + var dfs func(string) bool dfs = func(src string) bool { if len(res) == len(tickets) + 1 { return true } - + destinations, exists := adj[src] if !exists { return false } - + temp := make([]string, len(destinations)) copy(temp, destinations) - + for i, v := range temp { adj[src] = append(adj[src][:i], adj[src][i+1:]...) res = append(res, v) - + if dfs(v) { return true } - + adj[src] = append(adj[src][:i], append([]string{v}, adj[src][i:]...)...) res = res[:len(res)-1] } return false } - + dfs("JFK") return res } @@ -249,34 +249,74 @@ func findItinerary(tickets [][]string) []string { class Solution { fun findItinerary(tickets: List>): List { val adj = HashMap>() - + tickets.sortedBy { it[1] }.forEach { (src, dst) -> adj.getOrPut(src) { mutableListOf() }.add(dst) } - + val res = mutableListOf("JFK") - + fun dfs(src: String): Boolean { if (res.size == tickets.size + 1) { return true } - + val destinations = adj[src] ?: return false - + for (i in destinations.indices) { val v = destinations.removeAt(i) res.add(v) - + if (dfs(v)) { return true } - + destinations.add(i, v) res.removeAt(res.lastIndex) } return false } - + + dfs("JFK") + return res + } +} +``` + +```swift +class Solution { + func findItinerary(_ tickets: [[String]]) -> [String] { + var adj = [String: [String]]() + for ticket in tickets { + adj[ticket[0], default: []].append(ticket[1]) + } + + for key in adj.keys { + adj[key]?.sort() + } + + var res = ["JFK"] + + func dfs(_ src: String) -> Bool { + if res.count == tickets.count + 1 { + return true + } + guard let destinations = adj[src] else { + return false + } + + var temp = destinations + for i in 0.. Where $E$ is the number of tickets (edges) and $V$ is the number of airports (vertices). @@ -311,7 +351,7 @@ class Solution: dst = adj[src].pop() dfs(dst) res.append(src) - + dfs('JFK') return res[::-1] ``` @@ -356,7 +396,7 @@ public: for (auto& [src, dests] : adj) { sort(dests.rbegin(), dests.rend()); } - + vector res; dfs("JFK", adj, res); reverse(res.begin(), res.end()); @@ -364,7 +404,7 @@ public: } private: - void dfs(const string& src, unordered_map>& adj, vector& res) { while (!adj[src].empty()) { string dst = adj[src].back(); @@ -385,12 +425,15 @@ class Solution { findItinerary(tickets) { const adj = new Map(); const res = []; - - tickets.sort().reverse().forEach(([src, dst]) => { - if (!adj.has(src)) adj.set(src, []); - adj.get(src).push(dst); - }); - + + tickets + .sort() + .reverse() + .forEach(([src, dst]) => { + if (!adj.has(src)) adj.set(src, []); + adj.get(src).push(dst); + }); + function dfs(src) { while (adj.has(src) && adj.get(src).length > 0) { const dst = adj.get(src).pop(); @@ -398,8 +441,8 @@ class Solution { } res.push(src); } - - dfs("JFK"); + + dfs('JFK'); return res.reverse(); } } @@ -409,7 +452,7 @@ class Solution { public class Solution { private Dictionary> adj; private List res = new List(); - + public List FindItinerary(List> tickets) { adj = new Dictionary>(); var sortedTickets = tickets.OrderByDescending(t => t[1]).ToList(); @@ -419,12 +462,12 @@ public class Solution { } adj[ticket[0]].Add(ticket[1]); } - + Dfs("JFK"); res.Reverse(); return res; } - + private void Dfs(string src) { while (adj.ContainsKey(src) && adj[src].Count > 0) { var dst = adj[src][adj[src].Count - 1]; @@ -439,21 +482,21 @@ public class Solution { ```go func findItinerary(tickets [][]string) []string { adj := make(map[string][]string) - + sort.Slice(tickets, func(i, j int) bool { if tickets[i][0] == tickets[j][0] { return tickets[i][1] > tickets[j][1] } return tickets[i][0] > tickets[j][0] }) - + for _, ticket := range tickets { src, dst := ticket[0], ticket[1] adj[src] = append(adj[src], dst) } - + res := make([]string, 0) - + var dfs func(string) dfs = func(src string) { for len(adj[src]) > 0 { @@ -464,13 +507,13 @@ func findItinerary(tickets [][]string) []string { } res = append(res, src) } - + dfs("JFK") - + for i := 0; i < len(res)/2; i++ { res[i], res[len(res)-1-i] = res[len(res)-1-i], res[i] } - + return res } ``` @@ -479,15 +522,15 @@ func findItinerary(tickets [][]string) []string { class Solution { fun findItinerary(tickets: List>): List { val adj = HashMap>() - + tickets.sortedWith(compareBy({ it[0] }, { it[1] })) .reversed() .forEach { (src, dst) -> adj.getOrPut(src) { mutableListOf() }.add(dst) } - + val res = mutableListOf() - + fun dfs(src: String) { while (adj[src]?.isNotEmpty() == true) { val dst = adj[src]!!.removeAt(adj[src]!!.lastIndex) @@ -495,7 +538,31 @@ class Solution { } res.add(src) } - + + dfs("JFK") + return res.reversed() + } +} +``` + +```swift +class Solution { + func findItinerary(_ tickets: [[String]]) -> [String] { + var adj = [String: [String]]() + for ticket in tickets.sorted(by: { $0[1] > $1[1] }) { + adj[ticket[0], default: []].append(ticket[1]) + } + + var res = [String]() + + func dfs(_ src: String) { + while let destinations = adj[src], !destinations.isEmpty { + let dst = adj[src]!.removeLast() + dfs(dst) + } + res.append(src) + } + dfs("JFK") return res.reversed() } @@ -506,8 +573,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(E\log E)$ -* Space complexity: $O(E)$ +- Time complexity: $O(E\log E)$ +- Space complexity: $O(E)$ > Where $E$ is the number of tickets (edges) and $V$ is the number of airports (vertices). @@ -523,17 +590,17 @@ class Solution: adj = defaultdict(list) for src, dst in sorted(tickets)[::-1]: adj[src].append(dst) - + stack = ["JFK"] res = [] - + while stack: curr = stack[-1] if not adj[curr]: res.append(stack.pop()) else: stack.append(adj[curr].pop()) - + return res[::-1] ``` @@ -542,14 +609,14 @@ public class Solution { public List findItinerary(List> tickets) { Map> adj = new HashMap<>(); for (List ticket : tickets) { - adj.computeIfAbsent(ticket.get(0), + adj.computeIfAbsent(ticket.get(0), k -> new PriorityQueue<>()).add(ticket.get(1)); } - + LinkedList res = new LinkedList<>(); Stack stack = new Stack<>(); stack.push("JFK"); - + while (!stack.isEmpty()) { String curr = stack.peek(); if (!adj.containsKey(curr) || adj.get(curr).isEmpty()) { @@ -558,7 +625,7 @@ public class Solution { stack.push(adj.get(curr).poll()); } } - + return res; } } @@ -575,11 +642,11 @@ public: for (auto& [src, destinations] : adj) { sort(destinations.rbegin(), destinations.rend()); } - + vector res; stack stk; stk.push("JFK"); - + while (!stk.empty()) { string curr = stk.top(); if (adj[curr].empty()) { @@ -591,7 +658,7 @@ public: stk.push(next); } } - + reverse(res.begin(), res.end()); return res; } @@ -606,14 +673,17 @@ class Solution { */ findItinerary(tickets) { const adj = new Map(); - tickets.sort().reverse().forEach(([src, dst]) => { - if (!adj.has(src)) adj.set(src, []); - adj.get(src).push(dst); - }); - + tickets + .sort() + .reverse() + .forEach(([src, dst]) => { + if (!adj.has(src)) adj.set(src, []); + adj.get(src).push(dst); + }); + const res = []; - const stack = ["JFK"]; - + const stack = ['JFK']; + while (stack.length > 0) { let curr = stack[stack.length - 1]; if (!adj.has(curr) || adj.get(curr).length === 0) { @@ -622,7 +692,7 @@ class Solution { stack.push(adj.get(curr).pop()); } } - + return res; } } @@ -638,11 +708,11 @@ public class Solution { } adj[ticket[0]].Add(ticket[1]); } - + var res = new List(); var stack = new Stack(); stack.Push("JFK"); - + while (stack.Count > 0) { var curr = stack.Peek(); if (!adj.ContainsKey(curr) || adj[curr].Count == 0) { @@ -653,7 +723,7 @@ public class Solution { stack.Push(next); } } - + return res; } } @@ -712,17 +782,42 @@ class Solution { stack.add(adj[curr]!!.removeLast()) } } - + return res.asReversed() } } ``` +```swift +class Solution { + func findItinerary(_ tickets: [[String]]) -> [String] { + var adj = [String: [String]]() + for ticket in tickets.sorted(by: { $0[1] > $1[1] }) { + adj[ticket[0], default: []].append(ticket[1]) + } + + var stack = ["JFK"] + var res = [String]() + + while !stack.isEmpty { + let curr = stack.last! + if adj[curr] == nil || adj[curr]!.isEmpty { + res.append(stack.removeLast()) + } else { + stack.append(adj[curr]!.removeLast()) + } + } + + return res.reversed() + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(E\log E)$ -* Space complexity: $O(E)$ +- Time complexity: $O(E\log E)$ +- Space complexity: $O(E)$ -> Where $E$ is the number of tickets (edges) and $V$ is the number of airports (vertices). \ No newline at end of file +> Where $E$ is the number of tickets (edges) and $V$ is the number of airports (vertices). diff --git a/articles/recover-binary-search-tree.md b/articles/recover-binary-search-tree.md new file mode 100644 index 000000000..8ead7cb15 --- /dev/null +++ b/articles/recover-binary-search-tree.md @@ -0,0 +1,982 @@ +## 1. Brute Force + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def recoverTree(self, root: Optional[TreeNode]) -> None: + """ + Do not return anything, modify root in-place instead. + """ + def isBST(node): + if not node: + return True + + q = deque([(node, float("-inf"), float("inf"))]) + while q: + cur, left, right = q.popleft() + if not (left < cur.val < right): + return False + if cur.left: + q.append((cur.left, left, cur.val)) + if cur.right: + q.append((cur.right, cur.val, right)) + + return True + + def dfs1(node1, node2): + if not node2 or node1 == node2: + return False + + node1.val, node2.val = node2.val, node1.val + if isBST(root): + return True + + node1.val, node2.val = node2.val, node1.val + return dfs1(node1, node2.left) or dfs1(node1, node2.right) + + + def dfs(node): + if not node: + return False + + if dfs1(node, root): + return True + + return dfs(node.left) or dfs(node.right) + + dfs(root) + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public void recoverTree(TreeNode root) { + dfs(root, root); + } + + private boolean dfs(TreeNode node1, TreeNode root) { + if (node1 == null) return false; + if (dfs1(node1, root, root)) return true; + return dfs(node1.left, root) || dfs(node1.right, root); + } + + private boolean dfs1(TreeNode node1, TreeNode node2, TreeNode root) { + if (node2 == null || node1 == node2) return false; + + swap(node1, node2); + if (isBST(root)) return true; + swap(node1, node2); + + return dfs1(node1, node2.left, root) || dfs1(node1, node2.right, root); + } + + private boolean isBST(TreeNode node) { + Queue q = new LinkedList<>(); + q.offer(new Object[]{node, Long.MIN_VALUE, Long.MAX_VALUE}); + + while (!q.isEmpty()) { + Object[] curr = q.poll(); + TreeNode n = (TreeNode) curr[0]; + long left = (long) curr[1]; + long right = (long) curr[2]; + + if (n == null) continue; + if (n.val <= left || n.val >= right) return false; + + q.offer(new Object[]{n.left, left, (long) n.val}); + q.offer(new Object[]{n.right, (long) n.val, right}); + } + + return true; + } + + private void swap(TreeNode a, TreeNode b) { + int tmp = a.val; + a.val = b.val; + b.val = tmp; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + void recoverTree(TreeNode* root) { + dfs(root, root, root); + } + + bool dfs(TreeNode* node1, TreeNode* node2, TreeNode* root) { + if (!node1) return false; + if (dfs1(node1, node2, root)) return true; + return dfs(node1->left, node2, root) || dfs(node1->right, node2, root); + } + + bool dfs1(TreeNode* node1, TreeNode* node2, TreeNode* root) { + if (!node2 || node1 == node2) return false; + + swap(node1->val, node2->val); + if (isBST(root)) return true; + swap(node1->val, node2->val); + + return dfs1(node1, node2->left, root) || dfs1(node1, node2->right, root); + } + + bool isBST(TreeNode* node) { + TreeNode* prev = nullptr; + return inorder(node, prev); + } + + bool inorder(TreeNode* node, TreeNode*& prev) { + if (!node) return true; + if (!inorder(node->left, prev)) return false; + if (prev && prev->val >= node->val) return false; + prev = node; + return inorder(node->right, prev); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ + class Solution { + /** + * @param {TreeNode} root + * @return {void} Do not return anything, modify root in-place instead. + */ + recoverTree(root) { + const isBST = (node) => { + const q = [[node, -Infinity, Infinity]]; + while (q.length) { + const [cur, left, right] = q.shift(); + if (!cur) continue; + if (!(left < cur.val && cur.val < right)) return false; + q.push([cur.left, left, cur.val]); + q.push([cur.right, cur.val, right]); + } + return true; + }; + + const dfs1 = (node1, node2) => { + if (!node2 || node1 === node2) return false; + [node1.val, node2.val] = [node2.val, node1.val]; + if (isBST(root)) return true; + [node1.val, node2.val] = [node2.val, node1.val]; + return dfs1(node1, node2.left) || dfs1(node1, node2.right); + }; + + const dfs = (node) => { + if (!node) return false; + if (dfs1(node, root)) return true; + return dfs(node.left) || dfs(node.right); + }; + + dfs(root); + } + } +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public void RecoverTree(TreeNode root) { + Dfs(root, root); + } + + private bool Dfs(TreeNode node1, TreeNode root) { + if (node1 == null) return false; + if (Dfs1(node1, root, root)) return true; + return Dfs(node1.left, root) || Dfs(node1.right, root); + } + + private bool Dfs1(TreeNode node1, TreeNode node2, TreeNode root) { + if (node2 == null || node1 == node2) return false; + + Swap(node1, node2); + if (IsBST(root)) return true; + Swap(node1, node2); + + return Dfs1(node1, node2.left, root) || Dfs1(node1, node2.right, root); + } + + private bool IsBST(TreeNode node) { + var q = new Queue<(TreeNode node, long min, long max)>(); + q.Enqueue((node, long.MinValue, long.MaxValue)); + + while (q.Count > 0) { + var (cur, min, max) = q.Dequeue(); + if (cur == null) continue; + long val = cur.val; + if (val <= min || val >= max) return false; + + q.Enqueue((cur.left, min, val)); + q.Enqueue((cur.right, val, max)); + } + return true; + } + + private void Swap(TreeNode a, TreeNode b) { + int temp = a.val; + a.val = b.val; + b.val = temp; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2)$ +* Space complexity: $O(n)$ + +--- + +## 2. Inorder Traversal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def recoverTree(self, root: Optional[TreeNode]) -> None: + """ + Do not return anything, modify root in-place instead. + """ + arr = [] + def inorder(node): + if not node: + return + + inorder(node.left) + arr.append(node) + inorder(node.right) + + inorder(root) + node1, node2 = None, None + + for i in range(len(arr) - 1): + if arr[i].val > arr[i + 1].val: + node2 = arr[i + 1] + if node1 is None: + node1 = arr[i] + else: + break + node1.val, node2.val = node2.val, node1.val +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public void recoverTree(TreeNode root) { + List arr = new ArrayList<>(); + inorder(root, arr); + + TreeNode node1 = null, node2 = null; + for (int i = 0; i < arr.size() - 1; i++) { + if (arr.get(i).val > arr.get(i + 1).val) { + node2 = arr.get(i + 1); + if (node1 == null) node1 = arr.get(i); + else break; + } + } + + int temp = node1.val; + node1.val = node2.val; + node2.val = temp; + } + + private void inorder(TreeNode node, List arr) { + if (node == null) return; + inorder(node.left, arr); + arr.add(node); + inorder(node.right, arr); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + void recoverTree(TreeNode* root) { + vector arr; + inorder(root, arr); + + TreeNode* node1 = nullptr; + TreeNode* node2 = nullptr; + + for (int i = 0; i < arr.size() - 1; i++) { + if (arr[i]->val > arr[i + 1]->val) { + node2 = arr[i + 1]; + if (!node1) node1 = arr[i]; + else break; + } + } + + swap(node1->val, node2->val); + } + + void inorder(TreeNode* node, vector& arr) { + if (!node) return; + inorder(node->left, arr); + arr.push_back(node); + inorder(node->right, arr); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ + class Solution { + /** + * @param {TreeNode} root + * @return {void} Do not return anything, modify root in-place instead. + */ + recoverTree(root) { + const arr = []; + + const inorder = node => { + if (!node) return; + inorder(node.left); + arr.push(node); + inorder(node.right); + }; + + inorder(root); + + let node1 = null, node2 = null; + for (let i = 0; i < arr.length - 1; i++) { + if (arr[i].val > arr[i + 1].val) { + node2 = arr[i + 1]; + if (node1 === null) node1 = arr[i]; + else break; + } + } + + [node1.val, node2.val] = [node2.val, node1.val]; + } + } +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public void RecoverTree(TreeNode root) { + var arr = new List(); + Inorder(root, arr); + + TreeNode node1 = null, node2 = null; + for (int i = 0; i < arr.Count - 1; i++) { + if (arr[i].val > arr[i + 1].val) { + node2 = arr[i + 1]; + if (node1 == null) node1 = arr[i]; + else break; + } + } + + int temp = node1.val; + node1.val = node2.val; + node2.val = temp; + } + + private void Inorder(TreeNode node, List arr) { + if (node == null) return; + Inorder(node.left, arr); + arr.Add(node); + Inorder(node.right, arr); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 3. Iterative Inorder Traversal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def recoverTree(self, root: Optional[TreeNode]) -> None: + stack = [] + node1 = node2 = prev = None + curr = root + + while stack or curr: + while curr: + stack.append(curr) + curr = curr.left + + curr = stack.pop() + if prev and prev.val > curr.val: + node2 = curr + if not node1: + node1 = prev + else: + break + prev = curr + curr = curr.right + + node1.val, node2.val = node2.val, node1.val +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public void recoverTree(TreeNode root) { + Stack stack = new Stack<>(); + TreeNode node1 = null, node2 = null, prev = null, curr = root; + + while (!stack.isEmpty() || curr != null) { + while (curr != null) { + stack.push(curr); + curr = curr.left; + } + + curr = stack.pop(); + if (prev != null && prev.val > curr.val) { + node2 = curr; + if (node1 == null) node1 = prev; + else break; + } + prev = curr; + curr = curr.right; + } + + int temp = node1.val; + node1.val = node2.val; + node2.val = temp; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + void recoverTree(TreeNode* root) { + stack stack; + TreeNode *node1 = nullptr, *node2 = nullptr, *prev = nullptr, *curr = root; + + while (!stack.empty() || curr) { + while (curr) { + stack.push(curr); + curr = curr->left; + } + + curr = stack.top(); stack.pop(); + if (prev && prev->val > curr->val) { + node2 = curr; + if (!node1) node1 = prev; + else break; + } + prev = curr; + curr = curr->right; + } + + swap(node1->val, node2->val); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ + class Solution { + /** + * @param {TreeNode} root + * @return {void} Do not return anything, modify root in-place instead. + */ + recoverTree(root) { + let stack = []; + let node1 = null, node2 = null, prev = null, curr = root; + + while (stack.length > 0 || curr) { + while (curr) { + stack.push(curr); + curr = curr.left; + } + + curr = stack.pop(); + if (prev && prev.val > curr.val) { + node2 = curr; + if (!node1) node1 = prev; + else break; + } + prev = curr; + curr = curr.right; + } + + [node1.val, node2.val] = [node2.val, node1.val]; + } + } +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public void RecoverTree(TreeNode root) { + var stack = new Stack(); + TreeNode node1 = null, node2 = null, prev = null, curr = root; + + while (stack.Count > 0 || curr != null) { + while (curr != null) { + stack.Push(curr); + curr = curr.left; + } + + curr = stack.Pop(); + if (prev != null && prev.val > curr.val) { + node2 = curr; + if (node1 == null) node1 = prev; + else break; + } + prev = curr; + curr = curr.right; + } + + int temp = node1.val; + node1.val = node2.val; + node2.val = temp; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(n)$ + +--- + +## 4. Morris Traversal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def recoverTree(self, root: Optional[TreeNode]) -> None: + node1 = node2 = prev = None + curr = root + + while curr: + if not curr.left: + if prev and prev.val > curr.val: + node2 = curr + if not node1: + node1 = prev + prev = curr + curr = curr.right + else: + pred = curr.left + while pred.right and pred.right != curr: + pred = pred.right + + if not pred.right: + pred.right = curr + curr = curr.left + else: + pred.right = None + if prev and prev.val > curr.val: + node2 = curr + if not node1: + node1 = prev + prev = curr + curr = curr.right + + node1.val, node2.val = node2.val, node1.val +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public void recoverTree(TreeNode root) { + TreeNode node1 = null, node2 = null, prev = null, curr = root; + + while (curr != null) { + if (curr.left == null) { + if (prev != null && prev.val > curr.val) { + node2 = curr; + if (node1 == null) node1 = prev; + } + prev = curr; + curr = curr.right; + } else { + TreeNode pred = curr.left; + while (pred.right != null && pred.right != curr) { + pred = pred.right; + } + + if (pred.right == null) { + pred.right = curr; + curr = curr.left; + } else { + pred.right = null; + if (prev != null && prev.val > curr.val) { + node2 = curr; + if (node1 == null) node1 = prev; + } + prev = curr; + curr = curr.right; + } + } + } + + int temp = node1.val; + node1.val = node2.val; + node2.val = temp; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + void recoverTree(TreeNode* root) { + TreeNode* node1 = nullptr; + TreeNode* node2 = nullptr; + TreeNode* prev = nullptr; + TreeNode* curr = root; + + while (curr) { + if (!curr->left) { + if (prev && prev->val > curr->val) { + node2 = curr; + if (!node1) node1 = prev; + } + prev = curr; + curr = curr->right; + } else { + TreeNode* pred = curr->left; + while (pred->right && pred->right != curr) { + pred = pred->right; + } + + if (!pred->right) { + pred->right = curr; + curr = curr->left; + } else { + pred->right = nullptr; + if (prev && prev->val > curr->val) { + node2 = curr; + if (!node1) node1 = prev; + } + prev = curr; + curr = curr->right; + } + } + } + + swap(node1->val, node2->val); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ + class Solution { + /** + * @param {TreeNode} root + * @return {void} Do not return anything, modify root in-place instead. + */ + recoverTree(root) { + let node1 = null, node2 = null, prev = null, curr = root; + + while (curr !== null) { + if (curr.left === null) { + if (prev !== null && prev.val > curr.val) { + node2 = curr; + if (node1 === null) node1 = prev; + } + prev = curr; + curr = curr.right; + } else { + let pred = curr.left; + while (pred.right !== null && pred.right !== curr) { + pred = pred.right; + } + + if (pred.right === null) { + pred.right = curr; + curr = curr.left; + } else { + pred.right = null; + if (prev !== null && prev.val > curr.val) { + node2 = curr; + if (node1 === null) node1 = prev; + } + prev = curr; + curr = curr.right; + } + } + } + + let temp = node1.val; + node1.val = node2.val; + node2.val = temp; + } + } +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public void RecoverTree(TreeNode root) { + TreeNode node1 = null, node2 = null, prev = null, curr = root; + + while (curr != null) { + if (curr.left == null) { + if (prev != null && prev.val > curr.val) { + node2 = curr; + if (node1 == null) node1 = prev; + } + prev = curr; + curr = curr.right; + } else { + TreeNode pred = curr.left; + while (pred.right != null && pred.right != curr) { + pred = pred.right; + } + + if (pred.right == null) { + pred.right = curr; + curr = curr.left; + } else { + pred.right = null; + if (prev != null && prev.val > curr.val) { + node2 = curr; + if (node1 == null) node1 = prev; + } + prev = curr; + curr = curr.right; + } + } + } + + int temp = node1.val; + node1.val = node2.val; + node2.val = temp; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/redistribute-characters-to-make-all-strings-equal.md b/articles/redistribute-characters-to-make-all-strings-equal.md index b825a3786..d503fb3d7 100644 --- a/articles/redistribute-characters-to-make-all-strings-equal.md +++ b/articles/redistribute-characters-to-make-all-strings-equal.md @@ -10,7 +10,7 @@ class Solution: for w in words: for c in w: char_cnt[c] += 1 - + for c in char_cnt: if char_cnt[c] % len(words): return False @@ -89,8 +89,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(n * m)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. > Where $n$ is the number of words and $m$ is the average length of each word. @@ -119,7 +119,7 @@ class Solution: if freq[i] % n != 0: flag -= 1 freq[i] %= n - + return flag == 0 ``` @@ -147,7 +147,7 @@ public class Solution { freq[i] %= n; } } - + return flag == 0; } } @@ -178,7 +178,7 @@ public: freq[i] %= n; } } - + return flag == 0; } }; @@ -222,7 +222,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(n * m)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. -> Where $n$ is the number of words and $m$ is the average length of each word. \ No newline at end of file +> Where $n$ is the number of words and $m$ is the average length of each word. diff --git a/articles/redundant-connection.md b/articles/redundant-connection.md index 4a51a9aa3..bedd63762 100644 --- a/articles/redundant-connection.md +++ b/articles/redundant-connection.md @@ -11,7 +11,7 @@ class Solution: def dfs(node, par): if visit[node]: return True - + visit[node] = True for nei in adj[node]: if nei == par: @@ -19,12 +19,12 @@ class Solution: if dfs(nei, node): return True return False - + for u, v in edges: adj[u].append(v) adj[v].append(u) visit = [False] * (n + 1) - + if dfs(u, -1): return [u, v] return [] @@ -52,7 +52,7 @@ public class Solution { return new int[0]; } - private boolean dfs(int node, int parent, + private boolean dfs(int node, int parent, List> adj, boolean[] visit) { if (visit[node]) { return true; @@ -93,7 +93,7 @@ public: } private: - bool dfs(int node, int parent, + bool dfs(int node, int parent, vector>& adj, vector& visit) { if (visit[node]) return true; visit[node] = true; @@ -161,7 +161,7 @@ public class Solution { return new int[0]; } - private bool Dfs(int node, int parent, + private bool Dfs(int node, int parent, List> adj, bool[] visit) { if (visit[node]) return true; visit[node] = true; @@ -204,7 +204,7 @@ func findRedundantConnection(edges [][]int) []int { for i := 0; i <= n; i++ { visit[i] = false } - + if dfs(u, -1) { return []int{u, v} } @@ -247,12 +247,51 @@ class Solution { } ``` +```swift +class Solution { + func findRedundantConnection(_ edges: [[Int]]) -> [Int] { + let n = edges.count + var adj = Array(repeating: [Int](), count: n + 1) + + func dfs(_ node: Int, _ par: Int, _ visit: inout [Bool]) -> Bool { + if visit[node] { + return true + } + + visit[node] = true + for nei in adj[node] { + if nei == par { + continue + } + if dfs(nei, node, &visit) { + return true + } + } + return false + } + + for edge in edges { + let u = edge[0] + let v = edge[1] + adj[u].append(v) + adj[v].append(u) + var visit = Array(repeating: false, count: n + 1) + + if dfs(u, -1, &visit) { + return [u, v] + } + } + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(E * (V + E))$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(E * (V + E))$ +- Space complexity: $O(V + E)$ > Where $V$ is the number of vertices and $E$ is the number of edges in the graph. @@ -274,13 +313,13 @@ class Solution: visit = [False] * (n + 1) cycle = set() cycleStart = -1 - + def dfs(node, par): nonlocal cycleStart if visit[node]: cycleStart = node - return True - + return True + visit[node] = True for nei in adj[node]: if nei == par: @@ -292,9 +331,9 @@ class Solution: cycleStart = -1 return True return False - + dfs(1, -1) - + for u, v in reversed(edges): if u in cycle and v in cycle: return [u, v] @@ -312,7 +351,7 @@ public class Solution { public int[] findRedundantConnection(int[][] edges) { int n = edges.length; adj = new ArrayList<>(); - for (int i = 0; i <= n; i++) + for (int i = 0; i <= n; i++) adj.add(new ArrayList<>()); for (int[] edge : edges) { @@ -527,7 +566,7 @@ func findRedundantConnection(edges [][]int) []int { cycleStart = node return true } - + visit[node] = true for _, nei := range adj[node] { if nei == par { @@ -606,12 +645,68 @@ class Solution { } ``` +```swift +class Solution { + func findRedundantConnection(_ edges: [[Int]]) -> [Int] { + let n = edges.count + var adj = Array(repeating: [Int](), count: n + 1) + + for edge in edges { + let u = edge[0] + let v = edge[1] + adj[u].append(v) + adj[v].append(u) + } + + var visit = Array(repeating: false, count: n + 1) + var cycle = Set() + var cycleStart = -1 + + func dfs(_ node: Int, _ par: Int) -> Bool { + if visit[node] { + cycleStart = node + return true + } + + visit[node] = true + for nei in adj[node] { + if nei == par { + continue + } + if dfs(nei, node) { + if cycleStart != -1 { + cycle.insert(node) + } + if node == cycleStart { + cycleStart = -1 + } + return true + } + } + return false + } + + dfs(1, -1) + + for edge in edges.reversed() { + let u = edge[0] + let v = edge[1] + if cycle.contains(u) && cycle.contains(v) { + return [u, v] + } + } + + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V + E)$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ > Where $V$ is the number of vertices and $E$ is the number of edges in the graph. @@ -632,7 +727,7 @@ class Solution: adj[v].append(u) indegree[u] += 1 indegree[v] += 1 - + q = deque() for i in range(1, n + 1): if indegree[i] == 1: @@ -646,7 +741,7 @@ class Solution: if indegree[nei] == 1: q.append(nei) - for u, v in edges[::-1]: + for u, v in reversed(edges): if indegree[u] == 2 and indegree[v]: return [u, v] return [] @@ -683,7 +778,7 @@ public class Solution { for (int i = edges.length - 1; i >= 0; i--) { int u = edges[i][0], v = edges[i][1]; - if (indegree[u] == 2 && indegree[v] > 0) + if (indegree[u] == 2 && indegree[v] > 0) return new int[]{u, v}; } return new int[0]; @@ -722,7 +817,7 @@ public: for (int i = edges.size() - 1; i >= 0; i--) { int u = edges[i][0], v = edges[i][1]; - if (indegree[u] == 2 && indegree[v]) + if (indegree[u] == 2 && indegree[v]) return {u, v}; } return {}; @@ -763,8 +858,7 @@ class Solution { for (let i = edges.length - 1; i >= 0; i--) { const [u, v] = edges[i]; - if (indegree[u] === 2 && indegree[v]) - return [u, v]; + if (indegree[u] === 2 && indegree[v]) return [u, v]; } return []; } @@ -802,7 +896,7 @@ public class Solution { for (int i = edges.Length - 1; i >= 0; i--) { int u = edges[i][0], v = edges[i][1]; - if (indegree[u] == 2 && indegree[v] > 0) + if (indegree[u] == 2 && indegree[v] > 0) return new int[] {u, v}; } return new int[0]; @@ -895,12 +989,58 @@ class Solution { } ``` +```swift +class Solution { + func findRedundantConnection(_ edges: [[Int]]) -> [Int] { + let n = edges.count + var indegree = Array(repeating: 0, count: n + 1) + var adj = Array(repeating: [Int](), count: n + 1) + + for edge in edges { + let u = edge[0] + let v = edge[1] + adj[u].append(v) + adj[v].append(u) + indegree[u] += 1 + indegree[v] += 1 + } + + var queue = Deque() + for i in 1...n { + if indegree[i] == 1 { + queue.append(i) + } + } + + while !queue.isEmpty { + let node = queue.popFirst()! + indegree[node] -= 1 + for nei in adj[node] { + indegree[nei] -= 1 + if indegree[nei] == 1 { + queue.append(nei) + } + } + } + + for edge in edges.reversed() { + let u = edge[0] + let v = edge[1] + if indegree[u] == 2 && indegree[v] > 0 { + return [u, v] + } + } + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V + E)$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ > Where $V$ is the number of vertices and $E$ is the number of edges in the graph. @@ -1086,7 +1226,7 @@ class Solution { ```csharp public class Solution { - + public int[] FindRedundantConnection(int[][] edges) { int[] par = new int[edges.Length + 1]; int[] rank = new int[edges.Length + 1]; @@ -1134,7 +1274,7 @@ func findRedundantConnection(edges [][]int) []int { n := len(edges) par := make([]int, n+1) rank := make([]int, n+1) - + for i := 0; i <= n; i++ { par[i] = i rank[i] = 1 @@ -1212,11 +1352,55 @@ class Solution { } ``` +```swift +class Solution { + func findRedundantConnection(_ edges: [[Int]]) -> [Int] { + var par = Array(0...edges.count) + var rank = Array(repeating: 1, count: edges.count + 1) + + func find(_ n: Int) -> Int { + var p = par[n] + while p != par[p] { + par[p] = par[par[p]] + p = par[p] + } + return p + } + + func union(_ n1: Int, _ n2: Int) -> Bool { + let p1 = find(n1) + let p2 = find(n2) + + if p1 == p2 { + return false + } + if rank[p1] > rank[p2] { + par[p2] = p1 + rank[p1] += rank[p2] + } else { + par[p1] = p2 + rank[p2] += rank[p1] + } + return true + } + + for edge in edges { + let n1 = edge[0] + let n2 = edge[1] + if !union(n1, n2) { + return [n1, n2] + } + } + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V + (E * α(V)))$ -* Space complexity: $O(V)$ +- Time complexity: $O(V + (E * α(V)))$ +- Space complexity: $O(V)$ -> Where $V$ is the number of vertices and $E$ is the number of edges in the graph. $α()$ is used for amortized complexity. \ No newline at end of file +> Where $V$ is the number of vertices and $E$ is the number of edges in the graph. $α()$ is used for amortized complexity. diff --git a/articles/regular-expression-matching.md b/articles/regular-expression-matching.md index 31b2a26a4..30ec007ac 100644 --- a/articles/regular-expression-matching.md +++ b/articles/regular-expression-matching.md @@ -10,15 +10,15 @@ class Solution: def dfs(i, j): if j == n: return i == m - + match = i < m and (s[i] == p[j] or p[j] == ".") if (j + 1) < n and p[j + 1] == "*": - return (dfs(i, j + 2) or # don't use * + return (dfs(i, j + 2) or # don't use * (match and dfs(i + 1, j))) # use * if match: return dfs(i + 1, j + 1) return False - + return dfs(0, 0) ``` @@ -32,17 +32,17 @@ public class Solution { private boolean dfs(int i, int j, String s, String p, int m, int n) { if (j == n) return i == m; - boolean match = i < m && (s.charAt(i) == p.charAt(j) || + boolean match = i < m && (s.charAt(i) == p.charAt(j) || p.charAt(j) == '.'); if (j + 1 < n && p.charAt(j + 1) == '*') { - return dfs(i, j + 2, s, p, m, n) || + return dfs(i, j + 2, s, p, m, n) || (match && dfs(i + 1, j, s, p, m, n)); } if (match) { return dfs(i + 1, j + 1, s, p, m, n); } - + return false; } } @@ -61,7 +61,7 @@ public: bool match = (i < m && (s[i] == p[j] || p[j] == '.')); if (j + 1 < n && p[j + 1] == '*') { - return dfs(i, j + 2, s, p, m, n) || + return dfs(i, j + 2, s, p, m, n) || (match && dfs(i + 1, j, s, p, m, n)); } @@ -82,7 +82,8 @@ class Solution { * @return {boolean} */ isMatch(s, p) { - let m = s.length, n = p.length; + let m = s.length, + n = p.length; const dfs = (i, j) => { if (j === n) { @@ -91,8 +92,7 @@ class Solution { let match = i < m && (s[i] === p[j] || p[j] === '.'); if (j + 1 < n && p[j + 1] === '*') { - return dfs(i, j + 2) || - (match && dfs(i + 1, j)); + return dfs(i, j + 2) || (match && dfs(i + 1, j)); } if (match) { @@ -100,7 +100,7 @@ class Solution { } return false; - } + }; return dfs(0, 0); } @@ -121,7 +121,7 @@ public class Solution { bool match = i < m && (s[i] == p[j] || p[j] == '.'); if (j + 1 < n && p[j + 1] == '*') { - return Dfs(i, j + 2, s, p, m, n) || + return Dfs(i, j + 2, s, p, m, n) || (match && Dfs(i + 1, j, s, p, m, n)); } @@ -145,11 +145,11 @@ func isMatch(s string, p string) bool { } match := i < m && (s[i] == p[j] || p[j] == '.') - + if (j+1) < n && p[j+1] == '*' { return dfs(i, j+2) || (match && dfs(i+1, j)) } - + if match { return dfs(i+1, j+1) } @@ -169,13 +169,13 @@ class Solution { fun dfs(i: Int, j: Int): Boolean { if (j == n) return i == m - + val match = i < m && (s[i] == p[j] || p[j] == '.') - + if ((j + 1) < n && p[j + 1] == '*') { return dfs(i, j + 2) || (match && dfs(i + 1, j)) } - + return match && dfs(i + 1, j + 1) } @@ -184,12 +184,41 @@ class Solution { } ``` +```swift +class Solution { + func isMatch(_ s: String, _ p: String) -> Bool { + let sArr = Array(s), pArr = Array(p) + let m = sArr.count, n = pArr.count + + func dfs(_ i: Int, _ j: Int) -> Bool { + if j == n { + return i == m + } + + let match = i < m && (sArr[i] == pArr[j] || pArr[j] == ".") + + if j + 1 < n && pArr[j + 1] == "*" { + return dfs(i, j + 2) || (match && dfs(i + 1, j)) + } + + if match { + return dfs(i + 1, j + 1) + } + + return false + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ {m + n})$ -* Space complexity: $O(m + n)$ +- Time complexity: $O(2 ^ {m + n})$ +- Space complexity: $O(m + n)$ > Where $m$ is the length of the string $s$ and $n$ is the length of the string $p$. @@ -213,17 +242,17 @@ class Solution: match = i < m and (s[i] == p[j] or p[j] == ".") if (j + 1) < n and p[j + 1] == "*": - cache[(i, j)] = (dfs(i, j + 2) or + cache[(i, j)] = (dfs(i, j + 2) or (match and dfs(i + 1, j))) return cache[(i, j)] if match: cache[(i, j)] = dfs(i + 1, j + 1) return cache[(i, j)] - + cache[(i, j)] = False return False - + return dfs(0, 0) ``` @@ -245,10 +274,10 @@ public class Solution { return dp[i][j]; } - boolean match = i < m && (s.charAt(i) == p.charAt(j) || + boolean match = i < m && (s.charAt(i) == p.charAt(j) || p.charAt(j) == '.'); if (j + 1 < n && p.charAt(j + 1) == '*') { - dp[i][j] = dfs(i, j + 2, s, p, m, n) || + dp[i][j] = dfs(i, j + 2, s, p, m, n) || (match && dfs(i + 1, j, s, p, m, n)); } else { dp[i][j] = match && dfs(i + 1, j + 1, s, p, m, n); @@ -280,7 +309,7 @@ private: } bool match = i < m && (s[i] == p[j] || p[j] == '.'); if (j + 1 < n && p[j + 1] == '*') { - dp[i][j] = dfs(i, j + 2, s, p, m, n) || + dp[i][j] = dfs(i, j + 2, s, p, m, n) || (match && dfs(i + 1, j, s, p, m, n)); } else { dp[i][j] = match && dfs(i + 1, j + 1, s, p, m, n); @@ -298,10 +327,12 @@ class Solution { * @return {boolean} */ isMatch(s, p) { - const m = s.length, n = p.length; - let dp = Array(m + 1).fill().map(() => - Array(n + 1).fill(null)); - + const m = s.length, + n = p.length; + let dp = Array(m + 1) + .fill() + .map(() => Array(n + 1).fill(null)); + const dfs = (i, j) => { if (j === n) { return i === m; @@ -311,13 +342,12 @@ class Solution { } const match = i < m && (s[i] === p[j] || p[j] === '.'); if (j + 1 < n && p[j + 1] === '*') { - dp[i][j] = dfs(i, j + 2) || - (match && dfs(i + 1, j)); + dp[i][j] = dfs(i, j + 2) || (match && dfs(i + 1, j)); } else { dp[i][j] = match && dfs(i + 1, j + 1); } return dp[i][j]; - } + }; return dfs(0, 0); } @@ -343,7 +373,7 @@ public class Solution { } bool match = i < m && (s[i] == p[j] || p[j] == '.'); if (j + 1 < n && p[j + 1] == '*') { - dp[i, j] = Dfs(i, j + 2, s, p, m, n) || + dp[i, j] = Dfs(i, j + 2, s, p, m, n) || (match && Dfs(i + 1, j, s, p, m, n)); } else { dp[i, j] = match && Dfs(i + 1, j + 1, s, p, m, n); @@ -360,7 +390,7 @@ func isMatch(s string, p string) bool { for i := range dp { dp[i] = make([]int, n+1) for j := range dp[i] { - dp[i][j] = -1 + dp[i][j] = -1 } } @@ -374,17 +404,17 @@ func isMatch(s string, p string) bool { } match := i < m && (s[i] == p[j] || p[j] == '.') - + if (j+1) < n && p[j+1] == '*' { dp[i][j] = boolToInt(dfs(i, j+2) || (match && dfs(i+1, j))) return dp[i][j] == 1 } - + if match { dp[i][j] = boolToInt(dfs(i+1, j+1)) return dp[i][j] == 1 } - + dp[i][j] = 0 return false } @@ -405,24 +435,24 @@ class Solution { fun isMatch(s: String, p: String): Boolean { val m = s.length val n = p.length - val dp = Array(m + 1) { IntArray(n + 1) { -1 } } + val dp = Array(m + 1) { IntArray(n + 1) { -1 } } fun dfs(i: Int, j: Int): Boolean { if (j == n) return i == m if (dp[i][j] != -1) return dp[i][j] == 1 val match = i < m && (s[i] == p[j] || p[j] == '.') - + if ((j + 1) < n && p[j + 1] == '*') { dp[i][j] = if (dfs(i, j + 2) || (match && dfs(i + 1, j))) 1 else 0 return dp[i][j] == 1 } - + if (match) { dp[i][j] = if (dfs(i + 1, j + 1)) 1 else 0 return dp[i][j] == 1 } - + dp[i][j] = 0 return false } @@ -432,12 +462,48 @@ class Solution { } ``` +```swift +class Solution { + func isMatch(_ s: String, _ p: String) -> Bool { + let sArr = Array(s), pArr = Array(p) + let m = sArr.count, n = pArr.count + var cache = [[Bool?]](repeating: [Bool?](repeating: nil, count: n + 1), count: m + 1) + + func dfs(_ i: Int, _ j: Int) -> Bool { + if j == n { + return i == m + } + if let cached = cache[i][j] { + return cached + } + + let match = i < m && (sArr[i] == pArr[j] || pArr[j] == ".") + + if j + 1 < n && pArr[j + 1] == "*" { + cache[i][j] = dfs(i, j + 2) || (match && dfs(i + 1, j)) + return cache[i][j]! + } + + if match { + cache[i][j] = dfs(i + 1, j + 1) + return cache[i][j]! + } + + cache[i][j] = false + return false + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the length of the string $s$ and $n$ is the length of the string $p$. @@ -538,8 +604,7 @@ class Solution { for (let i = s.length; i >= 0; i--) { for (let j = p.length - 1; j >= 0; j--) { - const match = i < s.length && - (s[i] === p[j] || p[j] === '.'); + const match = i < s.length && (s[i] === p[j] || p[j] === '.'); if (j + 1 < p.length && p[j + 1] === '*') { dp[i][j] = dp[i][j + 2]; @@ -565,7 +630,7 @@ public class Solution { for (int i = s.Length; i >= 0; i--) { for (int j = p.Length - 1; j >= 0; j--) { - bool match = i < s.Length && + bool match = i < s.Length && (s[i] == p[j] || p[j] == '.'); if ((j + 1) < p.Length && p[j + 1] == '*') { @@ -596,7 +661,7 @@ func isMatch(s, p string) bool { for i := m; i >= 0; i-- { for j := n - 1; j >= 0; j-- { match := i < m && (s[i] == p[j] || p[j] == '.') - + if j+1 < n && p[j+1] == '*' { dp[i][j] = dp[i][j+2] if match { @@ -622,7 +687,7 @@ class Solution { for (i in m downTo 0) { for (j in n - 1 downTo 0) { val match = i < m && (s[i] == p[j] || p[j] == '.') - + if (j + 1 < n && p[j + 1] == '*') { dp[i][j] = dp[i][j + 2] || (match && dp[i + 1][j]) } else if (match) { @@ -635,12 +700,40 @@ class Solution { } ``` +```swift +class Solution { + func isMatch(_ s: String, _ p: String) -> Bool { + let sArr = Array(s), pArr = Array(p) + let m = sArr.count, n = pArr.count + var dp = Array(repeating: Array(repeating: false, count: n + 1), count: m + 1) + dp[m][n] = true + + for i in stride(from: m, through: 0, by: -1) { + for j in stride(from: n - 1, through: 0, by: -1) { + let match = i < m && (sArr[i] == pArr[j] || pArr[j] == ".") + + if j + 1 < n && pArr[j + 1] == "*" { + dp[i][j] = dp[i][j + 2] + if match { + dp[i][j] = dp[i][j] || dp[i + 1][j] + } + } else if match { + dp[i][j] = dp[i + 1][j + 1] + } + } + } + + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the length of the string $s$ and $n$ is the length of the string $p$. @@ -655,23 +748,23 @@ class Solution: def isMatch(self, s: str, p: str) -> bool: dp = [False] * (len(p) + 1) dp[len(p)] = True - + for i in range(len(s), -1, -1): nextDp = [False] * (len(p) + 1) nextDp[len(p)] = (i == len(s)) for j in range(len(p) - 1, -1, -1): match = i < len(s) and (s[i] == p[j] or p[j] == ".") - + if (j + 1) < len(p) and p[j + 1] == "*": nextDp[j] = nextDp[j + 2] if match: nextDp[j] |= dp[j] elif match: nextDp[j] = dp[j + 1] - + dp = nextDp - + return dp[0] ``` @@ -686,8 +779,8 @@ public class Solution { nextDp[p.length()] = (i == s.length()); for (int j = p.length() - 1; j >= 0; j--) { - boolean match = i < s.length() && - (s.charAt(i) == p.charAt(j) || + boolean match = i < s.length() && + (s.charAt(i) == p.charAt(j) || p.charAt(j) == '.'); if (j + 1 < p.length() && p.charAt(j + 1) == '*') { @@ -720,7 +813,7 @@ public: nextDp[p.length()] = (i == s.length()); for (int j = p.length() - 1; j >= 0; j--) { - bool match = i < s.length() && + bool match = i < s.length() && (s[i] == p[j] || p[j] == '.'); if (j + 1 < p.length() && p[j + 1] == '*') { @@ -754,13 +847,12 @@ class Solution { for (let i = s.length; i >= 0; i--) { let nextDp = new Array(p.length + 1).fill(false); - nextDp[p.length] = (i === s.length); + nextDp[p.length] = i === s.length; for (let j = p.length - 1; j >= 0; j--) { - const match = i < s.length && - (s[i] === p[j] || p[j] === "."); + const match = i < s.length && (s[i] === p[j] || p[j] === '.'); - if (j + 1 < p.length && p[j + 1] === "*") { + if (j + 1 < p.length && p[j + 1] === '*') { nextDp[j] = nextDp[j + 2]; if (match) { nextDp[j] = nextDp[j] || dp[j]; @@ -821,7 +913,7 @@ func isMatch(s, p string) bool { for j := n - 1; j >= 0; j-- { match := i < m && (s[i] == p[j] || p[j] == '.') - + if j+1 < n && p[j+1] == '*' { nextDp[j] = nextDp[j+2] || (match && dp[j]) } else if match { @@ -862,12 +954,44 @@ class Solution { } ``` +```swift +class Solution { + func isMatch(_ s: String, _ p: String) -> Bool { + let sArr = Array(s), pArr = Array(p) + var dp = Array(repeating: false, count: pArr.count + 1) + dp[pArr.count] = true + + for i in stride(from: sArr.count, through: 0, by: -1) { + var nextDp = Array(repeating: false, count: pArr.count + 1) + nextDp[pArr.count] = (i == sArr.count) + + for j in stride(from: pArr.count - 1, through: 0, by: -1) { + let match = i < sArr.count && (sArr[i] == pArr[j] || pArr[j] == ".") + + if j + 1 < pArr.count && pArr[j + 1] == "*" { + nextDp[j] = nextDp[j + 2] + if match { + nextDp[j] = nextDp[j] || dp[j] + } + } else if match { + nextDp[j] = dp[j + 1] + } + } + + dp = nextDp + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(n)$ > Where $m$ is the length of the string $s$ and $n$ is the length of the string $p$. @@ -882,11 +1006,11 @@ class Solution: def isMatch(self, s: str, p: str) -> bool: dp = [False] * (len(p) + 1) dp[len(p)] = True - + for i in range(len(s), -1, -1): dp1 = dp[len(p)] dp[len(p)] = (i == len(s)) - + for j in range(len(p) - 1, -1, -1): match = i < len(s) and (s[i] == p[j] or p[j] == ".") res = False @@ -912,8 +1036,8 @@ public class Solution { dp[p.length()] = (i == s.length()); for (int j = p.length() - 1; j >= 0; j--) { - boolean match = i < s.length() && - (s.charAt(i) == p.charAt(j) || + boolean match = i < s.length() && + (s.charAt(i) == p.charAt(j) || p.charAt(j) == '.'); boolean res = false; if (j + 1 < p.length() && p.charAt(j + 1) == '*') { @@ -946,7 +1070,7 @@ public: dp[p.length()] = (i == s.length()); for (int j = p.length() - 1; j >= 0; j--) { - bool match = i < s.length() && + bool match = i < s.length() && (s[i] == p[j] || p[j] == '.'); bool res = false; if (j + 1 < p.length() && p[j + 1] == '*') { @@ -980,13 +1104,12 @@ class Solution { for (let i = s.length; i >= 0; i--) { let dp1 = dp[p.length]; - dp[p.length] = (i == s.length); + dp[p.length] = i == s.length; for (let j = p.length - 1; j >= 0; j--) { - const match = i < s.length && - (s[i] === p[j] || p[j] === "."); + const match = i < s.length && (s[i] === p[j] || p[j] === '.'); let res = false; - if (j + 1 < p.length && p[j + 1] === "*") { + if (j + 1 < p.length && p[j + 1] === '*') { res = dp[j + 2]; if (match) { res = res || dp[j]; @@ -1096,11 +1219,44 @@ class Solution { } ``` +```swift +class Solution { + func isMatch(_ s: String, _ p: String) -> Bool { + let sArr = Array(s) + let pArr = Array(p) + var dp = [Bool](repeating: false, count: pArr.count + 1) + dp[pArr.count] = true + + for i in stride(from: sArr.count, through: 0, by: -1) { + var dp1 = dp[pArr.count] + dp[pArr.count] = (i == sArr.count) + + for j in stride(from: pArr.count - 1, through: 0, by: -1) { + let match = i < sArr.count && (sArr[i] == pArr[j] || pArr[j] == ".") + var res = false + if j + 1 < pArr.count && pArr[j + 1] == "*" { + res = dp[j + 2] + if match { + res = res || dp[j] + } + } else if match { + res = dp1 + } + dp1 = dp[j] + dp[j] = res + } + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(n)$ -> Where $m$ is the length of the string $s$ and $n$ is the length of the string $p$. \ No newline at end of file +> Where $m$ is the length of the string $s$ and $n$ is the length of the string $p$. diff --git a/articles/relative-sort-array.md b/articles/relative-sort-array.md new file mode 100644 index 000000000..f7596a24d --- /dev/null +++ b/articles/relative-sort-array.md @@ -0,0 +1,553 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + res = [] + + for num2 in arr2: + for i, num1 in enumerate(arr1): + if num1 == num2: + res.append(num1) + arr1[i] = -1 + + arr1.sort() + for i in range(len(res), len(arr1)): + res.append(arr1[i]) + + return res +``` + +```java +public class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + List res = new ArrayList<>(); + + for (int num2 : arr2) { + for (int i = 0; i < arr1.length; i++) { + if (arr1[i] == num2) { + res.add(arr1[i]); + arr1[i] = -1; + } + } + } + + Arrays.sort(arr1); + for (int i = res.size(); i < arr1.length; i++) { + res.add(arr1[i]); + } + + return res.stream().mapToInt(i -> i).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector relativeSortArray(vector& arr1, vector& arr2) { + vector res; + + for (int num2 : arr2) { + for (int i = 0; i < arr1.size(); i++) { + if (arr1[i] == num2) { + res.push_back(arr1[i]); + arr1[i] = -1; + } + } + } + + sort(arr1.begin(), arr1.end()); + for (int i = res.size(); i < arr1.size(); i++) { + res.push_back(arr1[i]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number[]} + */ + relativeSortArray(arr1, arr2) { + const res = []; + + for (let num2 of arr2) { + for (let i = 0; i < arr1.length; i++) { + if (arr1[i] === num2) { + res.push(arr1[i]); + arr1[i] = -1; + } + } + } + + arr1.sort((a, b) => a - b); + for (let i = res.length; i < arr1.length; i++) { + res.push(arr1[i]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n + n \log n)$ +- Space complexity: + - $O(1)$ or $O(n)$ depending on the sorting algorithm. + - $O(n)$ space for the output list. + +> Where $n$ is the size of the array $arr1$, and $m$ is the size of the array $arr2$. + +--- + +## 2. Hash Map + +::tabs-start + +```python +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + arr2_set = set(arr2) + arr1_count = defaultdict(int) + end = [] + + for num in arr1: + if num not in arr2_set: + end.append(num) + arr1_count[num] += 1 + end.sort() + + res = [] + for num in arr2: + for _ in range(arr1_count[num]): + res.append(num) + return res + end +``` + +```java +public class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + Set arr2Set = new HashSet<>(); + for (int num : arr2) arr2Set.add(num); + + Map count = new HashMap<>(); + List end = new ArrayList<>(); + for (int num : arr1) { + if (!arr2Set.contains(num)) end.add(num); + count.put(num, count.getOrDefault(num, 0) + 1); + } + Collections.sort(end); + + List res = new ArrayList<>(); + for (int num : arr2) { + int freq = count.get(num); + for (int i = 0; i < freq; i++) res.add(num); + } + res.addAll(end); + + return res.stream().mapToInt(i -> i).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector relativeSortArray(vector& arr1, vector& arr2) { + unordered_set arr2Set(arr2.begin(), arr2.end()); + unordered_map count; + vector end; + + for (int num : arr1) { + if (!arr2Set.count(num)) end.push_back(num); + count[num]++; + } + + sort(end.begin(), end.end()); + vector res; + + for (int num : arr2) { + for (int i = 0; i < count[num]; i++) { + res.push_back(num); + } + } + + res.insert(res.end(), end.begin(), end.end()); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number[]} + */ + relativeSortArray(arr1, arr2) { + const arr2Set = new Set(arr2); + const count = {}; + const end = []; + + for (let num of arr1) { + if (!arr2Set.has(num)) end.push(num); + count[num] = (count[num] || 0) + 1; + } + + end.sort((a, b) => a - b); + const res = []; + + for (let num of arr2) { + for (let i = 0; i < count[num]; i++) { + res.push(num); + } + } + + return res.concat(end); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m + n \log n)$ +- Space complexity: $O(n)$ + +> Where $n$ is the size of the array $arr1$, and $m$ is the size of the array $arr2$. + +--- + +## 3. Hash Map (Optimal) + +::tabs-start + +```python +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + count = {} + for num in arr1: + count[num] = count.get(num, 0) + 1 + + res = [] + for num in arr2: + res += [num] * count.pop(num) + + for num in sorted(count): + res += [num] * count[num] + + return res +``` + +```java +public class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + Map count = new HashMap<>(); + for (int num : arr1) { + count.put(num, count.getOrDefault(num, 0) + 1); + } + + List res = new ArrayList<>(); + for (int num : arr2) { + int freq = count.remove(num); + for (int i = 0; i < freq; i++) { + res.add(num); + } + } + + List remaining = new ArrayList<>(count.keySet()); + Collections.sort(remaining); + for (int num : remaining) { + int freq = count.get(num); + for (int i = 0; i < freq; i++) { + res.add(num); + } + } + + return res.stream().mapToInt(i -> i).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector relativeSortArray(vector& arr1, vector& arr2) { + unordered_map count; + for (int num : arr1) { + count[num]++; + } + + vector res; + for (int num : arr2) { + for (int i = 0; i < count[num]; i++) { + res.push_back(num); + } + count.erase(num); + } + + vector remaining; + for (auto& [num, freq] : count) { + for (int i = 0; i < freq; i++) { + remaining.push_back(num); + } + } + + sort(remaining.begin(), remaining.end()); + res.insert(res.end(), remaining.begin(), remaining.end()); + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number[]} + */ + relativeSortArray(arr1, arr2) { + const count = {}; + for (let num of arr1) { + count[num] = (count[num] || 0) + 1; + } + + const res = []; + for (let num of arr2) { + for (let i = 0; i < count[num]; i++) { + res.push(num); + } + delete count[num]; + } + + const remaining = Object.keys(count) + .map(Number) + .sort((a, b) => a - b); + for (let num of remaining) { + for (let i = 0; i < count[num]; i++) { + res.push(num); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m + n \log n)$ +- Space complexity: $O(n)$ + +> Where $n$ is the size of the array $arr1$, and $m$ is the size of the array $arr2$. + +--- + +## 4. Counting Sort + +::tabs-start + +```python +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + max_val = max(arr1) + count = [0] * (max_val + 1) + + for num in arr1: + count[num] += 1 + + res = [] + for num in arr2: + res += [num] * count[num] + count[num] = 0 + + for num in range(len(count)): + res += [num] * count[num] + + return res +``` + +```java +public class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + int max = 0; + for (int num : arr1) max = Math.max(max, num); + + int[] count = new int[max + 1]; + for (int num : arr1) count[num]++; + + List res = new ArrayList<>(); + for (int num : arr2) { + while (count[num]-- > 0) res.add(num); + } + + for (int num = 0; num < count.length; num++) { + while (count[num]-- > 0) res.add(num); + } + + return res.stream().mapToInt(i -> i).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector relativeSortArray(vector& arr1, vector& arr2) { + int max_val = *max_element(arr1.begin(), arr1.end()); + vector count(max_val + 1, 0); + + for (int num : arr1) count[num]++; + + vector res; + for (int num : arr2) { + while (count[num]-- > 0) res.push_back(num); + } + + for (int num = 0; num <= max_val; num++) { + while (count[num]-- > 0) res.push_back(num); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number[]} + */ + relativeSortArray(arr1, arr2) { + let max = Math.max(...arr1); + let count = new Array(max + 1).fill(0); + + for (let num of arr1) count[num]++; + + let res = []; + for (let num of arr2) { + while (count[num]-- > 0) res.push(num); + } + + for (let num = 0; num < count.length; num++) { + while (count[num]-- > 0) res.push(num); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m + M)$ +- Space complexity: + - $O(M)$ extra space. + - $O(n)$ space for the output list. + +> Where $n$ is the size of the array $arr1$, $m$ is the size of the array $arr2$, and $M$ is the maximum value in the array $arr1$. + +--- + +## 5. Custom Sort + +::tabs-start + +```python +class Solution: + def relativeSortArray(self, arr1: List[int], arr2: List[int]) -> List[int]: + index = {num: i for i, num in enumerate(arr2)} + return sorted(arr1, key=lambda x: (index.get(x, 1000 + x))) +``` + +```java +public class Solution { + public int[] relativeSortArray(int[] arr1, int[] arr2) { + Map index = new HashMap<>(); + for (int i = 0; i < arr2.length; i++) { + index.put(arr2[i], i); + } + + Integer[] boxed = Arrays.stream(arr1).boxed().toArray(Integer[]::new); + Arrays.sort(boxed, (a, b) -> { + int ia = index.getOrDefault(a, 1000 + a); + int ib = index.getOrDefault(b, 1000 + b); + return Integer.compare(ia, ib); + }); + + return Arrays.stream(boxed).mapToInt(i -> i).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector relativeSortArray(vector& arr1, vector& arr2) { + unordered_map index; + for (int i = 0; i < arr2.size(); i++) { + index[arr2[i]] = i; + } + + sort(arr1.begin(), arr1.end(), [&](int a, int b) { + int ia = index.count(a) ? index[a] : 1000 + a; + int ib = index.count(b) ? index[b] : 1000 + b; + return ia < ib; + }); + + return arr1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr1 + * @param {number[]} arr2 + * @return {number[]} + */ + relativeSortArray(arr1, arr2) { + const index = new Map(); + arr2.forEach((num, i) => index.set(num, i)); + + return arr1.sort((a, b) => { + const ia = index.has(a) ? index.get(a) : 1000 + a; + const ib = index.has(b) ? index.get(b) : 1000 + b; + return ia - ib; + }); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m + n \log n)$ +- Space complexity: + - $O(m)$ extra space. + - $O(n)$ space for the output list. + +> Where $n$ is the size of the array $arr1$, and $m$ is the size of the array $arr2$. diff --git a/articles/remove-all-adjacent-duplicates-in-string-ii.md b/articles/remove-all-adjacent-duplicates-in-string-ii.md new file mode 100644 index 000000000..3e6d60c3f --- /dev/null +++ b/articles/remove-all-adjacent-duplicates-in-string-ii.md @@ -0,0 +1,467 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def removeDuplicates(self, s: str, k: int) -> str: + while True: + flag = False + cur = s[0] + cnt = 1 + for i in range(1, len(s)): + if cur != s[i]: + cnt = 0 + cur = s[i] + cnt += 1 + if cnt == k: + s = s[:i - cnt + 1] + s[i + 1:] + flag = True + break + + if not flag: + break + + return s +``` + +```java +public class Solution { + public String removeDuplicates(String s, int k) { + while (true) { + boolean flag = false; + char cur = s.charAt(0); + int cnt = 1; + + for (int i = 1; i < s.length(); i++) { + if (cur != s.charAt(i)) { + cnt = 0; + cur = s.charAt(i); + } + cnt++; + if (cnt == k) { + s = s.substring(0, i - cnt + 1) + s.substring(i + 1); + flag = true; + break; + } + } + + if (!flag) { + break; + } + } + + return s; + } +} +``` + +```cpp +class Solution { +public: + string removeDuplicates(string s, int k) { + while (true) { + bool flag = false; + char cur = s[0]; + int cnt = 1; + + for (int i = 1; i < s.size(); i++) { + if (cur != s[i]) { + cnt = 0; + cur = s[i]; + } + cnt++; + if (cnt == k) { + s = s.substr(0, i - cnt + 1) + s.substr(i + 1); + flag = true; + break; + } + } + + if (!flag) { + break; + } + } + + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {number} k + * @return {string} + */ + removeDuplicates(s, k) { + while (true) { + let flag = false; + let cur = s[0]; + let cnt = 1; + + for (let i = 1; i < s.length; i++) { + if (cur !== s[i]) { + cnt = 0; + cur = s[i]; + } + cnt++; + if (cnt === k) { + s = s.slice(0, i - cnt + 1) + s.slice(i + 1); + flag = true; + break; + } + } + + if (!flag) { + break; + } + } + + return s; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\frac {n ^ 2}{k})$ +- Space complexity: $O(n)$ + +--- + +## 2. Stack + +::tabs-start + +```python +class Solution: + def removeDuplicates(self, s: str, k: int) -> str: + stack = [] + n = len(s) + i = 0 + s = list(s) + + while i < n: + if i == 0 or s[i] != s[i - 1]: + stack.append(1) + else: + stack[-1] += 1 + if stack[-1] == k: + stack.pop() + del s[i - k + 1:i + 1] + i -= k + n -= k + + i += 1 + + return ''.join(s) +``` + +```java +public class Solution { + public String removeDuplicates(String s, int k) { + StringBuilder sb = new StringBuilder(s); + Stack stack = new Stack<>(); + int i = 0; + + while (i < sb.length()) { + if (i == 0 || sb.charAt(i) != sb.charAt(i - 1)) { + stack.push(1); + } else { + stack.push(stack.pop() + 1); + if (stack.peek() == k) { + stack.pop(); + sb.delete(i - k + 1, i + 1); + i -= k; + } + } + i++; + } + + return sb.toString(); + } +} +``` + +```cpp +class Solution { +public: + string removeDuplicates(string s, int k) { + vector stack; + int n = s.length(), i = 0; + + while (i < n) { + if (i == 0 || s[i] != s[i - 1]) { + stack.push_back(1); + } else { + stack.back()++; + if (stack.back() == k) { + stack.pop_back(); + s.erase(i - k + 1, k); + i -= k; + n -= k; + } + } + i++; + } + + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {number} k + * @return {string} + */ + removeDuplicates(s, k) { + let stack = []; + let arr = s.split(''); + let i = 0; + + while (i < arr.length) { + if (i === 0 || arr[i] !== arr[i - 1]) { + stack.push(1); + } else { + stack[stack.length - 1]++; + if (stack[stack.length - 1] === k) { + stack.pop(); + arr.splice(i - k + 1, k); + i -= k; + } + } + i++; + } + + return arr.join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Stack (Optimal) + +::tabs-start + +```python +class Solution: + def removeDuplicates(self, s: str, k: int) -> str: + stack = [] # [char, count] + + for c in s: + if stack and stack[-1][0] == c: + stack[-1][1] += 1 + else: + stack.append([c, 1]) + if stack[-1][1] == k: + stack.pop() + + return ''.join(char * count for char, count in stack) +``` + +```java +public class Solution { + public String removeDuplicates(String s, int k) { + Stack stack = new Stack<>(); // [char, count] + + for (char c : s.toCharArray()) { + if (!stack.isEmpty() && stack.peek()[0] == c) { + stack.peek()[1]++; + } else { + stack.push(new int[] {c, 1}); + } + if (stack.peek()[1] == k) { + stack.pop(); + } + } + + StringBuilder res = new StringBuilder(); + while (!stack.isEmpty()) { + int[] top = stack.pop(); + res.append(String.valueOf((char) top[0]).repeat(top[1])); + } + + return res.reverse().toString(); + } +} +``` + +```cpp +class Solution { +public: + string removeDuplicates(string s, int k) { + vector> stack; + + for (char c : s) { + if (!stack.empty() && stack.back().first == c) { + stack.back().second++; + } else { + stack.push_back({c, 1}); + } + if (stack.back().second == k) { + stack.pop_back(); + } + } + + string res; + for (auto& p : stack) { + res.append(p.second, p.first); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {number} k + * @return {string} + */ + removeDuplicates(s, k) { + const stack = []; // [char, count] + + for (const c of s) { + if (stack.length && stack[stack.length - 1][0] === c) { + stack[stack.length - 1][1]++; + } else { + stack.push([c, 1]); + } + if (stack[stack.length - 1][1] === k) { + stack.pop(); + } + } + + let res = ''; + for (const [char, count] of stack) { + res += char.repeat(count); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Two Pointers + +::tabs-start + +```python +class Solution: + def removeDuplicates(self, s: str, k: int) -> str: + i = 0 + n = len(s) + count = [0] * n + s = list(s) + for j in range(n): + s[i] = s[j] + count[i] = 1 + if i > 0 and s[i - 1] == s[j]: + count[i] += count[i - 1] + if count[i] == k: + i -= k + i += 1 + return ''.join(s[:i]) +``` + +```java +public class Solution { + public String removeDuplicates(String s, int k) { + int i = 0, n = s.length(); + char[] str = s.toCharArray(); + int[] count = new int[n]; + for (int j = 0; j < n; j++) { + str[i] = str[j]; + count[i] = 1; + if (i > 0 && str[i - 1] == str[j]) { + count[i] += count[i - 1]; + } + if (count[i] == k) { + i -= k; + } + i++; + } + return new String(str, 0, i); + } +} +``` + +```cpp +class Solution { +public: + string removeDuplicates(string s, int k) { + int i = 0, n = s.length(); + vector count(n); + for (int j = 0; j < n; i++, j++) { + s[i] = s[j]; + count[i] = 1; + if (i > 0 && s[i - 1] == s[j]) { + count[i] += count[i - 1]; + } + if (count[i] == k) i -= k; + } + return s.substr(0, i); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {number} k + * @return {string} + */ + removeDuplicates(s, k) { + let i = 0; + const n = s.length; + const count = new Array(n).fill(0); + s = s.split(''); + for (let j = 0; j < n; j++) { + s[i] = s[j]; + count[i] = 1; + if (i > 0 && s[i - 1] === s[j]) { + count[i] += count[i - 1]; + } + if (count[i] === k) { + i -= k; + } + i++; + } + return s.slice(0, i).join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/remove-colored-pieces-if-both-neighbors-are-the-same-color.md b/articles/remove-colored-pieces-if-both-neighbors-are-the-same-color.md new file mode 100644 index 000000000..a86e56cac --- /dev/null +++ b/articles/remove-colored-pieces-if-both-neighbors-are-the-same-color.md @@ -0,0 +1,325 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def winnerOfGame(self, colors: str) -> bool: + s = list(colors) + + def removeChar(c): + for i in range(1, len(s) - 1): + if s[i] != c: + continue + + if s[i] == s[i + 1] == s[i - 1]: + s.pop(i) + return True + return False + + while True: + if not removeChar('A'): + return False + if not removeChar('B'): + return True + + return False +``` + +```java +public class Solution { + public boolean winnerOfGame(String colors) { + StringBuilder s = new StringBuilder(colors); + + while (true) { + if (!removeChar(s, 'A')) return false; + if (!removeChar(s, 'B')) return true; + } + } + + private boolean removeChar(StringBuilder s, char c) { + for (int i = 1; i < s.length() - 1; i++) { + if (s.charAt(i) != c) continue; + + if (s.charAt(i - 1) == c && s.charAt(i + 1) == c) { + s.deleteCharAt(i); + return true; + } + } + return false; + } +} +``` + +```cpp +class Solution { +public: + bool winnerOfGame(string colors) { + while (true) { + if (!removeChar(colors, 'A')) return false; + if (!removeChar(colors, 'B')) return true; + } + } + +private: + bool removeChar(string& s, char c) { + for (int i = 1; i < s.size() - 1; i++) { + if (s[i] != c) continue; + + if (s[i - 1] == c && s[i + 1] == c) { + s.erase(i, 1); + return true; + } + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @return {boolean} + */ + winnerOfGame(colors) { + let s = colors.split(''); + + const removeChar = (c) => { + for (let i = 1; i < s.length - 1; i++) { + if (s[i] !== c) continue; + + if (s[i - 1] === c && s[i + 1] === c) { + s.splice(i, 1); + return true; + } + } + return false; + }; + + while (true) { + if (!removeChar('A')) return false; + if (!removeChar('B')) return true; + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 2. Greedy + Two Pointers + +::tabs-start + +```python +class Solution: + def winnerOfGame(self, colors: str) -> bool: + alice = bob = l = 0 + + for r in range(len(colors)): + if colors[l] != colors[r]: + l = r + + extra = r - l - 1 + if extra > 0: + if colors[l] == 'A': + alice += 1 + else: + bob += 1 + + return alice > bob +``` + +```java +public class Solution { + public boolean winnerOfGame(String colors) { + int alice = 0, bob = 0, l = 0; + + for (int r = 0; r < colors.length(); r++) { + if (colors.charAt(l) != colors.charAt(r)) { + l = r; + } + + int extra = r - l - 1; + if (extra > 0) { + if (colors.charAt(l) == 'A') { + alice++; + } else { + bob++; + } + } + } + + return alice > bob; + } +} +``` + +```cpp +class Solution { +public: + bool winnerOfGame(string colors) { + int alice = 0, bob = 0, l = 0; + + for (int r = 0; r < colors.size(); r++) { + if (colors[l] != colors[r]) { + l = r; + } + + int extra = r - l - 1; + if (extra > 0) { + if (colors[l] == 'A') { + alice++; + } else { + bob++; + } + } + } + + return alice > bob; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @return {boolean} + */ + winnerOfGame(colors) { + let alice = 0, + bob = 0, + l = 0; + + for (let r = 0; r < colors.length; r++) { + if (colors[l] !== colors[r]) { + l = r; + } + + let extra = r - l - 1; + if (extra > 0) { + if (colors[l] === 'A') { + alice++; + } else { + bob++; + } + } + } + + return alice > bob; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 3. Greedy + +::tabs-start + +```python +class Solution: + def winnerOfGame(self, colors: str) -> bool: + alice, bob = 0, 0 + + for i in range(1, len(colors) - 1): + if colors[i - 1] == colors[i] == colors[i + 1]: + if colors[i] == 'A': + alice += 1 + if colors[i] == 'B': + bob += 1 + + return alice > bob +``` + +```java +public class Solution { + public boolean winnerOfGame(String colors) { + int alice = 0, bob = 0; + + for (int i = 1; i < colors.length() - 1; i++) { + if (colors.charAt(i - 1) == colors.charAt(i) && + colors.charAt(i) == colors.charAt(i + 1)) { + if (colors.charAt(i) == 'A') { + alice++; + } + if (colors.charAt(i) == 'B') { + bob++; + } + } + } + + return alice > bob; + } +} +``` + +```cpp +class Solution { +public: + bool winnerOfGame(string colors) { + int alice = 0, bob = 0; + + for (int i = 1; i < colors.size() - 1; i++) { + if (colors[i - 1] == colors[i] && colors[i] == colors[i + 1]) { + if (colors[i] == 'A') { + alice++; + } + if (colors[i] == 'B') { + bob++; + } + } + } + + return alice > bob; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} colors + * @return {boolean} + */ + winnerOfGame(colors) { + let alice = 0, + bob = 0; + + for (let i = 1; i < colors.length - 1; i++) { + if (colors[i - 1] === colors[i] && colors[i] === colors[i + 1]) { + if (colors[i] === 'A') { + alice++; + } + if (colors[i] === 'B') { + bob++; + } + } + } + + return alice > bob; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/remove-covered-intervals.md b/articles/remove-covered-intervals.md new file mode 100644 index 000000000..f06632921 --- /dev/null +++ b/articles/remove-covered-intervals.md @@ -0,0 +1,281 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def removeCoveredIntervals(self, intervals: List[List[int]]) -> int: + n = len(intervals) + res = n + + for i in range(n): + for j in range(n): + if (i != j and intervals[j][0] <= intervals[i][0] and + intervals[j][1] >= intervals[i][1] + ): + res -= 1 + break + + return res +``` + +```java +public class Solution { + public int removeCoveredIntervals(int[][] intervals) { + int n = intervals.length; + int res = n; + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (i != j && intervals[j][0] <= intervals[i][0] && + intervals[j][1] >= intervals[i][1]) { + res--; + break; + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int removeCoveredIntervals(vector>& intervals) { + int n = intervals.size(); + int res = n; + + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + if (i != j && intervals[j][0] <= intervals[i][0] && + intervals[j][1] >= intervals[i][1]) { + res--; + break; + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} intervals + * @return {number} + */ + removeCoveredIntervals(intervals) { + let n = intervals.length; + let res = n; + + for (let i = 0; i < n; i++) { + for (let j = 0; j < n; j++) { + if ( + i !== j && + intervals[j][0] <= intervals[i][0] && + intervals[j][1] >= intervals[i][1] + ) { + res--; + break; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 2. Sorting - I + +::tabs-start + +```python +class Solution: + def removeCoveredIntervals(self, intervals: List[List[int]]) -> int: + intervals.sort(key=lambda x: (x[0], -x[1])) + res = 1 + prevL, prevR = intervals[0][0], intervals[0][1] + for l, r in intervals: + if prevL <= l and prevR >= r: + continue + res += 1 + prevL, prevR = l, r + + return res +``` + +```java +public class Solution { + public int removeCoveredIntervals(int[][] intervals) { + Arrays.sort(intervals, (a, b) -> + a[0] == b[0] ? Integer.compare(b[1], a[1]) : Integer.compare(a[0], b[0]) + ); + int res = 1, prevL = intervals[0][0], prevR = intervals[0][1]; + for (int[] interval : intervals) { + int l = interval[0], r = interval[1]; + if (prevL <= l && prevR >= r) { + continue; + } + res++; + prevL = l; + prevR = r; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int removeCoveredIntervals(vector>& intervals) { + sort(intervals.begin(), intervals.end(), [](const auto& a, const auto& b) { + return a[0] == b[0] ? b[1] < a[1] : a[0] < b[0]; + }); + + int res = 1, prevL = intervals[0][0], prevR = intervals[0][1]; + for (const auto& interval : intervals) { + int l = interval[0], r = interval[1]; + if (prevL <= l && prevR >= r) { + continue; + } + res++; + prevL = l; + prevR = r; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} intervals + * @return {number} + */ + removeCoveredIntervals(intervals) { + intervals.sort((a, b) => (a[0] === b[0] ? b[1] - a[1] : a[0] - b[0])); + let res = 1, + [prevL, prevR] = intervals[0]; + for (const [l, r] of intervals) { + if (prevL <= l && prevR >= r) { + continue; + } + res++; + prevL = l; + prevR = r; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n\log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 3. Sorting - II + +::tabs-start + +```python +class Solution: + def removeCoveredIntervals(self, intervals: List[List[int]]) -> int: + intervals.sort() + res, start, end = 1, intervals[0][0], intervals[0][1] + + for l, r in intervals: + if start < l and end < r: + start = l + res += 1 + end = max(end, r) + + return res +``` + +```java +public class Solution { + public int removeCoveredIntervals(int[][] intervals) { + Arrays.sort(intervals, (a, b) -> a[0] - b[0]); + int res = 1, start = intervals[0][0], end = intervals[0][1]; + + for (int[] interval : intervals) { + int l = interval[0], r = interval[1]; + if (start < l && end < r) { + start = l; + res++; + } + end = Math.max(end, r); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int removeCoveredIntervals(vector>& intervals) { + sort(intervals.begin(), intervals.end()); + int res = 1, start = intervals[0][0], end = intervals[0][1]; + + for (const auto& interval : intervals) { + int l = interval[0], r = interval[1]; + if (start < l && end < r) { + start = l; + res++; + } + end = max(end, r); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} intervals + * @return {number} + */ + removeCoveredIntervals(intervals) { + intervals.sort((a, b) => a[0] - b[0]); + let res = 1, + start = intervals[0][0], + end = intervals[0][1]; + + for (const [l, r] of intervals) { + if (start < l && end < r) { + start = l; + res++; + } + end = Math.max(end, r); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. diff --git a/articles/remove-duplicates-from-sorted-array-ii.md b/articles/remove-duplicates-from-sorted-array-ii.md new file mode 100644 index 000000000..678e6c93d --- /dev/null +++ b/articles/remove-duplicates-from-sorted-array-ii.md @@ -0,0 +1,423 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + n = len(nums) + if n <= 2: + return n + i = 0 + while i < n - 1: + if nums[i] == nums[i + 1]: + j = i + 2 + cnt = 0 + while j < n and nums[i] == nums[j]: + j += 1 + cnt += 1 + for k in range(i + 2, n): + if j >= n: + break + nums[k] = nums[j] + j += 1 + n -= cnt + i += 2 + else: + i += 1 + return n +``` + +```java +public class Solution { + public int removeDuplicates(int[] nums) { + int n = nums.length; + if (n <= 2) return n; + int i = 0; + while (i < n - 1) { + if (nums[i] == nums[i + 1]) { + int j = i + 2, cnt = 0; + while (j < n && nums[i] == nums[j]) { + j++; + cnt++; + } + for (int k = i + 2; k < n; k++) { + if (j >= n) break; + nums[k] = nums[j++]; + } + n -= cnt; + i += 2; + } else { + i++; + } + } + return n; + } +} +``` + +```cpp +class Solution { +public: + int removeDuplicates(vector& nums) { + int n = nums.size(); + if (n <= 2) return n; + int i = 0; + while (i < n - 1) { + if (nums[i] == nums[i + 1]) { + int j = i + 2, cnt = 0; + while (j < n && nums[i] == nums[j]) { + j++; + cnt++; + } + for (int k = i + 2; k < n; k++) { + if (j >= n) break; + nums[k] = nums[j++]; + } + n -= cnt; + i += 2; + } else { + i++; + } + } + return n; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + removeDuplicates(nums) { + let n = nums.length; + if (n <= 2) return n; + let i = 0; + while (i < n - 1) { + if (nums[i] === nums[i + 1]) { + let j = i + 2, + cnt = 0; + while (j < n && nums[i] === nums[j]) { + j++; + cnt++; + } + for (let k = i + 2; k < n; k++) { + if (j >= n) break; + nums[k] = nums[j++]; + } + n -= cnt; + i += 2; + } else { + i++; + } + } + return n; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 2. Hash Map + +::tabs-start + +```python +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + n = len(nums) + if n <= 2: + return n + + count = Counter(nums) + i = 0 + for num in count: + nums[i] = num + count[num] -= 1 + i += 1 + if count[num] >= 1: + nums[i] = num + count[num] -= 1 + i += 1 + return i +``` + +```java +public class Solution { + public int removeDuplicates(int[] nums) { + Map count = new HashMap<>(); + List arr = new ArrayList<>(); + for (int num : nums) { + count.put(num, count.getOrDefault(num, 0) + 1); + if (count.get(num) == 1) { + arr.add(num); + } + } + + int i = 0; + for (int num : arr) { + nums[i++] = num; + count.put(num, count.get(num) - 1); + if (count.get(num) >= 1) { + nums[i++] = num; + count.put(num, count.get(num) - 1); + } + } + return i; + } +} +``` + +```cpp +class Solution { +public: + int removeDuplicates(vector& nums) { + unordered_map count; + vector arr; + for (int& num : nums) { + count[num]++; + if (count[num] == 1) { + arr.push_back(num); + } + } + + int i = 0; + for (auto& num : arr) { + int& cnt = count[num]; + nums[i++] = num; + cnt--; + if (cnt >= 1) { + nums[i++] = num; + cnt--; + } + } + return i; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + removeDuplicates(nums) { + const count = new Map(); + for (const num of nums) { + count.set(num, (count.get(num) || 0) + 1); + } + + let i = 0; + for (const [num, cnt] of count) { + nums[i++] = num; + count.set(num, cnt - 1); + if (count.get(num) >= 1) { + nums[i++] = num; + count.set(num, cnt - 1); + } + } + return i; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Two Pointers + +::tabs-start + +```python +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + l, r = 0, 0 + + while r < len(nums): + count = 1 + while r + 1 < len(nums) and nums[r] == nums[r + 1]: + r += 1 + count += 1 + + for i in range(min(2, count)): + nums[l] = nums[r] + l += 1 + r += 1 + + return l +``` + +```java +public class Solution { + public int removeDuplicates(int[] nums) { + int l = 0, r = 0; + + while (r < nums.length) { + int count = 1; + while (r + 1 < nums.length && nums[r] == nums[r + 1]) { + r++; + count++; + } + + for (int i = 0; i < Math.min(2, count); i++) { + nums[l] = nums[r]; + l++; + } + r++; + } + + return l; + } +} +``` + +```cpp +class Solution { +public: + int removeDuplicates(vector& nums) { + int l = 0, r = 0; + + while (r < nums.size()) { + int count = 1; + while (r + 1 < nums.size() && nums[r] == nums[r + 1]) { + r++; + count++; + } + + for (int i = 0; i < min(2, count); i++) { + nums[l] = nums[r]; + l++; + } + r++; + } + + return l; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + removeDuplicates(nums) { + let l = 0, + r = 0; + + while (r < nums.length) { + let count = 1; + while (r + 1 < nums.length && nums[r] === nums[r + 1]) { + r++; + count++; + } + + for (let i = 0; i < Math.min(2, count); i++) { + nums[l] = nums[r]; + l++; + } + r++; + } + + return l; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 4. Two Pointers (Optimal) + +::tabs-start + +```python +class Solution: + def removeDuplicates(self, nums: List[int]) -> int: + l = 0 + for num in nums: + if l < 2 or num != nums[l - 2]: + nums[l] = num + l += 1 + return l +``` + +```java +public class Solution { + public int removeDuplicates(int[] nums) { + int l = 0; + for (int num : nums) { + if (l < 2 || num != nums[l - 2]) { + nums[l] = num; + l++; + } + } + return l; + } +} +``` + +```cpp +class Solution { +public: + int removeDuplicates(vector& nums) { + int l = 0; + for (int num : nums) { + if (l < 2 || num != nums[l - 2]) { + nums[l] = num; + l++; + } + } + return l; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + removeDuplicates(nums) { + let l = 0; + for (let num of nums) { + if (l < 2 || num !== nums[l - 2]) { + nums[l] = num; + l++; + } + } + return l; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/remove-duplicates-from-sorted-array.md b/articles/remove-duplicates-from-sorted-array.md index 57bb96cdc..4f5f95a85 100644 --- a/articles/remove-duplicates-from-sorted-array.md +++ b/articles/remove-duplicates-from-sorted-array.md @@ -56,12 +56,22 @@ class Solution { } ``` +```csharp +public class Solution { + public int RemoveDuplicates(int[] nums) { + int[] unique = nums.Distinct().OrderBy(x => x).ToArray(); + Array.Copy(unique, nums, unique.Length); + return unique.Length; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -122,7 +132,9 @@ class Solution { * @return {number} */ removeDuplicates(nums) { - let n = nums.length, l = 0, r = 0; + let n = nums.length, + l = 0, + r = 0; while (r < n) { nums[l] = nums[r]; while (r < n && nums[r] === nums[l]) { @@ -135,12 +147,31 @@ class Solution { } ``` +```csharp +public class Solution { + public int RemoveDuplicates(int[] nums) { + int n = nums.Length; + int l = 0, r = 0; + + while (r < n) { + nums[l] = nums[r]; + while (r < n && nums[r] == nums[l]) { + r++; + } + l++; + } + + return l; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -206,9 +237,25 @@ class Solution { } ``` +```csharp +public class Solution { + public int RemoveDuplicates(int[] nums) { + int l = 1; + for (int r = 1; r < nums.Length; r++) { + if (nums[r] != nums[r - 1]) { + nums[l] = nums[r]; + l++; + } + } + + return l; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/remove-duplicates-from-sorted-list.md b/articles/remove-duplicates-from-sorted-list.md index b50bbbdcb..3fabf8439 100644 --- a/articles/remove-duplicates-from-sorted-list.md +++ b/articles/remove-duplicates-from-sorted-list.md @@ -12,7 +12,7 @@ class Solution: def deleteDuplicates(self, head: Optional[ListNode]) -> Optional[ListNode]: if not head or not head.next: return head - + head.next = self.deleteDuplicates(head.next) return head if head.val != head.next.val else head.next ``` @@ -31,7 +31,7 @@ class Solution: public class Solution { public ListNode deleteDuplicates(ListNode head) { if (head == null || head.next == null) return head; - + head.next = deleteDuplicates(head.next); return head.val != head.next.val ? head : head.next; } @@ -53,7 +53,7 @@ class Solution { public: ListNode* deleteDuplicates(ListNode* head) { if (!head || !head->next) return head; - + head->next = deleteDuplicates(head->next); return head->val != head->next->val ? head : head->next; } @@ -88,8 +88,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -196,8 +196,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -308,5 +308,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/remove-element.md b/articles/remove-element.md index 1c3d722e4..b53bb57ee 100644 --- a/articles/remove-element.md +++ b/articles/remove-element.md @@ -72,12 +72,31 @@ class Solution { } ``` +```csharp +public class Solution { + public int RemoveElement(int[] nums, int val) { + List tmp = new List(); + foreach (int num in nums) { + if (num != val) { + tmp.Add(num); + } + } + + for (int i = 0; i < tmp.Count; i++) { + nums[i] = tmp[i]; + } + + return tmp.Count; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -144,12 +163,26 @@ class Solution { } ``` +```csharp +public class Solution { + public int RemoveElement(int[] nums, int val) { + int k = 0; + for (int i = 0; i < nums.Length; i++) { + if (nums[i] != val) { + nums[k++] = nums[i]; + } + } + return k; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -212,7 +245,24 @@ class Solution { * @return {number} */ removeElement(nums, val) { - let i = 0, n = nums.length; + let i = 0, + n = nums.length; + while (i < n) { + if (nums[i] == val) { + nums[i] = nums[--n]; + } else { + i++; + } + } + return n; + } +} +``` + +```csharp +public class Solution { + public int RemoveElement(int[] nums, int val) { + int i = 0, n = nums.Length; while (i < n) { if (nums[i] == val) { nums[i] = nums[--n]; @@ -229,5 +279,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/remove-k-digits.md b/articles/remove-k-digits.md new file mode 100644 index 000000000..93374679b --- /dev/null +++ b/articles/remove-k-digits.md @@ -0,0 +1,344 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def removeKdigits(self, num: str, k: int) -> str: + num = list(num) + while k: + i = 1 + while i < len(num) and num[i] >= num[i - 1]: + i += 1 + num.pop(i - 1) + k -= 1 + + i = 0 + while i < len(num) and num[i] == '0': + i += 1 + + num = num[i:] + return ''.join(num) if num else '0' +``` + +```java +public class Solution { + public String removeKdigits(String num, int k) { + StringBuilder sb = new StringBuilder(num); + while (k > 0) { + int i = 1; + while (i < sb.length() && sb.charAt(i) >= sb.charAt(i - 1)) { + i++; + } + sb.deleteCharAt(i - 1); + k--; + } + + int i = 0; + while (i < sb.length() && sb.charAt(i) == '0') { + i++; + } + + sb = new StringBuilder(sb.substring(i)); + return sb.length() == 0 ? "0" : sb.toString(); + } +} +``` + +```cpp +class Solution { +public: + string removeKdigits(string num, int k) { + while (k > 0) { + int i = 1; + while (i < num.size() && num[i] >= num[i - 1]) { + i++; + } + num.erase(i - 1, 1); + k--; + } + + int i = 0; + while (i < num.size() && num[i] == '0') { + i++; + } + + num = num.substr(i); + return num.empty() ? "0" : num; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} num + * @param {number} k + * @return {string} + */ + removeKdigits(num, k) { + num = num.split(''); + while (k > 0) { + let i = 1; + while (i < num.length && num[i] >= num[i - 1]) { + i++; + } + num.splice(i - 1, 1); + k--; + } + + let i = 0; + while (i < num.length && num[i] === '0') { + i++; + } + + num = num.slice(i); + return num.length === 0 ? '0' : num.join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * k)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the language. + +--- + +## 2. Greedy + Stack + +::tabs-start + +```python +class Solution: + def removeKdigits(self, num: str, k: int) -> str: + stack = [] + for c in num: + while k > 0 and stack and stack[-1] > c: + k -= 1 + stack.pop() + stack.append(c) + + while stack and k: + stack.pop() + k -= 1 + + i = 0 + while i < len(stack) and stack[i] == '0': + i += 1 + + res = stack[i:] + return ''.join(res) if res else "0" +``` + +```java +public class Solution { + public String removeKdigits(String num, int k) { + StringBuilder stack = new StringBuilder(); + for (char c : num.toCharArray()) { + while (k > 0 && stack.length() > 0 && stack.charAt(stack.length() - 1) > c) { + stack.deleteCharAt(stack.length() - 1); + k--; + } + stack.append(c); + } + + while (k > 0 && stack.length() > 0) { + stack.deleteCharAt(stack.length() - 1); + k--; + } + + int i = 0; + while (i < stack.length() && stack.charAt(i) == '0') { + i++; + } + + String res = stack.substring(i); + return res.isEmpty() ? "0" : res; + } +} +``` + +```cpp +class Solution { +public: + string removeKdigits(string num, int k) { + string stack; + for (char c : num) { + while (k > 0 && !stack.empty() && stack.back() > c) { + stack.pop_back(); + k--; + } + stack.push_back(c); + } + + while (k > 0 && !stack.empty()) { + stack.pop_back(); + k--; + } + + int i = 0; + while (i < stack.size() && stack[i] == '0') { + i++; + } + + string res = stack.substr(i); + return res.empty() ? "0" : res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} num + * @param {number} k + * @return {string} + */ + removeKdigits(num, k) { + let stack = []; + for (let c of num) { + while (k > 0 && stack.length > 0 && stack[stack.length - 1] > c) { + stack.pop(); + k--; + } + stack.push(c); + } + + while (k > 0 && stack.length > 0) { + stack.pop(); + k--; + } + + let i = 0; + while (i < stack.length && stack[i] === '0') { + i++; + } + + let res = stack.slice(i).join(''); + return res === '' ? '0' : res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Two Pointers + +::tabs-start + +```python +class Solution: + def removeKdigits(self, num: str, k: int) -> str: + l = 0 + num = list(num) + + for r in range(len(num)): + while l > 0 and k > 0 and num[l - 1] > num[r]: + l -= 1 + k -= 1 + num[l] = num[r] + l += 1 + + l -= k + i = 0 + while i < l and num[i] == '0': + i += 1 + res = ''.join(num[i:l]) + return res if res else '0' +``` + +```java +public class Solution { + public String removeKdigits(String num, int k) { + char[] numArray = num.toCharArray(); + int l = 0; + + for (int r = 0; r < numArray.length; r++) { + while (l > 0 && k > 0 && numArray[l - 1] > numArray[r]) { + l--; + k--; + } + numArray[l++] = numArray[r]; + } + + l -= k; + int i = 0; + while (i < l && numArray[i] == '0') { + i++; + } + String res = new String(numArray, i, l - i); + return res.isEmpty() ? "0" : res; + } +} +``` + +```cpp +class Solution { +public: + string removeKdigits(string num, int k) { + int l = 0; + for (int r = 0; r < num.size(); r++) { + while (l > 0 && k > 0 && num[l - 1] > num[r]) { + l--; + k--; + } + num[l++] = num[r]; + } + + l -= k; + int i = 0; + while (i < l && num[i] == '0') { + i++; + } + if (i == l) return "0"; + return num.substr(i, l - i); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} num + * @param {number} k + * @return {string} + */ + removeKdigits(num, k) { + let numArray = num.split(''); + let l = 0; + + for (let r = 0; r < numArray.length; r++) { + while (l > 0 && k > 0 && numArray[l - 1] > numArray[r]) { + l--; + k--; + } + numArray[l++] = numArray[r]; + } + + l -= k; + let i = 0; + while (i < l && numArray[i] === '0') { + i++; + } + let res = numArray.slice(i, l).join(''); + return res.length === 0 ? '0' : res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the language. diff --git a/articles/remove-linked-list-elements.md b/articles/remove-linked-list-elements.md index 30e4a5e94..b456ca2cf 100644 --- a/articles/remove-linked-list-elements.md +++ b/articles/remove-linked-list-elements.md @@ -17,7 +17,7 @@ class Solution: if cur.val != val: arr.append(cur.val) cur = cur.next - + if not arr: return None @@ -27,7 +27,7 @@ class Solution: node = ListNode(arr[i]) cur.next = node cur = cur.next - + return res ``` @@ -156,12 +156,53 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val = 0, ListNode next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + public ListNode RemoveElements(ListNode head, int val) { + List arr = new List(); + ListNode cur = head; + + while (cur != null) { + if (cur.val != val) { + arr.Add(cur.val); + } + cur = cur.next; + } + + if (arr.Count == 0) { + return null; + } + + ListNode res = new ListNode(arr[0]); + cur = res; + for (int i = 1; i < arr.Count; i++) { + ListNode node = new ListNode(arr[i]); + cur.next = node; + cur = cur.next; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -248,12 +289,35 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val=0, ListNode next=null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + public ListNode RemoveElements(ListNode head, int val) { + if (head == null) { + return null; + } + head.next = RemoveElements(head.next, val); + return head.val != val ? head : head.next; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -308,7 +372,7 @@ public class Solution { } curr = nxt; } - + return dummy.next; } } @@ -330,7 +394,7 @@ public: ListNode* removeElements(ListNode* head, int val) { ListNode dummy(0, head); ListNode *prev = &dummy, *curr = head; - + while (curr) { ListNode* nxt = curr->next; if (curr->val == val) { @@ -340,7 +404,7 @@ public: } curr = nxt; } - + return dummy.next; } }; @@ -364,7 +428,8 @@ class Solution { */ removeElements(head, val) { let dummy = new ListNode(0, head); - let prev = dummy, curr = head; + let prev = dummy, + curr = head; while (curr) { let nxt = curr.next; @@ -381,12 +446,44 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val=0, ListNode next=null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + public ListNode RemoveElements(ListNode head, int val) { + ListNode dummy = new ListNode(0, head); + ListNode prev = dummy, curr = head; + + while (curr != null) { + ListNode nxt = curr.next; + if (curr.val == val) { + prev.next = nxt; + } else { + prev = curr; + } + curr = nxt; + } + + return dummy.next; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -437,7 +534,7 @@ public class Solution { curr = curr.next; } } - + return dummy.next; } } @@ -459,7 +556,7 @@ public: ListNode* removeElements(ListNode* head, int val) { ListNode dummy(-1, head); ListNode *curr = &dummy; - + while (curr->next) { if (curr->next->val == val) { curr->next = curr->next->next; @@ -467,7 +564,7 @@ public: curr = curr->next; } } - + return dummy.next; } }; @@ -506,9 +603,39 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val=0, ListNode next=null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + public ListNode RemoveElements(ListNode head, int val) { + ListNode dummy = new ListNode(-1, head); + ListNode curr = dummy; + + while (curr.next != null) { + if (curr.next.val == val) { + curr.next = curr.next.next; + } else { + curr = curr.next; + } + } + + return dummy.next; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/remove-max-number-of-edges-to-keep-graph-fully-traversable.md b/articles/remove-max-number-of-edges-to-keep-graph-fully-traversable.md new file mode 100644 index 000000000..11f1ff3bd --- /dev/null +++ b/articles/remove-max-number-of-edges-to-keep-graph-fully-traversable.md @@ -0,0 +1,280 @@ +## 1. Disjoint Set Union + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.n = n + self.Parent = list(range(n + 1)) + self.Size = [1] * (n + 1) + + def find(self, node): + if self.Parent[node] != node: + self.Parent[node] = self.find(self.Parent[node]) + return self.Parent[node] + + def union(self, u, v): + pu = self.find(u) + pv = self.find(v) + if pu == pv: + return 0 + if self.Size[pu] < self.Size[pv]: + pu, pv = pv, pu + self.Size[pu] += self.Size[pv] + self.Parent[pv] = pu + self.n -= 1 + return 1 + + def isConnected(self): + return self.n == 1 + +class Solution: + def maxNumEdgesToRemove(self, n: int, edges: List[List[int]]) -> int: + alice, bob = DSU(n), DSU(n) + cnt = 0 + + for type, src, dst in edges: + if type == 3: + cnt += (alice.union(src, dst) | bob.union(src, dst)) + + for type, src, dst in edges: + if type == 1: + cnt += alice.union(src, dst) + elif type == 2: + cnt += bob.union(src, dst) + + if alice.isConnected() and bob.isConnected(): + return len(edges) - cnt + return -1 +``` + +```java +class DSU { + private int[] parent, size; + private int n; + + public DSU(int n) { + this.n = n; + parent = new int[n + 1]; + size = new int[n + 1]; + for (int i = 0; i <= n; i++) { + parent[i] = i; + size[i] = 1; + } + } + + public int find(int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + public int union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) { + return 0; + } + if (size[pu] < size[pv]) { + int temp = pu; + pu = pv; + pv = temp; + } + size[pu] += size[pv]; + parent[pv] = pu; + n--; + return 1; + } + + public boolean isConnected() { + return n == 1; + } +} + +public class Solution { + public int maxNumEdgesToRemove(int n, int[][] edges) { + DSU alice = new DSU(n), bob = new DSU(n); + int cnt = 0; + + for (int[] edge : edges) { + if (edge[0] == 3) { + cnt += (alice.union(edge[1], edge[2]) | bob.union(edge[1], edge[2])); + } + } + + for (int[] edge : edges) { + if (edge[0] == 1) { + cnt += alice.union(edge[1], edge[2]); + } else if (edge[0] == 2) { + cnt += bob.union(edge[1], edge[2]); + } + } + + if (alice.isConnected() && bob.isConnected()) { + return edges.length - cnt; + } + return -1; + } +} +``` + +```cpp +class DSU { +private: + vector parent, size; + int n; + +public: + DSU(int n) : n(n), parent(n + 1), size(n + 1, 1) { + for (int i = 0; i <= n; i++) { + parent[i] = i; + } + } + + int find(int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + int unionSets(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) { + return 0; + } + if (size[pu] < size[pv]) { + swap(pu, pv); + } + size[pu] += size[pv]; + parent[pv] = pu; + n--; + return 1; + } + + bool isConnected() { + return n == 1; + } +}; + +class Solution { +public: + int maxNumEdgesToRemove(int n, vector>& edges) { + DSU alice(n), bob(n); + int cnt = 0; + + for (auto& edge : edges) { + if (edge[0] == 3) { + cnt += (alice.unionSets(edge[1], edge[2]) | bob.unionSets(edge[1], edge[2])); + } + } + + for (auto& edge : edges) { + if (edge[0] == 1) { + cnt += alice.unionSets(edge[1], edge[2]); + } else if (edge[0] == 2) { + cnt += bob.unionSets(edge[1], edge[2]); + } + } + + if (alice.isConnected() && bob.isConnected()) { + return edges.size() - cnt; + } + return -1; + } +}; +``` + +```javascript +class DSU { + /** + * @param {number} n + */ + constructor(n) { + this.n = n; + this.parent = Array(n + 1) + .fill(0) + .map((_, i) => i); + this.size = Array(n + 1).fill(1); + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.parent[node] !== node) { + this.parent[node] = this.find(this.parent[node]); + } + return this.parent[node]; + } + + /** + * @param {number} u + * @param {number} v + * @return {number} + */ + union(u, v) { + let pu = this.find(u), + pv = this.find(v); + if (pu === pv) { + return 0; + } + if (this.size[pu] < this.size[pv]) { + [pu, pv] = [pv, pu]; + } + this.size[pu] += this.size[pv]; + this.parent[pv] = pu; + this.n--; + return 1; + } + + /** + * @return {boolean} + */ + isConnected() { + return this.n === 1; + } +} + +class Solution { + /** + * @param {number} n + * @param {number[][]} edges + * @return {number} + */ + maxNumEdgesToRemove(n, edges) { + let alice = new DSU(n), + bob = new DSU(n); + let cnt = 0; + + for (let [type, src, dst] of edges) { + if (type === 3) { + cnt += alice.union(src, dst) | bob.union(src, dst); + } + } + + for (let [type, src, dst] of edges) { + if (type === 1) { + cnt += alice.union(src, dst); + } else if (type === 2) { + cnt += bob.union(src, dst); + } + } + + return alice.isConnected() && bob.isConnected() + ? edges.length - cnt + : -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(E * α(V))$ +- Space complexity: $O(V)$ + +> Where $V$ is the number of verticies and $E$ is the number of edges. diff --git a/articles/remove-node-from-end-of-linked-list.md b/articles/remove-node-from-end-of-linked-list.md index 141817504..4d919436e 100644 --- a/articles/remove-node-from-end-of-linked-list.md +++ b/articles/remove-node-from-end-of-linked-list.md @@ -16,11 +16,11 @@ class Solution: while cur: nodes.append(cur) cur = cur.next - + removeIndex = len(nodes) - n if removeIndex == 0: return head.next - + nodes[removeIndex - 1].next = nodes[removeIndex].next return head ``` @@ -199,7 +199,7 @@ class Solution { fun removeNthFromEnd(head: ListNode?, n: Int): ListNode? { val nodes = mutableListOf() var cur = head - + while (cur != null) { nodes.add(cur) cur = cur.next @@ -216,12 +216,44 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? { + var nodes: [ListNode] = [] + var cur = head + + while cur != nil { + nodes.append(cur!) + cur = cur?.next + } + + let removeIndex = nodes.count - n + if removeIndex == 0 { + return head?.next + } + + nodes[removeIndex - 1].next = nodes[removeIndex].next + return head + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(N)$ -* Space complexity: $O(N)$ +- Time complexity: $O(N)$ +- Space complexity: $O(N)$ --- @@ -243,11 +275,11 @@ class Solution: while cur: N += 1 cur = cur.next - + removeIndex = N - n if removeIndex == 0: return head.next - + cur = head for i in range(N - 1): if (i + 1) == removeIndex: @@ -490,12 +522,50 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? { + var N = 0 + var cur = head + while cur != nil { + N += 1 + cur = cur?.next + } + + let removeIndex = N - n + if removeIndex == 0 { + return head?.next + } + + cur = head + for i in 0..<(N - 1) { + if (i + 1) == removeIndex { + cur?.next = cur?.next?.next + break + } + cur = cur?.next + } + return head + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(N)$ -* Space complexity: $O(1)$ +- Time complexity: $O(N)$ +- Space complexity: $O(1)$ --- @@ -580,7 +650,7 @@ public: n--; if (n == 0) { return head -> next; - } + } return head; } @@ -678,16 +748,16 @@ func rec(head *ListNode, n *int) *ListNode { } head.Next = rec(head.Next, n) - (*n)-- + (*n)-- if *n == 0 { - return head.Next + return head.Next } - return head + return head } func removeNthFromEnd(head *ListNode, n int) *ListNode { - return rec(head, &n) + return rec(head, &n) } ``` @@ -711,9 +781,9 @@ class Solution { n[0]-- return if (n[0] == 0) { - head.next + head.next } else { - head + head } } @@ -723,12 +793,44 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func rec(_ head: ListNode?, _ n: inout Int) -> ListNode? { + if head == nil { + return nil + } + + head?.next = rec(head?.next, &n) + n -= 1 + if n == 0 { + return head?.next + } + return head + } + + func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? { + var n = n + return rec(head, &n) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(N)$ -* Space complexity: $O(N)$ +- Time complexity: $O(N)$ +- Space complexity: $O(N)$ for recursion stack. --- @@ -964,9 +1066,43 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func removeNthFromEnd(_ head: ListNode?, _ n: Int) -> ListNode? { + let dummy = ListNode(0, head) + var left: ListNode? = dummy + var right: ListNode? = head + var n = n + + while n > 0 { + right = right?.next + n -= 1 + } + + while right != nil { + left = left?.next + right = right?.next + } + + left?.next = left?.next?.next + return dummy.next + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(N)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(N)$ +- Space complexity: $O(1)$ diff --git a/articles/remove-nodes-from-linked-list.md b/articles/remove-nodes-from-linked-list.md index b629d4760..b03300e26 100644 --- a/articles/remove-nodes-from-linked-list.md +++ b/articles/remove-nodes-from-linked-list.md @@ -14,14 +14,14 @@ class Solution: while cur: arr.append(cur) cur = cur.next - + rightMaxi = ListNode(0, None) for i in range(len(arr) - 1, 0, -1): if rightMaxi.val > arr[i].val: arr[i - 1].next = rightMaxi else: rightMaxi = arr[i] - + return arr[0].next ``` @@ -114,7 +114,8 @@ class Solution { * @return {ListNode} */ removeNodes(head) { - let cur = head, arr = [{ val: 0, next: head }]; + let cur = head, + arr = [{ val: 0, next: head }]; while (cur) { arr.push(cur); cur = cur.next; @@ -138,8 +139,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -293,8 +294,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -312,7 +313,7 @@ class Solution: def removeNodes(self, head: Optional[ListNode]) -> Optional[ListNode]: if not head: return None - + head.next = self.removeNodes(head.next) if head.next and head.val < head.next.val: return head.next @@ -399,8 +400,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -434,7 +435,7 @@ class Solution: else: cur_max = cur.next.val cur = cur.next - + return reverse(head) ``` @@ -503,7 +504,7 @@ public: } return prev; } - + ListNode* removeNodes(ListNode* head) { head = reverse(head); ListNode* cur = head; @@ -539,7 +540,8 @@ class Solution { */ removeNodes(head) { const reverse = (head) => { - let prev = null, cur = head; + let prev = null, + cur = head; while (cur) { let tmp = cur.next; cur.next = prev; @@ -570,5 +572,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/removing-stars-from-a-string.md b/articles/removing-stars-from-a-string.md new file mode 100644 index 000000000..54964a0bb --- /dev/null +++ b/articles/removing-stars-from-a-string.md @@ -0,0 +1,357 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def removeStars(self, s: str) -> str: + while True: + flag = False + for i in range(1, len(s)): + if s[i] == '*' and s[i - 1] != '*': + s = s[:i - 1] + s[i + 1:] + flag = True + break + if not flag: + break + return s +``` + +```java +public class Solution { + public String removeStars(String s) { + while (true) { + boolean flag = false; + StringBuilder sb = new StringBuilder(s); + for (int i = 1; i < sb.length(); i++) { + if (sb.charAt(i) == '*' && sb.charAt(i - 1) != '*') { + sb.delete(i - 1, i + 1); + flag = true; + break; + } + } + s = sb.toString(); + if (!flag) { + break; + } + } + return s; + } +} +``` + +```cpp +class Solution { +public: + string removeStars(string s) { + while (true) { + bool flag = false; + for (int i = 1; i < s.size(); ++i) { + if (s[i] == '*' && s[i - 1] != '*') { + s = s.substr(0, i - 1) + s.substr(i + 1); + flag = true; + break; + } + } + if (!flag) { + break; + } + } + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + removeStars(s) { + while (true) { + let flag = false; + for (let i = 1; i < s.length; i++) { + if (s[i] === '*' && s[i - 1] !== '*') { + s = s.slice(0, i - 1) + s.slice(i + 1); + flag = true; + break; + } + } + if (!flag) { + break; + } + } + return s; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 2. Brute Force (Optimized) + +::tabs-start + +```python +class Solution: + def removeStars(self, s: str) -> str: + n = len(s) + i = 0 + while i < n: + if i and s[i] == '*' and s[i - 1] != '*': + s = s[:i - 1] + s[i + 1:] + n -= 2 + i -= 2 + i += 1 + return s +``` + +```java +public class Solution { + public String removeStars(String s) { + int n = s.length(); + int i = 0; + while (i < n) { + if (i > 0 && s.charAt(i) == '*' && s.charAt(i - 1) != '*') { + s = s.substring(0, i - 1) + s.substring(i + 1); + n -= 2; + i -= 2; + } + i++; + } + return s; + } +} +``` + +```cpp +class Solution { +public: + string removeStars(string s) { + int n = s.length(); + int i = 0; + while (i < n) { + if (i > 0 && s[i] == '*' && s[i - 1] != '*') { + s = s.substr(0, i - 1) + s.substr(i + 1); + n -= 2; + i -= 2; + } + i++; + } + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + removeStars(s) { + let n = s.length; + let i = 0; + while (i < n) { + if (i > 0 && s[i] === '*' && s[i - 1] !== '*') { + s = s.slice(0, i - 1) + s.slice(i + 1); + n -= 2; + i -= 2; + } + i++; + } + return s; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 3. Stack + +::tabs-start + +```python +class Solution: + def removeStars(self, s: str) -> str: + stack = [] + for c in s: + if c == "*": + stack and stack.pop() + else: + stack.append(c) + return "".join(stack) +``` + +```java +public class Solution { + public String removeStars(String s) { + Stack stack = new Stack<>(); + for (char c : s.toCharArray()) { + if (c == '*') { + if (!stack.isEmpty()) stack.pop(); + } else { + stack.push(c); + } + } + StringBuilder res = new StringBuilder(); + for (char c : stack) res.append(c); + return res.toString(); + } +} +``` + +```cpp +class Solution { +public: + string removeStars(string s) { + stack stack; + for (char c : s) { + if (c == '*') { + if (!stack.empty()) stack.pop(); + } else { + stack.push(c); + } + } + string res; + while (!stack.empty()) { + res += stack.top(); + stack.pop(); + } + reverse(res.begin(), res.end()); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + removeStars(s) { + const stack = []; + for (const c of s) { + if (c === '*') { + if (stack.length > 0) stack.pop(); + } else { + stack.push(c); + } + } + return stack.join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Two Pointers + +::tabs-start + +```python +class Solution: + def removeStars(self, s: str) -> str: + l = 0 + s = list(s) + + for r in range(len(s)): + if s[r] == '*': + l -= 1 + else: + s[l] = s[r] + l += 1 + + return ''.join(s[:l]) +``` + +```java +public class Solution { + public String removeStars(String s) { + char[] arr = s.toCharArray(); + int l = 0; + + for (int r = 0; r < arr.length; r++) { + if (arr[r] == '*') { + l--; + } else { + arr[l] = arr[r]; + l++; + } + } + return new String(arr, 0, l); + } +} +``` + +```cpp +class Solution { +public: + string removeStars(string s) { + int l = 0; + + for (int r = 0; r < s.size(); r++) { + if (s[r] == '*') { + l--; + } else { + s[l] = s[r]; + l++; + } + } + return s.substr(0, l); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {string} + */ + removeStars(s) { + const arr = s.split(''); + let l = 0; + + for (let r = 0; r < arr.length; r++) { + if (arr[r] === '*') { + l--; + } else { + arr[l] = arr[r]; + l++; + } + } + return arr.slice(0, l).join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the language. diff --git a/articles/reorder-linked-list.md b/articles/reorder-linked-list.md index 399860a22..7f87f29ec 100644 --- a/articles/reorder-linked-list.md +++ b/articles/reorder-linked-list.md @@ -13,13 +13,13 @@ class Solution: def reorderList(self, head: Optional[ListNode]) -> None: if not head: return - + nodes = [] cur = head while cur: nodes.append(cur) cur = cur.next - + i, j = 0, len(nodes) - 1 while i < j: nodes[i].next = nodes[j] @@ -28,7 +28,7 @@ class Solution: break nodes[j].next = nodes[i] j -= 1 - + nodes[i].next = None ``` @@ -89,14 +89,14 @@ class Solution { public: void reorderList(ListNode* head) { if (!head) return; - + vector nodes; ListNode* cur = head; while (cur) { nodes.push_back(cur); cur = cur->next; } - + int i = 0, j = nodes.size() - 1; while (i < j) { nodes[i]->next = nodes[j]; @@ -105,7 +105,7 @@ public: nodes[j]->next = nodes[i]; j--; } - + nodes[i]->next = nullptr; } }; @@ -137,7 +137,8 @@ class Solution { cur = cur.next; } - let i = 0, j = nodes.length - 1; + let i = 0, + j = nodes.length - 1; while (i < j) { nodes[i].next = nodes[j]; i++; @@ -260,12 +261,53 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func reorderList(_ head: ListNode?) { + if head == nil { + return + } + + var nodes: [ListNode] = [] + var cur = head + + while cur != nil { + nodes.append(cur!) + cur = cur?.next + } + + var i = 0, j = nodes.count - 1 + while i < j { + nodes[i].next = nodes[j] + i += 1 + if i >= j { + break + } + nodes[j].next = nodes[i] + j -= 1 + } + + nodes[i].next = nil + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -286,10 +328,11 @@ class Solution: def rec(root: ListNode, cur: ListNode) -> ListNode: if not cur: return root - root = rec(root, cur.next) + root = rec(root, cur.next) if not root: return None + tmp = None if root == cur or root.next == cur: cur.next = None @@ -297,8 +340,9 @@ class Solution: tmp = root.next root.next = cur cur.next = tmp + return tmp - + head = rec(head, head.next) ``` @@ -323,10 +367,12 @@ public class Solution { if (cur == null) { return root; } + root = rec(root, cur.next); if (root == null) { return null; } + ListNode tmp = null; if (root == cur || root.next == cur) { cur.next = null; @@ -335,6 +381,7 @@ public class Solution { root.next = cur; cur.next = tmp; } + return tmp; } } @@ -363,10 +410,12 @@ private: if (cur == nullptr) { return root; } + root = rec(root, cur->next); if (root == nullptr) { return nullptr; } + ListNode* tmp = nullptr; if (root == cur || root->next == cur) { cur->next = nullptr; @@ -375,6 +424,7 @@ private: root->next = cur; cur->next = tmp; } + return tmp; } }; @@ -409,10 +459,12 @@ class Solution { if (cur === null) { return root; } + root = this.rec(root, cur.next); if (root === null) { return null; } + let tmp = null; if (root === cur || root.next === cur) { cur.next = null; @@ -421,6 +473,7 @@ class Solution { root.next = cur; cur.next = tmp; } + return tmp; } } @@ -448,10 +501,12 @@ public class Solution { if (cur == null) { return root; } + root = Rec(root, cur.next); if (root == null) { return null; } + ListNode tmp = null; if (root == cur || root.next == cur) { cur.next = null; @@ -460,6 +515,7 @@ public class Solution { root.next = cur; cur.next = tmp; } + return tmp; } } @@ -483,11 +539,12 @@ func reorderList(head *ListNode) { if cur == nil { return root } - root = rec(root, cur.Next) + root = rec(root, cur.Next) if root == nil { return nil } + var tmp *ListNode if root == cur || root.Next == cur { cur.Next = nil @@ -496,6 +553,7 @@ func reorderList(head *ListNode) { root.Next = cur cur.Next = tmp } + return tmp } @@ -521,11 +579,12 @@ class Solution { if (cur == null) { return root } - var updatedRoot = rec(root, cur.next) + var updatedRoot = rec(root, cur.next) if (updatedRoot == null) { return null } + var tmp: ListNode? = null if (updatedRoot == cur || updatedRoot?.next == cur) { cur.next = null @@ -534,6 +593,7 @@ class Solution { updatedRoot.next = cur cur.next = tmp } + return tmp } @@ -542,12 +602,52 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func reorderList(_ head: ListNode?) { + func rec(_ root: ListNode?, _ cur: ListNode?) -> ListNode? { + if cur == nil { + return root + } + + var root = rec(root, cur?.next) + if root == nil { + return nil + } + + var tmp: ListNode? = nil + if root === cur || root?.next === cur { + cur?.next = nil + } else { + tmp = root?.next + root?.next = cur + cur?.next = tmp + } + + return tmp + } + + rec(head, head?.next) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -852,9 +952,54 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func reorderList(_ head: ListNode?) { + var slow = head, fast = head?.next + while fast != nil && fast?.next != nil { + slow = slow?.next + fast = fast?.next?.next + } + + var second = slow?.next + var prev: ListNode? = nil + slow?.next = nil + + while second != nil { + let tmp = second?.next + second?.next = prev + prev = second + second = tmp + } + + var first = head + second = prev + + while second != nil { + let tmp1 = first?.next + let tmp2 = second?.next + first?.next = second + second?.next = tmp1 + first = tmp1 + second = tmp2 + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/reorder-routes-to-make-all-paths-lead-to-the-city-zero.md b/articles/reorder-routes-to-make-all-paths-lead-to-the-city-zero.md index ae2727f84..2ca0dcc12 100644 --- a/articles/reorder-routes-to-make-all-paths-lead-to-the-city-zero.md +++ b/articles/reorder-routes-to-make-all-paths-lead-to-the-city-zero.md @@ -134,8 +134,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -158,7 +158,7 @@ class Solution: continue changes += dfs(abs(nei), node) + (nei > 0) return changes - + return dfs(0, -1) ``` @@ -197,7 +197,7 @@ public: adj[u].push_back(v); adj[v].push_back(-u); } - + return dfs(0, -1, adj); } @@ -245,8 +245,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -261,12 +261,12 @@ class Solution: for u, v in connections: adj[u].append((v, 1)) adj[v].append((u, 0)) - + visit = [False] * n queue = deque([0]) visit[0] = True changes = 0 - + while queue: node = queue.popleft() for neighbor, isForward in adj[node]: @@ -319,13 +319,13 @@ public: adj[conn[0]].push_back({conn[1], 1}); adj[conn[1]].push_back({conn[0], 0}); } - + vector visit(n, false); queue q; q.push(0); visit[0] = true; int changes = 0; - + while (!q.empty()) { int node = q.front(); q.pop(); @@ -381,5 +381,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/reorganize-string.md b/articles/reorganize-string.md index 57d672327..bf57f927e 100644 --- a/articles/reorganize-string.md +++ b/articles/reorganize-string.md @@ -8,11 +8,11 @@ class Solution: freq = [0] * 26 for char in s: freq[ord(char) - ord('a')] += 1 - + max_freq = max(freq) if max_freq > (len(s) + 1) // 2: return "" - + res = [] while len(res) < len(s): maxIdx = freq.index(max(freq)) @@ -21,7 +21,7 @@ class Solution: freq[maxIdx] -= 1 if freq[maxIdx] == 0: continue - + tmp = freq[maxIdx] freq[maxIdx] = float("-inf") nextMaxIdx = freq.index(max(freq)) @@ -29,7 +29,7 @@ class Solution: res.append(char) freq[maxIdx] = tmp freq[nextMaxIdx] -= 1 - + return ''.join(res) ``` @@ -145,7 +145,7 @@ class Solution { const maxFreq = Math.max(...freq); if (maxFreq > Math.floor((s.length + 1) / 2)) { - return ""; + return ''; } const findMaxIndex = () => { @@ -172,7 +172,9 @@ class Solution { const tmp = freq[maxIdx]; freq[maxIdx] = -Infinity; const nextMaxIdx = findMaxIndex(); - const nextMaxChar = String.fromCharCode(nextMaxIdx + 'a'.charCodeAt(0)); + const nextMaxChar = String.fromCharCode( + nextMaxIdx + 'a'.charCodeAt(0), + ); res.push(nextMaxChar); freq[maxIdx] = tmp; freq[nextMaxIdx]--; @@ -183,14 +185,50 @@ class Solution { } ``` +```csharp +public class Solution { + public string ReorganizeString(string s) { + int[] freq = new int[26]; + foreach (char c in s) { + freq[c - 'a']++; + } + + int maxFreq = freq.Max(); + if (maxFreq > (s.Length + 1) / 2) { + return ""; + } + + List res = new List(); + while (res.Count < s.Length) { + int maxIdx = Array.IndexOf(freq, freq.Max()); + char ch = (char)(maxIdx + 'a'); + res.Add(ch); + freq[maxIdx]--; + + if (freq[maxIdx] == 0) continue; + + int tmp = freq[maxIdx]; + freq[maxIdx] = int.MinValue; + int nextMaxIdx = Array.IndexOf(freq, freq.Max()); + char nextCh = (char)(nextMaxIdx + 'a'); + res.Add(nextCh); + freq[maxIdx] = tmp; + freq[nextMaxIdx]--; + } + + return new string(res.ToArray()); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(1)$ extra space, since we have at most $26$ different characters. - * $O(n)$ space for the output string. +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space, since we have at most $26$ different characters. + - $O(n)$ space for the output string. --- @@ -204,13 +242,13 @@ class Solution: count = Counter(s) maxHeap = [[-cnt, char] for char, cnt in count.items()] heapq.heapify(maxHeap) - + prev = None res = "" while maxHeap or prev: if prev and not maxHeap: return "" - + cnt, char = heapq.heappop(maxHeap) res += char cnt += 1 @@ -218,10 +256,10 @@ class Solution: if prev: heapq.heappush(maxHeap, prev) prev = None - + if cnt != 0: prev = [cnt, char] - + return res ``` @@ -323,7 +361,10 @@ class Solution { }); for (let i = 0; i < 26; i++) { if (freq[i] > 0) { - maxHeap.enqueue([freq[i], String.fromCharCode(i + 'a'.charCodeAt(0))]); + maxHeap.enqueue([ + freq[i], + String.fromCharCode(i + 'a'.charCodeAt(0)), + ]); } } @@ -352,14 +393,53 @@ class Solution { } ``` +```csharp +public class Solution { + public string ReorganizeString(string s) { + Dictionary count = new(); + foreach (char c in s) { + if (!count.ContainsKey(c)) count[c] = 0; + count[c]++; + } + + PriorityQueue maxHeap = new(); + foreach (var kvp in count) { + maxHeap.Enqueue(new int[] { kvp.Value, kvp.Key }, -kvp.Value); + } + + string res = ""; + int[] prev = null; + + while (maxHeap.Count > 0 || prev != null) { + if (prev != null && maxHeap.Count == 0) return ""; + + int[] curr = maxHeap.Dequeue(); + res += (char)curr[1]; + curr[0]--; + + if (prev != null) { + maxHeap.Enqueue(prev, -prev[0]); + prev = null; + } + + if (curr[0] > 0) { + prev = curr; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(1)$ extra space, since we have at most $26$ different characters. - * $O(n)$ space for the output string. +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space, since we have at most $26$ different characters. + - $O(n)$ space for the output string. --- @@ -378,7 +458,7 @@ class Solution: max_freq = freq[max_idx] if max_freq > (len(s) + 1) // 2: return "" - + res = [''] * len(s) idx = 0 max_char = chr(max_idx + ord('a')) @@ -387,7 +467,7 @@ class Solution: res[idx] = max_char idx += 2 freq[max_idx] -= 1 - + for i in range(26): while freq[i] > 0: if idx >= len(s): @@ -395,7 +475,7 @@ class Solution: res[idx] = chr(i + ord('a')) idx += 2 freq[i] -= 1 - + return ''.join(res) ``` @@ -536,11 +616,53 @@ class Solution { } ``` +```csharp +public class Solution { + public string ReorganizeString(string s) { + int[] freq = new int[26]; + foreach (char c in s) { + freq[c - 'a']++; + } + + int maxIdx = 0; + for (int i = 1; i < 26; i++) { + if (freq[i] > freq[maxIdx]) { + maxIdx = i; + } + } + + int maxFreq = freq[maxIdx]; + if (maxFreq > (s.Length + 1) / 2) return ""; + + char[] res = new char[s.Length]; + int idx = 0; + char maxChar = (char)(maxIdx + 'a'); + + while (freq[maxIdx] > 0) { + res[idx] = maxChar; + idx += 2; + freq[maxIdx]--; + } + + for (int i = 0; i < 26; i++) { + while (freq[i] > 0) { + if (idx >= s.Length) idx = 1; + res[idx] = (char)(i + 'a'); + idx += 2; + freq[i]--; + } + } + + return new string(res); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: - * $O(1)$ extra space, since we have at most $26$ different characters. - * $O(n)$ space for the output string. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space, since we have at most $26$ different characters. + - $O(n)$ space for the output string. diff --git a/articles/repeated-dna-sequences.md b/articles/repeated-dna-sequences.md index 6976f8850..de3a9938b 100644 --- a/articles/repeated-dna-sequences.md +++ b/articles/repeated-dna-sequences.md @@ -78,8 +78,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -182,8 +182,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -316,9 +316,14 @@ class Solution { const cnt = new Map(); const res = []; - const base1 = 31, base2 = 37; - let hash1 = 0, hash2 = 0, power1 = 1, power2 = 1; - const MOD1 = 685683731, MOD2 = 768258391; + const base1 = 31, + base2 = 37; + let hash1 = 0, + hash2 = 0, + power1 = 1, + power2 = 1; + const MOD1 = 685683731, + MOD2 = 768258391; for (let i = 0; i < 9; i++) { power1 = (power1 * base1) % MOD1; @@ -336,8 +341,12 @@ class Solution { res.push(s.substring(i - 9, i + 1)); } - hash1 = (hash1 - power1 * s.charCodeAt(i - 9) % MOD1 + MOD1) % MOD1; - hash2 = (hash2 - power2 * s.charCodeAt(i - 9) % MOD2 + MOD2) % MOD2; + hash1 = + (hash1 - ((power1 * s.charCodeAt(i - 9)) % MOD1) + MOD1) % + MOD1; + hash2 = + (hash2 - ((power2 * s.charCodeAt(i - 9)) % MOD2) + MOD2) % + MOD2; } } @@ -350,8 +359,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -375,7 +384,7 @@ class Solution: res.add(s[i - 9: i + 1]) else: seen.add(mask) - + return list(res) ``` @@ -410,7 +419,7 @@ public: vector findRepeatedDnaSequences(string s) { if (s.length() < 10) return {}; - unordered_map mp = {{'A', 0}, {'C', 1}, + unordered_map mp = {{'A', 0}, {'C', 1}, {'G', 2}, {'T', 3}}; unordered_map cnt; vector res; @@ -441,13 +450,13 @@ class Solution { findRepeatedDnaSequences(s) { if (s.length < 10) return []; - const mp = { 'A': 0, 'C': 1, 'G': 2, 'T': 3 }; + const mp = { A: 0, C: 1, G: 2, T: 3 }; const cnt = new Map(); const res = []; let mask = 0; for (let i = 0; i < s.length; i++) { - mask = ((mask << 2) | mp[s[i]]) & 0xFFFFF; + mask = ((mask << 2) | mp[s[i]]) & 0xfffff; if (i >= 9) { cnt.set(mask, (cnt.get(mask) || 0) + 1); @@ -466,5 +475,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/replace-elements-with-greatest-element-on-right-side.md b/articles/replace-elements-with-greatest-element-on-right-side.md index 1825436a7..373188429 100644 --- a/articles/replace-elements-with-greatest-element-on-right-side.md +++ b/articles/replace-elements-with-greatest-element-on-right-side.md @@ -71,12 +71,29 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] ReplaceElements(int[] arr) { + int n = arr.Length; + int[] ans = new int[n]; + for (int i = 0; i < n; i++) { + int rightMax = -1; + for (int j = i + 1; j < n; j++) { + rightMax = Math.Max(rightMax, arr[j]); + } + ans[i] = rightMax; + } + return ans; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -93,7 +110,7 @@ class Solution: for i in range(n - 1, -1, -1): ans[i] = rightMax rightMax = max(arr[i], rightMax) - return ans + return ans ``` ```java @@ -146,9 +163,24 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] ReplaceElements(int[] arr) { + int n = arr.Length; + int[] ans = new int[n]; + int rightMax = -1; + for (int i = n - 1; i >= 0; i--) { + ans[i] = rightMax; + rightMax = Math.Max(arr[i], rightMax); + } + return ans; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/restore-ip-addresses.md b/articles/restore-ip-addresses.md index a0a6fd2b6..2c00656c9 100644 --- a/articles/restore-ip-addresses.md +++ b/articles/restore-ip-addresses.md @@ -8,20 +8,20 @@ class Solution: res = [] if len(s) > 12: return res - + def backtrack(i, dots, curIP): if dots == 4 and i == len(s): res.append(curIP[:-1]) return if dots > 4: return - + for j in range(i, min(i + 3, len(s))): if i != j and s[i] == "0": continue if int(s[i: j + 1]) < 256: backtrack(j + 1, dots + 1, curIP + s[i: j + 1] + ".") - + backtrack(0, 0, "") return res ``` @@ -107,7 +107,7 @@ class Solution { } }; - backtrack(0, 0, ""); + backtrack(0, 0, ''); return res; } } @@ -117,8 +117,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m ^ n * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m ^ n * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is equals to $3$ as there are at most three digits in a valid segment and $n$ is equals to $4$ as there are four segments in a valid IP. @@ -134,27 +134,27 @@ class Solution: res = [] if len(s) > 12: return res - + def valid(num): return len(num) == 1 or (int(num) < 256 and num[0] != "0") - + def add(s1, s2, s3, s4): if s1 + s2 + s3 + s4 != len(s): return - + num1 = s[:s1] num2 = s[s1:s1+s2] num3 = s[s1+s2:s1+s2+s3] num4 = s[s1+s2+s3:] if valid(num1) and valid(num2) and valid(num3) and valid(num4): res.append(num1 + "." + num2 + "." + num3 + "." + num4) - + for seg1 in range(1, 4): for seg2 in range(1, 4): for seg3 in range(1, 4): for seg4 in range(1, 4): add(seg1, seg2, seg3, seg4) - + return res ``` @@ -163,13 +163,13 @@ public class Solution { public List restoreIpAddresses(String s) { List res = new ArrayList<>(); if (s.length() > 12) return res; - + for (int seg1 = 1; seg1 < 4; seg1++) { for (int seg2 = 1; seg2 < 4; seg2++) { for (int seg3 = 1; seg3 < 4; seg3++) { for (int seg4 = 1; seg4 < 4; seg4++) { if (seg1 + seg2 + seg3 + seg4 != s.length()) continue; - + String num1 = s.substring(0, seg1); String num2 = s.substring(seg1, seg1 + seg2); String num3 = s.substring(seg1 + seg2, seg1 + seg2 + seg3); @@ -211,7 +211,7 @@ public: for (int seg3 = 1; seg3 < 4; ++seg3) { for (int seg4 = 1; seg4 < 4; ++seg4) { if (seg1 + seg2 + seg3 + seg4 != s.size()) continue; - + string num1 = s.substr(0, seg1); string num2 = s.substr(seg1, seg2); string num3 = s.substr(seg1 + seg2, seg3); @@ -238,7 +238,7 @@ class Solution { restoreIpAddresses(s) { const res = []; if (s.length > 12) return res; - + const isValid = (num) => { if (num.length > 1 && num[0] === '0') return false; const value = parseInt(num, 10); @@ -253,10 +253,18 @@ class Solution { const num1 = s.substring(0, seg1); const num2 = s.substring(seg1, seg1 + seg2); - const num3 = s.substring(seg1 + seg2, seg1 + seg2 + seg3); + const num3 = s.substring( + seg1 + seg2, + seg1 + seg2 + seg3, + ); const num4 = s.substring(seg1 + seg2 + seg3); - if (isValid(num1) && isValid(num2) && isValid(num3) && isValid(num4)) { + if ( + isValid(num1) && + isValid(num2) && + isValid(num3) && + isValid(num4) + ) { res.push(`${num1}.${num2}.${num3}.${num4}`); } } @@ -272,7 +280,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m ^ n * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m ^ n * n)$ +- Space complexity: $O(m * n)$ -> Where $m$ is equals to $3$ as there are at most three digits in a valid segment and $n$ is equals to $4$ as there are four segments in a valid IP. \ No newline at end of file +> Where $m$ is equals to $3$ as there are at most three digits in a valid segment and $n$ is equals to $4$ as there are four segments in a valid IP. diff --git a/articles/reveal-cards-in-increasing-order.md b/articles/reveal-cards-in-increasing-order.md new file mode 100644 index 000000000..473876c16 --- /dev/null +++ b/articles/reveal-cards-in-increasing-order.md @@ -0,0 +1,407 @@ +## 1. Simulation Using Queue - I + +::tabs-start + +```python +class Solution: + def deckRevealedIncreasing(self, deck: List[int]) -> List[int]: + deck.sort() + res = [0] * len(deck) + q = deque(range(len(deck))) + + for num in deck: + i = q.popleft() + res[i] = num + if q: + q.append(q.popleft()) + + return res +``` + +```java +public class Solution { + public int[] deckRevealedIncreasing(int[] deck) { + Arrays.sort(deck); + int n = deck.length; + int[] res = new int[n]; + Queue q = new LinkedList<>(); + + for (int i = 0; i < n; i++) { + q.offer(i); + } + + for (int num : deck) { + int i = q.poll(); + res[i] = num; + if (!q.isEmpty()) { + q.offer(q.poll()); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector deckRevealedIncreasing(vector& deck) { + sort(deck.begin(), deck.end()); + int n = deck.size(); + vector res(n); + queue q; + + for (int i = 0; i < n; i++) { + q.push(i); + } + + for (int num : deck) { + int i = q.front(); + q.pop(); + res[i] = num; + if (!q.empty()) { + q.push(q.front()); + q.pop(); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} deck + * @return {number[]} + */ + deckRevealedIncreasing(deck) { + deck.sort((a, b) => a - b); + let n = deck.length; + let res = new Array(n).fill(0); + const q = new Queue(); + + for (let i = 0; i < n; i++) { + q.push(i); + } + + for (let num of deck) { + let i = q.pop(); + res[i] = num; + if (!q.isEmpty()) { + q.push(q.pop()); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Simuation Using Queue - II + +::tabs-start + +```python +class Solution: + def deckRevealedIncreasing(self, deck: List[int]) -> List[int]: + deck.sort() + q = deque() + for i in range(len(deck) - 1, -1, -1): + if q: + q.append(q.popleft()) + q.append(deck[i]) + return list(q)[::-1] +``` + +```java +public class Solution { + public int[] deckRevealedIncreasing(int[] deck) { + Arrays.sort(deck); + Queue q = new LinkedList<>(); + + for (int i = deck.length - 1; i >= 0; i--) { + if (!q.isEmpty()) { + q.offer(q.poll()); + } + q.offer(deck[i]); + } + + int[] res = new int[deck.length]; + for (int i = deck.length - 1; i >= 0; i--) { + res[i] = q.poll(); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector deckRevealedIncreasing(vector& deck) { + sort(deck.begin(), deck.end()); + queue q; + + for (int i = deck.size() - 1; i >= 0; i--) { + if (!q.empty()) { + q.push(q.front()); + q.pop(); + } + q.push(deck[i]); + } + + vector res(deck.size()); + for (int i = deck.size() - 1; i >= 0; i--) { + res[i] = q.front(); + q.pop(); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} deck + * @return {number[]} + */ + deckRevealedIncreasing(deck) { + deck.sort((a, b) => a - b); + const q = new Queue(); + + for (let i = deck.length - 1; i >= 0; i--) { + if (!q.isEmpty()) { + q.push(q.pop()); + } + q.push(deck[i]); + } + + return q.toArray().reverse(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Simulation Using Deque + +::tabs-start + +```python +class Solution: + def deckRevealedIncreasing(self, deck: List[int]) -> List[int]: + deck.sort() + dq = deque() + dq.append(deck.pop()) + for i in range(len(deck) - 1, -1, -1): + dq.appendleft(dq.pop()) + dq.appendleft(deck[i]) + return list(dq) +``` + +```java +public class Solution { + public int[] deckRevealedIncreasing(int[] deck) { + int n = deck.length; + Arrays.sort(deck); + Deque dq = new LinkedList<>(); + dq.addLast(deck[n - 1]); + + for (int i = n - 2; i >= 0; i--) { + dq.addFirst(dq.removeLast()); + dq.addFirst(deck[i]); + } + + return dq.stream().mapToInt(Integer::intValue).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector deckRevealedIncreasing(vector& deck) { + sort(deck.begin(), deck.end()); + deque dq; + dq.push_back(deck.back()); + + for (int i = deck.size() - 2; i >= 0; i--) { + dq.push_front(dq.back()); + dq.pop_back(); + dq.push_front(deck[i]); + } + + return vector(dq.begin(), dq.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} deck + * @return {number[]} + */ + deckRevealedIncreasing(deck) { + deck.sort((a, b) => a - b); + const dq = new Deque([deck.pop()]); + + for (let i = deck.length - 1; i >= 0; i--) { + let val = dq.popBack(); + dq.pushFront(val); + dq.pushFront(deck[i]); + } + + let res = []; + while (!dq.isEmpty()) { + res.push(dq.popFront()); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Simulation Using Two Pointers + +::tabs-start + +```python +class Solution: + def deckRevealedIncreasing(self, deck: List[int]) -> List[int]: + n = len(deck) + res = [0] * n + skip = False + deckIndex, i = 0, 0 + + deck.sort() + + while deckIndex < n: + if res[i] == 0: + if not skip: + res[i] = deck[deckIndex] + deckIndex += 1 + skip = not skip + i = (i + 1) % n + + return res +``` + +```java +public class Solution { + public int[] deckRevealedIncreasing(int[] deck) { + int n = deck.length; + int[] res = new int[n]; + Arrays.fill(res, 0); + boolean skip = false; + int deckIndex = 0, i = 0; + + Arrays.sort(deck); + + while (deckIndex < n) { + if (res[i] == 0) { + if (!skip) { + res[i] = deck[deckIndex++]; + } + skip = !skip; + } + i = (i + 1) % n; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector deckRevealedIncreasing(vector& deck) { + int n = deck.size(); + vector res(n, 0); + bool skip = false; + int deckIndex = 0, i = 0; + + sort(deck.begin(), deck.end()); + + while (deckIndex < n) { + if (res[i] == 0) { + if (!skip) { + res[i] = deck[deckIndex++]; + } + skip = !skip; + } + i = (i + 1) % n; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} deck + * @return {number[]} + */ + deckRevealedIncreasing(deck) { + let n = deck.length; + let res = new Array(n).fill(0); + let skip = false; + let deckIndex = 0, + i = 0; + + deck.sort((a, b) => a - b); + + while (deckIndex < n) { + if (res[i] === 0) { + if (!skip) { + res[i] = deck[deckIndex++]; + } + skip = !skip; + } + i = (i + 1) % n; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: + - $O(1)$ or $O(n)$ space depending on the sorting algorithm. + - $O(n)$ space for the output array. diff --git a/articles/reverse-a-linked-list.md b/articles/reverse-a-linked-list.md index 98f5ee98d..128f9269b 100644 --- a/articles/reverse-a-linked-list.md +++ b/articles/reverse-a-linked-list.md @@ -19,7 +19,7 @@ class Solution: newHead = self.reverseList(head.next) head.next.next = head head.next = None - + return newHead ``` @@ -129,7 +129,7 @@ class Solution { * } * } */ - + public class Solution { public ListNode ReverseList(ListNode head) { if (head == null) { @@ -160,14 +160,14 @@ func reverseList(head *ListNode) *ListNode { if head == nil { return nil } - + newHead := head if head.Next != nil { newHead = reverseList(head.Next) head.Next.Next = head } head.Next = nil - + return newHead } ``` @@ -200,12 +200,41 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func reverseList(_ head: ListNode?) -> ListNode? { + if head == nil { + return nil + } + + var newHead = head + if head?.next != nil { + newHead = reverseList(head?.next) + head?.next?.next = head + } + head?.next = nil + + return newHead + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -332,7 +361,7 @@ class Solution { * } * } */ - + public class Solution { public ListNode ReverseList(ListNode head) { ListNode prev = null; @@ -397,9 +426,36 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func reverseList(_ head: ListNode?) -> ListNode? { + var prev: ListNode? = nil + var curr = head + + while curr != nil { + let temp = curr?.next + curr?.next = prev + prev = curr + curr = temp + } + return prev + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/reverse-bits.md b/articles/reverse-bits.md index d5267bf19..d77b73092 100644 --- a/articles/reverse-bits.md +++ b/articles/reverse-bits.md @@ -11,12 +11,12 @@ class Solution: binary += "1" else: binary += "0" - + res = 0 for i, bit in enumerate(binary[::-1]): if bit == "1": res |= (1 << i) - + return res ``` @@ -31,7 +31,7 @@ public class Solution { binary.append("0"); } } - + int res = 0; String reversedBinary = binary.reverse().toString(); for (int i = 0; i < 32; i++) { @@ -39,7 +39,7 @@ public class Solution { res |= (1 << i); } } - + return res; } } @@ -57,14 +57,14 @@ public: binary += '0'; } } - + uint32_t res = 0; for (int i = 0; i < 32; i++) { - if (binary[31 - i] == '1') { + if (binary[31 - i] == '1') { res |= (1 << i); } } - + return res; } }; @@ -77,22 +77,22 @@ class Solution { * @return {number} - a positive integer */ reverseBits(n) { - let binary = ""; + let binary = ''; for (let i = 0; i < 32; i++) { if (n & (1 << i)) { - binary += "1"; + binary += '1'; } else { - binary += "0"; + binary += '0'; } } - + let res = 0; for (let i = 0; i < 32; i++) { - if (binary[31 - i] === "1") { - res |= (1 << i); + if (binary[31 - i] === '1') { + res |= 1 << i; } } - + return res >>> 0; } } @@ -109,14 +109,14 @@ public class Solution { binary += "0"; } } - + uint res = 0; for (int i = 0; i < 32; i++) { - if (binary[31 - i] == '1') { + if (binary[31 - i] == '1') { res |= (1u << i); } } - + return res; } } @@ -162,12 +162,36 @@ class Solution { } ``` +```swift +class Solution { + func reverseBits(_ n: Int) -> Int { + var binary = "" + for i in 0..<32 { + if (n & (1 << i)) != 0 { + binary += "1" + } else { + binary += "0" + } + } + + var res = 0 + for (i, bit) in binary.reversed().enumerated() { + if bit == "1" { + res |= (1 << i) + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ --- @@ -266,12 +290,26 @@ class Solution { } ``` +```swift +class Solution { + func reverseBits(_ n: Int) -> Int { + var res = 0 + var num = n + for i in 0..<32 { + let bit = (num >> i) & 1 + res |= (bit << (31 - i)) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ --- @@ -327,7 +365,7 @@ class Solution { * @return {number} - a positive integer */ reverseBits(n) { - let ret = n >>> 0; + let ret = n >>> 0; ret = (ret >>> 16) | (ret << 16); ret = ((ret & 0xff00ff00) >>> 8) | ((ret & 0x00ff00ff) << 8); ret = ((ret & 0xf0f0f0f0) >>> 4) | ((ret & 0x0f0f0f0f) << 4); @@ -378,9 +416,23 @@ class Solution { } ``` +```swift +class Solution { + func reverseBits(_ n: Int) -> Int { + var res = n + res = (res >> 16) | (res << 16) & 0xFFFFFFFF + res = ((res & 0xff00ff00) >> 8) | ((res & 0x00ff00ff) << 8) + res = ((res & 0xf0f0f0f0) >> 4) | ((res & 0x0f0f0f0f) << 4) + res = ((res & 0xcccccccc) >> 2) | ((res & 0x33333333) << 2) + res = ((res & 0xaaaaaaaa) >> 1) | ((res & 0x55555555) << 1) + return res & 0xFFFFFFFF + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ diff --git a/articles/reverse-integer.md b/articles/reverse-integer.md index f6d060a33..8eb02eb59 100644 --- a/articles/reverse-integer.md +++ b/articles/reverse-integer.md @@ -42,7 +42,7 @@ public: x = abs(x); string strX = to_string(x); std::reverse(strX.begin(), strX.end()); - long long res = stoll(strX); + long long res = stoll(strX); if (org < 0) { res *= -1; } @@ -67,7 +67,7 @@ class Solution { if (org < 0) { res *= -1; } - if (res < -(2 ** 31) || res > (2 ** 31) - 1) { + if (res < -(2 ** 31) || res > 2 ** 31 - 1) { return 0; } return res; @@ -82,16 +82,16 @@ public class Solution { x = Math.Abs(x); char[] arr = x.ToString().ToCharArray(); Array.Reverse(arr); - - long res = long.Parse(new string(arr)); + + long res = long.Parse(new string(arr)); if (org < 0) { - res *= -1; + res *= -1; } - + if (res < int.MinValue || res > int.MaxValue) { - return 0; + return 0; } - return (int)res; + return (int)res; } } ``` @@ -147,12 +147,31 @@ class Solution { } ``` +```swift +class Solution { + func reverse(_ x: Int) -> Int { + let org = x + var x = abs(x) + var res = Int(String(String(x).reversed()))! + + if org < 0 { + res *= -1 + } + if res < Int32.min || res > Int32.max { + return 0 + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ --- @@ -166,17 +185,17 @@ class Solution: def rec(n: int, rev: int) -> int: if n == 0: return rev - + rev = rev * 10 + n % 10 return rec(n // 10, rev) - + sign = -1 if x < 0 else 1 - x = abs(x) + x = abs(x) reversed_num = rec(x, 0) - reversed_num *= sign + reversed_num *= sign if reversed_num < -(1 << 31) or reversed_num > (1 << 31) - 1: return 0 - + return reversed_num ``` @@ -230,7 +249,7 @@ class Solution { */ reverse(x) { let res = this.rec(Math.abs(x), 0) * (x < 0 ? -1 : 1); - if (res < -(2 ** 31) || res > (2 ** 31) - 1) { + if (res < -(2 ** 31) || res > 2 ** 31 - 1) { return 0; } return res; @@ -245,7 +264,7 @@ class Solution { if (n === 0) { return rev; } - rev = rev * 10 + n % 10; + rev = rev * 10 + (n % 10); return this.rec(Math.floor(n / 10), rev); } } @@ -310,12 +329,34 @@ class Solution { } ``` +```swift +class Solution { + func reverse(_ x: Int) -> Int { + func rec(_ n: Int, _ rev: Int) -> Int { + if n == 0 { + return rev + } + return rec(n / 10, rev * 10 + n % 10) + } + + let sign = x < 0 ? -1 : 1 + let reversedNum = rec(abs(x), 0) * sign + + if reversedNum < Int32.min || reversedNum > Int32.max { + return 0 + } + + return reversedNum + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ --- @@ -489,9 +530,36 @@ class Solution { } ``` +```swift +class Solution { + func reverse(_ x: Int) -> Int { + let MIN = Int32.min + let MAX = Int32.max + + var res = 0 + var num = x + + while num != 0 { + let digit = num % 10 + num /= 10 + + if res > MAX / 10 || (res == MAX / 10 && digit > MAX % 10) { + return 0 + } + if res < MIN / 10 || (res == MIN / 10 && digit < MIN % 10) { + return 0 + } + res = res * 10 + digit + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ diff --git a/articles/reverse-linked-list-ii.md b/articles/reverse-linked-list-ii.md index 5a3d69df7..cd0845c1f 100644 --- a/articles/reverse-linked-list-ii.md +++ b/articles/reverse-linked-list-ii.md @@ -38,7 +38,7 @@ class Solution: newHead = self.reverseList(head.next) head.next.next = head head.next = None - + return newHead ``` @@ -194,12 +194,63 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val=0, ListNode next=null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + public ListNode ReverseBetween(ListNode head, int left, int right) { + ListNode dummy = new ListNode(0, head); + ListNode prev = dummy; + + for (int i = 0; i < left - 1; i++) { + prev = prev.next; + } + + ListNode sublistHead = prev.next; + ListNode sublistTail = sublistHead; + for (int i = 0; i < right - left; i++) { + sublistTail = sublistTail.next; + } + + ListNode nextNode = sublistTail.next; + sublistTail.next = null; + + ListNode reversedSublist = ReverseList(sublistHead); + prev.next = reversedSublist; + sublistHead.next = nextNode; + + return dummy.next; + } + + private ListNode ReverseList(ListNode head) { + if (head == null) return null; + + ListNode newHead = head; + if (head.next != null) { + newHead = ReverseList(head.next); + head.next.next = head; + } + head.next = null; + return newHead; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -226,7 +277,7 @@ class Solution: if left == 1: new_head, _ = reverseList(head, right) return new_head - + head.next = self.reverseBetween(head.next, left - 1, right - 1) return head ``` @@ -334,12 +385,48 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val=0, ListNode next=null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + private ListNode successor = null; + + private ListNode ReverseList(ListNode node, int n) { + if (n == 1) { + successor = node.next; + return node; + } + ListNode newHead = ReverseList(node.next, n - 1); + node.next.next = node; + node.next = successor; + return newHead; + } + + public ListNode ReverseBetween(ListNode head, int left, int right) { + if (left == 1) { + return ReverseList(head, right); + } + head.next = ReverseBetween(head.next, left - 1, right - 1); + return head; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -517,7 +604,7 @@ class Solution { } return prev; }; - + const dummy = new ListNode(0, head); let prev = dummy; for (let i = 0; i < left - 1; i++) { @@ -540,12 +627,64 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val=0, ListNode next=null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + public ListNode ReverseBetween(ListNode head, int left, int right) { + ListNode dummy = new ListNode(0); + dummy.next = head; + ListNode prev = dummy; + + for (int i = 0; i < left - 1; i++) { + prev = prev.next; + } + + ListNode sublistHead = prev.next; + ListNode sublistTail = sublistHead; + for (int i = 0; i < right - left; i++) { + sublistTail = sublistTail.next; + } + + ListNode nextNode = sublistTail.next; + sublistTail.next = null; + + ListNode reversedSublist = ReverseList(sublistHead); + prev.next = reversedSublist; + + sublistHead.next = nextNode; + return dummy.next; + } + + private ListNode ReverseList(ListNode head) { + ListNode prev = null; + ListNode curr = head; + while (curr != null) { + ListNode temp = curr.next; + curr.next = prev; + prev = curr; + curr = temp; + } + return prev; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -676,7 +815,8 @@ class Solution { */ reverseBetween(head, left, right) { const dummy = new ListNode(0, head); - let leftPrev = dummy, cur = head; + let leftPrev = dummy, + cur = head; for (let i = 0; i < left - 1; i++) { leftPrev = cur; @@ -699,9 +839,47 @@ class Solution { } ``` +```csharp +/** + * Definition for singly-linked list. + * public class ListNode { + * public int val; + * public ListNode next; + * public ListNode(int val=0, ListNode next=null) { + * this.val = val; + * this.next = next; + * } + * } + */ +public class Solution { + public ListNode ReverseBetween(ListNode head, int left, int right) { + ListNode dummy = new ListNode(0, head); + ListNode leftPrev = dummy, curr = head; + + for (int i = 0; i < left - 1; i++) { + leftPrev = curr; + curr = curr.next; + } + + ListNode prev = null; + for (int i = 0; i < right - left + 1; i++) { + ListNode tmpNext = curr.next; + curr.next = prev; + prev = curr; + curr = tmpNext; + } + + leftPrev.next.next = curr; + leftPrev.next = prev; + + return dummy.next; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/reverse-nodes-in-k-group.md b/articles/reverse-nodes-in-k-group.md index ad54de13e..8a073e130 100644 --- a/articles/reverse-nodes-in-k-group.md +++ b/articles/reverse-nodes-in-k-group.md @@ -45,18 +45,18 @@ public class Solution { public ListNode reverseKGroup(ListNode head, int k) { ListNode cur = head; int group = 0; - while (cur != null && group < k) { + while (cur != null && group < k) { cur = cur.next; group++; } - if (group == k) { - cur = reverseKGroup(cur, k); - while (group-- > 0) { - ListNode tmp = head.next; - head.next = cur; - cur = head; - head = tmp; + if (group == k) { + cur = reverseKGroup(cur, k); + while (group-- > 0) { + ListNode tmp = head.next; + head.next = cur; + cur = head; + head = tmp; } head = cur; } @@ -243,10 +243,51 @@ class Solution { tempHead = tmp group-- } - cur + cur } else { - head + head + } + } +} +``` + +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func reverseKGroup(_ head: ListNode?, _ k: Int) -> ListNode? { + var cur = head + var group = 0 + + while cur != nil && group < k { + cur = cur!.next + group += 1 + } + + if group == k { + cur = reverseKGroup(cur, k) + + var tempHead = head + while group > 0 { + let tmp = tempHead!.next + tempHead!.next = cur + cur = tempHead + tempHead = tmp + group -= 1 + } + + return cur } + + return head } } ``` @@ -255,8 +296,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(\frac{n}{k})$ +- Time complexity: $O(n)$ +- Space complexity: $O(\frac{n}{k})$ --- @@ -314,7 +355,7 @@ class Solution: */ class Solution { - + public ListNode reverseKGroup(ListNode head, int k) { ListNode dummy = new ListNode(0, head); ListNode groupPrev = dummy; @@ -603,9 +644,60 @@ class Solution { } ``` +```swift +/** + * Definition for singly-linked list. + * public class ListNode { + * public var val: Int + * public var next: ListNode? + * public init() { self.val = 0; self.next = nil; } + * public init(_ val: Int) { self.val = val; self.next = nil; } + * public init(_ val: Int, _ next: ListNode?) { self.val = val; self.next = next; } + * } + */ +class Solution { + func reverseKGroup(_ head: ListNode?, _ k: Int) -> ListNode? { + let dummy = ListNode(0, head) + var groupPrev: ListNode? = dummy + + while true { + guard let kth = getKth(groupPrev, k) else { + break + } + let groupNext = kth.next + + var prev: ListNode? = kth.next + var curr = groupPrev?.next + + while curr !== groupNext { + let tmp = curr?.next + curr?.next = prev + prev = curr + curr = tmp + } + + let tmp = groupPrev?.next + groupPrev?.next = kth + groupPrev = tmp + } + return dummy.next + } + + private func getKth(_ curr: ListNode?, _ k: Int) -> ListNode? { + var curr = curr + var k = k + while curr != nil && k > 0 { + curr = curr?.next + k -= 1 + } + return curr + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/reverse-string.md b/articles/reverse-string.md index ac60401c5..acebe2477 100644 --- a/articles/reverse-string.md +++ b/articles/reverse-string.md @@ -62,12 +62,29 @@ class Solution { } ``` +```csharp +public class Solution { + public void ReverseString(char[] s) { + char[] tmp = new char[s.Length]; + int n = s.Length; + + for (int i = 0; i < n; i++) { + tmp[i] = s[n - 1 - i]; + } + + for (int i = 0; i < n; i++) { + s[i] = tmp[i]; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -85,7 +102,7 @@ class Solution: if l < r: reverse(l + 1, r - 1) s[l], s[r] = s[r], s[l] - + reverse(0, len(s) - 1) ``` @@ -94,7 +111,7 @@ public class Solution { public void reverseString(char[] s) { reverse(s, 0, s.length - 1); } - + private void reverse(char[] s, int l, int r) { if (l < r) { reverse(s, l + 1, r - 1); @@ -112,7 +129,7 @@ public: void reverseString(vector& s) { reverse(s, 0, s.size() - 1); } - + private: void reverse(vector& s, int l, int r) { if (l < r) { @@ -141,12 +158,29 @@ class Solution { } ``` +```csharp +public class Solution { + public void ReverseString(char[] s) { + Reverse(s, 0, s.Length - 1); + } + + private void Reverse(char[] s, int left, int right) { + if (left < right) { + Reverse(s, left + 1, right - 1); + char temp = s[left]; + s[left] = s[right]; + s[right] = temp; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -220,12 +254,28 @@ class Solution { } ``` +```csharp +public class Solution { + public void ReverseString(char[] s) { + Stack stack = new Stack(); + + foreach (char c in s) { + stack.Push(c); + } + + for (int i = 0; i < s.Length; i++) { + s[i] = stack.Pop(); + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -250,7 +300,7 @@ public class Solution { list.add(c); } Collections.reverse(list); - + for (int i = 0; i < s.length; i++) { s[i] = list.get(i); } @@ -279,12 +329,20 @@ class Solution { } ``` +```csharp +public class Solution { + public void ReverseString(char[] s) { + Array.Reverse(s); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -339,7 +397,8 @@ class Solution { * @return {void} Do not return anything, modify s in-place instead. */ reverseString(s) { - let l = 0, r = s.length - 1; + let l = 0, + r = s.length - 1; while (l < r) { [s[l], s[r]] = [s[r], s[l]]; l++; @@ -349,9 +408,24 @@ class Solution { } ``` +```csharp +public class Solution { + public void ReverseString(char[] s) { + int l = 0, r = s.Length - 1; + while (l < r) { + char temp = s[l]; + s[l] = s[r]; + s[r] = temp; + l++; + r--; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/reverse-words-in-a-string-iii.md b/articles/reverse-words-in-a-string-iii.md index b9fb3b3cb..96514518a 100644 --- a/articles/reverse-words-in-a-string-iii.md +++ b/articles/reverse-words-in-a-string-iii.md @@ -27,7 +27,7 @@ public: stringstream ss(s); string word, res; bool first = true; - + while (ss >> word) { reverse(word.begin(), word.end()); if (first) { @@ -37,7 +37,7 @@ public: res += " " + word; } } - + return res; } }; @@ -50,7 +50,10 @@ class Solution { * @return {string} */ reverseWords(s) { - return s.split(' ').map(w => w.split('').reverse().join('')).join(' '); + return s + .split(' ') + .map((w) => w.split('').reverse().join('')) + .join(' '); } } ``` @@ -59,8 +62,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -137,15 +140,15 @@ class Solution { * @return {string} */ reverseWords(s) { - let tmpStr = ""; - let res = ""; + let tmpStr = ''; + let res = ''; for (let r = 0; r <= s.length; r++) { if (r === s.length || s[r] === ' ') { res += tmpStr; - tmpStr = ""; + tmpStr = ''; if (r !== s.length) { - res += " "; + res += ' '; } } else { tmpStr = s[r] + tmpStr; @@ -160,8 +163,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -240,7 +243,8 @@ class Solution { let l = 0; for (let r = 0; r <= chars.length; r++) { if (r === chars.length || chars[r] === ' ') { - let tempL = l, tempR = r - 1; + let tempL = l, + tempR = r - 1; while (tempL < tempR) { [chars[tempL], chars[tempR]] = [chars[tempR], chars[tempL]]; tempL++; @@ -258,8 +262,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -285,7 +289,7 @@ class Solution: j += 1 reverse(i, j - 1) i = j + 1 - return ''.join(s) + return ''.join(s) ``` ```java @@ -383,5 +387,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/robot-bounded-in-circle.md b/articles/robot-bounded-in-circle.md new file mode 100644 index 000000000..464883cc9 --- /dev/null +++ b/articles/robot-bounded-in-circle.md @@ -0,0 +1,109 @@ +## 1. Simulation + +::tabs-start + +```python +class Solution: + def isRobotBounded(self, instructions: str) -> bool: + dirX, dirY = 0, 1 + x, y = 0, 0 + + for d in instructions: + if d == "G": + x, y = x + dirX, y + dirY + elif d == "L": + dirX, dirY = -dirY, dirX + else: + dirX, dirY = dirY, -dirX + + return (x, y) == (0, 0) or (dirX, dirY) != (0, 1) +``` + +```java +public class Solution { + public boolean isRobotBounded(String instructions) { + int dirX = 0, dirY = 1; + int x = 0, y = 0; + + for (int i = 0; i < instructions.length(); i++) { + char d = instructions.charAt(i); + if (d == 'G') { + x += dirX; + y += dirY; + } else if (d == 'L') { + int temp = dirX; + dirX = -dirY; + dirY = temp; + } else { + int temp = dirX; + dirX = dirY; + dirY = -temp; + } + } + + return (x == 0 && y == 0) || (dirX != 0 || dirY != 1); + } +} +``` + +```cpp +class Solution { +public: + bool isRobotBounded(string instructions) { + int dirX = 0, dirY = 1; + int x = 0, y = 0; + + for (char d : instructions) { + if (d == 'G') { + x += dirX; + y += dirY; + } else if (d == 'L') { + int temp = dirX; + dirX = -dirY; + dirY = temp; + } else { + int temp = dirX; + dirX = dirY; + dirY = -temp; + } + } + + return (x == 0 && y == 0) || (dirX != 0 || dirY != 1); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} instructions + * @return {boolean} + */ + isRobotBounded(instructions) { + let dirX = 0, + dirY = 1; + let x = 0, + y = 0; + + for (const d of instructions) { + if (d === 'G') { + x += dirX; + y += dirY; + } else if (d === 'L') { + [dirX, dirY] = [-dirY, dirX]; + } else { + [dirX, dirY] = [dirY, -dirX]; + } + } + + return (x === 0 && y === 0) || dirX !== 0 || dirY !== 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/roman-to-integer.md b/articles/roman-to-integer.md index b21b20e18..6cd1e98df 100644 --- a/articles/roman-to-integer.md +++ b/articles/roman-to-integer.md @@ -70,8 +70,13 @@ class Solution { */ romanToInt(s) { const roman = { - "I": 1, "V": 5, "X": 10, - "L": 50, "C": 100, "D": 500, "M": 1000 + I: 1, + V: 5, + X: 10, + L: 50, + C: 100, + D: 500, + M: 1000, }; let res = 0; @@ -87,9 +92,30 @@ class Solution { } ``` +```csharp +public class Solution { + public int RomanToInt(string s) { + Dictionary roman = new Dictionary { + {'I', 1}, {'V', 5}, {'X', 10}, + {'L', 50}, {'C', 100}, {'D', 500}, {'M', 1000} + }; + + int res = 0; + for (int i = 0; i < s.Length; i++) { + if (i + 1 < s.Length && roman[s[i]] < roman[s[i + 1]]) { + res -= roman[s[i]]; + } else { + res += roman[s[i]]; + } + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ since we have $7$ characters in the hash map. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ since we have $7$ characters in the hash map. diff --git a/articles/rotate-array.md b/articles/rotate-array.md index 72dfcb037..1a6d2365c 100644 --- a/articles/rotate-array.md +++ b/articles/rotate-array.md @@ -75,12 +75,30 @@ class Solution { } ``` +```csharp +public class Solution { + public void Rotate(int[] nums, int k) { + int n = nums.Length; + k %= n; + + while (k > 0) { + int tmp = nums[n - 1]; + for (int i = n - 1; i > 0; i--) { + nums[i] = nums[i - 1]; + } + nums[0] = tmp; + k--; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * k)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n * k)$ +- Space complexity: $O(1)$ extra space. --- @@ -98,7 +116,7 @@ class Solution: tmp = [0] * n for i in range(n): tmp[(i + k) % n] = nums[i] - + nums[:] = tmp ``` @@ -153,12 +171,29 @@ class Solution { } ``` +```csharp +public class Solution { + public void Rotate(int[] nums, int k) { + int n = nums.Length; + int[] tmp = new int[n]; + + for (int i = 0; i < n; i++) { + tmp[(i + k) % n] = nums[i]; + } + + for (int i = 0; i < n; i++) { + nums[i] = tmp[i]; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ extra space. --- @@ -174,7 +209,7 @@ class Solution: """ n = len(nums) k %= n - count = start = 0 + count = start = 0 while count < n: current = start @@ -196,7 +231,7 @@ public class Solution { int n = nums.length; k %= n; int count = 0; - + for (int start = 0; count < n; start++) { int current = start; int prev = nums[start]; @@ -220,7 +255,7 @@ public: int n = nums.size(); k %= n; int count = 0; - + for (int start = 0; count < n; start++) { int current = start; int prev = nums[start]; @@ -248,7 +283,7 @@ class Solution { const n = nums.length; k %= n; let count = 0; - + for (let start = 0; count < n; start++) { let current = start; let prev = nums[start]; @@ -265,12 +300,36 @@ class Solution { } ``` +```csharp +public class Solution { + public void Rotate(int[] nums, int k) { + int n = nums.Length; + k %= n; + int count = 0; + + for (int start = 0; count < n; start++) { + int current = start; + int prev = nums[start]; + + do { + int nextIdx = (current + k) % n; + int temp = nums[nextIdx]; + nums[nextIdx] = prev; + prev = temp; + current = nextIdx; + count++; + } while (start != current); + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -369,12 +428,35 @@ class Solution { } ``` +```csharp +public class Solution { + public void Rotate(int[] nums, int k) { + int n = nums.Length; + k %= n; + + Reverse(nums, 0, n - 1); + Reverse(nums, 0, k - 1); + Reverse(nums, k, n - 1); + } + + private void Reverse(int[] nums, int left, int right) { + while (left < right) { + int temp = nums[left]; + nums[left] = nums[right]; + nums[right] = temp; + left++; + right--; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -425,9 +507,23 @@ class Solution { } ``` +```csharp +public class Solution { + public void Rotate(int[] nums, int k) { + int n = nums.Length; + k %= n; + + int[] rotated = new int[n]; + Array.Copy(nums, n - k, rotated, 0, k); + Array.Copy(nums, 0, rotated, k, n - k); + Array.Copy(rotated, nums, n); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the language. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the language. diff --git a/articles/rotate-list.md b/articles/rotate-list.md new file mode 100644 index 000000000..a954129f6 --- /dev/null +++ b/articles/rotate-list.md @@ -0,0 +1,488 @@ +## 1. Convert To Array + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def rotateRight(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: + if not head: + return None + + arr, cur = [], head + while cur: + arr.append(cur.val) + cur = cur.next + + n = len(arr) + k %= n + cur = head + for i in range(n - k, n): + cur.val = arr[i] + cur = cur.next + + for i in range(n - k): + cur.val = arr[i] + cur = cur.next + + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode rotateRight(ListNode head, int k) { + if (head == null) return null; + + ArrayList arr = new ArrayList<>(); + ListNode cur = head; + while (cur != null) { + arr.add(cur.val); + cur = cur.next; + } + + int n = arr.size(); + k %= n; + cur = head; + for (int i = n - k; i < n; i++) { + cur.val = arr.get(i); + cur = cur.next; + } + for (int i = 0; i < n - k; i++) { + cur.val = arr.get(i); + cur = cur.next; + } + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* rotateRight(ListNode* head, int k) { + if (!head) return nullptr; + + vector arr; + ListNode* cur = head; + while (cur) { + arr.push_back(cur->val); + cur = cur->next; + } + + int n = arr.size(); + k %= n; + cur = head; + for (int i = n - k; i < n; i++) { + cur->val = arr[i]; + cur = cur->next; + } + for (int i = 0; i < n - k; i++) { + cur->val = arr[i]; + cur = cur->next; + } + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + rotateRight(head, k) { + if (!head) return null; + + let arr = []; + let cur = head; + while (cur) { + arr.push(cur.val); + cur = cur.next; + } + + let n = arr.length; + k %= n; + cur = head; + for (let i = n - k; i < n; i++) { + cur.val = arr[i]; + cur = cur.next; + } + for (let i = 0; i < n - k; i++) { + cur.val = arr[i]; + cur = cur.next; + } + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Iteration + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def rotateRight(self, head: ListNode, k: int) -> ListNode: + if not head: + return head + + length, tail = 1, head + while tail.next: + tail = tail.next + length += 1 + + k = k % length + if k == 0: + return head + + cur = head + for i in range(length - k - 1): + cur = cur.next + newHead = cur.next + cur.next = None + tail.next = head + + return newHead +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode rotateRight(ListNode head, int k) { + if (head == null) { + return head; + } + + int length = 1; + ListNode tail = head; + while (tail.next != null) { + tail = tail.next; + length++; + } + + k = k % length; + if (k == 0) { + return head; + } + + ListNode cur = head; + for (int i = 0; i < length - k - 1; i++) { + cur = cur.next; + } + ListNode newHead = cur.next; + cur.next = null; + tail.next = head; + + return newHead; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* rotateRight(ListNode* head, int k) { + if (!head) { + return head; + } + + int length = 1; + ListNode* tail = head; + while (tail->next) { + tail = tail->next; + length++; + } + + k = k % length; + if (k == 0) { + return head; + } + + ListNode* cur = head; + for (int i = 0; i < length - k - 1; i++) { + cur = cur->next; + } + ListNode* newHead = cur->next; + cur->next = nullptr; + tail->next = head; + + return newHead; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + rotateRight(head, k) { + if (!head) { + return head; + } + + let length = 1, + tail = head; + while (tail.next) { + tail = tail.next; + length++; + } + + k = k % length; + if (k === 0) { + return head; + } + + let cur = head; + for (let i = 0; i < length - k - 1; i++) { + cur = cur.next; + } + let newHead = cur.next; + cur.next = null; + tail.next = head; + + return newHead; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 3. Iteration (Using One Pointer) + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def rotateRight(self, head: ListNode, k: int) -> ListNode: + if not head: + return head + + cur, n = head, 1 + while cur.next: + n += 1 + cur = cur.next + + cur.next = head + k %= n + for i in range(n - k): + cur = cur.next + + head = cur.next + cur.next = None + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode rotateRight(ListNode head, int k) { + if (head == null) { + return head; + } + + ListNode cur = head; + int n = 1; + while (cur.next != null) { + n++; + cur = cur.next; + } + + cur.next = head; + k %= n; + for (int i = 0; i < n - k; i++) { + cur = cur.next; + } + + head = cur.next; + cur.next = null; + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* rotateRight(ListNode* head, int k) { + if (!head) { + return head; + } + + ListNode* cur = head; + int n = 1; + while (cur->next) { + n++; + cur = cur->next; + } + + cur->next = head; + k %= n; + for (int i = 0; i < n - k; i++) { + cur = cur->next; + } + + head = cur->next; + cur->next = nullptr; + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + rotateRight(head, k) { + if (!head) { + return head; + } + + let cur = head, + n = 1; + while (cur.next) { + n++; + cur = cur.next; + } + + cur.next = head; + k %= n; + for (let i = 0; i < n - k; i++) { + cur = cur.next; + } + + head = cur.next; + cur.next = null; + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/rotate-matrix.md b/articles/rotate-matrix.md index 2f050d984..493bc1d54 100644 --- a/articles/rotate-matrix.md +++ b/articles/rotate-matrix.md @@ -7,11 +7,11 @@ class Solution: def rotate(self, matrix: List[List[int]]) -> None: n = len(matrix) rotated = [[0] * n for _ in range(n)] - + for i in range(n): for j in range(n): rotated[j][n - 1 - i] = matrix[i][j] - + for i in range(n): for j in range(n): matrix[i][j] = rotated[i][j] @@ -64,8 +64,7 @@ class Solution { */ rotate(matrix) { const n = matrix.length; - const rotated = Array.from({ length: n }, () => - Array(n).fill(0)); + const rotated = Array.from({ length: n }, () => Array(n).fill(0)); for (let i = 0; i < n; i++) { for (let j = 0; j < n; j++) { @@ -86,16 +85,16 @@ class Solution { public class Solution { public void Rotate(int[][] matrix) { int n = matrix.Length; - int[][] rotated = new int[n][]; + int[][] rotated = new int[n][]; for (int i = 0; i < n; i++) { - rotated[i] = new int[n]; + rotated[i] = new int[n]; for (int j = 0; j < n; j++) { - rotated[i][j] = matrix[n - 1 - j][i]; + rotated[i][j] = matrix[n - 1 - j][i]; } } for (int i = 0; i < n; i++) { for (int j = 0; j < n; j++) { - matrix[i][j] = rotated[i][j]; + matrix[i][j] = rotated[i][j]; } } } @@ -145,12 +144,33 @@ class Solution { } ``` +```swift +class Solution { + func rotate(_ matrix: inout [[Int]]) { + let n = matrix.count + var rotated = Array(repeating: Array(repeating: 0, count: n), count: n) + + for i in 0..>& matrix) { int l = 0; int r = matrix.size() - 1; - + while ( l < r ) { for(int i = 0; i < r - l; i++) { int top = l; @@ -243,7 +263,7 @@ public: // move top left into top right matrix[top + i][r] = topLeft; - + } r--; l++; @@ -293,32 +313,32 @@ class Solution { public class Solution { public void Rotate(int[][] matrix) { (int left, int right) = (0, matrix.Length -1); - + while(left < right) { var limit = right - left; for(var i = 0; i < limit; i++) { (int top, int bottom) = (left, right); - + // save the top left position var topLeft = matrix[top][left + i]; - + // put the bottom left value to the top left position matrix[top][left + i] = matrix[bottom - i][left]; - + // put the bottom right value to the bottom left position matrix[bottom - i][left] = matrix[bottom][right - i]; - + // put the top right value to the bottom right position - matrix[bottom][right - i] = matrix[top + i][right]; + matrix[bottom][right - i] = matrix[top + i][right]; // put the saved top left value to the top right position - matrix[top + i][right] = topLeft; + matrix[top + i][right] = topLeft; } left++; right--; } - + return; } } @@ -384,12 +404,44 @@ class Solution { } ``` +```swift +class Solution { + func rotate(_ matrix: inout [[Int]]) { + var l = 0 + var r = matrix.count - 1 + while l < r { + for i in 0.. List[List[str]]: + ROWS, COLS = len(boxGrid), len(boxGrid[0]) + + for r in range(ROWS - 1, -1, -1): + for c1 in range(COLS - 1, -1, -1): + if boxGrid[r][c1] == '#': + c2 = c1 + 1 + while c2 < COLS and boxGrid[r][c2] == '.': + c2 += 1 + + boxGrid[r][c1] = '.' + boxGrid[r][c2 - 1] = '#' + + + res = [] + for c in range(COLS): + col = [] + for r in range(ROWS - 1, -1, -1): + col.append(boxGrid[r][c]) + res.append(col) + return res +``` + +```java +public class Solution { + public char[][] rotateTheBox(char[][] boxGrid) { + int ROWS = boxGrid.length, COLS = boxGrid[0].length; + + for (int r = ROWS - 1; r >= 0; r--) { + for (int c1 = COLS - 1; c1 >= 0; c1--) { + if (boxGrid[r][c1] == '#') { + int c2 = c1 + 1; + while (c2 < COLS && boxGrid[r][c2] == '.') { + c2++; + } + boxGrid[r][c1] = '.'; + boxGrid[r][c2 - 1] = '#'; + } + } + } + + char[][] res = new char[COLS][ROWS]; + for (int c = 0; c < COLS; c++) { + for (int r = ROWS - 1; r >= 0; r--) { + res[c][ROWS - 1 - r] = boxGrid[r][c]; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> rotateTheBox(vector>& boxGrid) { + int ROWS = boxGrid.size(), COLS = boxGrid[0].size(); + + for (int r = ROWS - 1; r >= 0; r--) { + for (int c1 = COLS - 1; c1 >= 0; c1--) { + if (boxGrid[r][c1] == '#') { + int c2 = c1 + 1; + while (c2 < COLS && boxGrid[r][c2] == '.') { + c2++; + } + boxGrid[r][c1] = '.'; + boxGrid[r][c2 - 1] = '#'; + } + } + } + + vector> res(COLS, vector(ROWS)); + for (int c = 0; c < COLS; c++) { + for (int r = ROWS - 1; r >= 0; r--) { + res[c][ROWS - 1 - r] = boxGrid[r][c]; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {character[][]} boxGrid + * @return {character[][]} + */ + rotateTheBox(boxGrid) { + const ROWS = boxGrid.length, + COLS = boxGrid[0].length; + const res = Array.from({ length: COLS }, () => Array(ROWS).fill('.')); + for (let r = 0; r < ROWS; r++) { + let i = COLS - 1; + for (let c = COLS - 1; c >= 0; c--) { + if (boxGrid[r][c] === '#') { + res[i][ROWS - r - 1] = '#'; + i--; + } else if (boxGrid[r][c] === '*') { + res[c][ROWS - r - 1] = '*'; + i = c - 1; + } + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public char[][] RotateTheBox(char[][] boxGrid) { + int ROWS = boxGrid.Length, COLS = boxGrid[0].Length; + + for (int r = ROWS - 1; r >= 0; r--) { + for (int c1 = COLS - 1; c1 >= 0; c1--) { + if (boxGrid[r][c1] == '#') { + int c2 = c1 + 1; + while (c2 < COLS && boxGrid[r][c2] == '.') { + c2++; + } + boxGrid[r][c1] = '.'; + boxGrid[r][c2 - 1] = '#'; + } + } + } + + char[][] res = new char[COLS][]; + for (int c = 0; c < COLS; c++) { + res[c] = new char[ROWS]; + for (int r = ROWS - 1; r >= 0; r--) { + res[c][ROWS - 1 - r] = boxGrid[r][c]; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n ^ 2)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 2. Two Pointers - I + +::tabs-start + +```python +class Solution: + def rotateTheBox(self, boxGrid: List[List[str]]) -> List[List[str]]: + ROWS, COLS = len(boxGrid), len(boxGrid[0]) + + for r in range(ROWS): + i = COLS - 1 + for c in reversed(range(COLS)): + if boxGrid[r][c] == "#": + boxGrid[r][c], boxGrid[r][i] = boxGrid[r][i], boxGrid[r][c] + i -= 1 + elif boxGrid[r][c] == "*": + i = c - 1 + + res = [] + for c in range(COLS): + col = [] # this is a row after rotation + for r in reversed(range(ROWS)): + col.append(boxGrid[r][c]) + res.append(col) + + return res +``` + +```java +public class Solution { + public char[][] rotateTheBox(char[][] boxGrid) { + int ROWS = boxGrid.length, COLS = boxGrid[0].length; + for (int r = 0; r < ROWS; r++) { + int i = COLS - 1; + for (int c = COLS - 1; c >= 0; c--) { + if (boxGrid[r][c] == '#') { + char tmp = boxGrid[r][c]; + boxGrid[r][c] = boxGrid[r][i]; + boxGrid[r][i] = tmp; + i--; + } else if (boxGrid[r][c] == '*') { + i = c - 1; + } + } + } + char[][] res = new char[COLS][ROWS]; + for (int c = 0; c < COLS; c++) { + for (int r = ROWS - 1; r >= 0; r--) { + res[c][ROWS - 1 - r] = boxGrid[r][c]; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> rotateTheBox(vector>& boxGrid) { + int ROWS = boxGrid.size(), COLS = boxGrid[0].size(); + for (int r = 0; r < ROWS; ++r) { + int i = COLS - 1; + for (int c = COLS - 1; c >= 0; --c) { + if (boxGrid[r][c] == '#') { + swap(boxGrid[r][c], boxGrid[r][i]); + i--; + } else if (boxGrid[r][c] == '*') { + i = c - 1; + } + } + } + vector> res(COLS, vector(ROWS)); + for (int c = 0; c < COLS; ++c) { + for (int r = ROWS - 1; r >= 0; --r) { + res[c][ROWS - 1 - r] = boxGrid[r][c]; + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {character[][]} boxGrid + * @return {character[][]} + */ + rotateTheBox(boxGrid) { + const ROWS = boxGrid.length, + COLS = boxGrid[0].length; + for (let r = 0; r < ROWS; r++) { + let i = COLS - 1; + for (let c = COLS - 1; c >= 0; c--) { + if (boxGrid[r][c] === '#') { + [boxGrid[r][c], boxGrid[r][i]] = [ + boxGrid[r][i], + boxGrid[r][c], + ]; + i--; + } else if (boxGrid[r][c] === '*') { + i = c - 1; + } + } + } + const res = []; + for (let c = 0; c < COLS; c++) { + const row = []; + for (let r = ROWS - 1; r >= 0; r--) { + row.push(boxGrid[r][c]); + } + res.push(row); + } + return res; + } +} +``` + +```csharp +public class Solution { + public char[][] RotateTheBox(char[][] boxGrid) { + int ROWS = boxGrid.Length, COLS = boxGrid[0].Length; + for (int r = 0; r < ROWS; r++) { + int i = COLS - 1; + for (int c = COLS - 1; c >= 0; c--) { + if (boxGrid[r][c] == '#') { + char tmp = boxGrid[r][c]; + boxGrid[r][c] = boxGrid[r][i]; + boxGrid[r][i] = tmp; + i--; + } else if (boxGrid[r][c] == '*') { + i = c - 1; + } + } + } + char[][] res = new char[COLS][]; + for (int c = 0; c < COLS; c++) { + res[c] = new char[ROWS]; + for (int r = ROWS - 1; r >= 0; r--) { + res[c][ROWS - 1 - r] = boxGrid[r][c]; + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 3. Two Pointers - II + +::tabs-start + +```python +class Solution: + def rotateTheBox(self, boxGrid: List[List[str]]) -> List[List[str]]: + ROWS, COLS = len(boxGrid), len(boxGrid[0]) + + res = [["."] * ROWS for _ in range(COLS)] + + for r in range(ROWS): + i = COLS - 1 + for c in reversed(range(COLS)): + if boxGrid[r][c] == "#": + res[i][ROWS - r - 1] = "#" + i -= 1 + elif boxGrid[r][c] == "*": + res[c][ROWS - r - 1] = "*" + i = c - 1 + + return res +``` + +```java +public class Solution { + public char[][] rotateTheBox(char[][] boxGrid) { + int ROWS = boxGrid.length, COLS = boxGrid[0].length; + char[][] res = new char[COLS][ROWS]; + for (int c = 0; c < COLS; c++) { + for (int r = 0; r < ROWS; r++) { + res[c][r] = '.'; + } + } + + for (int r = 0; r < ROWS; r++) { + int i = COLS - 1; + for (int c = COLS - 1; c >= 0; c--) { + if (boxGrid[r][c] == '#') { + res[i][ROWS - r - 1] = '#'; + i--; + } else if (boxGrid[r][c] == '*') { + res[c][ROWS - r - 1] = '*'; + i = c - 1; + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> rotateTheBox(vector>& boxGrid) { + int ROWS = boxGrid.size(), COLS = boxGrid[0].size(); + vector> res(COLS, vector(ROWS, '.')); + for (int r = 0; r < ROWS; ++r) { + int i = COLS - 1; + for (int c = COLS - 1; c >= 0; --c) { + if (boxGrid[r][c] == '#') { + res[i][ROWS - r - 1] = '#'; + --i; + } else if (boxGrid[r][c] == '*') { + res[c][ROWS - r - 1] = '*'; + i = c - 1; + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {character[][]} boxGrid + * @return {character[][]} + */ + rotateTheBox(boxGrid) { + const ROWS = boxGrid.length, + COLS = boxGrid[0].length; + const res = Array.from({ length: COLS }, () => Array(ROWS).fill('.')); + for (let r = 0; r < ROWS; r++) { + let i = COLS - 1; + for (let c = COLS - 1; c >= 0; c--) { + if (boxGrid[r][c] === '#') { + res[i][ROWS - r - 1] = '#'; + i--; + } else if (boxGrid[r][c] === '*') { + res[c][ROWS - r - 1] = '*'; + i = c - 1; + } + } + } + return res; + } +} +``` + +```csharp +public class Solution { + public char[][] RotateTheBox(char[][] boxGrid) { + int ROWS = boxGrid.Length, COLS = boxGrid[0].Length; + var res = new char[COLS][]; + for (int c = 0; c < COLS; c++) { + res[c] = new char[ROWS]; + for (int r = 0; r < ROWS; r++) { + res[c][r] = '.'; + } + } + + for (int r = 0; r < ROWS; r++) { + int i = COLS - 1; + for (int c = COLS - 1; c >= 0; c--) { + if (boxGrid[r][c] == '#') { + res[i][ROWS - r - 1] = '#'; + i--; + } else if (boxGrid[r][c] == '*') { + res[c][ROWS - r - 1] = '*'; + i = c - 1; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows and $n$ is the number of columns. diff --git a/articles/rotting-fruit.md b/articles/rotting-fruit.md index 33f3162a0..656ce8d15 100644 --- a/articles/rotting-fruit.md +++ b/articles/rotting-fruit.md @@ -64,7 +64,7 @@ public class Solution { for (int[] dir : directions) { int row = r + dir[0]; int col = c + dir[1]; - if (row >= 0 && row < grid.length && + if (row >= 0 && row < grid.length && col >= 0 && col < grid[0].length && grid[row][col] == 1) { grid[row][col] = 2; @@ -111,7 +111,7 @@ public: for (const auto& dir : directions) { int row = r + dir.first; int col = c + dir.second; - if (row >= 0 && row < grid.size() && + if (row >= 0 && row < grid.size() && col >= 0 && col < grid[0].size() && grid[row][col] == 1) { grid[row][col] = 2; @@ -163,9 +163,13 @@ class Solution { for (const [dr, dc] of directions) { const row = currR + dr; const col = currC + dc; - if (row >= 0 && row < grid.length && - col >= 0 && col < grid[0].length && - grid[row][col] === 1) { + if ( + row >= 0 && + row < grid.length && + col >= 0 && + col < grid[0].length && + grid[row][col] === 1 + ) { grid[row][col] = 2; q.push([row, col]); fresh--; @@ -208,7 +212,7 @@ public class Solution { foreach (int[] dir in directions) { int row = r + dir[0]; int col = c + dir[1]; - if (row >= 0 && row < grid.Length && + if (row >= 0 && row < grid.Length && col >= 0 && col < grid[0].Length && grid[row][col] == 1) { grid[row][col] = 2; @@ -234,7 +238,7 @@ func orangesRotting(grid [][]int) int { queue := make([]Pair, 0) fresh := 0 time := 0 - + for r := 0; r < rows; r++ { for c := 0; c < cols; c++ { if grid[r][c] == 1 { @@ -245,20 +249,20 @@ func orangesRotting(grid [][]int) int { } } } - + directions := [][]int{{0, 1}, {0, -1}, {1, 0}, {-1, 0}} - + for fresh > 0 && len(queue) > 0 { length := len(queue) - + for i := 0; i < length; i++ { current := queue[0] - queue = queue[1:] - + queue = queue[1:] + for _, dir := range directions { newRow := current.row + dir[0] newCol := current.col + dir[1] - + if newRow >= 0 && newRow < rows && newCol >= 0 && newCol < cols && grid[newRow][newCol] == 1 { @@ -270,7 +274,7 @@ func orangesRotting(grid [][]int) int { } time++ } - + if fresh == 0 { return time } @@ -281,14 +285,14 @@ func orangesRotting(grid [][]int) int { ```kotlin class Solution { data class Pair(val row: Int, val col: Int) - + fun orangesRotting(grid: Array): Int { val rows = grid.size val cols = grid[0].size val queue = ArrayDeque() var fresh = 0 var time = 0 - + for (r in 0 until rows) { for (c in 0 until cols) { if (grid[r][c] == 1) { @@ -299,24 +303,24 @@ class Solution { } } } - + val directions = arrayOf( intArrayOf(0, 1), intArrayOf(0, -1), intArrayOf(1, 0), intArrayOf(-1, 0) ) - + while (fresh > 0 && queue.isNotEmpty()) { val length = queue.size - + repeat(length) { val current = queue.removeFirst() - + for (dir in directions) { val newRow = current.row + dir[0] val newCol = current.col + dir[1] - + if (newRow in 0 until rows && newCol in 0 until cols && grid[newRow][newCol] == 1) { @@ -328,24 +332,72 @@ class Solution { } time++ } - + return if (fresh == 0) time else -1 } } ``` +```swift +class Solution { + func orangesRotting(_ grid: [[Int]]) -> Int { + var grid = grid + var queue = Deque<(Int, Int)>() + var fresh = 0 + var time = 0 + + let ROWS = grid.count + let COLS = grid[0].count + + for r in 0.. 0 && !queue.isEmpty { + let length = queue.count + for _ in 0..= 0 && row < ROWS && col >= 0 && col < COLS && grid[row][col] == 1 { + grid[row][col] = 2 + queue.append((row, col)) + fresh -= 1 + } + } + } + time += 1 + } + + return fresh == 0 ? time : -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. --- -## 2. Breadth First Search (No Queue) +## 2. Breadth First Search (No Queue) ::tabs-start @@ -370,10 +422,10 @@ class Solution: if grid[r][c] == 2: for dr, dc in directions: row, col = r + dr, c + dc - if (row in range(ROWS) and - col in range(COLS) and + if (row in range(ROWS) and + col in range(COLS) and grid[row][col] == 1): - grid[row][col] = 3 + grid[row][col] = 3 fresh -= 1 flag = True @@ -383,7 +435,7 @@ class Solution: for r in range(ROWS): for c in range(COLS): if grid[r][c] == 3: - grid[r][c] = 2 + grid[r][c] = 2 time += 1 @@ -411,8 +463,8 @@ public class Solution { if (grid[r][c] == 2) { for (int[] d : directions) { int row = r + d[0], col = c + d[1]; - if (row >= 0 && col >= 0 && - row < ROWS && col < COLS && + if (row >= 0 && col >= 0 && + row < ROWS && col < COLS && grid[row][col] == 1) { grid[row][col] = 3; fresh--; @@ -452,7 +504,7 @@ public: } } - vector> directions = {{0, 1}, {0, -1}, + vector> directions = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; while (fresh > 0) { @@ -462,8 +514,8 @@ public: if (grid[r][c] == 2) { for (auto& d : directions) { int row = r + d[0], col = c + d[1]; - if (row >= 0 && col >= 0 && - row < ROWS && col < COLS && + if (row >= 0 && col >= 0 && + row < ROWS && col < COLS && grid[row][col] == 1) { grid[row][col] = 3; fresh--; @@ -497,8 +549,10 @@ class Solution { * @return {number} */ orangesRotting(grid) { - let ROWS = grid.length, COLS = grid[0].length; - let fresh = 0, time = 0; + let ROWS = grid.length, + COLS = grid[0].length; + let fresh = 0, + time = 0; for (let r = 0; r < ROWS; r++) { for (let c = 0; c < COLS; c++) { @@ -506,7 +560,12 @@ class Solution { } } - let directions = [[0, 1], [0, -1], [1, 0], [-1, 0]]; + let directions = [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ]; while (fresh > 0) { let flag = false; @@ -514,10 +573,15 @@ class Solution { for (let c = 0; c < COLS; c++) { if (grid[r][c] === 2) { for (let [dr, dc] of directions) { - let row = r + dr, col = c + dc; - if (row >= 0 && col >= 0 && - row < ROWS && col < COLS && - grid[row][col] === 1) { + let row = r + dr, + col = c + dc; + if ( + row >= 0 && + col >= 0 && + row < ROWS && + col < COLS && + grid[row][col] === 1 + ) { grid[row][col] = 3; fresh--; flag = true; @@ -556,7 +620,7 @@ public class Solution { } int[][] directions = new int[][] { - new int[] {0, 1}, new int[] {0, -1}, + new int[] {0, 1}, new int[] {0, -1}, new int[] {1, 0}, new int[] {-1, 0} }; @@ -567,8 +631,8 @@ public class Solution { if (grid[r][c] == 2) { foreach (var d in directions) { int row = r + d[0], col = c + d[1]; - if (row >= 0 && col >= 0 && - row < ROWS && col < COLS && + if (row >= 0 && col >= 0 && + row < ROWS && col < COLS && grid[row][col] == 1) { grid[row][col] = 3; fresh--; @@ -600,7 +664,7 @@ func orangesRotting(grid [][]int) int { rows, cols := len(grid), len(grid[0]) fresh := 0 time := 0 - + for r := 0; r < rows; r++ { for c := 0; c < cols; c++ { if grid[r][c] == 1 { @@ -608,9 +672,9 @@ func orangesRotting(grid [][]int) int { } } } - + directions := [][]int{{0, 1}, {0, -1}, {1, 0}, {-1, 0}} - + for fresh > 0 { flag := false for r := 0; r < rows; r++ { @@ -618,8 +682,8 @@ func orangesRotting(grid [][]int) int { if grid[r][c] == 2 { for _, d := range directions { row, col := r+d[0], c+d[1] - if row >= 0 && row < rows && - col >= 0 && col < cols && + if row >= 0 && row < rows && + col >= 0 && col < cols && grid[row][col] == 1 { grid[row][col] = 3 fresh-- @@ -629,11 +693,11 @@ func orangesRotting(grid [][]int) int { } } } - + if !flag { return -1 } - + for r := 0; r < rows; r++ { for c := 0; c < cols; c++ { if grid[r][c] == 3 { @@ -643,7 +707,7 @@ func orangesRotting(grid [][]int) int { } time++ } - + return time } ``` @@ -655,20 +719,20 @@ class Solution { val cols = grid[0].size var fresh = 0 var time = 0 - + for (r in 0 until rows) { for (c in 0 until cols) { if (grid[r][c] == 1) fresh++ } } - + val directions = arrayOf( intArrayOf(0, 1), intArrayOf(0, -1), intArrayOf(1, 0), intArrayOf(-1, 0) ) - + while (fresh > 0) { var flag = false for (r in 0 until rows) { @@ -677,8 +741,8 @@ class Solution { for (d in directions) { val row = r + d[0] val col = c + d[1] - if (row in 0 until rows && - col in 0 until cols && + if (row in 0 until rows && + col in 0 until cols && grid[row][col] == 1) { grid[row][col] = 3 fresh-- @@ -688,9 +752,9 @@ class Solution { } } } - + if (!flag) return -1 - + for (r in 0 until rows) { for (c in 0 until cols) { if (grid[r][c] == 3) grid[r][c] = 2 @@ -698,7 +762,65 @@ class Solution { } time++ } - + + return time + } +} +``` + +```swift +class Solution { + func orangesRotting(_ grid: [[Int]]) -> Int { + var grid = grid + let ROWS = grid.count + let COLS = grid[0].count + var fresh = 0 + var time = 0 + + for r in 0.. 0 { + var flag = false + for r in 0..= 0 && row < ROWS && col >= 0 && + col < COLS && grid[row][col] == 1) { + grid[row][col] = 3 + fresh -= 1 + flag = true + } + } + } + } + } + + if !flag { + return -1 + } + + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns in the $grid$. diff --git a/articles/russian-doll-envelopes.md b/articles/russian-doll-envelopes.md new file mode 100644 index 000000000..5f61e6e8f --- /dev/null +++ b/articles/russian-doll-envelopes.md @@ -0,0 +1,884 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def maxEnvelopes(self, envelopes: List[List[int]]) -> int: + n = len(envelopes) + envelopes.sort(key=lambda x: (x[0], -x[1])) + + def lis(nums): + n = len(nums) + memo = [-1] * n + + def dfs(i): + if memo[i] != -1: + return memo[i] + + LIS = 1 + for j in range(i + 1, n): + if nums[i] < nums[j]: + LIS = max(LIS, 1 + dfs(j)) + + memo[i] = LIS + return LIS + + return max(dfs(i) for i in range(n)) + + return lis([e[1] for e in envelopes]) +``` + +```java +public class Solution { + public int maxEnvelopes(int[][] envelopes) { + int n = envelopes.length; + if (n == 0) return 0; + Arrays.sort(envelopes, (a, b) -> + a[0] != b[0] + ? Integer.compare(a[0], b[0]) + : Integer.compare(b[1], a[1]) + ); + + int[] heights = new int[n]; + for (int i = 0; i < n; i++) { + heights[i] = envelopes[i][1]; + } + + int[] memo = new int[n]; + Arrays.fill(memo, -1); + int result = 0; + for (int i = 0; i < n; i++) { + result = Math.max(result, dfs(heights, i, memo)); + } + return result; + } + + private int dfs(int[] nums, int i, int[] memo) { + if (memo[i] != -1) return memo[i]; + int lis = 1; + for (int j = i + 1; j < nums.length; j++) { + if (nums[i] < nums[j]) { + lis = Math.max(lis, 1 + dfs(nums, j, memo)); + } + } + memo[i] = lis; + return lis; + } +} +``` + +```cpp +class Solution { + vector nums, memo; + int n; + + int dfs(int i) { + if (memo[i] != -1) return memo[i]; + int lis = 1; + for (int j = i + 1; j < n; j++) { + if (nums[i] < nums[j]) { + lis = max(lis, 1 + dfs(j)); + } + } + return memo[i] = lis; + } + +public: + int maxEnvelopes(vector>& envelopes) { + n = envelopes.size(); + sort(envelopes.begin(), envelopes.end(), [](auto &a, auto &b) { + if (a[0] != b[0]) return a[0] < b[0]; + return a[1] > b[1]; + }); + nums.resize(n); + for (int i = 0; i < n; i++) nums[i] = envelopes[i][1]; + memo.assign(n, -1); + + int result = 0; + for (int i = 0; i < n; i++) { + result = max(result, dfs(i)); + } + return result; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} envelopes + * @return {number} + */ + maxEnvelopes(envelopes) { + const n = envelopes.length; + envelopes.sort((a, b) => a[0] - b[0] || b[1] - a[1]); + const nums = envelopes.map((e) => e[1]); + const memo = new Array(n).fill(-1); + + const dfs = (i) => { + if (memo[i] !== -1) return memo[i]; + let lis = 1; + for (let j = i + 1; j < n; j++) { + if (nums[i] < nums[j]) { + lis = Math.max(lis, 1 + dfs(j)); + } + } + memo[i] = lis; + return lis; + }; + + let result = 0; + for (let i = 0; i < n; i++) { + result = Math.max(result, dfs(i)); + } + return result; + } +} +``` + +```csharp +public class Solution { + public int MaxEnvelopes(int[][] envelopes) { + int n = envelopes.Length; + Array.Sort(envelopes, (a, b) => + a[0] != b[0] ? a[0] - b[0] : b[1] - a[1] + ); + + int[] nums = envelopes.Select(e => e[1]).ToArray(); + int[] memo = Enumerable.Repeat(-1, n).ToArray(); + + int dfs(int i) { + if (memo[i] != -1) return memo[i]; + int lis = 1; + for (int j = i + 1; j < n; j++) { + if (nums[i] < nums[j]) { + lis = Math.Max(lis, 1 + dfs(j)); + } + } + memo[i] = lis; + return lis; + } + + int result = 0; + for (int i = 0; i < n; i++) { + result = Math.Max(result, dfs(i)); + } + return result; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def maxEnvelopes(self, envelopes: List[List[int]]) -> int: + n = len(envelopes) + envelopes.sort(key=lambda x: (x[0], -x[1])) + + def lis(nums): + LIS = [1] * n + + for i in range(n - 1, -1, -1): + for j in range(i + 1, n): + if nums[i] < nums[j]: + LIS[i] = max(LIS[i], 1 + LIS[j]) + return max(LIS) + + return lis([e[1] for e in envelopes]) +``` + +```java +public class Solution { + public int maxEnvelopes(int[][] envelopes) { + int n = envelopes.length; + Arrays.sort(envelopes, (a, b) -> + a[0] != b[0] ? a[0] - b[0] : b[1] - a[1] + ); + int[] heights = new int[n]; + for (int i = 0; i < n; i++) heights[i] = envelopes[i][1]; + int[] LIS = new int[n]; + Arrays.fill(LIS, 1); + int ans = 0; + for (int i = n - 1; i >= 0; i--) { + for (int j = i + 1; j < n; j++) { + if (heights[i] < heights[j]) { + LIS[i] = Math.max(LIS[i], 1 + LIS[j]); + } + } + ans = Math.max(ans, LIS[i]); + } + return ans; + } +} +``` + +```cpp +class Solution { +public: + int maxEnvelopes(vector>& envelopes) { + int n = envelopes.size(); + sort(envelopes.begin(), envelopes.end(), + [](const vector& a, const vector& b) { + if (a[0] != b[0]) return a[0] < b[0]; + return a[1] > b[1]; + }); + vector heights(n); + for (int i = 0; i < n; ++i) heights[i] = envelopes[i][1]; + vector LIS(n, 1); + int ans = 0; + for (int i = n - 1; i >= 0; --i) { + for (int j = i + 1; j < n; ++j) { + if (heights[i] < heights[j]) { + LIS[i] = max(LIS[i], 1 + LIS[j]); + } + } + ans = max(ans, LIS[i]); + } + return ans; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} envelopes + * @return {number} + */ + maxEnvelopes(envelopes) { + envelopes.sort((a, b) => a[0] - b[0] || b[1] - a[1]); + const heights = envelopes.map((e) => e[1]); + const n = heights.length; + if (n === 0) return 0; + const LIS = new Array(n).fill(1); + let ans = 0; + for (let i = n - 1; i >= 0; i--) { + for (let j = i + 1; j < n; j++) { + if (heights[i] < heights[j]) { + LIS[i] = Math.max(LIS[i], 1 + LIS[j]); + } + } + ans = Math.max(ans, LIS[i]); + } + return ans; + } +} +``` + +```csharp +public class Solution { + public int MaxEnvelopes(int[][] envelopes) { + int n = envelopes.Length; + Array.Sort(envelopes, (a, b) => + a[0] != b[0] ? a[0] - b[0] : b[1] - a[1] + ); + int[] heights = new int[n]; + for (int i = 0; i < n; i++) heights[i] = envelopes[i][1]; + int[] LIS = new int[n]; + for (int i = 0; i < n; i++) LIS[i] = 1; + int ans = 0; + for (int i = n - 1; i >= 0; i--) { + for (int j = i + 1; j < n; j++) { + if (heights[i] < heights[j]) { + LIS[i] = Math.Max(LIS[i], 1 + LIS[j]); + } + } + ans = Math.Max(ans, LIS[i]); + } + return ans; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming + Binary Search + +::tabs-start + +```python +class Solution: + def maxEnvelopes(self, envelopes: List[List[int]]) -> int: + envelopes.sort(key=lambda x: (x[0], -x[1])) + + def lis(nums): + dp = [] + dp.append(nums[0]) + + LIS = 1 + for i in range(1, len(nums)): + if dp[-1] < nums[i]: + dp.append(nums[i]) + LIS += 1 + continue + + idx = bisect_left(dp, nums[i]) + dp[idx] = nums[i] + + return LIS + + return lis([e[1] for e in envelopes]) +``` + +```java +public class Solution { + public int maxEnvelopes(int[][] envelopes) { + int n = envelopes.length; + Arrays.sort(envelopes, (a, b) -> + a[0] != b[0] + ? Integer.compare(a[0], b[0]) + : Integer.compare(b[1], a[1]) + ); + + int[] nums = new int[n]; + for (int i = 0; i < n; i++) { + nums[i] = envelopes[i][1]; + } + + List dp = new ArrayList<>(); + dp.add(nums[0]); + + int LIS = 1; + for (int i = 1; i < n; i++) { + if (dp.get(dp.size() - 1) < nums[i]) { + dp.add(nums[i]); + LIS++; + continue; + } + + int idx = Collections.binarySearch(dp, nums[i]); + if (idx < 0) idx = -idx - 1; + dp.set(idx, nums[i]); + } + + return LIS; + } +} +``` + +```cpp +class Solution { +public: + int maxEnvelopes(vector>& envelopes) { + int n = envelopes.size(); + vector nums(n); + sort(envelopes.begin(), envelopes.end(), [](auto &a, auto &b) { + if (a[0] != b[0]) return a[0] < b[0]; + return a[1] > b[1]; + }); + for (int i = 0; i < n; i++) nums[i] = envelopes[i][1]; + + vector dp; + dp.push_back(nums[0]); + + int LIS = 1; + for (int i = 1; i < n; i++) { + if (dp.back() < nums[i]) { + dp.push_back(nums[i]); + LIS++; + continue; + } + + int idx = lower_bound(dp.begin(), + dp.end(), nums[i]) - dp.begin(); + dp[idx] = nums[i]; + } + + return LIS; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} envelopes + * @return {number} + */ + maxEnvelopes(envelopes) { + const n = envelopes.length; + envelopes.sort((a, b) => a[0] - b[0] || b[1] - a[1]); + const nums = envelopes.map((e) => e[1]); + const dp = []; + dp.push(nums[0]); + + let LIS = 1; + for (let i = 1; i < n; i++) { + if (dp[dp.length - 1] < nums[i]) { + dp.push(nums[i]); + LIS++; + continue; + } + + let left = 0, + right = dp.length - 1; + while (left < right) { + const mid = Math.floor((left + right) / 2); + if (dp[mid] < nums[i]) { + left = mid + 1; + } else { + right = mid; + } + } + dp[left] = nums[i]; + } + + return LIS; + } +} +``` + +```csharp +public class Solution { + public int MaxEnvelopes(int[][] envelopes) { + int n = envelopes.Length; + Array.Sort(envelopes, (a, b) => + a[0] != b[0] ? a[0] - b[0] : b[1] - a[1] + ); + + int[] nums = envelopes.Select(e => e[1]).ToArray(); + + List dp = new List(); + dp.Add(nums[0]); + + int LIS = 1; + for (int i = 1; i < n; i++) { + if (dp[dp.Count - 1] < nums[i]) { + dp.Add(nums[i]); + LIS++; + continue; + } + + int idx = dp.BinarySearch(nums[i]); + if (idx < 0) idx = ~idx; + dp[idx] = nums[i]; + } + + return LIS; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Segment Tree + +::tabs-start + +```python +class SegmentTree: + def __init__(self, N): + self.n = N + while (self.n & (self.n - 1)) != 0: + self.n += 1 + self.tree = [0] * (2 * self.n) + + def update(self, i, val): + self.tree[self.n + i] = val + j = (self.n + i) >> 1 + while j >= 1: + self.tree[j] = max(self.tree[j << 1], self.tree[j << 1 | 1]) + j >>= 1 + + def query(self, l, r): + if l > r: + return 0 + res = float('-inf') + l += self.n + r += self.n + 1 + while l < r: + if l & 1: + res = max(res, self.tree[l]) + l += 1 + if r & 1: + r -= 1 + res = max(res, self.tree[r]) + l >>= 1 + r >>= 1 + return res + +class Solution: + def maxEnvelopes(self, envelopes: List[List[int]]) -> int: + n = len(envelopes) + envelopes.sort(key=lambda x: (x[0], -x[1])) + + def lis(nums): + def compress(arr): + sortedArr = sorted(set(arr)) + order = [] + for num in arr: + order.append(bisect_left(sortedArr, num)) + return order + + nums = compress(nums) + n = len(nums) + segTree = SegmentTree(n) + + LIS = 0 + for num in nums: + curLIS = segTree.query(0, num - 1) + 1 + segTree.update(num, curLIS) + LIS = max(LIS, curLIS) + return LIS + + return lis([e[1] for e in envelopes]) +``` + +```java +class SegmentTree { + int n; + int[] tree; + + public SegmentTree(int N) { + n = N; + while ((n & (n - 1)) != 0) { + n++; + } + tree = new int[2 * n]; + } + + void update(int i, int val) { + tree[n + i] = val; + int j = (n + i) >> 1; + while (j >= 1) { + tree[j] = Math.max(tree[j << 1], tree[j << 1 | 1]); + j >>= 1; + } + } + + int query(int l, int r) { + if (l > r) { + return 0; + } + int res = Integer.MIN_VALUE; + l += n; + r += n + 1; + while (l < r) { + if ((l & 1) != 0) { + res = Math.max(res, tree[l]); + l++; + } + if ((r & 1) != 0) { + r--; + res = Math.max(res, tree[r]); + } + l >>= 1; + r >>= 1; + } + return res; + } +} + +public class Solution { + public int lis(int[] nums) { + int[] sortedArr = Arrays.stream(nums).distinct().sorted().toArray(); + int[] order = new int[nums.length]; + for (int i = 0; i < nums.length; i++) { + order[i] = Arrays.binarySearch(sortedArr, nums[i]); + } + int n = sortedArr.length; + SegmentTree segTree = new SegmentTree(n); + + int LIS = 0; + for (int num : order) { + int curLIS = segTree.query(0, num - 1) + 1; + segTree.update(num, curLIS); + LIS = Math.max(LIS, curLIS); + } + return LIS; + } + + public int maxEnvelopes(int[][] envelopes) { + int n = envelopes.length; + Arrays.sort(envelopes, (a, b) -> + a[0] != b[0] ? a[0] - b[0] : b[1] - a[1] + ); + + int[] heights = new int[n]; + for (int i = 0; i < n; i++) heights[i] = envelopes[i][1]; + return lis(heights); + } +} +``` + +```cpp +class SegmentTree { +public: + int n; + vector tree; + + SegmentTree(int N) { + n = N; + while (n & (n - 1)) { + n++; + } + tree.resize(2 * n); + } + + void update(int i, int val) { + tree[n + i] = val; + int j = (n + i) >> 1; + while (j >= 1) { + tree[j] = max(tree[j << 1], tree[j << 1 | 1]); + j >>= 1; + } + } + + int query(int l, int r) { + if (l > r) { + return 0; + } + int res = INT_MIN; + l += n; + r += n + 1; + while (l < r) { + if (l & 1) { + res = max(res, tree[l]); + l++; + } + if (r & 1) { + r--; + res = max(res, tree[r]); + } + l >>= 1; + r >>= 1; + } + return res; + } +}; + +class Solution { + int lis(vector& nums) { + vector sortedArr = nums; + sort(sortedArr.begin(), sortedArr.end()); + sortedArr.erase(unique(sortedArr.begin(), + sortedArr.end()), sortedArr.end()); + + vector order(nums.size()); + for (int i = 0; i < nums.size(); i++) { + order[i] = lower_bound(sortedArr.begin(), sortedArr.end(), + nums[i]) - sortedArr.begin(); + } + + int n = sortedArr.size(); + SegmentTree segTree(n); + + int LIS = 0; + for (int num : order) { + int curLIS = segTree.query(0, num - 1) + 1; + segTree.update(num, curLIS); + LIS = max(LIS, curLIS); + } + return LIS; + } + +public: + int maxEnvelopes(vector>& envelopes) { + int n = envelopes.size(); + sort(envelopes.begin(), envelopes.end(), + [](const vector& a, const vector& b) { + if (a[0] != b[0]) return a[0] < b[0]; + return a[1] > b[1]; + }); + vector heights(n); + for (int i = 0; i < n; ++i) heights[i] = envelopes[i][1]; + return lis(heights); + } +}; +``` + +```javascript +class SegmentTree { + constructor(N, a) { + this.n = N; + while ((this.n & (this.n - 1)) !== 0) { + this.n++; + } + this.tree = new Array(2 * this.n).fill(0); + } + + /** + * @param {number} i + * @param {number} val + */ + update(i, val) { + this.tree[this.n + i] = val; + let j = (this.n + i) >> 1; + while (j >= 1) { + this.tree[j] = Math.max(this.tree[j << 1], this.tree[(j << 1) | 1]); + j >>= 1; + } + } + + /** + * @param {number} l + * @param {number} r + * @return {number} + */ + query(l, r) { + if (l > r) { + return 0; + } + let res = -Infinity; + l += this.n; + r += this.n + 1; + while (l < r) { + if (l & 1) { + res = Math.max(res, this.tree[l]); + l++; + } + if (r & 1) { + r--; + res = Math.max(res, this.tree[r]); + } + l >>= 1; + r >>= 1; + } + return res; + } +} + +class Solution { + /** + * @param {number[][]} envelopes + * @return {number} + */ + maxEnvelopes(envelopes) { + envelopes.sort((a, b) => a[0] - b[0] || b[1] - a[1]); + const heights = envelopes.map((e) => e[1]); + + const lis = (nums) => { + const sortedArr = Array.from(new Set(nums)).sort((a, b) => a - b); + const map = new Map(); + + sortedArr.forEach((num, index) => { + map.set(num, index); + }); + + const order = nums.map((num) => map.get(num)); + const n = sortedArr.length; + const segTree = new SegmentTree(n, order); + + let LIS = 0; + for (const num of order) { + const curLIS = segTree.query(0, num - 1) + 1; + segTree.update(num, curLIS); + LIS = Math.max(LIS, curLIS); + } + return LIS; + }; + return lis(heights); + } +} +``` + +```csharp +public class SegmentTree { + private int n; + private int[] tree; + + public SegmentTree(int N) { + n = N; + tree = new int[2 * n]; + Array.Fill(tree, 0); + } + + public void Update(int i, int val) { + tree[n + i] = val; + int j = (n + i) >> 1; + while (j >= 1) { + tree[j] = Math.Max(tree[2 * j], tree[2 * j + 1]); + j >>= 1; + } + } + + public int Query(int l, int r) { + if (l > r) { + return 0; + } + int res = int.MinValue; + l += n; + r += n + 1; + while (l < r) { + if ((l & 1) == 1) { + res = Math.Max(res, tree[l]); + l++; + } + if ((r & 1) == 1) { + r--; + res = Math.Max(res, tree[r]); + } + l >>= 1; + r >>= 1; + } + return res; + } +} + +public class Solution { + public int Lis(int[] nums) { + var sortedArr = nums.Distinct().OrderBy(x => x).ToArray(); + var map = new Dictionary(); + + for (int i = 0; i < sortedArr.Length; i++) { + map[sortedArr[i]] = i; + } + + int n = sortedArr.Length; + var segTree = new SegmentTree(n); + + int LIS = 0; + foreach (var num in nums) { + int compressedIndex = map[num]; + int curLIS = segTree.Query(0, compressedIndex - 1) + 1; + segTree.Update(compressedIndex, curLIS); + LIS = Math.Max(LIS, curLIS); + } + return LIS; + } + + public int MaxEnvelopes(int[][] envelopes) { + int n = envelopes.Length; + Array.Sort(envelopes, (a, b) => + a[0] != b[0] ? a[0] - b[0] : b[1] - a[1] + ); + int[] heights = new int[n]; + for (int i = 0; i < n; i++) heights[i] = envelopes[i][1]; + return Lis(heights); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/same-binary-tree.md b/articles/same-binary-tree.md index 6cbfc12aa..84877698c 100644 --- a/articles/same-binary-tree.md +++ b/articles/same-binary-tree.md @@ -186,20 +186,343 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isSameTree(_ p: TreeNode?, _ q: TreeNode?) -> Bool { + if p == nil && q == nil { + return true + } + if let p = p, let q = q, p.val == q.val { + return isSameTree(p.left, q.left) && isSameTree(p.right, q.right) + } else { + return false + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(h)$ - * Best Case ([balanced tree](https://www.geeksforgeeks.org/balanced-binary-tree/)): $O(log(n))$ - * Worst Case ([degenerate tree](https://www.geeksforgeeks.org/introduction-to-degenerate-binary-tree/)): $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + - Best Case ([balanced tree](https://www.geeksforgeeks.org/balanced-binary-tree/)): $O(log(n))$ + - Worst Case ([degenerate tree](https://www.geeksforgeeks.org/introduction-to-degenerate-binary-tree/)): $O(n)$ > Where $n$ is the number of nodes in the tree and $h$ is the height of the tree. --- -## 2. Breadth First Search +## 2. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right + +class Solution: + def isSameTree(self, p: Optional[TreeNode], q: Optional[TreeNode]) -> bool: + stack = [(p, q)] + + while stack: + node1, node2 = stack.pop() + + if not node1 and not node2: + continue + if not node1 or not node2 or node1.val != node2.val: + return False + + stack.append((node1.right, node2.right)) + stack.append((node1.left, node2.left)) + + return True +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ + +public class Solution { + public boolean isSameTree(TreeNode p, TreeNode q) { + Stack stack = new Stack<>(); + stack.push(new TreeNode[]{p, q}); + + while (!stack.isEmpty()) { + TreeNode[] nodes = stack.pop(); + TreeNode node1 = nodes[0], node2 = nodes[1]; + + if (node1 == null && node2 == null) continue; + if (node1 == null || node2 == null || node1.val != node2.val) { + return false; + } + stack.push(new TreeNode[]{node1.right, node2.right}); + stack.push(new TreeNode[]{node1.left, node2.left}); + } + + return true; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ + +class Solution { +public: + bool isSameTree(TreeNode* p, TreeNode* q) { + stack> stk; + stk.push({p, q}); + + while (!stk.empty()) { + auto [node1, node2] = stk.top(); + stk.pop(); + + if (!node1 && !node2) continue; + if (!node1 || !node2 || node1->val != node2->val) return false; + + stk.push({node1->right, node2->right}); + stk.push({node1->left, node2->left}); + } + + return true; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ + +class Solution { + /** + * @param {TreeNode} p + * @param {TreeNode} q + * @return {boolean} + */ + isSameTree(p, q) { + const stack = [[p, q]]; + + while (stack.length) { + const [node1, node2] = stack.pop(); + + if (!node1 && !node2) continue; + if (!node1 || !node2 || node1.val !== node2.val) { + return false; + } + stack.push([node1.right, node2.right]); + stack.push([node1.left, node2.left]); + } + + return true; + } +} +``` + +```csharp +/** + * Definition for a binary tree node. + * public class TreeNode { + * public 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 class Solution { + public bool IsSameTree(TreeNode p, TreeNode q) { + var stack = new Stack<(TreeNode, TreeNode)>(); + stack.Push((p, q)); + + while (stack.Count > 0) { + var (node1, node2) = stack.Pop(); + + if (node1 == null && node2 == null) continue; + if (node1 == null || node2 == null || node1.val != node2.val) { + return false; + } + stack.Push((node1.right, node2.right)); + stack.Push((node1.left, node2.left)); + } + + return true; + } +} +``` + +```go +/** + * Definition for a binary tree node. + * type TreeNode struct { + * Val int + * Left *TreeNode + * Right *TreeNode + * } + */ +func isSameTree(p *TreeNode, q *TreeNode) bool { + type Pair struct { + first, second *TreeNode + } + + stack := []Pair{{p, q}} + + for len(stack) > 0 { + lastIdx := len(stack) - 1 + node1, node2 := stack[lastIdx].first, stack[lastIdx].second + stack = stack[:lastIdx] + + if node1 == nil && node2 == nil { + continue + } + if node1 == nil || node2 == nil || node1.Val != node2.Val { + return false + } + + stack = append(stack, Pair{node1.Right, node2.Right}) + stack = append(stack, Pair{node1.Left, node2.Left}) + } + + return true +} +``` + +```kotlin +/** + * Example: + * var ti = TreeNode(5) + * var v = ti.`val` + * Definition for a binary tree node. + * class TreeNode(var `val`: Int) { + * var left: TreeNode? = null + * var right: TreeNode? = null + * } + */ +class Solution { + fun isSameTree(p: TreeNode?, q: TreeNode?): Boolean { + val stack = ArrayDeque>() + stack.addLast(Pair(p, q)) + + while (stack.isNotEmpty()) { + val (node1, node2) = stack.removeLast() + + if (node1 == null && node2 == null) continue + if (node1 == null || node2 == null || node1.`val` != node2.`val`) { + return false + } + stack.addLast(Pair(node1.right, node2.right)) + stack.addLast(Pair(node1.left, node2.left)) + } + + return true + } +} +``` + +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isSameTree(_ p: TreeNode?, _ q: TreeNode?) -> Bool { + var stack: [(TreeNode?, TreeNode?)] = [(p, q)] + + while !stack.isEmpty { + let (node1, node2) = stack.removeLast() + + if node1 == nil && node2 == nil { + continue + } + if node1 == nil || node2 == nil || node1!.val != node2!.val { + return false + } + + stack.append((node1!.right, node2!.right)) + stack.append((node1!.left, node2!.left)) + } + + return true + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Breadth First Search ::tabs-start @@ -217,18 +540,19 @@ class Solution: q2 = deque([q]) while q1 and q2: - nodeP = q1.popleft() - nodeQ = q2.popleft() + for _ in range(len(q1)): + nodeP = q1.popleft() + nodeQ = q2.popleft() - if nodeP is None and nodeQ is None: - continue - if nodeP is None or nodeQ is None or nodeP.val != nodeQ.val: - return False + if nodeP is None and nodeQ is None: + continue + if nodeP is None or nodeQ is None or nodeP.val != nodeQ.val: + return False - q1.append(nodeP.left) - q1.append(nodeP.right) - q2.append(nodeQ.left) - q2.append(nodeQ.right) + q1.append(nodeP.left) + q1.append(nodeP.right) + q2.append(nodeQ.left) + q2.append(nodeQ.right) return True ``` @@ -258,17 +582,19 @@ public class Solution { q2.add(q); while (!q1.isEmpty() && !q2.isEmpty()) { - TreeNode nodeP = q1.poll(); - TreeNode nodeQ = q2.poll(); - - if (nodeP == null && nodeQ == null) continue; - if (nodeP == null || nodeQ == null || nodeP.val != nodeQ.val) - return false; - - q1.add(nodeP.left); - q1.add(nodeP.right); - q2.add(nodeQ.left); - q2.add(nodeQ.right); + for (int i = q1.size(); i > 0; i--) { + TreeNode nodeP = q1.poll(); + TreeNode nodeQ = q2.poll(); + + if (nodeP == null && nodeQ == null) continue; + if (nodeP == null || nodeQ == null || nodeP.val != nodeQ.val) + return false; + + q1.add(nodeP.left); + q1.add(nodeP.right); + q2.add(nodeQ.left); + q2.add(nodeQ.right); + } } return true; @@ -298,17 +624,19 @@ public: q2.push(q); while (!q1.empty() && !q2.empty()) { - TreeNode* nodeP = q1.front(); q1.pop(); - TreeNode* nodeQ = q2.front(); q2.pop(); - - if (!nodeP && !nodeQ) continue; - if (!nodeP || !nodeQ || nodeP->val != nodeQ->val) - return false; - - q1.push(nodeP->left); - q1.push(nodeP->right); - q2.push(nodeQ->left); - q2.push(nodeQ->right); + for (int i = q1.size(); i > 0; i--) { + TreeNode* nodeP = q1.front(); q1.pop(); + TreeNode* nodeQ = q2.front(); q2.pop(); + + if (!nodeP && !nodeQ) continue; + if (!nodeP || !nodeQ || nodeP->val != nodeQ->val) + return false; + + q1.push(nodeP->left); + q1.push(nodeP->right); + q2.push(nodeQ->left); + q2.push(nodeQ->right); + } } return true; @@ -339,19 +667,26 @@ class Solution { const q2 = new Queue(); q1.push(p); q2.push(q); - - while (!q1.isEmpty() && !q2.isEmpty()) { - let nodeP = q1.pop(); - let nodeQ = q2.pop(); - - if (nodeP === null && nodeQ === null) continue; - if (nodeP === null || nodeQ === null || nodeP.val !== nodeQ.val) - return false; - q1.push(nodeP.left); - q1.push(nodeP.right); - q2.push(nodeQ.left); - q2.push(nodeQ.right); + while (!q1.isEmpty() && !q2.isEmpty()) { + for (let i = q1.size(); i > 0; i--) { + let nodeP = q1.pop(); + let nodeQ = q2.pop(); + + if (nodeP === null && nodeQ === null) continue; + if ( + nodeP === null || + nodeQ === null || + nodeP.val !== nodeQ.val + ) { + return false; + } + + q1.push(nodeP.left); + q1.push(nodeP.right); + q2.push(nodeQ.left); + q2.push(nodeQ.right); + } } return true; @@ -380,17 +715,20 @@ public class Solution { var q2 = new Queue(new[] { q }); while (q1.Count > 0 && q2.Count > 0) { - var nodeP = q1.Dequeue(); - var nodeQ = q2.Dequeue(); - - if (nodeP == null && nodeQ == null) continue; - if (nodeP == null || nodeQ == null || nodeP.val != nodeQ.val) - return false; - - q1.Enqueue(nodeP.left); - q1.Enqueue(nodeP.right); - q2.Enqueue(nodeQ.left); - q2.Enqueue(nodeQ.right); + for (int i = q1.Count; i > 0; i--) { + var nodeP = q1.Dequeue(); + var nodeQ = q2.Dequeue(); + + if (nodeP == null && nodeQ == null) continue; + if (nodeP == null || nodeQ == null || nodeP.val != nodeQ.val) { + return false; + } + + q1.Enqueue(nodeP.left); + q1.Enqueue(nodeP.right); + q2.Enqueue(nodeQ.left); + q2.Enqueue(nodeQ.right); + } } return true; @@ -412,20 +750,22 @@ func isSameTree(p *TreeNode, q *TreeNode) bool { queue2 := []*TreeNode{q} for len(queue1) > 0 && len(queue2) > 0 { - nodeP := queue1[0] - nodeQ := queue2[0] - queue1 = queue1[1:] - queue2 = queue2[1:] + for i := len(queue1); i > 0; i-- { + nodeP := queue1[0] + nodeQ := queue2[0] + queue1 = queue1[1:] + queue2 = queue2[1:] - if nodeP == nil && nodeQ == nil { - continue - } - if nodeP == nil || nodeQ == nil || nodeP.Val != nodeQ.Val { - return false - } + if nodeP == nil && nodeQ == nil { + continue + } + if nodeP == nil || nodeQ == nil || nodeP.Val != nodeQ.Val { + return false + } - queue1 = append(queue1, nodeP.Left, nodeP.Right) - queue2 = append(queue2, nodeQ.Left, nodeQ.Right) + queue1 = append(queue1, nodeP.Left, nodeP.Right) + queue2 = append(queue2, nodeQ.Left, nodeQ.Right) + } } return len(queue1) == 0 && len(queue2) == 0 @@ -452,20 +792,67 @@ class Solution { q2.add(q) while (q1.isNotEmpty() && q2.isNotEmpty()) { - val nodeP = q1.removeFirst() - val nodeQ = q2.removeFirst() + for (i in q1.size downTo 1) { + val nodeP = q1.removeFirst() + val nodeQ = q2.removeFirst() + + if (nodeP == null && nodeQ == null) { + continue + } + if (nodeP == null || nodeQ == null || nodeP.`val` != nodeQ.`val`) { + return false + } + + q1.add(nodeP.left) + q1.add(nodeP.right) + q2.add(nodeQ.left) + q2.add(nodeQ.right) + } + } + + return true + } +} +``` + +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isSameTree(_ p: TreeNode?, _ q: TreeNode?) -> Bool { + var q1 = Deque() + var q2 = Deque() + q1.append(p) + q2.append(q) + + while !q1.isEmpty && !q2.isEmpty { + let nodeP = q1.removeFirst() + let nodeQ = q2.removeFirst() - if (nodeP == null && nodeQ == null) { + if nodeP == nil && nodeQ == nil { continue } - if (nodeP == null || nodeQ == null || nodeP.`val` != nodeQ.`val`) { + if nodeP == nil || nodeQ == nil || nodeP!.val != nodeQ!.val { return false } - q1.add(nodeP.left) - q1.add(nodeP.right) - q2.add(nodeQ.left) - q2.add(nodeQ.right) + q1.append(nodeP!.left) + q1.append(nodeP!.right) + q2.append(nodeQ!.left) + q2.append(nodeQ!.right) } return true @@ -477,5 +864,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/score-after-flipping-matrix.md b/articles/score-after-flipping-matrix.md new file mode 100644 index 000000000..2136f3a3c --- /dev/null +++ b/articles/score-after-flipping-matrix.md @@ -0,0 +1,255 @@ +## 1. Greedy (Overwriting the Input) + +::tabs-start + +```python +class Solution: + def matrixScore(self, grid: List[List[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + + for r in range(ROWS): + if grid[r][0] == 0: + for c in range(COLS): + grid[r][c] ^= 1 + + for c in range(COLS): + one_cnt = sum(grid[r][c] for r in range(ROWS)) + if one_cnt < ROWS - one_cnt: + for r in range(ROWS): + grid[r][c] ^= 1 + + res = 0 + for r in range(ROWS): + for c in range(COLS): + res += grid[r][c] << (COLS - c - 1) + + return res +``` + +```java +public class Solution { + public int matrixScore(int[][] grid) { + int ROWS = grid.length, COLS = grid[0].length; + + for (int r = 0; r < ROWS; r++) { + if (grid[r][0] == 0) { + for (int c = 0; c < COLS; c++) { + grid[r][c] ^= 1; + } + } + } + + for (int c = 0; c < COLS; c++) { + int oneCnt = 0; + for (int r = 0; r < ROWS; r++) { + oneCnt += grid[r][c]; + } + if (oneCnt < ROWS - oneCnt) { + for (int r = 0; r < ROWS; r++) { + grid[r][c] ^= 1; + } + } + } + + int res = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + res += grid[r][c] << (COLS - c - 1); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int matrixScore(vector>& grid) { + int ROWS = grid.size(), COLS = grid[0].size(); + + for (int r = 0; r < ROWS; r++) { + if (grid[r][0] == 0) { + for (int c = 0; c < COLS; c++) { + grid[r][c] ^= 1; + } + } + } + + for (int c = 0; c < COLS; c++) { + int oneCnt = 0; + for (int r = 0; r < ROWS; r++) { + oneCnt += grid[r][c]; + } + if (oneCnt < ROWS - oneCnt) { + for (int r = 0; r < ROWS; r++) { + grid[r][c] ^= 1; + } + } + } + + int res = 0; + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + res += grid[r][c] << (COLS - c - 1); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + matrixScore(grid) { + let ROWS = grid.length, + COLS = grid[0].length; + + for (let r = 0; r < ROWS; r++) { + if (grid[r][0] === 0) { + for (let c = 0; c < COLS; c++) { + grid[r][c] ^= 1; + } + } + } + + for (let c = 0; c < COLS; c++) { + let oneCnt = 0; + for (let r = 0; r < ROWS; r++) { + oneCnt += grid[r][c]; + } + if (oneCnt < ROWS - oneCnt) { + for (let r = 0; r < ROWS; r++) { + grid[r][c] ^= 1; + } + } + } + + let res = 0; + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < COLS; c++) { + res += grid[r][c] << (COLS - c - 1); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(1)$ extra space. + +> Where $m$ is the number of rows and $n$ is the number of columns. + +--- + +## 2. Greedy (Optimal) + +::tabs-start + +```python +class Solution: + def matrixScore(self, grid: List[List[int]]) -> int: + ROWS, COLS = len(grid), len(grid[0]) + res = ROWS * (1 << (COLS - 1)) + + for c in range(1, COLS): + cnt = 0 + for r in range(ROWS): + if grid[r][c] != grid[r][0]: + cnt += 1 + + cnt = max(cnt, ROWS - cnt) + res += cnt * (1 << (COLS - c - 1)) + + return res +``` + +```java +public class Solution { + public int matrixScore(int[][] grid) { + int ROWS = grid.length, COLS = grid[0].length; + int res = ROWS * (1 << (COLS - 1)); + + for (int c = 1; c < COLS; c++) { + int cnt = 0; + for (int r = 0; r < ROWS; r++) { + if (grid[r][c] != grid[r][0]) { + cnt++; + } + } + cnt = Math.max(cnt, ROWS - cnt); + res += cnt * (1 << (COLS - c - 1)); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int matrixScore(vector>& grid) { + int ROWS = grid.size(), COLS = grid[0].size(); + int res = ROWS * (1 << (COLS - 1)); + + for (int c = 1; c < COLS; c++) { + int cnt = 0; + for (int r = 0; r < ROWS; r++) { + if (grid[r][c] != grid[r][0]) { + cnt++; + } + } + cnt = max(cnt, ROWS - cnt); + res += cnt * (1 << (COLS - c - 1)); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + matrixScore(grid) { + const ROWS = grid.length, + COLS = grid[0].length; + let res = ROWS * (1 << (COLS - 1)); + + for (let c = 1; c < COLS; c++) { + let cnt = 0; + for (let r = 0; r < ROWS; r++) { + if (grid[r][c] !== grid[r][0]) { + cnt++; + } + } + cnt = Math.max(cnt, ROWS - cnt); + res += cnt * (1 << (COLS - c - 1)); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(1)$ extra space. + +> Where $m$ is the number of rows and $n$ is the number of columns. diff --git a/articles/score-of-a-string.md b/articles/score-of-a-string.md new file mode 100644 index 000000000..f20806ea9 --- /dev/null +++ b/articles/score-of-a-string.md @@ -0,0 +1,72 @@ +## 1. Iteration + +::tabs-start + +```python +class Solution: + def scoreOfString(self, s: str) -> int: + res = 0 + for i in range(len(s) - 1): + res += abs(ord(s[i]) - ord(s[i + 1])) + return res +``` + +```java +public class Solution { + public int scoreOfString(String s) { + int res = 0; + for (int i = 0; i < s.length() - 1; i++) { + res += Math.abs(s.charAt(i) - s.charAt(i + 1)); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int scoreOfString(string s) { + int res = 0; + for (int i = 0; i < s.length() - 1; i++) { + res += abs(s[i] - s[i + 1]); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {number} + */ + scoreOfString(s) { + let res = 0; + for (let i = 0; i < s.length - 1; i++) { + res += Math.abs(s.charCodeAt(i) - s.charCodeAt(i + 1)); + } + return res; + } +} +``` + +```csharp +public class Solution { + public int ScoreOfString(string s) { + int res = 0; + for (int i = 0; i < s.Length - 1; i++) { + res += Math.Abs(s[i] - s[i + 1]); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/search-2d-matrix.md b/articles/search-2d-matrix.md index 722cbe2b6..7a9c1baf4 100644 --- a/articles/search-2d-matrix.md +++ b/articles/search-2d-matrix.md @@ -106,12 +106,27 @@ class Solution { } ``` +```swift +class Solution { + func searchMatrix(_ matrix: [[Int]], _ target: Int) -> Bool { + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns of matrix. @@ -186,8 +201,10 @@ class Solution { * @return {boolean} */ searchMatrix(matrix, target) { - const m = matrix.length, n = matrix[0].length; - let r = 0, c = n - 1; + const m = matrix.length, + n = matrix[0].length; + let r = 0, + c = n - 1; while (r < m && c >= 0) { if (matrix[r][c] > target) { @@ -263,12 +280,33 @@ class Solution { } ``` +```swift +class Solution { + func searchMatrix(_ matrix: [[Int]], _ target: Int) -> Bool { + let m = matrix.count + let n = matrix[0].count + var r = 0, c = n - 1 + + while r < m && c >= 0 { + if matrix[r][c] > target { + c -= 1 + } else if matrix[r][c] < target { + r += 1 + } else { + return true + } + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(m + n)$ +- Space complexity: $O(1)$ > Where $m$ is the number of rows and $n$ is the number of columns of matrix. @@ -546,12 +584,50 @@ class Solution { } ``` +```swift +class Solution { + func searchMatrix(_ matrix: [[Int]], _ target: Int) -> Bool { + let ROWS = matrix.count + let COLS = matrix[0].count + + var top = 0, bot = ROWS - 1 + while top <= bot { + let row = (top + bot) / 2 + if target > matrix[row][COLS - 1] { + top = row + 1 + } else if target < matrix[row][0] { + bot = row - 1 + } else { + break + } + } + + if !(top <= bot) { + return false + } + let row = (top + bot) / 2 + var l = 0, r = COLS - 1 + while l <= r { + let m = (l + r) / 2 + if target > matrix[row][m] { + l = m + 1 + } else if target < matrix[row][m] { + r = m - 1 + } else { + return true + } + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log m + \log n)$ (which reduces to $O(\log(m * n))$) -* Space complexity: $O(1)$ +- Time complexity: $O(\log m + \log n)$ (which reduces to $O(\log(m * n))$) +- Space complexity: $O(1)$ > Where $m$ is the number of rows and $n$ is the number of columns of matrix. @@ -632,12 +708,15 @@ class Solution { * @return {boolean} */ searchMatrix(matrix, target) { - let ROWS = matrix.length, COLS = matrix[0].length; + let ROWS = matrix.length, + COLS = matrix[0].length; - let l = 0, r = ROWS * COLS - 1; + let l = 0, + r = ROWS * COLS - 1; while (l <= r) { let m = l + Math.floor((r - l) / 2); - let row = Math.floor(m / COLS), col = m % COLS; + let row = Math.floor(m / COLS), + col = m % COLS; if (target > matrix[row][col]) { l = m + 1; } else if (target < matrix[row][col]) { @@ -718,11 +797,36 @@ class Solution { } ``` +```swift +class Solution { + func searchMatrix(_ matrix: [[Int]], _ target: Int) -> Bool { + let ROWS = matrix.count + let COLS = matrix[0].count + + var l = 0, r = ROWS * COLS - 1 + while l <= r { + let m = l + (r - l) / 2 + let row = m / COLS + let col = m % COLS + + if target > matrix[row][col] { + l = m + 1 + } else if target < matrix[row][col] { + r = m - 1 + } else { + return true + } + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log(m * n))$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log(m * n))$ +- Space complexity: $O(1)$ -> Where $m$ is the number of rows and $n$ is the number of columns of matrix. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns of matrix. diff --git a/articles/search-for-word-ii.md b/articles/search-for-word-ii.md index d304ea983..9451914a1 100644 --- a/articles/search-for-word-ii.md +++ b/articles/search-for-word-ii.md @@ -11,7 +11,7 @@ class Solution: def backtrack(r, c, i): if i == len(word): return True - if (r < 0 or c < 0 or r >= ROWS or + if (r < 0 or c < 0 or r >= ROWS or c >= COLS or board[r][c] != word[i] ): return False @@ -63,7 +63,7 @@ public class Solution { private boolean backtrack(char[][] board, int r, int c, String word, int i) { if (i == word.length()) return true; - if (r < 0 || c < 0 || r >= board.length || + if (r < 0 || c < 0 || r >= board.length || c >= board[0].length || board[r][c] != word.charAt(i)) return false; @@ -104,7 +104,7 @@ public: private: bool backtrack(vector>& board, int r, int c, string& word, int i) { if (i == word.length()) return true; - if (r < 0 || c < 0 || r >= board.size() || + if (r < 0 || c < 0 || r >= board.size() || c >= board[0].size() || board[r][c] != word[i]) return false; @@ -127,20 +127,28 @@ class Solution { * @return {string[]} */ findWords(board, words) { - const ROWS = board.length, COLS = board[0].length; + const ROWS = board.length, + COLS = board[0].length; const res = []; const backtrack = (r, c, word, i) => { if (i === word.length) return true; - if (r < 0 || c < 0 || r >= ROWS || - c >= COLS || board[r][c] !== word[i]) return false; + if ( + r < 0 || + c < 0 || + r >= ROWS || + c >= COLS || + board[r][c] !== word[i] + ) + return false; const temp = board[r][c]; board[r][c] = '*'; - const ret = backtrack(r + 1, c, word, i + 1) || - backtrack(r - 1, c, word, i + 1) || - backtrack(r, c + 1, word, i + 1) || - backtrack(r, c - 1, word, i + 1); + const ret = + backtrack(r + 1, c, word, i + 1) || + backtrack(r - 1, c, word, i + 1) || + backtrack(r, c + 1, word, i + 1) || + backtrack(r, c - 1, word, i + 1); board[r][c] = temp; return ret; }; @@ -188,7 +196,7 @@ public class Solution { private bool Backtrack(char[][] board, int r, int c, string word, int i) { if (i == word.Length) return true; - if (r < 0 || c < 0 || r >= board.Length || + if (r < 0 || c < 0 || r >= board.Length || c >= board[0].Length || board[r][c] != word[i]) return false; @@ -282,14 +290,61 @@ class Solution { } ``` +```swift +class Solution { + func findWords(_ board: [[Character]], _ words: [String]) -> [String] { + let ROWS = board.count + let COLS = board[0].count + var res: [String] = [] + var board = board + + func backtrack(_ r: Int, _ c: Int, _ i: Int, _ word: [Character]) -> Bool { + if i == word.count { + return true + } + if r < 0 || c < 0 || r >= ROWS || c >= COLS || board[r][c] != word[i] { + return false + } + + board[r][c] = "*" + let ret = backtrack(r + 1, c, i + 1, word) || + backtrack(r - 1, c, i + 1, word) || + backtrack(r, c + 1, i + 1, word) || + backtrack(r, c - 1, i + 1, word) + board[r][c] = word[i] + return ret + } + + for word in words { + var flag = false + let wordArray = Array(word) + for r in 0.. Where $m$ is the number of rows, $n$ is the number of columns, $t$ is the maximum length of any word in the array $words$ and $s$ is the sum of the lengths of all the words. +> Where $m$ is the number of rows, $n$ is the number of columns, $t$ is the maximum length of any word in the array $words$ and $s$ is the sum of the lengths of all the words. --- @@ -321,8 +376,8 @@ class Solution: res, visit = set(), set() def dfs(r, c, node, word): - if (r < 0 or c < 0 or r >= ROWS or - c >= COLS or (r, c) in visit or + if (r < 0 or c < 0 or r >= ROWS or + c >= COLS or (r, c) in visit or board[r][c] not in node.children ): return @@ -347,7 +402,7 @@ class Solution: ``` ```java -public class TrieNode { +class TrieNode { Map children; boolean isWord; @@ -369,7 +424,7 @@ public class TrieNode { public class Solution { private Set res; private boolean[][] visit; - + public List findWords(char[][] board, String[] words) { TrieNode root = new TrieNode(); for (String word : words) { @@ -390,8 +445,8 @@ public class Solution { private void dfs(char[][] board, int r, int c, TrieNode node, String word) { int ROWS = board.length, COLS = board[0].length; - if (r < 0 || c < 0 || r >= ROWS || - c >= COLS || visit[r][c] || + if (r < 0 || c < 0 || r >= ROWS || + c >= COLS || visit[r][c] || !node.children.containsKey(board[r][c])) { return; } @@ -457,8 +512,8 @@ public: private: void dfs(vector>& board, int r, int c, TrieNode* node, string word) { int ROWS = board.size(), COLS = board[0].size(); - if (r < 0 || c < 0 || r >= ROWS || - c >= COLS || visit[r][c] || + if (r < 0 || c < 0 || r >= ROWS || + c >= COLS || visit[r][c] || !node->children.count(board[r][c])) { return; } @@ -515,13 +570,20 @@ class Solution { root.addWord(word); } - const ROWS = board.length, COLS = board[0].length; - const res = new Set(), visit = new Set(); + const ROWS = board.length, + COLS = board[0].length; + const res = new Set(), + visit = new Set(); const dfs = (r, c, node, word) => { - if (r < 0 || c < 0 || r >= ROWS || - c >= COLS || visit.has(`${r},${c}`) || - !(board[r][c] in node.children)) { + if ( + r < 0 || + c < 0 || + r >= ROWS || + c >= COLS || + visit.has(`${r},${c}`) || + !(board[r][c] in node.children) + ) { return; } @@ -542,7 +604,7 @@ class Solution { for (let r = 0; r < ROWS; r++) { for (let c = 0; c < COLS; c++) { - dfs(r, c, root, ""); + dfs(r, c, root, ''); } } @@ -590,8 +652,8 @@ public class Solution { private void Dfs(char[][] board, int r, int c, TrieNode node, string word) { int ROWS = board.Length, COLS = board[0].Length; - if (r < 0 || c < 0 || r >= ROWS || - c >= COLS || visit[r, c] || + if (r < 0 || c < 0 || r >= ROWS || + c >= COLS || visit[r, c] || !node.Children.ContainsKey(board[r][c])) { return; } @@ -712,7 +774,7 @@ class Solution { val visit = HashSet>() fun dfs(r: Int, c: Int, node: TrieNode, word: String) { - if (r < 0 || c < 0 || r >= rows || c >= cols || + if (r < 0 || c < 0 || r >= rows || c >= cols || (r to c) in visit || board[r][c] !in node.children) { return } @@ -743,14 +805,76 @@ class Solution { } ``` +```swift +class TrieNode { + var children: [Character: TrieNode] = [:] + var isWord: Bool = false + + func addWord(_ word: String) { + var current = self + for char in word { + if current.children[char] == nil { + current.children[char] = TrieNode() + } + current = current.children[char]! + } + current.isWord = true + } +} + +class Solution { + func findWords(_ board: [[Character]], _ words: [String]) -> [String] { + let root = TrieNode() + for word in words { + root.addWord(word) + } + + let ROWS = board.count + let COLS = board[0].count + var result = Set() + var visited = Set<[Int]>() + + func dfs(_ r: Int, _ c: Int, _ node: TrieNode, _ word: String) { + if r < 0 || c < 0 || r >= ROWS || c >= COLS || + visited.contains([r, c]) || node.children[board[r][c]] == nil { + return + } + + visited.insert([r, c]) + let nextNode = node.children[board[r][c]]! + let newWord = word + String(board[r][c]) + + if nextNode.isWord { + result.insert(newWord) + } + + dfs(r + 1, c, nextNode, newWord) + dfs(r - 1, c, nextNode, newWord) + dfs(r, c + 1, nextNode, newWord) + dfs(r, c - 1, nextNode, newWord) + + visited.remove([r, c]) + } + + for r in 0.. Where $m$ is the number of rows, $n$ is the number of columns, $t$ is the maximum length of any word in the array $words$ and $s$ is the sum of the lengths of all the words. +> Where $m$ is the number of rows, $n$ is the number of columns, $t$ is the maximum length of any word in the array $words$ and $s$ is the sum of the lengths of all the words. --- @@ -790,11 +914,11 @@ class Solution: return index def dfs(r, c, node): - if (r < 0 or c < 0 or r >= ROWS or - c >= COLS or board[r][c] == '*' or + if (r < 0 or c < 0 or r >= ROWS or + c >= COLS or board[r][c] == '*' or not node.children[getIndex(board[r][c])]): return - + tmp = board[r][c] board[r][c] = '*' prev = node @@ -824,7 +948,7 @@ class Solution: ``` ```java -public class TrieNode { +class TrieNode { TrieNode[] children = new TrieNode[26]; int idx = -1; int refs = 0; @@ -863,8 +987,8 @@ public class Solution { } private void dfs(char[][] board, TrieNode node, int r, int c, String[] words) { - if (r < 0 || c < 0 || r >= board.length || - c >= board[0].length || board[r][c] == '*' || + if (r < 0 || c < 0 || r >= board.length || + c >= board[0].length || board[r][c] == '*' || node.children[board[r][c] - 'a'] == null) { return; } @@ -945,8 +1069,8 @@ public: } void dfs(auto& board, TrieNode* node, int r, int c, auto& words) { - if (r < 0 || c < 0 || r >= board.size() || - c >= board[0].size() || board[r][c] == '*' || + if (r < 0 || c < 0 || r >= board.size() || + c >= board[0].size() || board[r][c] == '*' || !node->children[board[r][c] - 'a']) { return; } @@ -984,7 +1108,7 @@ class TrieNode { this.idx = -1; this.refs = 0; } - + /** * @param {string} word * @param {number} i @@ -1017,16 +1141,22 @@ class Solution { root.addWord(words[i], i); } - const ROWS = board.length, COLS = board[0].length; + const ROWS = board.length, + COLS = board[0].length; const res = []; const dfs = (r, c, node) => { - if (r < 0 || c < 0 || r >= ROWS || - c >= COLS || board[r][c] === '*' || - node.children[this.getId(board[r][c])] === null) { + if ( + r < 0 || + c < 0 || + r >= ROWS || + c >= COLS || + board[r][c] === '*' || + node.children[this.getId(board[r][c])] === null + ) { return; } - + let tmp = board[r][c]; board[r][c] = '*'; let prev = node; @@ -1039,7 +1169,7 @@ class Solution { prev.children[this.getId(tmp)] = null; node = null; board[r][c] = tmp; - return ; + return; } } @@ -1047,7 +1177,7 @@ class Solution { dfs(r - 1, c, node); dfs(r, c + 1, node); dfs(r, c - 1, node); - + board[r][c] = tmp; }; @@ -1110,8 +1240,8 @@ public class Solution { } private void Dfs(char[][] board, TrieNode node, int r, int c, string[] words) { - if (r < 0 || c < 0 || r >= board.Length || - c >= board[0].Length || board[r][c] == '*' || + if (r < 0 || c < 0 || r >= board.Length || + c >= board[0].Length || board[r][c] == '*' || node.children[board[r][c] - 'a'] == null) { return; } @@ -1180,7 +1310,7 @@ func findWords(board [][]byte, words []string) []string { var dfs func(r, c int, node *TrieNode) dfs = func(r, c int, node *TrieNode) { - if r < 0 || c < 0 || r >= rows || c >= cols || + if r < 0 || c < 0 || r >= rows || c >= cols || board[r][c] == '*' || node.children[getIndex(board[r][c])] == nil { return } @@ -1251,7 +1381,7 @@ class Solution { fun getIndex(c: Char): Int = c - 'a' fun dfs(r: Int, c: Int, node: TrieNode?) { - if (r < 0 || c < 0 || r >= rows || c >= cols || board[r][c] == '*' || + if (r < 0 || c < 0 || r >= rows || c >= cols || board[r][c] == '*' || node?.children?.get(getIndex(board[r][c])) == null) { return } @@ -1291,11 +1421,90 @@ class Solution { } ``` +```swift +class TrieNode { + var children: [TrieNode?] = Array(repeating: nil, count: 26) + var idx: Int = -1 + var refs: Int = 0 + + func addWord(_ word: String, _ i: Int) { + var cur = self + cur.refs += 1 + for c in word { + let index = Int(c.asciiValue! - Character("a").asciiValue!) + if cur.children[index] == nil { + cur.children[index] = TrieNode() + } + cur = cur.children[index]! + cur.refs += 1 + } + cur.idx = i + } +} + +class Solution { + func findWords(_ board: [[Character]], _ words: [String]) -> [String] { + let root = TrieNode() + for i in 0.. Int { + return Int(c.asciiValue! - Character("a").asciiValue!) + } + + func dfs(_ r: Int, _ c: Int, _ node: TrieNode) { + if r < 0 || c < 0 || r >= ROWS || c >= COLS || + boardCopy[r][c] == "*" || + node.children[getIndex(boardCopy[r][c])] == nil { + return + } + + let tmp = boardCopy[r][c] + boardCopy[r][c] = "*" + let prev = node + let nextNode = node.children[getIndex(tmp)]! + + if nextNode.idx != -1 { + res.append(words[nextNode.idx]) + nextNode.idx = -1 + nextNode.refs -= 1 + if nextNode.refs == 0 { + prev.children[getIndex(tmp)] = nil + boardCopy[r][c] = tmp + return + } + } + + dfs(r + 1, c, nextNode) + dfs(r - 1, c, nextNode) + dfs(r, c + 1, nextNode) + dfs(r, c - 1, nextNode) + + boardCopy[r][c] = tmp + } + + for r in 0.. Where $m$ is the number of rows, $n$ is the number of columns, $t$ is the maximum length of any word in the array $words$ and $s$ is the sum of the lengths of all the words. \ No newline at end of file +> Where $m$ is the number of rows, $n$ is the number of columns, $t$ is the maximum length of any word in the array $words$ and $s$ is the sum of the lengths of all the words. diff --git a/articles/search-for-word.md b/articles/search-for-word.md index 93fd51588..d0c1b0f6c 100644 --- a/articles/search-for-word.md +++ b/articles/search-for-word.md @@ -11,13 +11,13 @@ class Solution: def dfs(r, c, i): if i == len(word): return True - + if (min(r, c) < 0 or r >= ROWS or c >= COLS or word[i] != board[r][c] or (r, c) in path): return False - + path.add((r, c)) res = (dfs(r + 1, c, i + 1) or dfs(r - 1, c, i + 1) or @@ -25,7 +25,7 @@ class Solution: dfs(r, c - 1, i + 1)) path.remove((r, c)) return res - + for r in range(ROWS): for c in range(COLS): if dfs(r, c, 0): @@ -57,16 +57,16 @@ public class Solution { return true; } - if (r < 0 || c < 0 || r >= ROWS || c >= COLS || - board[r][c] != word.charAt(i) || + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + board[r][c] != word.charAt(i) || path.contains(new Pair<>(r, c))) { return false; } path.add(new Pair<>(r, c)); - boolean res = dfs(board, word, r + 1, c, i + 1) || + boolean res = dfs(board, word, r + 1, c, i + 1) || dfs(board, word, r - 1, c, i + 1) || - dfs(board, word, r, c + 1, i + 1) || + dfs(board, word, r, c + 1, i + 1) || dfs(board, word, r, c - 1, i + 1); path.remove(new Pair<>(r, c)); @@ -100,15 +100,15 @@ public: return true; } - if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || board[r][c] != word[i] || path.count({r, c})) { return false; } path.insert({r, c}); - bool res = dfs(board, word, r + 1, c, i + 1) || + bool res = dfs(board, word, r + 1, c, i + 1) || dfs(board, word, r - 1, c, i + 1) || - dfs(board, word, r, c + 1, i + 1) || + dfs(board, word, r, c + 1, i + 1) || dfs(board, word, r, c - 1, i + 1); path.erase({r, c}); @@ -131,16 +131,23 @@ class Solution { const dfs = (r, c, i) => { if (i === word.length) return true; - if (r < 0 || c < 0 || r >= ROWS || c >= COLS || - board[r][c] !== word[i] || path.has(`${r},${c}`)) { + if ( + r < 0 || + c < 0 || + r >= ROWS || + c >= COLS || + board[r][c] !== word[i] || + path.has(`${r},${c}`) + ) { return false; } path.add(`${r},${c}`); - const res = dfs(r + 1, c, i + 1) || - dfs(r - 1, c, i + 1) || - dfs(r, c + 1, i + 1) || - dfs(r, c - 1, i + 1); + const res = + dfs(r + 1, c, i + 1) || + dfs(r - 1, c, i + 1) || + dfs(r, c + 1, i + 1) || + dfs(r, c - 1, i + 1); path.delete(`${r},${c}`); return res; }; @@ -179,15 +186,15 @@ public class Solution { return true; } - if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || board[r][c] != word[i] || path.Contains((r, c))) { return false; } path.Add((r, c)); - bool res = DFS(board, word, r + 1, c, i + 1) || + bool res = DFS(board, word, r + 1, c, i + 1) || DFS(board, word, r - 1, c, i + 1) || - DFS(board, word, r, c + 1, i + 1) || + DFS(board, word, r, c + 1, i + 1) || DFS(board, word, r, c - 1, i + 1); path.Remove((r, c)); @@ -206,15 +213,15 @@ func exist(board [][]byte, word string) bool { if i == len(word) { return true } - if r < 0 || c < 0 || r >= rows || c >= cols || + if r < 0 || c < 0 || r >= rows || c >= cols || board[r][c] != word[i] || path[[2]int{r, c}] { return false } path[[2]int{r, c}] = true - res := dfs(r+1, c, i+1) || - dfs(r-1, c, i+1) || - dfs(r, c+1, i+1) || + res := dfs(r+1, c, i+1) || + dfs(r-1, c, i+1) || + dfs(r, c+1, i+1) || dfs(r, c-1, i+1) delete(path, [2]int{r, c}) @@ -241,7 +248,7 @@ class Solution { fun dfs(r: Int, c: Int, i: Int): Boolean { if (i == word.length) return true - if (r < 0 || c < 0 || r >= rows || c >= cols || + if (r < 0 || c < 0 || r >= rows || c >= cols || board[r][c] != word[i] || Pair(r, c) in path) { return false } @@ -268,12 +275,50 @@ class Solution { } ``` +```swift +class Solution { + func exist(_ board: [[Character]], _ word: String) -> Bool { + let ROWS = board.count + let COLS = board[0].count + var path = Set<[Int]>() + let wordArray = Array(word) + + func dfs(_ r: Int, _ c: Int, _ i: Int) -> Bool { + if i == wordArray.count { + return true + } + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + board[r][c] != wordArray[i] || path.contains([r, c])) { + return false + } + + path.insert([r, c]) + let res = dfs(r + 1, c, i + 1) || + dfs(r - 1, c, i + 1) || + dfs(r, c + 1, i + 1) || + dfs(r, c - 1, i + 1) + path.remove([r, c]) + return res + } + + for r in 0.. Where $m$ is the number of cells in the $board$ and $n$ is the length of the $word$. @@ -336,15 +381,15 @@ public class Solution { return true; } - if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || board[r][c] != word.charAt(i) || visited[r][c]) { return false; } visited[r][c] = true; - boolean res = dfs(board, word, r + 1, c, i + 1) || + boolean res = dfs(board, word, r + 1, c, i + 1) || dfs(board, word, r - 1, c, i + 1) || - dfs(board, word, r, c + 1, i + 1) || + dfs(board, word, r, c + 1, i + 1) || dfs(board, word, r, c - 1, i + 1); visited[r][c] = false; @@ -379,15 +424,15 @@ public: return true; } - if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || board[r][c] != word[i] || visited[r][c]) { return false; } visited[r][c] = true; - bool res = dfs(board, word, r + 1, c, i + 1) || + bool res = dfs(board, word, r + 1, c, i + 1) || dfs(board, word, r - 1, c, i + 1) || - dfs(board, word, r, c + 1, i + 1) || + dfs(board, word, r, c + 1, i + 1) || dfs(board, word, r, c - 1, i + 1); visited[r][c] = false; @@ -406,20 +451,29 @@ class Solution { exist(board, word) { const ROWS = board.length; const COLS = board[0].length; - const visited = Array.from({ length: ROWS }, () => Array(COLS).fill(false)); + const visited = Array.from({ length: ROWS }, () => + Array(COLS).fill(false), + ); const dfs = (r, c, i) => { if (i === word.length) return true; - if (r < 0 || c < 0 || r >= ROWS || c >= COLS || - board[r][c] !== word[i] || visited[r][c]) { + if ( + r < 0 || + c < 0 || + r >= ROWS || + c >= COLS || + board[r][c] !== word[i] || + visited[r][c] + ) { return false; } visited[r][c] = true; - const res = dfs(r + 1, c, i + 1) || - dfs(r - 1, c, i + 1) || - dfs(r, c + 1, i + 1) || - dfs(r, c - 1, i + 1); + const res = + dfs(r + 1, c, i + 1) || + dfs(r - 1, c, i + 1) || + dfs(r, c + 1, i + 1) || + dfs(r, c - 1, i + 1); visited[r][c] = false; return res; }; @@ -459,15 +513,15 @@ public class Solution { return true; } - if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || board[r][c] != word[i] || visited[r, c]) { return false; } visited[r, c] = true; - bool res = DFS(board, word, r + 1, c, i + 1) || + bool res = DFS(board, word, r + 1, c, i + 1) || DFS(board, word, r - 1, c, i + 1) || - DFS(board, word, r, c + 1, i + 1) || + DFS(board, word, r, c + 1, i + 1) || DFS(board, word, r, c - 1, i + 1); visited[r, c] = false; @@ -489,15 +543,15 @@ func exist(board [][]byte, word string) bool { if i == len(word) { return true } - if r < 0 || c < 0 || r >= rows || c >= cols || + if r < 0 || c < 0 || r >= rows || c >= cols || board[r][c] != word[i] || visited[r][c] { return false } visited[r][c] = true - res := dfs(r+1, c, i+1) || - dfs(r-1, c, i+1) || - dfs(r, c+1, i+1) || + res := dfs(r+1, c, i+1) || + dfs(r-1, c, i+1) || + dfs(r, c+1, i+1) || dfs(r, c-1, i+1) visited[r][c] = false @@ -524,15 +578,15 @@ class Solution { fun dfs(r: Int, c: Int, i: Int): Boolean { if (i == word.length) return true - if (r < 0 || c < 0 || r >= rows || c >= cols || + if (r < 0 || c < 0 || r >= rows || c >= cols || board[r][c] != word[i] || visited[r][c]) { return false } visited[r][c] = true - val res = dfs(r + 1, c, i + 1) || + val res = dfs(r + 1, c, i + 1) || dfs(r - 1, c, i + 1) || - dfs(r, c + 1, i + 1) || + dfs(r, c + 1, i + 1) || dfs(r, c - 1, i + 1) visited[r][c] = false @@ -551,12 +605,50 @@ class Solution { } ``` +```swift +class Solution { + func exist(_ board: [[Character]], _ word: String) -> Bool { + let ROWS = board.count + let COLS = board[0].count + var visited = Array(repeating: Array(repeating: false, count: COLS), count: ROWS) + let wordArray = Array(word) + + func dfs(_ r: Int, _ c: Int, _ i: Int) -> Bool { + if i == wordArray.count { + return true + } + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + board[r][c] != wordArray[i] || visited[r][c]) { + return false + } + + visited[r][c] = true + let res = dfs(r + 1, c, i + 1) || + dfs(r - 1, c, i + 1) || + dfs(r, c + 1, i + 1) || + dfs(r, c - 1, i + 1) + visited[r][c] = false + return res + } + + for r in 0.. Where $m$ is the number of cells in the $board$ and $n$ is the length of the $word$. @@ -615,7 +707,7 @@ public class Solution { if (i == word.length()) { return true; } - if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || board[r][c] != word.charAt(i) || board[r][c] == '#') { return false; } @@ -654,7 +746,7 @@ public: if (i == word.size()) { return true; } - if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || board[r][c] != word[i] || board[r][c] == '#') { return false; } @@ -683,16 +775,23 @@ class Solution { const dfs = (r, c, i) => { if (i === word.length) return true; - if (r < 0 || c < 0 || r >= ROWS || c >= COLS || - board[r][c] !== word[i] || board[r][c] === '#') { + if ( + r < 0 || + c < 0 || + r >= ROWS || + c >= COLS || + board[r][c] !== word[i] || + board[r][c] === '#' + ) { return false; } board[r][c] = '#'; - const res = dfs(r + 1, c, i + 1) || - dfs(r - 1, c, i + 1) || - dfs(r, c + 1, i + 1) || - dfs(r, c - 1, i + 1); + const res = + dfs(r + 1, c, i + 1) || + dfs(r - 1, c, i + 1) || + dfs(r, c + 1, i + 1) || + dfs(r, c - 1, i + 1); board[r][c] = word[i]; return res; }; @@ -729,7 +828,7 @@ public class Solution { if (i == word.Length) { return true; } - if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || board[r][c] != word[i] || board[r][c] == '#') { return false; } @@ -754,16 +853,16 @@ func exist(board [][]byte, word string) bool { if i == len(word) { return true } - if r < 0 || c < 0 || r >= rows || c >= cols || + if r < 0 || c < 0 || r >= rows || c >= cols || board[r][c] != word[i] || board[r][c] == '#' { return false } temp := board[r][c] board[r][c] = '#' - res := dfs(r+1, c, i+1) || - dfs(r-1, c, i+1) || - dfs(r, c+1, i+1) || + res := dfs(r+1, c, i+1) || + dfs(r-1, c, i+1) || + dfs(r, c+1, i+1) || dfs(r, c-1, i+1) board[r][c] = temp @@ -789,16 +888,16 @@ class Solution { fun dfs(r: Int, c: Int, i: Int): Boolean { if (i == word.length) return true - if (r < 0 || c < 0 || r >= rows || c >= cols || + if (r < 0 || c < 0 || r >= rows || c >= cols || board[r][c] != word[i] || board[r][c] == '#') { return false } val temp = board[r][c] board[r][c] = '#' - val res = dfs(r + 1, c, i + 1) || + val res = dfs(r + 1, c, i + 1) || dfs(r - 1, c, i + 1) || - dfs(r, c + 1, i + 1) || + dfs(r, c + 1, i + 1) || dfs(r, c - 1, i + 1) board[r][c] = temp @@ -817,11 +916,50 @@ class Solution { } ``` +```swift +class Solution { + func exist(_ board: [[Character]], _ word: String) -> Bool { + let ROWS = board.count + let COLS = board[0].count + let wordArray = Array(word) + var board = board + + func dfs(_ r: Int, _ c: Int, _ i: Int) -> Bool { + if i == wordArray.count { + return true + } + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || + board[r][c] != wordArray[i] || board[r][c] == "#") { + return false + } + + let temp = board[r][c] + board[r][c] = "#" + let res = dfs(r + 1, c, i + 1) || + dfs(r - 1, c, i + 1) || + dfs(r, c + 1, i + 1) || + dfs(r, c - 1, i + 1) + board[r][c] = temp + return res + } + + for r in 0.. Where $m$ is the number of cells in the $board$ and $n$ is the length of the $word$. \ No newline at end of file +> Where $m$ is the number of cells in the $board$ and $n$ is the length of the $word$. diff --git a/articles/search-in-a-binary-search-tree.md b/articles/search-in-a-binary-search-tree.md new file mode 100644 index 000000000..b60dc3de6 --- /dev/null +++ b/articles/search-in-a-binary-search-tree.md @@ -0,0 +1,207 @@ +## 1. Recursion + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]: + if not root or root.val == val: + return root + return self.searchBST(root.left, val) if val < root.val else self.searchBST(root.right, val) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode searchBST(TreeNode root, int val) { + if (root == null || root.val == val) { + return root; + } + return val < root.val ? searchBST(root.left, val) : searchBST(root.right, val); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* searchBST(TreeNode* root, int val) { + if (!root || root->val == val) { + return root; + } + return val < root->val ? searchBST(root->left, val) : searchBST(root->right, val); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} val + * @return {TreeNode} + */ + searchBST(root, val) { + if (!root || root.val === val) { + return root; + } + return val < root.val + ? this.searchBST(root.left, val) + : this.searchBST(root.right, val); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(H)$ +- Space complexity: $O(H)$ for recursion stack. + +> Where $H$ is the height of the given tree. + +--- + +## 2. Iteration + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def searchBST(self, root: Optional[TreeNode], val: int) -> Optional[TreeNode]: + while root and root.val != val: + root = root.left if val < root.val else root.right + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode searchBST(TreeNode root, int val) { + while (root != null && root.val != val) { + root = val < root.val ? root.left : root.right; + } + return root; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* searchBST(TreeNode* root, int val) { + while (root && root->val != val) { + root = val < root->val ? root->left : root->right; + } + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} val + * @return {TreeNode} + */ + searchBST(root, val) { + while (root != null && root.val != val) { + root = val < root.val ? root.left : root.right; + } + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(H)$ +- Space complexity: $O(1)$ extra space. + +> Where $H$ is the height of the given tree. diff --git a/articles/search-in-rotated-sorted-array-ii.md b/articles/search-in-rotated-sorted-array-ii.md index d77b4c923..507bd0a81 100644 --- a/articles/search-in-rotated-sorted-array-ii.md +++ b/articles/search-in-rotated-sorted-array-ii.md @@ -53,12 +53,20 @@ class Solution { } ``` +```csharp +public class Solution { + public bool Search(int[] nums, int target) { + return nums.Contains(target); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -168,7 +176,8 @@ class Solution { * @return {boolean} */ search(nums, target) { - let l = 0, r = nums.length - 1; + let l = 0, + r = nums.length - 1; while (l <= r) { const m = Math.floor(l + (r - l) / 2); @@ -177,13 +186,15 @@ class Solution { return true; } - if (nums[l] < nums[m]) { // Left portion + if (nums[l] < nums[m]) { + // Left portion if (nums[l] <= target && target < nums[m]) { r = m - 1; } else { l = m + 1; } - } else if (nums[l] > nums[m]) { // Right portion + } else if (nums[l] > nums[m]) { + // Right portion if (nums[m] < target && target <= nums[r]) { l = m + 1; } else { @@ -199,9 +210,40 @@ class Solution { } ``` +```csharp +public class Solution { + public bool Search(int[] nums, int target) { + int l = 0, r = nums.Length - 1; + while (l <= r) { + int m = l + (r - l) / 2; + if (nums[m] == target) { + return true; + } + + if (nums[l] < nums[m]) { + if (nums[l] <= target && target < nums[m]) { + r = m - 1; + } else { + l = m + 1; + } + } else if (nums[l] > nums[m]) { + if (nums[m] < target && target <= nums[r]) { + l = m + 1; + } else { + r = m - 1; + } + } else { + l++; + } + } + return false; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ in average case, $O(n)$ in worst case. -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(\log n)$ in average case, $O(n)$ in worst case. +- Space complexity: $O(1)$ diff --git a/articles/search-insert-position.md b/articles/search-insert-position.md index 225a7e0a1..4277480df 100644 --- a/articles/search-insert-position.md +++ b/articles/search-insert-position.md @@ -56,12 +56,25 @@ class Solution { } ``` +```csharp +public class Solution { + public int SearchInsert(int[] nums, int target) { + for (int i = 0; i < nums.Length; i++) { + if (nums[i] >= target) { + return i; + } + } + return nums.Length; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -140,7 +153,8 @@ class Solution { */ searchInsert(nums, target) { let res = nums.length; - let l = 0, r = nums.length - 1; + let l = 0, + r = nums.length - 1; while (l <= r) { const mid = Math.floor((l + r) / 2); if (nums[mid] === target) { @@ -158,12 +172,36 @@ class Solution { } ``` +```csharp +public class Solution { + public int SearchInsert(int[] nums, int target) { + int res = nums.Length; + int l = 0, r = nums.Length - 1; + + while (l <= r) { + int mid = (l + r) / 2; + if (nums[mid] == target) { + return mid; + } + if (nums[mid] > target) { + res = mid; + r = mid - 1; + } else { + l = mid + 1; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ extra space. --- @@ -235,7 +273,8 @@ class Solution { * @return {number} */ searchInsert(nums, target) { - let l = 0, r = nums.length - 1; + let l = 0, + r = nums.length - 1; while (l <= r) { const mid = Math.floor((l + r) / 2); if (nums[mid] === target) { @@ -252,12 +291,34 @@ class Solution { } ``` +```csharp +public class Solution { + public int SearchInsert(int[] nums, int target) { + int l = 0, r = nums.Length - 1; + + while (l <= r) { + int mid = (l + r) / 2; + if (nums[mid] == target) { + return mid; + } + if (nums[mid] > target) { + r = mid - 1; + } else { + l = mid + 1; + } + } + + return l; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ extra space. --- @@ -270,7 +331,7 @@ class Solution: def searchInsert(self, nums: List[int], target: int) -> int: l, r = 0, len(nums) while l < r: - m = l + ((r - l) // 2) + m = l + ((r - l) // 2) if nums[m] >= target: r = m elif nums[m] < target: @@ -321,7 +382,8 @@ class Solution { * @return {number} */ searchInsert(nums, target) { - let l = 0, r = nums.length; + let l = 0, + r = nums.length; while (l < r) { let m = l + Math.floor((r - l) / 2); if (nums[m] >= target) { @@ -335,12 +397,31 @@ class Solution { } ``` +```csharp +public class Solution { + public int SearchInsert(int[] nums, int target) { + int l = 0, r = nums.Length; + + while (l < r) { + int m = l + (r - l) / 2; + if (nums[m] >= target) { + r = m; + } else { + l = m + 1; + } + } + + return l; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ --- @@ -382,8 +463,17 @@ class Solution { */ searchInsert(nums, target) { // There is no built in Binary Search function for JS. - let index = nums.findIndex(x => x >= target); - return index !== -1 ? index : nums.length + let index = nums.findIndex((x) => x >= target); + return index !== -1 ? index : nums.length; + } +} +``` + +```csharp +public class Solution { + public int SearchInsert(int[] nums, int target) { + int idx = Array.BinarySearch(nums, target); + return idx >= 0 ? idx : ~idx; } } ``` @@ -392,5 +482,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/search-suggestions-system.md b/articles/search-suggestions-system.md new file mode 100644 index 000000000..03b06ed5f --- /dev/null +++ b/articles/search-suggestions-system.md @@ -0,0 +1,597 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]: + res = [] + m = len(searchWord) + products.sort() + + for i in range(m): + cur = [] + for w in products: + if len(w) <= i: + continue + + flag = True + for j in range(i + 1): + if w[j] != searchWord[j]: + flag = False + break + + if flag: + cur.append(w) + if len(cur) == 3: + break + + if not cur: + for j in range(i, m): + res.append([]) + break + res.append(cur) + + return res +``` + +```java +public class Solution { + public List> suggestedProducts(String[] products, String searchWord) { + List> res = new ArrayList<>(); + int m = searchWord.length(); + Arrays.sort(products); + + for (int i = 0; i < m; i++) { + List cur = new ArrayList<>(); + for (String w : products) { + if (w.length() <= i) continue; + + boolean flag = true; + for (int j = 0; j <= i; j++) { + if (w.charAt(j) != searchWord.charAt(j)) { + flag = false; + break; + } + } + + if (flag) { + cur.add(w); + if (cur.size() == 3) break; + } + } + + if (cur.isEmpty()) { + while (i < m) { + res.add(new ArrayList<>()); + i++; + } + break; + } + + res.add(cur); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> suggestedProducts(vector& products, string searchWord) { + vector> res; + int m = searchWord.size(); + sort(products.begin(), products.end()); + + for (int i = 0; i < m; i++) { + vector cur; + for (const string& w : products) { + if (w.size() <= i) continue; + + bool flag = true; + for (int j = 0; j <= i; j++) { + if (w[j] != searchWord[j]) { + flag = false; + break; + } + } + + if (flag) { + cur.push_back(w); + if (cur.size() == 3) break; + } + } + + if (cur.empty()) { + while (i < m) { + res.push_back({}); + i++; + } + break; + } + + res.push_back(cur); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} products + * @param {string} searchWord + * @return {string[][]} + */ + suggestedProducts(products, searchWord) { + let res = []; + let m = searchWord.length; + products.sort(); + + for (let i = 0; i < m; i++) { + let cur = []; + for (let w of products) { + if (w.length <= i) continue; + + let flag = true; + for (let j = 0; j <= i; j++) { + if (w[j] !== searchWord[j]) { + flag = false; + break; + } + } + + if (flag) { + cur.push(w); + if (cur.length === 3) break; + } + } + + if (cur.length === 0) { + while (i < m) { + res.push([]); + i++; + } + break; + } + + res.push(cur); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n + m * n)$ +- Space complexity: + - $O(n)$ or $O(1)$ space for the sorting algorithm. + - $O(m * w)$ space for the output array. + +> Where $n$ is the total number of characters in the string array $products$, $m$ is the length of the string $searchWord$, and $w$ is the average length of each word in the given string array. + +--- + +## 2. Sorting + Binary Search + +::tabs-start + +```python +class Solution: + def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]: + res = [] + m = len(searchWord) + products.sort() + + prefix = [] + start = 0 + + def binary_search(target, start): + l, r = start, len(products) + while l < r: + mid = l + (r - l) // 2 + if products[mid] >= target: + r = mid + else: + l = mid + 1 + return l + + for i in range(m): + prefix.append(searchWord[i]) + start = binary_search("".join(prefix), start) + + cur = [] + for j in range(start, min(start + 3, len(products))): + if products[j].startswith("".join(prefix)): + cur.append(products[j]) + else: + break + + res.append(cur) + + return res +``` + +```java +public class Solution { + public List> suggestedProducts(String[] products, String searchWord) { + List> res = new ArrayList<>(); + int m = searchWord.length(); + Arrays.sort(products); + + StringBuilder prefix = new StringBuilder(); + int start = 0; + + for (int i = 0; i < m; i++) { + prefix.append(searchWord.charAt(i)); + start = binarySearch(products, prefix.toString(), start); + + List cur = new ArrayList<>(); + for (int j = start; j < Math.min(start + 3, products.length); j++) { + if (products[j].startsWith(prefix.toString())) { + cur.add(products[j]); + } else { + break; + } + } + + res.add(cur); + } + + return res; + } + + private int binarySearch(String[] products, String target, int start) { + int l = start, r = products.length; + while (l < r) { + int mid = l + (r - l) / 2; + if (products[mid].compareTo(target) >= 0) { + r = mid; + } else { + l = mid + 1; + } + } + return l; + } +} +``` + +```cpp +class Solution { +public: + vector> suggestedProducts(vector& products, string searchWord) { + vector> res; + int m = searchWord.size(); + sort(products.begin(), products.end()); + + string prefix = ""; + int start = 0; + + for (int i = 0; i < m; i++) { + prefix += searchWord[i]; + start = binarySearch(products, prefix, start); + + vector cur; + for (int j = start; j < min(start + 3, (int)products.size()); j++) { + if (products[j].substr(0, prefix.size()) == prefix) { + cur.push_back(products[j]); + } else { + break; + } + } + + res.push_back(cur); + } + + return res; + } + +private: + int binarySearch(vector& products, string target, int start) { + int l = start, r = products.size(); + while (l < r) { + int mid = l + (r - l) / 2; + if (products[mid] >= target) { + r = mid; + } else { + l = mid + 1; + } + } + return l; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} products + * @param {string} searchWord + * @return {string[][]} + */ + suggestedProducts(products, searchWord) { + let res = []; + let m = searchWord.length; + products.sort(); + + let prefix = []; + let start = 0; + + for (let i = 0; i < m; i++) { + prefix.push(searchWord[i]); + start = this.binarySearch(products, prefix.join(''), start); + + let cur = []; + for (let j = start; j < Math.min(start + 3, products.length); j++) { + if (products[j].startsWith(prefix.join(''))) { + cur.push(products[j]); + } else { + break; + } + } + + res.push(cur); + } + + return res; + } + + /** + * @param {string[]} products + * @param {string} target + * @param {number} start + * @return {number} + */ + binarySearch(products, target, start) { + let l = start, + r = products.length; + while (l < r) { + let mid = Math.floor(l + (r - l) / 2); + if (products[mid] >= target) { + r = mid; + } else { + l = mid + 1; + } + } + return l; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n + m * w * \log N)$ +- Space complexity: + - $O(n)$ or $O(1)$ space for the sorting algorithm. + - $O(m * w)$ space for the output array. + +> Where $n$ is the total number of characters in the string array $products$, $N$ is the size of the array $products$, $m$ is the length of the string $searchWord$, and $w$ is the average length of each word in the given string array. + +--- + +## 3. Sorting + Binary Search (Built-In Function) + +::tabs-start + +```python +class Solution: + def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]: + res = [] + m = len(searchWord) + products.sort() + + prefix = "" + start = 0 + for i in range(m): + prefix += searchWord[i] + start = bisect_left(products, prefix, start) + + cur = [] + for j in range(start, min(start + 3, len(products))): + if products[j].startswith(prefix): + cur.append(products[j]) + else: + break + + res.append(cur) + + return res +``` + +```cpp +class Solution { +public: + vector> suggestedProducts(vector& products, string searchWord) { + vector> res; + int m = searchWord.size(); + sort(products.begin(), products.end()); + + string prefix = ""; + int start = 0; + for (int i = 0; i < m; i++) { + prefix += searchWord[i]; + start = lower_bound(products.begin() + start, products.end(), prefix) - products.begin(); + + vector cur; + for (int j = start; j < min(start + 3, (int)products.size()); j++) { + if (products[j].find(prefix) == 0) { + cur.push_back(products[j]); + } else { + break; + } + } + + res.push_back(cur); + } + + return res; + } +}; +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n + m * w * \log N)$ +- Space complexity: + - $O(n)$ or $O(1)$ space for the sorting algorithm. + - $O(m * w)$ space for the output array. + +> Where $n$ is the total number of characters in the string array $products$, $N$ is the size of the array $products$, $m$ is the length of the string $searchWord$, and $w$ is the average length of each word in the given string array. + +--- + +## 4. Sorting + Two Pointers + +::tabs-start + +```python +class Solution: + def suggestedProducts(self, products: List[str], searchWord: str) -> List[List[str]]: + res = [] + products.sort() + + l, r = 0, len(products) - 1 + for i in range(len(searchWord)): + c = searchWord[i] + + while l <= r and (len(products[l]) <= i or products[l][i] != c): + l += 1 + while l <= r and (len(products[r]) <= i or products[r][i] != c): + r -= 1 + + res.append([]) + remain = r - l + 1 + for j in range(min(3, remain)): + res[-1].append(products[l + j]) + + return res +``` + +```java +public class Solution { + public List> suggestedProducts(String[] products, String searchWord) { + List> res = new ArrayList<>(); + Arrays.sort(products); + + int l = 0, r = products.length - 1; + for (int i = 0; i < searchWord.length(); i++) { + char c = searchWord.charAt(i); + + while (l <= r && (products[l].length() <= i || products[l].charAt(i) != c)) { + l++; + } + while (l <= r && (products[r].length() <= i || products[r].charAt(i) != c)) { + r--; + } + + List cur = new ArrayList<>(); + int remain = r - l + 1; + for (int j = 0; j < Math.min(3, remain); j++) { + cur.add(products[l + j]); + } + + res.add(cur); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> suggestedProducts(vector& products, string searchWord) { + vector> res; + sort(products.begin(), products.end()); + + int l = 0, r = products.size() - 1; + for (int i = 0; i < searchWord.size(); i++) { + char c = searchWord[i]; + + while (l <= r && (products[l].size() <= i || products[l][i] != c)) { + l++; + } + while (l <= r && (products[r].size() <= i || products[r][i] != c)) { + r--; + } + + vector cur; + int remain = r - l + 1; + for (int j = 0; j < min(3, remain); j++) { + cur.push_back(products[l + j]); + } + + res.push_back(cur); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} products + * @param {string} searchWord + * @return {string[][]} + */ + suggestedProducts(products, searchWord) { + let res = []; + products.sort(); + + let l = 0, + r = products.length - 1; + for (let i = 0; i < searchWord.length; i++) { + let c = searchWord[i]; + + while ( + l <= r && + (products[l].length <= i || products[l][i] !== c) + ) { + l++; + } + while ( + l <= r && + (products[r].length <= i || products[r][i] !== c) + ) { + r--; + } + + let cur = []; + let remain = r - l + 1; + for (let j = 0; j < Math.min(3, remain); j++) { + cur.push(products[l + j]); + } + + res.push(cur); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n + m * w + N)$ +- Space complexity: + - $O(n)$ or $O(1)$ space for the sorting algorithm. + - $O(m * w)$ space for the output array. + +> Where $n$ is the total number of characters in the string array $products$, $N$ is the size of the array $products$, $m$ is the length of the string $searchWord$, and $w$ is the average length of each word in the given string array. diff --git a/articles/seat-reservation-manager.md b/articles/seat-reservation-manager.md new file mode 100644 index 000000000..6280f7f6f --- /dev/null +++ b/articles/seat-reservation-manager.md @@ -0,0 +1,407 @@ +## 1. Brute Force + +::tabs-start + +```python +class SeatManager: + + def __init__(self, n: int): + self.seats = [False] * n + + def reserve(self) -> int: + for i in range(len(self.seats)): + if not self.seats[i]: + self.seats[i] = True + return i + 1 + + def unreserve(self, seatNumber: int) -> None: + self.seats[seatNumber - 1] = False +``` + +```java +public class SeatManager { + private boolean[] seats; + + public SeatManager(int n) { + seats = new boolean[n]; + } + + public int reserve() { + for (int i = 0; i < seats.length; i++) { + if (!seats[i]) { + seats[i] = true; + return i + 1; + } + } + return -1; + } + + public void unreserve(int seatNumber) { + seats[seatNumber - 1] = false; + } +} +``` + +```cpp +class SeatManager { +private: + vector seats; + +public: + SeatManager(int n) : seats(n, false) {} + + int reserve() { + for (int i = 0; i < seats.size(); i++) { + if (!seats[i]) { + seats[i] = true; + return i + 1; + } + } + return -1; + } + + void unreserve(int seatNumber) { + seats[seatNumber - 1] = false; + } +}; +``` + +```javascript +class SeatManager { + /** + * @param {number} n + */ + constructor(n) { + this.seats = new Array(n).fill(false); + } + + /** + * @return {number} + */ + reserve() { + for (let i = 0; i < this.seats.length; i++) { + if (!this.seats[i]) { + this.seats[i] = true; + return i + 1; + } + } + } + + /** + * @param {number} seatNumber + * @return {void} + */ + unreserve(seatNumber) { + this.seats[seatNumber - 1] = false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(n)$ time for initialization. + - $O(n)$ time for each $reserve()$ function call. + - $O(1)$ time for each $unreserve()$ function call. +- Space complexity: $O(n)$ + +--- + +## 2. Min-Heap + +::tabs-start + +```python +class SeatManager: + def __init__(self, n: int): + self.unres = list(range(1, n + 1)) + heapq.heapify(self.unres) + + def reserve(self) -> int: + return heapq.heappop(self.unres) + + def unreserve(self, seatNumber: int) -> None: + heapq.heappush(self.unres, seatNumber) +``` + +```java +public class SeatManager { + private PriorityQueue unres; + + public SeatManager(int n) { + unres = new PriorityQueue<>(); + for (int i = 1; i <= n; i++) { + unres.offer(i); + } + } + + public int reserve() { + return unres.poll(); + } + + public void unreserve(int seatNumber) { + unres.offer(seatNumber); + } +} +``` + +```cpp +class SeatManager { +private: + priority_queue, greater> unres; + +public: + SeatManager(int n) { + for (int i = 1; i <= n; i++) { + unres.push(i); + } + } + + int reserve() { + int seat = unres.top(); + unres.pop(); + return seat; + } + + void unreserve(int seatNumber) { + unres.push(seatNumber); + } +}; +``` + +```javascript +class SeatManager { + /** + * @param {number} n + */ + constructor(n) { + this.unres = new MinPriorityQueue(); + for (let i = 1; i <= n; i++) { + this.unres.enqueue(i); + } + } + + /** + * @return {number} + */ + reserve() { + return this.unres.dequeue(); + } + + /** + * @param {number} seatNumber + * @return {void} + */ + unreserve(seatNumber) { + this.unres.enqueue(seatNumber); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(n \log n)$ time for initialization. + - $O(\log n)$ time for each $reserve()$ function call. + - $O(\log n)$ time for each $unreserve()$ function call. +- Space complexity: $O(n)$ + +--- + +## 3. Min-Heap (Optimal) + +::tabs-start + +```python +class SeatManager: + def __init__(self, n: int): + self.minHeap = [] + self.nextSeat = 1 + + def reserve(self) -> int: + if self.minHeap: + return heapq.heappop(self.minHeap) + + seat = self.nextSeat + self.nextSeat += 1 + return seat + + def unreserve(self, seatNumber: int) -> None: + heapq.heappush(self.minHeap, seatNumber) +``` + +```java +public class SeatManager { + private PriorityQueue minHeap; + private int nextSeat; + + public SeatManager(int n) { + minHeap = new PriorityQueue<>(); + nextSeat = 1; + } + + public int reserve() { + if (!minHeap.isEmpty()) { + return minHeap.poll(); + } + return nextSeat++; + } + + public void unreserve(int seatNumber) { + minHeap.offer(seatNumber); + } +} +``` + +```cpp +class SeatManager { +private: + priority_queue, greater> minHeap; + int nextSeat; + +public: + SeatManager(int n) { + nextSeat = 1; + } + + int reserve() { + if (!minHeap.empty()) { + int seat = minHeap.top(); + minHeap.pop(); + return seat; + } + return nextSeat++; + } + + void unreserve(int seatNumber) { + minHeap.push(seatNumber); + } +}; +``` + +```javascript +class SeatManager { + /** + * @param {number} n + */ + constructor(n) { + this.minHeap = new MinPriorityQueue(); + this.nextSeat = 1; + } + + /** + * @return {number} + */ + reserve() { + if (!this.minHeap.isEmpty()) { + return this.minHeap.dequeue(); + } + return this.nextSeat++; + } + + /** + * @param {number} seatNumber + * @return {void} + */ + unreserve(seatNumber) { + this.minHeap.enqueue(seatNumber); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(\log n)$ time for each $reserve()$ function call. + - $O(\log n)$ time for each $unreserve()$ function call. +- Space complexity: $O(n)$ + +--- + +## 4. Ordered Set + +::tabs-start + +```python +class SeatManager: + def __init__(self, n: int): + self.available = SortedSet() + self.nextSeat = 1 + + def reserve(self) -> int: + if self.available: + return self.available.pop(0) + + seat = self.nextSeat + self.nextSeat += 1 + return seat + + def unreserve(self, seatNumber: int) -> None: + self.available.add(seatNumber) +``` + +```java +public class SeatManager { + private TreeSet available; + private int nextSeat; + + public SeatManager(int n) { + available = new TreeSet<>(); + nextSeat = 1; + } + + public int reserve() { + if (!available.isEmpty()) { + return available.pollFirst(); + } + return nextSeat++; + } + + public void unreserve(int seatNumber) { + available.add(seatNumber); + } +} +``` + +```cpp +class SeatManager { +private: + set available; + int nextSeat; + +public: + SeatManager(int n) { + nextSeat = 1; + } + + int reserve() { + if (!available.empty()) { + int seat = *available.begin(); + available.erase(available.begin()); + return seat; + } + return nextSeat++; + } + + void unreserve(int seatNumber) { + available.insert(seatNumber); + } +}; +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: + - $O(1)$ time for initialization. + - $O(\log n)$ time for each $reserve()$ function call. + - $O(\log n)$ time for each $unreserve()$ function call. +- Space complexity: $O(n)$ diff --git a/articles/sequential-digits.md b/articles/sequential-digits.md new file mode 100644 index 000000000..60f54c763 --- /dev/null +++ b/articles/sequential-digits.md @@ -0,0 +1,579 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def sequentialDigits(self, low: int, high: int) -> List[int]: + res = [] + + for num in range(low, high + 1): + s = str(num) + flag = True + for i in range(1, len(s)): + if ord(s[i]) - ord(s[i - 1]) != 1: + flag = False + break + if flag: + res.append(num) + + return res +``` + +```java +public class Solution { + public List sequentialDigits(int low, int high) { + List res = new ArrayList<>(); + for (int num = low; num <= high; num++) { + String s = String.valueOf(num); + boolean flag = true; + for (int i = 1; i < s.length(); i++) { + if (s.charAt(i) - s.charAt(i - 1) != 1) { + flag = false; + break; + } + } + if (flag) { + res.add(num); + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector sequentialDigits(int low, int high) { + vector res; + for (int num = low; num <= high; num++) { + string s = to_string(num); + bool flag = true; + for (int i = 1; i < s.size(); i++) { + if (s[i] - s[i - 1] != 1) { + flag = false; + break; + } + } + if (flag) { + res.push_back(num); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} low + * @param {number} high + * @return {number[]} + */ + sequentialDigits(low, high) { + const res = []; + for (let num = low; num <= high; num++) { + const s = num.toString(); + let flag = true; + for (let i = 1; i < s.length; i++) { + if (s.charCodeAt(i) - s.charCodeAt(i - 1) !== 1) { + flag = false; + break; + } + } + if (flag) { + res.push(num); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 2. Simulation + +::tabs-start + +```python +class Solution: + def sequentialDigits(self, low: int, high: int) -> List[int]: + res = [] + low_digit, high_digit = len(str(low)), len(str(high)) + + for digits in range(low_digit, high_digit + 1): + for start in range(1, 10): + if start + digits > 10: + break + num = start + prev = start + for i in range(digits - 1): + num = num * 10 + prev += 1 + num += prev + if low <= num <= high: + res.append(num) + return res +``` + +```java +public class Solution { + public List sequentialDigits(int low, int high) { + List res = new ArrayList<>(); + int lowDigit = String.valueOf(low).length(); + int highDigit = String.valueOf(high).length(); + + for (int digits = lowDigit; digits <= highDigit; digits++) { + for (int start = 1; start < 10; start++) { + if (start + digits > 10) { + break; + } + int num = start; + int prev = start; + for (int i = 1; i < digits; i++) { + num = num * 10 + (++prev); + } + if (num >= low && num <= high) { + res.add(num); + } + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector sequentialDigits(int low, int high) { + vector res; + int lowDigit = to_string(low).length(); + int highDigit = to_string(high).length(); + + for (int digits = lowDigit; digits <= highDigit; digits++) { + for (int start = 1; start < 10; start++) { + if (start + digits > 10) { + break; + } + int num = start; + int prev = start; + for (int i = 1; i < digits; i++) { + num = num * 10 + (++prev); + } + if (num >= low && num <= high) { + res.push_back(num); + } + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} low + * @param {number} high + * @return {number[]} + */ + sequentialDigits(low, high) { + const res = []; + const lowDigit = low.toString().length; + const highDigit = high.toString().length; + + for (let digits = lowDigit; digits <= highDigit; digits++) { + for (let start = 1; start < 10; start++) { + if (start + digits > 10) { + break; + } + let num = start; + let prev = start; + for (let i = 1; i < digits; i++) { + num = num * 10 + ++prev; + } + if (num >= low && num <= high) { + res.push(num); + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +> Since, we have at most $36$ valid numbers as per the given constraints. + +--- + +## 3. Breadth First Search + +::tabs-start + +```python +class Solution: + def sequentialDigits(self, low: int, high: int) -> List[int]: + res = [] + queue = deque(range(1, 10)) + + while queue: + n = queue.popleft() + if n > high: + continue + if low <= n <= high: + res.append(n) + ones = n % 10 + if ones < 9: + queue.append(n * 10 + (ones + 1)) + + return res +``` + +```java +public class Solution { + public List sequentialDigits(int low, int high) { + List res = new ArrayList<>(); + Queue queue = new LinkedList<>(); + + for (int i = 1; i < 10; i++) { + queue.add(i); + } + + while (!queue.isEmpty()) { + int n = queue.poll(); + if (n > high) { + continue; + } + if (n >= low && n <= high) { + res.add(n); + } + int ones = n % 10; + if (ones < 9) { + queue.add(n * 10 + (ones + 1)); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector sequentialDigits(int low, int high) { + vector res; + queue queue; + + for (int i = 1; i < 10; i++) { + queue.push(i); + } + + while (!queue.empty()) { + int n = queue.front(); + queue.pop(); + + if (n > high) { + continue; + } + if (n >= low && n <= high) { + res.push_back(n); + } + int ones = n % 10; + if (ones < 9) { + queue.push(n * 10 + (ones + 1)); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} low + * @param {number} high + * @return {number[]} + */ + sequentialDigits(low, high) { + const res = []; + const queue = new Queue(); + for (let i = 1; i < 9; i++) { + queue.push(i); + } + + while (!queue.isEmpty()) { + const n = queue.pop(); + if (n > high) { + continue; + } + if (n >= low && n <= high) { + res.push(n); + } + const ones = n % 10; + if (ones < 9) { + queue.push(n * 10 + (ones + 1)); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +> Since, we have at most $36$ valid numbers as per the given constraints. + +--- + +## 4. Depth First Search + +::tabs-start + +```python +class Solution: + def sequentialDigits(self, low: int, high: int) -> List[int]: + res = [] + + def dfs(num): + if num > high: + return + if low <= num <= high: + res.append(num) + last_digit = num % 10 + if last_digit < 9: + dfs(num * 10 + (last_digit + 1)) + + for i in range(1, 10): + dfs(i) + + return sorted(res) +``` + +```java +public class Solution { + public List sequentialDigits(int low, int high) { + List res = new ArrayList<>(); + + for (int i = 1; i < 10; i++) { + dfs(i, low, high, res); + } + + Collections.sort(res); + return res; + } + + private void dfs(int num, int low, int high, List res) { + if (num > high) { + return; + } + if (num >= low) { + res.add(num); + } + int lastDigit = num % 10; + if (lastDigit < 9) { + dfs(num * 10 + (lastDigit + 1), low, high, res); + } + } +} +``` + +```cpp +class Solution { +public: + vector sequentialDigits(int low, int high) { + vector res; + for (int i = 1; i < 10; i++) { + dfs(i, low, high, res); + } + sort(res.begin(), res.end()); + return res; + } + +private: + void dfs(int num, int low, int high, vector& res) { + if (num > high) { + return; + } + if (num >= low) { + res.push_back(num); + } + int lastDigit = num % 10; + if (lastDigit < 9) { + dfs(num * 10 + (lastDigit + 1), low, high, res); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} low + * @param {number} high + * @return {number[]} + */ + sequentialDigits(low, high) { + const res = []; + + const dfs = (num) => { + if (num > high) { + return; + } + if (num >= low) { + res.push(num); + } + const lastDigit = num % 10; + if (lastDigit < 9) { + dfs(num * 10 + (lastDigit + 1)); + } + }; + + for (let i = 1; i < 10; i++) { + dfs(i); + } + + return res.sort((a, b) => a - b); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +> Since, we have at most $36$ valid numbers as per the given constraints. + +--- + +## 5. Sliding Window + +::tabs-start + +```python +class Solution: + def sequentialDigits(self, low: int, high: int) -> List[int]: + nums = "123456789" + res = [] + for d in range(2, 10): + for i in range(9 - d + 1): + num = int(nums[i: i + d]) + if num > high: + break + if low <= num <= high: + res.append(num) + return res +``` + +```java +public class Solution { + public List sequentialDigits(int low, int high) { + String nums = "123456789"; + List res = new ArrayList<>(); + + for (int d = 2; d <= 9; d++) { + for (int i = 0; i <= 9 - d; i++) { + int num = Integer.parseInt(nums.substring(i, i + d)); + if (num > high) { + break; + } + if (num >= low && num <= high) { + res.add(num); + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector sequentialDigits(int low, int high) { + string nums = "123456789"; + vector res; + + for (int d = 2; d <= 9; d++) { + for (int i = 0; i <= 9 - d; i++) { + int num = stoi(nums.substr(i, d)); + if (num > high) { + break; + } + if (num >= low && num <= high) { + res.push_back(num); + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} low + * @param {number} high + * @return {number[]} + */ + sequentialDigits(low, high) { + const nums = '123456789'; + const res = []; + + for (let d = 2; d <= 9; d++) { + for (let i = 0; i <= 9 - d; i++) { + const num = parseInt(nums.substring(i, i + d)); + if (num > high) { + break; + } + if (num >= low && num <= high) { + res.push(num); + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +> Since, we have at most $36$ valid numbers as per the given constraints. diff --git a/articles/serialize-and-deserialize-binary-tree.md b/articles/serialize-and-deserialize-binary-tree.md index 01a3b0d41..9d53a481b 100644 --- a/articles/serialize-and-deserialize-binary-tree.md +++ b/articles/serialize-and-deserialize-binary-tree.md @@ -11,7 +11,7 @@ # self.right = right class Codec: - + # Encodes a tree to a single string. def serialize(self, root: Optional[TreeNode]) -> str: res = [] @@ -26,7 +26,7 @@ class Codec: dfs(root) return ",".join(res) - + # Decodes your encoded data to tree. def deserialize(self, data: str) -> Optional[TreeNode]: vals = data.split(",") @@ -63,7 +63,7 @@ class Codec: */ public class Codec { - + // Encodes a tree to a single string. public String serialize(TreeNode root) { List res = new ArrayList<>(); @@ -253,7 +253,7 @@ class Codec { */ public class Codec { - + // Encodes a tree to a single string. public string Serialize(TreeNode root) { List res = new List(); @@ -401,12 +401,67 @@ class Codec { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init(_ val: Int) { + * self.val = val + * self.left = nil + * self.right = nil + * } + * } + */ + +class Codec { + + func serialize(_ root: TreeNode?) -> String { + var res = [String]() + + func dfs(_ node: TreeNode?) { + guard let node = node else { + res.append("N") + return + } + res.append("\(node.val)") + dfs(node.left) + dfs(node.right) + } + + dfs(root) + return res.joined(separator: ",") + } + + func deserialize(_ data: String) -> TreeNode? { + var vals = data.split(separator: ",").map { String($0) } + var i = 0 + + func dfs() -> TreeNode? { + if vals[i] == "N" { + i += 1 + return nil + } + let node = TreeNode(Int(vals[i])!) + i += 1 + node.left = dfs() + node.right = dfs() + return node + } + + return dfs() + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -423,7 +478,7 @@ class Codec { # self.right = right class Codec: - + # Encodes a tree to a single string. def serialize(self, root: Optional[TreeNode]) -> str: if not root: @@ -439,7 +494,7 @@ class Codec: queue.append(node.left) queue.append(node.right) return ",".join(res) - + # Decodes your encoded data to tree. def deserialize(self, data: str) -> Optional[TreeNode]: vals = data.split(",") @@ -486,7 +541,7 @@ public class Codec { StringBuilder res = new StringBuilder(); Queue queue = new LinkedList<>(); queue.add(root); - + while (!queue.isEmpty()) { TreeNode node = queue.poll(); if (node == null) { @@ -612,7 +667,7 @@ class Codec { * @return {string} */ serialize(root) { - if (!root) return "N"; + if (!root) return 'N'; const res = []; const queue = new Queue(); queue.push(root); @@ -620,14 +675,14 @@ class Codec { while (!queue.isEmpty()) { const node = queue.pop(); if (!node) { - res.push("N"); + res.push('N'); } else { res.push(node.val); queue.push(node.left); queue.push(node.right); } } - return res.join(","); + return res.join(','); } /** @@ -637,20 +692,20 @@ class Codec { * @return {TreeNode} */ deserialize(data) { - const vals = data.split(","); - if (vals[0] === "N") return null; + const vals = data.split(','); + if (vals[0] === 'N') return null; const root = new TreeNode(parseInt(vals[0])); const queue = new Queue([root]); let index = 1; while (!queue.isEmpty()) { const node = queue.pop(); - if (vals[index] !== "N") { + if (vals[index] !== 'N') { node.left = new TreeNode(parseInt(vals[index])); queue.push(node.left); } index++; - if (vals[index] !== "N") { + if (vals[index] !== 'N') { node.right = new TreeNode(parseInt(vals[index])); queue.push(node.right); } @@ -771,7 +826,7 @@ func (this *Codec) deserialize(data string) *TreeNode { if vals[0] == "N" { return nil } - + rootVal, _ := strconv.Atoi(vals[0]) root := &TreeNode{Val: rootVal} queue := []*TreeNode{root} @@ -863,9 +918,79 @@ class Codec { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init(_ val: Int) { + * self.val = val + * self.left = nil + * self.right = nil + * } + * } + */ + +class Codec { + + func serialize(_ root: TreeNode?) -> String { + guard let root = root else { + return "N" + } + + var res = [String]() + var queue: Deque = [root] + + while !queue.isEmpty { + let node = queue.removeFirst() + if let node = node { + res.append("\(node.val)") + queue.append(node.left) + queue.append(node.right) + } else { + res.append("N") + } + } + + return res.joined(separator: ",") + } + + func deserialize(_ data: String) -> TreeNode? { + let vals = data.split(separator: ",").map { String($0) } + guard vals[0] != "N" else { + return nil + } + + let root = TreeNode(Int(vals[0])!) + var queue: Deque = [root] + var index = 1 + + while !queue.isEmpty { + let node = queue.popFirst()! + + if vals[index] != "N" { + node.left = TreeNode(Int(vals[index])!) + queue.append(node.left!) + } + index += 1 + + if vals[index] != "N" { + node.right = TreeNode(Int(vals[index])!) + queue.append(node.right!) + } + index += 1 + } + + return root + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/set-mismatch.md b/articles/set-mismatch.md index f29e54444..8b5f7037a 100644 --- a/articles/set-mismatch.md +++ b/articles/set-mismatch.md @@ -13,12 +13,12 @@ class Solution: for num in nums: if num == i: cnt += 1 - + if cnt == 0: res[1] = i elif cnt == 2: res[0] = i - + return res ``` @@ -109,8 +109,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -129,9 +129,9 @@ class Solution: res[0] = nums[i] elif nums[i] - nums[i - 1] == 2: res[1] = nums[i] - 1 - + if nums[-1] != len(nums): - res[1] = len(nums) + res[1] = len(nums) return res ``` @@ -210,8 +210,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -230,7 +230,7 @@ class Solution: res[1] = i if count[i] == 2: res[0] = i - + return res ``` @@ -318,8 +318,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -337,7 +337,7 @@ class Solution: nums[num - 1] *= -1 if nums[num - 1] > 0: res[0] = num - + for i, num in enumerate(nums): if num > 0 and i + 1 != res[0]: res[1] = i + 1 @@ -431,8 +431,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -450,7 +450,7 @@ class Solution: for i in range(1, N + 1): x += nums[i - 1] - i y += nums[i - 1]**2 - i**2 - + missing = (y - x**2) // (2 * x) duplicate = missing + x return [duplicate, missing] @@ -522,9 +522,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ - +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -539,11 +538,11 @@ class Solution: # a ^ a = 0 # xorr = (1 ^ 2 ^ ... N) ^ (nums[0] ^ nums[1] ^ ... nums[N - 1]) # xorr = missing ^ duplicate - xorr = 0 + xorr = 0 for i in range(1, N + 1): xorr ^= i xorr ^= nums[i - 1] - + # bit that is set in only one number among (duplicate, missing), # will be set in (duplicate ^ missing) # take rightMost set bit for simplicity @@ -557,12 +556,12 @@ class Solution: x ^= i else: y ^= i - + if nums[i - 1] & rightMostBit: x ^= nums[i - 1] else: y ^= nums[i - 1] - + # identify the duplicate number from x and y for num in nums: if num == x: @@ -577,7 +576,7 @@ public class Solution { // a ^ a = 0 // xorr = (1 ^ 2 ^ ... N) ^ (nums[0] ^ nums[1] ^ ... nums[N - 1]) // xorr = missing ^ duplicate - int xorr = 0; + int xorr = 0; for (int i = 1; i <= N; i++) { xorr ^= i; xorr ^= nums[i - 1]; @@ -624,7 +623,7 @@ public: // a ^ a = 0 // xorr = (1 ^ 2 ^ ... N) ^ (nums[0] ^ nums[1] ^ ... nums[N - 1]) // xorr = missing ^ duplicate - int xorr = 0; + int xorr = 0; for (int i = 1; i <= N; i++) { xorr ^= i; xorr ^= nums[i - 1]; @@ -687,7 +686,8 @@ class Solution { // divide numbers (from nums, from [1, N]) into two sets w.r.t the rightMostBit // xorr the numbers of these sets independently - let x = 0, y = 0; + let x = 0, + y = 0; for (let i = 1; i <= N; i++) { if (i & rightMostBit) { x ^= i; @@ -717,5 +717,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/set-zeroes-in-matrix.md b/articles/set-zeroes-in-matrix.md index 905883b5c..262d6b526 100644 --- a/articles/set-zeroes-in-matrix.md +++ b/articles/set-zeroes-in-matrix.md @@ -87,8 +87,9 @@ class Solution { * @return {void} */ setZeroes(matrix) { - const ROWS = matrix.length, COLS = matrix[0].length; - const mark = matrix.map(row => [...row]); + const ROWS = matrix.length, + COLS = matrix[0].length; + const mark = matrix.map((row) => [...row]); for (let r = 0; r < ROWS; r++) { for (let c = 0; c < COLS; c++) { @@ -208,12 +209,41 @@ class Solution { } ``` +```swift +class Solution { + func setZeroes(_ matrix: inout [[Int]]) { + let rows = matrix.count + let cols = matrix[0].count + var mark = matrix + + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns. @@ -303,7 +333,8 @@ class Solution { * @return {void} */ setZeroes(matrix) { - const rows = matrix.length, cols = matrix[0].length; + const rows = matrix.length, + cols = matrix[0].length; const rowZero = Array(rows).fill(false); const colZero = Array(cols).fill(false); @@ -407,12 +438,40 @@ class Solution { } ``` +```swift +class Solution { + func setZeroes(_ matrix: inout [[Int]]) { + let rows = matrix.count + let cols = matrix[0].count + var rowFlags = Array(repeating: false, count: rows) + var colFlags = Array(repeating: false, count: cols) + + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns. @@ -544,7 +603,7 @@ class Solution { */ setZeroes(matrix) { const ROWS = matrix.length; - const COLS = matrix[0].length; + const COLS = matrix[0].length; let rowZero = false; for (let r = 0; r < ROWS; r++) { @@ -708,11 +767,54 @@ class Solution { } ``` +```swift +class Solution { + func setZeroes(_ matrix: inout [[Int]]) { + let ROWS = matrix.count + let COLS = matrix[0].count + var rowZero = false + + for r in 0.. 0 { + matrix[r][0] = 0 + } else { + rowZero = true + } + } + } + } + + for r in 1.. Where $m$ is the number of rows and $n$ is the number of columns. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns. diff --git a/articles/shift-2d-grid.md b/articles/shift-2d-grid.md new file mode 100644 index 000000000..ec5a6301b --- /dev/null +++ b/articles/shift-2d-grid.md @@ -0,0 +1,506 @@ +## 1. Simulation (Extra Space) + +::tabs-start + +```python +class Solution: + def shiftGrid(self, grid: List[List[int]], k: int) -> List[List[int]]: + m, n = len(grid), len(grid[0]) + + while k: + cur = [[0] * n for _ in range(m)] + + for r in range(m): + for c in range(n - 1): + cur[r][c + 1] = grid[r][c] + + for r in range(m): + cur[(r + 1) % m][0] = grid[r][n - 1] + + grid = cur + k -= 1 + + return grid +``` + +```java +public class Solution { + public List> shiftGrid(int[][] grid, int k) { + int m = grid.length, n = grid[0].length; + + while (k > 0) { + int[][] cur = new int[m][n]; + + for (int r = 0; r < m; r++) { + for (int c = 0; c < n - 1; c++) { + cur[r][c + 1] = grid[r][c]; + } + } + + for (int r = 0; r < m; r++) { + cur[(r + 1) % m][0] = grid[r][n - 1]; + } + + grid = cur; + k--; + } + + List> res = new ArrayList<>(); + for (int r = 0; r < m; r++) { + List tmp = new ArrayList<>(); + for (int c = 0; c < n; c++) { + tmp.add(grid[r][c]); + } + res.add(tmp); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> shiftGrid(vector>& grid, int k) { + int m = grid.size(), n = grid[0].size(); + + while (k > 0) { + vector> cur(m, vector(n, 0)); + + for (int r = 0; r < m; r++) { + for (int c = 0; c < n - 1; c++) { + cur[r][c + 1] = grid[r][c]; + } + } + + for (int r = 0; r < m; r++) { + cur[(r + 1) % m][0] = grid[r][n - 1]; + } + + grid = cur; + k--; + } + + return grid; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @param {number} k + * @return {number[][]} + */ + shiftGrid(grid, k) { + const m = grid.length, + n = grid[0].length; + + while (k > 0) { + const cur = Array.from({ length: m }, () => Array(n).fill(0)); + + for (let r = 0; r < m; r++) { + for (let c = 0; c < n - 1; c++) { + cur[r][c + 1] = grid[r][c]; + } + } + + for (let r = 0; r < m; r++) { + cur[(r + 1) % m][0] = grid[r][n - 1]; + } + + grid = cur; + k--; + } + + return grid; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(k * m * n)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows in the grid, $n$ is the number of columns in the grid, and $k$ is the shift count. + +--- + +## 2. Simulation + +::tabs-start + +```python +class Solution: + def shiftGrid(self, grid: List[List[int]], k: int) -> List[List[int]]: + m, n = len(grid), len(grid[0]) + + while k: + prev = grid[m - 1][n - 1] + for r in range(m): + for c in range(n): + grid[r][c], prev = prev, grid[r][c] + k -= 1 + + return grid +``` + +```java +public class Solution { + public List> shiftGrid(int[][] grid, int k) { + int m = grid.length, n = grid[0].length; + + while (k > 0) { + int prev = grid[m - 1][n - 1]; + for (int r = 0; r < m; r++) { + for (int c = 0; c < n; c++) { + int temp = grid[r][c]; + grid[r][c] = prev; + prev = temp; + } + } + k--; + } + + List> res = new ArrayList<>(); + for (int r = 0; r < m; r++) { + List tmp = new ArrayList<>(); + for (int c = 0; c < n; c++) { + tmp.add(grid[r][c]); + } + res.add(tmp); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> shiftGrid(vector>& grid, int k) { + int m = grid.size(), n = grid[0].size(); + + while (k > 0) { + int prev = grid[m - 1][n - 1]; + for (int r = 0; r < m; r++) { + for (int c = 0; c < n; c++) { + swap(grid[r][c], prev); + } + } + k--; + } + + return grid; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @param {number} k + * @return {number[][]} + */ + shiftGrid(grid, k) { + const m = grid.length, + n = grid[0].length; + + while (k > 0) { + let prev = grid[m - 1][n - 1]; + for (let r = 0; r < m; r++) { + for (let c = 0; c < n; c++) { + [prev, grid[r][c]] = [grid[r][c], prev]; + } + } + k--; + } + + return grid; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(k * m * n)$ +- Space complexity: $O(m * n)$ for the output matrix. + +> Where $m$ is the number of rows in the grid, $n$ is the number of columns in the grid, and $k$ is the shift count. + +--- + +## 3. Convert to One Dimensional Array + +::tabs-start + +```python +class Solution: + def shiftGrid(self, grid: List[List[int]], k: int) -> List[List[int]]: + m, n = len(grid), len(grid[0]) + N = m * n + k %= N + + arr = [0] * N + for r in range(m): + for c in range(n): + arr[r * n + c] = grid[r][c] + + def reverse(l, r): + while l < r: + arr[l], arr[r] = arr[r], arr[l] + l += 1 + r -= 1 + + reverse(0, N - 1) + reverse(0, k - 1) + reverse(k, N - 1) + + for r in range(m): + for c in range(n): + grid[r][c] = arr[r * n + c] + + return grid +``` + +```java +public class Solution { + public List> shiftGrid(int[][] grid, int k) { + int m = grid.length, n = grid[0].length; + int N = m * n; + k %= N; + + int[] arr = new int[N]; + for (int r = 0; r < m; r++) { + for (int c = 0; c < n; c++) { + arr[r * n + c] = grid[r][c]; + } + } + + reverse(arr, 0, N - 1); + reverse(arr, 0, k - 1); + reverse(arr, k, N - 1); + + List> res = new ArrayList<>(); + for (int r = 0; r < m; r++) { + List tmp = new ArrayList<>(); + for (int c = 0; c < n; c++) { + tmp.add(arr[r * n + c]); + } + res.add(tmp); + } + return res; + } + + private void reverse(int[] arr, int l, int r) { + while (l < r) { + int temp = arr[l]; + arr[l] = arr[r]; + arr[r] = temp; + l++; + r--; + } + } +} +``` + +```cpp +class Solution { +public: + vector> shiftGrid(vector>& grid, int k) { + int m = grid.size(), n = grid[0].size(); + int N = m * n; + k %= N; + + vector arr(N); + for (int r = 0; r < m; r++) { + for (int c = 0; c < n; c++) { + arr[r * n + c] = grid[r][c]; + } + } + + reverse(arr.begin(), arr.end()); + reverse(arr.begin(), arr.begin() + k); + reverse(arr.begin() + k, arr.end()); + + for (int r = 0; r < m; r++) { + for (int c = 0; c < n; c++) { + grid[r][c] = arr[r * n + c]; + } + } + + return grid; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @param {number} k + * @return {number[][]} + */ + shiftGrid(grid, k) { + const m = grid.length, + n = grid[0].length; + const N = m * n; + k %= N; + + const arr = new Array(N); + for (let r = 0; r < m; r++) { + for (let c = 0; c < n; c++) { + arr[r * n + c] = grid[r][c]; + } + } + + const reverse = (l, r) => { + while (l < r) { + [arr[l], arr[r]] = [arr[r], arr[l]]; + l++; + r--; + } + }; + + reverse(0, N - 1); + reverse(0, k - 1); + reverse(k, N - 1); + + for (let r = 0; r < m; r++) { + for (let c = 0; c < n; c++) { + grid[r][c] = arr[r * n + c]; + } + } + + return grid; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows in the grid and $n$ is the number of columns in the grid. + +--- + +## 4. Iteration + +::tabs-start + +```python +class Solution: + def shiftGrid(self, grid: List[List[int]], k: int) -> List[List[int]]: + M, N = len(grid), len(grid[0]) + + def posToVal(r, c): + return r * N + c + + def valToPos(v): + return [v // N, v % N] + + res = [[0] * N for _ in range(M)] + for r in range(M): + for c in range(N): + newVal = (posToVal(r, c) + k) % (M * N) + newR, newC = valToPos(newVal) + res[newR][newC] = grid[r][c] + + return res +``` + +```java +public class Solution { + public List> shiftGrid(int[][] grid, int k) { + int M = grid.length, N = grid[0].length; + int[][] arr = new int[M][N]; + + for (int r = 0; r < M; r++) { + for (int c = 0; c < N; c++) { + int newVal = (r * N + c + k) % (M * N); + int newR = newVal / N, newC = newVal % N; + arr[newR][newC] = grid[r][c]; + } + } + + List> res = new ArrayList<>(); + for (int r = 0; r < M; r++) { + List tmp = new ArrayList<>(); + for (int c = 0; c < N; c++) { + tmp.add(arr[r][c]); + } + res.add(tmp); + } + return res; + } + +} +``` + +```cpp +class Solution { +public: + vector> shiftGrid(vector>& grid, int k) { + int M = grid.size(), N = grid[0].size(); + vector> res(M, vector(N)); + + for (int r = 0; r < M; r++) { + for (int c = 0; c < N; c++) { + int newVal = (r * N + c + k) % (M * N); + int newR = newVal / N, newC = newVal % N; + res[newR][newC] = grid[r][c]; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @param {number} k + * @return {number[][]} + */ + shiftGrid(grid, k) { + const M = grid.length, + N = grid[0].length; + + const posToVal = (r, c) => r * N + c; + const valToPos = (v) => [Math.floor(v / N), v % N]; + + const res = Array.from({ length: M }, () => Array(N).fill(0)); + for (let r = 0; r < M; r++) { + for (let c = 0; c < N; c++) { + const newVal = (posToVal(r, c) + k) % (M * N); + const [newR, newC] = valToPos(newVal); + res[newR][newC] = grid[r][c]; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ + +> Where $m$ is the number of rows in the grid and $n$ is the number of columns in the grid. diff --git a/articles/shifting-letters-ii.md b/articles/shifting-letters-ii.md new file mode 100644 index 000000000..7c588f014 --- /dev/null +++ b/articles/shifting-letters-ii.md @@ -0,0 +1,485 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def shiftingLetters(self, s: str, shifts: List[List[int]]) -> str: + s = [ord(c) - ord('a') for c in s] + + for l, r, d in shifts: + for i in range(l, r + 1): + s[i] += 1 if d else -1 + s[i] %= 26 + + s = [chr(ord('a') + c) for c in s] + return "".join(s) +``` + +```java +class Solution { + public String shiftingLetters(String s, int[][] shifts) { + char[] arr = s.toCharArray(); + int[] letters = new int[arr.length]; + + for (int i = 0; i < arr.length; i++) { + letters[i] = arr[i] - 'a'; + } + + for (int[] shift : shifts) { + int l = shift[0], r = shift[1], d = shift[2]; + for (int i = l; i <= r; i++) { + letters[i] = (letters[i] + (d == 1 ? 1 : -1) + 26) % 26; + } + } + + for (int i = 0; i < arr.length; i++) { + arr[i] = (char) (letters[i] + 'a'); + } + + return new String(arr); + } +} +``` + +```cpp +class Solution { +public: + string shiftingLetters(string s, vector>& shifts) { + vector letters(s.size()); + for (int i = 0; i < s.size(); i++) { + letters[i] = s[i] - 'a'; + } + + for (const auto& shift : shifts) { + int l = shift[0], r = shift[1], d = shift[2]; + for (int i = l; i <= r; i++) { + letters[i] = (letters[i] + (d == 1 ? 1 : -1) + 26) % 26; + } + } + + for (int i = 0; i < s.size(); i++) { + s[i] = letters[i] + 'a'; + } + + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {number[][]} shifts + * @return {string} + */ + shiftingLetters(s, shifts) { + let arr = Array.from(s).map((c) => c.charCodeAt(0) - 97); + + for (const [l, r, d] of shifts) { + for (let i = l; i <= r; i++) { + arr[i] = (arr[i] + (d === 1 ? 1 : -1) + 26) % 26; + } + } + + return arr.map((c) => String.fromCharCode(c + 97)).join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m)$ +- Space complexity: $O(n)$ + +> Where $n$ is the length of the string $s$ and $m$ is the size of the array $shifts$. + +--- + +## 2. Sweep Line Algorithm + +::tabs-start + +```python +class Solution: + def shiftingLetters(self, s: str, shifts: List[List[int]]) -> str: + prefix_diff = [0] * (len(s) + 1) + + for left, right, d in shifts: + val = 1 if d == 1 else -1 + prefix_diff[left] += val + prefix_diff[right + 1] -= val + + diff = 0 + res = [ord(c) - ord("a") for c in s] + + for i in range(len(s)): + diff += prefix_diff[i] + res[i] = (diff + res[i] + 26) % 26 + + s = [chr(ord("a") + n) for n in res] + return "".join(s) +``` + +```java +class Solution { + public String shiftingLetters(String s, int[][] shifts) { + int n = s.length(); + int[] prefix_diff = new int[n + 1]; + + for (int[] shift : shifts) { + int left = shift[0], right = shift[1], d = shift[2]; + int val = d == 1 ? 1 : -1; + prefix_diff[left] += val; + prefix_diff[right + 1] -= val; + } + + int[] res = new int[n]; + for (int i = 0; i < n; i++) { + res[i] = s.charAt(i) - 'a'; + } + + int diff = 0; + for (int i = 0; i < n; i++) { + diff += prefix_diff[i]; + res[i] = (res[i] + diff % 26 + 26) % 26; + } + + StringBuilder sb = new StringBuilder(); + for (int i = 0; i < n; i++) { + sb.append((char) ('a' + res[i])); + } + + return sb.toString(); + } +} +``` + +```cpp +class Solution { +public: + string shiftingLetters(string s, vector>& shifts) { + int n = s.size(); + vector prefix_diff(n + 1, 0); + + for (auto& shift : shifts) { + int left = shift[0], right = shift[1], d = shift[2]; + int val = d == 1 ? 1 : -1; + prefix_diff[left] += val; + prefix_diff[right + 1] -= val; + } + + int diff = 0; + vector res(n); + for (int i = 0; i < n; ++i) { + res[i] = s[i] - 'a'; + } + + for (int i = 0; i < n; ++i) { + diff += prefix_diff[i]; + res[i] = (diff % 26 + res[i] + 26) % 26; + } + + for (int i = 0; i < n; ++i) { + s[i] = 'a' + res[i]; + } + + return s; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {number[][]} shifts + * @return {string} + */ + shiftingLetters(s, shifts) { + const n = s.length; + const prefix_diff = Array(n + 1).fill(0); + + for (const [left, right, d] of shifts) { + const val = d === 1 ? 1 : -1; + prefix_diff[left] += val; + prefix_diff[right + 1] -= val; + } + + let diff = 0; + const res = Array.from(s).map( + (c) => c.charCodeAt(0) - 'a'.charCodeAt(0), + ); + + for (let i = 0; i < n; i++) { + diff += prefix_diff[i]; + res[i] = ((diff % 26) + res[i] + 26) % 26; + } + + return res + .map((x) => String.fromCharCode('a'.charCodeAt(0) + x)) + .join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m)$ +- Space complexity: $O(n)$ + +> Where $n$ is the length of the string $s$ and $m$ is the size of the array $shifts$. + +--- + +## 3. Binary Indexed Tree (Fenwick Tree) + +::tabs-start + +```python +class BIT: + def __init__(self, size): + self.n = size + 2 + self.tree = [0] * self.n + + def update(self, index, delta): + index += 1 + while index < self.n: + self.tree[index] += delta + index += index & -index + + def prefix_sum(self, index): + index += 1 + total = 0 + while index > 0: + total += self.tree[index] + index -= index & -index + return total + + def range_update(self, left, right, delta): + self.update(left, delta) + self.update(right + 1, -delta) + + +class Solution: + def shiftingLetters(self, s: str, shifts: List[List[int]]) -> str: + n = len(s) + bit = BIT(n) + + for left, right, d in shifts: + delta = 1 if d == 1 else -1 + bit.range_update(left, right, delta) + + res = [] + for i in range(n): + shift = bit.prefix_sum(i) % 26 + code = (ord(s[i]) - ord('a') + shift + 26) % 26 + res.append(chr(ord('a') + code)) + + return ''.join(res) +``` + +```java +class BIT { + int[] tree; + int n; + + public BIT(int size) { + n = size + 2; + tree = new int[n]; + } + + public void update(int index, int delta) { + index++; + while (index < n) { + tree[index] += delta; + index += index & -index; + } + } + + public int prefixSum(int index) { + index++; + int sum = 0; + while (index > 0) { + sum += tree[index]; + index -= index & -index; + } + return sum; + } + + public void rangeUpdate(int left, int right, int delta) { + update(left, delta); + update(right + 1, -delta); + } +} + +public class Solution { + public String shiftingLetters(String s, int[][] shifts) { + int n = s.length(); + BIT bit = new BIT(n); + + for (int[] shift : shifts) { + int left = shift[0], right = shift[1], d = shift[2]; + int delta = d == 1 ? 1 : -1; + bit.rangeUpdate(left, right, delta); + } + + StringBuilder res = new StringBuilder(); + for (int i = 0; i < n; i++) { + int shift = bit.prefixSum(i) % 26; + int code = (s.charAt(i) - 'a' + shift + 26) % 26; + res.append((char) ('a' + code)); + } + + return res.toString(); + } +} +``` + +```cpp +class BIT { + vector tree; + int n; +public: + BIT(int size) { + n = size + 2; + tree.assign(n, 0); + } + + void update(int index, int delta) { + index++; + while (index < n) { + tree[index] += delta; + index += index & -index; + } + } + + int prefixSum(int index) { + index++; + int sum = 0; + while (index > 0) { + sum += tree[index]; + index -= index & -index; + } + return sum; + } + + void rangeUpdate(int left, int right, int delta) { + update(left, delta); + update(right + 1, -delta); + } +}; + +class Solution { +public: + string shiftingLetters(string s, vector>& shifts) { + int n = s.size(); + BIT bit(n); + + for (auto& shift : shifts) { + int left = shift[0], right = shift[1], d = shift[2]; + int delta = d == 1 ? 1 : -1; + bit.rangeUpdate(left, right, delta); + } + + string res; + for (int i = 0; i < n; i++) { + int shift = bit.prefixSum(i) % 26; + int code = (s[i] - 'a' + shift + 26) % 26; + res += char('a' + code); + } + + return res; + } +}; +``` + +```javascript +class BIT { + /** + * @constructor + * @param {number} size + */ + constructor(size) { + this.n = size + 2; + this.tree = new Array(this.n).fill(0); + } + + /** + * @param {number} index + * @param {number} delta + * @return {void} + */ + update(index, delta) { + index++; + while (index < this.n) { + this.tree[index] += delta; + index += index & -index; + } + } + + /** + * @param {number} index + * @return {number} + */ + prefixSum(index) { + index++; + let sum = 0; + while (index > 0) { + sum += this.tree[index]; + index -= index & -index; + } + return sum; + } + + /** + * @param {number} left + * @param {number} right + * @param {number} delta + * @return {void} + */ + rangeUpdate(left, right, delta) { + this.update(left, delta); + this.update(right + 1, -delta); + } +} + +class Solution { + /** + * @param {string} s + * @param {number[][]} shifts + * @return {string} + */ + shiftingLetters(s, shifts) { + const n = s.length; + const bit = new BIT(n); + for (const [left, right, d] of shifts) { + const delta = d === 1 ? 1 : -1; + bit.rangeUpdate(left, right, delta); + } + + let res = ''; + for (let i = 0; i < n; i++) { + const shift = bit.prefixSum(i) % 26; + const code = (s.charCodeAt(i) - 97 + shift + 26) % 26; + res += String.fromCharCode(97 + code); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O((m + n) * \log n)$ +- Space complexity: $O(n)$ + +> Where $n$ is the length of the string $s$ and $m$ is the size of the array $shifts$. diff --git a/articles/shortest-bridge.md b/articles/shortest-bridge.md new file mode 100644 index 000000000..11ea77be0 --- /dev/null +++ b/articles/shortest-bridge.md @@ -0,0 +1,1119 @@ +## 1. Depth First Search + Breadth First Search - I + +::tabs-start + +```python +class Solution: + def shortestBridge(self, grid: List[List[int]]) -> int: + N = len(grid) + direct = [[0, 1], [0, -1], [1, 0], [-1, 0]] + + def invalid(r, c): + return r < 0 or c < 0 or r == N or c == N + + visit = set() + + def dfs(r, c): + if invalid(r, c) or not grid[r][c] or (r, c) in visit: + return + visit.add((r, c)) + for dr, dc in direct: + dfs(r + dr, c + dc) + + def bfs(): + res, q = 0, deque(visit) + while q: + for _ in range(len(q)): + r, c = q.popleft() + for dr, dc in direct: + curR, curC = r + dr, c + dc + if invalid(curR, curC) or (curR, curC) in visit: + continue + if grid[curR][curC]: + return res + q.append((curR, curC)) + visit.add((curR, curC)) + res += 1 + + for r in range(N): + for c in range(N): + if grid[r][c]: + dfs(r, c) + return bfs() +``` + +```java +public class Solution { + private int N; + private boolean[][] visited; + private final int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + public int shortestBridge(int[][] grid) { + N = grid.length; + visited = new boolean[N][N]; + + boolean found = false; + for (int r = 0; r < N; r++) { + if (found) break; + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + dfs(grid, r, c); + found = true; + break; + } + } + } + + return bfs(grid); + } + + private void dfs(int[][] grid, int r, int c) { + if (r < 0 || c < 0 || r >= N || c >= N || grid[r][c] == 0 || visited[r][c]) + return; + + visited[r][c] = true; + + for (int[] d : direct) { + dfs(grid, r + d[0], c + d[1]); + } + } + + private int bfs(int[][] grid) { + Queue q = new LinkedList<>(); + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (visited[r][c]) { + q.offer(new int[]{r, c}); + } + } + } + + int res = 0; + while (!q.isEmpty()) { + for (int i = q.size(); i > 0; i--) { + int[] cell = q.poll(); + int r = cell[0], c = cell[1]; + + for (int[] d : direct) { + int curR = r + d[0], curC = c + d[1]; + + if (curR < 0 || curC < 0 || curR >= N || curC >= N || visited[curR][curC]) + continue; + + if (grid[curR][curC] == 1) return res; + + q.offer(new int[]{curR, curC}); + visited[curR][curC] = true; + } + } + res++; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int N; + vector> visited; + vector> direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + int shortestBridge(vector>& grid) { + N = grid.size(); + visited = vector>(N, vector(N, false)); + + bool found = false; + for (int r = 0; r < N; r++) { + if (found) break; + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + dfs(grid, r, c); + found = true; + break; + } + } + } + + return bfs(grid); + } + +private: + void dfs(vector>& grid, int r, int c) { + if (r < 0 || c < 0 || r >= N || c >= N || grid[r][c] == 0 || visited[r][c]) + return; + + visited[r][c] = true; + for (auto& d : direct) { + dfs(grid, r + d[0], c + d[1]); + } + } + + int bfs(vector>& grid) { + queue> q; + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (visited[r][c]) { + q.push({r, c}); + } + } + } + + int res = 0; + while (!q.empty()) { + for (int i = q.size(); i > 0; i--) { + auto [r, c] = q.front(); q.pop(); + + for (auto& d : direct) { + int curR = r + d[0], curC = c + d[1]; + + if (curR < 0 || curC < 0 || curR >= N || curC >= N || visited[curR][curC]) + continue; + + if (grid[curR][curC] == 1) return res; + q.push({curR, curC}); + visited[curR][curC] = true; + } + } + res++; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + shortestBridge(grid) { + const N = grid.length; + const direct = [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ]; + const visited = Array.from({ length: N }, () => Array(N).fill(false)); + const q = new Queue(); + + const dfs = (r, c) => { + if ( + r < 0 || + c < 0 || + r >= N || + c >= N || + grid[r][c] === 0 || + visited[r][c] + ) + return; + visited[r][c] = true; + q.push([r, c]); + + for (const [dr, dc] of direct) { + dfs(r + dr, c + dc); + } + }; + + const bfs = () => { + let res = 0; + while (!q.isEmpty()) { + for (let i = q.size(); i > 0; i--) { + const [r, c] = q.pop(); + for (const [dr, dc] of direct) { + const curR = r + dr, + curC = c + dc; + + if ( + curR < 0 || + curC < 0 || + curR >= N || + curC >= N || + visited[curR][curC] + ) + continue; + if (grid[curR][curC] === 1) return res; + + q.push([curR, curC]); + visited[curR][curC] = true; + } + } + res++; + } + }; + + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + dfs(r, c); + return bfs(); + } + } + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 2. Depth First Search + Breadth First Search - II + +::tabs-start + +```python +class Solution: + def shortestBridge(self, grid: list[list[int]]) -> int: + N, direct = len(grid), [(0, 1), (0, -1), (1, 0), (-1, 0)] + + def dfs(r, c): + if 0 <= r < N and 0 <= c < N and grid[r][c] == 1: + grid[r][c] = 2 + q.append((r, c)) + for dr, dc in direct: + dfs(r + dr, c + dc) + + q = deque() + for r in range(N): + for c in range(N): + if grid[r][c]: + dfs(r, c) + break + if q: break + + res = 0 + while q: + for _ in range(len(q)): + r, c = q.popleft() + for dr, dc in direct: + nr, nc = r + dr, c + dc + if 0 <= nr < N and 0 <= nc < N: + if grid[nr][nc] == 1: + return res + if grid[nr][nc] == 0: + grid[nr][nc] = 2 + q.append((nr, nc)) + res += 1 +``` + +```java +public class Solution { + private int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + + public int shortestBridge(int[][] grid) { + int N = grid.length; + Queue q = new LinkedList<>(); + + boolean found = false; + for (int r = 0; r < N; r++) { + if (found) break; + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + dfs(grid, r, c, q); + found = true; + break; + } + } + } + + int res = 0; + while (!q.isEmpty()) { + for (int i = q.size(); i > 0; i--) { + int[] cell = q.poll(); + int r = cell[0], c = cell[1]; + + for (int[] d : direct) { + int nr = r + d[0], nc = c + d[1]; + + if (nr < 0 || nc < 0 || nr >= N || nc >= N) continue; + if (grid[nr][nc] == 1) return res; + + if (grid[nr][nc] == 0) { + grid[nr][nc] = 2; + q.offer(new int[]{nr, nc}); + } + } + } + res++; + } + return res; + } + + private void dfs(int[][] grid, int r, int c, Queue q) { + if (r < 0 || c < 0 || r >= grid.length || c >= grid.length || grid[r][c] != 1) + return; + + grid[r][c] = 2; + q.offer(new int[]{r, c}); + for (int[] d : direct) { + dfs(grid, r + d[0], c + d[1], q); + } + } +} +``` + +```cpp +class Solution { + vector> direct; + +public: + int shortestBridge(vector>& grid) { + int N = grid.size(); + direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + queue> q; + + bool found = false; + for (int r = 0; r < N; r++) { + if (found) break; + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + dfs(grid, r, c, q); + found = true; + break; + } + } + } + + int res = 0; + while (!q.empty()) { + for (int i = q.size(); i > 0; i--) { + auto [r, c] = q.front(); q.pop(); + + for (auto& d : direct) { + int nr = r + d[0], nc = c + d[1]; + + if (nr < 0 || nc < 0 || nr >= N || nc >= N) continue; + if (grid[nr][nc] == 1) return res; + + if (grid[nr][nc] == 0) { + grid[nr][nc] = 2; + q.push({nr, nc}); + } + } + } + res++; + } + return res; + } + +private: + void dfs(vector>& grid, int r, int c, queue>& q) { + if (r < 0 || c < 0 || r >= grid.size() || c >= grid.size() || grid[r][c] != 1) + return; + + grid[r][c] = 2; + q.push({r, c}); + for (auto& d : direct) { + dfs(grid, r + d[0], c + d[1], q); + } + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + shortestBridge(grid) { + const N = grid.length; + const direct = [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ]; + const q = new Queue(); + + const dfs = (r, c) => { + if (r < 0 || c < 0 || r >= N || c >= N || grid[r][c] !== 1) return; + grid[r][c] = 2; + q.push([r, c]); + for (const [dr, dc] of direct) { + dfs(r + dr, c + dc); + } + }; + + let found = false; + for (let r = 0; r < N; r++) { + if (found) break; + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + dfs(r, c); + found = true; + break; + } + } + } + + let res = 0; + while (!q.isEmpty()) { + for (let i = q.size(); i > 0; i--) { + const [r, c] = q.pop(); + for (const [dr, dc] of direct) { + let nr = r + dr, + nc = c + dc; + if (nr < 0 || nc < 0 || nr >= N || nc >= N) continue; + if (grid[nr][nc] === 1) return res; + if (grid[nr][nc] === 0) { + grid[nr][nc] = 2; + q.push([nr, nc]); + } + } + } + res++; + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 3. Breadth First Search + +::tabs-start + +```python +class Solution: + def shortestBridge(self, grid: list[list[int]]) -> int: + N, direct = len(grid), [(0, 1), (0, -1), (1, 0), (-1, 0)] + q2 = deque() + + found = False + for r in range(N): + if found: break + for c in range(N): + if grid[r][c] == 1: + q1 = deque([(r, c)]) + grid[r][c] = 2 + while q1: + x, y = q1.popleft() + q2.append((x, y)) + for dx, dy in direct: + nx, ny = x + dx, y + dy + if 0 <= nx < N and 0 <= ny < N and grid[nx][ny] == 1: + grid[nx][ny] = 2 + q1.append((nx, ny)) + found = True + break + + res = 0 + while q2: + for _ in range(len(q2)): + x, y = q2.popleft() + for dx, dy in direct: + nx, ny = x + dx, y + dy + if 0 <= nx < N and 0 <= ny < N: + if grid[nx][ny] == 1: + return res + if grid[nx][ny] == 0: + grid[nx][ny] = 2 + q2.append((nx, ny)) + res += 1 + + return res +``` + +```java +public class Solution { + public int shortestBridge(int[][] grid) { + int N = grid.length; + int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + Queue q2 = new LinkedList<>(); + + boolean found = false; + for (int r = 0; r < N; r++) { + if (found) break; + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + Queue q1 = new LinkedList<>(); + q1.offer(new int[]{r, c}); + grid[r][c] = 2; + + while (!q1.isEmpty()) { + int[] cell = q1.poll(); + int x = cell[0], y = cell[1]; + q2.offer(new int[]{x, y}); + + for (int[] d : direct) { + int nx = x + d[0], ny = y + d[1]; + if (nx >= 0 && ny >= 0 && nx < N && ny < N && grid[nx][ny] == 1) { + grid[nx][ny] = 2; + q1.offer(new int[]{nx, ny}); + } + } + } + found = true; + break; + } + } + } + + int res = 0; + while (!q2.isEmpty()) { + for (int i = q2.size(); i > 0; i--) { + int[] cell = q2.poll(); + int x = cell[0], y = cell[1]; + + for (int[] d : direct) { + int nx = x + d[0], ny = y + d[1]; + + if (nx >= 0 && ny >= 0 && nx < N && ny < N) { + if (grid[nx][ny] == 1) return res; + if (grid[nx][ny] == 0) { + grid[nx][ny] = 2; + q2.offer(new int[]{nx, ny}); + } + } + } + } + res++; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int shortestBridge(vector>& grid) { + int N = grid.size(); + vector> direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + queue> q2; + + bool found = false; + for (int r = 0; r < N; r++) { + if (found) break; + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + queue> q1; + q1.push({r, c}); + grid[r][c] = 2; + + while (!q1.empty()) { + auto [x, y] = q1.front(); q1.pop(); + q2.push({x, y}); + + for (auto& d : direct) { + int nx = x + d[0], ny = y + d[1]; + if (nx >= 0 && ny >= 0 && nx < N && ny < N && grid[nx][ny] == 1) { + grid[nx][ny] = 2; + q1.push({nx, ny}); + } + } + } + found = true; + break; + } + } + } + + int res = 0; + while (!q2.empty()) { + for (int i = q2.size(); i > 0; i--) { + auto [x, y] = q2.front(); q2.pop(); + + for (auto& d : direct) { + int nx = x + d[0], ny = y + d[1]; + + if (nx >= 0 && ny >= 0 && nx < N && ny < N) { + if (grid[nx][ny] == 1) return res; + if (grid[nx][ny] == 0) { + grid[nx][ny] = 2; + q2.push({nx, ny}); + } + } + } + } + res++; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + shortestBridge(grid) { + const N = grid.length; + const direct = [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ]; + const q2 = new Queue(); + + let found = false; + for (let r = 0; r < N; r++) { + if (found) break; + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + const q1 = new Queue([[r, c]]); + grid[r][c] = 2; + + while (!q1.isEmpty()) { + let [x, y] = q1.pop(); + q2.push([x, y]); + + for (let [dx, dy] of direct) { + let nx = x + dx, + ny = y + dy; + if ( + nx >= 0 && + ny >= 0 && + nx < N && + ny < N && + grid[nx][ny] === 1 + ) { + grid[nx][ny] = 2; + q1.push([nx, ny]); + } + } + } + found = true; + break; + } + } + } + + let res = 0; + while (!q2.isEmpty()) { + for (let i = q2.size(); i > 0; i--) { + const [x, y] = q2.pop(); + + for (let [dx, dy] of direct) { + let nx = x + dx, + ny = y + dy; + if (nx >= 0 && ny >= 0 && nx < N && ny < N) { + if (grid[nx][ny] === 1) return res; + if (grid[nx][ny] === 0) { + grid[nx][ny] = 2; + q2.push([nx, ny]); + } + } + } + } + res++; + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 4. Disjoint Set Union + Breadth First Search + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.parent = list(range(n)) + self.rank = [1] * n + + def find(self, node): + cur = node + while cur != self.parent[cur]: + self.parent[cur] = self.parent[self.parent[cur]] + cur = self.parent[cur] + return cur + + def union(self, u, v): + pu, pv = self.find(u), self.find(v) + if pu == pv: + return False + if self.rank[pv] > self.rank[pu]: + pu, pv = pv, pu + self.parent[pv] = pu + self.rank[pu] += self.rank[pv] + return True + +class Solution: + def shortestBridge(self, grid: list[list[int]]) -> int: + n, direct = len(grid), [(0, 1), (0, -1), (1, 0), (-1, 0)] + dsu = DSU(n * n + 1) + + def idx(r, c): + return r * n + c + 1 + + for r in range(n): + for c in range(n): + if grid[r][c] == 1: + first_island = dsu.find(idx(r, c)) + if c + 1 < n and grid[r][c + 1] == 1: + dsu.union(idx(r, c), idx(r, c + 1)) + if r + 1 < n and grid[r + 1][c] == 1: + dsu.union(idx(r, c), idx(r + 1, c)) + + q = deque() + for r in range(n): + for c in range(n): + if grid[r][c] == 1: + if dsu.find(idx(r, c)) != first_island: + continue + for dx, dy in direct: + nr, nc = r + dx, c + dy + if 0 <= nr < n and 0 <= nc < n and grid[nr][nc] == 0: + q.append((r,c)) + break + + res = 0 + while q: + for _ in range(len(q)): + r, c = q.popleft() + for dx, dy in direct: + nr, nc = r + dx, c + dy + if 0 <= nr < n and 0 <= nc < n: + if grid[nr][nc] == 1 and dsu.union(idx(r, c), idx(nr, nc)): + return res + if grid[nr][nc] == 0: + grid[nr][nc] = 1 + dsu.union(idx(r, c), idx(nr, nc)) + q.append((nr, nc)) + res += 1 +``` + +```java +class DSU { + private int[] parent, rank; + + public DSU(int n) { + parent = new int[n]; + rank = new int[n]; + for (int i = 0; i < n; i++) parent[i] = i; + Arrays.fill(rank, 1); + } + + public int find(int node) { + if (parent[node] != node) { + parent[node] = find(parent[node]); + } + return parent[node]; + } + + public boolean union(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + + if (rank[pv] > rank[pu]) { + int temp = pu; + pu = pv; + pv = temp; + } + parent[pv] = pu; + rank[pu] += rank[pv]; + return true; + } +} + +public class Solution { + private int n; + private int idx(int r, int c) { + return r * n + c + 1; + } + + public int shortestBridge(int[][] grid) { + n = grid.length; + int[][] direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + DSU dsu = new DSU(n * n + 1); + Queue q = new LinkedList<>(); + + + int firstIsland = -1; + for (int r = 0; r < n; r++) { + for (int c = 0; c < n; c++) { + if (grid[r][c] == 1) { + firstIsland = dsu.find(idx(r, c)); + if (c + 1 < n && grid[r][c + 1] == 1) + dsu.union(idx(r, c), idx(r, c + 1)); + if (r + 1 < n && grid[r + 1][c] == 1) + dsu.union(idx(r, c), idx(r + 1, c)); + } + } + } + + for (int r = 0; r < n; r++) { + for (int c = 0; c < n; c++) { + if (grid[r][c] == 1 && dsu.find(idx(r, c)) == firstIsland) { + for (int[] d : direct) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nc >= 0 && nr < n && nc < n && grid[nr][nc] == 0) { + q.offer(new int[]{r, c}); + break; + } + } + } + } + } + + int res = 0; + while (!q.isEmpty()) { + for (int i = q.size(); i > 0; i--) { + int[] cell = q.poll(); + int r = cell[0], c = cell[1]; + + for (int[] d : direct) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nc >= 0 && nr < n && nc < n) { + if (grid[nr][nc] == 1 && dsu.union(idx(r, c), idx(nr, nc))) { + return res; + } + if (grid[nr][nc] == 0) { + grid[nr][nc] = 1; + dsu.union(idx(r, c), idx(nr, nc)); + q.offer(new int[]{nr, nc}); + } + } + } + } + res++; + } + return res; + } +} +``` + +```cpp +class DSU { +public: + vector parent, rank; + + DSU(int n) : parent(n), rank(n, 1) { + for (int i = 0; i < n; i++) parent[i] = i; + } + + int find(int node) { + if (parent[node] != node) + parent[node] = find(parent[node]); + return parent[node]; + } + + bool unionSet(int u, int v) { + int pu = find(u), pv = find(v); + if (pu == pv) return false; + if (rank[pv] > rank[pu]) swap(pu, pv); + parent[pv] = pu; + rank[pu] += rank[pv]; + return true; + } +}; + +class Solution { +public: + int shortestBridge(vector>& grid) { + int N = grid.size(); + vector> direct = {{0, 1}, {0, -1}, {1, 0}, {-1, 0}}; + DSU dsu(N * N + 1); + queue> q; + + auto idx = [&](int r, int c) { + return r * N + c + 1; + }; + + int firstIsland = -1; + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1) { + firstIsland = dsu.find(idx(r, c)); + if (c + 1 < N && grid[r][c + 1] == 1) + dsu.unionSet(idx(r, c), idx(r, c + 1)); + if (r + 1 < N && grid[r + 1][c] == 1) + dsu.unionSet(idx(r, c), idx(r + 1, c)); + } + } + } + + for (int r = 0; r < N; r++) { + for (int c = 0; c < N; c++) { + if (grid[r][c] == 1 && dsu.find(idx(r, c)) == firstIsland) { + for (auto& d : direct) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nc >= 0 && nr < N && nc < N && grid[nr][nc] == 0) { + q.push({r, c}); + break; + } + } + } + } + } + + int res = 0; + while (!q.empty()) { + for (int i = q.size(); i > 0; i--) { + auto [r, c] = q.front();q.pop(); + for (auto& d : direct) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nc >= 0 && nr < N && nc < N) { + if (grid[nr][nc] == 1 && dsu.unionSet(idx(r, c), idx(nr, nc))) + return res; + if (grid[nr][nc] == 0) { + grid[nr][nc] = 1; + dsu.unionSet(idx(r, c), idx(nr, nc)); + q.push({nr, nc}); + } + } + } + } + res++; + } + return res; + } +}; +``` + +```javascript +class DSU { + /** + * @constructor + * @param {number} n + */ + constructor(n) { + this.parent = Array.from({ length: n }, (_, i) => i); + this.rank = Array(n).fill(1); + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.parent[node] !== node) { + this.parent[node] = this.find(this.parent[node]); + } + return this.parent[node]; + } + + /** + * @param {number} u + * @param {number} v + * @return {boolean} + */ + union(u, v) { + let pu = this.find(u), + pv = this.find(v); + if (pu === pv) return false; + + if (this.rank[pv] > this.rank[pu]) [pu, pv] = [pv, pu]; + this.parent[pv] = pu; + this.rank[pu] += this.rank[pv]; + return true; + } +} + +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + shortestBridge(grid) { + const N = grid.length; + const direct = [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ]; + const dsu = new DSU(N * N + 1); + const q = new Queue(); + + const idx = (r, c) => r * N + c + 1; + + let firstIsland = -1; + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1) { + firstIsland = dsu.find(idx(r, c)); + if (c + 1 < N && grid[r][c + 1] === 1) + dsu.union(idx(r, c), idx(r, c + 1)); + if (r + 1 < N && grid[r + 1][c] === 1) + dsu.union(idx(r, c), idx(r + 1, c)); + } + } + } + + for (let r = 0; r < N; r++) { + for (let c = 0; c < N; c++) { + if (grid[r][c] === 1 && dsu.find(idx(r, c)) === firstIsland) { + for (const [dx, dy] of direct) { + let nr = r + dx, + nc = c + dy; + if ( + nr >= 0 && + nc >= 0 && + nr < N && + nc < N && + grid[nr][nc] === 0 + ) { + q.push([r, c]); + break; + } + } + } + } + } + + let res = 0; + while (!q.isEmpty()) { + for (let i = q.size(); i > 0; i--) { + const [r, c] = q.pop(); + for (let [dx, dy] of direct) { + let nr = r + dx, + nc = c + dy; + if (nr >= 0 && nc >= 0 && nr < N && nc < N) { + if ( + grid[nr][nc] === 1 && + dsu.union(idx(r, c), idx(nr, nc)) + ) { + return res; + } + if (grid[nr][nc] === 0) { + grid[nr][nc] = 1; + dsu.union(idx(r, c), idx(nr, nc)); + q.push([nr, nc]); + } + } + } + } + res++; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ diff --git a/articles/shortest-common-supersequence.md b/articles/shortest-common-supersequence.md new file mode 100644 index 000000000..3ae4cde8e --- /dev/null +++ b/articles/shortest-common-supersequence.md @@ -0,0 +1,804 @@ +## 1. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def shortestCommonSupersequence(self, str1: str, str2: str) -> str: + cache = [[None] * (len(str2) + 1) for _ in range(len(str1) + 1)] + str1 = list(str1) + str2 = list(str2) + + def dfs(i: int, j: int) -> list: + if cache[i][j] is not None: + return cache[i][j] + if i == len(str1): + cache[i][j] = str2[j:][::-1] + return cache[i][j] + if j == len(str2): + cache[i][j] = str1[i:][::-1] + return cache[i][j] + + if str1[i] == str2[j]: + res = dfs(i + 1, j + 1) + [str1[i]] + else: + s1 = dfs(i + 1, j) + s2 = dfs(i, j + 1) + if len(s1) < len(s2): + res = s1 + [str1[i]] + else: + res = s2 + [str2[j]] + + cache[i][j] = res + return res + + return ''.join(reversed(dfs(0, 0))) +``` + +```java +public class Solution { + private List[][] cache; + private int n, m; + + public String shortestCommonSupersequence(String str1, String str2) { + n = str1.length(); + m = str2.length(); + cache = new ArrayList[n + 1][m + 1]; + + List res = dfs(0, 0, str1, str2); + StringBuilder sb = new StringBuilder(); + for (int k = res.size() - 1; k >= 0; k--) sb.append(res.get(k)); + return sb.toString(); + } + + private List dfs(int i, int j, String str1, String str2) { + if (cache[i][j] != null) return cache[i][j]; + if (i == n) { + List res = new ArrayList<>(); + for (int k = m - 1; k >= j; k--) { + res.add(str2.charAt(k)); + } + cache[i][j] = res; + return res; + } + if (j == m) { + List res = new ArrayList<>(); + for (int k = n - 1; k >= i; k--) { + res.add(str1.charAt(k)); + } + cache[i][j] = res; + return res; + } + + List res; + if (str1.charAt(i) == str2.charAt(j)) { + res = new ArrayList<>(dfs(i + 1, j + 1, str1, str2)); + res.add(str1.charAt(i)); + } else { + List s1 = dfs(i + 1, j, str1, str2); + List s2 = dfs(i, j + 1, str1, str2); + + if (s1.size() < s2.size()) { + res = new ArrayList<>(s1); + res.add(str1.charAt(i)); + } else { + res = new ArrayList<>(s2); + res.add(str2.charAt(j)); + } + } + + cache[i][j] = res; + return res; + } +} +``` + +```cpp +class Solution { +public: + string shortestCommonSupersequence(const string &str1, const string &str2) { + n = str1.size(); + m = str2.size(); + cache.resize(n + 1, vector(m + 1, "")); + cacheUsed.resize(n + 1, vector(m + 1, false)); + + string res = dfs(0, 0, str1, str2); + reverse(res.begin(), res.end()); + return res; + } + +private: + int n, m; + vector> cache; + vector> cacheUsed; + + string dfs(int i, int j, const string &str1, const string &str2) { + if (cacheUsed[i][j]) { + return cache[i][j]; + } + cacheUsed[i][j] = true; + + if (i == n) { + string tail = str2.substr(j); + reverse(tail.begin(), tail.end()); + cache[i][j] = tail; + return tail; + } + if (j == m) { + string tail = str1.substr(i); + reverse(tail.begin(), tail.end()); + cache[i][j] = tail; + return tail; + } + + if (str1[i] == str2[j]) { + string temp = dfs(i + 1, j + 1, str1, str2); + temp.push_back(str1[i]); + cache[i][j] = temp; + } else { + string s1 = dfs(i + 1, j, str1, str2); + string s2 = dfs(i, j + 1, str1, str2); + if (s1.size() < s2.size()) { + s1.push_back(str1[i]); + cache[i][j] = s1; + } else { + s2.push_back(str2[j]); + cache[i][j] = s2; + } + } + return cache[i][j]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} str1 + * @param {string} str2 + * @return {string} + */ + shortestCommonSupersequence(str1, str2) { + const n = str1.length, + m = str2.length; + const cache = Array.from({ length: n + 1 }, () => + Array(m + 1).fill(null), + ); + + const dfs = (i, j) => { + if (cache[i][j] !== null) return cache[i][j]; + if (i === n) { + let arr = str2.slice(j).split(''); + arr.reverse(); + cache[i][j] = arr; + return arr; + } + if (j === m) { + let arr = str1.slice(i).split(''); + arr.reverse(); + cache[i][j] = arr; + return arr; + } + let res; + if (str1[i] === str2[j]) { + res = [...dfs(i + 1, j + 1)]; + res.push(str1[i]); + } else { + const s1 = dfs(i + 1, j); + const s2 = dfs(i, j + 1); + if (s1.length < s2.length) { + res = [...s1]; + res.push(str1[i]); + } else { + res = [...s2]; + res.push(str2[j]); + } + } + cache[i][j] = res; + return res; + }; + + return dfs(0, 0).reverse().join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m * min(n, m))$ +- Space complexity: $O(n * m * min(n, m))$ + +> Where $n$ and $m$ are the lengths of the strings $str1$ and $str2$ respectively. + +--- + +## 2. Dynamic Programming (Top-Down) + Tracing + +::tabs-start + +```python +class Solution: + def shortestCommonSupersequence(self, str1: str, str2: str) -> str: + n, m = len(str1), len(str2) + dp = [[-1] * (m + 1) for _ in range(n + 1)] + + def dfs(i, j): + if dp[i][j] != -1: + return dp[i][j] + if i == n: + dp[i][j] = m - j + return dp[i][j] + if j == m: + dp[i][j] = n - i + return dp[i][j] + if str1[i] == str2[j]: + dp[i][j] = 1 + dfs(i + 1, j + 1) + else: + dp[i][j] = 1 + min(dfs(i + 1, j), dfs(i, j + 1)) + return dp[i][j] + + dfs(0, 0) + + def build_scs(i, j): + res = [] + while i < n or j < m: + if i == n: + res.extend(str2[j:]) + break + if j == m: + res.extend(str1[i:]) + break + if str1[i] == str2[j]: + res.append(str1[i]) + i += 1 + j += 1 + elif dp[i + 1][j] < dp[i][j + 1]: + res.append(str1[i]) + i += 1 + else: + res.append(str2[j]) + j += 1 + return res + + return ''.join(build_scs(0, 0)) +``` + +```java +public class Solution { + private int[][] dp; + private int n, m; + + public String shortestCommonSupersequence(String str1, String str2) { + n = str1.length(); + m = str2.length(); + dp = new int[n + 1][m + 1]; + + for (int[] row : dp) { + Arrays.fill(row, -1); + } + + dfs(0, 0, str1, str2); + + return buildSCS(str1, str2); + } + + private int dfs(int i, int j, String str1, String str2) { + if (dp[i][j] != -1) return dp[i][j]; + if (i == n) return dp[i][j] = m - j; + if (j == m) return dp[i][j] = n - i; + + if (str1.charAt(i) == str2.charAt(j)) { + dp[i][j] = 1 + dfs(i + 1, j + 1, str1, str2); + } else { + dp[i][j] = 1 + Math.min(dfs(i + 1, j, str1, str2), dfs(i, j + 1, str1, str2)); + } + return dp[i][j]; + } + + private String buildSCS(String str1, String str2) { + StringBuilder res = new StringBuilder(); + int i = 0, j = 0; + + while (i < n || j < m) { + if (i == n) { + res.append(str2.substring(j)); + break; + } + if (j == m) { + res.append(str1.substring(i)); + break; + } + if (str1.charAt(i) == str2.charAt(j)) { + res.append(str1.charAt(i)); + i++; + j++; + } else if (dp[i + 1][j] < dp[i][j + 1]) { + res.append(str1.charAt(i)); + i++; + } else { + res.append(str2.charAt(j)); + j++; + } + } + + return res.toString(); + } +} +``` + +```cpp +class Solution { +private: + vector> dp; + int n, m; + + int dfs(int i, int j, const string& str1, const string& str2) { + if (dp[i][j] != -1) return dp[i][j]; + if (i == n) return dp[i][j] = m - j; + if (j == m) return dp[i][j] = n - i; + + if (str1[i] == str2[j]) { + dp[i][j] = 1 + dfs(i + 1, j + 1, str1, str2); + } else { + dp[i][j] = 1 + min(dfs(i + 1, j, str1, str2), dfs(i, j + 1, str1, str2)); + } + return dp[i][j]; + } + + string buildSCS(const string& str1, const string& str2) { + string res; + int i = 0, j = 0; + + while (i < n || j < m) { + if (i == n) { + res += str2.substr(j); + break; + } + if (j == m) { + res += str1.substr(i); + break; + } + if (str1[i] == str2[j]) { + res += str1[i]; + i++; + j++; + } else if (dp[i + 1][j] < dp[i][j + 1]) { + res += str1[i]; + i++; + } else { + res += str2[j]; + j++; + } + } + + return res; + } + +public: + string shortestCommonSupersequence(string str1, string str2) { + n = str1.size(); + m = str2.size(); + dp = vector>(n + 1, vector(m + 1, -1)); + + dfs(0, 0, str1, str2); + return buildSCS(str1, str2); + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} str1 + * @param {string} str2 + * @return {string} + */ + shortestCommonSupersequence(str1, str2) { + const n = str1.length, + m = str2.length; + const dp = Array.from({ length: n + 1 }, () => Array(m + 1).fill(-1)); + + const dfs = (i, j) => { + if (dp[i][j] !== -1) return dp[i][j]; + if (i === n) return (dp[i][j] = m - j); + if (j === m) return (dp[i][j] = n - i); + + if (str1[i] === str2[j]) { + dp[i][j] = 1 + dfs(i + 1, j + 1); + } else { + dp[i][j] = 1 + Math.min(dfs(i + 1, j), dfs(i, j + 1)); + } + return dp[i][j]; + }; + + dfs(0, 0); + + const buildSCS = () => { + const res = []; + let i = 0, + j = 0; + + while (i < n || j < m) { + if (i === n) { + res.push(...str2.slice(j)); + break; + } + if (j === m) { + res.push(...str1.slice(i)); + break; + } + if (str1[i] === str2[j]) { + res.push(str1[i]); + i++; + j++; + } else if (dp[i + 1][j] < dp[i][j + 1]) { + res.push(str1[i]); + i++; + } else { + res.push(str2[j]); + j++; + } + } + + return res.join(''); + }; + + return buildSCS(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ + +> Where $n$ and $m$ are the lengths of the strings $str1$ and $str2$ respectively. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def shortestCommonSupersequence(self, str1: str, str2: str) -> str: + n, m = len(str1), len(str2) + dp = [[""] * (m + 1) for _ in range(n + 1)] + + for i in range(n + 1): + for j in range(m + 1): + if i == 0: + dp[i][j] = str2[:j] + elif j == 0: + dp[i][j] = str1[:i] + elif str1[i - 1] == str2[j - 1]: + dp[i][j] = dp[i - 1][j - 1] + str1[i - 1] + else: + if len(dp[i - 1][j]) < len(dp[i][j - 1]): + dp[i][j] = dp[i - 1][j] + str1[i - 1] + else: + dp[i][j] = dp[i][j - 1] + str2[j - 1] + + return dp[n][m] +``` + +```java +public class Solution { + public String shortestCommonSupersequence(String str1, String str2) { + int n = str1.length(), m = str2.length(); + String[][] dp = new String[n + 1][m + 1]; + + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= m; j++) { + if (i == 0) { + dp[i][j] = str2.substring(0, j); + } else if (j == 0) { + dp[i][j] = str1.substring(0, i); + } else if (str1.charAt(i - 1) == str2.charAt(j - 1)) { + dp[i][j] = dp[i - 1][j - 1] + str1.charAt(i - 1); + } else { + dp[i][j] = dp[i - 1][j].length() < dp[i][j - 1].length() ? + dp[i - 1][j] + str1.charAt(i - 1) : + dp[i][j - 1] + str2.charAt(j - 1); + } + } + } + + return dp[n][m]; + } +} +``` + +```cpp +class Solution { +public: + string shortestCommonSupersequence(string str1, string str2) { + int n = str1.size(), m = str2.size(); + vector> dp(n + 1, vector(m + 1)); + + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= m; j++) { + if (i == 0) { + dp[i][j] = str2.substr(0, j); + } else if (j == 0) { + dp[i][j] = str1.substr(0, i); + } else if (str1[i - 1] == str2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + str1[i - 1]; + } else { + dp[i][j] = dp[i - 1][j].size() < dp[i][j - 1].size() ? + dp[i - 1][j] + str1[i - 1] : + dp[i][j - 1] + str2[j - 1]; + } + } + } + + return dp[n][m]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} str1 + * @param {string} str2 + * @return {string} + */ + shortestCommonSupersequence(str1, str2) { + const n = str1.length, + m = str2.length; + const dp = Array.from({ length: n + 1 }, () => Array(m + 1).fill('')); + + for (let i = 0; i <= n; i++) { + for (let j = 0; j <= m; j++) { + if (i === 0) { + dp[i][j] = str2.slice(0, j); + } else if (j === 0) { + dp[i][j] = str1.slice(0, i); + } else if (str1[i - 1] === str2[j - 1]) { + dp[i][j] = dp[i - 1][j - 1] + str1[i - 1]; + } else { + dp[i][j] = + dp[i - 1][j].length < dp[i][j - 1].length + ? dp[i - 1][j] + str1[i - 1] + : dp[i][j - 1] + str2[j - 1]; + } + } + } + + return dp[n][m]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m * min(n, m))$ +- Space complexity: $O(n * m * min(n, m))$ + +> Where $n$ and $m$ are the lengths of the strings $str1$ and $str2$ respectively. + +--- + +## 4. Dynamic Programming (Bottom-Up) + Tracing + +::tabs-start + +```python +class Solution: + def shortestCommonSupersequence(self, str1: str, str2: str) -> str: + n, m = len(str1), len(str2) + dp = [[0] * (m + 1) for _ in range(n + 1)] + + for i in range(n + 1): + for j in range(m + 1): + if i == 0: + dp[i][j] = j + elif j == 0: + dp[i][j] = i + elif str1[i - 1] == str2[j - 1]: + dp[i][j] = 1 + dp[i - 1][j - 1] + else: + dp[i][j] = 1 + min(dp[i - 1][j], dp[i][j - 1]) + + res = [] + i, j = n, m + while i > 0 and j > 0: + if str1[i - 1] == str2[j - 1]: + res.append(str1[i - 1]) + i -= 1 + j -= 1 + elif dp[i - 1][j] < dp[i][j - 1]: + res.append(str1[i - 1]) + i -= 1 + else: + res.append(str2[j - 1]) + j -= 1 + + while i > 0: + res.append(str1[i - 1]) + i -= 1 + + while j > 0: + res.append(str2[j - 1]) + j -= 1 + + return ''.join(reversed(res)) +``` + +```java +public class Solution { + public String shortestCommonSupersequence(String str1, String str2) { + int n = str1.length(), m = str2.length(); + int[][] dp = new int[n + 1][m + 1]; + + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= m; j++) { + if (i == 0) { + dp[i][j] = j; + } else if (j == 0) { + dp[i][j] = i; + } else if (str1.charAt(i - 1) == str2.charAt(j - 1)) { + dp[i][j] = 1 + dp[i - 1][j - 1]; + } else { + dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1]); + } + } + } + + StringBuilder res = new StringBuilder(); + int i = n, j = m; + while (i > 0 && j > 0) { + if (str1.charAt(i - 1) == str2.charAt(j - 1)) { + res.append(str1.charAt(i - 1)); + i--; + j--; + } else if (dp[i - 1][j] < dp[i][j - 1]) { + res.append(str1.charAt(i - 1)); + i--; + } else { + res.append(str2.charAt(j - 1)); + j--; + } + } + while (i > 0) { + res.append(str1.charAt(i - 1)); + i--; + } + while (j > 0) { + res.append(str2.charAt(j - 1)); + j--; + } + + return res.reverse().toString(); + } +} +``` + +```cpp +class Solution { +public: + string shortestCommonSupersequence(string str1, string str2) { + int n = str1.size(), m = str2.size(); + vector> dp(n + 1, vector(m + 1, 0)); + + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= m; j++) { + if (i == 0) { + dp[i][j] = j; + } else if (j == 0) { + dp[i][j] = i; + } else if (str1[i - 1] == str2[j - 1]) { + dp[i][j] = 1 + dp[i - 1][j - 1]; + } else { + dp[i][j] = 1 + min(dp[i - 1][j], dp[i][j - 1]); + } + } + } + + string res; + int i = n, j = m; + while (i > 0 && j > 0) { + if (str1[i - 1] == str2[j - 1]) { + res.push_back(str1[i - 1]); + i--; + j--; + } else if (dp[i - 1][j] < dp[i][j - 1]) { + res.push_back(str1[i - 1]); + i--; + } else { + res.push_back(str2[j - 1]); + j--; + } + } + + while (i > 0) { + res.push_back(str1[i - 1]); + i--; + } + + while (j > 0) { + res.push_back(str2[j - 1]); + j--; + } + + reverse(res.begin(), res.end()); + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} str1 + * @param {string} str2 + * @return {string} + */ + shortestCommonSupersequence(str1, str2) { + const n = str1.length, + m = str2.length; + const dp = Array.from({ length: n + 1 }, () => Array(m + 1).fill(0)); + + for (let i = 0; i <= n; i++) { + for (let j = 0; j <= m; j++) { + if (i === 0) { + dp[i][j] = j; + } else if (j === 0) { + dp[i][j] = i; + } else if (str1[i - 1] === str2[j - 1]) { + dp[i][j] = 1 + dp[i - 1][j - 1]; + } else { + dp[i][j] = 1 + Math.min(dp[i - 1][j], dp[i][j - 1]); + } + } + } + + const res = []; + let i = n, + j = m; + while (i > 0 && j > 0) { + if (str1[i - 1] === str2[j - 1]) { + res.push(str1[i - 1]); + i--; + j--; + } else if (dp[i - 1][j] < dp[i][j - 1]) { + res.push(str1[i - 1]); + i--; + } else { + res.push(str2[j - 1]); + j--; + } + } + + while (i > 0) { + res.push(str1[i - 1]); + i--; + } + + while (j > 0) { + res.push(str2[j - 1]); + j--; + } + + return res.reverse().join(''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ + +> Where $n$ and $m$ are the lengths of the strings $str1$ and $str2$ respectively. diff --git a/articles/shortest-path-in-binary-matrix.md b/articles/shortest-path-in-binary-matrix.md new file mode 100644 index 000000000..879a873cd --- /dev/null +++ b/articles/shortest-path-in-binary-matrix.md @@ -0,0 +1,623 @@ +## 1. Breadth First Search + +::tabs-start + +```python +class Solution: + def shortestPathBinaryMatrix(self, grid: list[list[int]]) -> int: + N = len(grid) + if grid[0][0] or grid[N - 1][N - 1]: + return -1 + + q = deque([(0, 0, 1)]) + visit = set((0, 0)) + direct = [(0, 1), (1, 0), (0, -1), (-1, 0), + (1, 1), (-1, -1), (1, -1), (-1, 1)] + + while q: + r, c, length = q.popleft() + if r == N - 1 and c == N - 1: + return length + + for dr, dc in direct: + nr, nc = r + dr, c + dc + if (0 <= nr < N and 0 <= nc < N and grid[nr][nc] == 0 and + (nr, nc) not in visit): + q.append((nr, nc, length + 1)) + visit.add((nr, nc)) + + return -1 +``` + +```java +public class Solution { + public int shortestPathBinaryMatrix(int[][] grid) { + int N = grid.length; + if (grid[0][0] == 1 || grid[N - 1][N - 1] == 1) return -1; + + int[][] directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}, + {1, 1}, {-1, -1}, {1, -1}, {-1, 1}}; + boolean[][] visit = new boolean[N][N]; + + Queue q = new LinkedList<>(); + q.offer(new int[]{0, 0, 1}); + visit[0][0] = true; + + while (!q.isEmpty()) { + int[] cell = q.poll(); + int r = cell[0], c = cell[1], length = cell[2]; + + if (r == N - 1 && c == N - 1) return length; + + for (int[] d : directions) { + int nr = r + d[0], nc = c + d[1]; + if (nr >= 0 && nc >= 0 && nr < N && nc < N && + grid[nr][nc] == 0 && !visit[nr][nc]) { + q.offer(new int[]{nr, nc, length + 1}); + visit[nr][nc] = true; + } + } + } + return -1; + } +} +``` + +```cpp +class Solution { +public: + int shortestPathBinaryMatrix(vector>& grid) { + int N = grid.size(); + if (grid[0][0] == 1 || grid[N - 1][N - 1] == 1) return -1; + + vector> directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}, + {1, 1}, {-1, -1}, {1, -1}, {-1, 1}}; + vector> visit(N, vector(N, false)); + + queue> q; + q.push({0, 0, 1}); + visit[0][0] = true; + + while (!q.empty()) { + auto [r, c, length] = q.front(); + q.pop(); + + if (r == N - 1 && c == N - 1) return length; + + for (auto [dr, dc] : directions) { + int nr = r + dr, nc = c + dc; + if (nr >= 0 && nc >= 0 && nr < N && nc < N && + grid[nr][nc] == 0 && !visit[nr][nc]) { + q.push({nr, nc, length + 1}); + visit[nr][nc] = true; + } + } + } + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + shortestPathBinaryMatrix(grid) { + const N = grid.length; + if (grid[0][0] === 1 || grid[N - 1][N - 1] === 1) return -1; + + const directions = [ + [0, 1], + [1, 0], + [0, -1], + [-1, 0], + [1, 1], + [-1, -1], + [1, -1], + [-1, 1], + ]; + const visit = Array.from({ length: N }, () => Array(N).fill(false)); + + const q = new Queue([[0, 0, 1]]); + visit[0][0] = true; + + while (!q.isEmpty()) { + const [r, c, length] = q.pop(); + if (r === N - 1 && c === N - 1) return length; + + for (const [dr, dc] of directions) { + const nr = r + dr, + nc = c + dc; + if ( + nr >= 0 && + nc >= 0 && + nr < N && + nc < N && + grid[nr][nc] === 0 && + !visit[nr][nc] + ) { + q.push([nr, nc, length + 1]); + visit[nr][nc] = true; + } + } + } + return -1; + } +} +``` + +```csharp +public class Solution { + public int ShortestPathBinaryMatrix(int[][] grid) { + int n = grid.Length; + if (grid[0][0] == 1 || grid[n - 1][n - 1] == 1) { + return -1; + } + + var q = new Queue<(int r, int c, int length)>(); + q.Enqueue((0, 0, 1)); + var visit = new HashSet<(int, int)> { (0, 0) }; + (int dr, int dc)[] directions = new (int, int)[] { + (0, 1), (1, 0), (0, -1), (-1, 0), + (1, 1), (-1, -1), (1, -1), (-1, 1) + }; + + while (q.Count > 0) { + var (r, c, length) = q.Dequeue(); + if (r == n - 1 && c == n - 1) { + return length; + } + + foreach (var (dr, dc) in directions) { + int nr = r + dr, nc = c + dc; + if (nr >= 0 && nr < n && nc >= 0 && nc < n + && grid[nr][nc] == 0 + && !visit.Contains((nr, nc))) { + q.Enqueue((nr, nc, length + 1)); + visit.Add((nr, nc)); + } + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 2. Breadth First Search (Overwriting the Input) + +::tabs-start + +```python +class Solution: + def shortestPathBinaryMatrix(self, grid: list[list[int]]) -> int: + N = len(grid) + direct = [0, 1, 0, -1, 0, 1, 1, -1, -1, 1] + + if grid[0][0] or grid[N - 1][N - 1]: + return -1 + + q = deque([(0, 0)]) + grid[0][0] = 1 + + while q: + r, c = q.popleft() + dist = grid[r][c] + + if r == N - 1 and c == N - 1: + return dist + + for d in range(9): + nr, nc = r + direct[d], c + direct[d + 1] + if 0 <= nr < N and 0 <= nc < N and grid[nr][nc] == 0: + grid[nr][nc] = dist + 1 + q.append((nr, nc)) + + return -1 +``` + +```java +public class Solution { + public int shortestPathBinaryMatrix(int[][] grid) { + int N = grid.length; + int[] direct = {0, 1, 0, -1, 0, 1, 1, -1, -1, 1}; + + if (grid[0][0] == 1 || grid[N - 1][N - 1] == 1) + return -1; + + Queue q = new LinkedList<>(); + q.offer(new int[]{0, 0}); + grid[0][0] = 1; + + while (!q.isEmpty()) { + int[] cell = q.poll(); + int r = cell[0], c = cell[1]; + int dist = grid[r][c]; + + if (r == N - 1 && c == N - 1) + return dist; + + for (int d = 0; d < 9; d++) { + int nr = r + direct[d], nc = c + direct[d + 1]; + + if (nr >= 0 && nc >= 0 && nr < N && nc < N && grid[nr][nc] == 0) { + grid[nr][nc] = dist + 1; + q.offer(new int[]{nr, nc}); + } + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int shortestPathBinaryMatrix(vector>& grid) { + int N = grid.size(); + int direct[10] = {0, 1, 0, -1, 0, 1, 1, -1, -1, 1}; + + if (grid[0][0] || grid[N - 1][N - 1]) + return -1; + + queue> q; + q.push({0, 0}); + grid[0][0] = 1; + + while (!q.empty()) { + auto [r, c] = q.front(); + q.pop(); + int dist = grid[r][c]; + + if (r == N - 1 && c == N - 1) + return dist; + + for (int d = 0; d < 9; d++) { + int nr = r + direct[d], nc = c + direct[d + 1]; + + if (nr >= 0 && nc >= 0 && nr < N && nc < N && grid[nr][nc] == 0) { + grid[nr][nc] = dist + 1; + q.push({nr, nc}); + } + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + shortestPathBinaryMatrix(grid) { + const N = grid.length; + const direct = [0, 1, 0, -1, 0, 1, 1, -1, -1, 1]; + + if (grid[0][0] || grid[N - 1][N - 1]) return -1; + + let q = [[0, 0]]; + grid[0][0] = 1; + + while (q.length) { + let [r, c] = q.shift(); + let dist = grid[r][c]; + + if (r === N - 1 && c === N - 1) return dist; + + for (let d = 0; d < 9; d++) { + let nr = r + direct[d], + nc = c + direct[d + 1]; + + if ( + nr >= 0 && + nc >= 0 && + nr < N && + nc < N && + grid[nr][nc] === 0 + ) { + grid[nr][nc] = dist + 1; + q.push([nr, nc]); + } + } + } + + return -1; + } +} +``` + +```csharp +public class Solution { + public int ShortestPathBinaryMatrix(int[][] grid) { + int N = grid.Length; + int[] direct = new int[]{0, 1, 0, -1, 0, 1, 1, -1, -1, 1}; + + if (grid[0][0] == 1 || grid[N - 1][N - 1] == 1) { + return -1; + } + + var q = new Queue<(int r, int c)>(); + q.Enqueue((0, 0)); + grid[0][0] = 1; + + while (q.Count > 0) { + var (r, c) = q.Dequeue(); + int dist = grid[r][c]; + + if (r == N - 1 && c == N - 1) { + return dist; + } + + for (int d = 0; d < 9; d++) { + int nr = r + direct[d]; + int nc = c + direct[d + 1]; + if (nr >= 0 && nr < N && nc >= 0 && nc < N && grid[nr][nc] == 0) { + grid[nr][nc] = dist + 1; + q.Enqueue((nr, nc)); + } + } + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 3. Bidirectional Breadth First Search + +::tabs-start + +```python +class Solution: + def shortestPathBinaryMatrix(self, grid: list[list[int]]) -> int: + N = len(grid) + if grid[0][0] or grid[N - 1][N - 1]: + return -1 + if N == 1: + return 1 + + direct = [0, 1, 0, -1, 0, 1, 1, -1, -1, 1] + q1 = deque([(0, 0)]) + q2 = deque([(N - 1, N - 1)]) + grid[0][0] = -1 + grid[N - 1][N - 1] = -2 + + res = 2 + start, end = -1, -2 + while q1 and q2: + for _ in range(len(q1)): + r, c = q1.popleft() + for d in range(9): + nr, nc = r + direct[d], c + direct[d + 1] + if 0 <= nr < N and 0 <= nc < N: + if grid[nr][nc] == end: + return res + if grid[nr][nc] == 0: + grid[nr][nc] = start + q1.append((nr, nc)) + + q1, q2 = q2, q1 + start, end = end, start + res += 1 + + return -1 +``` + +```java +public class Solution { + public int shortestPathBinaryMatrix(int[][] grid) { + int N = grid.length; + if (grid[0][0] == 1 || grid[N - 1][N - 1] == 1) return -1; + if (N == 1) return 1; + + int[] direct = {0, 1, 0, -1, 0, 1, 1, -1, -1, 1}; + Queue q1 = new LinkedList<>(), q2 = new LinkedList<>(); + q1.offer(new int[]{0, 0}); + q2.offer(new int[]{N - 1, N - 1}); + grid[0][0] = -1; + grid[N - 1][N - 1] = -2; + + int res = 2, start = -1, end = -2; + while (!q1.isEmpty() && !q2.isEmpty()) { + for (int i = q1.size(); i > 0; i--) { + int[] cell = q1.poll(); + int r = cell[0], c = cell[1]; + + for (int d = 0; d < 9; d++) { + int nr = r + direct[d], nc = c + direct[d + 1]; + if (nr >= 0 && nc >= 0 && nr < N && nc < N) { + if (grid[nr][nc] == end) return res; + if (grid[nr][nc] == 0) { + grid[nr][nc] = start; + q1.offer(new int[]{nr, nc}); + } + } + } + } + Queue temp = q1; + q1 = q2; + q2 = temp; + int tempVal = start; + start = end; + end = tempVal; + res++; + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int shortestPathBinaryMatrix(vector>& grid) { + int N = grid.size(); + if (grid[0][0] || grid[N - 1][N - 1]) return -1; + if (N == 1) return 1; + + int direct[10] = {0, 1, 0, -1, 0, 1, 1, -1, -1, 1}; + queue> q1, q2; + q1.push({0, 0}); + q2.push({N - 1, N - 1}); + grid[0][0] = -1; + grid[N - 1][N - 1] = -2; + + int res = 2, start = -1, end = -2; + while (!q1.empty() && !q2.empty()) { + for (int i = q1.size(); i > 0; i--) { + auto [r, c] = q1.front(); + q1.pop(); + + for (int d = 0; d < 9; d++) { + int nr = r + direct[d], nc = c + direct[d + 1]; + if (nr >= 0 && nc >= 0 && nr < N && nc < N) { + if (grid[nr][nc] == end) return res; + if (grid[nr][nc] == 0) { + grid[nr][nc] = start; + q1.push({nr, nc}); + } + } + } + } + swap(q1, q2); + swap(start, end); + res++; + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} grid + * @return {number} + */ + shortestPathBinaryMatrix(grid) { + const N = grid.length; + if (grid[0][0] || grid[N - 1][N - 1]) return -1; + if (N === 1) return 1; + + const direct = [0, 1, 0, -1, 0, 1, 1, -1, -1, 1]; + let q1 = new Queue([[0, 0]]); + let q2 = new Queue([[N - 1, N - 1]]); + grid[0][0] = -1; + grid[N - 1][N - 1] = -2; + + let res = 2, + start = -1, + end = -2; + while (!q1.isEmpty() && !q2.isEmpty()) { + for (let i = q1.size(); i > 0; i--) { + const [r, c] = q1.pop(); + for (let d = 0; d < 9; d++) { + let nr = r + direct[d], + nc = c + direct[d + 1]; + if (nr >= 0 && nc >= 0 && nr < N && nc < N) { + if (grid[nr][nc] === end) return res; + if (grid[nr][nc] === 0) { + grid[nr][nc] = start; + q1.push([nr, nc]); + } + } + } + } + [q1, q2] = [q2, q1]; + [start, end] = [end, start]; + res++; + } + + return -1; + } +} +``` + +```csharp +public class Solution { + public int ShortestPathBinaryMatrix(int[][] grid) { + int N = grid.Length; + if (grid[0][0] != 0 || grid[N - 1][N - 1] != 0) { + return -1; + } + if (N == 1) { + return 1; + } + + int[] direct = new int[] { 0, 1, 0, -1, 0, 1, 1, -1, -1, 1 }; + var q1 = new Queue<(int r, int c)>(); + var q2 = new Queue<(int r, int c)>(); + q1.Enqueue((0, 0)); + q2.Enqueue((N - 1, N - 1)); + grid[0][0] = -1; + grid[N - 1][N - 1] = -2; + + int res = 2; + int start = -1, end = -2; + while (q1.Count > 0 && q2.Count > 0) { + int size = q1.Count; + for (int i = 0; i < size; i++) { + var (r, c) = q1.Dequeue(); + for (int d = 0; d < 9; d++) { + int nr = r + direct[d]; + int nc = c + direct[d + 1]; + if (nr >= 0 && nr < N && nc >= 0 && nc < N) { + if (grid[nr][nc] == end) { + return res; + } + if (grid[nr][nc] == 0) { + grid[nr][nc] = start; + q1.Enqueue((nr, nc)); + } + } + } + } + + var tmpQ = q1; + q1 = q2; + q2 = tmpQ; + int tmp = start; + start = end; + end = tmp; + res++; + } + + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ diff --git a/articles/shortest-path-with-alternating-colors.md b/articles/shortest-path-with-alternating-colors.md new file mode 100644 index 000000000..63a21c484 --- /dev/null +++ b/articles/shortest-path-with-alternating-colors.md @@ -0,0 +1,548 @@ +## 1. Breadth First Search - I + +::tabs-start + +```python +class Solution: + def shortestAlternatingPaths(self, n: int, redEdges: list[list[int]], blueEdges: list[list[int]]) -> list[int]: + red, blue = defaultdict(list), defaultdict(list) + + for src, dst in redEdges: + red[src].append(dst) + + for src, dst in blueEdges: + blue[src].append(dst) + + answer = [-1 for _ in range(n)] + q = deque() + q.append((0, 0, None)) # [node, length, prev_edge_color] + visit = set() + visit.add((0, None)) + + while q: + node, length, edgeColor = q.popleft() + if answer[node] == -1: + answer[node] = length + + if edgeColor != "RED": + for nei in red[node]: + if (nei, "RED") not in visit: + visit.add((nei, "RED")) + q.append((nei, length + 1, "RED")) + + if edgeColor != "BLUE": + for nei in blue[node]: + if (nei, "BLUE") not in visit: + visit.add((nei, "BLUE")) + q.append((nei, length + 1, "BLUE")) + + return answer +``` + +```java +public class Solution { + public int[] shortestAlternatingPaths(int n, int[][] redEdges, int[][] blueEdges) { + List[] red = new ArrayList[n], blue = new ArrayList[n]; + for (int i = 0; i < n; i++) { + red[i] = new ArrayList<>(); + blue[i] = new ArrayList<>(); + } + for (int[] edge : redEdges) red[edge[0]].add(edge[1]); + for (int[] edge : blueEdges) blue[edge[0]].add(edge[1]); + + int[] answer = new int[n]; + Arrays.fill(answer, -1); + Queue q = new LinkedList<>(); + q.offer(new int[]{0, 0, -1}); + Set visit = new HashSet<>(); + visit.add("0,-1"); + + while (!q.isEmpty()) { + int[] nodeData = q.poll(); + int node = nodeData[0], length = nodeData[1], edgeColor = nodeData[2]; + + if (answer[node] == -1) answer[node] = length; + + if (edgeColor != 0) { + for (int nei : red[node]) { + if (visit.add(nei + ",0")) { + q.offer(new int[]{nei, length + 1, 0}); + } + } + } + if (edgeColor != 1) { + for (int nei : blue[node]) { + if (visit.add(nei + ",1")) { + q.offer(new int[]{nei, length + 1, 1}); + } + } + } + } + return answer; + } +} +``` + +```cpp +class Solution { +public: + vector shortestAlternatingPaths(int n, vector>& redEdges, vector>& blueEdges) { + vector> red(n), blue(n); + for (auto& edge : redEdges) red[edge[0]].push_back(edge[1]); + for (auto& edge : blueEdges) blue[edge[0]].push_back(edge[1]); + + vector answer(n, -1); + queue> q; + q.push({0, 0, -1}); + unordered_set visit; + visit.insert("0,-1"); + + while (!q.empty()) { + vector nodeData = q.front(); + q.pop(); + int node = nodeData[0], length = nodeData[1], edgeColor = nodeData[2]; + + if (answer[node] == -1) answer[node] = length; + + if (edgeColor != 0) { + for (int nei : red[node]) { + string key = to_string(nei) + ",0"; + if (visit.insert(key).second) { + q.push({nei, length + 1, 0}); + } + } + } + if (edgeColor != 1) { + for (int nei : blue[node]) { + string key = to_string(nei) + ",1"; + if (visit.insert(key).second) { + q.push({nei, length + 1, 1}); + } + } + } + } + return answer; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} redEdges + * @param {number[][]} blueEdges + * @return {number[]} + */ + shortestAlternatingPaths(n, redEdges, blueEdges) { + const red = Array.from({ length: n }, () => []); + const blue = Array.from({ length: n }, () => []); + + for (const [src, dst] of redEdges) red[src].push(dst); + for (const [src, dst] of blueEdges) blue[src].push(dst); + + const answer = new Array(n).fill(-1); + const q = new Queue([[0, 0, null]]); + const visit = new Set(['0,null']); + + while (!q.isEmpty()) { + const [node, length, edgeColor] = q.pop(); + if (answer[node] === -1) answer[node] = length; + + if (edgeColor !== 'RED') { + for (const nei of red[node]) { + if (!visit.has(`${nei},RED`)) { + visit.add(`${nei},RED`); + q.push([nei, length + 1, 'RED']); + } + } + } + if (edgeColor !== 'BLUE') { + for (const nei of blue[node]) { + if (!visit.has(`${nei},BLUE`)) { + visit.add(`${nei},BLUE`); + q.push([nei, length + 1, 'BLUE']); + } + } + } + } + return answer; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 2. Breadth First Search - II + +::tabs-start + +```python +class Solution: + def shortestAlternatingPaths(self, n: int, redEdges: list[list[int]], blueEdges: list[list[int]]) -> list[int]: + def buildGraph(edges): + adj = [[] for _ in range(n)] + for u, v in edges: + adj[u].append(v) + return adj + + red, blue = buildGraph(redEdges), buildGraph(blueEdges) + adj = [red, blue] + INF = float("inf") + dist = [[INF] * 2 for _ in range(n)] + dist[0][0] = dist[0][1] = 0 + + q = deque([(0, 0), (0, 1)]) + while q: + node, color = q.popleft() + for nei in adj[color][node]: + if dist[nei][color ^ 1] > dist[node][color] + 1: + dist[nei][color ^ 1] = dist[node][color] + 1 + q.append((nei, color ^ 1)) + + answer = [0] + [-1] * (n - 1) + for i in range(1, n): + answer[i] = min(dist[i][0], dist[i][1]) + if answer[i] == INF: + answer[i] = -1 + return answer +``` + +```java +public class Solution { + public int[] shortestAlternatingPaths(int n, int[][] redEdges, int[][] blueEdges) { + List[][] adj = new ArrayList[2][n]; + adj[0] = buildGraph(n, redEdges); + adj[1] = buildGraph(n, blueEdges); + + int INF = Integer.MAX_VALUE; + int[][] dist = new int[n][2]; + + for (int i = 0; i < n; i++) Arrays.fill(dist[i], INF); + dist[0][0] = dist[0][1] = 0; + + Queue q = new LinkedList<>(); + q.offer(new int[]{0, 0}); + q.offer(new int[]{0, 1}); + + while (!q.isEmpty()) { + int[] cur = q.poll(); + int node = cur[0], color = cur[1]; + + for (int nei : adj[color][node]) { + if (dist[nei][color ^ 1] > dist[node][color] + 1) { + dist[nei][color ^ 1] = dist[node][color] + 1; + q.offer(new int[]{nei, color ^ 1}); + } + } + } + + int[] answer = new int[n]; + for (int i = 0; i < n; i++) { + answer[i] = Math.min(dist[i][0], dist[i][1]); + if (answer[i] == INF) answer[i] = -1; + } + return answer; + } + + private List[] buildGraph(int n, int[][] edges) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + } + return adj; + } +} +``` + +```cpp +class Solution { +public: + vector shortestAlternatingPaths(int n, vector>& redEdges, vector>& blueEdges) { + vector> red = buildGraph(n, redEdges); + vector> blue = buildGraph(n, blueEdges); + vector> adj[] = {red, blue}; + + const int INF = 1e6; + vector> dist(n, vector(2, INF)); + dist[0][0] = dist[0][1] = 0; + + queue> q; + q.push({0, 0}); + q.push({0, 1}); + + while (!q.empty()) { + auto [node, color] = q.front();q.pop(); + for (int nei : adj[color][node]) { + if (dist[nei][color ^ 1] > dist[node][color] + 1) { + dist[nei][color ^ 1] = dist[node][color] + 1; + q.push({nei, color ^ 1}); + } + } + } + + vector answer(n, -1); + for (int i = 0; i < n; i++) { + answer[i] = min(dist[i][0], dist[i][1]); + if (answer[i] == INF) answer[i] = -1; + } + return answer; + } + +private: + vector> buildGraph(int n, vector>& edges) { + vector> adj(n); + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + } + return adj; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} redEdges + * @param {number[][]} blueEdges + * @return {number[]} + */ + shortestAlternatingPaths(n, redEdges, blueEdges) { + const red = this.buildGraph(n, redEdges); + const blue = this.buildGraph(n, blueEdges); + const adj = [red, blue]; + const INF = 1e6; + const dist = Array.from({ length: n }, () => [INF, INF]); + dist[0][0] = dist[0][1] = 0; + + const q = new Queue([ + [0, 0], + [0, 1], + ]); + while (!q.isEmpty()) { + const [node, color] = q.pop(); + for (const nei of adj[color][node]) { + if (dist[nei][color ^ 1] > dist[node][color] + 1) { + dist[nei][color ^ 1] = dist[node][color] + 1; + q.push([nei, color ^ 1]); + } + } + } + + return Array.from({ length: n }, (_, i) => { + let minDist = Math.min(dist[i][0], dist[i][1]); + return minDist === INF ? -1 : minDist; + }); + } + + /** + * @param {number} n + * @param {number[][]} edges + * @return {number[][]} + */ + buildGraph(n, edges) { + const adj = Array.from({ length: n }, () => []); + for (const [u, v] of edges) { + adj[u].push(v); + } + return adj; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. + +--- + +## 3. Depth First Search + +::tabs-start + +```python +class Solution: + def shortestAlternatingPaths(self, n: int, redEdges: list[list[int]], blueEdges: list[list[int]]) -> list[int]: + def buildGraph(edges): + adj = [[] for _ in range(n)] + for u, v in edges: + adj[u].append(v) + return adj + + red, blue = buildGraph(redEdges), buildGraph(blueEdges) + adj = [red, blue] + INF = float("inf") + dist = [[INF] * 2 for _ in range(n)] + dist[0][0] = dist[0][1] = 0 + + def dfs(node, color): + for nei in adj[color][node]: + if dist[nei][color ^ 1] > dist[node][color] + 1: + dist[nei][color ^ 1] = dist[node][color] + 1 + dfs(nei, color ^ 1) + + dfs(0, 0) + dfs(0, 1) + + answer = [0] + [-1] * (n - 1) + for i in range(1, n): + answer[i] = min(dist[i][0], dist[i][1]) + if answer[i] == INF: + answer[i] = -1 + + return answer +``` + +```java +public class Solution { + public int[] shortestAlternatingPaths(int n, int[][] redEdges, int[][] blueEdges) { + List[][] adj = new ArrayList[2][n]; + adj[0] = buildGraph(n, redEdges); + adj[1] = buildGraph(n, blueEdges); + + int INF = Integer.MAX_VALUE; + int[][] dist = new int[n][2]; + for (int i = 0; i < n; i++) Arrays.fill(dist[i], INF); + dist[0][0] = dist[0][1] = 0; + + dfs(0, 0, adj, dist); + dfs(0, 1, adj, dist); + + int[] answer = new int[n]; + for (int i = 0; i < n; i++) { + answer[i] = Math.min(dist[i][0], dist[i][1]); + if (answer[i] == INF) answer[i] = -1; + } + return answer; + } + + private void dfs(int node, int color, List[][] adj, int[][] dist) { + for (int nei : adj[color][node]) { + if (dist[nei][color ^ 1] > dist[node][color] + 1) { + dist[nei][color ^ 1] = dist[node][color] + 1; + dfs(nei, color ^ 1, adj, dist); + } + } + } + + private List[] buildGraph(int n, int[][] edges) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (int[] edge : edges) { + adj[edge[0]].add(edge[1]); + } + return adj; + } +} +``` + +```cpp +class Solution { +public: + vector shortestAlternatingPaths(int n, vector>& redEdges, vector>& blueEdges) { + vector> adj[2] = {buildGraph(n, redEdges), buildGraph(n, blueEdges)}; + + int INF = numeric_limits::max(); + vector> dist(n, vector(2, INF)); + dist[0][0] = dist[0][1] = 0; + + dfs(0, 0, adj, dist); + dfs(0, 1, adj, dist); + + vector answer(n, -1); + for (int i = 0; i < n; i++) { + answer[i] = min(dist[i][0], dist[i][1]); + if (answer[i] == INF) answer[i] = -1; + } + return answer; + } + +private: + void dfs(int node, int color, vector> adj[], vector>& dist) { + for (int nei : adj[color][node]) { + if (dist[nei][color ^ 1] > dist[node][color] + 1) { + dist[nei][color ^ 1] = dist[node][color] + 1; + dfs(nei, color ^ 1, adj, dist); + } + } + } + + vector> buildGraph(int n, vector>& edges) { + vector> adj(n); + for (auto& edge : edges) { + adj[edge[0]].push_back(edge[1]); + } + return adj; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[][]} redEdges + * @param {number[][]} blueEdges + * @return {number[]} + */ + shortestAlternatingPaths(n, redEdges, blueEdges) { + const INF = Number.MAX_SAFE_INTEGER; + const adj = [ + Array.from({ length: n }, () => []), + Array.from({ length: n }, () => []), + ]; + + redEdges.forEach(([u, v]) => adj[0][u].push(v)); + blueEdges.forEach(([u, v]) => adj[1][u].push(v)); + + const dist = Array.from({ length: n }, () => [INF, INF]); + dist[0][0] = dist[0][1] = 0; + + const dfs = (node, color) => { + adj[color][node].forEach((nei) => { + if (dist[nei][color ^ 1] > dist[node][color] + 1) { + dist[nei][color ^ 1] = dist[node][color] + 1; + dfs(nei, color ^ 1); + } + }); + }; + + dfs(0, 0); + dfs(0, 1); + + return dist.map(([red, blue]) => { + let res = Math.min(red, blue); + return res === INF ? -1 : res; + }); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of vertices and $E$ is the number of edges. diff --git a/articles/shuffle-the-array.md b/articles/shuffle-the-array.md new file mode 100644 index 000000000..b20c31311 --- /dev/null +++ b/articles/shuffle-the-array.md @@ -0,0 +1,257 @@ +## 1. Iteration (Extra Space) + +::tabs-start + +```python +class Solution: + def shuffle(self, nums: List[int], n: int) -> List[int]: + res = [] + for i in range(n): + res.append(nums[i]) + res.append(nums[i + n]) + return res +``` + +```java +public class Solution { + public int[] shuffle(int[] nums, int n) { + int[] res = new int[2 * n]; + int idx = 0; + for (int i = 0; i < n; i++) { + res[idx++] = nums[i]; + res[idx++] = nums[i + n]; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector shuffle(vector& nums, int n) { + vector res; + for (int i = 0; i < n; i++) { + res.push_back(nums[i]); + res.push_back(nums[i + n]); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} n + * @return {number[]} + */ + shuffle(nums) { + const res = []; + for (let i = 0; i < n; i++) { + res.push(nums[i]); + res.push(nums[i + n]); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ extra space. + +--- + +## 2. Multiplication And Modulo + +::tabs-start + +```python +class Solution: + def shuffle(self, nums: List[int], n: int) -> List[int]: + M = max(nums) + 1 + for i in range(2 * n): + if i % 2 == 0: + nums[i] += (nums[i // 2] % M) * M + else: + nums[i] += (nums[n + i // 2] % M) * M + + for i in range(2 * n): + nums[i] //= M + + return nums +``` + +```java +public class Solution { + public int[] shuffle(int[] nums, int n) { + int M = 1001; + for (int i = 0; i < 2 * n; i++) { + if (i % 2 == 0) { + nums[i] += (nums[i / 2] % M) * M; + } else { + nums[i] += (nums[n + i / 2] % M) * M; + } + } + for (int i = 0; i < 2 * n; i++) { + nums[i] /= M; + } + return nums; + } +} +``` + +```cpp +class Solution { +public: + vector shuffle(vector& nums, int n) { + int M = *max_element(nums.begin(), nums.end()) + 1; + for (int i = 0; i < 2 * n; i++) { + if (i % 2 == 0) { + nums[i] += (nums[i / 2] % M) * M; + } else { + nums[i] += (nums[n + i / 2] % M) * M; + } + } + for (int i = 0; i < 2 * n; i++) { + nums[i] /= M; + } + return nums; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} n + * @return {number[]} + */ + shuffle(nums) { + const M = Math.max(...nums) + 1; + for (let i = 0; i < 2 * n; i++) { + if (i % 2 === 0) { + nums[i] += (nums[i >> 1] % M) * M; + } else { + nums[i] += (nums[n + (i >> 1)] % M) * M; + } + } + for (let i = 0; i < 2 * n; i++) { + nums[i] = Math.floor(nums[i] / M); + } + return nums; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 3. Bit Manipulation + +::tabs-start + +```python +class Solution: + def shuffle(self, nums: List[int], n: int) -> List[int]: + for i in range(n): + nums[i] = (nums[i] << 10) | nums[i + n] # Store x, y in nums[i] + + j = 2 * n - 1 + for i in range(n - 1, -1, -1): + y = nums[i] & ((1 << 10) - 1) + x = nums[i] >> 10 + nums[j] = y + nums[j - 1] = x + j -= 2 + + return nums +``` + +```java +public class Solution { + public int[] shuffle(int[] nums, int n) { + for (int i = 0; i < n; i++) { + nums[i] = (nums[i] << 10) | nums[i + n]; // Store x, y in nums[i] + } + + int j = 2 * n - 1; + for (int i = n - 1; i >= 0; i--) { + int y = nums[i] & ((1 << 10) - 1); + int x = nums[i] >> 10; + nums[j] = y; + nums[j - 1] = x; + j -= 2; + } + + return nums; + } +} +``` + +```cpp +class Solution { +public: + vector shuffle(vector& nums, int n) { + for (int i = 0; i < n; i++) { + nums[i] = (nums[i] << 10) | nums[i + n]; // Store x, y in nums[i] + } + + int j = 2 * n - 1; + for (int i = n - 1; i >= 0; i--) { + int y = nums[i] & ((1 << 10) - 1); + int x = nums[i] >> 10; + nums[j] = y; + nums[j - 1] = x; + j -= 2; + } + + return nums; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} n + * @return {number[]} + */ + shuffle(nums) { + for (let i = 0; i < n; i++) { + nums[i] = (nums[i] << 10) | nums[i + n]; // Store x, y in nums[i] + } + + let j = 2 * n - 1; + for (let i = n - 1; i >= 0; i--) { + let y = nums[i] & ((1 << 10) - 1); + let x = nums[i] >> 10; + nums[j] = y; + nums[j - 1] = x; + j -= 2; + } + + return nums; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/sign-of-the-product-of-an-array.md b/articles/sign-of-the-product-of-an-array.md index 76922c8d0..ed9a161f0 100644 --- a/articles/sign-of-the-product-of-an-array.md +++ b/articles/sign-of-the-product-of-an-array.md @@ -73,8 +73,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -154,5 +154,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/simplify-path.md b/articles/simplify-path.md index 23fe29c96..ab45b62b7 100644 --- a/articles/simplify-path.md +++ b/articles/simplify-path.md @@ -85,22 +85,48 @@ class Solution { */ simplifyPath(path) { const stack = []; - let cur = ""; + let cur = ''; - for (const c of path + "/") { - if (c === "/") { - if (cur === "..") { + for (const c of path + '/') { + if (c === '/') { + if (cur === '..') { if (stack.length) stack.pop(); - } else if (cur !== "" && cur !== ".") { + } else if (cur !== '' && cur !== '.') { stack.push(cur); } + cur = ''; + } else { + cur += c; + } + } + + return '/' + stack.join('/'); + } +} +``` + +```csharp +public class Solution { + public string SimplifyPath(string path) { + Stack stack = new Stack(); + string cur = ""; + + foreach (char c in path + "/") { + if (c == '/') { + if (cur == "..") { + if (stack.Count > 0) stack.Pop(); + } else if (cur != "" && cur != ".") { + stack.Push(cur); + } cur = ""; } else { cur += c; } } - return "/" + stack.join("/"); + var result = new List(stack); + result.Reverse(); + return "/" + string.Join("/", result); } } ``` @@ -109,8 +135,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -188,19 +214,42 @@ class Solution { */ simplifyPath(path) { const stack = []; - const paths = path.split("/"); + const paths = path.split('/'); for (const cur of paths) { - if (cur === "..") { + if (cur === '..') { if (stack.length) { stack.pop(); } - } else if (cur !== "" && cur !== ".") { + } else if (cur !== '' && cur !== '.') { stack.push(cur); } } - return "/" + stack.join("/"); + return '/' + stack.join('/'); + } +} +``` + +```csharp +public class Solution { + public string SimplifyPath(string path) { + Stack stack = new Stack(); + string[] parts = path.Split('/'); + + foreach (string part in parts) { + if (part == "..") { + if (stack.Count > 0) { + stack.Pop(); + } + } else if (part != "" && part != ".") { + stack.Push(part); + } + } + + var result = new List(stack); + result.Reverse(); + return "/" + string.Join("/", result); } } ``` @@ -209,5 +258,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/single-element-in-a-sorted-array.md b/articles/single-element-in-a-sorted-array.md new file mode 100644 index 000000000..8855fac24 --- /dev/null +++ b/articles/single-element-in-a-sorted-array.md @@ -0,0 +1,445 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def singleNonDuplicate(self, nums: List[int]) -> int: + n = len(nums) + for i in range(n): + if ((i and nums[i] == nums[i - 1]) or + (i < n - 1 and nums[i] == nums[i + 1]) + ): + continue + return nums[i] +``` + +```java +public class Solution { + public int singleNonDuplicate(int[] nums) { + int n = nums.length; + for (int i = 0; i < n; i++) { + if ((i > 0 && nums[i] == nums[i - 1]) || + (i < n - 1 && nums[i] == nums[i + 1])) { + continue; + } + return nums[i]; + } + return -1; + } +} +``` + +```cpp +class Solution { +public: + int singleNonDuplicate(vector& nums) { + int n = nums.size(); + for (int i = 0; i < n; i++) { + if ((i > 0 && nums[i] == nums[i - 1]) || + (i < n - 1 && nums[i] == nums[i + 1])) { + continue; + } + return nums[i]; + } + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + singleNonDuplicate(nums) { + const n = nums.length; + for (let i = 0; i < n; i++) { + if ( + (i > 0 && nums[i] === nums[i - 1]) || + (i < n - 1 && nums[i] === nums[i + 1]) + ) { + continue; + } + return nums[i]; + } + return -1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 2. Brute Force (Bitwise Xor) + +::tabs-start + +```python +class Solution: + def singleNonDuplicate(self, nums: List[int]) -> int: + xorr = 0 + for num in nums: + xorr ^= num + return xorr +``` + +```java +public class Solution { + public int singleNonDuplicate(int[] nums) { + int xorr = 0; + for (int num : nums) { + xorr ^= num; + } + return xorr; + } +} +``` + +```cpp +class Solution { +public: + int singleNonDuplicate(vector& nums) { + int xorr = 0; + for (int num : nums) { + xorr ^= num; + } + return xorr; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + singleNonDuplicate(nums) { + let xorr = 0; + for (const num of nums) { + xorr ^= num; + } + return xorr; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 3. Binary Search + +::tabs-start + +```python +class Solution: + def singleNonDuplicate(self, nums: List[int]) -> int: + l, r = 0, len(nums) - 1 + + while l <= r: + m = l + ((r - l) // 2) + if ((m - 1 < 0 or nums[m - 1] != nums[m]) and + (m + 1 == len(nums) or nums[m] != nums[m + 1])): + return nums[m] + + leftSize = m - 1 if nums[m - 1] == nums[m] else m + if leftSize % 2: + r = m - 1 + else: + l = m + 1 +``` + +```java +public class Solution { + public int singleNonDuplicate(int[] nums) { + int l = 0, r = nums.length - 1; + + while (l <= r) { + int m = l + (r - l) / 2; + if ((m - 1 < 0 || nums[m - 1] != nums[m]) && + (m + 1 == nums.length || nums[m] != nums[m + 1])) { + return nums[m]; + } + + int leftSize = (m - 1 >= 0 && nums[m - 1] == nums[m]) ? m - 1 : m; + if (leftSize % 2 == 1) { + r = m - 1; + } else { + l = m + 1; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + int singleNonDuplicate(vector& nums) { + int l = 0, r = nums.size() - 1; + + while (l <= r) { + int m = l + (r - l) / 2; + if ((m - 1 < 0 || nums[m - 1] != nums[m]) && + (m + 1 == nums.size() || nums[m] != nums[m + 1])) { + return nums[m]; + } + + int leftSize = (m - 1 >= 0 && nums[m - 1] == nums[m]) ? m - 1 : m; + if (leftSize % 2 == 1) { + r = m - 1; + } else { + l = m + 1; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + singleNonDuplicate(nums) { + let l = 0, + r = nums.length - 1; + + while (l <= r) { + let m = l + Math.floor((r - l) / 2); + if ( + (m - 1 < 0 || nums[m - 1] !== nums[m]) && + (m + 1 === nums.length || nums[m] !== nums[m + 1]) + ) { + return nums[m]; + } + + let leftSize = m - 1 >= 0 && nums[m - 1] === nums[m] ? m - 1 : m; + if (leftSize % 2 === 1) { + r = m - 1; + } else { + l = m + 1; + } + } + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ + +--- + +## 4. Binary Search On Even Indexes + +::tabs-start + +```python +class Solution: + def singleNonDuplicate(self, nums: List[int]) -> int: + l, r = 0, len(nums) - 1 + + while l < r: + m = l + (r - l) // 2 + if m & 1: + m -= 1 + if nums[m] != nums[m + 1]: + r = m + else: + l = m + 2 + + return nums[l] +``` + +```java +public class Solution { + public int singleNonDuplicate(int[] nums) { + int l = 0, r = nums.length - 1; + + while (l < r) { + int m = l + (r - l) / 2; + if ((m & 1) == 1) { + m--; + } + if (nums[m] != nums[m + 1]) { + r = m; + } else { + l = m + 2; + } + } + + return nums[l]; + } +} +``` + +```cpp +class Solution { +public: + int singleNonDuplicate(vector& nums) { + int l = 0, r = nums.size() - 1; + + while (l < r) { + int m = l + (r - l) / 2; + if (m & 1) { + m--; + } + if (nums[m] != nums[m + 1]) { + r = m; + } else { + l = m + 2; + } + } + + return nums[l]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + singleNonDuplicate(nums) { + let l = 0, + r = nums.length - 1; + + while (l < r) { + let m = Math.floor(l + (r - l) / 2); + if (m & 1) { + m--; + } + if (nums[m] !== nums[m + 1]) { + r = m; + } else { + l = m + 2; + } + } + + return nums[l]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ + +--- + +## 5. Binary Search + Bit Manipulation + +::tabs-start + +```python +class Solution: + def singleNonDuplicate(self, nums: List[int]) -> int: + l, r = 0, len(nums) - 1 + + while l < r: + m = (l + r) >> 1 + if nums[m] != nums[m ^ 1]: + r = m + else: + l = m + 1 + + return nums[l] +``` + +```java +public class Solution { + public int singleNonDuplicate(int[] nums) { + int l = 0, r = nums.length - 1; + + while (l < r) { + int m = (l + r) >> 1; + if (nums[m] != nums[m ^ 1]) { + r = m; + } else { + l = m + 1; + } + } + + return nums[l]; + } +} +``` + +```cpp +class Solution { +public: + int singleNonDuplicate(vector& nums) { + int l = 0, r = nums.size() - 1; + + while (l < r) { + int m = (l + r) >> 1; + if (nums[m] != nums[m ^ 1]) { + r = m; + } else { + l = m + 1; + } + } + + return nums[l]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number} + */ + singleNonDuplicate(nums) { + let l = 0, + r = nums.length - 1; + + while (l < r) { + let m = (l + r) >> 1; + if (nums[m] !== nums[m ^ 1]) { + r = m; + } else { + l = m + 1; + } + } + + return nums[l]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/single-number-iii.md b/articles/single-number-iii.md new file mode 100644 index 000000000..fa32a2b71 --- /dev/null +++ b/articles/single-number-iii.md @@ -0,0 +1,757 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def singleNumber(self, nums: List[int]) -> List[int]: + n, res = len(nums), [] + + for i in range(n): + flag = True + for j in range(n): + if i != j and nums[i] == nums[j]: + flag = False + break + + if flag: + res.append(nums[i]) + if len(res) == 2: + break + + return res +``` + +```java +public class Solution { + public int[] singleNumber(int[] nums) { + int n = nums.length; + List res = new ArrayList<>(); + + for (int i = 0; i < n; i++) { + boolean flag = true; + for (int j = 0; j < n; j++) { + if (i != j && nums[i] == nums[j]) { + flag = false; + break; + } + } + + if (flag) { + res.add(nums[i]); + if (res.size() == 2) { + break; + } + } + } + + return new int[] {res.get(0), res.get(1)}; + } +} +``` + +```cpp +class Solution { +public: + vector singleNumber(vector& nums) { + int n = nums.size(); + vector res; + + for (int i = 0; i < n; i++) { + bool flag = true; + for (int j = 0; j < n; j++) { + if (i != j && nums[i] == nums[j]) { + flag = false; + break; + } + } + + if (flag) { + res.push_back(nums[i]); + if (res.size() == 2) { + break; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + singleNumber(nums) { + const n = nums.length; + const res = []; + + for (let i = 0; i < n; i++) { + let flag = true; + for (let j = 0; j < n; j++) { + if (i !== j && nums[i] === nums[j]) { + flag = false; + break; + } + } + + if (flag) { + res.push(nums[i]); + if (res.length === 2) { + break; + } + } + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int[] SingleNumber(int[] nums) { + int n = nums.Length; + List res = new List(); + + for (int i = 0; i < n; i++) { + bool flag = true; + for (int j = 0; j < n; j++) { + if (i != j && nums[i] == nums[j]) { + flag = false; + break; + } + } + if (flag) { + res.Add(nums[i]); + if (res.Count == 2) { + break; + } + } + } + + return new int[] { res[0], res[1] }; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 2. Hash Map + +::tabs-start + +```python +class Solution: + def singleNumber(self, nums: List[int]) -> List[int]: + count = {} + for num in nums: + count[num] = 1 + count.get(num, 0) + + return [k for k in count if count[k] == 1] +``` + +```java +public class Solution { + public int[] singleNumber(int[] nums) { + Map count = new HashMap<>(); + for (int num : nums) { + count.put(num, count.getOrDefault(num, 0) + 1); + } + + ArrayList res = new ArrayList<>(); + for (int key : count.keySet()) { + if (count.get(key) == 1) { + res.add(key); + } + } + + return new int[] {res.get(0), res.get(1)}; + } +} +``` + +```cpp +class Solution { +public: + vector singleNumber(vector& nums) { + unordered_map count; + for (int num : nums) { + count[num]++; + } + + vector res; + for (const auto& pair : count) { + if (pair.second == 1) { + res.push_back(pair.first); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + singleNumber(nums) { + const count = new Map(); + for (const num of nums) { + count.set(num, (count.get(num) || 0) + 1); + } + + const res = []; + for (const [key, value] of count) { + if (value === 1) { + res.push(key); + } + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int[] SingleNumber(int[] nums) { + Dictionary count = new Dictionary(); + foreach (int num in nums) { + if (count.ContainsKey(num)) { + count[num]++; + } else { + count[num] = 1; + } + } + + List res = new List(); + foreach (var key in count.Keys) { + if (count[key] == 1) { + res.Add(key); + } + } + + return new int[] { res[0], res[1] }; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Hash Set + +::tabs-start + +```python +class Solution: + def singleNumber(self, nums: List[int]) -> List[int]: + seen = set() + for num in nums: + if num in seen: + seen.remove(num) + else: + seen.add(num) + return list(seen) +``` + +```java +public class Solution { + public int[] singleNumber(int[] nums) { + HashSet seen = new HashSet<>(); + for (int num : nums) { + if (seen.contains(num)) { + seen.remove(num); + } else { + seen.add(num); + } + } + + int[] res = new int[2]; + int index = 0; + for (int num : seen) { + res[index++] = num; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector singleNumber(vector& nums) { + unordered_set seen; + for (int& num : nums) { + if (seen.count(num)) { + seen.erase(num); + } else { + seen.insert(num); + } + } + + return vector(seen.begin(), seen.end()); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + singleNumber(nums) { + const seen = new Set(); + for (const num of nums) { + if (seen.has(num)) { + seen.delete(num); + } else { + seen.add(num); + } + } + + return Array.from(seen); + } +} +``` + +```csharp +public class Solution { + public int[] SingleNumber(int[] nums) { + HashSet seen = new HashSet(); + foreach (int num in nums) { + if (seen.Contains(num)) { + seen.Remove(num); + } else { + seen.Add(num); + } + } + + int[] res = new int[2]; + int index = 0; + foreach (int num in seen) { + res[index++] = num; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Sorting + +::tabs-start + +```python +class Solution: + def singleNumber(self, nums: List[int]) -> List[int]: + res, n = [], len(nums) + nums.sort() + + for i in range(n): + if ((i > 0 and nums[i] == nums[i - 1]) or + (i + 1 < n and nums[i] == nums[i + 1])): + continue + res.append(nums[i]) + + return res +``` + +```java +public class Solution { + public int[] singleNumber(int[] nums) { + Arrays.sort(nums); + List res = new ArrayList<>(); + int n = nums.length; + + for (int i = 0; i < n; i++) { + if ((i > 0 && nums[i] == nums[i - 1]) || + (i + 1 < n && nums[i] == nums[i + 1])) { + continue; + } + res.add(nums[i]); + } + + return res.stream().mapToInt(i -> i).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector singleNumber(vector& nums) { + sort(nums.begin(), nums.end()); + vector res; + int n = nums.size(); + + for (int i = 0; i < n; i++) { + if ((i > 0 && nums[i] == nums[i - 1]) || + (i + 1 < n && nums[i] == nums[i + 1])) { + continue; + } + res.push_back(nums[i]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + singleNumber(nums) { + nums.sort((a, b) => a - b); + const res = []; + const n = nums.length; + + for (let i = 0; i < n; i++) { + if ( + (i > 0 && nums[i] === nums[i - 1]) || + (i + 1 < n && nums[i] === nums[i + 1]) + ) { + continue; + } + res.push(nums[i]); + } + + return res; + } +} +``` + +```csharp +public class Solution { + public int[] SingleNumber(int[] nums) { + Array.Sort(nums); + List res = new List(); + int n = nums.Length; + + for (int i = 0; i < n; i++) { + if ((i > 0 && nums[i] == nums[i - 1]) || + (i + 1 < n && nums[i] == nums[i + 1])) { + continue; + } + res.Add(nums[i]); + } + + return res.ToArray(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. + +--- + +## 5. Bitwise XOR (Least Significant Bit) + +::tabs-start + +```python +class Solution: + def singleNumber(self, nums: List[int]) -> List[int]: + xor = 0 + for num in nums: + xor ^= num + + diff_bit = 1 + while not (xor & diff_bit): + diff_bit <<= 1 + + a = b = 0 + for num in nums: + if diff_bit & num: + a ^= num + else: + b ^= num + return [a, b] +``` + +```java +public class Solution { + public int[] singleNumber(int[] nums) { + int xor = 0; + for (int num : nums) { + xor ^= num; + } + + int diff_bit = 1; + while ((xor & diff_bit) == 0) { + diff_bit <<= 1; + } + + int a = 0, b = 0; + for (int num : nums) { + if ((num & diff_bit) != 0) { + a ^= num; + } else { + b ^= num; + } + } + return new int[]{a, b}; + } +} +``` + +```cpp +class Solution { +public: + vector singleNumber(vector& nums) { + int xor_all = 0; + for (int& num : nums) { + xor_all ^= num; + } + + int diff_bit = 1; + while ((xor_all & diff_bit) == 0) { + diff_bit <<= 1; + } + + int a = 0, b = 0; + for (int& num : nums) { + if (num & diff_bit) { + a ^= num; + } else { + b ^= num; + } + } + return {a, b}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + singleNumber(nums) { + let xor = 0; + for (const num of nums) { + xor ^= num; + } + + let diff_bit = 1; + while ((xor & diff_bit) === 0) { + diff_bit <<= 1; + } + + let a = 0, + b = 0; + for (const num of nums) { + if (num & diff_bit) { + a ^= num; + } else { + b ^= num; + } + } + return [a, b]; + } +} +``` + +```csharp +public class Solution { + public int[] SingleNumber(int[] nums) { + int xor = 0; + foreach (int num in nums) { + xor ^= num; + } + + int diffBit = 1; + while ((xor & diffBit) == 0) { + diffBit <<= 1; + } + + int a = 0, b = 0; + foreach (int num in nums) { + if ((num & diffBit) != 0) { + a ^= num; + } else { + b ^= num; + } + } + + return new int[] { a, b }; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 6. Bitwise XOR (Most Significant Bit) + +::tabs-start + +```python +class Solution: + def singleNumber(self, nums: List[int]) -> List[int]: + xor = 0 + for num in nums: + xor ^= num + + diff_bit = xor & (-xor) + + a = b = 0 + for num in nums: + if diff_bit & num: + a ^= num + else: + b ^= num + return [a, b] +``` + +```java +public class Solution { + public int[] singleNumber(int[] nums) { + int xor = 0; + for (int num : nums) { + xor ^= num; + } + + int diff_bit = xor & (-xor); + + int a = 0, b = 0; + for (int num : nums) { + if ((num & diff_bit) != 0) { + a ^= num; + } else { + b ^= num; + } + } + return new int[]{a, b}; + } +} +``` + +```cpp +class Solution { +public: + vector singleNumber(vector& nums) { + uint xor_all = 0; + for (int& num : nums) { + xor_all ^= num; + } + + int diff_bit = xor_all & (-xor_all); + + int a = 0, b = 0; + for (int& num : nums) { + if (num & diff_bit) { + a ^= num; + } else { + b ^= num; + } + } + return {a, b}; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + singleNumber(nums) { + let xor = 0; + for (const num of nums) { + xor ^= num; + } + + let diff_bit = xor & -xor; + + let a = 0, + b = 0; + for (const num of nums) { + if (num & diff_bit) { + a ^= num; + } else { + b ^= num; + } + } + return [a, b]; + } +} +``` + +```csharp +public class Solution { + public int[] SingleNumber(int[] nums) { + int xor = 0; + foreach (int num in nums) { + xor ^= num; + } + + int diffBit = xor & -xor; + + int a = 0, b = 0; + foreach (int num in nums) { + if ((num & diffBit) != 0) { + a ^= num; + } else { + b ^= num; + } + } + + return new int[] { a, b }; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/single-number.md b/articles/single-number.md index f46078213..f9aa4abf2 100644 --- a/articles/single-number.md +++ b/articles/single-number.md @@ -30,7 +30,7 @@ public class Solution { return nums[i]; } } - return -1; + return -1; } } ``` @@ -51,7 +51,7 @@ public: return nums[i]; } } - return -1; + return -1; } }; ``` @@ -136,12 +136,32 @@ class Solution { } ``` +```swift +class Solution { + func singleNumber(_ nums: [Int]) -> Int { + for i in 0.. Int { + var seen = Set() + + for num in nums { + if seen.contains(num) { + seen.remove(num) + } else { + seen.insert(num) + } + } + + return seen.first! + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -397,12 +435,31 @@ class Solution { } ``` +```swift +class Solution { + func singleNumber(_ nums: [Int]) -> Int { + var nums = nums.sorted() + var i = 0 + + while i < nums.count - 1 { + if nums[i] == nums[i + 1] { + i += 2 + } else { + return nums[i] + } + } + + return nums[i] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -494,9 +551,21 @@ class Solution { } ``` +```swift +class Solution { + func singleNumber(_ nums: [Int]) -> Int { + var res = 0 + for num in nums { + res ^= num + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/single-threaded-cpu.md b/articles/single-threaded-cpu.md index 5b7005989..ec2e4fe1f 100644 --- a/articles/single-threaded-cpu.md +++ b/articles/single-threaded-cpu.md @@ -31,7 +31,7 @@ class Solution: ```java public class Solution { public int[] getOrder(int[][] tasks) { - PriorityQueue available = new PriorityQueue<>((a, b) -> + PriorityQueue available = new PriorityQueue<>((a, b) -> a[0] == b[0] ? Integer.compare(a[1], b[1]) : Integer.compare(a[0], b[0]) ); PriorityQueue pending = new PriorityQueue<>(Comparator.comparingInt(a -> a[0])); @@ -109,12 +109,10 @@ class Solution { * @return {number[]} */ getOrder(tasks) { - const available = new MinPriorityQueue({ - compare: (a, b) => a[0] === b[0] ? a[1] - b[1] : a[0] - b[0] - }); - const pending = new MinPriorityQueue({ - compare: (a, b) => a[0] - b[0] - }); + const available = new PriorityQueue((a, b) => + a[0] === b[0] ? a[1] - b[1] : a[0] - b[0], + ); + const pending = new PriorityQueue((a, b) => a[0] - b[0]); tasks.forEach(([enqueueTime, processTime], i) => { pending.enqueue([enqueueTime, processTime, i]); @@ -143,12 +141,48 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] GetOrder(int[][] tasks) { + var available = new PriorityQueue<(int procTime, int index), (int procTime, int index)>(); + var pending = new PriorityQueue<(int startTime, int procTime, int index), int>(); + + int n = tasks.Length; + for (int i = 0; i < n; i++) { + pending.Enqueue((tasks[i][0], tasks[i][1], i), tasks[i][0]); + } + + long time = 0; + int[] res = new int[n]; + int idx = 0; + + while (pending.Count > 0 || available.Count > 0) { + while (pending.Count > 0 && pending.Peek().startTime <= time) { + var task = pending.Dequeue(); + available.Enqueue((task.procTime, task.index), (task.procTime, task.index)); + } + + if (available.Count == 0) { + time = pending.Peek().startTime; + continue; + } + + var next = available.Dequeue(); + time += next.procTime; + res[idx++] = next.index; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -189,7 +223,7 @@ public class Solution { Arrays.sort(tasks, Comparator.comparingInt(t -> t[0])); int[] res = new int[n]; - PriorityQueue minHeap = new PriorityQueue<>((a, b) -> + PriorityQueue minHeap = new PriorityQueue<>((a, b) -> a[0] == b[0] ? Integer.compare(a[1], b[1]) : Integer.compare(a[0], b[0]) ); @@ -259,11 +293,12 @@ class Solution { tasks.sort((a, b) => a[0] - b[0]); const res = []; - const minHeap = new MinPriorityQueue({ compare: (a, b) => - a[0] === b[0] ? a[1] - b[1] : a[0] - b[0] - }); + const minHeap = new PriorityQueue((a, b) => + a[0] === b[0] ? a[1] - b[1] : a[0] - b[0], + ); - let i = 0, time = tasks[0][0]; + let i = 0, + time = tasks[0][0]; while (minHeap.size() || i < n) { while (i < n && time >= tasks[i][0]) { minHeap.enqueue([tasks[i][1], tasks[i][2]]); @@ -282,12 +317,50 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] GetOrder(int[][] tasks) { + int n = tasks.Length; + int i = 0; + for (; i < n; i++) { + tasks[i] = new int[] { tasks[i][0], tasks[i][1], i }; // {enqueueTime, processingTime, index} + } + + Array.Sort(tasks, (a, b) => a[0].CompareTo(b[0])); // sort by enqueueTime + + int[] res = new int[n]; + var minHeap = new PriorityQueue<(int procTime, int index), (int procTime, int index)>(); + + int idx = 0; + i = 0; + long time = tasks[0][0]; + + while (minHeap.Count > 0 || i < n) { + while (i < n && tasks[i][0] <= time) { + minHeap.Enqueue((tasks[i][1], tasks[i][2]), (tasks[i][1], tasks[i][2])); + i++; + } + + if (minHeap.Count == 0) { + time = tasks[i][0]; + } else { + var task = minHeap.Dequeue(); + time += task.procTime; + res[idx++] = task.index; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -301,16 +374,16 @@ class Solution: n = len(tasks) indices = list(range(n)) indices.sort(key=lambda i: (tasks[i][0], i)) - + class Task: def __init__(self, idx): self.idx = idx - + def __lt__(self, other): if tasks[self.idx][1] != tasks[other.idx][1]: return tasks[self.idx][1] < tasks[other.idx][1] return self.idx < other.idx - + minHeap = [] res = [] time = i = 0 @@ -318,14 +391,14 @@ class Solution: while i < n and tasks[indices[i]][0] <= time: heapq.heappush(minHeap, Task(indices[i])) i += 1 - + if not minHeap: time = tasks[indices[i]][0] else: next_task = heapq.heappop(minHeap) time += tasks[next_task.idx][1] res.append(next_task.idx) - + return res ``` @@ -337,15 +410,15 @@ public class Solution { for (int i = 0; i < n; i++) { indices[i] = i; } - - Arrays.sort(indices, (a, b) -> + + Arrays.sort(indices, (a, b) -> tasks[a][0] != tasks[b][0] ? tasks[a][0] - tasks[b][0] : a - b ); - - PriorityQueue minHeap = new PriorityQueue<>((a, b) -> + + PriorityQueue minHeap = new PriorityQueue<>((a, b) -> tasks[a][1] != tasks[b][1] ? tasks[a][1] - tasks[b][1] : a - b ); - + int[] result = new int[n]; long time = 0; int i = 0, resIndex = 0; @@ -354,7 +427,7 @@ public class Solution { minHeap.offer(indices[i]); i++; } - + if (minHeap.isEmpty()) { time = tasks[indices[i]][0]; } else { @@ -363,7 +436,7 @@ public class Solution { result[resIndex++] = nextIndex; } } - + return result; } } @@ -379,26 +452,26 @@ public: iota(indices.begin(), indices.end(), 0); sort(indices.begin(), indices.end(), [&](int a, int b) { - return tasks[a][0] < tasks[b][0] || + return tasks[a][0] < tasks[b][0] || (tasks[a][0] == tasks[b][0] && a < b); }); - + auto comp = [&](int a, int b) { - return tasks[a][1] > tasks[b][1] || + return tasks[a][1] > tasks[b][1] || (tasks[a][1] == tasks[b][1] && a > b); }; priority_queue, decltype(comp)> minHeap(comp); - + vector result; long long time = 0; int i = 0; - + while (!minHeap.empty() || i < n) { while (i < n && tasks[indices[i]][0] <= time) { minHeap.push(indices[i]); i++; } - + if (minHeap.empty()) { time = tasks[indices[i]][0]; } else { @@ -408,7 +481,7 @@ public: result.push_back(nextIndex); } } - + return result; } }; @@ -430,13 +503,11 @@ class Solution { return a - b; }); - const minHeap = new MinPriorityQueue({ - compare: (a, b) => { - if (tasks[a][1] !== tasks[b][1]) { - return tasks[a][1] - tasks[b][1]; - } - return a - b; + const minHeap = new PriorityQueue((a, b) => { + if (tasks[a][1] !== tasks[b][1]) { + return tasks[a][1] - tasks[b][1]; } + return a - b; }); const res = []; @@ -457,15 +528,57 @@ class Solution { res.push(nextIndex); } } - + return res; } } ``` +```csharp +public class Solution { + public int[] GetOrder(int[][] tasks) { + int n = tasks.Length; + int[] indices = new int[n]; + int i = 0; + for (; i < n; i++) { + indices[i] = i; + } + + Array.Sort(indices, (a, b) => + tasks[a][0] != tasks[b][0] ? tasks[a][0].CompareTo(tasks[b][0]) : a.CompareTo(b) + ); + + var minHeap = new PriorityQueue(); + + int[] result = new int[n]; + long time = 0; + int resIndex = 0; + i = 0; + + while (minHeap.Count > 0 || i < n) { + while (i < n && tasks[indices[i]][0] <= time) { + int idx = indices[i]; + minHeap.Enqueue(idx, (tasks[idx][1], idx)); + i++; + } + + if (minHeap.Count == 0) { + time = tasks[indices[i]][0]; + } else { + int nextIndex = minHeap.Dequeue(); + time += tasks[nextIndex][1]; + result[resIndex++] = nextIndex; + } + } + + return result; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/sliding-window-maximum.md b/articles/sliding-window-maximum.md index c4accb268..9e2d695b0 100644 --- a/articles/sliding-window-maximum.md +++ b/articles/sliding-window-maximum.md @@ -21,7 +21,7 @@ public class Solution { public int[] maxSlidingWindow(int[] nums, int k) { int n = nums.length; int[] output = new int[n - k + 1]; - + for (int i = 0; i <= n - k; i++) { int maxi = nums[i]; for (int j = i; j < i + k; j++) { @@ -29,7 +29,7 @@ public class Solution { } output[i] = maxi; } - + return output; } } @@ -41,7 +41,7 @@ public: vector maxSlidingWindow(vector& nums, int k) { vector output; int n = nums.size(); - + for (int i = 0; i <= n - k; i++) { int maxi = nums[i]; for (int j = i; j < i + k; j++) { @@ -49,7 +49,7 @@ public: } output.push_back(maxi); } - + return output; } }; @@ -64,7 +64,7 @@ class Solution { */ maxSlidingWindow(nums, k) { let output = []; - + for (let i = 0; i <= nums.length - k; i++) { let maxi = nums[i]; for (let j = i; j < i + k; j++) { @@ -72,7 +72,7 @@ class Solution { } output.push(maxi); } - + return output; } } @@ -133,12 +133,32 @@ class Solution { } ``` +```swift +class Solution { + func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] { + var output = [Int]() + + for i in 0...(nums.count - k) { + var maxi = nums[i] + for j in i..<(i + k) { + maxi = max(maxi, nums[j]) + } + output.append(maxi) + } + + return output + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * k)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n * k)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n - k + 1)$ space for the output array. > Where $n$ is the length of the array and $k$ is the size of the window. @@ -288,7 +308,7 @@ public: class SegmentTree { /** * @constructor - * @param {number} N + * @param {number} N * @param {number[]} A */ constructor(N, A) { @@ -300,7 +320,7 @@ class SegmentTree { } /** - * @param {number} N + * @param {number} N * @param {number[]} A * @return {void} */ @@ -310,7 +330,7 @@ class SegmentTree { this.tree[this.n + i] = A[i]; } for (let i = this.n - 1; i > 0; i--) { - this.tree[i] = Math.max(this.tree[i << 1], this.tree[i << 1 | 1]); + this.tree[i] = Math.max(this.tree[i << 1], this.tree[(i << 1) | 1]); } } @@ -417,7 +437,7 @@ func NewSegmentTree(N int, A []int) *SegmentTree { for bits.OnesCount(uint(n)) != 1 { n++ } - + st := &SegmentTree{ n: n, } @@ -429,7 +449,7 @@ func (st *SegmentTree) build(N int, A []int) { st.tree = make([]int, 2*st.n) for i := range st.tree { st.tree[i] = math.MinInt - } + } for i := 0; i < N; i++ { st.tree[st.n+i] = A[i] } @@ -442,7 +462,7 @@ func (st *SegmentTree) Query(l, r int) int { res := math.MinInt l += st.n r += st.n + 1 - + for l < r { if l&1 == 1 { res = max(res, st.tree[l]) @@ -469,11 +489,11 @@ func maxSlidingWindow(nums []int, k int) []int { n := len(nums) segTree := NewSegmentTree(n, nums) output := make([]int, n-k+1) - + for i := 0; i <= n-k; i++ { output[i] = segTree.Query(i, i+k-1) } - + return output } ``` @@ -482,7 +502,7 @@ func maxSlidingWindow(nums []int, k int) []int { class SegmentTree(N: Int, A: IntArray) { private var n: Int = N private var tree: IntArray = IntArray(0) - + init { var size = N while (Integer.bitCount(size) != 1) { @@ -491,10 +511,10 @@ class SegmentTree(N: Int, A: IntArray) { n = size build(N, A) } - + private fun build(N: Int, A: IntArray) { tree = IntArray(2 * n) - tree.fill(Int.MIN_VALUE) + tree.fill(Int.MIN_VALUE) for (i in 0 until N) { tree[n + i] = A[i] } @@ -502,12 +522,12 @@ class SegmentTree(N: Int, A: IntArray) { tree[i] = maxOf(tree[i * 2], tree[i * 2 + 1]) } } - + fun query(l: Int, r: Int): Int { var res = Int.MIN_VALUE var left = l + n var right = r + n + 1 - + while (left < right) { if (left % 2 == 1) { res = maxOf(res, tree[left]) @@ -537,12 +557,70 @@ class Solution { } ``` +```swift +class SegmentTree { + private var n: Int + private var tree: [Int] + + init(_ N: Int, _ A: [Int]) { + self.n = N + while (self.n & (self.n - 1)) != 0 { + self.n += 1 + } + self.tree = [Int](repeating: Int.min, count: 2 * self.n) + build(N, A) + } + + private func build(_ N: Int, _ A: [Int]) { + for i in 0.. Int { + var res = Int.min + var l = l + n + var r = r + n + 1 + while l < r { + if l & 1 != 0 { + res = max(res, tree[l]) + l += 1 + } + if r & 1 != 0 { + r -= 1 + res = max(res, tree[r]) + } + l >>= 1 + r >>= 1 + } + return res + } +} + +class Solution { + func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] { + let n = nums.count + let segTree = SegmentTree(n, nums) + var output = [Int]() + + for i in 0...(n - k) { + output.append(segTree.query(i, i + k - 1)) + } + + return output + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -612,7 +690,7 @@ class Solution { * @return {number[]} */ maxSlidingWindow(nums, k) { - const heap = new MaxPriorityQueue(x => x[0]); + const heap = new MaxPriorityQueue((x) => x[0]); const output = []; const length = nums.length; @@ -635,9 +713,10 @@ class Solution { ```csharp public class Solution { public int[] MaxSlidingWindow(int[] nums, int k) { - PriorityQueue<(int val, int idx), int> pq = new PriorityQueue<(int val, int idx), int> - (Comparer.Create((a, b) => b.CompareTo(a))); - + PriorityQueue<(int val, int idx), int> pq = new PriorityQueue<(int val, int idx), int>( + Comparer.Create((a, b) => b.CompareTo(a)) + ); + int[] output = new int[nums.Length - k + 1]; int idx = 0; @@ -662,7 +741,7 @@ func maxSlidingWindow(nums []int, k int) []int { heap := priorityqueue.NewWith(func(a, b interface{}) int { return b.([2]int)[0] - a.([2]int)[0] }) - + output := []int{} for i := 0; i < len(nums); i++ { heap.Enqueue([2]int{nums[i], i}) @@ -700,12 +779,42 @@ class Solution { } ``` +```swift +class Solution { + func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] { + var heap = Heap() + var output = [Int]() + + for i in 0..= k - 1 { + while heap.max!.index <= i - k { + heap.removeMax() + } + output.append(heap.max!.num) + } + } + return output + } +} + +struct Item: Comparable { + let num: Int + let index: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.num < rhs.num + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -838,7 +947,10 @@ class Solution { if ((n - 1 - i) % k === 0) { rightMax[n - 1 - i] = nums[n - 1 - i]; } else { - rightMax[n - 1 - i] = Math.max(rightMax[n - i], nums[n - 1 - i]); + rightMax[n - 1 - i] = Math.max( + rightMax[n - i], + nums[n - 1 - i], + ); } } @@ -935,29 +1047,64 @@ class Solution { val n = nums.size val leftMax = IntArray(n) val rightMax = IntArray(n) - + leftMax[0] = nums[0] rightMax[n - 1] = nums[n - 1] - + for (i in 1 until n) { if (i % k == 0) { leftMax[i] = nums[i] } else { leftMax[i] = maxOf(leftMax[i - 1], nums[i]) } - + if ((n - 1 - i) % k == 0) { rightMax[n - 1 - i] = nums[n - 1 - i] } else { rightMax[n - 1 - i] = maxOf(rightMax[n - i], nums[n - 1 - i]) } } - + val output = IntArray(n - k + 1) for (i in 0..n - k) { output[i] = maxOf(leftMax[i + k - 1], rightMax[i]) } - + + return output + } +} +``` + +```swift +class Solution { + func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] { + let n = nums.count + var leftMax = [Int](repeating: 0, count: n) + var rightMax = [Int](repeating: 0, count: n) + + leftMax[0] = nums[0] + rightMax[n - 1] = nums[n - 1] + + for i in 1..= k) { + if (r + 1 >= k) { output[l] = nums[q.front()]; l++; } @@ -1130,24 +1278,24 @@ func maxSlidingWindow(nums []int, k int) []int { output := []int{} q := []int{} l, r := 0, 0 - + for r < len(nums) { for len(q) > 0 && nums[q[len(q)-1]] < nums[r] { q = q[:len(q)-1] } q = append(q, r) - + if l > q[0] { q = q[1:] } - + if (r + 1) >= k { output = append(output, nums[q[0]]) l += 1 } r += 1 } - + return output } ``` @@ -1159,32 +1307,61 @@ class Solution { val q = ArrayDeque() var l = 0 var r = 0 - + while (r < nums.size) { while (q.isNotEmpty() && nums[q.last()] < nums[r]) { q.removeLast() } q.addLast(r) - + if (l > q.first()) { q.removeFirst() } - + if ((r + 1) >= k) { output.add(nums[q.first()]) l += 1 } r += 1 } - + return output.toIntArray() } } ``` +```swift +class Solution { + func maxSlidingWindow(_ nums: [Int], _ k: Int) -> [Int] { + var output = [Int]() + var deque = [Int]() // Index + var l = 0, r = 0 + + while r < nums.count { + while !deque.isEmpty && nums[deque.last!] < nums[r] { + deque.removeLast() + } + deque.append(r) + + if l > deque.first! { + deque.removeFirst() + } + + if (r + 1) >= k { + output.append(nums[deque.first!]) + l += 1 + } + r += 1 + } + + return output + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/sliding-window-median.md b/articles/sliding-window-median.md new file mode 100644 index 000000000..5c98c3c0d --- /dev/null +++ b/articles/sliding-window-median.md @@ -0,0 +1,482 @@ +## 1. Brute Force (Sorting) + +::tabs-start + +```python +class Solution: + def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]: + res = [] + for i in range(len(nums) - k + 1): + tmp = nums[i:i + k][:] + tmp.sort() + if k & 1: + res.append(tmp[k // 2]) + else: + res.append((tmp[k // 2] + tmp[(k - 1) // 2]) / 2) + return res +``` + +```java +public class Solution { + public double[] medianSlidingWindow(int[] nums, int k) { + int n = nums.length - k + 1; + double[] res = new double[n]; + for (int i = 0; i < n; i++) { + int[] tmp = Arrays.copyOfRange(nums, i, i + k); + Arrays.sort(tmp); + if (k % 2 == 1) { + res[i] = tmp[k / 2]; + } else { + res[i] = (tmp[k / 2] + 0L + tmp[(k - 1) / 2]) / 2.0; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector medianSlidingWindow(vector& nums, int k) { + vector res; + for (int i = 0; i <= nums.size() - k; ++i) { + vector tmp(nums.begin() + i, nums.begin() + i + k); + sort(tmp.begin(), tmp.end()); + if (k % 2 == 1) { + res.push_back(tmp[k / 2]); + } else { + res.push_back((tmp[k / 2] + 0LL + tmp[(k - 1) / 2]) / 2.0); + } + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ + medianSlidingWindow(nums, k) { + const res = []; + for (let i = 0; i <= nums.length - k; i++) { + const tmp = nums.slice(i, i + k).sort((a, b) => a - b); + if (k % 2 === 1) { + res.push(tmp[Math.floor(k / 2)]); + } else { + res.push( + (tmp[Math.floor(k / 2)] + tmp[Math.floor((k - 1) / 2)]) / 2, + ); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * k\log k)$ +- Space complexity: + - $O(k)$ extra space. + - $O(n - k + 1)$ space for output array. + +> Where $n$ is the size of the array $nums$ and $k$ is the size of the sliding window. + +--- + +## 2. Two Heaps + +::tabs-start + +```python +class Solution: + def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]: + small, large = [], [] + d = defaultdict(int) + + for i in range(k): + heapq.heappush(small, -nums[i]) + for i in range(k // 2): + heapq.heappush(large, -heapq.heappop(small)) + + res = [-small[0] if k & 1 else (large[0] - small[0]) / 2] + for i in range(k, len(nums)): + d[nums[i - k]] += 1 + balance = -1 if small and nums[i - k] <= -small[0] else 1 + + if small and nums[i] <= -small[0]: + heapq.heappush(small, -nums[i]) + balance += 1 + else: + heapq.heappush(large, nums[i]) + balance -= 1 + + if balance > 0: + heapq.heappush(large, -heapq.heappop(small)) + if balance < 0: + heapq.heappush(small, -heapq.heappop(large)) + + while small and d[-small[0]] > 0: + d[-heapq.heappop(small)] -= 1 + + while large and d[large[0]] > 0: + d[heapq.heappop(large)] -= 1 + + res.append(-small[0] if k & 1 else (large[0] - small[0]) / 2) + + return res +``` + +```java +public class Solution { + public double[] medianSlidingWindow(int[] nums, int k) { + PriorityQueue small = new PriorityQueue<>(Collections.reverseOrder()); + PriorityQueue large = new PriorityQueue<>(); + Map d = new HashMap<>(); + + for (int i = 0; i < k; i++) { + small.add(nums[i]); + } + for (int i = 0; i < k / 2; i++) { + large.add(small.poll()); + } + + double[] res = new double[nums.length - k + 1]; + res[0] = k % 2 == 1 ? small.peek() : (large.peek() + 0L + small.peek()) / 2.0; + for (int i = k; i < nums.length; i++) { + d.put(nums[i - k], d.getOrDefault(nums[i - k], 0) + 1); + int balance = (small.size() > 0 && nums[i - k] <= small.peek()) ? -1 : 1; + + if (nums[i] <= small.peek()) { + small.add(nums[i]); + balance++; + } else { + large.add(nums[i]); + balance--; + } + + if (balance > 0) { + large.add(small.poll()); + } + if (balance < 0) { + small.add(large.poll()); + } + + while (!small.isEmpty() && d.getOrDefault(small.peek(), 0) > 0) { + d.put(small.peek(), d.get(small.peek()) - 1); + small.poll(); + } + while (!large.isEmpty() && d.getOrDefault(large.peek(), 0) > 0) { + d.put(large.peek(), d.get(large.peek()) - 1); + large.poll(); + } + + res[i - k + 1] = k % 2 == 1 ? small.peek() : (large.peek() + 0L + small.peek()) / 2.0; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector medianSlidingWindow(vector& nums, int k) { + priority_queue small; + priority_queue, greater> large; + unordered_map d; + + for (int i = 0; i < k; ++i) { + small.push(nums[i]); + } + for (int i = 0; i < k / 2; ++i) { + large.push(small.top()); + small.pop(); + } + + vector res; + res.push_back(k & 1 ? small.top() : (large.top() + 0LL + small.top()) / 2.0); + for (int i = k; i < nums.size(); ++i) { + d[nums[i - k]]++; + int balance = small.size() > 0 && nums[i - k] <= small.top() ? -1 : 1; + + if (nums[i] <= small.top()) { + small.push(nums[i]); + balance++; + } else { + large.push(nums[i]); + balance--; + } + + if (balance > 0) { + large.push(small.top()); + small.pop(); + } + if (balance < 0) { + small.push(large.top()); + large.pop(); + } + + while (!small.empty() && d[small.top()] > 0) { + d[small.top()]--; + small.pop(); + } + + while (!large.empty() && d[large.top()] > 0) { + d[large.top()]--; + large.pop(); + } + + res.push_back(k & 1 ? small.top() : (large.top() + 0LL + small.top()) / 2.0); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number[]} + */ + medianSlidingWindow(nums, k) { + const small = new MaxPriorityQueue({ compare: (a, b) => b - a }); + const large = new MinPriorityQueue({ compare: (a, b) => a - b }); + const d = new Map(); + + for (let i = 0; i < k; i++) { + small.enqueue(nums[i]); + } + for (let i = 0; i < Math.floor(k / 2); i++) { + large.enqueue(small.dequeue()); + } + + const res = [ + k % 2 === 1 ? small.front() : (large.front() + small.front()) / 2, + ]; + for (let i = k; i < nums.length; i++) { + const toRemove = nums[i - k]; + d.set(toRemove, (d.get(toRemove) || 0) + 1); + let balance = + small.size() > 0 && toRemove <= small.front() ? -1 : 1; + + if (nums[i] <= small.front()) { + small.enqueue(nums[i]); + balance++; + } else { + large.enqueue(nums[i]); + balance--; + } + + if (balance > 0) { + large.enqueue(small.dequeue()); + } + if (balance < 0) { + small.enqueue(large.dequeue()); + } + + while (small.size() > 0 && d.get(small.front()) > 0) { + d.set(small.front(), d.get(small.front()) - 1); + small.dequeue(); + } + while (large.size() > 0 && d.get(large.front()) > 0) { + d.set(large.front(), d.get(large.front()) - 1); + large.dequeue(); + } + + res.push( + k % 2 === 1 + ? small.front() + : (large.front() + small.front()) / 2, + ); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: + - $O(n)$ extra space. + - $O(n - k + 1)$ space for output array. + +> Where $n$ is the size of the array $nums$ and $k$ is the size of the sliding window. + +--- + +## 3. Two Multisets + +::tabs-start + +```python +class Solution: + def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]: + small, large = SortedList(), SortedList() + res = [] + for i in range(len(nums)): + if len(small) == 0 or nums[i] <= small[-1]: + small.add(nums[i]) + else: + large.add(nums[i]) + if i >= k: + if nums[i - k] in small: + small.remove(nums[i - k]) + else: + large.remove(nums[i - k]) + if len(small) > len(large) + 1: + large.add(small.pop()) + if len(large) > len(small): + small.add(large.pop(0)) + if i >= k - 1: + res.append(small[-1] if k & 1 else (small[-1] + large[0]) / 2) + return res +``` + +```java +public class Solution { + public double[] medianSlidingWindow(int[] nums, int k) { + TreeSet small = new TreeSet<>((a, b) -> + nums[a] != nums[b] ? Integer.compare(nums[a], nums[b]) : Integer.compare(a, b) + ); + TreeSet large = new TreeSet<>((a, b) -> + nums[a] != nums[b] ? Integer.compare(nums[a], nums[b]) : Integer.compare(a, b) + ); + double[] res = new double[nums.length - k + 1]; + for (int i = 0; i < nums.length; i++) { + if (small.isEmpty() || nums[i] <= nums[small.last()]) small.add(i); + else large.add(i); + if (i >= k) { + if (small.contains(i - k)) small.remove(i - k); + else large.remove(i - k); + } + while (small.size() > large.size() + 1) large.add(small.pollLast()); + while (large.size() > small.size()) small.add(large.pollFirst()); + if (i >= k - 1) { + res[i - k + 1] = k % 2 == 1 ? nums[small.last()] : + (nums[small.last()] + 0L + nums[large.first()]) / 2.0; + } + } + return res; + } +} +``` + +```cpp +class Solution { +public: + vector medianSlidingWindow(vector& nums, int k) { + multiset small, large; + vector res; + for (int i = 0; i < nums.size(); ++i) { + if (small.empty() || nums[i] <= *small.rbegin()) small.insert(nums[i]); + else large.insert(nums[i]); + if (i >= k) { + if (small.count(nums[i - k])) small.erase(small.find(nums[i - k])); + else large.erase(large.find(nums[i - k])); + } + if (small.size() > large.size() + 1) { + large.insert(*small.rbegin()); + small.erase(prev(small.end())); + } + if (large.size() > small.size()) { + small.insert(*large.begin()); + large.erase(large.begin()); + } + if (i >= k - 1) { + res.push_back( + k % 2 == 1 ? *small.rbegin() : + ((*small.rbegin() + 0LL + *large.begin()) / 2.0) + ); + } + } + return res; + } +}; +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log k)$ +- Space complexity: + - $O(k)$ extra space. + - $O(n - k + 1)$ space for output array. + +> Where $n$ is the size of the array $nums$ and $k$ is the size of the sliding window. + +--- + +## 4. Multiset + +::tabs-start + +```python +class Solution: + def medianSlidingWindow(self, nums: List[int], k: int) -> List[float]: + window = SortedList() + res = [] + for i in range(len(nums)): + window.add(nums[i]) + if i >= k: + window.remove(nums[i - k]) + if i >= k - 1: + if k % 2 == 1: + res.append(float(window[k // 2])) + else: + res.append((window[k // 2 - 1] + window[k // 2]) / 2) + return res +``` + +```cpp +class Solution { +public: + vector medianSlidingWindow(vector& nums, int k) { + multiset window(nums.begin(), nums.begin() + k); + auto mid = next(window.begin(), k / 2); + vector res; + + for (int i = k;; i++) { + if (k & 1) { + res.push_back(*mid); + } else { + res.push_back((*mid + 0LL + *prev(mid)) / 2.0); + } + + if (i == nums.size()) return res; + + window.insert(nums[i]); + if (nums[i] < *mid) mid--; + if (nums[i - k] <= *mid) mid++; + window.erase(window.lower_bound(nums[i - k])); + } + } +}; +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log k)$ +- Space complexity: + - $O(k)$ extra space. + - $O(n - k + 1)$ space for output array. + +> Where $n$ is the size of the array $nums$ and $k$ is the size of the sliding window. diff --git a/articles/smallest-string-starting-from-leaf.md b/articles/smallest-string-starting-from-leaf.md new file mode 100644 index 000000000..cc389e666 --- /dev/null +++ b/articles/smallest-string-starting-from-leaf.md @@ -0,0 +1,474 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def smallestFromLeaf(self, root: Optional[TreeNode]) -> str: + def dfs(root, cur): + if not root: + return + + cur = chr(ord('a') + root.val) + cur + if root.left and root.right: + return min( + dfs(root.left, cur), + dfs(root.right, cur) + ) + + if root.right: + return dfs(root.right, cur) + if root.left: + return dfs(root.left, cur) + return cur + + return dfs(root, "") +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public String smallestFromLeaf(TreeNode root) { + return dfs(root, ""); + } + + private String dfs(TreeNode root, String cur) { + if (root == null) { + return null; + } + + cur = (char) ('a' + root.val) + cur; + if (root.left != null && root.right != null) { + return min(dfs(root.left, cur), dfs(root.right, cur)); + } + + if (root.right != null) { + return dfs(root.right, cur); + } + if (root.left != null) { + return dfs(root.left, cur); + } + return cur; + } + + private String min(String a, String b) { + if (a == null) return b; + if (b == null) return a; + return a.compareTo(b) < 0 ? a : b; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + string smallestFromLeaf(TreeNode* root) { + return dfs(root, ""); + } + +private: + string dfs(TreeNode* root, string cur) { + if (!root) return ""; + + cur = char('a' + root->val) + cur; + if (root->left && root->right) { + return min(dfs(root->left, cur), dfs(root->right, cur)); + } + + if (root->right) return dfs(root->right, cur); + if (root->left) return dfs(root->left, cur); + return cur; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {string} + */ + smallestFromLeaf(root) { + const min = (a, b) => { + if (!a) return b; + if (!b) return a; + return a < b ? a : b; + }; + + const dfs = (node, cur) => { + if (!node) return; + + cur = String.fromCharCode(97 + node.val) + cur; + + if (node.left && node.right) { + return min(dfs(node.left, cur), dfs(node.right, cur)); + } + if (node.left) return dfs(node.left, cur); + if (node.right) return dfs(node.right, cur); + return cur; + }; + + return dfs(root, ''); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def smallestFromLeaf(self, root: Optional[TreeNode]) -> str: + q = deque([(root, "")]) + res = None + + while q: + node, cur = q.popleft() + cur = chr(ord('a') + node.val) + cur + + if not node.left and not node.right: + res = min(res, cur) if res else cur + + if node.left: + q.append((node.left, cur)) + if node.right: + q.append((node.right, cur)) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public String smallestFromLeaf(TreeNode root) { + Queue> q = new LinkedList<>(); + q.offer(new Pair<>(root, "")); + String res = null; + + while (!q.isEmpty()) { + Pair pair = q.poll(); + TreeNode node = pair.getKey(); + String cur = (char) ('a' + node.val) + pair.getValue(); + + if (node.left == null && node.right == null) { + if (res == null || cur.compareTo(res) < 0) { + res = cur; + } + } + + if (node.left != null) q.offer(new Pair<>(node.left, cur)); + if (node.right != null) q.offer(new Pair<>(node.right, cur)); + } + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + string smallestFromLeaf(TreeNode* root) { + queue> q; + q.push({root, ""}); + string res; + + while (!q.empty()) { + auto [node, cur] = q.front(); + q.pop(); + cur = char('a' + node->val) + cur; + + if (!node->left && !node->right) { + if (res.empty() || cur < res) { + res = cur; + } + } + + if (node->left) q.push({node->left, cur}); + if (node->right) q.push({node->right, cur}); + } + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {string} + */ + smallestFromLeaf(root) { + const q = new Queue(); + q.push([root, '']); + let res = null; + + while (!q.isEmpty()) { + const [node, cur] = q.pop(); + const newCur = String.fromCharCode(97 + node.val) + cur; + + if (!node.left && !node.right) { + res = res === null || newCur < res ? newCur : res; + } + + if (node.left) q.push([node.left, newCur]); + if (node.right) q.push([node.right, newCur]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def smallestFromLeaf(self, root: Optional[TreeNode]) -> str: + stack = [(root, "")] + res = None + + while stack: + node, cur = stack.pop() + cur = chr(ord('a') + node.val) + cur + + if not node.left and not node.right: + res = min(res, cur) if res else cur + + if node.right: + stack.append((node.right, cur)) + if node.left: + stack.append((node.left, cur)) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public String smallestFromLeaf(TreeNode root) { + Stack> stack = new Stack<>(); + stack.push(new Pair<>(root, "")); + String res = null; + + while (!stack.isEmpty()) { + Pair pair = stack.pop(); + TreeNode node = pair.getKey(); + String cur = (char) ('a' + node.val) + pair.getValue(); + + if (node.left == null && node.right == null) { + if (res == null || cur.compareTo(res) < 0) { + res = cur; + } + } + + if (node.right != null) stack.push(new Pair<>(node.right, cur)); + if (node.left != null) stack.push(new Pair<>(node.left, cur)); + } + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + string smallestFromLeaf(TreeNode* root) { + stack> stk; + stk.push({root, ""}); + string res; + + while (!stk.empty()) { + auto [node, cur] = stk.top();stk.pop(); + cur = char('a' + node->val) + cur; + + if (!node->left && !node->right) { + if (res.empty() || cur < res) { + res = cur; + } + } + + if (node->right) stk.push({node->right, cur}); + if (node->left) stk.push({node->left, cur}); + } + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {string} + */ + smallestFromLeaf(root) { + const stack = [[root, '']]; + let res = null; + + while (stack.length) { + const [node, cur] = stack.pop(); + const newCur = String.fromCharCode(97 + node.val) + cur; + + if (!node.left && !node.right) { + res = res === null || newCur < res ? newCur : res; + } + + if (node.right) stack.push([node.right, newCur]); + if (node.left) stack.push([node.left, newCur]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ diff --git a/articles/snakes-and-ladders.md b/articles/snakes-and-ladders.md index afc71ef47..964c7d1fd 100644 --- a/articles/snakes-and-ladders.md +++ b/articles/snakes-and-ladders.md @@ -6,7 +6,7 @@ class Solution: def snakesAndLadders(self, board: List[List[int]]) -> int: n = len(board) - + def intToPos(square): r = (square - 1) // n c = (square - 1) % n @@ -14,26 +14,26 @@ class Solution: c = n - 1 - c r = n - 1 - r return r, c - + q = deque([(1, 0)]) visit = set() - + while q: square, moves = q.popleft() - + for i in range(1, 7): nextSquare = square + i r, c = intToPos(nextSquare) if board[r][c] != -1: nextSquare = board[r][c] - + if nextSquare == n * n: return moves + 1 - + if nextSquare not in visit: visit.add(nextSquare) q.append((nextSquare, moves + 1)) - + return -1 ``` @@ -44,11 +44,11 @@ public class Solution { Queue q = new LinkedList<>(); q.offer(new int[]{1, 0}); Set visit = new HashSet<>(); - + while (!q.isEmpty()) { int[] cur = q.poll(); int square = cur[0], moves = cur[1]; - + for (int i = 1; i <= 6; i++) { int nextSquare = square + i; int[] pos = intToPos(nextSquare, n); @@ -65,7 +65,7 @@ public class Solution { } return -1; } - + private int[] intToPos(int square, int n) { int r = (square - 1) / n; int c = (square - 1) % n; @@ -103,7 +103,7 @@ public: } return -1; } - + private: pair intToPos(int square, int n) { int r = (square - 1) / n; @@ -159,8 +159,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -172,7 +172,7 @@ class Solution { class Solution: def snakesAndLadders(self, board: List[List[int]]) -> int: n = len(board) - + def intToPos(square): r = (square - 1) // n c = (square - 1) % n @@ -180,29 +180,29 @@ class Solution: c = n - 1 - c r = n - 1 - r return r, c - + dist = [-1] * (n * n + 1) q = deque([1]) dist[1] = 0 - + while q: square = q.popleft() - + for i in range(1, 7): nextSquare = square + i if nextSquare > n * n: break - + r, c = intToPos(nextSquare) if board[r][c] != -1: nextSquare = board[r][c] - + if dist[nextSquare] == -1: dist[nextSquare] = dist[square] + 1 if nextSquare == n * n: return dist[nextSquare] q.append(nextSquare) - + return -1 ``` @@ -359,8 +359,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -372,7 +372,7 @@ class Solution { class Solution: def snakesAndLadders(self, board: List[List[int]]) -> int: n = len(board) - + def intToPos(square): r = (square - 1) // n c = (square - 1) % n @@ -380,31 +380,31 @@ class Solution: c = n - 1 - c r = n - 1 - r return r, c - + q = deque([1]) board[n - 1][0] = 0 moves = 0 - + while q: for _ in range(len(q)): square = q.popleft() - + for i in range(1, 7): nextSquare = square + i if nextSquare > n * n: break - + r, c = intToPos(nextSquare) if board[r][c] != -1: nextSquare = board[r][c] - + if board[r][c] != 0: if nextSquare == n * n: return moves + 1 q.append(nextSquare) board[r][c] = 0 moves += 1 - + return -1 ``` @@ -437,7 +437,7 @@ public class Solution { if (nextSquare == n * n) { return moves + 1; } - + board[r][c] = 0; q.add(nextSquare); } @@ -489,7 +489,7 @@ public: if (nextSquare == n * n) { return moves + 1; } - + board[r][c] = 0; q.push(nextSquare); } @@ -550,7 +550,7 @@ class Solution { if (nextSquare === n * n) { return moves + 1; } - + board[r][c] = 0; queue.push(nextSquare); } @@ -568,5 +568,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ \ No newline at end of file +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ diff --git a/articles/solving-questions-with-brainpower.md b/articles/solving-questions-with-brainpower.md index 248ec63b3..d0774539e 100644 --- a/articles/solving-questions-with-brainpower.md +++ b/articles/solving-questions-with-brainpower.md @@ -49,7 +49,10 @@ class Solution { mostPoints(questions) { const dfs = (i) => { if (i >= questions.length) return 0; - return Math.max(dfs(i + 1), questions[i][0] + dfs(i + 1 + questions[i][1])); + return Math.max( + dfs(i + 1), + questions[i][0] + dfs(i + 1 + questions[i][1]), + ); }; return dfs(0); } @@ -60,8 +63,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -134,7 +137,10 @@ class Solution { const dfs = (i) => { if (i >= questions.length) return 0; if (dp[i] !== -1) return dp[i]; - dp[i] = Math.max(dfs(i + 1), questions[i][0] + dfs(i + 1 + questions[i][1])); + dp[i] = Math.max( + dfs(i + 1), + questions[i][0] + dfs(i + 1 + questions[i][1]), + ); return dp[i]; }; @@ -147,8 +153,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -163,7 +169,7 @@ class Solution: for i in range(len(questions) - 1, -1, -1): dp[i] = max( - questions[i][0] + dp.get(i + 1 + questions[i][1], 0), + questions[i][0] + dp.get(i + 1 + questions[i][1], 0), dp.get(i + 1, 0) ) return dp.get(0) @@ -177,7 +183,7 @@ public class Solution { for (int i = n - 1; i >= 0; i--) { dp[i] = Math.max( - questions[i][0] + (i + 1 + questions[i][1] < n ? dp[i + 1 + questions[i][1]] : 0), + questions[i][0] + (i + 1 + questions[i][1] < n ? dp[i + 1 + questions[i][1]] : 0), dp[i + 1] ); } @@ -195,7 +201,7 @@ public: for (int i = n - 1; i >= 0; i--) { dp[i] = max( - (long long)questions[i][0] + (i + 1 + questions[i][1] < n ? dp[i + 1 + questions[i][1]] : 0), + (long long)questions[i][0] + (i + 1 + questions[i][1] < n ? dp[i + 1 + questions[i][1]] : 0), dp[i + 1] ); } @@ -216,8 +222,11 @@ class Solution { for (let i = n - 1; i >= 0; i--) { dp[i] = Math.max( - questions[i][0] + (i + 1 + questions[i][1] < n ? dp[i + 1 + questions[i][1]] : 0), - dp[i + 1] + questions[i][0] + + (i + 1 + questions[i][1] < n + ? dp[i + 1 + questions[i][1]] + : 0), + dp[i + 1], ); } return dp[0]; @@ -229,5 +238,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/sort-an-array.md b/articles/sort-an-array.md index ba9edb507..4dbf28c54 100644 --- a/articles/sort-an-array.md +++ b/articles/sort-an-array.md @@ -55,43 +55,43 @@ public class Solution { private int partition(int[] nums, int left, int right) { int mid = (left + right) >> 1; swap(nums, mid, left + 1); - - if (nums[left] > nums[right]) + + if (nums[left] > nums[right]) swap(nums, left, right); - if (nums[left + 1] > nums[right]) + if (nums[left + 1] > nums[right]) swap(nums, left + 1, right); - if (nums[left] > nums[left + 1]) + if (nums[left] > nums[left + 1]) swap(nums, left, left + 1); - + int pivot = nums[left + 1]; int i = left + 1; int j = right; - + while (true) { while (nums[++i] < pivot); while (nums[--j] > pivot); if (i > j) break; swap(nums, i, j); } - + nums[left + 1] = nums[j]; nums[j] = pivot; return j; } - + private void swap(int[] nums, int i, int j) { int temp = nums[i]; nums[i] = nums[j]; nums[j] = temp; } - + private void quickSort(int[] nums, int left, int right) { if (right <= left + 1) { if (right == left + 1 && nums[right] < nums[left]) swap(nums, left, right); return; } - + int j = partition(nums, left, right); quickSort(nums, left, j - 1); quickSort(nums, j + 1, right); @@ -110,30 +110,30 @@ public: int partition(vector& nums, int left, int right) { int mid = (left + right) >> 1; swap(nums[mid], nums[left + 1]); - - if (nums[left] > nums[right]) + + if (nums[left] > nums[right]) swap(nums[left], nums[right]); - if (nums[left + 1] > nums[right]) + if (nums[left + 1] > nums[right]) swap(nums[left + 1], nums[right]); - if (nums[left] > nums[left + 1]) + if (nums[left] > nums[left + 1]) swap(nums[left], nums[left + 1]); - + int pivot = nums[left + 1]; int i = left + 1; int j = right; - + while (true) { while (nums[++i] < pivot); while (nums[--j] > pivot); if (i > j) break; swap(nums[i], nums[j]); } - + nums[left + 1] = nums[j]; nums[j] = pivot; return j; } - + void quickSort(vector& nums, int left, int right) { if (right <= left + 1) { if (right == left + 1 && nums[right] < nums[left]) @@ -163,54 +163,106 @@ class Solution { function partition(left, right) { const mid = (left + right) >> 1; [nums[mid], nums[left + 1]] = [nums[left + 1], nums[mid]]; - + if (nums[left] > nums[right]) [nums[left], nums[right]] = [nums[right], nums[left]]; if (nums[left + 1] > nums[right]) [nums[left + 1], nums[right]] = [nums[right], nums[left + 1]]; if (nums[left] > nums[left + 1]) [nums[left], nums[left + 1]] = [nums[left + 1], nums[left]]; - + const pivot = nums[left + 1]; let i = left + 1; let j = right; - + while (true) { while (nums[++i] < pivot); while (nums[--j] > pivot); if (i > j) break; [nums[i], nums[j]] = [nums[j], nums[i]]; } - + nums[left + 1] = nums[j]; nums[j] = pivot; return j; } - + function quickSort(left, right) { if (right <= left + 1) { if (right == left + 1 && nums[right] < nums[left]) [nums[left], nums[right]] = [nums[right], nums[left]]; return; } - + const j = partition(left, right); quickSort(left, j - 1); quickSort(j + 1, right); } - + quickSort(0, nums.length - 1); return nums; } } ``` +```csharp +public class Solution { + public int[] SortArray(int[] nums) { + QuickSort(nums, 0, nums.Length - 1); + return nums; + } + + private void QuickSort(int[] nums, int left, int right) { + if (right <= left + 1) { + if (right == left + 1 && nums[right] < nums[left]) { + Swap(nums, left, right); + } + return; + } + + int j = Partition(nums, left, right); + QuickSort(nums, left, j - 1); + QuickSort(nums, j + 1, right); + } + + private int Partition(int[] nums, int left, int right) { + int mid = (left + right) >> 1; + Swap(nums, mid, left + 1); + + if (nums[left] > nums[right]) Swap(nums, left, right); + if (nums[left + 1] > nums[right]) Swap(nums, left + 1, right); + if (nums[left] > nums[left + 1]) Swap(nums, left, left + 1); + + int pivot = nums[left + 1]; + int i = left + 1, j = right; + + while (true) { + while (++i <= right && nums[i] < pivot) ; + while (--j >= left && nums[j] > pivot) ; + + if (i > j) break; + + Swap(nums, i, j); + } + + Swap(nums, left + 1, j); + return j; + } + + private void Swap(int[] nums, int i, int j) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ in average case, $O(n ^ 2)$ in worst case. -* Space complexity: $O(\log n)$ for recursive stack. +- Time complexity: $O(n \log n)$ in average case, $O(n ^ 2)$ in worst case. +- Space complexity: $O(\log n)$ for recursive stack. --- @@ -241,7 +293,7 @@ class Solution: nums[i] = right[k] k += 1 i += 1 - + def mergeSort(arr, l, r): if l == r: return @@ -251,7 +303,7 @@ class Solution: mergeSort(arr, m + 1, r) merge(arr, l, m, r) return - + mergeSort(nums, 0, len(nums)) return nums ``` @@ -355,11 +407,11 @@ class Solution { } /** - * @param {number[]} arr - * @param {number} l - * @param {number} r - * @return {void} - */ + * @param {number[]} arr + * @param {number} l + * @param {number} r + * @return {void} + */ mergeSort(arr, l, r) { if (l >= r) return; let m = Math.floor((l + r) / 2); @@ -369,15 +421,16 @@ class Solution { } /** - * @param {number[]} arr - * @param {number} l - * @param {number} m - * @param {number} r - * @return {void} - */ + * @param {number[]} arr + * @param {number} l + * @param {number} m + * @param {number} r + * @return {void} + */ merge(arr, l, m, r) { let temp = []; - let i = l, j = m + 1; + let i = l, + j = m + 1; while (i <= m && j <= r) { if (arr[i] <= arr[j]) { @@ -397,12 +450,53 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] SortArray(int[] nums) { + MergeSort(nums, 0, nums.Length - 1); + return nums; + } + + private void MergeSort(int[] arr, int l, int r) { + if (l == r) return; + + int m = (l + r) / 2; + MergeSort(arr, l, m); + MergeSort(arr, m + 1, r); + Merge(arr, l, m, r); + } + + private void Merge(int[] arr, int L, int M, int R) { + int[] left = arr[L..(M + 1)]; + int[] right = arr[(M + 1)..(R + 1)]; + + int i = L, j = 0, k = 0; + + while (j < left.Length && k < right.Length) { + if (left[j] <= right[k]) { + arr[i++] = left[j++]; + } else { + arr[i++] = right[k++]; + } + } + + while (j < left.Length) { + arr[i++] = left[j++]; + } + + while (k < right.Length) { + arr[i++] = right[k++]; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -415,27 +509,27 @@ class Solution: def sortArray(self, nums: List[int]) -> List[int]: self.heapSort(nums) return nums - + def heapify(self, arr, n, i): l = (i << 1) + 1 r = (i << 1) + 2 largestNode = i - + if l < n and arr[l] > arr[largestNode]: largestNode = l - + if r < n and arr[r] > arr[largestNode]: largestNode = r - + if largestNode != i: arr[i], arr[largestNode] = arr[largestNode], arr[i] self.heapify(arr, n, largestNode) - + def heapSort(self, arr): n = len(arr) for i in range(n // 2 - 1, -1, -1): self.heapify(arr, n, i) - + for i in range(n - 1, 0, -1): arr[0], arr[i] = arr[i], arr[0] self.heapify(arr, i, 0) @@ -447,20 +541,20 @@ public class Solution { heapSort(nums); return nums; } - + private void heapify(int[] arr, int n, int i) { int l = (i << 1) + 1; int r = (i << 1) + 2; int largestNode = i; - + if (l < n && arr[l] > arr[largestNode]) { largestNode = l; } - + if (r < n && arr[r] > arr[largestNode]) { largestNode = r; } - + if (largestNode != i) { int temp = arr[i]; arr[i] = arr[largestNode]; @@ -468,13 +562,13 @@ public class Solution { heapify(arr, n, largestNode); } } - + private void heapSort(int[] arr) { int n = arr.length; for (int i = n / 2 - 1; i >= 0; i--) { heapify(arr, n, i); } - + for (int i = n - 1; i > 0; i--) { int temp = arr[0]; arr[0] = arr[i]; @@ -497,27 +591,27 @@ private: int l = (i << 1) + 1; int r = (i << 1) + 2; int largestNode = i; - + if (l < n && arr[l] > arr[largestNode]) { largestNode = l; } - + if (r < n && arr[r] > arr[largestNode]) { largestNode = r; } - + if (largestNode != i) { swap(arr[i], arr[largestNode]); heapify(arr, n, largestNode); } } - + void heapSort(vector& arr) { int n = arr.size(); for (int i = n / 2 - 1; i >= 0; i--) { heapify(arr, n, i); } - + for (int i = n - 1; i > 0; i--) { swap(arr[0], arr[i]); heapify(arr, i, 0); @@ -529,49 +623,49 @@ private: ```javascript class Solution { /** - * @param {number[]} nums - * @return {number[]} - */ + * @param {number[]} nums + * @return {number[]} + */ sortArray(nums) { this.heapSort(nums); return nums; } - + /** - * @param {number[]} arr - * @param {number} n - * @param {number} i - * @return {void} - */ + * @param {number[]} arr + * @param {number} n + * @param {number} i + * @return {void} + */ heapify(arr, n, i) { let l = (i << 1) + 1; let r = (i << 1) + 2; let largestNode = i; - + if (l < n && arr[l] > arr[largestNode]) { largestNode = l; } - + if (r < n && arr[r] > arr[largestNode]) { largestNode = r; } - + if (largestNode !== i) { [arr[i], arr[largestNode]] = [arr[largestNode], arr[i]]; this.heapify(arr, n, largestNode); } } - + /** - * @param {number[]} arr - * @return {void} - */ + * @param {number[]} arr + * @return {void} + */ heapSort(arr) { let n = arr.length; for (let i = Math.floor(n / 2) - 1; i >= 0; i--) { this.heapify(arr, n, i); } - + for (let i = n - 1; i > 0; i--) { [arr[0], arr[i]] = [arr[i], arr[0]]; this.heapify(arr, i, 0); @@ -580,12 +674,59 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] SortArray(int[] nums) { + HeapSort(nums); + return nums; + } + + private void Heapify(int[] arr, int n, int i) { + int l = (i << 1) + 1; + int r = (i << 1) + 2; + int largestNode = i; + + if (l < n && arr[l] > arr[largestNode]) { + largestNode = l; + } + + if (r < n && arr[r] > arr[largestNode]) { + largestNode = r; + } + + if (largestNode != i) { + Swap(arr, i, largestNode); + Heapify(arr, n, largestNode); + } + } + + private void HeapSort(int[] arr) { + int n = arr.Length; + + for (int i = n / 2 - 1; i >= 0; i--) { + Heapify(arr, n, i); + } + + for (int i = n - 1; i > 0; i--) { + Swap(arr, 0, i); + Heapify(arr, i, 0); + } + } + + private void Swap(int[] arr, int i, int j) { + int temp = arr[i]; + arr[i] = arr[j]; + arr[j] = temp; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(\log n)$ for recursive stack. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(\log n)$ for recursive stack. --- @@ -618,13 +759,13 @@ public class Solution { private void countingSort(int[] arr) { HashMap count = new HashMap<>(); int minVal = arr[0], maxVal = arr[0]; - + for (int i = 0; i < arr.length; i++) { minVal = Math.min(minVal, arr[i]); maxVal = Math.max(maxVal, arr[i]); count.put(arr[i], count.getOrDefault(arr[i], 0) + 1); } - + int index = 0; for (int val = minVal; val <= maxVal; ++val) { while (count.getOrDefault(val, 0) > 0) { @@ -653,7 +794,7 @@ private: for (auto& val : arr) { count[val]++; } - + int index = 0; for (int val = minVal; val <= maxVal; ++val) { while (count[val] > 0) { @@ -675,30 +816,30 @@ public: ```javascript class Solution { /** - * @param {number[]} nums - * @return {number[]} - */ + * @param {number[]} nums + * @return {number[]} + */ sortArray(nums) { this.countingSort(nums); return nums; } - + /** - * @param {number[]} arr - * @return {void} - */ + * @param {number[]} arr + * @return {void} + */ countingSort(arr) { let count = new Map(); - let minVal = Math.min(...nums); - let maxVal = Math.max(...nums); + let minVal = Math.min(...nums); + let maxVal = Math.max(...nums); - nums.forEach(val => { + nums.forEach((val) => { if (!count.has(val)) { count.set(val, 0); } - count.set(val, count.get(val) + 1); + count.set(val, count.get(val) + 1); }); - + let index = 0; for (let val = minVal; val <= maxVal; val += 1) { while (count.get(val) > 0) { @@ -711,12 +852,43 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] SortArray(int[] nums) { + CountingSort(nums); + return nums; + } + + private void CountingSort(int[] nums) { + Dictionary count = new Dictionary(); + int minVal = int.MaxValue, maxVal = int.MinValue; + + foreach (int val in nums) { + if (!count.ContainsKey(val)) { + count[val] = 0; + } + count[val]++; + minVal = Math.Min(minVal, val); + maxVal = Math.Max(maxVal, val); + } + + int index = 0; + for (int val = minVal; val <= maxVal; val++) { + if (!count.ContainsKey(val)) continue; + while (count[val]-- > 0) { + nums[index++] = val; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n + k)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n + k)$ +- Space complexity: $O(n)$ > Where $n$ is the size of the array $nums$ and $k$ is the range between the minimum and maximum values in the array. @@ -914,8 +1086,8 @@ class Solution { * @return {number[]} */ sortArray(nums) { - const negatives = nums.filter(num => num < 0).map(num => -num); - const positives = nums.filter(num => num >= 0); + const negatives = nums.filter((num) => num < 0).map((num) => -num); + const positives = nums.filter((num) => num >= 0); if (negatives.length > 0) { this.radixSort(negatives); @@ -974,12 +1146,80 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] SortArray(int[] nums) { + List negatives = new List(); + List positives = new List(); + + foreach (int num in nums) { + if (num < 0) negatives.Add(-num); + else positives.Add(num); + } + + if (negatives.Count > 0) { + RadixSort(negatives); + negatives.Reverse(); + for (int i = 0; i < negatives.Count; i++) { + negatives[i] = -negatives[i]; + } + } + + if (positives.Count > 0) { + RadixSort(positives); + } + + List result = new List(); + result.AddRange(negatives); + result.AddRange(positives); + + return result.ToArray(); + } + + private void RadixSort(List arr) { + int n = arr.Count; + int maxElement = 0; + foreach (int num in arr) { + if (num > maxElement) maxElement = num; + } + + int d = 1; + while (maxElement / d > 0) { + CountSort(arr, n, d); + d *= 10; + } + } + + private void CountSort(List arr, int n, int d) { + int[] count = new int[10]; + for (int i = 0; i < n; i++) { + int digit = (arr[i] / d) % 10; + count[digit]++; + } + + for (int i = 1; i < 10; i++) { + count[i] += count[i - 1]; + } + + int[] res = new int[n]; + for (int i = n - 1; i >= 0; i--) { + int digit = (arr[i] / d) % 10; + res[--count[digit]] = arr[i]; + } + + for (int i = 0; i < n; i++) { + arr[i] = res[i]; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(d * n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(d * n)$ +- Space complexity: $O(n)$ > Where $n$ is the size of the array $nums$ and $d$ is the number of digits in the maximum element of the array. @@ -1003,7 +1243,7 @@ class Solution: j -= gap nums[j + gap] = tmp gap //= 2 - + n = len(nums) if n == 1: return nums @@ -1089,7 +1329,7 @@ class Solution { } gap = Math.floor(gap / 2); } - } + }; shellSort(); return nums; @@ -1097,9 +1337,37 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] SortArray(int[] nums) { + int n = nums.Length; + if (n == 1) return nums; + + ShellSort(nums, n); + return nums; + } + + private void ShellSort(int[] nums, int n) { + int gap = n / 2; + while (gap >= 1) { + for (int i = gap; i < n; i++) { + int tmp = nums[i]; + int j = i - gap; + while (j >= 0 && nums[j] > tmp) { + nums[j + gap] = nums[j]; + j -= gap; + } + nums[j + gap] = tmp; + } + gap /= 2; + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ in average case, $O(n ^ 2)$ in worst case. -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n \log n)$ in average case, $O(n ^ 2)$ in worst case. +- Space complexity: $O(1)$ diff --git a/articles/sort-array-by-increasing-frequency.md b/articles/sort-array-by-increasing-frequency.md new file mode 100644 index 000000000..b763527da --- /dev/null +++ b/articles/sort-array-by-increasing-frequency.md @@ -0,0 +1,79 @@ +## 1. Custom Sort + +::tabs-start + +```python +class Solution: + def frequencySort(self, nums: List[int]) -> List[int]: + count = Counter(nums) + nums.sort(key=lambda n: (count[n], -n)) + return nums +``` + +```java +public class Solution { + public int[] frequencySort(int[] nums) { + Map count = new HashMap<>(); + for (int num : nums) { + count.put(num, count.getOrDefault(num, 0) + 1); + } + + Integer[] arr = Arrays.stream(nums).boxed().toArray(Integer[]::new); + Arrays.sort(arr, (a, b) -> { + int freqA = count.get(a), freqB = count.get(b); + if (freqA != freqB) return Integer.compare(freqA, freqB); + return Integer.compare(b, a); + }); + + return Arrays.stream(arr).mapToInt(i -> i).toArray(); + } +} +``` + +```cpp +class Solution { +public: + vector frequencySort(vector& nums) { + unordered_map count; + for (int num : nums) { + count[num]++; + } + + sort(nums.begin(), nums.end(), [&](int a, int b) { + if (count[a] != count[b]) return count[a] < count[b]; + return a > b; + }); + + return nums; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {number[]} + */ + frequencySort(nums) { + const count = {}; + for (let num of nums) { + count[num] = (count[num] || 0) + 1; + } + + nums.sort((a, b) => { + if (count[a] !== count[b]) return count[a] - count[b]; + return b - a; + }); + + return nums; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/sort-array-by-parity.md b/articles/sort-array-by-parity.md index b282d0cea..51437ff50 100644 --- a/articles/sort-array-by-parity.md +++ b/articles/sort-array-by-parity.md @@ -23,8 +23,8 @@ public class Solution { class Solution { public: vector sortArrayByParity(vector& nums) { - sort(nums.begin(), nums.end(), [&](int& a, int& b) { - return (a & 1) < (b & 1); + sort(nums.begin(), nums.end(), [&](int& a, int& b) { + return (a & 1) < (b & 1); }); return nums; } @@ -47,8 +47,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -65,7 +65,7 @@ class Solution: odd.append(num) else: even.append(num) - + idx = 0 for e in even: nums[idx] = e @@ -81,7 +81,7 @@ public class Solution { public int[] sortArrayByParity(int[] nums) { List even = new ArrayList<>(); List odd = new ArrayList<>(); - + for (int num : nums) { if ((num & 1) == 1) { odd.add(num); @@ -89,7 +89,7 @@ public class Solution { even.add(num); } } - + int idx = 0; for (int e : even) { nums[idx++] = e; @@ -97,7 +97,7 @@ public class Solution { for (int o : odd) { nums[idx++] = o; } - + return nums; } } @@ -108,7 +108,7 @@ class Solution { public: vector sortArrayByParity(vector& nums) { vector even, odd; - + for (int& num : nums) { if (num & 1) { odd.push_back(num); @@ -116,7 +116,7 @@ public: even.push_back(num); } } - + int idx = 0; for (int& e : even) { nums[idx++] = e; @@ -124,7 +124,7 @@ public: for (int& o : odd) { nums[idx++] = o; } - + return nums; } }; @@ -139,7 +139,7 @@ class Solution { sortArrayByParity(nums) { const even = []; const odd = []; - + for (let num of nums) { if (num % 2) { odd.push(num); @@ -147,7 +147,7 @@ class Solution { even.push(num); } } - + let idx = 0; for (let e of even) { nums[idx++] = e; @@ -155,7 +155,7 @@ class Solution { for (let o of odd) { nums[idx++] = o; } - + return nums; } } @@ -165,8 +165,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -230,7 +230,8 @@ class Solution { * @return {number[]} */ sortArrayByParity(nums) { - let i = 0, j = nums.length - 1; + let i = 0, + j = nums.length - 1; while (i < j) { if ((nums[i] & 1) == 1) { [nums[i], nums[j]] = [nums[j], nums[i]]; @@ -248,8 +249,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. --- @@ -321,5 +322,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/sort-characters-by-frequency.md b/articles/sort-characters-by-frequency.md index 779312faf..943a26c0b 100644 --- a/articles/sort-characters-by-frequency.md +++ b/articles/sort-characters-by-frequency.md @@ -90,8 +90,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -106,7 +106,7 @@ class Solution: for c in s: count[ord(c)] += 1 - freq = [(chr(i), count[i]) for i in range(123) if count[i] > 0] + freq = [(chr(i), count[i]) for i in range(123) if count[i] > 0] freq.sort(key=lambda x: (-x[1], x[0])) return ''.join(char * freq for char, freq in freq) @@ -219,8 +219,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for the output string. +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for the output string. --- @@ -242,7 +242,7 @@ class Solution: if i in buckets: for c in buckets[i]: res.append(c * i) - + return "".join(res) ``` @@ -336,5 +336,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/sort-colors.md b/articles/sort-colors.md index c94416b39..16a3ec712 100644 --- a/articles/sort-colors.md +++ b/articles/sort-colors.md @@ -40,12 +40,20 @@ class Solution { } ``` +```csharp +public class Solution { + public void SortColors(int[] nums) { + Array.Sort(nums); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -62,7 +70,7 @@ class Solution: count = [0] * 3 for num in nums: count[num] += 1 - + index = 0 for i in range(3): while count[i]: @@ -130,12 +138,30 @@ class Solution { } ``` +```csharp +public class Solution { + public void SortColors(int[] nums) { + int[] count = new int[3]; + foreach (int num in nums) { + count[num]++; + } + + int index = 0; + for (int i = 0; i < 3; i++) { + while (count[i]-- > 0) { + nums[index++] = i; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -156,7 +182,7 @@ class Solution: temp = nums[i] nums[i] = nums[j] nums[j] = temp - + while i <= r: if nums[i] == 0: swap(l, i) @@ -220,7 +246,9 @@ class Solution { * @return {void} Do not return anything, modify nums in-place instead. */ sortColors(nums) { - let i = 0, l = 0, r = nums.length - 1; + let i = 0, + l = 0, + r = nums.length - 1; while (i <= r) { if (nums[i] == 0) { [nums[l], nums[i]] = [nums[i], nums[l]]; @@ -236,12 +264,38 @@ class Solution { } ``` +```csharp +public class Solution { + public void SortColors(int[] nums) { + int i = 0, l = 0, r = nums.Length - 1; + + while (i <= r) { + if (nums[i] == 0) { + Swap(nums, l, i); + l++; + } else if (nums[i] == 2) { + Swap(nums, i, r); + r--; + i--; + } + i++; + } + } + + private void Swap(int[] nums, int i, int j) { + int temp = nums[i]; + nums[i] = nums[j]; + nums[j] = temp; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -322,7 +376,9 @@ class Solution { * @return {void} Do not return anything, modify nums in-place instead. */ sortColors(nums) { - let zero = 0, one = 0, two = 0; + let zero = 0, + one = 0, + two = 0; for (let i = 0; i < nums.length; i++) { if (nums[i] == 0) { nums[two++] = 2; @@ -339,12 +395,33 @@ class Solution { } ``` +```csharp +public class Solution { + public void SortColors(int[] nums) { + int zero = 0, one = 0, two = 0; + + for (int i = 0; i < nums.Length; i++) { + if (nums[i] == 0) { + nums[two++] = 2; + nums[one++] = 1; + nums[zero++] = 0; + } else if (nums[i] == 1) { + nums[two++] = 2; + nums[one++] = 1; + } else { + nums[two++] = 2; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -414,7 +491,8 @@ class Solution { * @return {void} Do not return anything, modify nums in-place instead. */ sortColors(nums) { - let zero = 0, one = 0; + let zero = 0, + one = 0; for (let two = 0; two < nums.length; two++) { let tmp = nums[two]; nums[two] = 2; @@ -429,9 +507,29 @@ class Solution { } ``` +```csharp +public class Solution { + public void SortColors(int[] nums) { + int zero = 0, one = 0; + + for (int two = 0; two < nums.Length; two++) { + int tmp = nums[two]; + nums[two] = 2; + + if (tmp < 2) { + nums[one++] = 1; + } + if (tmp < 1) { + nums[zero++] = 0; + } + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/sort-items-by-groups-respecting-dependencies.md b/articles/sort-items-by-groups-respecting-dependencies.md new file mode 100644 index 000000000..9934f1ee8 --- /dev/null +++ b/articles/sort-items-by-groups-respecting-dependencies.md @@ -0,0 +1,562 @@ +## 1. Topological Sort (DFS) + +::tabs-start + +```python +class Solution: + def sortItems(self, n, m, group, beforeItems): + for i in range(n): + if group[i] == -1: + group[i] = m + m += 1 + + item_adj = defaultdict(list) + group_adj = defaultdict(list) + for i in range(n): + for par in beforeItems[i]: + item_adj[par].append(i) + if group[i] != group[par]: + group_adj[group[par]].append(group[i]) + + itm = self.topo_sort(item_adj, n) + if not itm: return [] + grp = self.topo_sort(group_adj, m) + if not grp: return [] + + grouping = defaultdict(list) + for i in itm: + grouping[group[i]].append(i) + + res = [] + for g in grp: + res.extend(grouping[g]) + + return res + + def topo_sort(self, adj, N): + visited = [0] * N + topo = [] + + def dfs(node): + if visited[node] == 1: + return True + if visited[node] == 2: + return False + visited[node] = 1 + for neighbor in adj[node]: + if dfs(neighbor): + return True + topo.append(node) + visited[node] = 2 + return False + + for i in range(N): + if visited[i] == 0: + if dfs(i): + return [] + + return topo[::-1] +``` + +```java +public class Solution { + public int[] sortItems(int n, int m, int[] group, List> beforeItems) { + for (int i = 0; i < n; i++) { + if (group[i] == -1) { + group[i] = m++; + } + } + + List[] itemAdj = new ArrayList[n]; + List[] groupAdj = new ArrayList[m]; + for (int i = 0; i < n; i++) { + itemAdj[i] = new ArrayList<>(); + } + for (int i = 0; i < m; i++) { + groupAdj[i] = new ArrayList<>(); + } + + for (int i = 0; i < n; i++) { + for (int parent : beforeItems.get(i)) { + itemAdj[parent].add(i); + if (group[i] != group[parent]) { + groupAdj[group[parent]].add(group[i]); + } + } + } + + List itm = topoSort(itemAdj, n); + if (itm.isEmpty()) return new int[]{}; + List grp = topoSort(groupAdj, m); + if (grp.isEmpty()) return new int[]{}; + + List[] grouping = new ArrayList[m]; + for (int i = 0; i < m; i++) { + grouping[i] = new ArrayList<>(); + } + for (int i : itm) { + grouping[group[i]].add(i); + } + + List res = new ArrayList<>(); + for (int g : grp) { + res.addAll(grouping[g]); + } + + return res.stream().mapToInt(Integer::intValue).toArray(); + } + + private List topoSort(List[] adj, int N) { + int[] visited = new int[N]; + List topo = new ArrayList<>(); + + for (int i = 0; i < N; i++) { + if (visited[i] == 0) { + if (dfs(i, adj, visited, topo)) { + return new ArrayList<>(); + } + } + } + + Collections.reverse(topo); + return topo; + } + + private boolean dfs(int node, List[] adj, int[] visited, List topo) { + if (visited[node] == 1) return true; + if (visited[node] == 2) return false; + visited[node] = 1; + for (int neighbor : adj[node]) { + if (dfs(neighbor, adj, visited, topo)) { + return true; + } + } + topo.add(node); + visited[node] = 2; + return false; + } +} +``` + +```cpp +class Solution { +public: + vector sortItems(int n, int m, vector& group, vector>& beforeItems) { + for (int i = 0; i < n; ++i) { + if (group[i] == -1) { + group[i] = m++; + } + } + + vector> itemAdj(n), groupAdj(m); + for (int i = 0; i < n; ++i) { + for (int parent : beforeItems[i]) { + itemAdj[parent].push_back(i); + if (group[i] != group[parent]) { + groupAdj[group[parent]].push_back(group[i]); + } + } + } + + vector itm = topoSort(itemAdj, n); + if (itm.empty()) return {}; + vector grp = topoSort(groupAdj, m); + if (grp.empty()) return {}; + + unordered_map> grouping; + for (int i : itm) { + grouping[group[i]].push_back(i); + } + + vector res; + for (int& g : grp) { + res.insert(res.end(), grouping[g].begin(), grouping[g].end()); + } + + return res; + } + +private: + vector topoSort(const vector>& adj, int N) { + vector visited(N, 0), topo; + function dfs = [&](int node) { + if (visited[node] == 1) return true; + if (visited[node] == 2) return false; + visited[node] = 1; + for (int neighbor : adj[node]) { + if (dfs(neighbor)) return true; + } + topo.push_back(node); + visited[node] = 2; + return false; + }; + + for (int i = 0; i < N; ++i) { + if (visited[i] == 0 && dfs(i)) { + return {}; + } + } + + reverse(topo.begin(), topo.end()); + return topo; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} m + * @param {number[]} group + * @param {number[][]} beforeItems + * @return {number[]} + */ + sortItems(n, m, group, beforeItems) { + for (let i = 0; i < n; i++) { + if (group[i] === -1) { + group[i] = m++; + } + } + + const itemAdj = Array.from({ length: n }, () => []); + const groupAdj = Array.from({ length: m }, () => []); + for (let i = 0; i < n; i++) { + for (const parent of beforeItems[i]) { + itemAdj[parent].push(i); + if (group[i] !== group[parent]) { + groupAdj[group[parent]].push(group[i]); + } + } + } + + const itm = this.topoSort(itemAdj, n); + if (!itm.length) return []; + const grp = this.topoSort(groupAdj, m); + if (!grp.length) return []; + + const grouping = {}; + for (const i of itm) { + if (!grouping[group[i]]) grouping[group[i]] = []; + grouping[group[i]].push(i); + } + + const res = []; + for (const g of grp) { + if (grouping[g]) res.push(...grouping[g]); + } + + return res; + } + + /** + * @param {number[][]} adj + * @param {number} N + * @return {number[]} + */ + topoSort(adj, N) { + const visited = new Array(N).fill(0); + const topo = []; + + const dfs = (node) => { + if (visited[node] === 1) return true; + if (visited[node] === 2) return false; + visited[node] = 1; + for (const neighbor of adj[node]) { + if (dfs(neighbor)) return true; + } + topo.push(node); + visited[node] = 2; + return false; + }; + + for (let i = 0; i < N; i++) { + if (visited[i] === 0 && dfs(i)) { + return []; + } + } + + return topo.reverse(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of items and $E$ is the total number of $beforeItems$ dependencies. + +--- + +## 2. Topological Sort (Kahn's Algorithm) + +::tabs-start + +```python +class Solution: + def sortItems(self, n, m, group, beforeItems): + for i in range(n): + if group[i] == -1: + group[i] = m + m += 1 + + item_adj = defaultdict(list) + group_adj = defaultdict(list) + item_indegree = [0] * n + group_indegree = [0] * m + + for i in range(n): + for par in beforeItems[i]: + item_adj[par].append(i) + item_indegree[i] += 1 + if group[i] != group[par]: + group_adj[group[par]].append(group[i]) + group_indegree[group[i]] += 1 + + itm = self.topo_sort(item_adj, item_indegree, n) + if not itm: return [] + grp = self.topo_sort(group_adj, group_indegree, m) + if not grp: return [] + + grouping = defaultdict(list) + for i in itm: + grouping[group[i]].append(i) + + res = [] + for g in grp: + res.extend(grouping[g]) + + return res + + def topo_sort(self, adj, indegree, N): + topo = [] + q = deque([i for i in range(N) if indegree[i] == 0]) + + while q: + node = q.popleft() + topo.append(node) + for neighbor in adj[node]: + indegree[neighbor] -= 1 + if indegree[neighbor] == 0: + q.append(neighbor) + + return topo if len(topo) == N else [] +``` + +```java +public class Solution { + public int[] sortItems(int n, int m, int[] group, List> beforeItems) { + for (int i = 0; i < n; i++) { + if (group[i] == -1) { + group[i] = m++; + } + } + + List> itemAdj = new ArrayList<>(); + List> groupAdj = new ArrayList<>(); + for (int i = 0; i < n; i++) itemAdj.add(new ArrayList<>()); + for (int i = 0; i < m; i++) groupAdj.add(new ArrayList<>()); + + int[] itemIndegree = new int[n]; + int[] groupIndegree = new int[m]; + + for (int i = 0; i < n; i++) { + for (int par : beforeItems.get(i)) { + itemAdj.get(par).add(i); + itemIndegree[i]++; + if (group[i] != group[par]) { + groupAdj.get(group[par]).add(group[i]); + groupIndegree[group[i]]++; + } + } + } + + List itm = topoSort(itemAdj, itemIndegree, n); + if (itm.isEmpty()) return new int[0]; + List grp = topoSort(groupAdj, groupIndegree, m); + if (grp.isEmpty()) return new int[0]; + + Map> grouping = new HashMap<>(); + for (int i : itm) { + grouping.computeIfAbsent(group[i], x -> new ArrayList<>()).add(i); + } + + List res = new ArrayList<>(); + for (int g : grp) { + res.addAll(grouping.getOrDefault(g, new ArrayList<>())); + } + + return res.stream().mapToInt(Integer::intValue).toArray(); + } + + private List topoSort(List> adj, int[] indegree, int N) { + Queue q = new LinkedList<>(); + List topo = new ArrayList<>(); + for (int i = 0; i < N; i++) { + if (indegree[i] == 0) q.add(i); + } + + while (!q.isEmpty()) { + int node = q.poll(); + topo.add(node); + for (int neighbor : adj.get(node)) { + indegree[neighbor]--; + if (indegree[neighbor] == 0) q.add(neighbor); + } + } + + return topo.size() == N ? topo : new ArrayList<>(); + } +} +``` + +```cpp +class Solution { +public: + vector sortItems(int n, int m, vector& group, vector>& beforeItems) { + for (int i = 0; i < n; i++) { + if (group[i] == -1) group[i] = m++; + } + + vector> itemAdj(n), groupAdj(m); + vector itemIndegree(n, 0), groupIndegree(m, 0); + + for (int i = 0; i < n; i++) { + for (int& par : beforeItems[i]) { + itemAdj[par].push_back(i); + itemIndegree[i]++; + if (group[i] != group[par]) { + groupAdj[group[par]].push_back(group[i]); + groupIndegree[group[i]]++; + } + } + } + + vector itm = topoSort(itemAdj, itemIndegree, n); + if (itm.empty()) return {}; + vector grp = topoSort(groupAdj, groupIndegree, m); + if (grp.empty()) return {}; + + unordered_map> grouping; + for (int& i : itm) { + grouping[group[i]].push_back(i); + } + + vector res; + for (int& g : grp) { + res.insert(res.end(), grouping[g].begin(), grouping[g].end()); + } + + return res; + } + +private: + vector topoSort(vector>& adj, vector& indegree, int N) { + queue q; + vector topo; + for (int i = 0; i < N; i++) { + if (indegree[i] == 0) q.push(i); + } + + while (!q.empty()) { + int node = q.front(); q.pop(); + topo.push_back(node); + for (int& neighbor : adj[node]) { + indegree[neighbor]--; + if (indegree[neighbor] == 0) q.push(neighbor); + } + } + + return topo.size() == N ? topo : vector(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} m + * @param {number[]} group + * @param {number[][]} beforeItems + * @return {number[]} + */ + sortItems(n, m, group, beforeItems) { + for (let i = 0; i < n; i++) { + if (group[i] === -1) group[i] = m++; + } + + const itemAdj = Array.from({ length: n }, () => []); + const groupAdj = Array.from({ length: m }, () => []); + const itemIndegree = Array(n).fill(0); + const groupIndegree = Array(m).fill(0); + + for (let i = 0; i < n; i++) { + for (const par of beforeItems[i]) { + itemAdj[par].push(i); + itemIndegree[i]++; + if (group[i] !== group[par]) { + groupAdj[group[par]].push(group[i]); + groupIndegree[group[i]]++; + } + } + } + + const itm = this.topoSort(itemAdj, itemIndegree, n); + if (itm.length === 0) return []; + const grp = this.topoSort(groupAdj, groupIndegree, m); + if (grp.length === 0) return []; + + const grouping = new Map(); + for (const i of itm) { + if (!grouping.has(group[i])) grouping.set(group[i], []); + grouping.get(group[i]).push(i); + } + + const res = []; + for (const g of grp) { + if (grouping.has(g)) res.push(...grouping.get(g)); + } + + return res; + } + + /** + * @param {number[][]} adj + * @param {number[]} indegree + * @param {number} N + * @return {number[]} + */ + topoSort(adj, indegree, N) { + const q = new Queue(); + const topo = []; + for (let i = 0; i < N; i++) { + if (indegree[i] === 0) q.push(i); + } + + while (!q.isEmpty()) { + const node = q.pop(); + topo.push(node); + for (const neighbor of adj[node]) { + indegree[neighbor]--; + if (indegree[neighbor] === 0) q.push(neighbor); + } + } + + return topo.length === N ? topo : []; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ + +> Where $V$ is the number of items and $E$ is the total number of $beforeItems$ dependencies. diff --git a/articles/sort-list.md b/articles/sort-list.md new file mode 100644 index 000000000..ff17ff660 --- /dev/null +++ b/articles/sort-list.md @@ -0,0 +1,732 @@ +## 1. Convert To Array + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]: + arr = [] + cur = head + + while cur: + arr.append(cur.val) + cur = cur.next + + arr.sort() + cur = head + for val in arr: + cur.val = val + cur = cur.next + + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode sortList(ListNode head) { + if (head == null) return null; + + List arr = new ArrayList<>(); + ListNode cur = head; + + while (cur != null) { + arr.add(cur.val); + cur = cur.next; + } + + Collections.sort(arr); + cur = head; + for (int val : arr) { + cur.val = val; + cur = cur.next; + } + + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* sortList(ListNode* head) { + if (!head) return nullptr; + + vector arr; + ListNode* cur = head; + + while (cur) { + arr.push_back(cur->val); + cur = cur->next; + } + + sort(arr.begin(), arr.end()); + cur = head; + for (int val : arr) { + cur->val = val; + cur = cur->next; + } + + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + sortList(head) { + if (!head) return null; + + let arr = []; + let cur = head; + + while (cur) { + arr.push(cur.val); + cur = cur.next; + } + + arr.sort((a, b) => a - b); + cur = head; + for (let val of arr) { + cur.val = val; + cur = cur.next; + } + + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Recursive Merge Sort + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]: + if not head or not head.next: + return head + + left = head + right = self.getMid(head) + tmp = right.next + right.next = None + right = tmp + + left = self.sortList(left) + right = self.sortList(right) + return self.merge(left, right) + + def getMid(self, head): + slow, fast = head, head.next + while fast and fast.next: + slow = slow.next + fast = fast.next.next + return slow + + def merge(self, list1, list2): + tail = dummy = ListNode() + while list1 and list2: + if list1.val < list2.val: + tail.next = list1 + list1 = list1.next + else: + tail.next = list2 + list2 = list2.next + tail = tail.next + + if list1: + tail.next = list1 + if list2: + tail.next = list2 + + return dummy.next +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode sortList(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + ListNode left = head; + ListNode right = getMid(head); + ListNode temp = right.next; + right.next = null; + right = temp; + + left = sortList(left); + right = sortList(right); + return merge(left, right); + } + + private ListNode getMid(ListNode head) { + ListNode slow = head, fast = head.next; + while (fast != null && fast.next != null) { + slow = slow.next; + fast = fast.next.next; + } + return slow; + } + + private ListNode merge(ListNode list1, ListNode list2) { + ListNode dummy = new ListNode(0); + ListNode tail = dummy; + + while (list1 != null && list2 != null) { + if (list1.val < list2.val) { + tail.next = list1; + list1 = list1.next; + } else { + tail.next = list2; + list2 = list2.next; + } + tail = tail.next; + } + + if (list1 != null) { + tail.next = list1; + } + if (list2 != null) { + tail.next = list2; + } + + return dummy.next; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* sortList(ListNode* head) { + if (!head || !head->next) { + return head; + } + + ListNode* left = head; + ListNode* right = getMid(head); + ListNode* temp = right->next; + right->next = nullptr; + right = temp; + + left = sortList(left); + right = sortList(right); + return merge(left, right); + } + +private: + ListNode* getMid(ListNode* head) { + ListNode* slow = head; + ListNode* fast = head->next; + while (fast && fast->next) { + slow = slow->next; + fast = fast->next->next; + } + return slow; + } + + ListNode* merge(ListNode* list1, ListNode* list2) { + ListNode dummy(0); + ListNode* tail = &dummy; + + while (list1 && list2) { + if (list1->val < list2->val) { + tail->next = list1; + list1 = list1->next; + } else { + tail->next = list2; + list2 = list2->next; + } + tail = tail->next; + } + + if (list1) { + tail->next = list1; + } + if (list2) { + tail->next = list2; + } + + return dummy.next; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + sortList(head) { + if (!head || !head.next) { + return head; + } + + let left = head; + let right = this.getMid(head); + let temp = right.next; + right.next = null; + right = temp; + + left = this.sortList(left); + right = this.sortList(right); + return this.merge(left, right); + } + + /** + * @param {ListNode} head + * @return {ListNode} + */ + getMid(head) { + let slow = head, + fast = head.next; + while (fast && fast.next) { + slow = slow.next; + fast = fast.next.next; + } + return slow; + } + + /** + * @param {ListNode} list1 + * @param {ListNode} list2 + * @return {ListNode} + */ + merge(list1, list2) { + let dummy = new ListNode(0); + let tail = dummy; + + while (list1 && list2) { + if (list1.val < list2.val) { + tail.next = list1; + list1 = list1.next; + } else { + tail.next = list2; + list2 = list2.next; + } + tail = tail.next; + } + + if (list1) { + tail.next = list1; + } + if (list2) { + tail.next = list2; + } + + return dummy.next; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(\log n)$ for recursion stack. + +--- + +## 3. Iterative Merge Sort + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def sortList(self, head: Optional[ListNode]) -> Optional[ListNode]: + if not head or not head.next: + return head + + length = 0 + cur = head + while cur: + length += 1 + cur = cur.next + + dummy = ListNode(0) + dummy.next = head + step = 1 + + while step < length: + prev, curr = dummy, dummy.next + while curr: + left = curr + right = self.split(left, step) + curr = self.split(right, step) + merged = self.merge(left, right) + prev.next = merged + while prev.next: + prev = prev.next + step *= 2 + + return dummy.next + + def split(self, head, step): + if not head: + return None + for _ in range(step - 1): + if not head.next: + break + head = head.next + next_part = head.next + head.next = None + return next_part + + def merge(self, list1, list2): + tail = dummy = ListNode(0) + while list1 and list2: + if list1.val < list2.val: + tail.next = list1 + list1 = list1.next + else: + tail.next = list2 + list2 = list2.next + tail = tail.next + + tail.next = list1 or list2 + return dummy.next +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode sortList(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + int length = 0; + ListNode cur = head; + while (cur != null) { + length++; + cur = cur.next; + } + + ListNode dummy = new ListNode(0); + dummy.next = head; + int step = 1; + + while (step < length) { + ListNode prev = dummy, curr = dummy.next; + while (curr != null) { + ListNode left = curr; + ListNode right = split(left, step); + curr = split(right, step); + ListNode merged = merge(left, right); + prev.next = merged; + while (prev.next != null) { + prev = prev.next; + } + } + step *= 2; + } + + return dummy.next; + } + + private ListNode split(ListNode head, int step) { + if (head == null) return null; + for (int i = 0; i < step - 1 && head.next != null; i++) { + head = head.next; + } + ListNode nextPart = head.next; + head.next = null; + return nextPart; + } + + private ListNode merge(ListNode list1, ListNode list2) { + ListNode dummy = new ListNode(0); + ListNode tail = dummy; + + while (list1 != null && list2 != null) { + if (list1.val < list2.val) { + tail.next = list1; + list1 = list1.next; + } else { + tail.next = list2; + list2 = list2.next; + } + tail = tail.next; + } + + tail.next = (list1 != null) ? list1 : list2; + return dummy.next; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +class Solution { +public: + ListNode* sortList(ListNode* head) { + if (!head || !head->next) { + return head; + } + + int length = 0; + ListNode* cur = head; + while (cur) { + length++; + cur = cur->next; + } + + ListNode dummy(0); + dummy.next = head; + int step = 1; + + while (step < length) { + ListNode* prev = &dummy, *curr = dummy.next; + while (curr) { + ListNode* left = curr; + ListNode* right = split(left, step); + curr = split(right, step); + ListNode* merged = merge(left, right); + prev->next = merged; + while (prev->next) { + prev = prev->next; + } + } + step *= 2; + } + + return dummy.next; + } + +private: + ListNode* split(ListNode* head, int step) { + if (!head) return nullptr; + for (int i = 0; i < step - 1 && head->next; i++) { + head = head->next; + } + ListNode* nextPart = head->next; + head->next = nullptr; + return nextPart; + } + + ListNode* merge(ListNode* list1, ListNode* list2) { + ListNode dummy(0); + ListNode* tail = &dummy; + + while (list1 && list2) { + if (list1->val < list2->val) { + tail->next = list1; + list1 = list1->next; + } else { + tail->next = list2; + list2 = list2->next; + } + tail = tail->next; + } + + tail->next = list1 ? list1 : list2; + return dummy.next; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + sortList(head) { + if (!head || !head.next) { + return head; + } + + let length = 0; + let cur = head; + while (cur) { + length++; + cur = cur.next; + } + + let dummy = new ListNode(0); + dummy.next = head; + let step = 1; + + while (step < length) { + let prev = dummy, + curr = dummy.next; + while (curr) { + let left = curr; + let right = this.split(left, step); + curr = this.split(right, step); + let merged = this.merge(left, right); + prev.next = merged; + while (prev.next) { + prev = prev.next; + } + } + step *= 2; + } + + return dummy.next; + } + + /** + * @param {ListNode} head + * @param {number} step + * @return {ListNode} + */ + split(head, step) { + if (!head) return null; + for (let i = 0; i < step - 1 && head.next; i++) { + head = head.next; + } + let nextPart = head.next; + head.next = null; + return nextPart; + } + + /** + * @param {ListNode} list1 + * @param {ListNode} list2 + * @return {ListNode} + */ + merge(list1, list2) { + let dummy = new ListNode(0); + let tail = dummy; + + while (list1 && list2) { + if (list1.val < list2.val) { + tail.next = list1; + list1 = list1.next; + } else { + tail.next = list2; + list2 = list2.next; + } + tail = tail.next; + } + + tail.next = list1 || list2; + return dummy.next; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ diff --git a/articles/sort-the-jumbled-numbers.md b/articles/sort-the-jumbled-numbers.md new file mode 100644 index 000000000..347cb98d8 --- /dev/null +++ b/articles/sort-the-jumbled-numbers.md @@ -0,0 +1,244 @@ +## 1. Convert To Strings + Sorting + +::tabs-start + +```python +class Solution: + def sortJumbled(self, mapping: List[int], nums: List[int]) -> List[int]: + pairs = [] + + for i, n in enumerate(nums): + n = str(n) + mapped_n = 0 + for c in n: + mapped_n *= 10 + mapped_n += mapping[int(c)] + pairs.append((mapped_n, i)) + + pairs.sort() + return [nums[p[1]] for p in pairs] +``` + +```java +public class Solution { + public int[] sortJumbled(int[] mapping, int[] nums) { + int n = nums.length; + int[][] pairs = new int[n][2]; + + for (int i = 0; i < n; i++) { + String numStr = String.valueOf(nums[i]); + int mapped_n = 0; + for (char c : numStr.toCharArray()) { + mapped_n = mapped_n * 10 + mapping[c - '0']; + } + pairs[i][0] = mapped_n; + pairs[i][1] = i; + } + + Arrays.sort(pairs, (a, b) -> a[0] - b[0]); + + int[] res = new int[n]; + for (int i = 0; i < n; i++) { + res[i] = nums[pairs[i][1]]; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector sortJumbled(vector& mapping, vector& nums) { + vector> pairs; + + for (int i = 0; i < nums.size(); ++i) { + string numStr = to_string(nums[i]); + int mapped_n = 0; + for (char c : numStr) { + mapped_n = mapped_n * 10 + mapping[c - '0']; + } + pairs.push_back({mapped_n, i}); + } + + sort(pairs.begin(), pairs.end()); + + vector res; + for (auto& p : pairs) { + res.push_back(nums[p.second]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} mapping + * @param {number[]} nums + * @return {number[]} + */ + sortJumbled(mapping, nums) { + let pairs = []; + + for (let i = 0; i < nums.length; i++) { + let numStr = nums[i].toString(); + let mapped_n = 0; + for (let c of numStr) { + mapped_n = mapped_n * 10 + mapping[parseInt(c)]; + } + pairs.push([mapped_n, i]); + } + + pairs.sort((a, b) => a[0] - b[0]); + + return pairs.map((p) => nums[p[1]]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Iterate On Numbers + Sorting + +::tabs-start + +```python +class Solution: + def sortJumbled(self, mapping: List[int], nums: List[int]) -> List[int]: + pairs = [] + + for i, n in enumerate(nums): + mapped_n = 0 + base = 1 + + if n == 0: + mapped_n = mapping[0] + else: + while n > 0: + digit = n % 10 + n //= 10 + mapped_n += base * mapping[digit] + base *= 10 + + pairs.append((mapped_n, i)) + + pairs.sort() + return [nums[p[1]] for p in pairs] +``` + +```java +public class Solution { + public int[] sortJumbled(int[] mapping, int[] nums) { + int n = nums.length; + int[][] pairs = new int[n][2]; + + for (int i = 0; i < n; i++) { + int mapped_n = 0, base = 1; + int num = nums[i]; + + if (num == 0) { + mapped_n = mapping[0]; + } else { + while (num > 0) { + int digit = num % 10; + num /= 10; + mapped_n += base * mapping[digit]; + base *= 10; + } + } + + pairs[i][0] = mapped_n; + pairs[i][1] = i; + } + + Arrays.sort(pairs, (a, b) -> Integer.compare(a[0], b[0])); + + int[] res = new int[n]; + for (int i = 0; i < n; i++) { + res[i] = nums[pairs[i][1]]; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector sortJumbled(vector& mapping, vector& nums) { + vector> pairs; + + for (int i = 0; i < nums.size(); i++) { + int mapped_n = 0, base = 1; + int num = nums[i]; + + if (num == 0) { + mapped_n = mapping[0]; + } else { + while (num > 0) { + int digit = num % 10; + num /= 10; + mapped_n += base * mapping[digit]; + base *= 10; + } + } + + pairs.push_back({mapped_n, i}); + } + + sort(pairs.begin(), pairs.end()); + + vector res; + for (auto& p : pairs) { + res.push_back(nums[p.second]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} mapping + * @param {number[]} nums + * @return {number[]} + */ + sortJumbled(mapping, nums) { + let pairs = []; + + for (let i = 0; i < nums.length; i++) { + let numStr = nums[i].toString(); + let mapped_n = 0; + for (let c of numStr) { + mapped_n = mapped_n * 10 + mapping[parseInt(c)]; + } + pairs.push([mapped_n, i]); + } + + pairs.sort((a, b) => a[0] - b[0]); + + return pairs.map((p) => nums[p[1]]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/sort-the-people.md b/articles/sort-the-people.md new file mode 100644 index 000000000..2d239bdf9 --- /dev/null +++ b/articles/sort-the-people.md @@ -0,0 +1,256 @@ +## 1. Hash Map + +::tabs-start + +```python +class Solution: + def sortPeople(self, names: List[str], heights: List[int]) -> List[str]: + height_to_name = {} + for h, n in zip(heights, names): + height_to_name[h] = n + + res = [] + for h in reversed(sorted(heights)): + res.append(height_to_name[h]) + + return res +``` + +```java +public class Solution { + public String[] sortPeople(String[] names, int[] heights) { + Map map = new HashMap<>(); + for (int i = 0; i < heights.length; i++) { + map.put(heights[i], names[i]); + } + + Arrays.sort(heights); + String[] res = new String[heights.length]; + for (int i = 0; i < heights.length; i++) { + res[i] = map.get(heights[heights.length - 1 - i]); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector sortPeople(vector& names, vector& heights) { + unordered_map map; + for (int i = 0; i < heights.size(); i++) { + map[heights[i]] = names[i]; + } + + sort(heights.begin(), heights.end()); + vector res; + for (int i = heights.size() - 1; i >= 0; i--) { + res.push_back(map[heights[i]]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} names + * @param {number[]} heights + * @return {string[]} + */ + sortPeople(names, heights) { + const map = {}; + for (let i = 0; i < heights.length; i++) { + map[heights[i]] = names[i]; + } + + heights.sort((a, b) => a - b); + const res = []; + for (let i = heights.length - 1; i >= 0; i--) { + res.push(map[heights[i]]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Sorting the Pairs + +::tabs-start + +```python +class Solution: + def sortPeople(self, names: List[str], heights: List[int]) -> List[str]: + arr = list(zip(heights, names)) + arr.sort(reverse=True) + return [name for _, name in arr] +``` + +```java +public class Solution { + public String[] sortPeople(String[] names, int[] heights) { + int n = names.length; + Pair[] arr = new Pair[n]; + + for (int i = 0; i < n; i++) { + arr[i] = new Pair(heights[i], names[i]); + } + + Arrays.sort(arr, (a, b) -> Integer.compare(b.height, a.height)); + + String[] res = new String[n]; + for (int i = 0; i < n; i++) { + res[i] = arr[i].name; + } + + return res; + } + + static class Pair { + int height; + String name; + + Pair(int height, String name) { + this.height = height; + this.name = name; + } + } +} +``` + +```cpp +class Solution { +public: + vector sortPeople(vector& names, vector& heights) { + vector> arr; + for (int i = 0; i < names.size(); i++) { + arr.emplace_back(heights[i], names[i]); + } + + sort(arr.begin(), arr.end(), [](auto& a, auto& b) { + return a.first > b.first; + }); + + vector res; + for (auto& [_, name] : arr) { + res.push_back(name); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} names + * @param {number[]} heights + * @return {string[]} + */ + sortPeople(names, heights) { + const arr = names.map((name, i) => [heights[i], name]); + arr.sort((a, b) => b[0] - a[0]); + return arr.map((pair) => pair[1]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Sorting the Indices + +::tabs-start + +```python +class Solution: + def sortPeople(self, names: List[str], heights: List[int]) -> List[str]: + indices = list(range(len(names))) + indices.sort(key=lambda i: -heights[i]) + return [names[i] for i in indices] +``` + +```java +public class Solution { + public String[] sortPeople(String[] names, int[] heights) { + Integer[] indices = new Integer[names.length]; + for (int i = 0; i < names.length; i++) { + indices[i] = i; + } + + Arrays.sort(indices, (i, j) -> Integer.compare(heights[j], heights[i])); + + String[] res = new String[names.length]; + for (int i = 0; i < names.length; i++) { + res[i] = names[indices[i]]; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector sortPeople(vector& names, vector& heights) { + int n = names.size(); + vector indices(n); + iota(indices.begin(), indices.end(), 0); + + sort(indices.begin(), indices.end(), [&](int a, int b) { + return heights[a] > heights[b]; + }); + + vector res; + for (int i : indices) { + res.push_back(names[i]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} names + * @param {number[]} heights + * @return {string[]} + */ + sortPeople(names, heights) { + const indices = names.map((_, i) => i); + indices.sort((a, b) => heights[b] - heights[a]); + return indices.map((i) => names[i]); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/special-array-i.md b/articles/special-array-i.md new file mode 100644 index 000000000..5bc6c1b13 --- /dev/null +++ b/articles/special-array-i.md @@ -0,0 +1,129 @@ +## 1. Modulo Comparision + +::tabs-start + +```python +class Solution: + def isArraySpecial(self, nums: List[int]) -> bool: + for i in range(1, len(nums)): + if nums[i - 1] % 2 == nums[i] % 2: + return False + return True +``` + +```java +public class Solution { + public boolean isArraySpecial(int[] nums) { + for (int i = 1; i < nums.length; i++) { + if (nums[i - 1] % 2 == nums[i] % 2) { + return false; + } + } + return true; + } +} +``` + +```cpp +class Solution { +public: + bool isArraySpecial(vector& nums) { + for (int i = 1; i < nums.size(); i++) { + if (nums[i - 1] % 2 == nums[i] % 2) { + return false; + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + isArraySpecial(nums) { + for (let i = 1; i < nums.length; i++) { + if (nums[i - 1] % 2 === nums[i] % 2) { + return false; + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 2. Bitwise Comparision + +::tabs-start + +```python +class Solution: + def isArraySpecial(self, nums: List[int]) -> bool: + for i in range(1, len(nums)): + if nums[i - 1] & 1 == nums[i] & 1: + return False + return True +``` + +```java +public class Solution { + public boolean isArraySpecial(int[] nums) { + for (int i = 1; i < nums.length; i++) { + if ((nums[i - 1] & 1) == (nums[i] & 1)) { + return false; + } + } + return true; + } +} +``` + +```cpp +class Solution { +public: + bool isArraySpecial(vector& nums) { + for (int i = 1; i < nums.size(); i++) { + if ((nums[i - 1] & 1) == (nums[i] & 1)) { + return false; + } + } + return true; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + isArraySpecial(nums) { + for (let i = 1; i < nums.length; i++) { + if ((nums[i - 1] & 1) === (nums[i] & 1)) { + return false; + } + } + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/special-array-with-x-elements-greater-than-or-equal-x.md b/articles/special-array-with-x-elements-greater-than-or-equal-x.md index 3ba445d99..c5f2849d8 100644 --- a/articles/special-array-with-x-elements-greater-than-or-equal-x.md +++ b/articles/special-array-with-x-elements-greater-than-or-equal-x.md @@ -83,8 +83,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -167,10 +167,11 @@ class Solution { * @return {number} */ specialArray(nums) { - let l = 1, r = nums.length; + let l = 1, + r = nums.length; while (l <= r) { const mid = Math.floor((l + r) / 2); - const cnt = nums.filter(num => num >= mid).length; + const cnt = nums.filter((num) => num >= mid).length; if (cnt === mid) return mid; @@ -189,8 +190,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ --- @@ -226,7 +227,7 @@ public class Solution { int i = 0, prev = -1, totalRight = nums.length; while (i < nums.length) { - if (nums[i] == totalRight || + if (nums[i] == totalRight || (prev < totalRight && totalRight < nums[i])) { return totalRight; } @@ -253,7 +254,7 @@ public: int i = 0, prev = -1, totalRight = nums.size(); while (i < nums.size()) { - if (nums[i] == totalRight || + if (nums[i] == totalRight || (prev < totalRight && totalRight < nums[i])) { return totalRight; } @@ -280,11 +281,15 @@ class Solution { */ specialArray(nums) { nums.sort((a, b) => a - b); - let i = 0, prev = -1, totalRight = nums.length; + let i = 0, + prev = -1, + totalRight = nums.length; while (i < nums.length) { - if (nums[i] === totalRight || - (prev < totalRight && totalRight < nums[i])) { + if ( + nums[i] === totalRight || + (prev < totalRight && totalRight < nums[i]) + ) { return totalRight; } @@ -306,8 +311,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -385,7 +390,8 @@ class Solution { specialArray(nums) { nums.sort((a, b) => a - b); const n = nums.length; - let i = 0, j = 1; + let i = 0, + j = 1; while (i < n && j <= n) { while (i < n && j > nums[i]) i++; @@ -405,8 +411,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -502,5 +508,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/spiral-matrix-ii.md b/articles/spiral-matrix-ii.md new file mode 100644 index 000000000..2c066c72b --- /dev/null +++ b/articles/spiral-matrix-ii.md @@ -0,0 +1,462 @@ +## 1. Iteration + +::tabs-start + +```python +class Solution: + def generateMatrix(self, n: int) -> List[List[int]]: + mat = [[0] * n for _ in range(n)] + left, right = 0, n - 1 + top, bottom = 0, n - 1 + val = 1 + + while left <= right: + # Fill every val in top row + for c in range(left, right + 1): + mat[top][c] = val + val += 1 + top += 1 + + # Fill every val in right col + for r in range(top, bottom + 1): + mat[r][right] = val + val += 1 + right -= 1 + + # Fill every val in bottom row (reverse order) + for c in range(right, left - 1, -1): + mat[bottom][c] = val + val += 1 + bottom -= 1 + + # Fill every val in the left col (reverse order) + for r in range(bottom, top - 1, -1): + mat[r][left] = val + val += 1 + left += 1 + + return mat +``` + +```java +public class Solution { + public int[][] generateMatrix(int n) { + int[][] mat = new int[n][n]; + int left = 0, right = n - 1, top = 0, bottom = n - 1, val = 1; + + while (left <= right) { + // Fill every val in top row + for (int c = left; c <= right; c++) { + mat[top][c] = val++; + } + top++; + + // Fill every val in right col + for (int r = top; r <= bottom; r++) { + mat[r][right] = val++; + } + right--; + + // Fill every val in bottom row (reverse order) + for (int c = right; c >= left; c--) { + mat[bottom][c] = val++; + } + bottom--; + + // Fill every val in the left col (reverse order) + for (int r = bottom; r >= top; r--) { + mat[r][left] = val++; + } + left++; + } + + return mat; + } +} +``` + +```cpp +class Solution { +public: + vector> generateMatrix(int n) { + vector> mat(n, vector(n, 0)); + int left = 0, right = n - 1, top = 0, bottom = n - 1, val = 1; + + while (left <= right) { + // Fill every val in top row + for (int c = left; c <= right; c++) { + mat[top][c] = val++; + } + top++; + + // Fill every val in right col + for (int r = top; r <= bottom; r++) { + mat[r][right] = val++; + } + right--; + + // Fill every val in bottom row (reverse order) + for (int c = right; c >= left; c--) { + mat[bottom][c] = val++; + } + bottom--; + + // Fill every val in the left col (reverse order) + for (int r = bottom; r >= top; r--) { + mat[r][left] = val++; + } + left++; + } + + return mat; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number[][]} + */ + generateMatrix(n) { + const mat = Array.from({ length: n }, () => Array(n).fill(0)); + let left = 0, + right = n - 1, + top = 0, + bottom = n - 1, + val = 1; + + while (left <= right) { + // Fill every val in top row + for (let c = left; c <= right; c++) { + mat[top][c] = val++; + } + top++; + + // Fill every val in right col + for (let r = top; r <= bottom; r++) { + mat[r][right] = val++; + } + right--; + + // Fill every val in bottom row (reverse order) + for (let c = right; c >= left; c--) { + mat[bottom][c] = val++; + } + bottom--; + + // Fill every val in the left col (reverse order) + for (let r = bottom; r >= top; r--) { + mat[r][left] = val++; + } + left++; + } + + return mat; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ for the output matrix. + +--- + +## 2. Recursion + +::tabs-start + +```python +class Solution: + def generateMatrix(self, n: int) -> List[List[int]]: + mat = [[0] * n for _ in range(n)] + + def fill(left, right, top, bottom, val): + if left > right or top > bottom: + return + + # Fill every val in top row + for c in range(left, right + 1): + mat[top][c] = val + val += 1 + top += 1 + + # Fill every val in right col + for r in range(top, bottom + 1): + mat[r][right] = val + val += 1 + right -= 1 + + # Fill every val in bottom row (reverse order) + for c in range(right, left - 1, -1): + mat[bottom][c] = val + val += 1 + bottom -= 1 + + # Fill every val in the left col (reverse order) + for r in range(bottom, top - 1, -1): + mat[r][left] = val + val += 1 + left += 1 + + # Recur for the inner layer + fill(left, right, top, bottom, val) + + fill(0, n - 1, 0, n - 1, 1) + return mat +``` + +```java +public class Solution { + public int[][] generateMatrix(int n) { + int[][] mat = new int[n][n]; + fill(mat, 0, n - 1, 0, n - 1, 1); + return mat; + } + + private void fill(int[][] mat, int left, int right, int top, int bottom, int val) { + if (left > right || top > bottom) return; + + // Fill every val in top row + for (int c = left; c <= right; c++) { + mat[top][c] = val++; + } + top++; + + // Fill every val in right col + for (int r = top; r <= bottom; r++) { + mat[r][right] = val++; + } + right--; + + // Fill every val in bottom row (reverse order) + for (int c = right; c >= left; c--) { + mat[bottom][c] = val++; + } + bottom--; + + // Fill every val in the left col (reverse order) + for (int r = bottom; r >= top; r--) { + mat[r][left] = val++; + } + left++; + + // Recur for the inner layer + fill(mat, left, right, top, bottom, val); + } +} +``` + +```cpp +class Solution { +public: + vector> generateMatrix(int n) { + vector> mat(n, vector(n, 0)); + fill(mat, 0, n - 1, 0, n - 1, 1); + return mat; + } + +private: + void fill(vector> &mat, int left, int right, int top, int bottom, int val) { + if (left > right || top > bottom) return; + + // Fill every val in top row + for (int c = left; c <= right; c++) { + mat[top][c] = val++; + } + top++; + + // Fill every val in right col + for (int r = top; r <= bottom; r++) { + mat[r][right] = val++; + } + right--; + + // Fill every val in bottom row (reverse order) + for (int c = right; c >= left; c--) { + mat[bottom][c] = val++; + } + bottom--; + + // Fill every val in the left col (reverse order) + for (int r = bottom; r >= top; r--) { + mat[r][left] = val++; + } + left++; + + // Recur for the inner layer + fill(mat, left, right, top, bottom, val); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number[][]} + */ + generateMatrix(n) { + const mat = Array.from({ length: n }, () => Array(n).fill(0)); + + const fill = (left, right, top, bottom, val) => { + if (left > right || top > bottom) return; + + // Fill every val in top row + for (let c = left; c <= right; c++) { + mat[top][c] = val++; + } + top++; + + // Fill every val in right col + for (let r = top; r <= bottom; r++) { + mat[r][right] = val++; + } + right--; + + // Fill every val in bottom row (reverse order) + for (let c = right; c >= left; c--) { + mat[bottom][c] = val++; + } + bottom--; + + // Fill every val in the left col (reverse order) + for (let r = bottom; r >= top; r--) { + mat[r][left] = val++; + } + left++; + + // Recur for the inner layer + fill(left, right, top, bottom, val); + }; + + fill(0, n - 1, 0, n - 1, 1); + return mat; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: + - $O(n)$ space for recursion stack. + - $O(n ^ 2)$ space for the output matrix. + +--- + +## 3. Iteration (Optimal) + +::tabs-start + +```python +class Solution: + def generateMatrix(self, n: int) -> List[List[int]]: + mat = [[0] * n for _ in range(n)] + r = c = 0 + dr, dc = 0, 1 + + for val in range(n * n): + mat[r][c] = val + 1 + if mat[(r + dr) % n][(c + dc) % n] != 0: + dr, dc = dc, -dr + r, c = r + dr, c + dc + + return mat +``` + +```java +public class Solution { + public int[][] generateMatrix(int n) { + int[][] mat = new int[n][n]; + int r = 0, c = 0, dr = 0, dc = 1; + + for (int val = 0; val < n * n; val++) { + mat[r][c] = val + 1; + int nextR = (r + dr) % n, nextC = (c + dc) % n; + if (nextR < 0) nextR += n; + if (nextC < 0) nextC += n; + if (mat[nextR][nextC] != 0) { + int temp = dr; + dr = dc; + dc = -temp; + } + r += dr; + c += dc; + } + + return mat; + } +} +``` + +```cpp +class Solution { +public: + vector> generateMatrix(int n) { + vector> mat(n, vector(n, 0)); + int r = 0, c = 0, dr = 0, dc = 1; + + for (int val = 0; val < n * n; val++) { + mat[r][c] = val + 1; + int nextR = (r + dr) % n, nextC = (c + dc) % n; + if (nextR < 0) nextR += n; + if (nextC < 0) nextC += n; + if (mat[nextR][nextC] != 0) { + int temp = dr; + dr = dc; + dc = -temp; + } + r += dr; + c += dc; + } + + return mat; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number[][]} + */ + generateMatrix(n) { + const mat = Array.from({ length: n }, () => Array(n).fill(0)); + let r = 0, + c = 0, + dr = 0, + dc = 1; + + for (let val = 0; val < n * n; val++) { + mat[r][c] = val + 1; + let nextR = (r + dr) % n, + nextC = (c + dc) % n; + if (nextR < 0) nextR += n; + if (nextC < 0) nextC += n; + if (mat[nextR][nextC] !== 0) { + [dr, dc] = [dc, -dr]; + } + r += dr; + c += dc; + } + + return mat; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ for the output matrix. diff --git a/articles/spiral-matrix.md b/articles/spiral-matrix.md index b9719b928..5877c116c 100644 --- a/articles/spiral-matrix.md +++ b/articles/spiral-matrix.md @@ -12,7 +12,7 @@ class Solution: def dfs(row, col, r, c, dr, dc): if row == 0 or col == 0: return - + for i in range(col): r += dr c += dc @@ -20,7 +20,7 @@ class Solution: # sub-problem dfs(col, row - 1, r, c, dc, -dr) - + # start by going to the right dfs(m, n, 0, -1, 0, 1) return res @@ -37,10 +37,10 @@ public class Solution { return res; } - private void dfs(int row, int col, int r, int c, + private void dfs(int row, int col, int r, int c, int dr, int dc, int[][] matrix, List res) { if (row == 0 || col == 0) return; - + for (int i = 0; i < col; i++) { r += dr; c += dc; @@ -65,10 +65,10 @@ public: return res; } - void dfs(int row, int col, int r, int c, int dr, int dc, + void dfs(int row, int col, int r, int c, int dr, int dc, vector>& matrix, vector& res) { if (row == 0 || col == 0) return; - + for (int i = 0; i < col; i++) { r += dr; c += dc; @@ -88,7 +88,8 @@ class Solution { * @return {number[]} */ spiralOrder(matrix) { - const m = matrix.length, n = matrix[0].length; + const m = matrix.length, + n = matrix[0].length; const res = []; // append all the elements in the given direction @@ -123,10 +124,10 @@ public class Solution { return res; } - private void Dfs(int row, int col, int r, int c, int dr, + private void Dfs(int row, int col, int r, int c, int dr, int dc, int[][] matrix, List res) { if (row == 0 || col == 0) return; - + for (int i = 0; i < col; i++) { r += dr; c += dc; @@ -198,12 +199,47 @@ class Solution { } ``` +```swift +class Solution { + func spiralOrder(_ matrix: [[Int]]) -> [Int] { + var m = matrix.count + var n = matrix[0].count + var res: [Int] = [] + + // append all the elements in the given direction + func dfs(_ row: Int, _ col: Int, _ r: inout Int, _ c: inout Int, _ dr: Int, _ dc: Int) { + if row == 0 || col == 0 { + return + } + + for _ in 0.. Where $m$ is the number of rows and $n$ is the number of columns. @@ -317,9 +353,9 @@ class Solution { spiralOrder(matrix) { const res = []; let left = 0; - let right = matrix[0].length; + let right = matrix[0].length; let top = 0; - let bottom = matrix.length; + let bottom = matrix.length; while (left < right && top < bottom) { for (let i = left; i < right; i++) { @@ -462,12 +498,48 @@ class Solution { } ``` +```swift +class Solution { + func spiralOrder(_ matrix: [[Int]]) -> [Int] { + var res: [Int] = [] + var left = 0, right = matrix[0].count + var top = 0, bottom = matrix.count + + while left < right && top < bottom { + for i in left.. Where $m$ is the number of rows and $n$ is the number of columns. @@ -523,7 +595,7 @@ class Solution { public: vector spiralOrder(vector>& matrix) { vector res; - vector> directions = {{0, 1}, {1, 0}, + vector> directions = {{0, 1}, {1, 0}, {0, -1}, {-1, 0}}; vector steps = {matrix[0].size(), matrix.size() - 1}; @@ -550,10 +622,17 @@ class Solution { */ spiralOrder(matrix) { const res = []; - const directions = [[0, 1], [1, 0], [0, -1], [-1, 0]]; + const directions = [ + [0, 1], + [1, 0], + [0, -1], + [-1, 0], + ]; const steps = [matrix[0].length, matrix.length - 1]; - let r = 0, c = -1, d = 0; + let r = 0, + c = -1, + d = 0; while (steps[d % 2]) { for (let i = 0; i < steps[d % 2]; i++) { r += directions[d][0]; @@ -572,7 +651,7 @@ class Solution { public class Solution { public List SpiralOrder(int[][] matrix) { var res = new List(); - var directions = new (int, int)[] { (0, 1), (1, 0), + var directions = new (int, int)[] { (0, 1), (1, 0), (0, -1), (-1, 0) }; var steps = new int[] { matrix[0].Length, matrix.Length - 1 }; @@ -609,8 +688,8 @@ func spiralOrder(matrix [][]int) []int { c += directions[d][1] res = append(res, matrix[r][c]) } - steps[d&1]-- - d = (d + 1) % 4 + steps[d&1]-- + d = (d + 1) % 4 } return res @@ -624,8 +703,8 @@ class Solution { if (matrix.isEmpty() || matrix[0].isEmpty()) return res val directions = arrayOf( - intArrayOf(0, 1), - intArrayOf(1, 0), + intArrayOf(0, 1), + intArrayOf(1, 0), intArrayOf(0, -1), intArrayOf(-1, 0) ) @@ -641,8 +720,8 @@ class Solution { c += directions[d][1] res.add(matrix[r][c]) } - steps[d and 1]-- - d = (d + 1) % 4 + steps[d and 1]-- + d = (d + 1) % 4 } return res @@ -650,11 +729,36 @@ class Solution { } ``` +```swift +class Solution { + func spiralOrder(_ matrix: [[Int]]) -> [Int] { + var res: [Int] = [] + let directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] + var steps = [matrix[0].count, matrix.count - 1] + + var r = 0, c = -1, d = 0 + while steps[d & 1] > 0 { + for _ in 0.. Where $m$ is the number of rows and $n$ is the number of columns. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns. diff --git a/articles/split-array-largest-sum.md b/articles/split-array-largest-sum.md index dccf649c5..7004771d3 100644 --- a/articles/split-array-largest-sum.md +++ b/articles/split-array-largest-sum.md @@ -113,12 +113,42 @@ class Solution { } ``` +```csharp +public class Solution { + public int SplitArray(int[] nums, int k) { + int n = nums.Length; + return Dfs(nums, 0, k, n); + } + + private int Dfs(int[] nums, int i, int m, int n) { + if (i == n) { + return m == 0 ? 0 : int.MaxValue; + } + if (m == 0) { + return int.MaxValue; + } + + int res = int.MaxValue; + int curSum = 0; + for (int j = i; j <= n - m; j++) { + curSum += nums[j]; + int next = Dfs(nums, j + 1, m - 1, n); + if (next != int.MaxValue) { + res = Math.Min(res, Math.Max(curSum, next)); + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -145,7 +175,7 @@ class Solution: for j in range(i, n - m + 1): curSum += nums[j] res = min(res, max(curSum, dfs(j + 1, m - 1))) - + dp[i][m] = res return res @@ -231,7 +261,7 @@ class Solution { */ splitArray(nums, k) { const n = nums.length; - const dp = Array.from({ length: n }, () => Array(m + 1).fill(-1)); + const dp = Array.from({ length: n }, () => Array(k + 1).fill(-1)); const dfs = (i, m) => { if (i === n) { @@ -251,7 +281,7 @@ class Solution { res = Math.min(res, Math.max(curSum, dfs(j + 1, m - 1))); } - return dp[i][m] = res; + return (dp[i][m] = res); }; return dfs(0, k); @@ -259,12 +289,56 @@ class Solution { } ``` +```csharp +public class Solution { + private int[,] dp; + + public int SplitArray(int[] nums, int k) { + int n = nums.Length; + dp = new int[n, k + 1]; + + for (int i = 0; i < n; i++) { + for (int j = 0; j <= k; j++) { + dp[i, j] = -1; + } + } + + return Dfs(nums, 0, k, n); + } + + private int Dfs(int[] nums, int i, int m, int n) { + if (i == n) { + return m == 0 ? 0 : int.MaxValue; + } + if (m == 0) { + return int.MaxValue; + } + if (dp[i, m] != -1) { + return dp[i, m]; + } + + int res = int.MaxValue; + int curSum = 0; + for (int j = i; j <= n - m; j++) { + curSum += nums[j]; + int next = Dfs(nums, j + 1, m - 1, n); + if (next != int.MaxValue) { + res = Math.Min(res, Math.Max(curSum, next)); + } + } + + dp[i, m] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(k * n ^ 2)$ -* Space complexity: $O(k * n)$ +- Time complexity: $O(k * n ^ 2)$ +- Space complexity: $O(k * n)$ > Where $n$ is the size of the array $nums$ and $k$ is the number of sub-arrays to form. @@ -348,8 +422,8 @@ class Solution { */ splitArray(nums, k) { const n = nums.length; - const dp = Array.from({ length: n + 1 }, () => - Array(k + 1).fill(Infinity) + const dp = Array.from({ length: n + 1 }, () => + Array(k + 1).fill(Infinity), ); dp[n][0] = 0; @@ -358,7 +432,10 @@ class Solution { let curSum = 0; for (let j = i; j < n - m + 1; j++) { curSum += nums[j]; - dp[i][m] = Math.min(dp[i][m], Math.max(curSum, dp[j + 1][m - 1])); + dp[i][m] = Math.min( + dp[i][m], + Math.max(curSum, dp[j + 1][m - 1]), + ); } } } @@ -368,12 +445,43 @@ class Solution { } ``` +```csharp +public class Solution { + public int SplitArray(int[] nums, int k) { + int n = nums.Length; + int[,] dp = new int[n + 1, k + 1]; + + for (int i = 0; i <= n; i++) { + for (int j = 0; j <= k; j++) { + dp[i, j] = int.MaxValue; + } + } + + dp[n, 0] = 0; + + for (int m = 1; m <= k; m++) { + for (int i = n - 1; i >= 0; i--) { + int curSum = 0; + for (int j = i; j < n - m + 1; j++) { + curSum += nums[j]; + if (dp[j + 1, m - 1] != int.MaxValue) { + dp[i, m] = Math.Min(dp[i, m], Math.Max(curSum, dp[j + 1, m - 1])); + } + } + } + } + + return dp[0, k]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(k * n ^ 2)$ -* Space complexity: $O(k * n)$ +- Time complexity: $O(k * n ^ 2)$ +- Space complexity: $O(k * n)$ > Where $n$ is the size of the array $nums$ and $k$ is the number of sub-arrays to form. @@ -474,7 +582,10 @@ class Solution { let curSum = 0; for (let j = i; j < n - m + 1; j++) { curSum += nums[j]; - nextDp[i] = Math.min(nextDp[i], Math.max(curSum, dp[j + 1])); + nextDp[i] = Math.min( + nextDp[i], + Math.max(curSum, dp[j + 1]), + ); } } [dp, nextDp] = [nextDp, dp]; @@ -485,12 +596,42 @@ class Solution { } ``` +```csharp +public class Solution { + public int SplitArray(int[] nums, int k) { + int n = nums.Length; + int[] dp = new int[n + 1]; + int[] nextDp = new int[n + 1]; + Array.Fill(dp, int.MaxValue); + dp[n] = 0; + + for (int m = 1; m <= k; m++) { + Array.Fill(nextDp, int.MaxValue); + for (int i = n - 1; i >= 0; i--) { + int curSum = 0; + for (int j = i; j < n - m + 1; j++) { + curSum += nums[j]; + if (dp[j + 1] != int.MaxValue) { + nextDp[i] = Math.Min(nextDp[i], Math.Max(curSum, dp[j + 1])); + } + } + } + var temp = dp; + dp = nextDp; + nextDp = temp; + } + + return dp[0]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(k * n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(k * n ^ 2)$ +- Space complexity: $O(n)$ > Where $n$ is the size of the array $nums$ and $k$ is the number of sub-arrays to form. @@ -609,7 +750,8 @@ class Solution { */ splitArray(nums, k) { const canSplit = (largest) => { - let subarray = 1, curSum = 0; + let subarray = 1, + curSum = 0; for (const num of nums) { curSum += num; if (curSum > largest) { @@ -639,12 +781,49 @@ class Solution { } ``` +```csharp +public class Solution { + public int SplitArray(int[] nums, int k) { + int l = 0, r = 0, res = 0; + foreach (int num in nums) { + l = Math.Max(l, num); + r += num; + } + res = r; + + while (l <= r) { + int mid = l + (r - l) / 2; + if (CanSplit(nums, k, mid)) { + res = mid; + r = mid - 1; + } else { + l = mid + 1; + } + } + return res; + } + + private bool CanSplit(int[] nums, int k, int largest) { + int subarray = 1, curSum = 0; + foreach (int num in nums) { + curSum += num; + if (curSum > largest) { + subarray++; + if (subarray > k) return false; + curSum = num; + } + } + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log s)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n \log s)$ +- Space complexity: $O(1)$ > Where $n$ is the size of the array $nums$ and $s$ is the sum of all the elements in the array. @@ -816,9 +995,11 @@ class Solution { } const canSplit = (largest) => { - let subarrays = 0, i = 0; + let subarrays = 0, + i = 0; while (i < n) { - let l = i + 1, r = n; + let l = i + 1, + r = n; while (l <= r) { const mid = Math.floor(l + (r - l) / 2); if (prefix[mid] - prefix[i] <= largest) { @@ -837,7 +1018,8 @@ class Solution { }; let l = Math.max(...nums); - let r = nums.reduce((a, b) => a + b, 0), res = r; + let r = nums.reduce((a, b) => a + b, 0), + res = r; while (l <= r) { const mid = Math.floor(l + (r - l) / 2); if (canSplit(mid)) { @@ -852,11 +1034,65 @@ class Solution { } ``` +```csharp +public class Solution { + private int[] prefix; + private int n; + + public int SplitArray(int[] nums, int k) { + n = nums.Length; + prefix = new int[n + 1]; + for (int i = 0; i < n; i++) { + prefix[i + 1] = prefix[i] + nums[i]; + } + + int l = int.MinValue, r = 0; + foreach (int num in nums) { + l = Math.Max(l, num); + r += num; + } + + int res = r; + while (l <= r) { + int mid = l + (r - l) / 2; + if (CanSplit(mid, k)) { + res = mid; + r = mid - 1; + } else { + l = mid + 1; + } + } + return res; + } + + private bool CanSplit(int largest, int k) { + int subarrays = 0, i = 0; + while (i < n) { + int l = i + 1, r = n; + while (l <= r) { + int mid = l + (r - l) / 2; + if (prefix[mid] - prefix[i] <= largest) { + l = mid + 1; + } else { + r = mid - 1; + } + } + subarrays++; + i = r; + if (subarrays > k) { + return false; + } + } + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n + (k * \log n * \log s))$ -* Space complexity: $O(n)$ +- Time complexity: $O(n + (k * \log n * \log s))$ +- Space complexity: $O(n)$ -> Where $n$ is the size of the array $nums$, $s$ is the sum of all the elements in the array, and $k$ is the number of sub-arrays to form. \ No newline at end of file +> Where $n$ is the size of the array $nums$, $s$ is the sum of all the elements in the array, and $k$ is the number of sub-arrays to form. diff --git a/articles/split-array-with-same-average.md b/articles/split-array-with-same-average.md new file mode 100644 index 000000000..977779ffe --- /dev/null +++ b/articles/split-array-with-same-average.md @@ -0,0 +1,720 @@ +## 1. Backtracking + +::tabs-start + +```python +class Solution: + def splitArraySameAverage(self, nums: List[int]) -> bool: + def backtrack(i, A, B): + if i == len(nums): + if not A or not B: + return False + return sum(A) * len(B) == sum(B) * len(A) + + A.append(nums[i]) + if backtrack(i + 1, A, B): + return True + B.append(nums[i]) + A.pop() + res = backtrack(i + 1, A, B) + B.pop() + return res + + return backtrack(0, [], []) +``` + +```java +public class Solution { + public boolean splitArraySameAverage(int[] nums) { + return backtrack(nums, 0, new ArrayList<>(), new ArrayList<>()); + } + + private boolean backtrack(int[] nums, int i, List A, List B) { + if (i == nums.length) { + if (A.isEmpty() || B.isEmpty()) return false; + int sumA = A.stream().mapToInt(x -> x).sum(); + int sumB = B.stream().mapToInt(x -> x).sum(); + return sumA * B.size() == sumB * A.size(); + } + + A.add(nums[i]); + if (backtrack(nums, i + 1, A, B)) return true; + A.remove(A.size() - 1); + + B.add(nums[i]); + boolean res = backtrack(nums, i + 1, A, B); + B.remove(B.size() - 1); + + return res; + } +} +``` + +```cpp +class Solution { +public: + bool splitArraySameAverage(vector& nums) { + vector A, B; + return backtrack(nums, 0, A, B); + } + + bool backtrack(vector& nums, int i, vector& A, vector& B) { + if (i == nums.size()) { + if (A.empty() || B.empty()) return false; + int sumA = accumulate(A.begin(), A.end(), 0); + int sumB = accumulate(B.begin(), B.end(), 0); + return sumA * B.size() == sumB * A.size(); + } + + A.push_back(nums[i]); + if (backtrack(nums, i + 1, A, B)) return true; + A.pop_back(); + + B.push_back(nums[i]); + bool res = backtrack(nums, i + 1, A, B); + B.pop_back(); + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + splitArraySameAverage(nums) { + const backtrack = (i, A, B) => { + if (i === nums.length) { + if (A.length === 0 || B.length === 0) return false; + const sumA = A.reduce((a, b) => a + b, 0); + const sumB = B.reduce((a, b) => a + b, 0); + return sumA * B.length === sumB * A.length; + } + + A.push(nums[i]); + if (backtrack(i + 1, A, B)) return true; + A.pop(); + + B.push(nums[i]); + const res = backtrack(i + 1, A, B); + B.pop(); + + return res; + }; + + return backtrack(0, [], []); + } +} +``` + +```csharp +public class Solution { + public bool SplitArraySameAverage(int[] nums) { + return Backtrack(nums, 0, new List(), new List()); + } + + private bool Backtrack(int[] nums, int i, List A, List B) { + if (i == nums.Length) { + if (A.Count == 0 || B.Count == 0) return false; + int sumA = A.Sum(); + int sumB = B.Sum(); + return sumA * B.Count == sumB * A.Count; + } + + A.Add(nums[i]); + if (Backtrack(nums, i + 1, A, B)) return true; + A.RemoveAt(A.Count - 1); + + B.Add(nums[i]); + bool res = Backtrack(nums, i + 1, A, B); + B.RemoveAt(B.Count - 1); + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * 2 ^ n)$ +* Space complexity: $O(n)$ + +--- + +## 2. Memoization (Brute Force) + +::tabs-start + +```python +class Solution: + def splitArraySameAverage(self, nums: List[int]) -> bool: + total = sum(nums) + n = len(nums) + memo = {} + + def dfs(i, size, curr_sum): + if (i, size, curr_sum) in memo: + return memo[(i, size, curr_sum)] + + if size > 0 and size < n and curr_sum * (n - size) == (total - curr_sum) * size: + return True + + if i == n: + return False + + # include nums[i] in A + if dfs(i + 1, size + 1, curr_sum + nums[i]): + memo[(i, size, curr_sum)] = True + return True + + # include nums[i] in B + if dfs(i + 1, size, curr_sum): + memo[(i, size, curr_sum)] = True + return True + + memo[(i, size, curr_sum)] = False + return False + + return dfs(0, 0, 0) +``` + +```java +public class Solution { + public boolean splitArraySameAverage(int[] nums) { + int total = 0, n = nums.length; + for (int num : nums) total += num; + Map memo = new HashMap<>(); + + return dfs(0, 0, 0, nums, total, n, memo); + } + + private boolean dfs(int i, int size, int currSum, int[] nums, int total, int n, Map memo) { + String key = i + "," + size + "," + currSum; + if (memo.containsKey(key)) return memo.get(key); + + if (size > 0 && size < n && currSum * (n - size) == (total - currSum) * size) + return true; + if (i == n) return false; + + if (dfs(i + 1, size + 1, currSum + nums[i], nums, total, n, memo) || + dfs(i + 1, size, currSum, nums, total, n, memo)) { + memo.put(key, true); + return true; + } + + memo.put(key, false); + return false; + } +} +``` + +```cpp +class Solution { +public: + bool splitArraySameAverage(vector& nums) { + int total = accumulate(nums.begin(), nums.end(), 0); + int n = nums.size(); + unordered_map memo; + + function dfs = [&](int i, int size, int currSum) { + string key = to_string(i) + "," + to_string(size) + "," + to_string(currSum); + if (memo.count(key)) return memo[key]; + + if (size > 0 && size < n && currSum * (n - size) == (total - currSum) * size) + return true; + if (i == n) return false; + + if (dfs(i + 1, size + 1, currSum + nums[i]) || dfs(i + 1, size, currSum)) + return memo[key] = true; + + return memo[key] = false; + }; + + return dfs(0, 0, 0); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + splitArraySameAverage(nums) { + const total = nums.reduce((a, b) => a + b, 0); + const n = nums.length; + const memo = new Map(); + + const dfs = (i, size, currSum) => { + const key = `${i},${size},${currSum}`; + if (memo.has(key)) return memo.get(key); + + if (size > 0 && size < n && currSum * (n - size) === (total - currSum) * size) + return true; + if (i === n) return false; + + if (dfs(i + 1, size + 1, currSum + nums[i]) || dfs(i + 1, size, currSum)) { + memo.set(key, true); + return true; + } + + memo.set(key, false); + return false; + }; + + return dfs(0, 0, 0); + } +} +``` + +```csharp +public class Solution { + public bool SplitArraySameAverage(int[] nums) { + int total = nums.Sum(), n = nums.Length; + var memo = new Dictionary(); + + bool Dfs(int i, int size, int currSum) { + string key = $"{i},{size},{currSum}"; + if (memo.ContainsKey(key)) return memo[key]; + + if (size > 0 && size < n && currSum * (n - size) == (total - currSum) * size) + return true; + if (i == n) return false; + + if (Dfs(i + 1, size + 1, currSum + nums[i]) || Dfs(i + 1, size, currSum)) { + memo[key] = true; + return true; + } + + memo[key] = false; + return false; + } + + return Dfs(0, 0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 * s)$ +* Space complexity: $O(n ^ 2 * s)$ + +> Where $n$ is the size of the input array $nums$, and $s$ is the sum of the elements of the array. + +--- + +## 3. Memoization (Optimal) + +::tabs-start + +```python +class Solution: + def splitArraySameAverage(self, nums: List[int]) -> bool: + n, total = len(nums), sum(nums) + # len(A) = a, len(B) = b, let a <= b + # avg(A) = avg(B) + # sum(A) / a = sum(B) / b = sum(nums) / n + # sum(A) / a = avg => sum(A) = a * avg + # sum(A) = a * sum(nums) / n + # Find if any subset exists with a * sum(nums) / n + # a is in the range [1, (n//2)] + + memo = {} + def dfs(i, a, s): + if (i, a, s) in memo: + return memo[(i, a, s)] + if a == 0: + return s == 0 + if i == n or a < 0: + return False + memo[(i, a, s)] = dfs(i + 1, a, s) or dfs(i + 1, a - 1, s - nums[i]) + return memo[(i, a, s)] + + for a in range(1, n // 2 + 1): + if total * a % n == 0: + if dfs(0, a, total * a // n): + return True + + return False +``` + +```java +public class Solution { + int[] nums; + int n, total; + Map memo; + + public boolean splitArraySameAverage(int[] nums) { + this.nums = nums; + this.n = nums.length; + this.total = 0; + for (int num : nums) total += num; + this.memo = new HashMap<>(); + + // len(A) = a, len(B) = b, let a <= b + // avg(A) = avg(B) + // sum(A) / a = sum(B) / b = sum(nums) / n + // sum(A) / a = avg => sum(A) = a * avg + // sum(A) = a * sum(nums) / n + // Find if any subset exists with a * sum(nums) / n + // a is in the range [1, (n//2)] + + for (int a = 1; a <= n / 2; a++) { + if ((total * a) % n == 0) { + if (dfs(0, a, (total * a) / n)) return true; + } + } + return false; + } + + private boolean dfs(int i, int a, int s) { + String key = i + "," + a + "," + s; + if (memo.containsKey(key)) return memo.get(key); + if (a == 0) return s == 0; + if (i == n || a < 0 || s < 0) return false; + boolean res = dfs(i + 1, a, s) || dfs(i + 1, a - 1, s - nums[i]); + memo.put(key, res); + return res; + } +} +``` + +```cpp +class Solution { +public: + bool splitArraySameAverage(vector& nums) { + int n = nums.size(); + int total = accumulate(nums.begin(), nums.end(), 0); + + // len(A) = a, len(B) = b, let a <= b + // avg(A) = avg(B) + // sum(A) / a = sum(B) / b = sum(nums) / n + // sum(A) / a = avg => sum(A) = a * avg + // sum(A) = a * sum(nums) / n + // Find if any subset exists with a * sum(nums) / n + // a is in the range [1, (n//2)] + + vector>> memo(n + 1, + vector>(n / 2 + 1, vector(total + 1, -1))); + + function dfs = [&](int i, int a, int s) -> bool { + if (a == 0) return s == 0; + if (i == n || s < 0 || a < 0) return false; + if (memo[i][a][s] != -1) return memo[i][a][s]; + + bool res = dfs(i + 1, a, s) || dfs(i + 1, a - 1, s - nums[i]); + memo[i][a][s] = res; + return res; + }; + + for (int a = 1; a <= n / 2; ++a) { + if ((total * a) % n == 0) { + int target = (total * a) / n; + if (dfs(0, a, target)) return true; + } + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + splitArraySameAverage(nums) { + const n = nums.length, total = nums.reduce((a, b) => a + b, 0); + + // len(A) = a, len(B) = b, let a <= b + // avg(A) = avg(B) + // sum(A) / a = sum(B) / b = sum(nums) / n + // sum(A) / a = avg => sum(A) = a * avg + // sum(A) = a * sum(nums) / n + // Find if any subset exists with a * sum(nums) / n + // a is in the range [1, (n//2)] + + const memo = new Map(); + + const dfs = (i, a, s) => { + const key = `${i},${a},${s}`; + if (memo.has(key)) return memo.get(key); + if (a === 0) return s === 0; + if (i === n || a < 0) return false; + const res = dfs(i + 1, a, s) || dfs(i + 1, a - 1, s - nums[i]); + memo.set(key, res); + return res; + }; + + for (let a = 1; a <= Math.floor(n / 2); a++) { + if ((total * a) % n === 0) { + if (dfs(0, a, Math.floor((total * a) / n))) return true; + } + } + + return false; + } +} +``` + +```csharp +public class Solution { + public bool SplitArraySameAverage(int[] nums) { + int n = nums.Length; + int total = nums.Sum(); + + // len(A) = a, len(B) = b, let a <= b + // avg(A) = avg(B) + // sum(A) / a = sum(B) / b = sum(nums) / n + // sum(A) / a = avg => sum(A) = a * avg + // sum(A) = a * sum(nums) / n + // Find if any subset exists with a * sum(nums) / n + // a is in the range [1, (n//2)] + + int[,,] memo = new int[n + 1, n / 2 + 1, total + 1]; + for (int i = 0; i <= n; i++) + for (int j = 0; j <= n / 2; j++) + for (int k = 0; k <= total; k++) + memo[i, j, k] = -1; + + for (int a = 1; a <= n / 2; a++) { + if ((total * a) % n == 0) { + int target = (total * a) / n; + if (Dfs(0, a, target, nums, memo)) return true; + } + } + + return false; + } + + private bool Dfs(int i, int a, int s, int[] nums, int[,,] memo) { + if (a == 0) return s == 0; + if (i == nums.Length || a < 0 || s < 0) return false; + if (memo[i, a, s] != -1) return memo[i, a, s] == 1; + + bool res = Dfs(i + 1, a, s, nums, memo) || Dfs(i + 1, a - 1, s - nums[i], nums, memo); + memo[i, a, s] = res ? 1 : 0; + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 * s)$ +* Space complexity: $O(n ^ 2 * s)$ + +> Where $n$ is the size of the input array $nums$, and $s$ is the sum of the elements of the array. + +--- + +## 4. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def splitArraySameAverage(self, nums: List[int]) -> bool: + n = len(nums) + # len(A) = a, len(B) = b, let a <= b + # avg(A) = avg(B) + # sum(A) / a = sum(B) / b = sum(nums) / n + # sum(A) / a = avg => sum(A) = a * avg + # sum(A) = a * sum(nums) / n + # Find if any subset exists with a * sum(nums) / n + # a is in the range [1, (n//2)] + + total = sum(nums) + dp = [set() for _ in range(n // 2 + 1)] + + dp[0].add(0) + for num in nums: + for a in range(n // 2, 0, -1): + for prev in dp[a - 1]: + dp[a].add(prev + num) + + for a in range(1, n // 2 + 1): + if (a * total % n == 0) and (a * total // n) in dp[a]: + return True + + return False +``` + +```java +public class Solution { + public boolean splitArraySameAverage(int[] nums) { + int n = nums.length; + + // len(A) = a, len(B) = b, let a <= b + // avg(A) = avg(B) + // sum(A) / a = sum(B) / b = sum(nums) / n + // sum(A) / a = avg => sum(A) = a * avg + // sum(A) = a * sum(nums) / n + // Find if any subset exists with a * sum(nums) / n + // a is in the range [1, (n//2)] + + int total = 0; + for (int num : nums) total += num; + + List> dp = new ArrayList<>(); + for (int i = 0; i <= n / 2; i++) { + dp.add(new HashSet<>()); + } + dp.get(0).add(0); + + for (int num : nums) { + for (int a = n / 2; a >= 1; a--) { + for (int prev : dp.get(a - 1)) { + dp.get(a).add(prev + num); + } + } + } + + for (int a = 1; a <= n / 2; a++) { + if ((a * total) % n == 0 && dp.get(a).contains((a * total) / n)) { + return true; + } + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool splitArraySameAverage(vector& nums) { + int n = nums.size(); + + // len(A) = a, len(B) = b, let a <= b + // avg(A) = avg(B) + // sum(A) / a = sum(B) / b = sum(nums) / n + // sum(A) / a = avg => sum(A) = a * avg + // sum(A) = a * sum(nums) / n + // Find if any subset exists with a * sum(nums) / n + // a is in the range [1, (n//2)] + + int total = accumulate(nums.begin(), nums.end(), 0); + vector> dp(n / 2 + 1); + dp[0].insert(0); + + for (int num : nums) { + for (int a = n / 2; a >= 1; a--) { + for (int prev : dp[a - 1]) { + dp[a].insert(prev + num); + } + } + } + + for (int a = 1; a <= n / 2; ++a) { + if ((a * total) % n == 0 && dp[a].count((a * total) / n)) { + return true; + } + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @return {boolean} + */ + splitArraySameAverage(nums) { + const n = nums.length; + + // len(A) = a, len(B) = b, let a <= b + // avg(A) = avg(B) + // sum(A) / a = sum(B) / b = sum(nums) / n + // sum(A) / a = avg => sum(A) = a * avg + // sum(A) = a * sum(nums) / n + // Find if any subset exists with a * sum(nums) / n + // a is in the range [1, (n//2)] + + const total = nums.reduce((a, b) => a + b, 0); + const dp = Array.from({ length: Math.floor(n / 2) + 1 }, () => new Set()); + dp[0].add(0); + + for (const num of nums) { + for (let a = Math.floor(n / 2); a >= 1; a--) { + for (const prev of dp[a - 1]) { + dp[a].add(prev + num); + } + } + } + + for (let a = 1; a <= Math.floor(n / 2); a++) { + if ((a * total) % n === 0 && dp[a].has((a * total) / n)) { + return true; + } + } + + return false; + } +} +``` + +```csharp +public class Solution { + public bool SplitArraySameAverage(int[] nums) { + int n = nums.Length; + + // len(A) = a, len(B) = b, let a <= b + // avg(A) = avg(B) + // sum(A) / a = sum(B) / b = sum(nums) / n + // sum(A) / a = avg => sum(A) = a * avg + // sum(A) = a * sum(nums) / n + // Find if any subset exists with a * sum(nums) / n + // a is in the range [1, (n//2)] + + int total = nums.Sum(); + List> dp = new List>(); + for (int i = 0; i <= n / 2; i++) { + dp.Add(new HashSet()); + } + dp[0].Add(0); + + foreach (int num in nums) { + for (int a = n / 2; a >= 1; a--) { + foreach (int prev in dp[a - 1]) { + dp[a].Add(prev + num); + } + } + } + + for (int a = 1; a <= n / 2; a++) { + if ((a * total) % n == 0 && dp[a].Contains((a * total) / n)) { + return true; + } + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n ^ 2 * s)$ +* Space complexity: $O(n ^ 2 * s)$ + +> Where $n$ is the size of the input array $nums$, and $s$ is the sum of the elements of the array. \ No newline at end of file diff --git a/articles/split-linked-list-in-parts.md b/articles/split-linked-list-in-parts.md new file mode 100644 index 000000000..577ae229f --- /dev/null +++ b/articles/split-linked-list-in-parts.md @@ -0,0 +1,346 @@ +## 1. Convert To Array + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def splitListToParts(self, head: Optional[ListNode], k: int) -> List[Optional[ListNode]]: + arr, cur = [], head + while cur: + arr.append(cur) + cur = cur.next + + N = len(arr) + base_len, remainder = N // k, N % k + + res = [None] * k + start = 0 + for i in range(k): + if start < N: + res[i] = arr[start] + tail = start + base_len - 1 + if remainder: + tail += 1 + remainder -= 1 + arr[tail].next = None + start = tail + 1 + + return res +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode[] splitListToParts(ListNode head, int k) { + List arr = new ArrayList<>(); + for (ListNode cur = head; cur != null; cur = cur.next) { + arr.add(cur); + } + + int N = arr.size(); + int base_len = N / k, remainder = N % k; + + ListNode[] res = new ListNode[k]; + int start = 0; + for (int i = 0; i < k; i++) { + if (start < N) { + res[i] = arr.get(start); + int tail = start + base_len - 1; + if (remainder > 0) { + tail++; + remainder--; + } + arr.get(tail).next = null; + start = tail + 1; + } + } + + return res; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + vector splitListToParts(ListNode* head, int k) { + vector arr; + for (ListNode* cur = head; cur != nullptr; cur = cur->next) { + arr.push_back(cur); + } + + int N = arr.size(); + int base_len = N / k, remainder = N % k; + + vector res(k, nullptr); + int start = 0; + for (int i = 0; i < k; i++) { + if (start < N) { + res[i] = arr[start]; + int tail = start + base_len - 1; + if (remainder > 0) { + tail++; + remainder--; + } + arr[tail]->next = nullptr; + start = tail + 1; + } + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode[]} + */ + splitListToParts(head, k) { + let arr = []; + for (let cur = head; cur !== null; cur = cur.next) { + arr.push(cur); + } + + let N = arr.length; + let base_len = Math.floor(N / k), + remainder = N % k; + + let res = new Array(k).fill(null); + let start = 0; + for (let i = 0; i < k; i++) { + if (start < N) { + res[i] = arr[start]; + let tail = start + base_len - 1; + if (remainder > 0) { + tail++; + remainder--; + } + arr[tail].next = null; + start = tail + 1; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Iteration + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def splitListToParts(self, head: Optional[ListNode], k: int) -> List[Optional[ListNode]]: + length, curr = 0, head + while curr: + curr = curr.next + length += 1 + + base_len, remainder = length // k, length % k + curr, res = head, [] + + for i in range(k): + res.append(curr) + for j in range(base_len - 1 + (1 if remainder else 0)): + if not curr: + break + curr = curr.next + remainder -= 1 if remainder else 0 + if curr: + curr.next, curr = None, curr.next + + return res +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode[] splitListToParts(ListNode head, int k) { + int length = 0; + ListNode curr = head; + while (curr != null) { + curr = curr.next; + length++; + } + + int baseLen = length / k, remainder = length % k; + ListNode[] res = new ListNode[k]; + curr = head; + + for (int i = 0; i < k; i++) { + res[i] = curr; + for (int j = 0; j < baseLen - 1 + (remainder > 0 ? 1 : 0); j++) { + if (curr == null) break; + curr = curr.next; + } + if (curr != null) { + ListNode temp = curr.next; + curr.next = null; + curr = temp; + } + remainder--; + } + return res; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + vector splitListToParts(ListNode* head, int k) { + int length = 0; + ListNode* curr = head; + while (curr) { + curr = curr->next; + length++; + } + + int baseLen = length / k, remainder = length % k; + vector res(k, nullptr); + curr = head; + + for (int i = 0; i < k; i++) { + res[i] = curr; + for (int j = 0; j < baseLen - 1 + (remainder > 0 ? 1 : 0); j++) { + if (!curr) break; + curr = curr->next; + } + if (curr) { + ListNode* temp = curr->next; + curr->next = nullptr; + curr = temp; + } + remainder--; + } + return res; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode[]} + */ + splitListToParts(head, k) { + let length = 0, + curr = head; + while (curr) { + curr = curr.next; + length++; + } + + let baseLen = Math.floor(length / k), + remainder = length % k; + let res = new Array(k).fill(null); + curr = head; + + for (let i = 0; i < k; i++) { + res[i] = curr; + for (let j = 0; j < baseLen - 1 + (remainder > 0 ? 1 : 0); j++) { + if (!curr) break; + curr = curr.next; + } + if (curr) { + let temp = curr.next; + curr.next = null; + curr = temp; + } + remainder--; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n)$ space for the output array. diff --git a/articles/splitting-a-string-into-descending-consecutive-values.md b/articles/splitting-a-string-into-descending-consecutive-values.md new file mode 100644 index 000000000..cd0529391 --- /dev/null +++ b/articles/splitting-a-string-into-descending-consecutive-values.md @@ -0,0 +1,570 @@ +## 1. Backtracking + +::tabs-start + +```python +class Solution: + def splitString(self, s: str) -> bool: + n = len(s) + + def isValid(splits): + for i in range(1, len(splits)): + if splits[i] != splits[i - 1] - 1: + return False + return len(splits) > 1 + + def dfs(i, splits): + if i == n: + return isValid(splits) + num = 0 + for j in range(i, n): + num = num * 10 + int(s[j]) + splits.append(num) + if dfs(j + 1, splits): + return True + splits.pop() + return False + + return dfs(0, []) +``` + +```java +public class Solution { + public boolean splitString(String s) { + return dfs(s, 0, new ArrayList<>()); + } + + private boolean isValid(List splits) { + for (int i = 1; i < splits.size(); i++) { + if (splits.get(i) != splits.get(i - 1) - 1) { + return false; + } + } + return splits.size() > 1; + } + + private boolean dfs(String s, int i, List splits) { + if (i == s.length()) { + return isValid(splits); + } + long num = 0; + for (int j = i; j < s.length(); j++) { + num = num * 10 + (s.charAt(j) - '0'); + splits.add(num); + if (dfs(s, j + 1, splits)) { + return true; + } + splits.remove(splits.size() - 1); + } + return false; + } +} +``` + +```cpp +class Solution { +public: + bool splitString(string s) { + vector splits; + return dfs(s, 0, splits); + } + +private: + bool isValid(vector& splits) { + for (int i = 1; i < splits.size(); i++) { + if (splits[i] != splits[i - 1] - 1) { + return false; + } + } + return splits.size() > 1; + } + + bool dfs(string& s, int i, vector& splits) { + if (i == s.size()) { + return isValid(splits); + } + unsigned long long num = 0; + for (int j = i; j < s.size(); j++) { + num = num * 10 + (s[j] - '0'); + splits.push_back(num); + if (dfs(s, j + 1, splits)) { + return true; + } + splits.pop_back(); + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {boolean} + */ + splitString(s) { + const n = s.length; + + const isValid = (splits) => { + for (let i = 1; i < splits.length; i++) { + if (splits[i] !== splits[i - 1] - 1) { + return false; + } + } + return splits.length > 1; + }; + + const dfs = (i, splits) => { + if (i === n) { + return isValid(splits); + } + let num = 0; + for (let j = i; j < n; j++) { + num = num * 10 + Number(s[j]); + splits.push(num); + if (dfs(j + 1, splits)) { + return true; + } + splits.pop(); + } + return false; + }; + + return dfs(0, []); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Recursion - I + +::tabs-start + +```python +class Solution: + def splitString(self, s: str) -> bool: + def dfs(index, prev): + if index == len(s): + return True + num = 0 + for j in range(index, len(s)): + num = num * 10 + int(s[j]) + if num + 1 == prev and dfs(j + 1, num): + return True + return False + + val = 0 + for i in range(len(s) - 1): + val = val * 10 + int(s[i]) + if dfs(i + 1, val): + return True + + return False +``` + +```java +public class Solution { + public boolean splitString(String s) { + int n = s.length(); + long val = 0; + for (int i = 0; i < n - 1; i++) { + val = val * 10 + (s.charAt(i) - '0'); + if (dfs(s, i + 1, val)) { + return true; + } + } + return false; + } + + private boolean dfs(String s, int index, long prev) { + if (index == s.length()) { + return true; + } + long num = 0; + for (int j = index; j < s.length(); j++) { + num = num * 10 + (s.charAt(j) - '0'); + if (num + 1 == prev && dfs(s, j + 1, num)) { + return true; + } + } + return false; + } +} +``` + +```cpp +class Solution { +public: + bool splitString(string s) { + int n = s.size(); + unsigned long long val = 0; + for (int i = 0; i < n - 1; i++) { + val = val * 10 + (s[i] - '0'); + if (dfs(s, i + 1, val)) { + return true; + } + } + return false; + } + +private: + bool dfs(string& s, int index, long long prev) { + if (index == s.size()) { + return true; + } + unsigned long long num = 0; + for (int j = index; j < s.size(); j++) { + num = num * 10 + (s[j] - '0'); + if (num + 1 == prev && dfs(s, j + 1, num)) { + return true; + } + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {boolean} + */ + splitString(s) { + const n = s.length; + + const dfs = (index, prev) => { + if (index === n) { + return true; + } + let num = 0; + for (let j = index; j < n; j++) { + num = num * 10 + Number(s[j]); + if (num + 1 === prev && dfs(j + 1, num)) { + return true; + } + } + return false; + }; + + let val = 0; + for (let i = 0; i < n - 1; i++) { + val = val * 10 + Number(s[i]); + if (dfs(i + 1, val)) { + return true; + } + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Recursion - II + +::tabs-start + +```python +class Solution: + def splitString(self, s: str) -> bool: + def dfs(index, prev): + if index == len(s): + return True + num = 0 + for j in range(index, len(s)): + num = num * 10 + int(s[j]) + if num + 1 == prev and dfs(j + 1, num): + return True + if num >= prev: + break + return False + + val = 0 + for i in range(len(s) - 1): + val = val * 10 + int(s[i]) + if dfs(i + 1, val): + return True + + return False +``` + +```java +public class Solution { + public boolean splitString(String s) { + int n = s.length(); + long val = 0; + for (int i = 0; i < n - 1; i++) { + val = val * 10 + (s.charAt(i) - '0'); + if (dfs(s, i + 1, val)) { + return true; + } + } + return false; + } + + private boolean dfs(String s, int index, long prev) { + if (index == s.length()) { + return true; + } + long num = 0; + for (int j = index; j < s.length(); j++) { + num = num * 10 + (s.charAt(j) - '0'); + if (num + 1 == prev && dfs(s, j + 1, num)) { + return true; + } + if (num >= prev) { + break; + } + } + return false; + } +} +``` + +```cpp +class Solution { +public: + bool splitString(string s) { + int n = s.size(); + unsigned long long val = 0; + for (int i = 0; i < n - 1; i++) { + val = val * 10 + (s[i] - '0'); + if (dfs(s, i + 1, val)) { + return true; + } + } + return false; + } + +private: + bool dfs(string& s, int index, long long prev) { + if (index == s.size()) { + return true; + } + unsigned long long num = 0; + for (int j = index; j < s.size(); j++) { + num = num * 10 + (s[j] - '0'); + if (num + 1 == prev && dfs(s, j + 1, num)) { + return true; + } + if (num >= prev) { + break; + } + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {boolean} + */ + splitString(s) { + const n = s.length; + + const dfs = (index, prev) => { + if (index === n) { + return true; + } + let num = 0; + for (let j = index; j < n; j++) { + num = num * 10 + Number(s[j]); + if (num + 1 === prev && dfs(j + 1, num)) { + return true; + } + if (num >= prev) { + break; + } + } + return false; + }; + + let val = 0; + for (let i = 0; i < n - 1; i++) { + val = val * 10 + Number(s[i]); + if (dfs(i + 1, val)) { + return true; + } + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 4. Stack + +::tabs-start + +```python +class Solution: + def splitString(self, s: str) -> bool: + n = len(s) + stack = [] + val = 0 + + for i in range(n - 1): + val = val * 10 + int(s[i]) + stack.append((i + 1, val)) + + while stack: + index, prev = stack.pop() + num = 0 + for j in range(index, n): + num = num * 10 + int(s[j]) + if num + 1 == prev: + if j + 1 == n: + return True + stack.append((j + 1, num)) + elif num >= prev: + break + + return False +``` + +```java +public class Solution { + public boolean splitString(String s) { + int n = s.length(); + Stack stack = new Stack<>(); + long val = 0; + + for (int i = 0; i < n - 1; i++) { + val = val * 10 + (s.charAt(i) - '0'); + stack.push(new long[]{i + 1, val}); + + while (!stack.isEmpty()) { + long[] top = stack.pop(); + int index = (int) top[0]; + long prev = top[1]; + long num = 0; + + for (int j = index; j < n; j++) { + num = num * 10 + (s.charAt(j) - '0'); + if (num + 1 == prev) { + if (j + 1 == n) { + return true; + } + stack.push(new long[]{j + 1, num}); + } else if (num >= prev) { + break; + } + } + } + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool splitString(string s) { + int n = s.size(); + stack> stack; + unsigned long long val = 0; + + for (int i = 0; i < n - 1; i++) { + val = val * 10 + (s[i] - '0'); + stack.push({i + 1, val}); + + while (!stack.empty()) { + auto [index, prev] = stack.top(); + stack.pop(); + unsigned long long num = 0; + + for (int j = index; j < n; j++) { + num = num * 10 + (s[j] - '0'); + if (num + 1 == prev) { + if (j + 1 == n) { + return true; + } + stack.push({j + 1, num}); + } else if (num >= prev) { + break; + } + } + } + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @return {boolean} + */ + splitString(s) { + const n = s.length; + let stack = []; + let val = 0; + + for (let i = 0; i < n - 1; i++) { + val = val * 10 + Number(s[i]); + stack.push([i + 1, val]); + + while (stack.length) { + let [index, prev] = stack.pop(); + let num = 0; + + for (let j = index; j < n; j++) { + num = num * 10 + Number(s[j]); + if (num + 1 === prev) { + if (j + 1 === n) { + return true; + } + stack.push([j + 1, num]); + } else if (num >= prev) { + break; + } + } + } + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ diff --git a/articles/sqrtx.md b/articles/sqrtx.md index 13d854b33..f6b37a7c2 100644 --- a/articles/sqrtx.md +++ b/articles/sqrtx.md @@ -82,12 +82,29 @@ class Solution { } ``` +```csharp +public class Solution { + public int MySqrt(int x) { + if (x == 0) return 0; + + int res = 1; + for (int i = 1; i <= x; i++) { + if ((long)i * i > x) { + return res; + } + res = i; + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\sqrt {n})$ -* Space complexity: $O(1)$ +- Time complexity: $O(\sqrt {n})$ +- Space complexity: $O(1)$ --- @@ -130,12 +147,20 @@ class Solution { } ``` +```csharp +public class Solution { + public int MySqrt(int x) { + return (int)Math.Sqrt(x); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ --- @@ -216,7 +241,8 @@ class Solution { * @return {number} */ mySqrt(x) { - let l = 0, r = x; + let l = 0, + r = x; let res = 0; while (l <= r) { @@ -236,12 +262,37 @@ class Solution { } ``` +```csharp +public class Solution { + public int MySqrt(int x) { + int l = 0, r = x; + int res = 0; + + while (l <= r) { + int m = l + (r - l) / 2; + long sq = (long)m * m; + + if (sq > x) { + r = m - 1; + } else if (sq < x) { + l = m + 1; + res = m; + } else { + return m; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ --- @@ -307,12 +358,26 @@ class Solution { } ``` +```csharp +public class Solution { + public int MySqrt(int x) { + if (x < 2) { + return x; + } + + int l = MySqrt(x >> 2) << 1; + int r = l + 1; + return (long)r * r > x ? l : r; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(\log n)$ for recursion stack. +- Time complexity: $O(\log n)$ +- Space complexity: $O(\log n)$ for recursion stack. --- @@ -370,9 +435,21 @@ class Solution { } ``` +```csharp +public class Solution { + public int MySqrt(int x) { + long r = x; + while (r * r > x) { + r = (r + x / r) >> 1; + } + return (int)r; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(\log n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/squares-of-a-sorted-array.md b/articles/squares-of-a-sorted-array.md index c4d76f6b3..610f4dea6 100644 --- a/articles/squares-of-a-sorted-array.md +++ b/articles/squares-of-a-sorted-array.md @@ -52,12 +52,24 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] SortedSquares(int[] nums) { + for (int i = 0; i < nums.Length; i++) { + nums[i] = nums[i] * nums[i]; + } + Array.Sort(nums); + return nums; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -77,7 +89,7 @@ class Solution: else: res.append(nums[r] * nums[r]) r -= 1 - + return res[::-1] ``` @@ -133,7 +145,8 @@ class Solution { * @return {number[]} */ sortedSquares(nums) { - let l = 0, r = nums.length - 1; + let l = 0, + r = nums.length - 1; const res = []; while (l <= r) { @@ -151,12 +164,36 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] SortedSquares(int[] nums) { + int l = 0, r = nums.Length - 1; + var res = new List(); + + while (l <= r) { + int leftSq = nums[l] * nums[l]; + int rightSq = nums[r] * nums[r]; + if (leftSq > rightSq) { + res.Add(leftSq); + l++; + } else { + res.Add(rightSq); + r--; + } + } + + res.Reverse(); + return res.ToArray(); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for the output array. +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for the output array. --- @@ -180,7 +217,7 @@ class Solution: res[res_index] = nums[r] * nums[r] r -= 1 res_index -= 1 - + return res ``` @@ -201,7 +238,7 @@ public class Solution { } resIndex--; } - + return res; } } @@ -225,7 +262,7 @@ public: } resIndex--; } - + return res; } }; @@ -240,7 +277,9 @@ class Solution { sortedSquares(nums) { const n = nums.length; const res = new Array(n); - let l = 0, r = n - 1, resIndex = n - 1; + let l = 0, + r = n - 1, + resIndex = n - 1; while (l <= r) { if (Math.abs(nums[l]) > Math.abs(nums[r])) { @@ -258,9 +297,32 @@ class Solution { } ``` +```csharp +public class Solution { + public int[] SortedSquares(int[] nums) { + int n = nums.Length; + int[] res = new int[n]; + int l = 0, r = n - 1, resIndex = n - 1; + + while (l <= r) { + if (Math.Abs(nums[l]) > Math.Abs(nums[r])) { + res[resIndex] = nums[l] * nums[l]; + l++; + } else { + res[resIndex] = nums[r] * nums[r]; + r--; + } + resIndex--; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for the output array. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for the output array. diff --git a/articles/stickers-to-spell-word.md b/articles/stickers-to-spell-word.md index 2abbe91a7..b803775e0 100644 --- a/articles/stickers-to-spell-word.md +++ b/articles/stickers-to-spell-word.md @@ -41,11 +41,11 @@ class Solution: public class Solution { private List> stickCount; private Map dp; - + public int minStickers(String[] stickers, String target) { stickCount = new ArrayList<>(); dp = new HashMap<>(); - + for (String s : stickers) { Map countMap = new HashMap<>(); for (char c : s.toCharArray()) { @@ -53,18 +53,18 @@ public class Solution { } stickCount.add(countMap); } - + int res = dfs(target, new HashMap<>()); return res == Integer.MAX_VALUE ? -1 : res; } - + private int dfs(String t, Map stick) { if (t.isEmpty()) return 0; if (dp.containsKey(t)) return dp.get(t); - + int res = stick.isEmpty() ? 0 : 1; StringBuilder remainT = new StringBuilder(); - + for (char c : t.toCharArray()) { if (stick.containsKey(c) && stick.get(c) > 0) { stick.put(c, stick.get(c) - 1); @@ -72,7 +72,7 @@ public class Solution { remainT.append(c); } } - + if (remainT.length() > 0) { int used = Integer.MAX_VALUE; for (Map s : stickCount) { @@ -89,7 +89,7 @@ public class Solution { res = Integer.MAX_VALUE; } } - + return res; } } @@ -99,12 +99,12 @@ public class Solution { class Solution { vector> stickCount; unordered_map dp; - + public: int minStickers(vector& stickers, string target) { stickCount.clear(); dp.clear(); - + for (const string& s : stickers) { unordered_map countMap; for (char c : s) { @@ -112,19 +112,19 @@ public: } stickCount.push_back(countMap); } - + int res = dfs(target, unordered_map()); return res == INT_MAX ? -1 : res; } - + private: int dfs(const string& t, unordered_map stick) { if (t.empty()) return 0; if (dp.count(t)) return dp[t]; - + int res = stick.empty() ? 0 : 1; string remainT; - + for (char c : t) { if (stick.count(c) && stick[c] > 0) { stick[c]--; @@ -132,7 +132,7 @@ private: remainT += c; } } - + if (!remainT.empty()) { int used = INT_MAX; for (const auto& s : stickCount) { @@ -149,7 +149,7 @@ private: res = INT_MAX; } } - + return res; } }; @@ -165,7 +165,7 @@ class Solution { minStickers(stickers, target) { const stickCount = []; const dp = new Map(); - + for (const s of stickers) { const countMap = new Map(); for (const c of s) { @@ -177,10 +177,10 @@ class Solution { const dfs = (t, stick) => { if (t === '') return 0; if (dp.has(t)) return dp.get(t); - + let res = stick.size === 0 ? 0 : 1; let remainT = ''; - + for (const c of t) { if (stick.has(c) && stick.get(c) > 0) { stick.set(c, stick.get(c) - 1); @@ -188,7 +188,7 @@ class Solution { remainT += c; } } - + if (remainT.length > 0) { let used = Infinity; for (const s of stickCount) { @@ -204,10 +204,10 @@ class Solution { res = Infinity; } } - + return res; }; - + const res = dfs(target, new Map()); return res === Infinity ? -1 : res; } @@ -218,8 +218,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * k *2 ^ n)$ -* Space complexity: $O(m * k + 2 ^ n)$ +- Time complexity: $O(m * k *2 ^ n)$ +- Space complexity: $O(m * k + 2 ^ n)$ > Where $n$ is the length of the target string, $m$ is the number of stickers and $k$ is the average length of each sticker. @@ -237,14 +237,14 @@ class Solution: stickCount = [] for s in stickers: stickCount.append(Counter(s)) - + dp = {} dp[""] = 0 def dfs(t): if t in dp: return dp[t] - + tarMp = Counter(t) res = float("inf") for s in stickCount: @@ -254,13 +254,13 @@ class Solution: for c in tarMp: if tarMp[c] > s[c]: remainT.extend([c] * (tarMp[c] - s[c])) - + remainT = ''.join(sorted(remainT)) res = min(res, 1 + dfs(remainT)) - + dp[t] = res return res - + ans = dfs(target) return -1 if ans == float("inf") else ans ``` @@ -388,7 +388,7 @@ class Solution { * @return {number} */ minStickers(stickers, target) { - const dp = { "": 0 }; + const dp = { '': 0 }; const stickCount = stickers.map((s) => { const counter = {}; for (const c of s) { @@ -418,7 +418,7 @@ class Solution { } } - remainT = remainT.sort().join(""); + remainT = remainT.sort().join(''); res = Math.min(res, 1 + dfs(remainT)); } @@ -426,7 +426,7 @@ class Solution { return res; }; - const ans = dfs(target.split("").sort().join("")); + const ans = dfs(target.split('').sort().join('')); return ans === Infinity ? -1 : ans; } } @@ -436,8 +436,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * k *2 ^ n)$ -* Space complexity: $O(m * k + 2 ^ n)$ +- Time complexity: $O(m * k *2 ^ n)$ +- Space complexity: $O(m * k + 2 ^ n)$ > Where $n$ is the length of the target string, $m$ is the number of stickers and $k$ is the average length of each sticker. @@ -574,7 +574,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m * k *2 ^ n)$ -* Space complexity: $O(2 ^ n)$ +- Time complexity: $O(n * m * k *2 ^ n)$ +- Space complexity: $O(2 ^ n)$ -> Where $n$ is the length of the target string, $m$ is the number of stickers and $k$ is the average length of each sticker. \ No newline at end of file +> Where $n$ is the length of the target string, $m$ is the number of stickers and $k$ is the average length of each sticker. diff --git a/articles/stone-game-ii.md b/articles/stone-game-ii.md index b9468738a..daae5b8ef 100644 --- a/articles/stone-game-ii.md +++ b/articles/stone-game-ii.md @@ -114,7 +114,7 @@ class Solution { stoneGameII(piles) { const n = piles.length; this.dp = Array.from({ length: 2 }, () => - Array.from({ length: n }, () => Array(n + 1).fill(-1)) + Array.from({ length: n }, () => Array(n + 1).fill(-1)), ); const dfs = (alice, i, M) => { @@ -143,12 +143,53 @@ class Solution { } ``` +```csharp +public class Solution { + private int[,,] dp; + + public int StoneGameII(int[] piles) { + int n = piles.Length; + dp = new int[2, n, n + 1]; + for (int a = 0; a < 2; a++) { + for (int i = 0; i < n; i++) { + for (int m = 0; m <= n; m++) { + dp[a, i, m] = -1; + } + } + } + + return Dfs(1, 0, 1, piles); + } + + private int Dfs(int alice, int i, int M, int[] piles) { + if (i == piles.Length) return 0; + if (dp[alice, i, M] != -1) return dp[alice, i, M]; + + int res = alice == 1 ? 0 : int.MaxValue; + int total = 0; + + for (int X = 1; X <= 2 * M; X++) { + if (i + X > piles.Length) break; + total += piles[i + X - 1]; + if (alice == 1) { + res = Math.Max(res, total + Dfs(0, i + X, Math.Max(M, X), piles)); + } else { + res = Math.Min(res, Dfs(1, i + X, Math.Max(M, X), piles)); + } + } + + dp[alice, i, M] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n ^ 2)$ --- @@ -213,7 +254,7 @@ public class Solution { if (i + X > suffixSum.length) break; res = Math.max(res, suffixSum[i] - dfs(i + X, Math.max(M, X))); } - + return dp[i][M] = res; } } @@ -229,7 +270,7 @@ public: int stoneGameII(vector& piles) { int n = piles.size(); dp.resize(n, vector(n + 1, -1)); - + suffixSum.resize(n); suffixSum[n - 1] = piles[n - 1]; for (int i = n - 2; i >= 0; i--) { @@ -281,7 +322,7 @@ class Solution { res = Math.max(res, suffixSum[i] - dfs(i + X, Math.max(M, X))); } - return dp[i][M] = res; + return (dp[i][M] = res); }; return dfs(0, 1); @@ -289,12 +330,52 @@ class Solution { } ``` +```csharp +public class Solution { + private int[,] dp; + private int[] suffixSum; + + public int StoneGameII(int[] piles) { + int n = piles.Length; + dp = new int[n, n + 1]; + + for (int i = 0; i < n; i++) { + for (int m = 0; m <= n; m++) { + dp[i, m] = -1; + } + } + + suffixSum = new int[n]; + suffixSum[n - 1] = piles[n - 1]; + for (int i = n - 2; i >= 0; i--) { + suffixSum[i] = piles[i] + suffixSum[i + 1]; + } + + return Dfs(0, 1); + } + + private int Dfs(int i, int M) { + if (i == suffixSum.Length) return 0; + if (dp[i, M] != -1) return dp[i, M]; + + int res = 0; + for (int X = 1; X <= 2 * M; X++) { + if (i + X > suffixSum.Length) break; + res = Math.Max(res, suffixSum[i] - Dfs(i + X, Math.Max(M, X))); + } + + dp[i, M] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n ^ 2)$ --- @@ -318,7 +399,7 @@ class Solution: if i + X > n: break total += piles[i + X - 1] - + dp[1][i][M] = max(dp[1][i][M], total + dp[0][i + X][max(M, X)]) dp[0][i][M] = min(dp[0][i][M], dp[1][i + X][max(M, X)]) @@ -388,7 +469,7 @@ class Solution { stoneGameII(piles) { const n = piles.length; const dp = Array.from({ length: 2 }, () => - Array.from({ length: n + 1 }, () => Array(n + 1).fill(0)) + Array.from({ length: n + 1 }, () => Array(n + 1).fill(0)), ); for (let i = n - 1; i >= 0; i--) { @@ -401,8 +482,14 @@ class Solution { if (i + X > n) break; total += piles[i + X - 1]; - dp[1][i][M] = Math.max(dp[1][i][M], total + dp[0][i + X][Math.max(M, X)]); - dp[0][i][M] = Math.min(dp[0][i][M], dp[1][i + X][Math.max(M, X)]); + dp[1][i][M] = Math.max( + dp[1][i][M], + total + dp[0][i + X][Math.max(M, X)], + ); + dp[0][i][M] = Math.min( + dp[0][i][M], + dp[1][i + X][Math.max(M, X)], + ); } } } @@ -412,12 +499,38 @@ class Solution { } ``` +```csharp +public class Solution { + public int StoneGameII(int[] piles) { + int n = piles.Length; + int[,,] dp = new int[2, n + 1, n + 1]; + + for (int i = n - 1; i >= 0; i--) { + for (int M = 1; M <= n; M++) { + int total = 0; + dp[1, i, M] = 0; + dp[0, i, M] = int.MaxValue; + + for (int X = 1; X <= 2 * M; X++) { + if (i + X > n) break; + total += piles[i + X - 1]; + dp[1, i, M] = Math.Max(dp[1, i, M], total + dp[0, i + X, Math.Max(M, X)]); + dp[0, i, M] = Math.Min(dp[0, i, M], dp[1, i + X, Math.Max(M, X)]); + } + } + } + + return dp[1, 0, 1]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n ^ 2)$ --- @@ -522,7 +635,10 @@ class Solution { for (let M = 1; M <= n; M++) { for (let X = 1; X <= 2 * M; X++) { if (i + X > n) break; - dp[i][M] = Math.max(dp[i][M], suffixSum[i] - dp[i + X][Math.max(M, X)]); + dp[i][M] = Math.max( + dp[i][M], + suffixSum[i] - dp[i + X][Math.max(M, X)], + ); } } } @@ -532,9 +648,36 @@ class Solution { } ``` +```csharp +public class Solution { + public int StoneGameII(int[] piles) { + int n = piles.Length; + + int[] suffixSum = new int[n]; + suffixSum[n - 1] = piles[n - 1]; + for (int i = n - 2; i >= 0; i--) { + suffixSum[i] = piles[i] + suffixSum[i + 1]; + } + + int[,] dp = new int[n + 1, n + 1]; + + for (int i = n - 1; i >= 0; i--) { + for (int M = 1; M <= n; M++) { + for (int X = 1; X <= 2 * M; X++) { + if (i + X > n) break; + dp[i, M] = Math.Max(dp[i, M], suffixSum[i] - dp[i + X, Math.Max(M, X)]); + } + } + } + + return dp[0, 1]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: $O(n ^ 2)$ \ No newline at end of file +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(n ^ 2)$ diff --git a/articles/stone-game-iii.md b/articles/stone-game-iii.md index e95a8e508..01fc6b8bd 100644 --- a/articles/stone-game-iii.md +++ b/articles/stone-game-iii.md @@ -138,7 +138,41 @@ class Solution { }; const result = dfs(0, 1); - if (result === 0) return "Tie"; + if (result === 0) return 'Tie'; + return result > 0 ? 'Alice' : 'Bob'; + } +} +``` + +```csharp +public class Solution { + public string StoneGameIII(int[] stoneValue) { + int n = stoneValue.Length; + int?[,] dp = new int?[n, 2]; + + int Dfs(int i, int alice) { + if (i >= n) return 0; + if (dp[i, alice].HasValue) return dp[i, alice].Value; + + int res = alice == 1 ? int.MinValue : int.MaxValue; + int score = 0; + + for (int j = i; j < Math.Min(i + 3, n); j++) { + if (alice == 1) { + score += stoneValue[j]; + res = Math.Max(res, score + Dfs(j + 1, 0)); + } else { + score -= stoneValue[j]; + res = Math.Min(res, score + Dfs(j + 1, 1)); + } + } + + dp[i, alice] = res; + return res; + } + + int result = Dfs(0, 1); + if (result == 0) return "Tie"; return result > 0 ? "Alice" : "Bob"; } } @@ -148,8 +182,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -260,7 +294,8 @@ class Solution { if (i >= n) return 0; if (dp[i] !== undefined) return dp[i]; - let res = -Infinity, total = 0; + let res = -Infinity, + total = 0; for (let j = i; j < Math.min(i + 3, n); j++) { total += stoneValue[j]; res = Math.max(res, total - dfs(j + 1)); @@ -271,7 +306,34 @@ class Solution { }; const result = dfs(0); - if (result === 0) return "Tie"; + if (result === 0) return 'Tie'; + return result > 0 ? 'Alice' : 'Bob'; + } +} +``` + +```csharp +public class Solution { + public string StoneGameIII(int[] stoneValue) { + int n = stoneValue.Length; + Dictionary dp = new Dictionary(); + + int Dfs(int i) { + if (i >= n) return 0; + if (dp.ContainsKey(i)) return dp[i]; + + int res = int.MinValue, total = 0; + for (int j = i; j < Math.Min(i + 3, n); j++) { + total += stoneValue[j]; + res = Math.Max(res, total - Dfs(j + 1)); + } + + dp[i] = res; + return res; + } + + int result = Dfs(0); + if (result == 0) return "Tie"; return result > 0 ? "Alice" : "Bob"; } } @@ -281,8 +343,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -378,7 +440,30 @@ class Solution { } const result = dp[0]; - if (result === 0) return "Tie"; + if (result === 0) return 'Tie'; + return result > 0 ? 'Alice' : 'Bob'; + } +} +``` + +```csharp +public class Solution { + public string StoneGameIII(int[] stoneValue) { + int n = stoneValue.Length; + int[] dp = new int[n + 1]; + for (int i = 0; i <= n; i++) dp[i] = int.MinValue; + dp[n] = 0; + + for (int i = n - 1; i >= 0; i--) { + int total = 0; + for (int j = i; j < Math.Min(i + 3, n); j++) { + total += stoneValue[j]; + dp[i] = Math.Max(dp[i], total - dp[j + 1]); + } + } + + int result = dp[0]; + if (result == 0) return "Tie"; return result > 0 ? "Alice" : "Bob"; } } @@ -388,8 +473,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -477,7 +562,29 @@ class Solution { } } - if (dp[0] === 0) return "Tie"; + if (dp[0] === 0) return 'Tie'; + return dp[0] > 0 ? 'Alice' : 'Bob'; + } +} +``` + +```csharp +public class Solution { + public string StoneGameIII(int[] stoneValue) { + int n = stoneValue.Length; + int[] dp = new int[4]; + + for (int i = n - 1; i >= 0; i--) { + int total = 0; + dp[i % 4] = int.MinValue; + + for (int j = i; j < Math.Min(i + 3, n); j++) { + total += stoneValue[j]; + dp[i % 4] = Math.Max(dp[i % 4], total - dp[(j + 1) % 4]); + } + } + + if (dp[0] == 0) return "Tie"; return dp[0] > 0 ? "Alice" : "Bob"; } } @@ -487,5 +594,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/stone-game.md b/articles/stone-game.md index 54e5043c1..3b18cdad4 100644 --- a/articles/stone-game.md +++ b/articles/stone-game.md @@ -89,12 +89,36 @@ class Solution { } ``` +```csharp +public class Solution { + public bool StoneGame(int[] piles) { + int total = 0; + foreach (int pile in piles) { + total += pile; + } + + int aliceScore = Dfs(0, piles.Length - 1, piles); + return aliceScore > total - aliceScore; + } + + private int Dfs(int l, int r, int[] piles) { + if (l > r) { + return 0; + } + bool even = (r - l) % 2 == 0; + int left = even ? piles[l] : 0; + int right = even ? piles[r] : 0; + return Math.Max(Dfs(l + 1, r, piles) + left, Dfs(l, r - 1, piles) + right); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -223,12 +247,50 @@ class Solution { } ``` +```csharp +public class Solution { + private int[,] dp; + + public bool StoneGame(int[] piles) { + int n = piles.Length; + dp = new int[n, n]; + for (int i = 0; i < n; i++) { + for (int j = 0; j < n; j++) { + dp[i, j] = -1; + } + } + + int total = 0; + foreach (int pile in piles) { + total += pile; + } + + int aliceScore = Dfs(0, n - 1, piles); + return aliceScore > total - aliceScore; + } + + private int Dfs(int l, int r, int[] piles) { + if (l > r) { + return 0; + } + if (dp[l, r] != -1) { + return dp[l, r]; + } + bool even = (r - l) % 2 == 0; + int left = even ? piles[l] : 0; + int right = even ? piles[r] : 0; + dp[l, r] = Math.Max(Dfs(l + 1, r, piles) + left, Dfs(l, r - 1, piles) + right); + return dp[l, r]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -332,7 +394,10 @@ class Solution { if (l === r) { dp[l][r] = left; } else { - dp[l][r] = Math.max(dp[l + 1][r] + left, dp[l][r - 1] + right); + dp[l][r] = Math.max( + dp[l + 1][r] + left, + dp[l][r - 1] + right, + ); } } } @@ -344,12 +409,42 @@ class Solution { } ``` +```csharp +public class Solution { + public bool StoneGame(int[] piles) { + int n = piles.Length; + int[,] dp = new int[n, n]; + + for (int l = n - 1; l >= 0; l--) { + for (int r = l; r < n; r++) { + bool even = (r - l) % 2 == 0; + int left = even ? piles[l] : 0; + int right = even ? piles[r] : 0; + if (l == r) { + dp[l, r] = left; + } else { + dp[l, r] = Math.Max(dp[l + 1, r] + left, dp[l, r - 1] + right); + } + } + } + + int total = 0; + foreach (int pile in piles) { + total += pile; + } + + int aliceScore = dp[0, n - 1]; + return aliceScore > total - aliceScore; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -464,6 +559,37 @@ class Solution { const total = piles.reduce((a, b) => a + b, 0); const aliceScore = dp[n - 1]; + return aliceScore > total - aliceScore; + } +} +``` + +```csharp +public class Solution { + public bool StoneGame(int[] piles) { + int n = piles.Length; + int[] dp = new int[n]; + + for (int l = n - 1; l >= 0; l--) { + for (int r = l; r < n; r++) { + bool even = (r - l) % 2 == 0; + int left = even ? piles[l] : 0; + int right = even ? piles[r] : 0; + + if (l == r) { + dp[r] = left; + } else { + dp[r] = Math.Max(dp[r] + left, dp[r - 1] + right); + } + } + } + + int total = 0; + foreach (int pile in piles) { + total += pile; + } + + int aliceScore = dp[n - 1]; return aliceScore > (total - aliceScore); } } @@ -473,8 +599,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -491,7 +617,7 @@ class Solution: ```java public class Solution { public boolean stoneGame(int[] piles) { - return true; + return true; } } ``` @@ -517,9 +643,17 @@ class Solution { } ``` +```csharp +public class Solution { + public bool StoneGame(int[] piles) { + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ diff --git a/articles/string-compression-ii.md b/articles/string-compression-ii.md index d1021b9ea..76a378c8c 100644 --- a/articles/string-compression-ii.md +++ b/articles/string-compression-ii.md @@ -126,7 +126,8 @@ class Solution { let res; if (prev === s.charCodeAt(i) - 97) { - const incr = prevCnt === 1 || prevCnt === 9 || prevCnt === 99 ? 1 : 0; + const incr = + prevCnt === 1 || prevCnt === 9 || prevCnt === 99 ? 1 : 0; res = incr + count(i + 1, k, prev, prevCnt + 1); } else { res = 1 + count(i + 1, k, s.charCodeAt(i) - 97, 1); // don't delete @@ -148,8 +149,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(k * n ^ 2)$ -* Space complexity: $O(k * n ^ 2)$ +- Time complexity: $O(k * n ^ 2)$ +- Space complexity: $O(k * n ^ 2)$ > Where $n$ is the length of the string $s$ and $k$ is the maximum number of characters that can be deleted from the string. @@ -174,7 +175,7 @@ class Solution: res = 150 if k > 0: res = dfs(i + 1, k - 1) - + freq = delCnt = 0 comp_len = 1 for j in range(i, n): @@ -189,7 +190,7 @@ class Solution: res = min(res, comp_len + dfs(j + 1, k - delCnt)) dp[(i, k)] = res return res - + return dfs(0, k) ``` @@ -284,7 +285,9 @@ class Solution { let res = 150; if (k > 0) res = dfs(i + 1, k - 1); - let freq = 0, delCnt = 0, comp_len = 1; + let freq = 0, + delCnt = 0, + comp_len = 1; for (let j = i; j < n; j++) { if (s[i] === s[j]) { if (freq === 1 || freq === 9 || freq === 99) comp_len++; @@ -308,8 +311,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2 * k)$ -* Space complexity: $O(n * k)$ +- Time complexity: $O(n ^ 2 * k)$ +- Space complexity: $O(n * k)$ > Where $n$ is the length of the string $s$ and $k$ is the maximum number of characters that can be deleted from the string. @@ -449,7 +452,9 @@ class Solution { dp[i][remK] = dp[i + 1][remK - 1]; } - let freq = 0, delCnt = 0, compLen = 1; + let freq = 0, + delCnt = 0, + compLen = 1; for (let j = i; j < n; j++) { if (s[i] === s[j]) { if (freq === 1 || freq === 9 || freq === 99) { @@ -460,7 +465,10 @@ class Solution { delCnt++; if (delCnt > remK) break; } - dp[i][remK] = Math.min(dp[i][remK], compLen + dp[j + 1][remK - delCnt]); + dp[i][remK] = Math.min( + dp[i][remK], + compLen + dp[j + 1][remK - delCnt], + ); } } } @@ -474,7 +482,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2 * k)$ -* Space complexity: $O(n * k)$ +- Time complexity: $O(n ^ 2 * k)$ +- Space complexity: $O(n * k)$ -> Where $n$ is the length of the string $s$ and $k$ is the maximum number of characters that can be deleted from the string. \ No newline at end of file +> Where $n$ is the length of the string $s$ and $k$ is the maximum number of characters that can be deleted from the string. diff --git a/articles/string-compression.md b/articles/string-compression.md new file mode 100644 index 000000000..cd1f85ab7 --- /dev/null +++ b/articles/string-compression.md @@ -0,0 +1,294 @@ +## 1. Using Extra Space + +::tabs-start + +```python +class Solution: + def compress(self, chars: List[str]) -> int: + n = len(chars) + s = "" + + i = 0 + while i < n: + s += chars[i] + j = i + 1 + while j < n and chars[i] == chars[j]: + j += 1 + + if j - i > 1: + s += str(j - i) + i = j + + i = 0 + while i < len(s): + chars[i] = s[i] + i += 1 + return i +``` + +```java +public class Solution { + public int compress(char[] chars) { + int n = chars.length; + StringBuilder s = new StringBuilder(); + + int i = 0; + while (i < n) { + s.append(chars[i]); + int j = i + 1; + while (j < n && chars[i] == chars[j]) { + j++; + } + + if (j - i > 1) { + s.append(String.valueOf(j - i)); + } + i = j; + } + + for (i = 0; i < s.length(); i++) { + chars[i] = s.charAt(i); + } + return s.length(); + } +} +``` + +```cpp +class Solution { +public: + int compress(vector& chars) { + int n = chars.size(); + string s = ""; + + int i = 0; + while (i < n) { + s += chars[i]; + int j = i + 1; + while (j < n && chars[i] == chars[j]) { + j++; + } + + if (j - i > 1) { + s += to_string(j - i); + } + i = j; + } + + for (i = 0; i < s.size(); i++) { + chars[i] = s[i]; + } + return s.size(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {character[]} chars + * @return {number} + */ + compress(chars) { + const n = chars.length; + let s = ""; + + let i = 0; + while (i < n) { + s += chars[i]; + let j = i + 1; + while (j < n && chars[i] === chars[j]) { + j++; + } + + if (j - i > 1) { + s += String(j - i); + } + i = j; + } + + for (i = 0; i < s.length; i++) { + chars[i] = s[i]; + } + return s.length; + } +} +``` + +```csharp +public class Solution { + public int Compress(char[] chars) { + int n = chars.Length; + string s = ""; + + int i = 0; + while (i < n) { + s += chars[i]; + int j = i + 1; + while (j < n && chars[i] == chars[j]) { + j++; + } + + if (j - i > 1) { + s += (j - i).ToString(); + } + i = j; + } + + for (i = 0; i < s.Length; i++) { + chars[i] = s[i]; + } + return s.Length; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ or $O(n ^ 2)$ depending on the language. +* Space complexity: $O(n)$ + +--- + +## 2. Two Pointers + +::tabs-start + +```python +class Solution: + def compress(self, chars: List[str]) -> int: + n = len(chars) + k = i = 0 + + while i < n: + chars[k] = chars[i] + k += 1 + j = i + 1 + while j < n and chars[i] == chars[j]: + j += 1 + + if j - i > 1: + for c in str(j - i): + chars[k] = c + k += 1 + i = j + return k +``` + +```java +public class Solution { + public int compress(char[] chars) { + int n = chars.length, k = 0, i = 0; + + while (i < n) { + chars[k++] = chars[i]; + int j = i + 1; + while (j < n && chars[i] == chars[j]) { + j++; + } + + if (j - i > 1) { + String cnt = String.valueOf(j - i); + for (char c : cnt.toCharArray()) { + chars[k++] = c; + } + } + i = j; + } + + return k; + } +} +``` + +```cpp +class Solution { +public: + int compress(vector& chars) { + int n = chars.size(), k = 0, i = 0; + + while (i < n) { + chars[k++] = chars[i]; + int j = i + 1; + while (j < n && chars[i] == chars[j]) { + j++; + } + + if (j - i > 1) { + string cnt = to_string(j - i); + for (char c : cnt) { + chars[k++] = c; + } + } + i = j; + } + + return k; + } +}; +``` + +```javascript +class Solution { + /** + * @param {character[]} chars + * @return {number} + */ + compress(chars) { + let n = chars.length, k = 0, i = 0; + + while (i < n) { + chars[k++] = chars[i]; + let j = i + 1; + while (j < n && chars[i] === chars[j]) { + j++; + } + + if (j - i > 1) { + const cnt = String(j - i); + for (const c of cnt) { + chars[k++] = c; + } + } + i = j; + } + + return k; + } +} +``` + +```csharp +public class Solution { + public int Compress(char[] chars) { + int n = chars.Length, k = 0, i = 0; + + while (i < n) { + chars[k++] = chars[i]; + int j = i + 1; + while (j < n && chars[i] == chars[j]) { + j++; + } + + if (j - i > 1) { + string cnt = (j - i).ToString(); + foreach (char c in cnt) { + chars[k++] = c; + } + } + i = j; + } + + return k; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n)$ +* Space complexity: $O(1)$ \ No newline at end of file diff --git a/articles/string-encode-and-decode.md b/articles/string-encode-and-decode.md index c0cad7e12..6eabea551 100644 --- a/articles/string-encode-and-decode.md +++ b/articles/string-encode-and-decode.md @@ -38,7 +38,7 @@ class Solution: ```java public class Solution { - + public String encode(List strs) { if (strs.isEmpty()) return ""; StringBuilder res = new StringBuilder(); @@ -133,8 +133,9 @@ class Solution { * @returns {string} */ encode(strs) { - if (strs.length === 0) return ""; - let sizes = [], res = ""; + if (strs.length === 0) return ''; + let sizes = [], + res = ''; for (let s of strs) { sizes.push(s.length); } @@ -154,9 +155,11 @@ class Solution { */ decode(str) { if (str.length === 0) return []; - let sizes = [], res = [], i = 0; + let sizes = [], + res = [], + i = 0; while (str[i] !== '#') { - let cur = ""; + let cur = ''; while (str[i] !== ',') { cur += str[i]; i++; @@ -282,12 +285,62 @@ class Solution { } ``` +```swift +class Solution { + func encode(_ strs: [String]) -> String { + if strs.isEmpty { return "" } + + var sizes: [Int] = [] + var res = "" + for s in strs { + sizes.append(s.count) + } + for sz in sizes { + res += String(sz) + res += "," + } + + res += "#" + for s in strs { + res += s + } + return res + } + + func decode(_ s: String) -> [String] { + if s.isEmpty { return [] } + let sArr = Array(s) + var sizes: [Int] = [] + var res: [String] = [] + var i = 0 + + while sArr[i] != "#" { + var cur = "" + while sArr[i] != "," { + cur.append(sArr[i]) + i += 1 + } + sizes.append(Int(cur)!) + i += 1 + } + + i += 1 + for sz in sizes { + let substring = String(sArr[i.. Where $m$ is the sum of lengths of all the strings and $n$ is the number of strings. @@ -299,7 +352,7 @@ class Solution { ```python class Solution: - + def encode(self, strs: List[str]) -> str: res = "" for s in strs: @@ -309,7 +362,7 @@ class Solution: def decode(self, s: str) -> List[str]: res = [] i = 0 - + while i < len(s): j = i while s[j] != '#': @@ -319,13 +372,13 @@ class Solution: j = i + length res.append(s[i:j]) i = j - + return res ``` ```java public class Solution { - + public String encode(List strs) { StringBuilder res = new StringBuilder(); for (String s : strs) { @@ -390,9 +443,9 @@ class Solution { * @returns {string} */ encode(strs) { - let res = ""; + let res = ''; for (let s of strs) { - res += s.length + "#" + s; + res += s.length + '#' + s; } return res; } @@ -479,7 +532,7 @@ func (s *Solution) Decode(encoded string) []string { ```kotlin class Solution { - + fun encode(strs: List): String { val res = StringBuilder() for (str in strs) { @@ -506,11 +559,46 @@ class Solution { } ``` +```swift +class Solution { + func encode(_ strs: [String]) -> String { + var res = "" + for s in strs { + res += "\(s.count)#\(s)" + } + return res + } + + func decode(_ s: String) -> [String] { + var res = [String]() + let sArr = Array(s) + var i = 0 + + while i < sArr.count { + var j = i + while sArr[j] != "#" { + j += 1 + } + let lengthStr = String(sArr[i.. Where $m$ is the sum of lengths of all the strings and $n$ is the number of strings. \ No newline at end of file +> Where $m$ is the sum of lengths of all the strings and $n$ is the number of strings. diff --git a/articles/string-matching-in-an-array.md b/articles/string-matching-in-an-array.md new file mode 100644 index 000000000..06091fc0a --- /dev/null +++ b/articles/string-matching-in-an-array.md @@ -0,0 +1,1173 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def stringMatching(self, words: List[str]) -> List[str]: + res = [] + + for i in range(len(words)): + for j in range(len(words)): + if i == j: + continue + + if words[i] in words[j]: + res.append(words[i]) + break + + return res +``` + +```java +public class Solution { + public List stringMatching(String[] words) { + List res = new ArrayList<>(); + + for (int i = 0; i < words.length; i++) { + for (int j = 0; j < words.length; j++) { + if (i == j) { + continue; + } + + if (words[j].contains(words[i])) { + res.add(words[i]); + break; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector stringMatching(vector& words) { + vector res; + + for (int i = 0; i < words.size(); i++) { + for (int j = 0; j < words.size(); j++) { + if (i == j) { + continue; + } + + if (words[j].find(words[i]) != string::npos) { + res.push_back(words[i]); + break; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + stringMatching(words) { + let res = []; + + for (let i = 0; i < words.length; i++) { + for (let j = 0; j < words.length; j++) { + if (i === j) { + continue; + } + + if (words[j].includes(words[i])) { + res.push(words[i]); + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2 * m ^ 2)$ +- Space complexity: + - $O(1)$ extra space. + - $O(n * m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the length of the longest word. + +--- + +## 2. Sorting + +::tabs-start + +```python +class Solution: + def stringMatching(self, words: List[str]) -> List[str]: + res = [] + words.sort(key=len) + + for i in range(len(words)): + for j in range(i + 1, len(words)): + if words[i] in words[j]: + res.append(words[i]) + break + + return res +``` + +```java +public class Solution { + public List stringMatching(String[] words) { + List res = new ArrayList<>(); + Arrays.sort(words, Comparator.comparingInt(String::length)); + + for (int i = 0; i < words.length; i++) { + for (int j = i + 1; j < words.length; j++) { + if (words[j].contains(words[i])) { + res.add(words[i]); + break; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector stringMatching(vector& words) { + vector res; + sort(words.begin(), words.end(), [](const string& a, const string& b) { + return a.length() < b.length(); + }); + + for (int i = 0; i < words.size(); i++) { + for (int j = i + 1; j < words.size(); j++) { + if (words[j].find(words[i]) != string::npos) { + res.push_back(words[i]); + break; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + stringMatching(words) { + let res = []; + words.sort((a, b) => a.length - b.length); + + for (let i = 0; i < words.length; i++) { + for (let j = i + 1; j < words.length; j++) { + if (words[j].includes(words[i])) { + res.push(words[i]); + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2 * m ^ 2)$ +- Space complexity: + - $O(1)$ or $O(n)$ depending on the sorting algorithm. + - $O(n * m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the length of the longest word. + +--- + +## 3. Knuth-Morris-Pratt (KMP) Algorithm + +::tabs-start + +```python +class Solution: + def stringMatching(self, words: List[str]) -> List[str]: + def kmp(word1: str, word2: str) -> int: + lps = [0] * len(word2) + prevLPS, i = 0, 1 + + while i < len(word2): + if word2[i] == word2[prevLPS]: + lps[i] = prevLPS + 1 + prevLPS += 1 + i += 1 + elif prevLPS == 0: + lps[i] = 0 + i += 1 + else: + prevLPS = lps[prevLPS - 1] + + i = j = 0 + while i < len(word1): + if word1[i] == word2[j]: + i += 1 + j += 1 + else: + if j == 0: + i += 1 + else: + j = lps[j - 1] + + if j == len(word2): + return i - len(word2) + + return -1 + + res = [] + words.sort(key=len) + + for i in range(len(words)): + for j in range(i + 1, len(words)): + if kmp(words[j], words[i]) != -1: + res.append(words[i]) + break + + return res +``` + +```java +public class Solution { + public List stringMatching(String[] words) { + List res = new ArrayList<>(); + Arrays.sort(words, Comparator.comparingInt(String::length)); + + for (int i = 0; i < words.length; i++) { + for (int j = i + 1; j < words.length; j++) { + if (kmp(words[j], words[i]) != -1) { + res.add(words[i]); + break; + } + } + } + + return res; + } + + private int kmp(String word1, String word2) { + int[] lps = new int[word2.length()]; + int prevLPS = 0, i = 1; + + while (i < word2.length()) { + if (word2.charAt(i) == word2.charAt(prevLPS)) { + lps[i] = prevLPS + 1; + prevLPS++; + i++; + } else if (prevLPS == 0) { + lps[i] = 0; + i++; + } else { + prevLPS = lps[prevLPS - 1]; + } + } + + i = 0; + int j = 0; + while (i < word1.length()) { + if (word1.charAt(i) == word2.charAt(j)) { + i++; + j++; + } else { + if (j == 0) { + i++; + } else { + j = lps[j - 1]; + } + } + + if (j == word2.length()) { + return i - word2.length(); + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + vector stringMatching(vector& words) { + vector res; + sort(words.begin(), words.end(), [](const string& a, const string& b) { + return a.length() < b.length(); + }); + + for (int i = 0; i < words.size(); i++) { + for (int j = i + 1; j < words.size(); j++) { + if (kmp(words[j], words[i]) != -1) { + res.push_back(words[i]); + break; + } + } + } + + return res; + } + +private: + int kmp(const string& word1, const string& word2) { + vector lps(word2.size(), 0); + int prevLPS = 0, i = 1; + + while (i < word2.size()) { + if (word2[i] == word2[prevLPS]) { + lps[i++] = ++prevLPS; + } else if (prevLPS == 0) { + lps[i++] = 0; + } else { + prevLPS = lps[prevLPS - 1]; + } + } + + i = 0; + int j = 0; + while (i < word1.size()) { + if (word1[i] == word2[j]) { + i++; + j++; + } else { + if (j == 0) { + i++; + } else { + j = lps[j - 1]; + } + } + + if (j == word2.size()) { + return i - word2.size(); + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + stringMatching(words) { + const kmp = (word1, word2) => { + const lps = Array(word2.length).fill(0); + let prevLPS = 0, + i = 1; + + while (i < word2.length) { + if (word2[i] === word2[prevLPS]) { + lps[i++] = ++prevLPS; + } else if (prevLPS === 0) { + lps[i++] = 0; + } else { + prevLPS = lps[prevLPS - 1]; + } + } + + i = 0; + let j = 0; + while (i < word1.length) { + if (word1[i] === word2[j]) { + i++; + j++; + } else { + if (j === 0) { + i++; + } else { + j = lps[j - 1]; + } + } + + if (j === word2.length) { + return i - word2.length; + } + } + + return -1; + }; + + let res = []; + words.sort((a, b) => a.length - b.length); + + for (let i = 0; i < words.length; i++) { + for (let j = i + 1; j < words.length; j++) { + if (kmp(words[j], words[i]) !== -1) { + res.push(words[i]); + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2 * m)$ +- Space complexity: + - $O(m)$ extra space. + - $O(1)$ or $O(n)$ space depending on the sorting algorithm. + - $O(n * m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the length of the longest word. + +--- + +## 4. Rabin-Karp Algorithm (Rolling Hash) + +::tabs-start + +```python +class Solution: + def stringMatching(self, words: List[str]) -> List[str]: + def rabinKarp(word1: str, word2: str) -> int: + base1, mod1 = 31, 768258391 + base2, mod2 = 37, 685683731 + n, m = len(word1), len(word2) + + power1, power2 = 1, 1 + for _ in range(m): + power1 = (power1 * base1) % mod1 + power2 = (power2 * base2) % mod2 + + word1_hash1 = word1_hash2 = 0 + word2_hash1 = word2_hash2 = 0 + + for i in range(m): + word1_hash1 = (word1_hash1 * base1 + ord(word2[i])) % mod1 + word1_hash2 = (word1_hash2 * base2 + ord(word2[i])) % mod2 + word2_hash1 = (word2_hash1 * base1 + ord(word1[i])) % mod1 + word2_hash2 = (word2_hash2 * base2 + ord(word1[i])) % mod2 + + for i in range(n - m + 1): + if word2_hash1 == word1_hash1 and word2_hash2 == word1_hash2: + return i + + if i + m < n: + word2_hash1 = (word2_hash1 * base1 - ord(word1[i]) * power1 + ord(word1[i + m])) % mod1 + word2_hash2 = (word2_hash2 * base2 - ord(word1[i]) * power2 + ord(word1[i + m])) % mod2 + + word2_hash1 = (word2_hash1 + mod1) % mod1 + word2_hash2 = (word2_hash2 + mod2) % mod2 + + return -1 + + res = [] + words.sort(key=len) + + for i in range(len(words)): + for j in range(i + 1, len(words)): + if rabinKarp(words[j], words[i]) != -1: + res.append(words[i]) + break + + return res +``` + +```java +public class Solution { + public List stringMatching(String[] words) { + List res = new ArrayList<>(); + Arrays.sort(words, Comparator.comparingInt(String::length)); + + for (int i = 0; i < words.length; i++) { + for (int j = i + 1; j < words.length; j++) { + if (rabinKarp(words[j], words[i]) != -1) { + res.add(words[i]); + break; + } + } + } + + return res; + } + + private int rabinKarp(String word1, String word2) { + int base1 = 31, mod1 = 768258391; + int base2 = 37, mod2 = 685683731; + int n = word1.length(), m = word2.length(); + + long power1 = 1, power2 = 1; + for (int k = 0; k < m; k++) { + power1 = (power1 * base1) % mod1; + power2 = (power2 * base2) % mod2; + } + + long word1Hash1 = 0, word1Hash2 = 0; + long word2Hash1 = 0, word2Hash2 = 0; + + for (int i = 0; i < m; i++) { + word1Hash1 = (word1Hash1 * base1 + word2.charAt(i)) % mod1; + word1Hash2 = (word1Hash2 * base2 + word2.charAt(i)) % mod2; + word2Hash1 = (word2Hash1 * base1 + word1.charAt(i)) % mod1; + word2Hash2 = (word2Hash2 * base2 + word1.charAt(i)) % mod2; + } + + for (int i = 0; i <= n - m; i++) { + if (word2Hash1 == word1Hash1 && word2Hash2 == word1Hash2) { + return i; + } + + if (i + m < n) { + word2Hash1 = (word2Hash1 * base1 - word1.charAt(i) * power1 + word1.charAt(i + m)) % mod1; + word2Hash2 = (word2Hash2 * base2 - word1.charAt(i) * power2 + word1.charAt(i + m)) % mod2; + + if (word2Hash1 < 0) word2Hash1 += mod1; + if (word2Hash2 < 0) word2Hash2 += mod2; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + vector stringMatching(vector& words) { + vector res; + sort(words.begin(), words.end(), [](const string& a, const string& b) { + return a.length() < b.length(); + }); + + for (int i = 0; i < words.size(); i++) { + for (int j = i + 1; j < words.size(); j++) { + if (rabinKarp(words[j], words[i]) != -1) { + res.push_back(words[i]); + break; + } + } + } + + return res; + } + +private: + int rabinKarp(const string& word1, const string& word2) { + int base1 = 31, mod1 = 768258391; + int base2 = 37, mod2 = 685683731; + int n = word1.size(), m = word2.size(); + + long long power1 = 1, power2 = 1; + for (int i = 0; i < m; i++) { + power1 = (power1 * base1) % mod1; + power2 = (power2 * base2) % mod2; + } + + long long word1Hash1 = 0, word1Hash2 = 0; + long long word2Hash1 = 0, word2Hash2 = 0; + + for (int i = 0; i < m; i++) { + word1Hash1 = (word1Hash1 * base1 + word2[i]) % mod1; + word1Hash2 = (word1Hash2 * base2 + word2[i]) % mod2; + word2Hash1 = (word2Hash1 * base1 + word1[i]) % mod1; + word2Hash2 = (word2Hash2 * base2 + word1[i]) % mod2; + } + + for (int i = 0; i <= n - m; i++) { + if (word2Hash1 == word1Hash1 && word2Hash2 == word1Hash2) { + return i; + } + + if (i + m < n) { + word2Hash1 = (word2Hash1 * base1 - word1[i] * power1 + word1[i + m]) % mod1; + word2Hash2 = (word2Hash2 * base2 - word1[i] * power2 + word1[i + m]) % mod2; + + if (word2Hash1 < 0) word2Hash1 += mod1; + if (word2Hash2 < 0) word2Hash2 += mod2; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + stringMatching(words) { + const rabinKarp = (word1, word2) => { + const base1 = 31, + mod1 = 768258391; + const base2 = 37, + mod2 = 685683731; + const n = word1.length, + m = word2.length; + + let power1 = 1, + power2 = 1; + for (let k = 0; k < m; k++) { + power1 = (power1 * base1) % mod1; + power2 = (power2 * base2) % mod2; + } + + let hash1 = 0, + hash2 = 0; + let cur1 = 0, + cur2 = 0; + + for (let i = 0; i < m; i++) { + hash1 = (hash1 * base1 + word2.charCodeAt(i)) % mod1; + hash2 = (hash2 * base2 + word2.charCodeAt(i)) % mod2; + cur1 = (cur1 * base1 + word1.charCodeAt(i)) % mod1; + cur2 = (cur2 * base2 + word1.charCodeAt(i)) % mod2; + } + + for (let i = 0; i <= n - m; i++) { + if (cur1 === hash1 && cur2 === hash2) { + return i; + } + + if (i + m < n) { + cur1 = + (cur1 * base1 - + word1.charCodeAt(i) * power1 + + word1.charCodeAt(i + m)) % + mod1; + cur2 = + (cur2 * base2 - + word1.charCodeAt(i) * power2 + + word1.charCodeAt(i + m)) % + mod2; + + cur1 = (cur1 + mod1) % mod1; + cur2 = (cur2 + mod2) % mod2; + } + } + + return -1; + }; + + words.sort((a, b) => a.length - b.length); + let res = []; + + for (let i = 0; i < words.length; i++) { + for (let j = i + 1; j < words.length; j++) { + if (rabinKarp(words[j], words[i]) !== -1) { + res.push(words[i]); + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2 * m)$ +- Space complexity: + - $O(1)$ or $O(n)$ space depending on the sorting algorithm. + - $O(n * m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the length of the longest word. + +--- + +## 5. Z-Algorithm + +::tabs-start + +```python +class Solution: + def stringMatching(self, words: List[str]) -> List[str]: + def zAlgorithm(word1: str, word2: str) -> int: + s = word2 + "$" + word1 + n = len(s) + z = [0] * n + l, r = 0, 0 + + for i in range(1, n): + if i <= r: + z[i] = min(r - i + 1, z[i - l]) + while i + z[i] < n and s[z[i]] == s[i + z[i]]: + z[i] += 1 + if i + z[i] - 1 > r: + l, r = i, i + z[i] - 1 + + for i in range(len(word2) + 1, n): + if z[i] == len(word2): + return i - len(word2) - 1 + + return -1 + + res = [] + words.sort(key=len) + + for i in range(len(words)): + for j in range(i + 1, len(words)): + if zAlgorithm(words[j], words[i]) != -1: + res.append(words[i]) + break + + return res +``` + +```java +public class Solution { + public List stringMatching(String[] words) { + List res = new ArrayList<>(); + Arrays.sort(words, Comparator.comparingInt(String::length)); + + for (int i = 0; i < words.length; i++) { + for (int j = i + 1; j < words.length; j++) { + if (zAlgorithm(words[j], words[i]) != -1) { + res.add(words[i]); + break; + } + } + } + + return res; + } + + private int zAlgorithm(String word1, String word2) { + String s = word2 + "$" + word1; + int n = s.length(); + int[] z = new int[n]; + int l = 0, r = 0; + + for (int i = 1; i < n; i++) { + if (i <= r) { + z[i] = Math.min(r - i + 1, z[i - l]); + } + while (i + z[i] < n && s.charAt(z[i]) == s.charAt(i + z[i])) { + z[i]++; + } + if (i + z[i] - 1 > r) { + l = i; + r = i + z[i] - 1; + } + } + + for (int i = word2.length() + 1; i < n; i++) { + if (z[i] == word2.length()) { + return i - word2.length() - 1; + } + } + + return -1; + } +} +``` + +```cpp +class Solution { +public: + vector stringMatching(vector& words) { + vector res; + sort(words.begin(), words.end(), [](const string& a, const string& b) { + return a.length() < b.length(); + }); + + for (int i = 0; i < words.size(); i++) { + for (int j = i + 1; j < words.size(); j++) { + if (zAlgorithm(words[j], words[i]) != -1) { + res.push_back(words[i]); + break; + } + } + } + + return res; + } + +private: + int zAlgorithm(const string& word1, const string& word2) { + string s = word2 + "$" + word1; + int n = s.size(); + vector z(n, 0); + int l = 0, r = 0; + + for (int i = 1; i < n; i++) { + if (i <= r) { + z[i] = min(r - i + 1, z[i - l]); + } + while (i + z[i] < n && s[z[i]] == s[i + z[i]]) { + z[i]++; + } + if (i + z[i] - 1 > r) { + l = i; + r = i + z[i] - 1; + } + } + + for (int i = word2.size() + 1; i < n; i++) { + if (z[i] == word2.size()) { + return i - word2.size() - 1; + } + } + + return -1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + stringMatching(words) { + const zAlgorithm = (word1, word2) => { + const s = word2 + '$' + word1; + const n = s.length; + const z = Array(n).fill(0); + let l = 0, + r = 0; + + for (let i = 1; i < n; i++) { + if (i <= r) { + z[i] = Math.min(r - i + 1, z[i - l]); + } + while (i + z[i] < n && s[z[i]] === s[i + z[i]]) { + z[i]++; + } + if (i + z[i] - 1 > r) { + l = i; + r = i + z[i] - 1; + } + } + + for (let i = word2.length + 1; i < n; i++) { + if (z[i] === word2.length) { + return i - word2.length - 1; + } + } + + return -1; + }; + + words.sort((a, b) => a.length - b.length); + let res = []; + + for (let i = 0; i < words.length; i++) { + for (let j = i + 1; j < words.length; j++) { + if (zAlgorithm(words[j], words[i]) !== -1) { + res.push(words[i]); + break; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2 * m)$ +- Space complexity: + - $O(m)$ extra space. + - $O(1)$ or $O(n)$ space depending on the sorting algorithm. + - $O(n * m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the length of the longest word. + +--- + +## 6. Trie + +::tabs-start + +```python +class TrieNode: + def __init__(self): + self.children = [None] * 26 + self.cnt = 0 + +class Trie: + def __init__(self): + self.root = TrieNode() + + def insert_suffixes(self, word: str) -> None: + for i in range(len(word)): + node = self.root + for j in range(i, len(word)): + idx = ord(word[j]) - ord('a') + if not node.children[idx]: + node.children[idx] = TrieNode() + + node = node.children[idx] + node.cnt += 1 + + def search(self, word: str) -> bool: + node = self.root + for c in word: + idx = ord(c) - ord('a') + node = node.children[idx] + return node.cnt > 1 + +class Solution: + def stringMatching(self, words: List[str]) -> List[str]: + res = [] + trie = Trie() + + for word in words: + trie.insert_suffixes(word) + + for word in words: + if trie.search(word): + res.append(word) + + return res +``` + +```java +class TrieNode { + TrieNode[] children; + int cnt; + + TrieNode() { + children = new TrieNode[26]; + cnt = 0; + } +} + +class Trie { + TrieNode root; + + Trie() { + root = new TrieNode(); + } + + void insertSuffixes(String word) { + for (int i = 0; i < word.length(); i++) { + TrieNode node = root; + for (int j = i; j < word.length(); j++) { + int idx = word.charAt(j) - 'a'; + if (node.children[idx] == null) { + node.children[idx] = new TrieNode(); + } + + node = node.children[idx]; + node.cnt++; + } + } + } + + boolean search(String word) { + TrieNode node = root; + for (int i = 0; i < word.length(); i++) { + int idx = word.charAt(i) - 'a'; + node = node.children[idx]; + } + return node.cnt > 1; + } +} + +class Solution { + public List stringMatching(String[] words) { + List res = new ArrayList<>(); + Trie trie = new Trie(); + + for (String word : words) { + trie.insertSuffixes(word); + } + + for (String word : words) { + if (trie.search(word)) { + res.add(word); + } + } + + return res; + } +} +``` + +```cpp +class TrieNode { +public: + TrieNode* children[26]; + int cnt; + + TrieNode() { + for (int i = 0; i < 26; i++) children[i] = nullptr; + cnt = 0; + } +}; + +class Trie { +public: + TrieNode* root; + + Trie() { + root = new TrieNode(); + } + + void insertSuffixes(const string& word) { + for (int i = 0; i < word.size(); i++) { + TrieNode* node = root; + for (int j = i; j < word.size(); j++) { + int idx = word[j] - 'a'; + if (!node->children[idx]) { + node->children[idx] = new TrieNode(); + } + + node = node->children[idx]; + node->cnt++; + } + } + } + + bool search(const string& word) { + TrieNode* node = root; + for (char c : word) { + int idx = c - 'a'; + node = node->children[idx]; + } + return node->cnt > 1; + } +}; + +class Solution { +public: + vector stringMatching(vector& words) { + vector res; + Trie trie; + + for (const string& word : words) { + trie.insertSuffixes(word); + } + + for (const string& word : words) { + if (trie.search(word)) { + res.push_back(word); + } + } + + return res; + } +}; +``` + +```javascript +class TrieNode { + constructor() { + this.children = new Array(26).fill(null); + this.cnt = 0; + } +} + +class Trie { + constructor() { + this.root = new TrieNode(); + } + + /** + * @param {string} word + * @return {void} + */ + insertSuffixes(word) { + for (let i = 0; i < word.length; i++) { + let node = this.root; + for (let j = i; j < word.length; j++) { + let idx = word.charCodeAt(j) - 97; + if (!node.children[idx]) { + node.children[idx] = new TrieNode(); + } + + node = node.children[idx]; + node.cnt++; + } + } + } + + /** + * @param {string} word + * @return {boolean} + */ + search(word) { + let node = this.root; + for (let i = 0; i < word.length; i++) { + let idx = word.charCodeAt(i) - 97; + node = node.children[idx]; + } + return node.cnt > 1; + } +} + +class Solution { + /** + * @param {string[]} words + * @return {string[]} + */ + stringMatching(words) { + const res = []; + const trie = new Trie(); + + for (let word of words) { + trie.insertSuffixes(word); + } + + for (let word of words) { + if (trie.search(word)) { + res.push(word); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m ^ 2)$ +- Space complexity: + - $O(n * m ^ 2)$ extra space. + - $O(n * m)$ space for the output list. + +> Where $n$ is the number of words, and $m$ is the length of the longest word. diff --git a/articles/student-attendance-record-ii.md b/articles/student-attendance-record-ii.md new file mode 100644 index 000000000..3db9174d1 --- /dev/null +++ b/articles/student-attendance-record-ii.md @@ -0,0 +1,869 @@ +## 1. Dynamic Programming (Top-Down) - I + +::tabs-start + +```python +class Solution: + def checkRecord(self, n: int) -> int: + MOD = 1000000007 + cache = [[[-1 for _ in range(3)] for _ in range(2)] for _ in range(n + 1)] + + def dfs(i, cntA, cntL): + if i == 0: + return 1 + if cache[i][cntA][cntL] != -1: + return cache[i][cntA][cntL] + + res = dfs(i - 1, cntA, 0) % MOD + + if cntA == 0: + res = (res + dfs(i - 1, 1, 0)) % MOD + + if cntL < 2: + res = (res + dfs(i - 1, cntA, cntL + 1)) % MOD + + cache[i][cntA][cntL] = res + return res + + return dfs(n, 0, 0) +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + private int[][][] cache; + + public int checkRecord(int n) { + this.cache = new int[n + 1][2][3]; + for (int[][] matrix : cache) { + for (int[] row : matrix) { + Arrays.fill(row, -1); + } + } + return dfs(n, 0, 0); + } + + private int dfs(int i, int cntA, int cntL) { + if (i == 0) { + return 1; + } + if (cache[i][cntA][cntL] != -1) { + return cache[i][cntA][cntL]; + } + + int res = dfs(i - 1, cntA, 0) % MOD; + + if (cntA == 0) { + res = (res + dfs(i - 1, 1, 0)) % MOD; + } + + if (cntL < 2) { + res = (res + dfs(i - 1, cntA, cntL + 1)) % MOD; + } + + return cache[i][cntA][cntL] = res; + } +} +``` + +```cpp +class Solution { + const int MOD = 1000000007; + vector>> cache; + +public: + int checkRecord(int n) { + cache.assign(n + 1, vector>(2, vector(3, -1))); + return dfs(n, 0, 0); + } + +private: + int dfs(int i, int cntA, int cntL) { + if (i == 0) { + return 1; + } + if (cache[i][cntA][cntL] != -1) { + return cache[i][cntA][cntL]; + } + + int res = dfs(i - 1, cntA, 0) % MOD; + + if (cntA == 0) { + res = (res + dfs(i - 1, 1, 0)) % MOD; + } + + if (cntL < 2) { + res = (res + dfs(i - 1, cntA, cntL + 1)) % MOD; + } + + return cache[i][cntA][cntL] = res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + checkRecord(n) { + const MOD = 1000000007; + let cache = Array.from({ length: n + 1 }, () => + Array.from({ length: 2 }, () => new Array(3).fill(-1)), + ); + + const dfs = (i, cntA, cntL) => { + if (i === 0) return 1; + if (cache[i][cntA][cntL] !== -1) return cache[i][cntA][cntL]; + + let res = dfs(i - 1, cntA, 0) % MOD; + + if (cntA === 0) { + res = (res + dfs(i - 1, 1, 0)) % MOD; + } + + if (cntL < 2) { + res = (res + dfs(i - 1, cntA, cntL + 1)) % MOD; + } + + return (cache[i][cntA][cntL] = res); + }; + + return dfs(n, 0, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Top-Down) - II + +::tabs-start + +```python +class Solution: + def checkRecord(self, n: int) -> int: + MOD = 10**9 + 7 + cache = {} + + def count(n): + if n == 1: + # (A, L) + return { + (0, 0): 1, (0, 1): 1, (0, 2): 0, + (1, 0): 1, (1, 1): 0, (1, 2): 0 + } + + if n in cache: + return cache[n] + + tmp = count(n - 1) + res = defaultdict(int) + + # Choose P + res[(0, 0)] = ((tmp[(0, 0)] + tmp[(0, 1)]) % MOD + tmp[(0, 2)]) % MOD + res[(1, 0)] = ((tmp[(1, 0)] + tmp[(1, 1)]) % MOD + tmp[(1, 2)]) % MOD + + # Choose L + res[(0, 1)] = tmp[(0, 0)] + res[(0, 2)] = tmp[(0, 1)] + res[(1, 1)] = tmp[(1, 0)] + res[(1, 2)] = tmp[(1, 1)] + + # Choose A + res[(1, 0)] += ((tmp[(0, 0)] + tmp[(0, 1)]) % MOD + tmp[(0, 2)]) % MOD + + cache[n] = res + return res + + return sum(count(n).values()) % MOD +``` + +```java +public class Solution { + private static final int MOD = 1000000007; + private int[][][] cache; + private int[][] baseCase; + + public int checkRecord(int n) { + cache = new int[n + 1][2][3]; + baseCase = new int[][]{{1, 1, 0}, {1, 0, 0}}; + for (int[][] matrix : cache) { + for (int[] row : matrix) { + Arrays.fill(row, -1); + } + } + int[][] result = count(n); + int total = 0; + for (int[] row : result) { + for (int val : row) { + total = (total + val) % MOD; + } + } + return total; + } + + private int[][] count(int n) { + if (n == 1) { + // (A, L) + return baseCase; + } + + if (cache[n][0][0] != -1) { + return cache[n]; + } + + int[][] prev = count(n - 1); + int[][] res = cache[n]; + + // Choose P + res[0][0] = ((prev[0][0] + prev[0][1]) % MOD + prev[0][2]) % MOD; + res[1][0] = ((prev[1][0] + prev[1][1]) % MOD + prev[1][2]) % MOD; + + // Choose L + res[0][1] = prev[0][0]; + res[0][2] = prev[0][1]; + res[1][1] = prev[1][0]; + res[1][2] = prev[1][1]; + + // Choose A + res[1][0] = (res[1][0] + ((prev[0][0] + prev[0][1]) % MOD + prev[0][2]) % MOD) % MOD; + + return cache[n]; + } +} +``` + +```cpp +class Solution { +private: + static constexpr int MOD = 1000000007; + vector> baseCase = {{1, 1, 0}, {1, 0, 0}}; + vector>> cache; + +public: + int checkRecord(int n) { + cache.assign(n + 1, vector>(2, vector(3, -1))); + const vector>& result = count(n); + int total = 0; + for (const auto& row : result) { + for (int val : row) { + total = (total + val) % MOD; + } + } + return total; + } + +private: + const vector>& count(int n) { + if (n == 1) { + return baseCase; + } + + if (cache[n][0][0] != -1) { + return cache[n]; + } + + const vector>& prev = count(n - 1); + auto& res = cache[n]; + + // Choose P + res[0][0] = ((prev[0][0] + prev[0][1]) % MOD + prev[0][2]) % MOD; + res[1][0] = ((prev[1][0] + prev[1][1]) % MOD + prev[1][2]) % MOD; + + // Choose L + res[0][1] = prev[0][0]; + res[0][2] = prev[0][1]; + res[1][1] = prev[1][0]; + res[1][2] = prev[1][1]; + + // Choose A + res[1][0] = (res[1][0] + ((prev[0][0] + prev[0][1]) % MOD + prev[0][2]) % MOD) % MOD; + + return cache[n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + checkRecord(n) { + const MOD = 1000000007; + const baseCase = [ + [1, 1, 0], // (A = 0, L = 0, 1, 2) + [1, 0, 0], // (A = 1, L = 0, 1, 2) + ]; + let cache = Array.from({ length: n + 1 }, () => + Array.from({ length: 2 }, () => new Array(3).fill(-1)), + ); + + const count = (n) => { + if (n === 1) return baseCase; + if (cache[n][0][0] !== -1) return cache[n]; + + const prev = count(n - 1); + const res = cache[n]; + + // Choose P + res[0][0] = (((prev[0][0] + prev[0][1]) % MOD) + prev[0][2]) % MOD; + res[1][0] = (((prev[1][0] + prev[1][1]) % MOD) + prev[1][2]) % MOD; + + // Choose L + res[0][1] = prev[0][0]; + res[0][2] = prev[0][1]; + res[1][1] = prev[1][0]; + res[1][2] = prev[1][1]; + + // Choose A + res[1][0] = + (res[1][0] + + ((((prev[0][0] + prev[0][1]) % MOD) + prev[0][2]) % MOD)) % + MOD; + + return res; + }; + + const result = count(n); + let total = 0; + for (const row of result) { + for (const val of row) { + total = (total + val) % MOD; + } + } + return total; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def checkRecord(self, n: int) -> int: + MOD = 1000000007 + dp = [[[0 for _ in range(3)] for _ in range(2)] for _ in range(n + 1)] + + dp[0][0][0] = 1 # Base case + + for i in range(1, n + 1): + for cntA in range(2): + for cntL in range(3): + # Choose P + dp[i][cntA][0] = (dp[i][cntA][0] + dp[i - 1][cntA][cntL]) % MOD + + # Choose A + if cntA > 0: + dp[i][cntA][0] = (dp[i][cntA][0] + dp[i - 1][cntA - 1][cntL]) % MOD + + # Choose L + if cntL > 0: + dp[i][cntA][cntL] = (dp[i][cntA][cntL] + dp[i - 1][cntA][cntL - 1]) % MOD + + return sum(dp[n][cntA][cntL] for cntA in range(2) for cntL in range(3)) % MOD +``` + +```java +public class Solution { + public int checkRecord(int n) { + final int MOD = 1000000007; + int[][][] dp = new int[n + 1][2][3]; + + dp[0][0][0] = 1; + + for (int i = 1; i <= n; i++) { + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + // Choose P + dp[i][cntA][0] = (dp[i][cntA][0] + dp[i - 1][cntA][cntL]) % MOD; + + // Choose A + if (cntA > 0) { + dp[i][cntA][0] = (dp[i][cntA][0] + dp[i - 1][cntA - 1][cntL]) % MOD; + } + + // Choose L + if (cntL > 0) { + dp[i][cntA][cntL] = (dp[i][cntA][cntL] + dp[i - 1][cntA][cntL - 1]) % MOD; + } + } + } + } + + int result = 0; + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + result = (result + dp[n][cntA][cntL]) % MOD; + } + } + + return result; + } +} +``` + +```cpp +class Solution { +public: + int checkRecord(int n) { + const int MOD = 1000000007; + vector>> dp(n + 1, vector>(2, vector(3, 0))); + + dp[0][0][0] = 1; + + for (int i = 1; i <= n; i++) { + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + // Choose P + dp[i][cntA][0] = (dp[i][cntA][0] + dp[i - 1][cntA][cntL]) % MOD; + + // Choose A + if (cntA > 0) { + dp[i][cntA][0] = (dp[i][cntA][0] + dp[i - 1][cntA - 1][cntL]) % MOD; + } + + // Choose L + if (cntL > 0) { + dp[i][cntA][cntL] = (dp[i][cntA][cntL] + dp[i - 1][cntA][cntL - 1]) % MOD; + } + } + } + } + + int result = 0; + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + result = (result + dp[n][cntA][cntL]) % MOD; + } + } + + return result; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + checkRecord(n) { + const MOD = 1000000007; + const dp = Array.from({ length: n + 1 }, () => + Array.from({ length: 2 }, () => new Array(3).fill(0)), + ); + + dp[0][0][0] = 1; + + for (let i = 1; i <= n; i++) { + for (let cntA = 0; cntA < 2; cntA++) { + for (let cntL = 0; cntL < 3; cntL++) { + // Choose P + dp[i][cntA][0] = + (dp[i][cntA][0] + dp[i - 1][cntA][cntL]) % MOD; + + // Choose A + if (cntA > 0) { + dp[i][cntA][0] = + (dp[i][cntA][0] + dp[i - 1][cntA - 1][cntL]) % MOD; + } + + // Choose L + if (cntL > 0) { + dp[i][cntA][cntL] = + (dp[i][cntA][cntL] + dp[i - 1][cntA][cntL - 1]) % + MOD; + } + } + } + } + + let result = 0; + for (let cntA = 0; cntA < 2; cntA++) { + for (let cntL = 0; cntL < 3; cntL++) { + result = (result + dp[n][cntA][cntL]) % MOD; + } + } + + return result; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Space Optimized) - I + +::tabs-start + +```python +class Solution: + def checkRecord(self, n: int) -> int: + if n == 1: + return 3 + + MOD = 10**9 + 7 + dp = { + (0, 0): 1, (0, 1): 1, (0, 2): 0, + (1, 0): 1, (1, 1): 0, (1, 2): 0 + } + + for i in range(n - 1): + ndp = defaultdict(int) + + # Choose P + ndp[(0, 0)] = ((dp[(0, 0)] + dp[(0, 1)]) % MOD + dp[(0, 2)]) % MOD + ndp[(1, 0)] = ((dp[(1, 0)] + dp[(1, 1)]) % MOD + dp[(1, 2)]) % MOD + + # Choose L + ndp[(0, 1)] = dp[(0, 0)] + ndp[(1, 1)] = dp[(1, 0)] + ndp[(0, 2)] = dp[(0, 1)] + ndp[(1, 2)] = dp[(1, 1)] + + # Choose A + ndp[(1, 0)] = (ndp[(1, 0)] + (((dp[(0, 0)] + dp[(0, 1)]) % MOD + dp[(0, 2)]) % MOD)) % MOD + + dp = ndp + + return sum(dp.values()) % MOD +``` + +```java +public class Solution { + public int checkRecord(int n) { + if (n == 1) return 3; + + final int MOD = 1000000007; + int[][] dp = {{1, 1, 0}, {1, 0, 0}}; + + for (int i = 0; i < n - 1; i++) { + int[][] ndp = new int[2][3]; + + // Choose P + ndp[0][0] = ((dp[0][0] + dp[0][1]) % MOD + dp[0][2]) % MOD; + ndp[1][0] = ((dp[1][0] + dp[1][1]) % MOD + dp[1][2]) % MOD; + + // Choose L + ndp[0][1] = dp[0][0]; + ndp[1][1] = dp[1][0]; + ndp[0][2] = dp[0][1]; + ndp[1][2] = dp[1][1]; + + // Choose A + ndp[1][0] = (ndp[1][0] + ((dp[0][0] + dp[0][1]) % MOD + dp[0][2]) % MOD) % MOD; + + dp = ndp; + } + + int total = 0; + for (int[] row : dp) { + for (int val : row) { + total = (total + val) % MOD; + } + } + return total; + } +} +``` + +```cpp +class Solution { +public: + int checkRecord(int n) { + if (n == 1) return 3; + + const int MOD = 1000000007; + vector> dp = {{1, 1, 0}, {1, 0, 0}}; + + for (int i = 0; i < n - 1; i++) { + vector> ndp(2, vector(3, 0)); + + // Choose P + ndp[0][0] = ((dp[0][0] + dp[0][1]) % MOD + dp[0][2]) % MOD; + ndp[1][0] = ((dp[1][0] + dp[1][1]) % MOD + dp[1][2]) % MOD; + + // Choose L + ndp[0][1] = dp[0][0]; + ndp[1][1] = dp[1][0]; + ndp[0][2] = dp[0][1]; + ndp[1][2] = dp[1][1]; + + // Choose A + ndp[1][0] = (ndp[1][0] + ((dp[0][0] + dp[0][1]) % MOD + dp[0][2]) % MOD) % MOD; + + swap(dp, ndp); + } + + int total = 0; + for (auto& row : dp) { + for (int val : row) { + total = (total + val) % MOD; + } + } + return total; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + checkRecord(n) { + if (n === 1) return 3; + + const MOD = 1000000007; + let dp = [ + [1, 1, 0], + [1, 0, 0], + ]; + + for (let i = 0; i < n - 1; i++) { + let ndp = Array.from({ length: 2 }, () => new Array(3).fill(0)); + + // Choose P + ndp[0][0] = (((dp[0][0] + dp[0][1]) % MOD) + dp[0][2]) % MOD; + ndp[1][0] = (((dp[1][0] + dp[1][1]) % MOD) + dp[1][2]) % MOD; + + // Choose L + ndp[0][1] = dp[0][0]; + ndp[1][1] = dp[1][0]; + ndp[0][2] = dp[0][1]; + ndp[1][2] = dp[1][1]; + + // Choose A + ndp[1][0] = + (ndp[1][0] + + ((((dp[0][0] + dp[0][1]) % MOD) + dp[0][2]) % MOD)) % + MOD; + + [dp, ndp] = [ndp, dp]; + } + + let total = 0; + for (let row of dp) { + for (let val of row) { + total = (total + val) % MOD; + } + } + return total; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 5. Dynamic Programming (Space Optimized) - II + +::tabs-start + +```python +class Solution: + def checkRecord(self, n: int) -> int: + MOD = 1000000007 + dp = [[0] * 3 for _ in range(2)] + + dp[0][0] = 1 # Base case + + for i in range(1, n + 1): + next_dp = [[0] * 3 for _ in range(2)] + + for cntA in range(2): + for cntL in range(3): + # Choose P + next_dp[cntA][0] = (next_dp[cntA][0] + dp[cntA][cntL]) % MOD + + # Choose A + if cntA > 0: + next_dp[cntA][0] = (next_dp[cntA][0] + dp[cntA - 1][cntL]) % MOD + + # Choose L + if cntL > 0: + next_dp[cntA][cntL] = (next_dp[cntA][cntL] + dp[cntA][cntL - 1]) % MOD + + dp = next_dp + + return sum(dp[cntA][cntL] for cntA in range(2) for cntL in range(3)) % MOD +``` + +```java +public class Solution { + public int checkRecord(int n) { + final int MOD = 1000000007; + int[][] dp = new int[2][3]; + + dp[0][0] = 1; + + for (int i = 1; i <= n; i++) { + int[][] nextDp = new int[2][3]; + + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + // Choose P + nextDp[cntA][0] = (nextDp[cntA][0] + dp[cntA][cntL]) % MOD; + + // Choose A + if (cntA > 0) { + nextDp[cntA][0] = (nextDp[cntA][0] + dp[cntA - 1][cntL]) % MOD; + } + + // Choose L + if (cntL > 0) { + nextDp[cntA][cntL] = (nextDp[cntA][cntL] + dp[cntA][cntL - 1]) % MOD; + } + } + } + + dp = nextDp; + } + + int result = 0; + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + result = (result + dp[cntA][cntL]) % MOD; + } + } + return result; + } +} +``` + +```cpp +class Solution { +public: + int checkRecord(int n) { + const int MOD = 1000000007; + vector> dp(2, vector(3, 0)); + + dp[0][0] = 1; + + for (int i = 1; i <= n; i++) { + vector> nextDp(2, vector(3, 0)); + + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + // Choose P + nextDp[cntA][0] = (nextDp[cntA][0] + dp[cntA][cntL]) % MOD; + + // Choose A + if (cntA > 0) { + nextDp[cntA][0] = (nextDp[cntA][0] + dp[cntA - 1][cntL]) % MOD; + } + + // Choose L + if (cntL > 0) { + nextDp[cntA][cntL] = (nextDp[cntA][cntL] + dp[cntA][cntL - 1]) % MOD; + } + } + } + + dp = nextDp; + } + + int result = 0; + for (int cntA = 0; cntA < 2; cntA++) { + for (int cntL = 0; cntL < 3; cntL++) { + result = (result + dp[cntA][cntL]) % MOD; + } + } + + return result; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + checkRecord(n) { + const MOD = 1000000007; + let dp = Array.from({ length: 2 }, () => new Array(3).fill(0)); + + dp[0][0] = 1; + + for (let i = 1; i <= n; i++) { + let nextDp = Array.from({ length: 2 }, () => new Array(3).fill(0)); + + for (let cntA = 0; cntA < 2; cntA++) { + for (let cntL = 0; cntL < 3; cntL++) { + // Choose P + nextDp[cntA][0] = (nextDp[cntA][0] + dp[cntA][cntL]) % MOD; + + // Choose A + if (cntA > 0) { + nextDp[cntA][0] = + (nextDp[cntA][0] + dp[cntA - 1][cntL]) % MOD; + } + + // Choose L + if (cntL > 0) { + nextDp[cntA][cntL] = + (nextDp[cntA][cntL] + dp[cntA][cntL - 1]) % MOD; + } + } + } + + dp = nextDp; + } + + let result = 0; + for (let cntA = 0; cntA < 2; cntA++) { + for (let cntL = 0; cntL < 3; cntL++) { + result = (result + dp[cntA][cntL]) % MOD; + } + } + + return result; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/subarray-product-less-than-k.md b/articles/subarray-product-less-than-k.md new file mode 100644 index 000000000..b1d660234 --- /dev/null +++ b/articles/subarray-product-less-than-k.md @@ -0,0 +1,317 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + + for i in range(n): + curProd = 1 + for j in range(i, n): + curProd *= nums[j] + if curProd >= k: + break + res += 1 + + return res +``` + +```java +public class Solution { + public int numSubarrayProductLessThanK(int[] nums, int k) { + int n = nums.length, res = 0; + + for (int i = 0; i < n; i++) { + int curProd = 1; + for (int j = i; j < n; j++) { + curProd *= nums[j]; + if (curProd >= k) break; + res++; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubarrayProductLessThanK(vector& nums, int k) { + int n = nums.size(), res = 0; + + for (int i = 0; i < n; i++) { + int curProd = 1; + for (int j = i; j < n; j++) { + curProd *= nums[j]; + if (curProd >= k) break; + res++; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + numSubarrayProductLessThanK(nums, k) { + let n = nums.length, + res = 0; + + for (let i = 0; i < n; i++) { + let curProd = 1; + for (let j = i; j < n; j++) { + curProd *= nums[j]; + if (curProd >= k) break; + res++; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Binary Search + +::tabs-start + +```python +class Solution: + def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int: + if k <= 1: + return 0 + + n = len(nums) + res = 0 + logs = [0] * (n + 1) + logK = log(k) + for i in range(n): + logs[i + 1] = logs[i] + log(nums[i]) + + for i in range(n): + l, r = i + 1, n + 1 + while l < r: + mid = (l + r) >> 1 + if logs[mid] < logs[i] + logK: + l = mid + 1 + else: + r = mid + + res += l - (i + 1) + + return res +``` + +```java +public class Solution { + public int numSubarrayProductLessThanK(int[] nums, int k) { + if (k <= 1) return 0; + + int n = nums.length, res = 0; + double[] logs = new double[n + 1]; + double logK = Math.log(k); + + for (int i = 0; i < n; i++) { + logs[i + 1] = logs[i] + Math.log(nums[i]); + } + + for (int i = 0; i < n; i++) { + int l = i + 1, r = n + 1; + while (l < r) { + int mid = (l + r) / 2; + if (logs[mid] < logs[i] + logK) { + l = mid + 1; + } else { + r = mid; + } + } + res += l - (i + 1); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubarrayProductLessThanK(vector& nums, int k) { + if (k <= 1) return 0; + + int n = nums.size(), res = 0; + vector logs(n + 1, 0); + double logK = log(k); + + for (int i = 0; i < n; i++) { + logs[i + 1] = logs[i] + log(nums[i]); + } + + for (int i = 0; i < n; i++) { + int l = i + 1, r = n + 1; + while (l < r) { + int mid = (l + r) / 2; + if (logs[mid] < logs[i] + logK) { + l = mid + 1; + } else { + r = mid; + } + } + res += l - (i + 1); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + numSubarrayProductLessThanK(nums, k) { + if (k <= 1) return 0; + + const n = nums.length; + let res = 0; + const logs = new Array(n + 1).fill(0); + const logK = Math.log(k); + + for (let i = 0; i < n; i++) { + logs[i + 1] = logs[i] + Math.log(nums[i]); + } + + for (let i = 0; i < n; i++) { + let l = i + 1, + r = n + 1; + while (l < r) { + const mid = Math.floor((l + r) / 2); + if (logs[mid] < logs[i] + logK) { + l = mid + 1; + } else { + r = mid; + } + } + res += l - (i + 1); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Sliding Window + +::tabs-start + +```python +class Solution: + def numSubarrayProductLessThanK(self, nums: List[int], k: int) -> int: + res = 0 + l = 0 + product = 1 + for r in range(len(nums)): + product *= nums[r] + while l <= r and product >= k: + product //= nums[l] + l += 1 + res += (r - l + 1) + return res +``` + +```java +public class Solution { + public int numSubarrayProductLessThanK(int[] nums, int k) { + int res = 0, l = 0; + long product = 1; + for (int r = 0; r < nums.length; r++) { + product *= nums[r]; + while (l <= r && product >= k) { + product /= nums[l++]; + } + res += (r - l + 1); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numSubarrayProductLessThanK(vector& nums, int k) { + int res = 0, l = 0; + long long product = 1; + for (int r = 0; r < nums.size(); r++) { + product *= nums[r]; + while (l <= r && product >= k) { + product /= nums[l++]; + } + res += (r - l + 1); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + numSubarrayProductLessThanK(nums, k) { + let res = 0, + l = 0, + product = 1; + for (let r = 0; r < nums.length; r++) { + product *= nums[r]; + while (l <= r && product >= k) { + product = Math.floor(product / nums[l++]); + } + res += r - l + 1; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/subarray-sum-equals-k.md b/articles/subarray-sum-equals-k.md index 5afa95bd3..e513192d1 100644 --- a/articles/subarray-sum-equals-k.md +++ b/articles/subarray-sum-equals-k.md @@ -69,12 +69,30 @@ class Solution { } ``` +```csharp +public class Solution { + public int SubarraySum(int[] nums, int k) { + int res = 0; + for (int i = 0; i < nums.Length; i++) { + int sum = 0; + for (int j = i; j < nums.Length; j++) { + sum += nums[j]; + if (sum == k) { + res++; + } + } + } + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ --- @@ -94,7 +112,7 @@ class Solution: res += prefixSums.get(diff, 0) prefixSums[curSum] = 1 + prefixSums.get(curSum, 0) - + return res ``` @@ -145,7 +163,8 @@ class Solution { * @return {number} */ subarraySum(nums, k) { - let res = 0, curSum = 0; + let res = 0, + curSum = 0; const prefixSums = new Map(); prefixSums.set(0, 1); @@ -161,9 +180,35 @@ class Solution { } ``` +```csharp +public class Solution { + public int SubarraySum(int[] nums, int k) { + int res = 0, curSum = 0; + Dictionary prefixSums = new Dictionary(); + prefixSums[0] = 1; + + foreach (int num in nums) { + curSum += num; + int diff = curSum - k; + + if (prefixSums.ContainsKey(diff)) { + res += prefixSums[diff]; + } + + if (!prefixSums.ContainsKey(curSum)) { + prefixSums[curSum] = 0; + } + prefixSums[curSum]++; + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/subarray-sums-divisible-by-k.md b/articles/subarray-sums-divisible-by-k.md new file mode 100644 index 000000000..30cc5ace9 --- /dev/null +++ b/articles/subarray-sums-divisible-by-k.md @@ -0,0 +1,282 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def subarraysDivByK(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + + for i in range(n): + curSum = 0 + for j in range(i, n): + curSum += nums[j] + if curSum % k == 0: + res += 1 + + return res +``` + +```java +public class Solution { + public int subarraysDivByK(int[] nums, int k) { + int n = nums.length, res = 0; + + for (int i = 0; i < n; i++) { + int curSum = 0; + for (int j = i; j < n; j++) { + curSum += nums[j]; + if (curSum % k == 0) { + res++; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int subarraysDivByK(vector& nums, int k) { + int n = nums.size(), res = 0; + + for (int i = 0; i < n; i++) { + int curSum = 0; + for (int j = i; j < n; j++) { + curSum += nums[j]; + if (curSum % k == 0) { + res++; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + subarraysDivByK(nums, k) { + const n = nums.length; + let res = 0; + + for (let i = 0; i < n; i++) { + let curSum = 0; + for (let j = i; j < n; j++) { + curSum += nums[j]; + if (curSum % k === 0) { + res++; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Prefix Sum + Hash Map + +::tabs-start + +```python +class Solution: + def subarraysDivByK(self, nums: List[int], k: int) -> int: + prefix_sum = 0 + res = 0 + prefix_cnt = defaultdict(int) + prefix_cnt[0] = 1 + + for n in nums: + prefix_sum += n + remain = prefix_sum % k + + res += prefix_cnt[remain] + prefix_cnt[remain] += 1 + + return res +``` + +```java +public class Solution { + public int subarraysDivByK(int[] nums, int k) { + int prefixSum = 0, res = 0; + Map prefixCnt = new HashMap<>(); + prefixCnt.put(0, 1); + + for (int n : nums) { + prefixSum += n; + int remain = prefixSum % k; + if (remain < 0) remain += k; + + res += prefixCnt.getOrDefault(remain, 0); + prefixCnt.put(remain, prefixCnt.getOrDefault(remain, 0) + 1); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int subarraysDivByK(vector& nums, int k) { + int prefixSum = 0, res = 0; + unordered_map prefixCnt; + prefixCnt[0] = 1; + + for (int n : nums) { + prefixSum += n; + int remain = prefixSum % k; + if (remain < 0) remain += k; + + res += prefixCnt[remain]; + prefixCnt[remain]++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + subarraysDivByK(nums, k) { + let prefixSum = 0, + res = 0; + const prefixCnt = new Map(); + prefixCnt.set(0, 1); + + for (let n of nums) { + prefixSum += n; + let remain = prefixSum % k; + if (remain < 0) remain += k; + + res += prefixCnt.get(remain) || 0; + prefixCnt.set(remain, (prefixCnt.get(remain) || 0) + 1); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(k)$ + +--- + +## 3. Prefix Sum + Array + +::tabs-start + +```python +class Solution: + def subarraysDivByK(self, nums: List[int], k: int) -> int: + count = [0] * k + count[0] = 1 + prefix = res = 0 + + for num in nums: + prefix = (prefix + num + k) % k + res += count[prefix] + count[prefix] += 1 + + return res +``` + +```java +public class Solution { + public int subarraysDivByK(int[] nums, int k) { + int[] count = new int[k]; + count[0] = 1; + int prefix = 0, res = 0; + + for (int num : nums) { + prefix = (prefix + num % k + k) % k; + res += count[prefix]; + count[prefix]++; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int subarraysDivByK(vector& nums, int k) { + vector count(k, 0); + count[0] = 1; + int prefix = 0, res = 0; + + for (int num : nums) { + prefix = (prefix + num % k + k) % k; + res += count[prefix]; + count[prefix]++; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + subarraysDivByK(nums, k) { + const count = Array(k).fill(0); + count[0] = 1; + let prefix = 0, + res = 0; + + for (let num of nums) { + prefix = (prefix + (num % k) + k) % k; + res += count[prefix]; + count[prefix]++; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + k)$ +- Space complexity: $O(k)$ diff --git a/articles/subarrays-with-k-different-integers.md b/articles/subarrays-with-k-different-integers.md new file mode 100644 index 000000000..a61fba032 --- /dev/null +++ b/articles/subarrays-with-k-different-integers.md @@ -0,0 +1,552 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def subarraysWithKDistinct(self, nums: List[int], k: int) -> int: + n, res = len(nums), 0 + + for i in range(n): + seen = set() + for j in range(i, n): + seen.add(nums[j]) + if len(seen) > k: + break + + if len(seen) == k: + res += 1 + + return res +``` + +```java +public class Solution { + public int subarraysWithKDistinct(int[] nums, int k) { + int n = nums.length, res = 0; + + for (int i = 0; i < n; i++) { + Set seen = new HashSet<>(); + for (int j = i; j < n; j++) { + seen.add(nums[j]); + if (seen.size() > k) { + break; + } + if (seen.size() == k) { + res++; + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int subarraysWithKDistinct(vector& nums, int k) { + int n = nums.size(), res = 0; + + for (int i = 0; i < n; i++) { + unordered_set seen; + for (int j = i; j < n; j++) { + seen.insert(nums[j]); + if (seen.size() > k) { + break; + } + if (seen.size() == k) { + res++; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + subarraysWithKDistinct(nums, k) { + let n = nums.length, + res = 0; + + for (let i = 0; i < n; i++) { + let seen = new Set(); + for (let j = i; j < n; j++) { + seen.add(nums[j]); + if (seen.size > k) { + break; + } + if (seen.size === k) { + res++; + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 2. Sliding Window + +::tabs-start + +```python +class Solution: + def subarraysWithKDistinct(self, nums: List[int], k: int) -> int: + + def atMostK(k): + count = defaultdict(int) + res = l = 0 + + for r in range(len(nums)): + count[nums[r]] += 1 + if count[nums[r]] == 1: + k -= 1 + + while k < 0: + count[nums[l]] -= 1 + if count[nums[l]] == 0: + k += 1 + l += 1 + + res += (r - l + 1) + + return res + + return atMostK(k) - atMostK(k - 1) +``` + +```java +public class Solution { + public int subarraysWithKDistinct(int[] nums, int k) { + return atMostK(nums, k) - atMostK(nums, k - 1); + } + + private int atMostK(int[] nums, int k) { + HashMap count = new HashMap<>(); + int res = 0, l = 0; + + for (int r = 0; r < nums.length; r++) { + count.put(nums[r], count.getOrDefault(nums[r], 0) + 1); + if (count.get(nums[r]) == 1) { + k--; + } + + while (k < 0) { + count.put(nums[l], count.get(nums[l]) - 1); + if (count.get(nums[l]) == 0) { + k++; + } + l++; + } + + res += (r - l + 1); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int subarraysWithKDistinct(vector& nums, int k) { + return atMostK(nums, k) - atMostK(nums, k - 1); + } + +private: + int atMostK(vector& nums, int k) { + unordered_map count; + int res = 0, l = 0; + + for (int r = 0; r < nums.size(); r++) { + count[nums[r]]++; + if (count[nums[r]] == 1) { + k--; + } + + while (k < 0) { + count[nums[l]]--; + if (count[nums[l]] == 0) { + k++; + } + l++; + } + + res += (r - l + 1); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + subarraysWithKDistinct(nums, k) { + const atMostK = (k) => { + const count = new Map(); + let res = 0, + l = 0; + + for (let r = 0; r < nums.length; r++) { + count.set(nums[r], (count.get(nums[r]) || 0) + 1); + if (count.get(nums[r]) === 1) { + k--; + } + + while (k < 0) { + count.set(nums[l], count.get(nums[l]) - 1); + if (count.get(nums[l]) === 0) { + k++; + } + l++; + } + + res += r - l + 1; + } + + return res; + }; + + return atMostK(k) - atMostK(k - 1); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Sliding Window (One Pass) - I + +::tabs-start + +```python +class Solution: + def subarraysWithKDistinct(self, nums: List[int], k: int) -> int: + count = defaultdict(int) + res = 0 + l_far = 0 + l_near = 0 + + for r in range(len(nums)): + count[nums[r]] += 1 + + while len(count) > k: + count[nums[l_near]] -= 1 + if count[nums[l_near]] == 0: + count.pop(nums[l_near]) + l_near += 1 + l_far = l_near + + while count[nums[l_near]] > 1: + count[nums[l_near]] -= 1 + l_near += 1 + + if len(count) == k: + res += l_near - l_far + 1 + + return res +``` + +```java +public class Solution { + public int subarraysWithKDistinct(int[] nums, int k) { + HashMap count = new HashMap<>(); + int res = 0, l_far = 0, l_near = 0; + + for (int r = 0; r < nums.length; r++) { + count.put(nums[r], count.getOrDefault(nums[r], 0) + 1); + + while (count.size() > k) { + count.put(nums[l_near], count.get(nums[l_near]) - 1); + if (count.get(nums[l_near]) == 0) { + count.remove(nums[l_near]); + } + l_near++; + l_far = l_near; + } + + while (count.get(nums[l_near]) > 1) { + count.put(nums[l_near], count.get(nums[l_near]) - 1); + l_near++; + } + + if (count.size() == k) { + res += l_near - l_far + 1; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int subarraysWithKDistinct(vector& nums, int k) { + unordered_map count; + int res = 0, l_far = 0, l_near = 0; + + for (int r = 0; r < nums.size(); r++) { + count[nums[r]]++; + + while (count.size() > k) { + count[nums[l_near]]--; + if (count[nums[l_near]] == 0) { + count.erase(nums[l_near]); + } + l_near++; + l_far = l_near; + } + + while (count[nums[l_near]] > 1) { + count[nums[l_near]]--; + l_near++; + } + + if (count.size() == k) { + res += l_near - l_far + 1; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + subarraysWithKDistinct(nums, k) { + const count = new Map(); + let res = 0, + l_far = 0, + l_near = 0; + + for (let r = 0; r < nums.length; r++) { + count.set(nums[r], (count.get(nums[r]) || 0) + 1); + + while (count.size > k) { + count.set(nums[l_near], count.get(nums[l_near]) - 1); + if (count.get(nums[l_near]) === 0) { + count.delete(nums[l_near]); + } + l_near++; + } + + while (count.get(nums[l_near]) > 1) { + count.set(nums[l_near], count.get(nums[l_near]) - 1); + l_near++; + } + + if (count.size === k) { + res += l_near - l_far + 1; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Sliding Window (One Pass) - II + +::tabs-start + +```python +class Solution: + def subarraysWithKDistinct(self, nums: List[int], k: int) -> int: + n = len(nums) + count = [0] * (n + 1) + res = l = cnt = 0 + + for r in range(n): + count[nums[r]] += 1 + if count[nums[r]] == 1: + k -= 1 + + if k < 0: + count[nums[l]] -= 1 + l += 1 + k += 1 + cnt = 0 + + if k == 0: + while count[nums[l]] > 1: + count[nums[l]] -= 1 + l += 1 + cnt += 1 + + res += (cnt + 1) + + return res +``` + +```java +public class Solution { + public int subarraysWithKDistinct(int[] nums, int k) { + int n = nums.length; + int[] count = new int[n + 1]; + int res = 0, l = 0, cnt = 0; + + for (int r = 0; r < n; r++) { + count[nums[r]]++; + if (count[nums[r]] == 1) { + k--; + } + + if (k < 0) { + count[nums[l]]--; + l++; + k++; + cnt = 0; + } + + if (k == 0) { + while (count[nums[l]] > 1) { + count[nums[l]]--; + l++; + cnt++; + } + + res += (cnt + 1); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int subarraysWithKDistinct(vector& nums, int k) { + int n = nums.size(); + vector count(n + 1, 0); + int res = 0, l = 0, cnt = 0; + + for (int r = 0; r < n; r++) { + count[nums[r]]++; + if (count[nums[r]] == 1) { + k--; + } + + if (k < 0) { + count[nums[l]]--; + l++; + k++; + cnt = 0; + } + + if (k == 0) { + while (count[nums[l]] > 1) { + count[nums[l]]--; + l++; + cnt++; + } + + res += (cnt + 1); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + subarraysWithKDistinct(nums, k) { + const n = nums.length; + const count = new Array(n + 1).fill(0); + let res = 0, + l = 0, + cnt = 0; + + for (let r = 0; r < n; r++) { + count[nums[r]]++; + if (count[nums[r]] === 1) { + k--; + } + + if (k < 0) { + count[nums[l]]--; + l++; + k++; + cnt = 0; + } + + if (k === 0) { + while (count[nums[l]] > 1) { + count[nums[l]]--; + l++; + cnt++; + } + + res += cnt + 1; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/subsets-ii.md b/articles/subsets-ii.md index 7ceeedab6..d1aeb5b99 100644 --- a/articles/subsets-ii.md +++ b/articles/subsets-ii.md @@ -83,7 +83,7 @@ class Solution { subsetsWithDup(nums) { nums.sort((a, b) => a - b); this.backtrack(nums, 0, []); - return Array.from(this.res).map(subset => JSON.parse(subset)); + return Array.from(this.res).map((subset) => JSON.parse(subset)); } /** @@ -160,7 +160,7 @@ func subsetsWithDup(nums []int) [][]int { } backtrack(0, []int{}) - + var result [][]int for _, v := range res { result = append(result, v) @@ -193,16 +193,41 @@ class Solution { } ``` +```swift +class Solution { + func subsetsWithDup(_ nums: [Int]) -> [[Int]] { + var res = Set<[Int]>() + var subset = [Int]() + let nums = nums.sorted() + + func backtrack(_ i: Int) { + if i == nums.count { + res.insert(subset) + return + } + + subset.append(nums[i]) + backtrack(i + 1) + subset.removeLast() + backtrack(i + 1) + } + + backtrack(0) + return Array(res) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^n)$ -* Space complexity: $O(2 ^ n)$ +- Time complexity: $O(n * 2 ^n)$ +- Space complexity: $O(2 ^ n)$ --- -## 2. Backtracking (Pick / Not Pick) +## 2. Backtracking - I ::tabs-start @@ -405,16 +430,48 @@ class Solution { } ``` +```swift +class Solution { + func subsetsWithDup(_ nums: [Int]) -> [[Int]] { + var res = [[Int]]() + var subset = [Int]() + let nums = nums.sorted() + + func backtrack(_ i: Int) { + if i == nums.count { + res.append(subset) + return + } + + subset.append(nums[i]) + backtrack(i + 1) + subset.removeLast() + + var j = i + while j + 1 < nums.count && nums[j] == nums[j + 1] { + j += 1 + } + backtrack(j + 1) + } + + backtrack(0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: + - $O(n)$ extra space. + - $O(2 ^ n)$ space for the output list. --- -## 3. Backtracking +## 3. Backtracking - II ::tabs-start @@ -595,12 +652,40 @@ class Solution { } ``` +```swift +class Solution { + func subsetsWithDup(_ nums: [Int]) -> [[Int]] { + var res = [[Int]]() + var subset = [Int]() + let nums = nums.sorted() + + func backtrack(_ i: Int) { + res.append(subset) + + for j in i.. i && nums[j] == nums[j - 1] { + continue + } + subset.append(nums[j]) + backtrack(j + 1) + subset.removeLast() + } + } + + backtrack(0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: + - $O(n)$ extra space. + - $O(2 ^ n)$ space for the output list. --- @@ -614,6 +699,7 @@ class Solution: nums.sort() res = [[]] prev_Idx = idx = 0 + for i in range(len(nums)): idx = prev_idx if i >= 1 and nums[i] == nums[i - 1] else 0 prev_idx = len(res) @@ -621,6 +707,7 @@ class Solution: tmp = res[j].copy() tmp.append(nums[i]) res.append(tmp) + return res ``` @@ -629,9 +716,10 @@ public class Solution { public List> subsetsWithDup(int[] nums) { Arrays.sort(nums); List> res = new ArrayList<>(); - res.add(new ArrayList<>()); + res.add(new ArrayList<>()); int prevIdx = 0; int idx = 0; + for (int i = 0; i < nums.length; i++) { idx = (i >= 1 && nums[i] == nums[i - 1]) ? prevIdx : 0; prevIdx = res.size(); @@ -641,6 +729,7 @@ public class Solution { res.add(tmp); } } + return res; } } @@ -654,6 +743,7 @@ public: vector> res = {{}}; int prevIdx = 0; int idx = 0; + for (int i = 0; i < nums.size(); i++) { idx = (i >= 1 && nums[i] == nums[i - 1]) ? prevIdx : 0; prevIdx = res.size(); @@ -663,6 +753,7 @@ public: res.push_back(tmp); } } + return res; } }; @@ -679,8 +770,9 @@ class Solution { const res = [[]]; let prevIdx = 0; let idx = 0; + for (let i = 0; i < nums.length; i++) { - idx = (i >= 1 && nums[i] === nums[i - 1]) ? prevIdx : 0; + idx = i >= 1 && nums[i] === nums[i - 1] ? prevIdx : 0; prevIdx = res.length; for (let j = idx; j < prevIdx; j++) { const tmp = [...res[j]]; @@ -688,6 +780,7 @@ class Solution { res.push(tmp); } } + return res; } } @@ -700,6 +793,7 @@ public class Solution { var res = new List> { new List() }; int prevIdx = 0; int idx = 0; + for (int i = 0; i < nums.Length; i++) { idx = (i >= 1 && nums[i] == nums[i - 1]) ? prevIdx : 0; prevIdx = res.Count; @@ -709,6 +803,7 @@ public class Solution { res.Add(tmp); } } + return res; } } @@ -761,9 +856,35 @@ class Solution { } ``` +```swift +class Solution { + func subsetsWithDup(_ nums: [Int]) -> [[Int]] { + let nums = nums.sorted() + var res: [[Int]] = [[]] + var prevIdx = 0 + var idx = 0 + + for i in 0..= 1 && nums[i] == nums[i - 1]) ? prevIdx : 0 + prevIdx = res.count + + for j in idx.. List[List[int]]: res = [] - subset = [] def dfs(i): @@ -24,7 +23,7 @@ class Solution: ```java public class Solution { - + public List> subsets(int[] nums) { List> res = new ArrayList<>(); List subset = new ArrayList<>(); @@ -104,7 +103,7 @@ class Solution { ```csharp public class Solution { - + public List> Subsets(int[] nums) { var res = new List>(); var subset = new List(); @@ -172,12 +171,37 @@ class Solution { } ``` +```swift +class Solution { + func subsets(_ nums: [Int]) -> [[Int]] { + var res = [[Int]]() + var subset = [Int]() + + func dfs(_ i: Int) { + if i >= nums.count { + res.append(subset) + return + } + subset.append(nums[i]) + dfs(i + 1) + subset.removeLast() + dfs(i + 1) + } + + dfs(0) + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: + - $O(n)$ extra space. + - $O(2 ^ n)$ for the output list. --- @@ -189,10 +213,10 @@ class Solution { class Solution: def subsets(self, nums: List[int]) -> List[List[int]]: res = [[]] - + for num in nums: res += [subset + [num] for subset in res] - + return res ``` @@ -221,7 +245,7 @@ class Solution { public: vector> subsets(vector& nums) { vector> res = {{}}; - + for (int num : nums) { int size = res.size(); for (int i = 0; i < size; i++) { @@ -248,7 +272,7 @@ class Solution { for (let num of nums) { let size = res.length; for (let i = 0; i < size; i++) { - let subset = res[i].slice(); + let subset = res[i].slice(); subset.push(num); res.push(subset); } @@ -264,7 +288,7 @@ public class Solution { public List> Subsets(int[] nums) { List> res = new List>(); res.Add(new List()); - + foreach (int num in nums) { int size = res.Count; for (int i = 0; i < size; i++) { @@ -316,12 +340,28 @@ class Solution { } ``` +```swift +class Solution { + func subsets(_ nums: [Int]) -> [[Int]] { + var res: [[Int]] = [[]] + + for num in nums { + res += res.map { $0 + [num] } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: + - $O(n)$ extra space. + - $O(2 ^ n)$ for the output list. --- @@ -388,7 +428,7 @@ class Solution { subsets(nums) { let res = []; let n = nums.length; - for (let i = 0; i < (1 << n); i++) { + for (let i = 0; i < 1 << n; i++) { let subset = []; for (let j = 0; j < n; j++) { if (i & (1 << j)) { @@ -461,9 +501,32 @@ class Solution { } ``` +```swift +class Solution { + func subsets(_ nums: [Int]) -> [[Int]] { + let n = nums.count + var res: [[Int]] = [] + + for i in 0..<(1 << n) { + var subset: [Int] = [] + for j in 0.. bool: if not subRoot: return True @@ -20,14 +20,14 @@ class Solution: if self.sameTree(root, subRoot): return True - return (self.isSubtree(root.left, subRoot) or + return (self.isSubtree(root.left, subRoot) or self.isSubtree(root.right, subRoot)) def sameTree(self, root: Optional[TreeNode], subRoot: Optional[TreeNode]) -> bool: if not root and not subRoot: return True if root and subRoot and root.val == subRoot.val: - return (self.sameTree(root.left, subRoot.left) and + return (self.sameTree(root.left, subRoot.left) and self.sameTree(root.right, subRoot.right)) return False ``` @@ -50,7 +50,7 @@ class Solution: */ class Solution { - + public boolean isSubtree(TreeNode root, TreeNode subRoot) { if (subRoot == null) { return true; @@ -62,7 +62,7 @@ class Solution { if (sameTree(root, subRoot)) { return true; } - return isSubtree(root.left, subRoot) || + return isSubtree(root.left, subRoot) || isSubtree(root.right, subRoot); } @@ -71,7 +71,7 @@ class Solution { return true; } if (root != null && subRoot != null && root.val == subRoot.val) { - return sameTree(root.left, subRoot.left) && + return sameTree(root.left, subRoot.left) && sameTree(root.right, subRoot.right); } return false; @@ -105,7 +105,7 @@ public: if (sameTree(root, subRoot)) { return true; } - return isSubtree(root->left, subRoot) || + return isSubtree(root->left, subRoot) || isSubtree(root->right, subRoot); } @@ -193,7 +193,7 @@ class Solution { */ public class Solution { - + public bool IsSubtree(TreeNode root, TreeNode subRoot) { if (subRoot == null) { return true; @@ -205,7 +205,7 @@ public class Solution { if (SameTree(root, subRoot)) { return true; } - return IsSubtree(root.left, subRoot) || + return IsSubtree(root.left, subRoot) || IsSubtree(root.right, subRoot); } @@ -214,7 +214,7 @@ public class Solution { return true; } if (root != null && subRoot != null && root.val == subRoot.val) { - return SameTree(root.left, subRoot.left) && + return SameTree(root.left, subRoot.left) && SameTree(root.right, subRoot.right); } return false; @@ -294,12 +294,54 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isSubtree(_ root: TreeNode?, _ subRoot: TreeNode?) -> Bool { + if subRoot == nil { + return true + } + if root == nil { + return false + } + if sameTree(root, subRoot) { + return true + } + return isSubtree(root?.left, subRoot) || isSubtree(root?.right, subRoot) + } + + func sameTree(_ root: TreeNode?, _ subRoot: TreeNode?) -> Bool { + if root == nil && subRoot == nil { + return true + } + if let root = root, let subRoot = subRoot, root.val == subRoot.val { + return sameTree(root.left, subRoot.left) && sameTree(root.right, subRoot.right) + } + return false + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m + n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m + n)$ > Where $m$ is the number of nodes in $subRoot$ and $n$ is the number of nodes in $root$. @@ -317,13 +359,12 @@ class Solution { # self.left = left # self.right = right -class Solution: +class Solution: def serialize(self, root: Optional[TreeNode]) -> str: - if root == None: - return "$#" - - return ("$" + str(root.val) + - self.serialize(root.left) + self.serialize(root.right)) + if root == None: + return "$#" + + return ("$" + str(root.val) + self.serialize(root.left) + self.serialize(root.right)) def z_function(self, s: str) -> list: z = [0] * len(s) @@ -341,10 +382,10 @@ class Solution: serialized_root = self.serialize(root) serialized_subRoot = self.serialize(subRoot) combined = serialized_subRoot + "|" + serialized_root - + z_values = self.z_function(combined) sub_len = len(serialized_subRoot) - + for i in range(sub_len + 1, len(combined)): if z_values[i] == sub_len: return True @@ -398,10 +439,10 @@ public class Solution { String serialized_root = serialize(root); String serialized_subRoot = serialize(subRoot); String combined = serialized_subRoot + "|" + serialized_root; - + int[] z_values = z_function(combined); int sub_len = serialized_subRoot.length(); - + for (int i = sub_len + 1; i < combined.length(); i++) { if (z_values[i] == sub_len) { return true; @@ -431,7 +472,7 @@ public: if (root == nullptr) { return "$#"; } - return "$" + to_string(root->val) + + return "$" + to_string(root->val) + serialize(root->left) + serialize(root->right); } @@ -457,10 +498,10 @@ public: string serialized_root = serialize(root); string serialized_subRoot = serialize(subRoot); string combined = serialized_subRoot + "|" + serialized_root; - + vector z_values = z_function(combined); int sub_len = serialized_subRoot.length(); - + for (int i = sub_len + 1; i < combined.length(); i++) { if (z_values[i] == sub_len) { return true; @@ -490,10 +531,14 @@ class Solution { */ serialize(root) { if (root === null) { - return "$#"; + return '$#'; } - return "$" + root.val + - this.serialize(root.left) + this.serialize(root.right); + return ( + '$' + + root.val + + this.serialize(root.left) + + this.serialize(root.right) + ); } /** @@ -502,7 +547,9 @@ class Solution { */ z_function(s) { const z = new Array(s.length).fill(0); - let l = 0, r = 0, n = s.length; + let l = 0, + r = 0, + n = s.length; for (let i = 1; i < n; i++) { if (i <= r) { z[i] = Math.min(r - i + 1, z[i - l]); @@ -526,11 +573,11 @@ class Solution { isSubtree(root, subRoot) { const serialized_root = this.serialize(root); const serialized_subRoot = this.serialize(subRoot); - const combined = serialized_subRoot + "|" + serialized_root; - + const combined = serialized_subRoot + '|' + serialized_root; + const z_values = this.z_function(combined); const sub_len = serialized_subRoot.length; - + for (let i = sub_len + 1; i < combined.length; i++) { if (z_values[i] === sub_len) { return true; @@ -561,7 +608,7 @@ public class Solution { if (root == null) { return "$#"; } - return "$" + root.val + + return "$" + root.val + Serialize(root.left) + Serialize(root.right); } @@ -587,10 +634,10 @@ public class Solution { string serialized_root = Serialize(root); string serialized_subRoot = Serialize(subRoot); string combined = serialized_subRoot + "|" + serialized_root; - + int[] z_values = ZFunction(combined); int sub_len = serialized_subRoot.Length; - + for (int i = sub_len + 1; i < combined.Length; i++) { if (z_values[i] == sub_len) { return true; @@ -621,7 +668,7 @@ func zFunction(s string) []int { n := len(s) z := make([]int, n) l, r := 0, 0 - + for i := 1; i < n; i++ { if i <= r { z[i] = min(r-i+1, z[i-l]) @@ -648,10 +695,10 @@ func isSubtree(root *TreeNode, subRoot *TreeNode) bool { serializedRoot := serialize(root) serializedSubRoot := serialize(subRoot) combined := serializedSubRoot + "|" + serializedRoot - + zValues := zFunction(combined) subLen := len(serializedSubRoot) - + for i := subLen + 1; i < len(combined); i++ { if zValues[i] == subLen { return true @@ -679,13 +726,13 @@ class Solution { else -> "$${root.`val`}${serialize(root.left)}${serialize(root.right)}" } } - + private fun zFunction(s: String): IntArray { val n = s.length val z = IntArray(n) var l = 0 var r = 0 - + for (i in 1 until n) { if (i <= r) { z[i] = minOf(r - i + 1, z[i - l]) @@ -700,25 +747,88 @@ class Solution { } return z } - + fun isSubtree(root: TreeNode?, subRoot: TreeNode?): Boolean { val serializedRoot = serialize(root) val serializedSubRoot = serialize(subRoot) val combined = serializedSubRoot + "|" + serializedRoot - + val zValues = zFunction(combined) val subLen = serializedSubRoot.length - + return (subLen + 1 until combined.length).any { i -> zValues[i] == subLen } } } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func serialize(_ root: TreeNode?) -> String { + guard let root = root else { + return "$#" + } + return "$\(root.val)" + serialize(root.left) + serialize(root.right) + } + + func zFunction(_ s: String) -> [Int] { + let n = s.count + var z = [Int](repeating: 0, count: n) + var l = 0, r = 0 + let chars = Array(s) + + for i in 1.. r { + l = i + r = i + z[i] - 1 + } + } + return z + } + + func isSubtree(_ root: TreeNode?, _ subRoot: TreeNode?) -> Bool { + let serializedRoot = serialize(root) + let serializedSubRoot = serialize(subRoot) + let combined = serializedSubRoot + "|" + serializedRoot + + let zValues = zFunction(combined) + let subLen = serializedSubRoot.count + + for i in (subLen + 1).. Where $m$ is the number of nodes in $subRoot$ and $n$ is the number of nodes in $root$. \ No newline at end of file +> Where $m$ is the number of nodes in $subRoot$ and $n$ is the number of nodes in $root$. diff --git a/articles/successful-pairs-of-spells-and-potions.md b/articles/successful-pairs-of-spells-and-potions.md new file mode 100644 index 000000000..532ed79dd --- /dev/null +++ b/articles/successful-pairs-of-spells-and-potions.md @@ -0,0 +1,465 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]: + res = [] + + for s in spells: + cnt = 0 + for p in potions: + if s * p >= success: + cnt += 1 + res.append(cnt) + + return res +``` + +```java +public class Solution { + public int[] successfulPairs(int[] spells, int[] potions, long success) { + int[] res = new int[spells.length]; + + for (int i = 0; i < spells.length; i++) { + int cnt = 0; + for (int p : potions) { + if ((long) spells[i] * p >= success) { + cnt++; + } + } + res[i] = cnt; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector successfulPairs(vector& spells, vector& potions, long long success) { + vector res(spells.size()); + + for (int i = 0; i < spells.size(); i++) { + int cnt = 0; + for (int p : potions) { + if ((long long) spells[i] * p >= success) { + cnt++; + } + } + res[i] = cnt; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} spells + * @param {number[]} potions + * @param {number} success + * @return {number[]} + */ + successfulPairs(spells, potions, success) { + let res = []; + + for (let s of spells) { + let cnt = 0; + for (let p of potions) { + if (s * p >= success) { + cnt++; + } + } + res.push(cnt); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m)$ +- Space complexity: $O(1)$ + +> Where $n$ and $m$ are the sizes of the arrays $spells$ and $potions$ respectively. + +--- + +## 2. Sorting + Binary Search + +::tabs-start + +```python +class Solution: + def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]: + potions.sort() + res = [] + + for s in spells: + l, r = 0, len(potions) - 1 + idx = len(potions) + + while l <= r: + m = (l + r) // 2 + if s * potions[m] >= success: + r = m - 1 + idx = m + else: + l = m + 1 + + res.append(len(potions) - idx) + + return res +``` + +```java +public class Solution { + public int[] successfulPairs(int[] spells, int[] potions, long success) { + Arrays.sort(potions); + int[] res = new int[spells.length]; + + for (int i = 0; i < spells.length; i++) { + int l = 0, r = potions.length - 1, idx = potions.length; + + while (l <= r) { + int m = (l + r) / 2; + if ((long) spells[i] * potions[m] >= success) { + r = m - 1; + idx = m; + } else { + l = m + 1; + } + } + + res[i] = potions.length - idx; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector successfulPairs(vector& spells, vector& potions, long long success) { + sort(potions.begin(), potions.end()); + vector res(spells.size()); + + for (int i = 0; i < spells.size(); i++) { + int l = 0, r = potions.size() - 1, idx = potions.size(); + + while (l <= r) { + int m = (l + r) / 2; + if ((long long) spells[i] * potions[m] >= success) { + r = m - 1; + idx = m; + } else { + l = m + 1; + } + } + + res[i] = potions.size() - idx; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} spells + * @param {number[]} potions + * @param {number} success + * @return {number[]} + */ + successfulPairs(spells, potions, success) { + potions.sort((a, b) => a - b); + let res = []; + + for (let s of spells) { + let l = 0, + r = potions.length - 1, + idx = potions.length; + + while (l <= r) { + let m = Math.floor((l + r) / 2); + if (s * potions[m] >= success) { + r = m - 1; + idx = m; + } else { + l = m + 1; + } + } + + res.push(potions.length - idx); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O((m + n) * \log m)$ +- Space complexity: + - $O(1)$ or $O(m)$ extra space depending on the sorting algorithm. + - $O(n)$ space for the output array. + +> Where $n$ and $m$ are the sizes of the arrays $spells$ and $potions$ respectively. + +--- + +## 3. Sorting + Two Pointers + +::tabs-start + +```python +class Solution: + def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]: + n, m = len(spells), len(potions) + S = spells[:] + count = defaultdict(int) + spells.sort() + potions.sort() + + j = m - 1 + for i in range(n): + while j >= 0 and spells[i] * potions[j] >= success: + j -= 1 + count[spells[i]] = m - j - 1 + + res = [0] * n + for i in range(n): + res[i] = count[S[i]] + + return res +``` + +```java +public class Solution { + public int[] successfulPairs(int[] spells, int[] potions, long success) { + int n = spells.length, m = potions.length; + int[] S = Arrays.copyOf(spells, n); + Map count = new HashMap<>(); + Arrays.sort(spells); + Arrays.sort(potions); + + int j = m - 1; + for (int i = 0; i < n; i++) { + while (j >= 0 && (long) spells[i] * potions[j] >= success) { + j--; + } + count.put(spells[i], m - j - 1); + } + + int[] res = new int[n]; + for (int i = 0; i < n; i++) { + res[i] = count.get(S[i]); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector successfulPairs(vector& spells, vector& potions, long long success) { + int n = spells.size(), m = potions.size(); + vector S = spells; + unordered_map count; + sort(spells.begin(), spells.end()); + sort(potions.begin(), potions.end()); + + int j = m - 1; + for (int i = 0; i < n; i++) { + while (j >= 0 && (long long) spells[i] * potions[j] >= success) { + j--; + } + count[spells[i]] = m - j - 1; + } + + vector res(n); + for (int i = 0; i < n; i++) { + res[i] = count[S[i]]; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} spells + * @param {number[]} potions + * @param {number} success + * @return {number[]} + */ + successfulPairs(spells, potions, success) { + const n = spells.length, + m = potions.length; + const S = [...spells]; + const count = new Map(); + spells.sort((a, b) => a - b); + potions.sort((a, b) => a - b); + + let j = m - 1; + for (let i = 0; i < n; i++) { + while (j >= 0 && spells[i] * potions[j] >= success) { + j--; + } + count.set(spells[i], m - j - 1); + } + + return S.map((s) => count.get(s)); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n + m\log m)$ +- Space complexity: + - $O(1)$ or $O(m + n)$ extra space depending on the sorting algorithm. + - $O(n)$ space for the output array. + +> Where $n$ and $m$ are the sizes of the arrays $spells$ and $potions$ respectively. + +--- + +## 4. Sorting + Two Pointers (Optimal) + +::tabs-start + +```python +class Solution: + def successfulPairs(self, spells: List[int], potions: List[int], success: int) -> List[int]: + n, m = len(spells), len(potions) + sIdx = list(range(n)) + sIdx.sort(key=lambda x: spells[x]) + potions.sort() + + j = m - 1 + res = [0] * n + for i in range(n): + while j >= 0 and spells[sIdx[i]] * potions[j] >= success: + j -= 1 + res[sIdx[i]] = m - j - 1 + + return res +``` + +```java +public class Solution { + public int[] successfulPairs(int[] spells, int[] potions, long success) { + int n = spells.length, m = potions.length; + Integer[] sIdx = new Integer[n]; + for (int i = 0; i < n; i++) sIdx[i] = i; + + Arrays.sort(sIdx, Comparator.comparingInt(i -> spells[i])); + Arrays.sort(potions); + + int j = m - 1; + int[] res = new int[n]; + for (int i = 0; i < n; i++) { + while (j >= 0 && (long) spells[sIdx[i]] * potions[j] >= success) { + j--; + } + res[sIdx[i]] = m - j - 1; + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector successfulPairs(vector& spells, vector& potions, long long success) { + int n = spells.size(), m = potions.size(); + vector sIdx(n); + for (int i = 0; i < n; i++) sIdx[i] = i; + + sort(sIdx.begin(), sIdx.end(), [&](int a, int b) { + return spells[a] < spells[b]; + }); + + sort(potions.begin(), potions.end()); + + int j = m - 1; + vector res(n); + for (int i = 0; i < n; i++) { + while (j >= 0 && (long long) spells[sIdx[i]] * potions[j] >= success) { + j--; + } + res[sIdx[i]] = m - j - 1; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} spells + * @param {number[]} potions + * @param {number} success + * @return {number[]} + */ + successfulPairs(spells, potions, success) { + const n = spells.length, + m = potions.length; + const sIdx = Array.from({ length: n }, (_, i) => i); + + sIdx.sort((a, b) => spells[a] - spells[b]); + potions.sort((a, b) => a - b); + + let j = m - 1; + const res = new Array(n).fill(0); + + for (let i = 0; i < n; i++) { + while (j >= 0 && spells[sIdx[i]] * potions[j] >= success) { + j--; + } + res[sIdx[i]] = m - j - 1; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n + m\log m)$ +- Space complexity: + - $O(1)$ or $O(m + n)$ extra space depending on the sorting algorithm. + - $O(n)$ space for the output array. + +> Where $n$ and $m$ are the sizes of the arrays $spells$ and $potions$ respectively. diff --git a/articles/sum-of-absolute-differences-in-a-sorted-array.md b/articles/sum-of-absolute-differences-in-a-sorted-array.md index f705f47d7..a8b0fa5fa 100644 --- a/articles/sum-of-absolute-differences-in-a-sorted-array.md +++ b/articles/sum-of-absolute-differences-in-a-sorted-array.md @@ -12,7 +12,7 @@ class Solution: for j in nums: sum += abs(i - j) res.append(sum) - + return res ``` @@ -29,7 +29,7 @@ public class Solution { } res[i] = sum; } - + return res; } } @@ -49,7 +49,7 @@ public: } res.push_back(sum); } - + return res; } }; @@ -72,7 +72,7 @@ class Solution { } res.push(sum); } - + return res; } } @@ -82,8 +82,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ for the output array. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ for the output array. --- @@ -98,20 +98,20 @@ class Solution: prefix_sum = [0] * n suffix_sum = [0] * n res = [0] * n - + prefix_sum[0] = nums[0] for i in range(1, n): prefix_sum[i] = prefix_sum[i - 1] + nums[i] - + suffix_sum[n - 1] = nums[n - 1] for i in range(n - 2, -1, -1): suffix_sum[i] = suffix_sum[i + 1] + nums[i] - + for i in range(n): left_sum = (i * nums[i]) - (prefix_sum[i - 1] if i > 0 else 0) right_sum = (suffix_sum[i + 1] if i < n - 1 else 0) - ((n - i - 1) * nums[i]) res[i] = left_sum + right_sum - + return res ``` @@ -195,8 +195,9 @@ class Solution { } for (let i = 0; i < n; i++) { - const leftSum = i > 0 ? (i * nums[i] - prefixSum[i - 1]) : 0; - const rightSum = i < n - 1 ? (suffixSum[i + 1] - (n - i - 1) * nums[i]) : 0; + const leftSum = i > 0 ? i * nums[i] - prefixSum[i - 1] : 0; + const rightSum = + i < n - 1 ? suffixSum[i + 1] - (n - i - 1) * nums[i] : 0; res[i] = leftSum + rightSum; } @@ -209,8 +210,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -223,18 +224,18 @@ class Solution: def getSumAbsoluteDifferences(self, nums: List[int]) -> List[int]: n = len(nums) res = [0] * n - + res[n - 1] = nums[n - 1] for i in range(n - 2, -1, -1): res[i] = res[i + 1] + nums[i] - + prefix_sum = 0 for i in range(n): left_sum = (i * nums[i]) - prefix_sum right_sum = (res[i + 1] if i < n - 1 else 0) - ((n - i - 1) * nums[i]) res[i] = left_sum + right_sum prefix_sum += nums[i] - + return res ``` @@ -305,7 +306,7 @@ class Solution { let prefixSum = 0; for (let i = 0; i < n; i++) { const leftSum = i * nums[i] - prefixSum; - const rightSum = i < n - 1 ? (res[i + 1] - (n - i - 1) * nums[i]) : 0; + const rightSum = i < n - 1 ? res[i + 1] - (n - i - 1) * nums[i] : 0; res[i] = leftSum + rightSum; prefixSum += nums[i]; } @@ -319,8 +320,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for the output array. +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for the output array. --- @@ -333,7 +334,7 @@ class Solution: def getSumAbsoluteDifferences(self, nums: List[int]) -> List[int]: n = len(nums) res = [0] * n - + total_sum = sum(nums) prefix_sum = 0 @@ -343,7 +344,7 @@ class Solution: right_sum = total_sum - (n - i - 1) * nums[i] res[i] = left_sum + right_sum prefix_sum += nums[i] - + return res ``` @@ -352,7 +353,7 @@ public class Solution { public int[] getSumAbsoluteDifferences(int[] nums) { int n = nums.length; int[] res = new int[n]; - + int totalSum = 0, prefixSum = 0; for (int num : nums) { totalSum += num; @@ -365,7 +366,7 @@ public class Solution { res[i] = leftSum + rightSum; prefixSum += nums[i]; } - + return res; } } @@ -377,7 +378,7 @@ public: vector getSumAbsoluteDifferences(vector& nums) { int n = nums.size(); vector res(n, 0); - + int totalSum = 0, prefixSum = 0; for (int& num : nums) { totalSum += num; @@ -390,7 +391,7 @@ public: res[i] = leftSum + rightSum; prefixSum += nums[i]; } - + return res; } }; @@ -405,7 +406,7 @@ class Solution { getSumAbsoluteDifferences(nums) { const n = nums.length; const res = Array(n).fill(0); - + let totalSum = nums.reduce((sum, num) => sum + num, 0); let prefixSum = 0; @@ -416,7 +417,7 @@ class Solution { res[i] = leftSum + rightSum; prefixSum += nums[i]; } - + return res; } } @@ -426,5 +427,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ for the output array. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for the output array. diff --git a/articles/sum-of-all-subset-xor-totals.md b/articles/sum-of-all-subset-xor-totals.md index b1f8dc9ae..a89444a0f 100644 --- a/articles/sum-of-all-subset-xor-totals.md +++ b/articles/sum-of-all-subset-xor-totals.md @@ -18,7 +18,7 @@ class Solution: subset.append(nums[j]) backtrack(j + 1, subset) subset.pop() - + backtrack(0, []) return res ``` @@ -98,12 +98,37 @@ class Solution { } ``` +```csharp +public class Solution { + private int res = 0; + + public int SubsetXORSum(int[] nums) { + Backtrack(0, new List(), nums); + return res; + } + + private void Backtrack(int i, List subset, int[] nums) { + int xorr = 0; + foreach (int num in subset) { + xorr ^= num; + } + res += xorr; + + for (int j = i; j < nums.Length; j++) { + subset.Add(nums[j]); + Backtrack(j + 1, subset, nums); + subset.RemoveAt(subset.Count - 1); + } + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -173,12 +198,27 @@ class Solution { } ``` +```csharp +public class Solution { + public int SubsetXORSum(int[] nums) { + return Dfs(0, 0, nums); + } + + private int Dfs(int i, int total, int[] nums) { + if (i == nums.Length) { + return total; + } + return Dfs(i + 1, total ^ nums[i], nums) + Dfs(i + 1, total, nums); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -198,7 +238,7 @@ class Solution: if mask & (1 << i): xorr ^= nums[i] res += xorr - + return res ``` @@ -217,7 +257,7 @@ public class Solution { } res += xorr; } - + return res; } } @@ -239,7 +279,7 @@ public: } res += xorr; } - + return res; } }; @@ -255,16 +295,37 @@ class Solution { const n = nums.length; let res = 0; - for (let mask = 0; mask < (1 << n); mask++) { + for (let mask = 0; mask < 1 << n; mask++) { let xorr = 0; for (let i = 0; i < n; i++) { - if ((mask & ( 1 << i)) !== 0) { + if ((mask & (1 << i)) !== 0) { xorr ^= nums[i]; } } res += xorr; } - + + return res; + } +} +``` + +```csharp +public class Solution { + public int SubsetXORSum(int[] nums) { + int n = nums.Length; + int res = 0; + + for (int mask = 0; mask < (1 << n); mask++) { + int xorr = 0; + for (int i = 0; i < n; i++) { + if ((mask & (1 << i)) != 0) { + xorr ^= nums[i]; + } + } + res += xorr; + } + return res; } } @@ -274,8 +335,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * 2 ^ n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(n * 2 ^ n)$ +- Space complexity: $O(1)$ extra space. --- @@ -333,9 +394,21 @@ class Solution { } ``` +```csharp +public class Solution { + public int SubsetXORSum(int[] nums) { + int res = 0; + foreach (int num in nums) { + res |= num; + } + return res << (nums.Length - 1); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/sum-of-subarray-minimums.md b/articles/sum-of-subarray-minimums.md new file mode 100644 index 000000000..cbe2dcd37 --- /dev/null +++ b/articles/sum-of-subarray-minimums.md @@ -0,0 +1,601 @@ +## 1. Brute FOrce + +::tabs-start + +```python +class Solution: + def sumSubarrayMins(self, arr: List[int]) -> int: + n, res = len(arr), 0 + MOD = 1000000007 + + for i in range(n): + minVal = arr[i] + for j in range(i, n): + minVal = min(minVal, arr[j]) + res = (res + minVal) % MOD + + return res +``` + +```java +public class Solution { + public int sumSubarrayMins(int[] arr) { + int n = arr.length, res = 0; + int MOD = 1000000007; + + for (int i = 0; i < n; i++) { + int minVal = arr[i]; + for (int j = i; j < n; j++) { + minVal = Math.min(minVal, arr[j]); + res = (res + minVal) % MOD; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int sumSubarrayMins(vector& arr) { + int n = arr.size(), res = 0; + const int MOD = 1000000007; + + for (int i = 0; i < n; i++) { + int minVal = arr[i]; + for (int j = i; j < n; j++) { + minVal = min(minVal, arr[j]); + res = (res + minVal) % MOD; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + sumSubarrayMins(arr) { + const n = arr.length; + let res = 0; + const MOD = 1000000007; + + for (let i = 0; i < n; i++) { + let minVal = arr[i]; + for (let j = i; j < n; j++) { + minVal = Math.min(minVal, arr[j]); + res = (res + minVal) % MOD; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ + +--- + +## 2. Monotonically Increasing Stack (Two Pass) + +::tabs-start + +```python +class Solution: + def sumSubarrayMins(self, arr: List[int]) -> int: + MOD = 10**9 + 7 + n = len(arr) + + # Compute previous smaller + prev_smaller = [-1] * n + stack = [] + for i in range(n): + while stack and arr[stack[-1]] > arr[i]: + stack.pop() + prev_smaller[i] = stack[-1] if stack else -1 + stack.append(i) + + # Compute next smaller + next_smaller = [n] * n + stack = [] + for i in range(n - 1, -1, -1): + while stack and arr[stack[-1]] >= arr[i]: + stack.pop() + next_smaller[i] = stack[-1] if stack else n + stack.append(i) + + res = 0 + for i in range(n): + left = i - prev_smaller[i] + right = next_smaller[i] - i + res = (res + arr[i] * left * right) % MOD + + return res +``` + +```java +public class Solution { + public int sumSubarrayMins(int[] arr) { + int MOD = 1000000007; + int n = arr.length; + + // Compute previous smaller + int[] prevSmaller = new int[n]; + Stack stack = new Stack<>(); + for (int i = 0; i < n; i++) { + while (!stack.isEmpty() && arr[stack.peek()] > arr[i]) { + stack.pop(); + } + prevSmaller[i] = stack.isEmpty() ? -1 : stack.peek(); + stack.push(i); + } + + // Compute next smaller + int[] nextSmaller = new int[n]; + stack = new Stack<>(); + for (int i = n - 1; i >= 0; i--) { + while (!stack.isEmpty() && arr[stack.peek()] >= arr[i]) { + stack.pop(); + } + nextSmaller[i] = stack.isEmpty() ? n : stack.peek(); + stack.push(i); + } + + // Calculate result + long res = 0; + for (int i = 0; i < n; i++) { + long left = i - prevSmaller[i]; + long right = nextSmaller[i] - i; + res = (res + arr[i] * left * right) % MOD; + } + + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int sumSubarrayMins(vector& arr) { + const int MOD = 1e9 + 7; + int n = arr.size(); + + // Compute previous smaller + vector prevSmaller(n, -1); + stack stack; + for (int i = 0; i < n; i++) { + while (!stack.empty() && arr[stack.top()] > arr[i]) { + stack.pop(); + } + prevSmaller[i] = stack.empty() ? -1 : stack.top(); + stack.push(i); + } + + // Compute next smaller + vector nextSmaller(n, n); + stack = {}; + for (int i = n - 1; i >= 0; i--) { + while (!stack.empty() && arr[stack.top()] >= arr[i]) { + stack.pop(); + } + nextSmaller[i] = stack.empty() ? n : stack.top(); + stack.push(i); + } + + // Calculate result + long long res = 0; + for (int i = 0; i < n; i++) { + long long left = i - prevSmaller[i]; + long long right = nextSmaller[i] - i; + res = (res + arr[i] * left * right) % MOD; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + sumSubarrayMins(arr) { + const MOD = 1e9 + 7; + const n = arr.length; + + // Compute previous smaller + const prevSmaller = new Array(n).fill(-1); + const stack = []; + for (let i = 0; i < n; i++) { + while (stack.length > 0 && arr[stack[stack.length - 1]] > arr[i]) { + stack.pop(); + } + prevSmaller[i] = stack.length > 0 ? stack[stack.length - 1] : -1; + stack.push(i); + } + + // Compute next smaller + const nextSmaller = new Array(n).fill(n); + stack.length = 0; + for (let i = n - 1; i >= 0; i--) { + while (stack.length > 0 && arr[stack[stack.length - 1]] >= arr[i]) { + stack.pop(); + } + nextSmaller[i] = stack.length > 0 ? stack[stack.length - 1] : n; + stack.push(i); + } + + // Calculate result + let res = 0; + for (let i = 0; i < n; i++) { + const left = i - prevSmaller[i]; + const right = nextSmaller[i] - i; + res = (res + arr[i] * left * right) % MOD; + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Monotonically Increasing Stack (One Pass) + +::tabs-start + +```python +class Solution: + def sumSubarrayMins(self, arr: List[int]) -> int: + MOD = 10 ** 9 + 7 + res = 0 + arr = [float("-inf")] + arr + [float("-inf")] + stack = [] # (index, num) + + for i, n in enumerate(arr): + while stack and n < stack[-1][1]: + j, m = stack.pop() + left = j - stack[-1][0] if stack else j + 1 + right = i - j + res = (res + m * left * right) % MOD + stack.append((i, n)) + + return res +``` + +```java +public class Solution { + public int sumSubarrayMins(int[] arr) { + int MOD = 1000000007; + int res = 0; + int[] newArr = new int[arr.length + 2]; + newArr[0] = Integer.MIN_VALUE; + newArr[newArr.length - 1] = Integer.MIN_VALUE; + System.arraycopy(arr, 0, newArr, 1, arr.length); + + Stack stack = new Stack<>(); + + for (int i = 0; i < newArr.length; i++) { + while (!stack.isEmpty() && newArr[i] < stack.peek()[1]) { + int[] top = stack.pop(); + int j = top[0], m = top[1]; + int left = stack.isEmpty() ? j + 1 : j - stack.peek()[0]; + int right = i - j; + res = (int) ((res + (long) m * left * right) % MOD); + } + stack.push(new int[]{i, newArr[i]}); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int sumSubarrayMins(vector& arr) { + const int MOD = 1e9 + 7; + int res = 0; + vector newArr(arr.size() + 2, INT_MIN); + copy(arr.begin(), arr.end(), newArr.begin() + 1); + + stack> stack; + + for (int i = 0; i < newArr.size(); i++) { + while (!stack.empty() && newArr[i] < stack.top().second) { + auto [j, m] = stack.top(); + stack.pop(); + int left = stack.empty() ? j + 1 : j - stack.top().first; + int right = i - j; + res = (res + (long long) m * left * right % MOD) % MOD; + } + stack.emplace(i, newArr[i]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + sumSubarrayMins(arr) { + const MOD = 1e9 + 7; + let res = 0; + arr = [-Infinity, ...arr, -Infinity]; + let stack = []; + + for (let i = 0; i < arr.length; i++) { + while (stack.length > 0 && arr[i] < stack[stack.length - 1][1]) { + let [j, m] = stack.pop(); + let left = + stack.length > 0 ? j - stack[stack.length - 1][0] : j + 1; + let right = i - j; + res = (res + m * left * right) % MOD; + } + stack.push([i, arr[i]]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Monotonically Increasing Stack (Optimal) + +::tabs-start + +```python +class Solution: + def sumSubarrayMins(self, arr: List[int]) -> int: + MOD = 10**9 + 7 + stack = [] + res, n = 0, len(arr) + + for i in range(n + 1): + while stack and (i == n or arr[i] < arr[stack[-1]]): + j = stack.pop() + left = j - (stack[-1] if stack else -1) + right = i - j + res = (res + arr[j] * left * right) % MOD + stack.append(i) + + return res +``` + +```java +public class Solution { + public int sumSubarrayMins(int[] arr) { + int MOD = 1000000007; + int n = arr.length; + Stack stack = new Stack<>(); + long res = 0; + + for (int i = 0; i <= n; i++) { + while (!stack.isEmpty() && (i == n || arr[i] < arr[stack.peek()])) { + int j = stack.pop(); + int left = j - (stack.isEmpty() ? -1 : stack.peek()); + int right = i - j; + res = (res + (long) arr[j] * left * right) % MOD; + } + stack.push(i); + } + + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int sumSubarrayMins(vector& arr) { + const int MOD = 1e9 + 7; + int n = arr.size(); + stack stack; + long long res = 0; + + for (int i = 0; i <= n; i++) { + while (!stack.empty() && (i == n || arr[i] < arr[stack.top()])) { + int j = stack.top(); + stack.pop(); + int left = j - (stack.empty() ? -1 : stack.top()); + int right = i - j; + res = (res + (long long) arr[j] * left * right) % MOD; + } + stack.push(i); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + sumSubarrayMins(arr) { + const MOD = 1e9 + 7; + const n = arr.length; + const stack = []; + let res = 0; + + for (let i = 0; i <= n; i++) { + while ( + stack.length > 0 && + (i === n || arr[i] < arr[stack[stack.length - 1]]) + ) { + const j = stack.pop(); + const left = + j - (stack.length > 0 ? stack[stack.length - 1] : -1); + const right = i - j; + res = (res + arr[j] * left * right) % MOD; + } + stack.push(i); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 5. Dynamic Programming + Stack + +::tabs-start + +```python +class Solution: + def sumSubarrayMins(self, arr: List[int]) -> int: + MOD = 10**9 + 7 + n = len(arr) + dp = [0] * n + stack, res = [], 0 + + for i in range(n): + while stack and arr[stack[-1]] > arr[i]: + stack.pop() + + j = stack[-1] if stack else -1 + dp[i] = (dp[j] if j != -1 else 0) + arr[i] * (i - j) + dp[i] %= MOD + res = (res + dp[i]) % MOD + stack.append(i) + + return res +``` + +```java +public class Solution { + public int sumSubarrayMins(int[] arr) { + int MOD = 1000000007; + int n = arr.length; + int[] dp = new int[n]; + Stack stack = new Stack<>(); + long res = 0; + + for (int i = 0; i < n; i++) { + while (!stack.isEmpty() && arr[stack.peek()] > arr[i]) { + stack.pop(); + } + + int j = stack.isEmpty() ? -1 : stack.peek(); + dp[i] = ((j != -1 ? dp[j] : 0) + arr[i] * (i - j)) % MOD; + res = (res + dp[i]) % MOD; + stack.push(i); + } + + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int sumSubarrayMins(vector& arr) { + const int MOD = 1e9 + 7; + int n = arr.size(); + vector dp(n, 0); + stack stack; + long long res = 0; + + for (int i = 0; i < n; i++) { + while (!stack.empty() && arr[stack.top()] > arr[i]) { + stack.pop(); + } + + int j = stack.empty() ? -1 : stack.top(); + dp[i] = ((j != -1 ? dp[j] : 0) + arr[i] * (i - j)) % MOD; + res = (res + dp[i]) % MOD; + stack.push(i); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} arr + * @return {number} + */ + sumSubarrayMins(arr) { + const MOD = 1e9 + 7; + const n = arr.length; + const dp = new Array(n).fill(0); + const stack = []; + let res = 0; + + for (let i = 0; i < n; i++) { + while (stack.length > 0 && arr[stack[stack.length - 1]] > arr[i]) { + stack.pop(); + } + + const j = stack.length > 0 ? stack[stack.length - 1] : -1; + dp[i] = ((j !== -1 ? dp[j] : 0) + arr[i] * (i - j)) % MOD; + res = (res + dp[i]) % MOD; + stack.push(i); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/sum-of-two-integers.md b/articles/sum-of-two-integers.md index 4fffcb35f..a22bdc3fc 100644 --- a/articles/sum-of-two-integers.md +++ b/articles/sum-of-two-integers.md @@ -11,7 +11,7 @@ class Solution: ```java public class Solution { public int getSum(int a, int b) { - return a + b; + return a + b; } } ``` @@ -60,12 +60,20 @@ class Solution { } ``` +```swift +class Solution { + func getSum(_ a: Int, _ b: Int) -> Int { + return a + b + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ --- @@ -90,7 +98,7 @@ class Solution: if res > 0x7FFFFFFF: res = ~(res ^ mask) - + return res ``` @@ -112,7 +120,7 @@ public class Solution { if (res > 0x7FFFFFFF) { res = ~(res ^ mask); } - + return res; } } @@ -137,7 +145,7 @@ public: if (res > 0x7FFFFFFF) { res = ~(res ^ mask); } - + return res; } }; @@ -151,22 +159,24 @@ class Solution { * @return {number} */ getSum(a, b) { - let carry = 0, res = 0, mask = 0xFFFFFFFF; + let carry = 0, + res = 0, + mask = 0xffffffff; for (let i = 0; i < 32; i++) { let a_bit = (a >> i) & 1; let b_bit = (b >> i) & 1; let cur_bit = a_bit ^ b_bit ^ carry; - carry = (a_bit + b_bit + carry) >= 2 ? 1 : 0; + carry = a_bit + b_bit + carry >= 2 ? 1 : 0; if (cur_bit) { - res |= (1 << i); + res |= 1 << i; } } - if (res > 0x7FFFFFFF) { + if (res > 0x7fffffff) { res = ~(res ^ mask); } - + return res; } } @@ -190,7 +200,7 @@ public class Solution { if (res > Int32.MaxValue) { res = ~(res ^ mask); } - + return res; } } @@ -250,12 +260,38 @@ class Solution { } ``` +```swift +class Solution { + func getSum(_ a: Int, _ b: Int) -> Int { + var carry = 0 + var res = 0 + let mask = 0xFFFFFFFF + + for i in 0..<32 { + let aBit = (a >> i) & 1 + let bBit = (b >> i) & 1 + let curBit = aBit ^ bBit ^ carry + carry = (aBit + bBit + carry) >= 2 ? 1 : 0 + if curBit == 1 { + res |= (1 << i) + } + } + + if res > 0x7FFFFFFF { + res = ~(res ^ mask) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ --- @@ -379,9 +415,28 @@ class Solution { } ``` +```swift +class Solution { + func getSum(_ a: Int, _ b: Int) -> Int { + let mask = 0xFFFFFFFF + let maxInt = 0x7FFFFFFF + var a = a + var b = b + + while b != 0 { + let carry = (a & b) << 1 + a = (a ^ b) & mask + b = carry & mask + } + + return a <= maxInt ? a : ~(a ^ mask) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ diff --git a/articles/sum-root-to-leaf-numbers.md b/articles/sum-root-to-leaf-numbers.md new file mode 100644 index 000000000..445fc6317 --- /dev/null +++ b/articles/sum-root-to-leaf-numbers.md @@ -0,0 +1,654 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def sumNumbers(self, root: TreeNode) -> int: + def dfs(cur, num): + if not cur: + return 0 + + num = num * 10 + cur.val + if not cur.left and not cur.right: + return num + return dfs(cur.left, num) + dfs(cur.right, num) + + return dfs(root, 0) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int sumNumbers(TreeNode root) { + return dfs(root, 0); + } + + private int dfs(TreeNode cur, int num) { + if (cur == null) return 0; + + num = num * 10 + cur.val; + if (cur.left == null && cur.right == null) return num; + + return dfs(cur.left, num) + dfs(cur.right, num); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int sumNumbers(TreeNode* root) { + return dfs(root, 0); + } + +private: + int dfs(TreeNode* cur, int num) { + if (!cur) return 0; + + num = num * 10 + cur->val; + if (!cur->left && !cur->right) return num; + + return dfs(cur->left, num) + dfs(cur->right, num); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + sumNumbers(root) { + const dfs = (cur, num) => { + if (!cur) return 0; + + num = num * 10 + cur.val; + if (!cur.left && !cur.right) return num; + + return dfs(cur.left, num) + dfs(cur.right, num); + }; + + return dfs(root, 0); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(h)$ for recursion stack. + +> Where $n$ is the number of nodes and $h$ is the height of the given tree. + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def sumNumbers(self, root: TreeNode) -> int: + res = 0 + q = deque([(root, 0)]) + while q: + cur, num = q.popleft() + num = num * 10 + cur.val + if not cur.left and not cur.right: + res += num + continue + + if cur.left: + q.append((cur.left, num)) + if cur.right: + q.append((cur.right, num)) + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int sumNumbers(TreeNode root) { + int res = 0; + Queue> q = new LinkedList<>(); + q.offer(new Pair<>(root, 0)); + while (!q.isEmpty()) { + Pair p = q.poll(); + TreeNode cur = p.getKey(); + int num = p.getValue() * 10 + cur.val; + if (cur.left == null && cur.right == null) { + res += num; + continue; + } + + if (cur.left != null) q.offer(new Pair<>(cur.left, num)); + if (cur.right != null) q.offer(new Pair<>(cur.right, num)); + } + + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int sumNumbers(TreeNode* root) { + int res = 0; + queue> q; + q.push({root, 0}); + while (!q.empty()) { + auto [cur, num] = q.front();q.pop(); + num = num * 10 + cur->val; + if (!cur->left && !cur->right) { + res += num; + continue; + } + + if (cur->left) q.push({cur->left, num}); + if (cur->right) q.push({cur->right, num}); + } + + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + sumNumbers(root) { + let res = 0; + const q = new Queue([[root, 0]]); + while (!q.isEmpty()) { + const [cur, num] = q.pop(); + const newNum = num * 10 + cur.val; + if (!cur.left && !cur.right) { + res += newNum; + continue; + } + + if (cur.left) q.push([cur.left, newNum]); + if (cur.right) q.push([cur.right, newNum]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def sumNumbers(self, root: Optional[TreeNode]) -> int: + res = 0 + stack = [] + cur, num = root, 0 + + while cur or stack: + if cur: + num = num * 10 + cur.val + if not cur.left and not cur.right: + res += num + + stack.append((cur.right, num)) + cur = cur.left + else: + cur, num = stack.pop() + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int sumNumbers(TreeNode root) { + int res = 0, num = 0; + Stack> stack = new Stack<>(); + TreeNode cur = root; + + while (cur != null || !stack.isEmpty()) { + if (cur != null) { + num = num * 10 + cur.val; + if (cur.left == null && cur.right == null) + res += num; + + stack.push(new Pair<>(cur.right, num)); + cur = cur.left; + } else { + Pair p = stack.pop(); + cur = p.getKey(); + num = p.getValue(); + } + } + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int sumNumbers(TreeNode* root) { + int res = 0; + stack> st; + TreeNode* cur = root; + int num = 0; + + while (cur || !st.empty()) { + if (cur) { + num = num * 10 + cur->val; + if (!cur->left && !cur->right) + res += num; + + st.push({cur->right, num}); + cur = cur->left; + } else { + cur = st.top().first; + num = st.top().second; + st.pop(); + } + } + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + sumNumbers(root) { + let res = 0, + num = 0; + let stack = []; + let cur = root; + + while (cur || stack.length) { + if (cur) { + num = num * 10 + cur.val; + if (!cur.left && !cur.right) res += num; + + stack.push([cur.right, num]); + cur = cur.left; + } else { + [cur, num] = stack.pop(); + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(h)$ + +> Where $n$ is the number of nodes and $h$ is the height of the given tree. + +--- + +## 4. Morris Travrsal + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def sumNumbers(self, root: Optional[TreeNode]) -> int: + res = 0 + cur = root + num = 0 + power = [1] * 10 + for i in range(1, 10): + power[i] *= power[i - 1] * 10 + + while cur: + if not cur.left: + num = num * 10 + cur.val + if not cur.right: + res += num + cur = cur.right + else: + prev = cur.left + steps = 1 + while prev.right and prev.right != cur: + prev = prev.right + steps += 1 + + if not prev.right: + prev.right = cur + num = num * 10 + cur.val + cur = cur.left + else: + prev.right = None + if not prev.left: + res += num + num //= power[steps] + cur = cur.right + + return res +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public int sumNumbers(TreeNode root) { + int res = 0, num = 0; + int[] power = new int[10]; + power[0] = 1; + for (int i = 1; i < 10; i++) { + power[i] = power[i - 1] * 10; + } + + TreeNode cur = root; + while (cur != null) { + if (cur.left == null) { + num = num * 10 + cur.val; + if (cur.right == null) res += num; + cur = cur.right; + } else { + TreeNode prev = cur.left; + int steps = 1; + while (prev.right != null && prev.right != cur) { + prev = prev.right; + steps++; + } + + if (prev.right == null) { + prev.right = cur; + num = num * 10 + cur.val; + cur = cur.left; + } else { + prev.right = null; + if (prev.left == null) res += num; + num /= power[steps]; + cur = cur.right; + } + } + } + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + int sumNumbers(TreeNode* root) { + int res = 0, num = 0; + int power[10] = {1}; + for (int i = 1; i < 10; i++) { + power[i] = power[i - 1] * 10; + } + + TreeNode* cur = root; + while (cur) { + if (!cur->left) { + num = num * 10 + cur->val; + if (!cur->right) res += num; + cur = cur->right; + } else { + TreeNode* prev = cur->left; + int steps = 1; + while (prev->right && prev->right != cur) { + prev = prev->right; + steps++; + } + + if (!prev->right) { + prev->right = cur; + num = num * 10 + cur->val; + cur = cur->left; + } else { + prev->right = nullptr; + if (!prev->left) res += num; + num /= power[steps]; + cur = cur->right; + } + } + } + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {number} + */ + sumNumbers(root) { + let res = 0, + num = 0; + let power = Array(10).fill(1); + for (let i = 1; i < 10; i++) { + power[i] = power[i - 1] * 10; + } + + let cur = root; + while (cur) { + if (!cur.left) { + num = num * 10 + cur.val; + if (!cur.right) res += num; + cur = cur.right; + } else { + let prev = cur.left, + steps = 1; + while (prev.right && prev.right !== cur) { + prev = prev.right; + steps++; + } + + if (!prev.right) { + prev.right = cur; + num = num * 10 + cur.val; + cur = cur.left; + } else { + prev.right = null; + if (!prev.left) res += num; + num = Math.floor(num / power[steps]); + cur = cur.right; + } + } + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/surrounded-regions.md b/articles/surrounded-regions.md index f1009a0bc..915c3563f 100644 --- a/articles/surrounded-regions.md +++ b/articles/surrounded-regions.md @@ -8,7 +8,7 @@ class Solution: ROWS, COLS = len(board), len(board[0]) def capture(r, c): - if (r < 0 or c < 0 or r == ROWS or + if (r < 0 or c < 0 or r == ROWS or c == COLS or board[r][c] != "O" ): return @@ -23,7 +23,7 @@ class Solution: capture(r, 0) if board[r][COLS - 1] == "O": capture(r, COLS - 1) - + for c in range(COLS): if board[0][c] == "O": capture(0, c) @@ -76,7 +76,7 @@ public class Solution { } private void capture(char[][] board, int r, int c) { - if (r < 0 || c < 0 || r >= ROWS || + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || board[r][c] != 'O') { return; } @@ -129,7 +129,7 @@ public: private: void capture(vector>& board, int r, int c) { - if (r < 0 || c < 0 || r >= ROWS || + if (r < 0 || c < 0 || r >= ROWS || c >= COLS || board[r][c] != 'O') { return; } @@ -149,11 +149,17 @@ class Solution { * @return {void} Do not return anything, modify board in-place instead. */ solve(board) { - let ROWS = board.length, COLS = board[0].length; + let ROWS = board.length, + COLS = board[0].length; const capture = (r, c) => { - if (r < 0 || c < 0 || r == ROWS || - c == COLS || board[r][c] !== 'O') { + if ( + r < 0 || + c < 0 || + r == ROWS || + c == COLS || + board[r][c] !== 'O' + ) { return; } board[r][c] = 'T'; @@ -161,7 +167,7 @@ class Solution { capture(r - 1, c); capture(r, c + 1); capture(r, c - 1); - } + }; for (let r = 0; r < ROWS; r++) { if (board[r][0] === 'O') capture(r, 0); @@ -221,7 +227,7 @@ public class Solution { } private void Capture(char[][] board, int r, int c) { - if (r < 0 || c < 0 || r == ROWS || + if (r < 0 || c < 0 || r == ROWS || c == COLS || board[r][c] != 'O') { return; } @@ -240,7 +246,7 @@ func solve(board [][]byte) { var capture func(r, c int) capture = func(r, c int) { - if r < 0 || c < 0 || r == rows || + if r < 0 || c < 0 || r == rows || c == cols || board[r][c] != 'O' { return } @@ -288,7 +294,7 @@ class Solution { val cols = board[0].size fun capture(r: Int, c: Int) { - if (r < 0 || c < 0 || r == rows || + if (r < 0 || c < 0 || r == rows || c == cols || board[r][c] != 'O') { return } @@ -330,12 +336,60 @@ class Solution { } ``` +```swift +class Solution { + func solve(_ board: inout [[Character]]) { + let ROWS = board.count + let COLS = board[0].count + + func capture(_ r: Int, _ c: Int) { + if r < 0 || c < 0 || r == ROWS || c == COLS || board[r][c] != "O" { + return + } + board[r][c] = "T" + capture(r + 1, c) + capture(r - 1, c) + capture(r, c + 1) + capture(r, c - 1) + } + + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns of the $board$. @@ -355,8 +409,8 @@ class Solution: q = deque() for r in range(ROWS): for c in range(COLS): - if (r == 0 or r == ROWS - 1 or - c == 0 or c == COLS - 1 and + if (r == 0 or r == ROWS - 1 or + c == 0 or c == COLS - 1 and board[r][c] == "O" ): q.append((r, c)) @@ -368,7 +422,7 @@ class Solution: nr, nc = r + dr, c + dc if 0 <= nr < ROWS and 0 <= nc < COLS: q.append((nr, nc)) - + capture() for r in range(ROWS): for c in range(COLS): @@ -406,8 +460,8 @@ public class Solution { Queue q = new LinkedList<>(); for (int r = 0; r < ROWS; r++) { for (int c = 0; c < COLS; c++) { - if (r == 0 || r == ROWS - 1 || - c == 0 || c == COLS - 1 && + if (r == 0 || r == ROWS - 1 || + c == 0 || c == COLS - 1 && board[r][c] == 'O') { q.offer(new int[]{r, c}); } @@ -433,7 +487,7 @@ public class Solution { ```cpp class Solution { int ROWS, COLS; - vector> directions = {{1, 0}, {-1, 0}, + vector> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; public: @@ -459,8 +513,8 @@ private: queue> q; for (int r = 0; r < ROWS; r++) { for (int c = 0; c < COLS; c++) { - if (r == 0 || r == ROWS - 1 || - c == 0 || c == COLS - 1 && + if (r == 0 || r == ROWS - 1 || + c == 0 || c == COLS - 1 && board[r][c] == 'O') { q.push({r, c}); } @@ -472,9 +526,9 @@ private: if (board[r][c] == 'O') { board[r][c] = 'T'; for (auto& direction : directions) { - int nr = r + direction.first; + int nr = r + direction.first; int nc = c + direction.second; - if (nr >= 0 && nr < ROWS && + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS) { q.push({nr, nc}); } @@ -492,34 +546,43 @@ class Solution { * @return {void} Do not return anything, modify board in-place instead. */ solve(board) { - let ROWS = board.length, COLS = board[0].length; - let directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; - + let ROWS = board.length, + COLS = board[0].length; + let directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; + const capture = () => { - let q = []; + let q = new Queue(); for (let r = 0; r < ROWS; r++) { for (let c = 0; c < COLS; c++) { - if (r === 0 || r === ROWS - 1 || - c === 0 || c === COLS - 1 && - board[r][c] === 'O') { + if ( + r === 0 || + r === ROWS - 1 || + c === 0 || + (c === COLS - 1 && board[r][c] === 'O') + ) { q.push([r, c]); } } } - while (q.length) { - let [r, c] = q.shift(); + while (!q.isEmpty()) { + let [r, c] = q.pop(); if (board[r][c] === 'O') { board[r][c] = 'T'; for (let [dr, dc] of directions) { - let nr = r + dr, nc = c + dc; - if (nr >= 0 && nr < ROWS && - nc >= 0 && nc < COLS) { + let nr = r + dr, + nc = c + dc; + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS) { q.push([nr, nc]); } } } } - } + }; capture(); for (let r = 0; r < ROWS; r++) { @@ -535,9 +598,9 @@ class Solution { ```csharp public class Solution { private int ROWS, COLS; - private int[][] directions = new int[][] { - new int[] { 1, 0 }, new int[] { -1, 0 }, - new int[] { 0, 1 }, new int[] { 0, -1 } + private int[][] directions = new int[][] { + new int[] { 1, 0 }, new int[] { -1, 0 }, + new int[] { 0, 1 }, new int[] { 0, -1 } }; public void Solve(char[][] board) { @@ -561,8 +624,8 @@ public class Solution { Queue q = new Queue(); for (int r = 0; r < ROWS; r++) { for (int c = 0; c < COLS; c++) { - if (r == 0 || r == ROWS - 1 || - c == 0 || c == COLS - 1 && + if (r == 0 || r == ROWS - 1 || + c == 0 || c == COLS - 1 && board[r][c] == 'O') { q.Enqueue(new int[] { r, c }); } @@ -576,7 +639,7 @@ public class Solution { foreach (var direction in directions) { int nr = r + direction[0]; int nc = c + direction[1]; - if (nr >= 0 && nr < ROWS && + if (nr >= 0 && nr < ROWS && nc >= 0 && nc < COLS) { q.Enqueue(new int[] { nr, nc }); } @@ -638,9 +701,9 @@ class Solution { fun solve(board: Array) { val rows = board.size val cols = board[0].size - val directions = arrayOf(intArrayOf(1, 0), - intArrayOf(-1, 0), - intArrayOf(0, 1), + val directions = arrayOf(intArrayOf(1, 0), + intArrayOf(-1, 0), + intArrayOf(0, 1), intArrayOf(0, -1)) fun capture() { @@ -684,12 +747,59 @@ class Solution { } ``` +```swift +class Solution { + func solve(_ board: inout [[Character]]) { + let ROWS = board.count + let COLS = board[0].count + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + + func capture() { + var queue = Deque<(Int, Int)>() + for r in 0..= 0, nr < ROWS, nc >= 0, nc < COLS { + queue.append((nr, nc)) + } + } + } + } + } + + capture() + + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns of the $board$. @@ -722,7 +832,7 @@ class DSU: self.Size[pv] += self.Size[pu] self.Parent[pu] = pv return True - + def connected(self, u, v): return self.find(u) == self.find(v) @@ -736,7 +846,7 @@ class Solution: for c in range(COLS): if board[r][c] != "O": continue - if (r == 0 or c == 0 or + if (r == 0 or c == 0 or r == (ROWS - 1) or c == (COLS - 1) ): dsu.union(ROWS * COLS, r * COLS + c) @@ -753,7 +863,7 @@ class Solution: ``` ```java -public class DSU { +class DSU { int[] Parent, Size; public DSU(int n) { @@ -799,7 +909,7 @@ public class Solution { for (int r = 0; r < ROWS; r++) { for (int c = 0; c < COLS; c++) { if (board[r][c] != 'O') continue; - if (r == 0 || c == 0 || + if (r == 0 || c == 0 || r == ROWS - 1 || c == COLS - 1) { dsu.union(ROWS * COLS, r * COLS + c); } else { @@ -868,13 +978,13 @@ public: void solve(vector>& board) { int ROWS = board.size(), COLS = board[0].size(); DSU dsu(ROWS * COLS + 1); - vector> directions = {{1, 0}, {-1, 0}, + vector> directions = {{1, 0}, {-1, 0}, {0, 1}, {0, -1}}; for (int r = 0; r < ROWS; r++) { for (int c = 0; c < COLS; c++) { if (board[r][c] != 'O') continue; - if (r == 0 || c == 0 || + if (r == 0 || c == 0 || r == ROWS - 1 || c == COLS - 1) { dsu.unionNodes(ROWS * COLS, r * COLS + c); } else { @@ -952,19 +1062,25 @@ class Solution { * @return {void} Do not return anything, modify board in-place instead. */ solve(board) { - const ROWS = board.length, COLS = board[0].length; + const ROWS = board.length, + COLS = board[0].length; const dsu = new DSU(ROWS * COLS + 1); - const directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; + const directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; for (let r = 0; r < ROWS; r++) { for (let c = 0; c < COLS; c++) { if (board[r][c] !== 'O') continue; - if (r === 0 || c === 0 || - r === ROWS - 1 || c === COLS - 1) { + if (r === 0 || c === 0 || r === ROWS - 1 || c === COLS - 1) { dsu.union(ROWS * COLS, r * COLS + c); } else { for (let [dx, dy] of directions) { - const nr = r + dx, nc = c + dy; + const nr = r + dx, + nc = c + dy; if (board[nr][nc] === 'O') { dsu.union(r * COLS + c, nr * COLS + nc); } @@ -1026,15 +1142,15 @@ public class Solution { public void Solve(char[][] board) { int ROWS = board.Length, COLS = board[0].Length; DSU dsu = new DSU(ROWS * COLS + 1); - int[][] directions = new int[][] { - new int[] { 1, 0 }, new int[] { -1, 0 }, - new int[] { 0, 1 }, new int[] { 0, -1 } + int[][] directions = new int[][] { + new int[] { 1, 0 }, new int[] { -1, 0 }, + new int[] { 0, 1 }, new int[] { 0, -1 } }; for (int r = 0; r < ROWS; r++) { for (int c = 0; c < COLS; c++) { if (board[r][c] != 'O') continue; - if (r == 0 || c == 0 || + if (r == 0 || c == 0 || r == ROWS - 1 || c == COLS - 1) { dsu.Union(ROWS * COLS, r * COLS + c); } else { @@ -1119,7 +1235,7 @@ func solve(board [][]byte) { } else { for _, dir := range directions { nr, nc := r+dir[0], c+dir[1] - if nr >= 0 && nr < rows && nc >= 0 && + if nr >= 0 && nr < rows && nc >= 0 && nc < cols && board[nr][nc] == 'O' { dsu.Union(r*cols+c, nr*cols+nc) } @@ -1173,9 +1289,9 @@ class Solution { fun solve(board: Array) { val rows = board.size val cols = board[0].size - val directions = arrayOf(intArrayOf(1, 0), - intArrayOf(-1, 0), - intArrayOf(0, 1), + val directions = arrayOf(intArrayOf(1, 0), + intArrayOf(-1, 0), + intArrayOf(0, 1), intArrayOf(0, -1)) val dsu = DSU(rows * cols) @@ -1188,7 +1304,7 @@ class Solution { for (dir in directions) { val nr = r + dir[0] val nc = c + dir[1] - if (nr in 0 until rows && + if (nr in 0 until rows && nc in 0 until cols && board[nr][nc] == 'O') { dsu.union(r * cols + c, nr * cols + nc) } @@ -1208,11 +1324,84 @@ class Solution { } ``` +```swift +class DSU { + private var parent: [Int] + private var size: [Int] + + init(_ n: Int) { + parent = Array(0...n) + size = Array(repeating: 1, count: n + 1) + } + + func find(_ node: Int) -> Int { + if parent[node] != node { + parent[node] = find(parent[node]) + } + return parent[node] + } + + func union(_ u: Int, _ v: Int) { + let pu = find(u) + let pv = find(v) + if pu == pv { return } + if size[pu] >= size[pv] { + size[pu] += size[pv] + parent[pv] = pu + } else { + size[pv] += size[pu] + parent[pu] = pv + } + } + + func connected(_ u: Int, _ v: Int) -> Bool { + return find(u) == find(v) + } +} + +class Solution { + func solve(_ board: inout [[Character]]) { + let ROWS = board.count + let COLS = board[0].count + let directions = [(1, 0), (-1, 0), (0, 1), (0, -1)] + let dsu = DSU(ROWS * COLS + 1) + let N = ROWS * COLS + + for r in 0..= 0, nr < ROWS, nc >= 0, nc < COLS, board[nr][nc] == "O" { + dsu.union(r * COLS + c, nr * COLS + nc) + } + } + } + } + } + + for r in 0.. Where $m$ is the number of rows and $n$ is the number of columns of the $board$. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns of the $board$. diff --git a/articles/swap-nodes-in-pairs.md b/articles/swap-nodes-in-pairs.md new file mode 100644 index 000000000..384141389 --- /dev/null +++ b/articles/swap-nodes-in-pairs.md @@ -0,0 +1,420 @@ +## 1. Convert TO Array + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]: + if not head: + return None + arr = [] + cur = head + + while cur: + arr.append(cur) + cur = cur.next + + for i in range(0, len(arr) - 1, 2): + arr[i], arr[i + 1] = arr[i + 1], arr[i] + + for i in range(len(arr) - 1): + arr[i].next = arr[i + 1] + + arr[-1].next = None + return arr[0] +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapPairs(ListNode head) { + if (head == null) return null; + + List arr = new ArrayList<>(); + ListNode cur = head; + + while (cur != null) { + arr.add(cur); + cur = cur.next; + } + + for (int i = 0; i < arr.size() - 1; i += 2) { + ListNode temp = arr.get(i); + arr.set(i, arr.get(i + 1)); + arr.set(i + 1, temp); + } + + for (int i = 0; i < arr.size() - 1; i++) { + arr.get(i).next = arr.get(i + 1); + } + + arr.get(arr.size() - 1).next = null; + return arr.get(0); + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapPairs(ListNode* head) { + if (!head) return nullptr; + + vector arr; + ListNode* cur = head; + + while (cur) { + arr.push_back(cur); + cur = cur->next; + } + + for (size_t i = 0; i + 1 < arr.size(); i += 2) { + swap(arr[i], arr[i + 1]); + } + + for (size_t i = 0; i + 1 < arr.size(); i++) { + arr[i]->next = arr[i + 1]; + } + + arr.back()->next = nullptr; + return arr[0]; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + swapPairs(head) { + if (!head) return null; + + let arr = []; + let cur = head; + + while (cur) { + arr.push(cur); + cur = cur.next; + } + + for (let i = 0; i + 1 < arr.length; i += 2) { + [arr[i], arr[i + 1]] = [arr[i + 1], arr[i]]; + } + + for (let i = 0; i + 1 < arr.length; i++) { + arr[i].next = arr[i + 1]; + } + + arr[arr.length - 1].next = null; + return arr[0]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Recursion + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]: + if not head or not head.next: + return head + + cur = head + nxt = head.next + cur.next = self.swapPairs(nxt.next) + nxt.next = cur + return nxt +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapPairs(ListNode head) { + if (head == null || head.next == null) { + return head; + } + + ListNode cur = head; + ListNode nxt = head.next; + cur.next = swapPairs(nxt.next); + nxt.next = cur; + + return nxt; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapPairs(ListNode* head) { + if (!head || !head->next) { + return head; + } + + ListNode* cur = head; + ListNode* nxt = head->next; + cur->next = swapPairs(nxt->next); + nxt->next = cur; + + return nxt; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + swapPairs(head) { + if (!head || !head.next) { + return head; + } + + let cur = head; + let nxt = head.next; + cur.next = this.swapPairs(nxt.next); + nxt.next = cur; + + return nxt; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Iteration + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapPairs(self, head: Optional[ListNode]) -> Optional[ListNode]: + dummy = ListNode(0, head) + prev, curr = dummy, head + + while curr and curr.next: + nxtPair = curr.next.next + second = curr.next + + # Reverse this pair + second.next = curr + curr.next = nxtPair + prev.next = second + + # Update pointers + prev = curr + curr = nxtPair + + return dummy.next +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapPairs(ListNode head) { + ListNode dummy = new ListNode(0, head); + ListNode prev = dummy, curr = head; + + while (curr != null && curr.next != null) { + ListNode nxtPair = curr.next.next; + ListNode second = curr.next; + + // Reverse this pair + second.next = curr; + curr.next = nxtPair; + prev.next = second; + + // Update pointers + prev = curr; + curr = nxtPair; + } + + return dummy.next; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapPairs(ListNode* head) { + ListNode dummy(0, head); + ListNode* prev = &dummy, *curr = head; + + while (curr && curr->next) { + ListNode* nxtPair = curr->next->next; + ListNode* second = curr->next; + + // Reverse this pair + second->next = curr; + curr->next = nxtPair; + prev->next = second; + + // Update pointers + prev = curr; + curr = nxtPair; + } + + return dummy.next; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @return {ListNode} + */ + swapPairs(head) { + let dummy = new ListNode(0, head); + let prev = dummy, + curr = head; + + while (curr && curr.next) { + let nxtPair = curr.next.next; + let second = curr.next; + + // Reverse this pair + second.next = curr; + curr.next = nxtPair; + prev.next = second; + + // Update pointers + prev = curr; + curr = nxtPair; + } + + return dummy.next; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/swapping-nodes-in-a-linked-list.md b/articles/swapping-nodes-in-a-linked-list.md new file mode 100644 index 000000000..6e80c42f1 --- /dev/null +++ b/articles/swapping-nodes-in-a-linked-list.md @@ -0,0 +1,790 @@ +## 1. Convert To Array + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapNodes(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: + arr = [] + cur = head + while cur: + arr.append(cur.val) + cur = cur.next + + n = len(arr) + arr[k - 1], arr[n - k] = arr[n - k], arr[k - 1] + + cur, i = head, 0 + while cur: + cur.val = arr[i] + cur = cur.next + i += 1 + + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapNodes(ListNode head, int k) { + List arr = new ArrayList<>(); + ListNode cur = head; + + while (cur != null) { + arr.add(cur.val); + cur = cur.next; + } + + int n = arr.size(); + int temp = arr.get(k - 1); + arr.set(k - 1, arr.get(n - k)); + arr.set(n - k, temp); + + cur = head; + int i = 0; + while (cur != null) { + cur.val = arr.get(i); + cur = cur.next; + i++; + } + + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapNodes(ListNode* head, int k) { + vector arr; + ListNode* cur = head; + + while (cur) { + arr.push_back(cur->val); + cur = cur->next; + } + + int n = arr.size(); + swap(arr[k - 1], arr[n - k]); + + cur = head; + int i = 0; + while (cur) { + cur->val = arr[i]; + cur = cur->next; + i++; + } + + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + swapNodes(head, k) { + let arr = []; + let cur = head; + + while (cur) { + arr.push(cur.val); + cur = cur.next; + } + + let n = arr.length; + [arr[k - 1], arr[n - k]] = [arr[n - k], arr[k - 1]]; + + cur = head; + let i = 0; + while (cur) { + cur.val = arr[i]; + cur = cur.next; + i++; + } + + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Recursion + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapNodes(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: + left, right, startIdx = None, None, 0 + + def dfs(node): + nonlocal left, right, startIdx + if not node: + return 0 + + startIdx += 1 + if startIdx == k: + left = node + + endIdx = dfs(node.next) + 1 + if endIdx == k: + right = node + + return endIdx + + dfs(head) + if left and right: + left.val, right.val = right.val, left.val + + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapNodes(ListNode head, int k) { + ListNode[] left = new ListNode[1]; + ListNode[] right = new ListNode[1]; + int[] startIdx = {0}; + + dfs(head, k, startIdx, left, right); + + if (left[0] != null && right[0] != null) { + int temp = left[0].val; + left[0].val = right[0].val; + right[0].val = temp; + } + + return head; + } + + private int dfs(ListNode node, int k, int[] startIdx, ListNode[] left, ListNode[] right) { + if (node == null) { + return 0; + } + + startIdx[0]++; + if (startIdx[0] == k) { + left[0] = node; + } + + int endIdx = dfs(node.next, k, startIdx, left, right) + 1; + if (endIdx == k) { + right[0] = node; + } + + return endIdx; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapNodes(ListNode* head, int k) { + ListNode* left = nullptr; + ListNode* right = nullptr; + int startIdx = 0; + + dfs(head, k, startIdx, left, right); + + if (left && right) { + swap(left->val, right->val); + } + + return head; + } + +private: + int dfs(ListNode* node, int k, int& startIdx, ListNode*& left, ListNode*& right) { + if (!node) { + return 0; + } + + startIdx++; + if (startIdx == k) { + left = node; + } + + int endIdx = dfs(node->next, k, startIdx, left, right) + 1; + if (endIdx == k) { + right = node; + } + + return endIdx; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + swapNodes(head, k) { + let left = null, + right = null, + startIdx = 0; + + const dfs = (node) => { + if (!node) return 0; + + startIdx++; + if (startIdx === k) left = node; + + let endIdx = dfs(node.next) + 1; + if (endIdx === k) right = node; + + return endIdx; + }; + + dfs(head); + if (left && right) { + [left.val, right.val] = [right.val, left.val]; + } + + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 3. Iteration (Two Pass) + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapNodes(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: + n = 0 + cur = head + while cur: + n += 1 + cur = cur.next + + left, right = None, None + cur = head + for i in range(1, n + 1): + if i == k: + left = cur + if i == (n - k + 1): + right = cur + cur = cur.next + + left.val, right.val = right.val, left.val + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapNodes(ListNode head, int k) { + int n = 0; + ListNode cur = head; + while (cur != null) { + n++; + cur = cur.next; + } + + ListNode left = null, right = null; + cur = head; + for (int i = 1; i <= n; i++) { + if (i == k) { + left = cur; + } + if (i == (n - k + 1)) { + right = cur; + } + cur = cur.next; + } + + int temp = left.val; + left.val = right.val; + right.val = temp; + + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapNodes(ListNode* head, int k) { + int n = 0; + ListNode* cur = head; + while (cur) { + n++; + cur = cur->next; + } + + ListNode* left = nullptr; + ListNode* right = nullptr; + cur = head; + for (int i = 1; i <= n; i++) { + if (i == k) { + left = cur; + } + if (i == (n - k + 1)) { + right = cur; + } + cur = cur->next; + } + + swap(left->val, right->val); + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + swapNodes(head, k) { + let n = 0; + let cur = head; + while (cur) { + n++; + cur = cur.next; + } + + let left = null, + right = null; + cur = head; + for (let i = 1; i <= n; i++) { + if (i === k) { + left = cur; + } + if (i === n - k + 1) { + right = cur; + } + cur = cur.next; + } + + [left.val, right.val] = [right.val, left.val]; + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 4. Iteration (One Pass) - I + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapNodes(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: + cur = head + for _ in range(k - 1): + cur = cur.next + + left = cur + right = head + + while cur.next: + cur = cur.next + right = right.next + + left.val, right.val = right.val, left.val + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapNodes(ListNode head, int k) { + ListNode cur = head; + for (int i = 0; i < k - 1; i++) { + cur = cur.next; + } + + ListNode left = cur; + ListNode right = head; + + while (cur.next != null) { + cur = cur.next; + right = right.next; + } + + int temp = left.val; + left.val = right.val; + right.val = temp; + + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapNodes(ListNode* head, int k) { + ListNode* cur = head; + for (int i = 0; i < k - 1; i++) { + cur = cur->next; + } + + ListNode* left = cur; + ListNode* right = head; + + while (cur->next) { + cur = cur->next; + right = right->next; + } + + swap(left->val, right->val); + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + swapNodes(head, k) { + let cur = head; + for (let i = 0; i < k - 1; i++) { + cur = cur.next; + } + + let left = cur; + let right = head; + + while (cur.next) { + cur = cur.next; + right = right.next; + } + + [left.val, right.val] = [right.val, left.val]; + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ + +--- + +## 5. Iteration (One Pass) - II + +::tabs-start + +```python +# Definition for singly-linked list. +# class ListNode: +# def __init__(self, val=0, next=None): +# self.val = val +# self.next = next +class Solution: + def swapNodes(self, head: Optional[ListNode], k: int) -> Optional[ListNode]: + left, right = None, None + cur = head + + while cur: + if right: + right = right.next + if k == 1: + left = cur + right = head + k -= 1 + cur = cur.next + + left.val, right.val = right.val, left.val + return head +``` + +```java +/** + * Definition for singly-linked list. + * public class ListNode { + * int val; + * ListNode next; + * ListNode() {} + * ListNode(int val) { this.val = val; } + * ListNode(int val, ListNode next) { this.val = val; this.next = next; } + * } + */ +public class Solution { + public ListNode swapNodes(ListNode head, int k) { + ListNode left = null, right = null, cur = head; + + while (cur != null) { + if (right != null) { + right = right.next; + } + if (k == 1) { + left = cur; + right = head; + } + k--; + cur = cur.next; + } + + int temp = left.val; + left.val = right.val; + right.val = temp; + + return head; + } +} +``` + +```cpp +/** + * Definition for singly-linked list. + * struct ListNode { + * int val; + * ListNode *next; + * ListNode() : val(0), next(nullptr) {} + * ListNode(int x) : val(x), next(nullptr) {} + * ListNode(int x, ListNode *next) : val(x), next(next) {} + * }; + */ +class Solution { +public: + ListNode* swapNodes(ListNode* head, int k) { + ListNode* left = nullptr; + ListNode* right = nullptr; + ListNode* cur = head; + + while (cur) { + if (right) { + right = right->next; + } + if (k == 1) { + left = cur; + right = head; + } + k--; + cur = cur->next; + } + + swap(left->val, right->val); + return head; + } +}; +``` + +```javascript +/** + * Definition for singly-linked list. + * class ListNode { + * constructor(val = 0, next = null) { + * this.val = val; + * this.next = next; + * } + * } + */ +class Solution { + /** + * @param {ListNode} head + * @param {number} k + * @return {ListNode} + */ + swapNodes(head, k) { + let left = null, + right = null, + cur = head; + + while (cur) { + if (right) { + right = right.next; + } + if (k === 1) { + left = cur; + right = head; + } + k--; + cur = cur.next; + } + + [left.val, right.val] = [right.val, left.val]; + return head; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/swim-in-rising-water.md b/articles/swim-in-rising-water.md index 820592628..0e2e3ea66 100644 --- a/articles/swim-in-rising-water.md +++ b/articles/swim-in-rising-water.md @@ -22,7 +22,7 @@ class Solution: dfs((r, c - 1), t)) visit[r][c] = False return res - + return dfs((0, 0), 0) ``` @@ -35,7 +35,7 @@ public class Solution { return dfs(grid, visit, 0, 0, 0); } - private int dfs(int[][] grid, boolean[][] visit, + private int dfs(int[][] grid, boolean[][] visit, int r, int c, int t) { int n = grid.length; if (r < 0 || c < 0 || r >= n || c >= n || visit[r][c]) { @@ -66,7 +66,7 @@ public: } private: - int dfs(vector>& grid, vector>& visit, + int dfs(vector>& grid, vector>& visit, int r, int c, int t) { int n = grid.size(); if (r < 0 || c < 0 || r >= n || c >= n || visit[r][c]) { @@ -95,12 +95,10 @@ class Solution { */ swimInWater(grid) { const n = grid.length; - const visit = Array.from({ length: n }, () => - Array(n).fill(false)); - + const visit = Array.from({ length: n }, () => Array(n).fill(false)); + const dfs = (r, c, t) => { - if (r < 0 || c < 0 || r >= n || - c >= n || visit[r][c]) { + if (r < 0 || c < 0 || r >= n || c >= n || visit[r][c]) { return 1000000; } if (r === n - 1 && c === n - 1) { @@ -109,14 +107,12 @@ class Solution { visit[r][c] = true; t = Math.max(t, grid[r][c]); const res = Math.min( - Math.min(dfs(r + 1, c, t), - dfs(r - 1, c, t)), - Math.min(dfs(r, c + 1, t), - dfs(r, c - 1, t)) + Math.min(dfs(r + 1, c, t), dfs(r - 1, c, t)), + Math.min(dfs(r, c + 1, t), dfs(r, c - 1, t)), ); visit[r][c] = false; return res; - } + }; return dfs(0, 0, 0); } @@ -134,10 +130,10 @@ public class Solution { return Dfs(grid, visit, 0, 0, 0); } - private int Dfs(int[][] grid, bool[][] visit, + private int Dfs(int[][] grid, bool[][] visit, int r, int c, int t) { int n = grid.Length; - if (r < 0 || c < 0 || r >= n || + if (r < 0 || c < 0 || r >= n || c >= n || visit[r][c]) { return 1000000; } @@ -174,16 +170,16 @@ func swimInWater(grid [][]int) int { } visit[r][c] = true t = max(t, grid[r][c]) - + res := min( min(dfs(r+1, c, t), dfs(r-1, c, t)), min(dfs(r, c+1, t), dfs(r, c-1, t)), ) - + visit[r][c] = false return res } - + return dfs(0, 0, 0) } @@ -232,12 +228,41 @@ class Solution { } ``` +```swift +class Solution { + func swimInWater(_ grid: [[Int]]) -> Int { + let n = grid.count + var visit = Array(repeating: Array(repeating: false, count: n), count: n) + + func dfs(_ node: (Int, Int), _ t: Int) -> Int { + let (r, c) = node + if r < 0 || c < 0 || r >= n || c >= n || visit[r][c] { + return 1000000 + } + if r == n - 1 && c == n - 1 { + return max(t, grid[r][c]) + } + visit[r][c] = true + let t = max(t, grid[r][c]) + let res = min(dfs((r + 1, c), t), + dfs((r - 1, c), t), + dfs((r, c + 1), t), + dfs((r, c - 1), t)) + visit[r][c] = false + return res + } + + return dfs((0, 0), 0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(4 ^ {n ^ 2})$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(4 ^ {n ^ 2})$ +- Space complexity: $O(n ^ 2)$ --- @@ -257,7 +282,7 @@ class Solution: def dfs(node, t): r, c = node - if (min(r, c) < 0 or max(r, c) >= n or + if (min(r, c) < 0 or max(r, c) >= n or visit[r][c] or grid[r][c] > t): return False if r == (n - 1) and c == (n - 1): @@ -267,14 +292,14 @@ class Solution: dfs((r - 1, c), t) or dfs((r, c + 1), t) or dfs((r, c - 1), t)) - + for t in range(minH, maxH): if dfs((0, 0), t): return t for r in range(n): for c in range(n): visit[r][c] = False - + return maxH ``` @@ -303,7 +328,7 @@ public class Solution { } private boolean dfs(int[][] grid, boolean[][] visit, int r, int c, int t) { - if (r < 0 || c < 0 || r >= grid.length || + if (r < 0 || c < 0 || r >= grid.length || c >= grid.length || visit[r][c] || grid[r][c] > t) { return false; } @@ -311,9 +336,9 @@ public class Solution { return true; } visit[r][c] = true; - return dfs(grid, visit, r + 1, c, t) || - dfs(grid, visit, r - 1, c, t) || - dfs(grid, visit, r, c + 1, t) || + return dfs(grid, visit, r + 1, c, t) || + dfs(grid, visit, r - 1, c, t) || + dfs(grid, visit, r, c + 1, t) || dfs(grid, visit, r, c - 1, t); } } @@ -345,9 +370,9 @@ public: } private: - bool dfs(vector>& grid, vector>& visit, + bool dfs(vector>& grid, vector>& visit, int r, int c, int t) { - if (r < 0 || c < 0 || r >= grid.size() || + if (r < 0 || c < 0 || r >= grid.size() || c >= grid.size() || visit[r][c] || grid[r][c] > t) { return false; } @@ -355,9 +380,9 @@ private: return true; } visit[r][c] = true; - return dfs(grid, visit, r + 1, c, t) || - dfs(grid, visit, r - 1, c, t) || - dfs(grid, visit, r, c + 1, t) || + return dfs(grid, visit, r + 1, c, t) || + dfs(grid, visit, r - 1, c, t) || + dfs(grid, visit, r, c + 1, t) || dfs(grid, visit, r, c - 1, t); } }; @@ -371,9 +396,9 @@ class Solution { */ swimInWater(grid) { const n = grid.length; - const visit = Array.from({ length: n }, () => - Array(n).fill(false)); - let minH = grid[0][0], maxH = grid[0][0]; + const visit = Array.from({ length: n }, () => Array(n).fill(false)); + let minH = grid[0][0], + maxH = grid[0][0]; for (let row = 0; row < n; row++) { for (let col = 0; col < n; col++) { maxH = Math.max(maxH, grid[row][col]); @@ -383,18 +408,24 @@ class Solution { const dfs = (node, t) => { const [r, c] = node; - if (Math.min(r, c) < 0 || Math.max(r, c) >= n || - visit[r][c] || grid[r][c] > t) { + if ( + Math.min(r, c) < 0 || + Math.max(r, c) >= n || + visit[r][c] || + grid[r][c] > t + ) { return false; } if (r === n - 1 && c === n - 1) { return true; } visit[r][c] = true; - return dfs([r + 1, c], t) || - dfs([r - 1, c], t) || - dfs([r, c + 1], t) || - dfs([r, c - 1], t); + return ( + dfs([r + 1, c], t) || + dfs([r - 1, c], t) || + dfs([r, c + 1], t) || + dfs([r, c - 1], t) + ); }; for (let t = minH; t < maxH; t++) { @@ -440,7 +471,7 @@ public class Solution { } private bool dfs(int[][] grid, bool[][] visit, int r, int c, int t) { - if (r < 0 || c < 0 || r >= grid.Length || + if (r < 0 || c < 0 || r >= grid.Length || c >= grid.Length || visit[r][c] || grid[r][c] > t) { return false; } @@ -448,9 +479,9 @@ public class Solution { return true; } visit[r][c] = true; - return dfs(grid, visit, r + 1, c, t) || - dfs(grid, visit, r - 1, c, t) || - dfs(grid, visit, r, c + 1, t) || + return dfs(grid, visit, r + 1, c, t) || + dfs(grid, visit, r - 1, c, t) || + dfs(grid, visit, r, c + 1, t) || dfs(grid, visit, r, c - 1, t); } } @@ -478,7 +509,7 @@ func swimInWater(grid [][]int) int { var dfs func(r, c, t int) bool dfs = func(r, c, t int) bool { - if r < 0 || c < 0 || r >= n || c >= n || + if r < 0 || c < 0 || r >= n || c >= n || visit[r][c] || grid[r][c] > t { return false } @@ -486,7 +517,7 @@ func swimInWater(grid [][]int) int { return true } visit[r][c] = true - found := dfs(r+1, c, t) || dfs(r-1, c, t) || + found := dfs(r+1, c, t) || dfs(r-1, c, t) || dfs(r, c+1, t) || dfs(r, c-1, t) return found } @@ -520,7 +551,7 @@ class Solution { val visit = Array(n) { BooleanArray(n) } fun dfs(r: Int, c: Int, t: Int): Boolean { - if (r < 0 || c < 0 || r >= n || c >= n || + if (r < 0 || c < 0 || r >= n || c >= n || visit[r][c] || grid[r][c] > t) { return false } @@ -528,7 +559,7 @@ class Solution { return true } visit[r][c] = true - return dfs(r + 1, c, t) || dfs(r - 1, c, t) || + return dfs(r + 1, c, t) || dfs(r - 1, c, t) || dfs(r, c + 1, t) || dfs(r, c - 1, t) } @@ -544,12 +575,57 @@ class Solution { } ``` +```swift +class Solution { + func swimInWater(_ grid: [[Int]]) -> Int { + let n = grid.count + var visit = Array(repeating: Array(repeating: false, count: n), count: n) + var minH = grid[0][0], maxH = grid[0][0] + + for row in 0.. Bool { + let (r, c) = node + if r < 0 || c < 0 || r >= n || c >= n || visit[r][c] || grid[r][c] > t { + return false + } + if r == n - 1 && c == n - 1 { + return true + } + visit[r][c] = true + return dfs((r + 1, c), t) || + dfs((r - 1, c), t) || + dfs((r, c + 1), t) || + dfs((r, c - 1), t) + } + + for t in minH...maxH { + if dfs((0, 0), t) { + return t + } + for r in 0..= n or + if (min(r, c) < 0 or max(r, c) >= n or visit[r][c] or grid[r][c] > t): return False if r == (n - 1) and c == (n - 1): @@ -579,7 +655,7 @@ class Solution: dfs((r - 1, c), t) or dfs((r, c + 1), t) or dfs((r, c - 1), t)) - + l, r = minH, maxH while l < r: m = (l + r) >> 1 @@ -590,7 +666,7 @@ class Solution: for row in range(n): for col in range(n): visit[row][col] = False - + return r ``` @@ -623,7 +699,7 @@ public class Solution { } private boolean dfs(int[][] grid, boolean[][] visit, int r, int c, int t) { - if (r < 0 || c < 0 || r >= grid.length || + if (r < 0 || c < 0 || r >= grid.length || c >= grid.length || visit[r][c] || grid[r][c] > t) { return false; } @@ -631,9 +707,9 @@ public class Solution { return true; } visit[r][c] = true; - return dfs(grid, visit, r + 1, c, t) || - dfs(grid, visit, r - 1, c, t) || - dfs(grid, visit, r, c + 1, t) || + return dfs(grid, visit, r + 1, c, t) || + dfs(grid, visit, r - 1, c, t) || + dfs(grid, visit, r, c + 1, t) || dfs(grid, visit, r, c - 1, t); } } @@ -669,9 +745,9 @@ public: } private: - bool dfs(vector>& grid, vector>& visit, + bool dfs(vector>& grid, vector>& visit, int r, int c, int t) { - if (r < 0 || c < 0 || r >= grid.size() || + if (r < 0 || c < 0 || r >= grid.size() || c >= grid.size() || visit[r][c] || grid[r][c] > t) { return false; } @@ -679,9 +755,9 @@ private: return true; } visit[r][c] = true; - return dfs(grid, visit, r + 1, c, t) || - dfs(grid, visit, r - 1, c, t) || - dfs(grid, visit, r, c + 1, t) || + return dfs(grid, visit, r + 1, c, t) || + dfs(grid, visit, r - 1, c, t) || + dfs(grid, visit, r, c + 1, t) || dfs(grid, visit, r, c - 1, t); } }; @@ -695,9 +771,9 @@ class Solution { */ swimInWater(grid) { const n = grid.length; - const visit = Array.from({ length: n }, () => - Array(n).fill(false)); - let minH = grid[0][0], maxH = grid[0][0]; + const visit = Array.from({ length: n }, () => Array(n).fill(false)); + let minH = grid[0][0], + maxH = grid[0][0]; for (let row = 0; row < n; row++) { for (let col = 0; col < n; col++) { maxH = Math.max(maxH, grid[row][col]); @@ -707,21 +783,28 @@ class Solution { const dfs = (node, t) => { const [r, c] = node; - if (Math.min(r, c) < 0 || Math.max(r, c) >= n || - visit[r][c] || grid[r][c] > t) { + if ( + Math.min(r, c) < 0 || + Math.max(r, c) >= n || + visit[r][c] || + grid[r][c] > t + ) { return false; } if (r === n - 1 && c === n - 1) { return true; } visit[r][c] = true; - return dfs([r + 1, c], t) || - dfs([r - 1, c], t) || - dfs([r, c + 1], t) || - dfs([r, c - 1], t); + return ( + dfs([r + 1, c], t) || + dfs([r - 1, c], t) || + dfs([r, c + 1], t) || + dfs([r, c - 1], t) + ); }; - let l = minH, r = maxH; + let l = minH, + r = maxH; while (l < r) { let m = (l + r) >> 1; if (dfs([0, 0], m)) { @@ -772,7 +855,7 @@ public class Solution { } private bool dfs(int[][] grid, bool[][] visit, int r, int c, int t) { - if (r < 0 || c < 0 || r >= grid.Length || + if (r < 0 || c < 0 || r >= grid.Length || c >= grid.Length || visit[r][c] || grid[r][c] > t) { return false; } @@ -780,9 +863,9 @@ public class Solution { return true; } visit[r][c] = true; - return dfs(grid, visit, r + 1, c, t) || - dfs(grid, visit, r - 1, c, t) || - dfs(grid, visit, r, c + 1, t) || + return dfs(grid, visit, r + 1, c, t) || + dfs(grid, visit, r - 1, c, t) || + dfs(grid, visit, r, c + 1, t) || dfs(grid, visit, r, c - 1, t); } } @@ -810,7 +893,7 @@ func swimInWater(grid [][]int) int { var dfs func(r, c, t int) bool dfs = func(r, c, t int) bool { - if r < 0 || c < 0 || r >= n || c >= n || + if r < 0 || c < 0 || r >= n || c >= n || visit[r][c] || grid[r][c] > t { return false } @@ -818,7 +901,7 @@ func swimInWater(grid [][]int) int { return true } visit[r][c] = true - found := dfs(r+1, c, t) || dfs(r-1, c, t) || + found := dfs(r+1, c, t) || dfs(r-1, c, t) || dfs(r, c+1, t) || dfs(r, c-1, t) return found } @@ -856,7 +939,7 @@ class Solution { val visit = Array(n) { BooleanArray(n) } fun dfs(r: Int, c: Int, t: Int): Boolean { - if (r < 0 || c < 0 || r >= n || c >= n || + if (r < 0 || c < 0 || r >= n || c >= n || visit[r][c] || grid[r][c] > t) { return false } @@ -864,7 +947,7 @@ class Solution { return true } visit[r][c] = true - return dfs(r + 1, c, t) || dfs(r - 1, c, t) || + return dfs(r + 1, c, t) || dfs(r - 1, c, t) || dfs(r, c + 1, t) || dfs(r, c - 1, t) } @@ -887,12 +970,61 @@ class Solution { } ``` +```swift +class Solution { + func swimInWater(_ grid: [[Int]]) -> Int { + let n = grid.count + var visit = Array(repeating: Array(repeating: false, count: n), count: n) + var minH = grid[0][0], maxH = grid[0][0] + + for row in 0.. Bool { + let (r, c) = node + if r < 0 || c < 0 || r >= n || c >= n || visit[r][c] || grid[r][c] > t { + return false + } + if r == n - 1 && c == n - 1 { + return true + } + visit[r][c] = true + return dfs((r + 1, c), t) || + dfs((r - 1, c), t) || + dfs((r, c + 1), t) || + dfs((r, c - 1), t) + } + + var l = minH, r = maxH + while l < r { + let m = (l + r) >> 1 + if dfs((0, 0), m) { + r = m + } else { + l = m + 1 + } + for row in 0.. minHeap = new PriorityQueue<>( Comparator.comparingInt(a -> a[0]) ); @@ -937,27 +1069,27 @@ public class Solution { }; minHeap.offer(new int[]{grid[0][0], 0, 0}); - visit[0][0] = true; + visit[0][0] = true; while (!minHeap.isEmpty()) { int[] curr = minHeap.poll(); int t = curr[0], r = curr[1], c = curr[2]; if (r == N - 1 && c == N - 1) { - return t; + return t; } for (int[] dir : directions) { int neiR = r + dir[0], neiC = c + dir[1]; - if (neiR >= 0 && neiC >= 0 && neiR < N && + if (neiR >= 0 && neiC >= 0 && neiR < N && neiC < N && !visit[neiR][neiC]) { - visit[neiR][neiC] = true; + visit[neiR][neiC] = true; minHeap.offer(new int[]{ - Math.max(t, grid[neiR][neiC]), + Math.max(t, grid[neiR][neiC]), neiR, neiC }); } } } - return N * N; + return N * N; } } ``` @@ -968,7 +1100,7 @@ public: int swimInWater(vector>& grid) { int N = grid.size(); set> visit; - priority_queue, + priority_queue, vector>, greater<>> minHeap; vector> directions = { {0, 1}, {0, -1}, {1, 0}, {-1, 0} @@ -986,7 +1118,7 @@ public: } for (const auto& dir : directions) { int neiR = r + dir[0], neiC = c + dir[1]; - if (neiR < 0 || neiC < 0 || neiR == N || + if (neiR < 0 || neiC < 0 || neiR == N || neiC == N || visit.count({neiR, neiC})) { continue; } @@ -1015,7 +1147,7 @@ class Solution { swimInWater(grid) { const N = grid.length; const visit = new Set(); - const minPQ = new MinPriorityQueue(entry => entry[0]); + const minPQ = new MinPriorityQueue((entry) => entry[0]); const directions = [ [0, 1], [0, -1], @@ -1044,9 +1176,7 @@ class Solution { continue; } visit.add(`${neiR},${neiC}`); - minPQ.push([ - Math.max(t, grid[neiR][neiC]), neiR, neiC - ]); + minPQ.push([Math.max(t, grid[neiR][neiC]), neiR, neiC]); } } } @@ -1059,9 +1189,9 @@ public class Solution { int N = grid.Length; var visit = new HashSet<(int, int)>(); var minHeap = new PriorityQueue<(int t, int r, int c), int>(); - int[][] directions = { - new int[]{0, 1}, new int[]{0, -1}, - new int[]{1, 0}, new int[]{-1, 0} + int[][] directions = { + new int[]{0, 1}, new int[]{0, -1}, + new int[]{1, 0}, new int[]{-1, 0} }; minHeap.Enqueue((grid[0][0], 0, 0), grid[0][0]); @@ -1075,18 +1205,18 @@ public class Solution { } foreach (var dir in directions) { int neiR = r + dir[0], neiC = c + dir[1]; - if (neiR < 0 || neiC < 0 || neiR >= N || + if (neiR < 0 || neiC < 0 || neiR >= N || neiC >= N || visit.Contains((neiR, neiC))) { continue; } visit.Add((neiR, neiC)); minHeap.Enqueue( - (Math.Max(t, grid[neiR][neiC]), neiR, neiC), + (Math.Max(t, grid[neiR][neiC]), neiR, neiC), Math.Max(t, grid[neiR][neiC])); } } - return N * N; + return N * N; } } ``` @@ -1119,7 +1249,7 @@ func swimInWater(grid [][]int) int { for _, dir := range directions { neiR, neiC := r+dir[0], c+dir[1] - if neiR < 0 || neiC < 0 || neiR >= N || neiC >= N || + if neiR < 0 || neiC < 0 || neiR >= N || neiC >= N || visited[[2]int{neiR, neiC}] { continue } @@ -1145,10 +1275,10 @@ class Solution { fun swimInWater(grid: Array): Int { val N = grid.size val directions = listOf(Pair(0, 1), Pair(0, -1), Pair(1, 0), Pair(-1, 0)) - + val minHeap = PriorityQueue(compareBy>> { it.first }) minHeap.offer(Pair(grid[0][0], Pair(0, 0))) - + val visited = HashSet>() visited.add(Pair(0, 0)) @@ -1175,12 +1305,57 @@ class Solution { } ``` +```swift +struct Item: Comparable { + let time: Int + let row: Int + let col: Int + + static func < (lhs: Item, rhs: Item) -> Bool { + return lhs.time < rhs.time + } +} + +class Solution { + func swimInWater(_ grid: [[Int]]) -> Int { + let N = grid.count + var visit = Set<[Int]>() + var minHeap = Heap() + + let directions = [(0, 1), (0, -1), (1, 0), (-1, 0)] + + minHeap.insert(Item(time: grid[0][0], row: 0, col: 0)) + visit.insert([0, 0]) + + while !minHeap.isEmpty { + let item = minHeap.removeMin() + let t = item.time, r = item.row, c = item.col + + if r == N - 1 && c == N - 1 { + return t + } + + for (dr, dc) in directions { + let neiR = r + dr, neiC = c + dc + if neiR < 0 || neiC < 0 || neiR == N || neiC == N || visit.contains([neiR, neiC]) { + continue + } + visit.insert([neiR, neiC]) + minHeap.insert(Item(time: max(t, grid[neiR][neiC]), row: neiR, col: neiC)) + } + } + + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2 \log n)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2 \log n)$ +- Space complexity: $O(n ^ 2)$ --- @@ -1209,7 +1384,7 @@ class DSU: self.Size[pu] += self.Size[pv] self.Parent[pv] = pu return True - + def connected(self, u, v): return self.find(u) == self.find(v) @@ -1219,7 +1394,7 @@ class Solution: dsu = DSU(N * N) positions = sorted((grid[r][c], r, c) for r in range(N) for c in range(N)) directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] - + for t, r, c in positions: for dr, dc in directions: nr, nc = r + dr, c + dc @@ -1230,7 +1405,7 @@ class Solution: ``` ```java -public class DSU { +class DSU { private int[] Parent; private int[] Size; @@ -1282,7 +1457,7 @@ public class Solution { int t = pos[0], r = pos[1], c = pos[2]; for (int[] dir : directions) { int nr = r + dir[0], nc = c + dir[1]; - if (nr >= 0 && nr < N && nc >= 0 && + if (nr >= 0 && nr < N && nc >= 0 && nc < N && grid[nr][nc] <= t) { dsu.union(r * N + c, nr * N + nc); } @@ -1340,7 +1515,7 @@ public: for (auto& [t, r, c] : positions) { for (auto& [dr, dc] : directions) { int nr = r + dr, nc = c + dc; - if (nr >= 0 && nr < N && nc >= 0 && + if (nr >= 0 && nr < N && nc >= 0 && nc < N && grid[nr][nc] <= t) { dsu.unionSets(r * N + c, nr * N + nc); } @@ -1376,7 +1551,8 @@ class DSU { * @return {boolean} */ union(u, v) { - let pu = this.find(u), pv = this.find(v); + let pu = this.find(u), + pv = this.find(v); if (pu === pv) return false; if (this.Size[pu] < this.Size[pv]) [pu, pv] = [pv, pu]; this.Size[pu] += this.Size[pv]; @@ -1410,14 +1586,23 @@ class Solution { } positions.sort((a, b) => a[0] - b[0]); const directions = [ - [0, 1], [1, 0], [0, -1], [-1, 0] + [0, 1], + [1, 0], + [0, -1], + [-1, 0], ]; for (const [t, r, c] of positions) { for (const [dr, dc] of directions) { - const nr = r + dr, nc = c + dc; - if (nr >= 0 && nr < N && nc >= 0 && - nc < N && grid[nr][nc] <= t) { + const nr = r + dr, + nc = c + dc; + if ( + nr >= 0 && + nr < N && + nc >= 0 && + nc < N && + grid[nr][nc] <= t + ) { dsu.union(r * N + c, nr * N + nc); } } @@ -1472,16 +1657,16 @@ public class Solution { for (int c = 0; c < N; c++) positions.Add(new int[] {grid[r][c], r, c}); positions.Sort((a, b) => a[0] - b[0]); - int[][] directions = new int[][] { - new int[] {0, 1}, new int[] {1, 0}, - new int[] {0, -1}, new int[] {-1, 0} + int[][] directions = new int[][] { + new int[] {0, 1}, new int[] {1, 0}, + new int[] {0, -1}, new int[] {-1, 0} }; foreach (var pos in positions) { int t = pos[0], r = pos[1], c = pos[2]; foreach (var dir in directions) { int nr = r + dir[0], nc = c + dir[1]; - if (nr >= 0 && nr < N && nc >= 0 && + if (nr >= 0 && nr < N && nc >= 0 && nc < N && grid[nr][nc] <= t) { dsu.Union(r * N + c, nr * N + nc); } @@ -1543,8 +1728,8 @@ func swimInWater(grid [][]int) int { positions = append(positions, [3]int{grid[r][c], r, c}) } } - sort.Slice(positions, func(i, j int) bool { - return positions[i][0] < positions[j][0] + sort.Slice(positions, func(i, j int) bool { + return positions[i][0] < positions[j][0] }) directions := [][2]int{{0, 1}, {1, 0}, {0, -1}, {-1, 0}} @@ -1625,9 +1810,78 @@ class Solution { } ``` +```swift +class DSU { + private var parent: [Int] + private var size: [Int] + + init(_ n: Int) { + parent = Array(0...(n - 1)) + size = Array(repeating: 1, count: n) + } + + func find(_ node: Int) -> Int { + if parent[node] != node { + parent[node] = find(parent[node]) + } + return parent[node] + } + + func union(_ u: Int, _ v: Int) -> Bool { + let pu = find(u) + let pv = find(v) + if pu == pv { + return false + } + if size[pu] < size[pv] { + parent[pu] = pv + size[pv] += size[pu] + } else { + parent[pv] = pu + size[pu] += size[pv] + } + return true + } + + func connected(_ u: Int, _ v: Int) -> Bool { + return find(u) == find(v) + } +} + +class Solution { + func swimInWater(_ grid: [[Int]]) -> Int { + let N = grid.count + let dsu = DSU(N * N) + var positions = [(Int, Int, Int)]() + let directions = [(0, 1), (1, 0), (0, -1), (-1, 0)] + + for r in 0..= 0, nc >= 0, nr < N, nc < N, grid[nr][nc] <= t { + dsu.union(r * N + c, nr * N + nc) + } + } + if dsu.connected(0, N * N - 1) { + return t + } + } + return -1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2 \log n)$ -* Space complexity: $O(n ^ 2)$ \ No newline at end of file +- Time complexity: $O(n ^ 2 \log n)$ +- Space complexity: $O(n ^ 2)$ diff --git a/articles/symmetric-tree.md b/articles/symmetric-tree.md new file mode 100644 index 000000000..dc721b31a --- /dev/null +++ b/articles/symmetric-tree.md @@ -0,0 +1,447 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def isSymmetric(self, root: Optional[TreeNode]) -> bool: + def dfs(left, right): + if not left and not right: + return True + if not left or not right: + return False + return ( + left.val == right.val and + dfs(left.left, right.right) and + dfs(left.right, right.left) + ) + return dfs(root.left, root.right) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean isSymmetric(TreeNode root) { + return dfs(root.left, root.right); + } + + private boolean dfs(TreeNode left, TreeNode right) { + if (left == null && right == null) { + return true; + } + if (left == null || right == null) { + return false; + } + return left.val == right.val && + dfs(left.left, right.right) && + dfs(left.right, right.left); + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool isSymmetric(TreeNode* root) { + return dfs(root->left, root->right); + } + +private: + bool dfs(TreeNode* left, TreeNode* right) { + if (!left && !right) { + return true; + } + if (!left || !right) { + return false; + } + return (left->val == right->val) && + dfs(left->left, right->right) && + dfs(left->right, right->left); + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {boolean} + */ + isSymmetric(root) { + const dfs = (left, right) => { + if (!left && !right) { + return true; + } + if (!left || !right) { + return false; + } + return ( + left.val === right.val && + dfs(left.left, right.right) && + dfs(left.right, right.left) + ); + }; + return dfs(root.left, root.right); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def isSymmetric(self, root: Optional[TreeNode]) -> bool: + if not root: + return True + + stack = [(root.left, root.right)] + while stack: + left, right = stack.pop() + if not left and not right: + continue + if not left or not right or left.val != right.val: + return False + stack.append((left.left, right.right)) + stack.append((left.right, right.left)) + return True +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean isSymmetric(TreeNode root) { + if (root == null) return true; + + Stack stack = new Stack<>(); + stack.push(new TreeNode[]{root.left, root.right}); + + while (!stack.isEmpty()) { + TreeNode[] nodes = stack.pop(); + TreeNode left = nodes[0], right = nodes[1]; + + if (left == null && right == null) continue; + if (left == null || right == null || left.val != right.val) { + return false; + } + + stack.push(new TreeNode[]{left.left, right.right}); + stack.push(new TreeNode[]{left.right, right.left}); + } + + return true; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool isSymmetric(TreeNode* root) { + if (!root) return true; + + std::stack> stack; + stack.push({root->left, root->right}); + + while (!stack.empty()) { + auto [left, right] = stack.top(); + stack.pop(); + + if (!left && !right) continue; + if (!left || !right || left->val != right->val) { + return false; + } + stack.push({left->left, right->right}); + stack.push({left->right, right->left}); + } + + return true; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {boolean} + */ + isSymmetric(root) { + if (!root) return true; + + const stack = [[root.left, root.right]]; + + while (stack.length > 0) { + const [left, right] = stack.pop(); + + if (!left && !right) continue; + if (!left || !right || left.val !== right.val) { + return false; + } + + stack.push([left.left, right.right]); + stack.push([left.right, right.left]); + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Breadth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def isSymmetric(self, root: Optional[TreeNode]) -> bool: + if not root: + return True + + queue = deque([(root.left, root.right)]) + while queue: + for _ in range(len(queue)): + left, right = queue.popleft() + if not left and not right: + continue + if not left or not right or left.val != right.val: + return False + queue.append((left.left, right.right)) + queue.append((left.right, right.left)) + + return True +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public boolean isSymmetric(TreeNode root) { + if (root == null) return true; + + Queue queue = new LinkedList<>(); + queue.add(new TreeNode[]{root.left, root.right}); + + while (!queue.isEmpty()) { + for (int i = queue.size(); i > 0; i--) { + TreeNode[] nodes = queue.poll(); + TreeNode left = nodes[0], right = nodes[1]; + + if (left == null && right == null) continue; + if (left == null || right == null || left.val != right.val) { + return false; + } + queue.add(new TreeNode[]{left.left, right.right}); + queue.add(new TreeNode[]{left.right, right.left}); + } + } + + return true; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + bool isSymmetric(TreeNode* root) { + if (!root) return true; + + queue> queue; + queue.push({root->left, root->right}); + + while (!queue.empty()) { + for (int i = queue.size(); i > 0; i--) { + auto [left, right] = queue.front(); + queue.pop(); + + if (!left && !right) continue; + if (!left || !right || left->val != right->val) { + return false; + } + queue.push({left->left, right->right}); + queue.push({left->right, right->left}); + } + } + + return true; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @return {boolean} + */ + isSymmetric(root) { + if (!root) return true; + + const queue = new Queue([[root.left, root.right]]); + + while (!queue.isEmpty()) { + for (let i = queue.size(); i > 0; i--) { + const [left, right] = queue.pop(); + + if (!left && !right) continue; + if (!left || !right || left.val !== right.val) { + return false; + } + queue.push([left.left, right.right]); + queue.push([left.right, right.left]); + } + } + + return true; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/take-gifts-from-the-richest-pile.md b/articles/take-gifts-from-the-richest-pile.md new file mode 100644 index 000000000..7e5a63926 --- /dev/null +++ b/articles/take-gifts-from-the-richest-pile.md @@ -0,0 +1,225 @@ +## 1. Simulation + +::tabs-start + +```python +class Solution: + def pickGifts(self, gifts: List[int], k: int) -> int: + for _ in range(k): + maxIdx = 0 + for i in range(1, len(gifts)): + if gifts[i] > gifts[maxIdx]: + maxIdx = i + gifts[maxIdx] = int(sqrt(gifts[maxIdx])) + return sum(gifts) +``` + +```java +public class Solution { + public long pickGifts(int[] gifts, int k) { + for (int t = 0; t < k; t++) { + int maxIdx = 0; + for (int i = 1; i < gifts.length; i++) { + if (gifts[i] > gifts[maxIdx]) { + maxIdx = i; + } + } + gifts[maxIdx] = (int) Math.floor(Math.sqrt(gifts[maxIdx])); + } + + long sum = 0; + for (int g : gifts) sum += g; + return sum; + } +} +``` + +```cpp +class Solution { +public: + long long pickGifts(vector& gifts, int k) { + for (int t = 0; t < k; t++) { + int maxIdx = 0; + for (int i = 1; i < gifts.size(); i++) { + if (gifts[i] > gifts[maxIdx]) { + maxIdx = i; + } + } + gifts[maxIdx] = floor(sqrt(gifts[maxIdx])); + } + + long long sum = 0; + for (int g : gifts) sum += g; + return sum; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} gifts + * @param {number} k + * @return {number} + */ + pickGifts(gifts, k) { + for (let t = 0; t < k; t++) { + let maxIdx = 0; + for (let i = 1; i < gifts.length; i++) { + if (gifts[i] > gifts[maxIdx]) { + maxIdx = i; + } + } + gifts[maxIdx] = Math.floor(Math.sqrt(gifts[maxIdx])); + } + + return gifts.reduce((a, b) => a + b, 0); + } +} +``` + +```csharp +public class Solution { + public long PickGifts(int[] gifts, int k) { + for (int t = 0; t < k; t++) { + int maxIdx = 0; + for (int i = 1; i < gifts.Length; i++) { + if (gifts[i] > gifts[maxIdx]) { + maxIdx = i; + } + } + gifts[maxIdx] = (int)Math.Floor(Math.Sqrt(gifts[maxIdx])); + } + + long sum = 0; + foreach (var g in gifts) sum += g; + return sum; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: $O(n * k)$ +* Space complexity: $O(1)$ extra space. + +> Where $n$ is the size of input array, $k$ is the number of seconds. + +--- + +## 2. Max-Heap + +::tabs-start + +```python +class Solution: + def pickGifts(self, gifts: List[int], k: int) -> int: + for i in range(len(gifts)): + gifts[i] = -gifts[i] + heapq.heapify(gifts) + + for _ in range(k): + n = -heapq.heappop(gifts) + heapq.heappush(gifts, -floor(sqrt(n))) + + return -sum(gifts) +``` + +```java +public class Solution { + public long pickGifts(int[] gifts, int k) { + PriorityQueue pq = new PriorityQueue<>(Collections.reverseOrder()); + for (int g : gifts) pq.offer(g); + + for (int t = 0; t < k; t++) { + int n = pq.poll(); + pq.offer((int) Math.floor(Math.sqrt(n))); + } + + long sum = 0; + while (!pq.isEmpty()) sum += pq.poll(); + return sum; + } +} +``` + +```cpp +class Solution { +public: + long long pickGifts(vector& gifts, int k) { + priority_queue pq(gifts.begin(), gifts.end()); + + for (int t = 0; t < k; t++) { + int n = pq.top(); pq.pop(); + pq.push((int)floor(sqrt(n))); + } + + long long sum = 0; + while (!pq.empty()) { + sum += pq.top(); pq.pop(); + } + return sum; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} gifts + * @param {number} k + * @return {number} + */ + pickGifts(gifts, k) { + const pq = new MaxPriorityQueue(); + gifts.forEach(g => pq.enqueue(g)); + + for (let t = 0; t < k; t++) { + const n = pq.dequeue(); + pq.enqueue(Math.floor(Math.sqrt(n))); + } + + let sum = 0; + while (!pq.isEmpty()) { + sum += pq.dequeue(); + } + return sum; + } +} +``` + +```csharp +public class Solution { + public long PickGifts(int[] gifts, int k) { + var pq = new PriorityQueue(); + + foreach (var g in gifts) { + pq.Enqueue(g, -g); + } + + for (int t = 0; t < k; t++) { + int n = pq.Dequeue(); + pq.Enqueue((int)Math.Floor(Math.Sqrt(n)), -(int)Math.Floor(Math.Sqrt(n))); + } + + long sum = 0; + while (pq.Count > 0) { + sum += pq.Dequeue(); + } + return sum; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +* Time complexity: + - $O(n + k \log n)$ in Python. + - $O(n \log n + k \log n)$ in other languages. +* Space complexity: $O(n)$ + +> Where $n$ is the size of input array, $k$ is the number of seconds. \ No newline at end of file diff --git a/articles/target-sum.md b/articles/target-sum.md index 819f11b56..1f21f5185 100644 --- a/articles/target-sum.md +++ b/articles/target-sum.md @@ -5,14 +5,14 @@ ```python class Solution: def findTargetSumWays(self, nums: List[int], target: int) -> int: - + def backtrack(i, total): if i ==len(nums): return total == target - - return (backtrack(i + 1, total + nums[i]) + + + return (backtrack(i + 1, total + nums[i]) + backtrack(i + 1, total - nums[i])) - + return backtrack(0, 0) ``` @@ -26,7 +26,7 @@ public class Solution { if (i == nums.length) { return total == target ? 1 : 0; } - return backtrack(i + 1, total + nums[i], nums, target) + + return backtrack(i + 1, total + nums[i], nums, target) + backtrack(i + 1, total - nums[i], nums, target); } } @@ -38,12 +38,12 @@ public: int findTargetSumWays(vector& nums, int target) { return backtrack(0, 0, nums, target); } - + int backtrack(int i, int total, vector& nums, int target) { if (i == nums.size()) { return total == target; } - return backtrack(i + 1, total + nums[i], nums, target) + + return backtrack(i + 1, total + nums[i], nums, target) + backtrack(i + 1, total - nums[i], nums, target); } }; @@ -57,14 +57,15 @@ class Solution { * @return {number} */ findTargetSumWays(nums, target) { - const backtrack = (i, total) => { if (i === nums.length) { return total === target ? 1 : 0; } - return backtrack(i + 1, total + nums[i]) + - backtrack(i + 1, total - nums[i]); - } + return ( + backtrack(i + 1, total + nums[i]) + + backtrack(i + 1, total - nums[i]) + ); + }; return backtrack(0, 0); } @@ -81,7 +82,7 @@ public class Solution { if (i == nums.Length) { return total == target ? 1 : 0; } - return Backtrack(i + 1, total + nums[i], nums, target) + + return Backtrack(i + 1, total + nums[i], nums, target) + Backtrack(i + 1, total - nums[i], nums, target); } } @@ -99,7 +100,7 @@ func findTargetSumWays(nums []int, target int) int { } return backtrack(i+1, total+nums[i]) + backtrack(i+1, total-nums[i]) } - + return backtrack(0, 0) } ``` @@ -111,10 +112,24 @@ class Solution { if (i == nums.size) { return if (total == target) 1 else 0 } - return backtrack(i + 1, total + nums[i]) + + return backtrack(i + 1, total + nums[i]) + backtrack(i + 1, total - nums[i]) } - + + return backtrack(0, 0) + } +} +``` + +```swift +class Solution { + func findTargetSumWays(_ nums: [Int], _ target: Int) -> Int { + func backtrack(_ i: Int, _ total: Int) -> Int { + if i == nums.count { + return total == target ? 1 : 0 + } + return backtrack(i + 1, total + nums[i]) + backtrack(i + 1, total - nums[i]) + } return backtrack(0, 0) } } @@ -124,8 +139,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ --- @@ -144,7 +159,7 @@ class Solution: if (i, total) in dp: return dp[(i, total)] - dp[(i, total)] = (backtrack(i + 1, total + nums[i]) + + dp[(i, total)] = (backtrack(i + 1, total + nums[i]) + backtrack(i + 1, total - nums[i])) return dp[(i, total)] @@ -175,7 +190,7 @@ public class Solution { if (dp[i][total + totalSum] != Integer.MIN_VALUE) { return dp[i][total + totalSum]; } - dp[i][total + totalSum] = backtrack(i + 1, total + nums[i], nums, target) + + dp[i][total + totalSum] = backtrack(i + 1, total + nums[i], nums, target) + backtrack(i + 1, total - nums[i], nums, target); return dp[i][total + totalSum]; } @@ -193,7 +208,7 @@ public: dp = vector>(nums.size(), vector(2 * totalSum + 1, INT_MIN)); return backtrack(0, 0, nums, target); } - + int backtrack(int i, int total, vector& nums, int target) { if (i == nums.size()) { return total == target; @@ -201,7 +216,7 @@ public: if (dp[i][total + totalSum] != INT_MIN) { return dp[i][total + totalSum]; } - dp[i][total + totalSum] = backtrack(i + 1, total + nums[i], nums, target) + + dp[i][total + totalSum] = backtrack(i + 1, total + nums[i], nums, target) + backtrack(i + 1, total - nums[i], nums, target); return dp[i][total + totalSum]; } @@ -218,8 +233,9 @@ class Solution { findTargetSumWays(nums, target) { const NEG_INF = Number.MIN_SAFE_INTEGER; const totalSum = nums.reduce((a, b) => a + b, 0); - const dp = Array.from({ length: nums.length }, () => - Array(2 * totalSum + 1).fill(NEG_INF)); + const dp = Array.from({ length: nums.length }, () => + Array(2 * totalSum + 1).fill(NEG_INF), + ); const backtrack = (i, total) => { if (i === nums.length) { @@ -228,10 +244,11 @@ class Solution { if (dp[i][total + totalSum] !== NEG_INF) { return dp[i][total + totalSum]; } - dp[i][total + totalSum] = backtrack(i + 1, total + nums[i]) + - backtrack(i + 1, total - nums[i]); + dp[i][total + totalSum] = + backtrack(i + 1, total + nums[i]) + + backtrack(i + 1, total - nums[i]); return dp[i][total + totalSum]; - } + }; return backtrack(0, 0); } @@ -249,7 +266,7 @@ public class Solution { dp = new int[nums.Length, 2 * totalSum + 1]; for (int i = 0; i < nums.Length; i++) { for (int j = 0; j < 2 * totalSum + 1; j++) { - dp[i, j] = int.MinValue; + dp[i, j] = int.MinValue; } } return Backtrack(0, 0, nums, target); @@ -261,11 +278,11 @@ public class Solution { } if (dp[i, total + totalSum] != int.MinValue) { - return dp[i, total + totalSum]; + return dp[i, total + totalSum]; } - dp[i, total + totalSum] = Backtrack(i + 1, total + nums[i], nums, target) + - Backtrack(i + 1, total - nums[i], nums, target); + dp[i, total + totalSum] = Backtrack(i + 1, total + nums[i], nums, target) + + Backtrack(i + 1, total - nums[i], nums, target); return dp[i, total + totalSum]; } } @@ -299,7 +316,7 @@ func findTargetSumWays(nums []int, target int) int { return dp[i][total+totalSum] } - dp[i][total+totalSum] = (backtrack(i+1, total+nums[i]) + + dp[i][total+totalSum] = (backtrack(i+1, total+nums[i]) + backtrack(i+1, total-nums[i])) return dp[i][total+totalSum] } @@ -321,11 +338,34 @@ class Solution { if (dp[i][total + totalSum] != Int.MIN_VALUE) { return dp[i][total + totalSum] } - dp[i][total + totalSum] = backtrack(i + 1, total + nums[i]) + + dp[i][total + totalSum] = backtrack(i + 1, total + nums[i]) + + backtrack(i + 1, total - nums[i]) + return dp[i][total + totalSum] + } + + return backtrack(0, 0) + } +} +``` + +```swift +class Solution { + func findTargetSumWays(_ nums: [Int], _ target: Int) -> Int { + let totalSum = nums.reduce(0, +) + var dp = Array(repeating: Array(repeating: Int.min, count: 2 * totalSum + 1), count: nums.count) + + func backtrack(_ i: Int, _ total: Int) -> Int { + if i == nums.count { + return total == target ? 1 : 0 + } + if dp[i][total + totalSum] != Int.min { + return dp[i][total + totalSum] + } + dp[i][total + totalSum] = backtrack(i + 1, total + nums[i]) + backtrack(i + 1, total - nums[i]) return dp[i][total + totalSum] } - + return backtrack(0, 0) } } @@ -335,8 +375,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ > Where $n$ is the length of the array $nums$ and $m$ is the sum of all the elements in the array. @@ -375,9 +415,9 @@ public class Solution { for (Map.Entry entry : dp[i].entrySet()) { int total = entry.getKey(); int count = entry.getValue(); - dp[i + 1].put(total + nums[i], + dp[i + 1].put(total + nums[i], dp[i + 1].getOrDefault(total + nums[i], 0) + count); - dp[i + 1].put(total - nums[i], + dp[i + 1].put(total - nums[i], dp[i + 1].getOrDefault(total - nums[i], 0) + count); } } @@ -421,8 +461,10 @@ class Solution { for (let total in dp[i]) { total = Number(total); let count = dp[i][total]; - dp[i + 1][total + nums[i]] = (dp[i + 1][total + nums[i]] || 0) + count; - dp[i + 1][total - nums[i]] = (dp[i + 1][total - nums[i]] || 0) + count; + dp[i + 1][total + nums[i]] = + (dp[i + 1][total + nums[i]] || 0) + count; + dp[i + 1][total - nums[i]] = + (dp[i + 1][total - nums[i]] || 0) + count; } } return dp[n][target] || 0; @@ -469,7 +511,7 @@ func findTargetSumWays(nums []int, target int) int { dp[i] = make(map[int]int) } - dp[0][0] = 1 + dp[0][0] = 1 for i := 0; i < n; i++ { for total, count := range dp[i] { @@ -488,7 +530,7 @@ class Solution { val n = nums.size val dp = Array(n + 1) { mutableMapOf() } - dp[0][0] = 1 + dp[0][0] = 1 for (i in 0 until n) { for ((total, count) in dp[i]) { @@ -502,12 +544,30 @@ class Solution { } ``` +```swift +class Solution { + func findTargetSumWays(_ nums: [Int], _ target: Int) -> Int { + let n = nums.count + var dp = Array(repeating: [Int: Int](), count: n + 1) + dp[0][0] = 1 + + for i in 0.. Where $n$ is the length of the array $nums$ and $m$ is the sum of all the elements in the array. @@ -529,7 +589,7 @@ class Solution: next_dp[total + num] += count next_dp[total - num] += count dp = next_dp - + return dp[target] ``` @@ -544,9 +604,9 @@ public class Solution { for (Map.Entry entry : dp.entrySet()) { int total = entry.getKey(); int count = entry.getValue(); - nextDp.put(total + num, + nextDp.put(total + num, nextDp.getOrDefault(total + num, 0) + count); - nextDp.put(total - num, + nextDp.put(total - num, nextDp.getOrDefault(total - num, 0) + count); } dp = nextDp; @@ -592,10 +652,8 @@ class Solution { for (let num of nums) { let nextDp = new Map(); for (let [total, count] of dp) { - nextDp.set((total + num), - (nextDp.get((total + num)) || 0) + count); - nextDp.set((total - num), - (nextDp.get((total - num)) || 0) + count); + nextDp.set(total + num, (nextDp.get(total + num) || 0) + count); + nextDp.set(total - num, (nextDp.get(total - num) || 0) + count); } dp = nextDp; } @@ -636,7 +694,7 @@ public class Solution { ```go func findTargetSumWays(nums []int, target int) int { dp := make(map[int]int) - dp[0] = 1 + dp[0] = 1 for _, num := range nums { nextDp := make(map[int]int) @@ -654,7 +712,7 @@ func findTargetSumWays(nums []int, target int) int { ```kotlin class Solution { fun findTargetSumWays(nums: IntArray, target: Int): Int { - val dp = mutableMapOf(0 to 1) + val dp = mutableMapOf(0 to 1) for (num in nums) { val nextDp = mutableMapOf() @@ -671,11 +729,29 @@ class Solution { } ``` +```swift +class Solution { + func findTargetSumWays(_ nums: [Int], _ target: Int) -> Int { + var dp = [0: 1] + + for num in nums { + var nextDp = [Int: Int]() + for (total, count) in dp { + nextDp[total + num, default: 0] += count + nextDp[total - num, default: 0] += count + } + dp = nextDp + } + return dp[target, default: 0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(m)$ -> Where $n$ is the length of the array $nums$ and $m$ is the sum of all the elements in the array. \ No newline at end of file +> Where $n$ is the length of the array $nums$ and $m$ is the sum of all the elements in the array. diff --git a/articles/task-scheduling.md b/articles/task-scheduling.md index d6718ba3f..6f4292428 100644 --- a/articles/task-scheduling.md +++ b/articles/task-scheduling.md @@ -8,7 +8,7 @@ class Solution: count = [0] * 26 for task in tasks: count[ord(task) - ord('A')] += 1 - + arr = [] for i in range(26): if count[i] > 0: @@ -22,7 +22,7 @@ class Solution: if all(processed[j] != arr[i][1] for j in range(max(0, time - n), time)): if maxi == -1 or arr[maxi][0] < arr[i][0]: maxi = i - + time += 1 cur = -1 if maxi != -1: @@ -41,7 +41,7 @@ public class Solution { for (char task : tasks) { count[task - 'A']++; } - + List arr = new ArrayList<>(); for (int i = 0; i < 26; i++) { if (count[i] > 0) { @@ -66,7 +66,7 @@ public class Solution { maxi = i; } } - + time++; int cur = -1; if (maxi != -1) { @@ -91,7 +91,7 @@ public: for (char task : tasks) { count[task - 'A']++; } - + vector> arr; for (int i = 0; i < 26; i++) { if (count[i] > 0) { @@ -116,7 +116,7 @@ public: maxi = i; } } - + time++; int cur = -1; if (maxi != -1) { @@ -145,7 +145,7 @@ class Solution { for (const task of tasks) { count[task.charCodeAt(0) - 'A'.charCodeAt(0)]++; } - + const arr = []; for (let i = 0; i < 26; i++) { if (count[i] > 0) { @@ -170,7 +170,7 @@ class Solution { maxi = i; } } - + time++; let cur = -1; if (maxi !== -1) { @@ -194,7 +194,7 @@ public class Solution { foreach (char task in tasks) { count[task - 'A']++; } - + List arr = new List(); for (int i = 0; i < 26; i++) { if (count[i] > 0) { @@ -219,7 +219,7 @@ public class Solution { maxi = i; } } - + time++; int cur = -1; if (maxi != -1) { @@ -330,12 +330,56 @@ class Solution { } ``` +```swift +class Solution { + func leastInterval(_ tasks: [Character], _ n: Int) -> Int { + var count = [Int](repeating: 0, count: 26) + for task in tasks { + count[Int(task.asciiValue! - Character("A").asciiValue!)] += 1 + } + + var arr = [(Int, Int)]() + for i in 0..<26 { + if count[i] > 0 { + arr.append((count[i], i)) + } + } + + var time = 0 + var processed = [Int]() + + while !arr.isEmpty { + var maxi = -1 + for i in 0.. Where $t$ is the time to process given tasks and $n$ is the cooldown time. @@ -387,7 +431,7 @@ public class Solution { Queue q = new LinkedList<>(); while (!maxHeap.isEmpty() || !q.isEmpty()) { time++; - + if (maxHeap.isEmpty()) { time = q.peek()[1]; } else { @@ -401,7 +445,7 @@ public class Solution { maxHeap.add(q.poll()[0]); } } - + return time; } } @@ -415,19 +459,19 @@ public: for (char task : tasks) { count[task - 'A']++; } - + priority_queue maxHeap; for (int cnt : count) { if (cnt > 0) { maxHeap.push(cnt); } } - + int time = 0; queue> q; while (!maxHeap.empty() || !q.empty()) { time++; - + if (maxHeap.empty()) { time = q.front().second; } else { @@ -437,13 +481,13 @@ public: q.push({cnt, time + n}); } } - + if (!q.empty() && q.front().second == time) { maxHeap.push(q.front().first); q.pop(); } } - + return time; } }; @@ -468,15 +512,15 @@ class Solution { } let time = 0; - let q = new Queue(); + let q = new Queue(); while (maxHeap.size() > 0 || q.size() > 0) { time++; if (maxHeap.size() > 0) { - let cnt = maxHeap.pop() - 1; + let cnt = maxHeap.pop() - 1; if (cnt !== 0) { - q.push([cnt, time + n]); + q.push([cnt, time + n]); } } @@ -506,7 +550,7 @@ public class Solution { } int time = 0; - Queue queue = new Queue(); + Queue queue = new Queue(); while (maxHeap.Count > 0 || queue.Count > 0) { if (queue.Count > 0 && time >= queue.Peek()[1]) { int[] temp = queue.Dequeue(); @@ -531,20 +575,20 @@ func leastInterval(tasks []byte, n int) int { for _, task := range tasks { count[task]++ } - + maxHeap := priorityqueue.NewWith(func(a, b interface{}) int { return b.(int) - a.(int) }) for _, cnt := range count { maxHeap.Enqueue(cnt) } - + time := 0 q := make([][2]int, 0) - + for maxHeap.Size() > 0 || len(q) > 0 { time++ - + if maxHeap.Size() == 0 { time = q[0][1] } else { @@ -554,13 +598,13 @@ func leastInterval(tasks []byte, n int) int { q = append(q, [2]int{cnt.(int), time + n}) } } - + if len(q) > 0 && q[0][1] == time { maxHeap.Enqueue(q[0][0]) q = q[1:] } } - + return time } ``` @@ -604,12 +648,45 @@ class Solution { } ``` +```swift +class Solution { + func leastInterval(_ tasks: [Character], _ n: Int) -> Int { + var count = [Character: Int]() + for task in tasks { + count[task, default: 0] += 1 + } + + var maxHeap = Heap(Array(count.values)) + var time = 0 + var queue = Deque<(Int, Int)>() + + while !maxHeap.isEmpty || !queue.isEmpty { + time += 1 + if maxHeap.isEmpty { + time = queue.first!.1 + } else { + let cnt = maxHeap.popMax()! - 1 + if cnt > 0 { + queue.append((cnt, time + n)) + } + } + if let front = queue.first, front.1 == time { + maxHeap.insert(front.0) + queue.removeFirst() + } + } + + return time + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(m)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. > Where $m$ is the number of tasks. @@ -625,7 +702,7 @@ class Solution: count = [0] * 26 for task in tasks: count[ord(task) - ord('A')] += 1 - + count.sort() maxf = count[25] idle = (maxf - 1) * n @@ -775,12 +852,33 @@ class Solution { } ``` +```swift +class Solution { + func leastInterval(_ tasks: [Character], _ n: Int) -> Int { + var count = [Int](repeating: 0, count: 26) + for task in tasks { + count[Int(task.asciiValue! - Character("A").asciiValue!)] += 1 + } + + count.sort() + let maxf = count[25] + var idle = (maxf - 1) * n + + for i in stride(from: 24, through: 0, by: -1) { + idle -= min(maxf - 1, count[i]) + } + + return max(0, idle) + tasks.count + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(m)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. > Where $m$ is the number of tasks. @@ -796,7 +894,7 @@ class Solution: count = [0] * 26 for task in tasks: count[ord(task) - ord('A')] += 1 - + maxf = max(count) maxCount = 0 for i in count: @@ -813,7 +911,7 @@ public class Solution { for (char task : tasks) { count[task - 'A']++; } - + int maxf = Arrays.stream(count).max().getAsInt(); int maxCount = 0; for (int i : count) { @@ -951,11 +1049,33 @@ class Solution { } ``` +```swift +class Solution { + func leastInterval(_ tasks: [Character], _ n: Int) -> Int { + var count = [Int](repeating: 0, count: 26) + for task in tasks { + count[Int(task.asciiValue! - Character("A").asciiValue!)] += 1 + } + + let maxf = count.max()! + var maxCount = 0 + for i in count { + if i == maxf { + maxCount += 1 + } + } + + let time = (maxf - 1) * (n + 1) + maxCount + return max(tasks.count, time) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(m)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. -> Where $m$ is the number of tasks. \ No newline at end of file +> Where $m$ is the number of tasks. diff --git a/articles/text-justification.md b/articles/text-justification.md new file mode 100644 index 000000000..6b20d676a --- /dev/null +++ b/articles/text-justification.md @@ -0,0 +1,185 @@ +## 1. Iteration + +::tabs-start + +```python +class Solution: + def fullJustify(self, words: List[str], maxWidth: int) -> List[str]: + res = [] + line, length = [], 0 + i = 0 + + while i < len(words): + if length + len(words[i]) + len(line) <= maxWidth: + line.append(words[i]) + length += len(words[i]) + i += 1 + else: + # Line complete + extra_space = maxWidth - length + remainder = extra_space % max(1, (len(line) - 1)) + space = extra_space // max(1, (len(line) - 1)) + for j in range(max(1, len(line) - 1)): + line[j] += " " * space + if remainder: + line[j] += " " + remainder -= 1 + res.append("".join(line)) + line, length = [], 0 + + # Handling last line + last_line = " ".join(line) + trail_space = maxWidth - len(last_line) + res.append(last_line + " " * trail_space) + return res +``` + +```java +public class Solution { + public List fullJustify(String[] words, int maxWidth) { + List res = new ArrayList<>(); + List line = new ArrayList<>(); + int length = 0, i = 0; + + while (i < words.length) { + // If the current word can fit in the line + if (length + words[i].length() + line.size() <= maxWidth) { + line.add(words[i]); + length += words[i].length(); + i++; + } else { + // Line complete + int extra_space = maxWidth - length; + int remainder = extra_space % Math.max(1, (line.size() - 1)); + int space = extra_space / Math.max(1, (line.size() - 1)); + + for (int j = 0; j < Math.max(1, line.size() - 1); j++) { + line.set(j, line.get(j) + " ".repeat(space)); + if (remainder > 0) { + line.set(j, line.get(j) + " "); + remainder--; + } + } + + res.add(String.join("", line)); + line.clear(); + length = 0; + } + } + + // Handling last line + String last_line = String.join(" ", line); + int trail_space = maxWidth - last_line.length(); + res.add(last_line + " ".repeat(trail_space)); + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector fullJustify(vector& words, int maxWidth) { + vector res; + vector line; + int length = 0, i = 0; + + while (i < words.size()) { + if (length + words[i].size() + line.size() <= maxWidth) { + line.push_back(words[i]); + length += words[i].size(); + i++; + } else { + // Line complete + int extra_space = maxWidth - length; + int remainder = extra_space % max(1, (int)(line.size() - 1)); + int space = extra_space / max(1, (int)(line.size() - 1)); + + for (int j = 0; j < max(1, (int)line.size() - 1); j++) { + line[j] += string(space, ' '); + if (remainder > 0) { + line[j] += " "; + remainder--; + } + } + + string justified_line = accumulate(line.begin(), line.end(), string()); + res.push_back(justified_line); + line.clear(); + length = 0; + } + } + + // Handling last line + string last_line = accumulate(line.begin(), line.end(), string(), + [](string a, string b) { + return a.empty() ? b : a + " " + b; + }); + int trail_space = maxWidth - last_line.size(); + last_line += string(trail_space, ' '); + res.push_back(last_line); + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words + * @param {number} maxWidth + * @return {string[]} + */ + fullJustify(words, maxWidth) { + let res = []; + let line = [], + length = 0, + i = 0; + + while (i < words.length) { + if (length + words[i].length + line.length <= maxWidth) { + line.push(words[i]); + length += words[i].length; + i++; + } else { + // Line complete + let extra_space = maxWidth - length; + let remainder = extra_space % Math.max(1, line.length - 1); + let space = Math.floor( + extra_space / Math.max(1, line.length - 1), + ); + + for (let j = 0; j < Math.max(1, line.length - 1); j++) { + line[j] += ' '.repeat(space); + if (remainder > 0) { + line[j] += ' '; + remainder--; + } + } + + res.push(line.join('')); + line = []; + length = 0; + } + } + + // Handling last line + let last_line = line.join(' '); + let trail_space = maxWidth - last_line.length; + res.push(last_line + ' '.repeat(trail_space)); + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ + +> Where $n$ is the number of words and $m$ is the average length of the words. diff --git a/articles/the-number-of-beautiful-subsets.md b/articles/the-number-of-beautiful-subsets.md new file mode 100644 index 000000000..f23f58f89 --- /dev/null +++ b/articles/the-number-of-beautiful-subsets.md @@ -0,0 +1,745 @@ +## 1. Backtracking + +::tabs-start + +```python +class Solution: + def beautifulSubsets(self, nums: List[int], k: int) -> int: + def helper(i, count): + if i == len(nums): + return 1 + + res = helper(i + 1, count) # Skip nums[i] + if not count[nums[i] + k] and not count[nums[i] - k]: + count[nums[i]] += 1 + res += helper(i + 1, count) + count[nums[i]] -= 1 + + return res + + return helper(0, defaultdict(int)) - 1 +``` + +```java +public class Solution { + public int beautifulSubsets(int[] nums, int k) { + return helper(0, new HashMap<>(), nums, k) - 1; + } + + private int helper(int i, Map count, int[] nums, int k) { + if (i == nums.length) { + return 1; + } + + int res = helper(i + 1, count, nums, k); // Skip nums[i] + + if (!count.containsKey(nums[i] + k) && !count.containsKey(nums[i] - k)) { + count.put(nums[i], count.getOrDefault(nums[i], 0) + 1); + res += helper(i + 1, count, nums, k); + count.put(nums[i], count.get(nums[i]) - 1); + if (count.get(nums[i]) == 0) { + count.remove(nums[i]); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int beautifulSubsets(vector& nums, int k) { + unordered_map count; + return helper(0, count, nums, k) - 1; + } + +private: + int helper(int i, unordered_map& count, vector& nums, int k) { + if (i == nums.size()) { + return 1; + } + + int res = helper(i + 1, count, nums, k); // Skip nums[i] + if (!count[nums[i] + k] && !count[nums[i] - k]) { + count[nums[i]]++; + res += helper(i + 1, count, nums, k); + count[nums[i]]--; + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + beautifulSubsets(nums, k) { + const helper = (i, count) => { + if (i === nums.length) { + return 1; + } + + let res = helper(i + 1, count); // Skip nums[i] + + if (!count.has(nums[i] + k) && !count.has(nums[i] - k)) { + count.set(nums[i], (count.get(nums[i]) || 0) + 1); + res += helper(i + 1, count); + count.set(nums[i], count.get(nums[i]) - 1); + if (count.get(nums[i]) === 0) { + count.delete(nums[i]); + } + } + + return res; + }; + + return helper(0, new Map()) - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def beautifulSubsets(self, nums: List[int], k: int) -> int: + cnt = Counter(nums) + groups = [] # List of dicts + cache = {} + + def helper(n, g): + if n not in g: + return 1 + if n in cache: + return cache[n] + + skip = helper(n + k, g) + include = (2**g[n] - 1) * helper(n + 2 * k, g) + cache[n] = skip + include + return skip + include + + visit = set() + for n in cnt.keys(): + if n in visit: + continue + g = {} + while n - k in cnt: + n -= k + while n in cnt: + g[n] = cnt[n] + visit.add(n) + n += k + groups.append(g) + + res = 1 + for g in groups: + n = min(g.keys()) + res *= helper(n, g) + + return res - 1 +``` + +```java +public class Solution { + private Map cache; + private Map cnt; + private Set visit; + + public int beautifulSubsets(int[] nums, int k) { + List> groups = new ArrayList<>(); + this.cache = new HashMap<>(); + this.cnt = new HashMap<>(); + this.visit = new HashSet<>(); + + for (int num : nums) { + cnt.put(num, cnt.getOrDefault(num, 0) + 1); + } + + for (int n : cnt.keySet()) { + if (visit.contains(n)) { + continue; + } + Map g = new HashMap<>(); + while (cnt.containsKey(n - k)) { + n -= k; + } + while (cnt.containsKey(n)) { + g.put(n, cnt.get(n)); + visit.add(n); + n += k; + } + groups.add(g); + } + + int res = 1; + for (Map g : groups) { + int n = Collections.min(g.keySet()); + res *= helper(n, g, k); + } + + return res - 1; + } + + private int helper(int n, Map g, int k) { + if (!g.containsKey(n)) { + return 1; + } + if (cache.containsKey(n)) { + return cache.get(n); + } + + int skip = helper(n + k, g, k); + int include = (int) ((Math.pow(2, g.get(n)) - 1) * helper(n + 2 * k, g, k)); + int result = skip + include; + cache.put(n, result); + return result; + } +} +``` + +```cpp +class Solution { +public: + int beautifulSubsets(vector& nums, int k) { + vector> groups; + cache.clear(); + cnt.clear(); + visit.clear(); + + for (int& num : nums) { + cnt[num]++; + } + + for (auto it = cnt.begin(); it != cnt.end(); ++it) { + int n = it->first; + if (visit.count(n)) { + continue; + } + unordered_map g; + while (cnt.count(n - k)) { + n -= k; + } + while (cnt.count(n)) { + g[n] = cnt[n]; + visit.insert(n); + n += k; + } + groups.push_back(g); + } + + int res = 1; + for (auto& g : groups) { + int n = min_element(g.begin(), g.end())->first; + res *= helper(n, g, k); + } + return res - 1; + } + +private: + unordered_map cache; + unordered_map cnt; + unordered_set visit; + + int helper(int n, unordered_map& g, int k) { + if (!g.count(n)) { + return 1; + } + if (cache.count(n)) { + return cache[n]; + } + + int skip = helper(n + k, g, k); + int include = (pow(2, g[n]) - 1) * helper(n + 2 * k, g, k); + return cache[n] = skip + include; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + beautifulSubsets(nums, k) { + let cnt = new Map(); + for (const num of nums) { + cnt.set(num, (cnt.get(num) || 0) + 1); + } + + let groups = []; + let cache = new Map(); + let visit = new Set(); + + for (let n of cnt.keys()) { + if (visit.has(n)) { + continue; + } + let g = new Map(); + while (cnt.has(n - k)) { + n -= k; + } + while (cnt.has(n)) { + g.set(n, cnt.get(n)); + visit.add(n); + n += k; + } + groups.push(g); + } + + const helper = (n, g) => { + if (!g.has(n)) { + return 1; + } + if (cache.has(n)) { + return cache.get(n); + } + + let skip = helper(n + k, g); + let include = (2 ** g.get(n) - 1) * helper(n + 2 * k, g); + let result = skip + include; + cache.set(n, result); + return result; + }; + + let res = 1; + for (const g of groups) { + let n = Math.min(...g.keys()); + res *= helper(n, g); + } + return res - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def beautifulSubsets(self, nums: List[int], k: int) -> int: + cnt = Counter(nums) + groups = [] # List of dicts + + visit = set() + for n in cnt.keys(): + if n in visit: + continue + g = {} + while n - k in cnt: + n -= k + while n in cnt: + g[n] = cnt[n] + visit.add(n) + n += k + groups.append(g) + + res = 1 + for g in groups: + dp = {} + prev = None + + for num in sorted(g): + count = g[num] + if prev is None or prev + k != num: + dp[num] = (dp.get(prev, 1) * (1 + (2 ** count - 1))) + else: + dp[num] = dp[prev] + (2 ** count - 1) * dp.get(prev - k, 1) + prev = num + + res *= dp[prev] + + return res - 1 +``` + +```java +class Solution { + public int beautifulSubsets(int[] nums, int k) { + Map cnt = new HashMap<>(); + for (int num : nums) { + cnt.put(num, cnt.getOrDefault(num, 0) + 1); + } + + List> groups = new ArrayList<>(); + Set visit = new HashSet<>(); + + for (int n : cnt.keySet()) { + if (visit.contains(n)) { + continue; + } + Map g = new HashMap<>(); + while (cnt.containsKey(n - k)) { + n -= k; + } + while (cnt.containsKey(n)) { + g.put(n, cnt.get(n)); + visit.add(n); + n += k; + } + groups.add(g); + } + + int res = 1; + for (Map g : groups) { + Map dp = new HashMap<>(); + Integer prev = null; + + List arr = new ArrayList<>(g.keySet()); + Collections.sort(arr); + for (int num : arr) { + int count = g.get(num); + if (prev == null || prev + k != num) { + dp.put(num, dp.getOrDefault(prev, 1) * (1 + (int) Math.pow(2, count) - 1)); + } else { + dp.put(num, dp.get(prev) + + ((int) Math.pow(2, count) - 1) * dp.getOrDefault(prev - k, 1)); + } + prev = num; + } + + res *= dp.get(prev); + } + + return res - 1; + } +} +``` + +```cpp +class Solution { +public: + int beautifulSubsets(vector& nums, int k) { + unordered_map cnt; + for (int num : nums) { + cnt[num]++; + } + + vector> groups; + unordered_set visit; + + for (auto it = cnt.begin(); it != cnt.end(); ++it) { + int n = it->first; + if (visit.count(n)) { + continue; + } + unordered_map g; + while (cnt.count(n - k)) { + n -= k; + } + while (cnt.count(n)) { + g[n] = cnt[n]; + visit.insert(n); + n += k; + } + groups.push_back(g); + } + + int res = 1; + for (auto& g : groups) { + unordered_map dp; + int prev = -1; + + vector keys; + for (auto& [num, _] : g) { + keys.push_back(num); + } + sort(keys.begin(), keys.end()); + + for (int num : keys) { + int count = g[num]; + if (prev == -1 || prev + k != num) { + dp[num] = dp.count(prev) ? dp[prev] * (1 + (1 << count) - 1) : + (1 + (1 << count) - 1); + } else { + dp[num] = dp[prev] + ((1 << count) - 1) * + (dp.count(prev - k) ? dp[prev - k] : 1); + } + prev = num; + } + + res *= dp[prev]; + } + + return res - 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + beautifulSubsets(nums, k) { + let cnt = new Map(); + for (const num of nums) { + cnt.set(num, (cnt.get(num) || 0) + 1); + } + + let groups = []; + let visit = new Set(); + + for (const n of cnt.keys()) { + if (visit.has(n)) { + continue; + } + let g = new Map(); + let num = n; + while (cnt.has(num - k)) { + num -= k; + } + while (cnt.has(num)) { + g.set(num, cnt.get(num)); + visit.add(num); + num += k; + } + groups.push(g); + } + + let res = 1; + for (const g of groups) { + let dp = new Map(); + let prev = null; + + for (const num of g.keys()) { + let count = g.get(num); + if (prev === null || prev + k !== num) { + dp.set(num, (dp.get(prev) || 1) * (1 + (2 ** count - 1))); + } else { + dp.set( + num, + dp.get(prev) + + (2 ** count - 1) * (dp.get(prev - k) || 1), + ); + } + prev = num; + } + + res *= dp.get(prev); + } + + return res - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def beautifulSubsets(self, nums: List[int], k: int) -> int: + cnt = Counter(nums) + groups = defaultdict(dict) + + # Group numbers based on their remainder with k + for num in nums: + groups[num % k][num] = cnt[num] + + res = 1 + for g in groups.values(): + prev = 0 + dp, ndp = 0, 1 + + for num in sorted(g.keys()): + count = g[num] + have = (1 << count) - 1 + tmp = ndp + ndp += dp + + if prev == 0 or prev + k != num: + dp = have * (tmp + dp) + else: + dp = tmp * have + + prev = num + + res *= (dp + ndp) + + return res - 1 +``` + +```java +public class Solution { + public int beautifulSubsets(int[] nums, int k) { + Map> groups = new HashMap<>(); + Map cnt = new HashMap<>(); + for (int num : nums) { + cnt.put(num, cnt.getOrDefault(num, 0) + 1); + } + + // Group numbers based on remainder with k + for (int num : nums) { + groups.putIfAbsent(num % k, new HashMap<>()); + groups.get(num % k).put(num, cnt.get(num)); + } + + int res = 1; + for (Map g : groups.values()) { + int prev = 0, dp = 0, ndp = 1; + List sortedKeys = new ArrayList<>(g.keySet()); + Collections.sort(sortedKeys); + + for (int num : sortedKeys) { + int count = g.get(num); + int have = (1 << count) - 1; + int tmp = ndp; + ndp += dp; + + if (prev == 0 || prev + k != num) { + dp = have * (tmp + dp); + } else { + dp = tmp * have; + } + + prev = num; + } + + res *= (dp + ndp); + } + + return res - 1; + } +} +``` + +```cpp +class Solution { +public: + int beautifulSubsets(vector& nums, int k) { + unordered_map> groups; + unordered_map cnt; + for (int& num : nums) { + cnt[num]++; + } + + // Group numbers based on remainder with k + for (int num : nums) { + groups[num % k][num] = cnt[num]; + } + + int res = 1; + for (auto& [rem, g] : groups) { + int prev = 0, dp = 0, ndp = 1; + + for (auto& [num, count] : g) { + int have = (1 << count) - 1; + int tmp = ndp; + ndp += dp; + + if (prev == 0 || prev + k != num) { + dp = have * (tmp + dp); + } else { + dp = tmp * have; + } + + prev = num; + } + + res *= (dp + ndp); + } + + return res - 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} nums + * @param {number} k + * @return {number} + */ + beautifulSubsets(nums, k) { + let groups = new Map(); + let cnt = new Map(); + for (const num of nums) { + cnt.set(num, (cnt.get(num) || 0) + 1); + } + + // Group numbers based on remainder with k + for (const num of nums) { + if (!groups.has(num % k)) { + groups.set(num % k, new Map()); + } + groups.get(num % k).set(num, cnt.get(num)); + } + + let res = 1; + for (const g of groups.values()) { + let prev = 0, + dp = 0, + ndp = 1; + let sortedKeys = Array.from(g.keys()).sort((a, b) => a - b); + + for (const num of sortedKeys) { + let count = g.get(num); + let have = (1 << count) - 1; + let tmp = ndp; + ndp += dp; + + if (prev === 0 || prev + k !== num) { + dp = have * (tmp + dp); + } else { + dp = tmp * have; + } + + prev = num; + } + + res *= dp + ndp; + } + + return res - 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ diff --git a/articles/three-integer-sum.md b/articles/three-integer-sum.md index 74afca85c..c3d13aa3e 100644 --- a/articles/three-integer-sum.md +++ b/articles/three-integer-sum.md @@ -74,7 +74,7 @@ class Solution { } } } - return Array.from(res).map(item => JSON.parse(item)); + return Array.from(res).map((item) => JSON.parse(item)); } } ``` @@ -145,12 +145,33 @@ class Solution { } ``` +```swift +class Solution { + func threeSum(_ nums: [Int]) -> [[Int]] { + var res = Set<[Int]>() + let nums = nums.sorted() + + for i in 0.. Where $m$ is the number of triplets and $n$ is the length of the given array. @@ -173,7 +194,7 @@ class Solution: count[nums[i]] -= 1 if i and nums[i] == nums[i - 1]: continue - + for j in range(i + 1, len(nums)): count[nums[j]] -= 1 if j - 1 > i and nums[j] == nums[j - 1]: @@ -398,12 +419,48 @@ class Solution { } ``` +```swift +class Solution { + func threeSum(_ nums: [Int]) -> [[Int]] { + var nums = nums.sorted() + var count = [Int: Int]() + for num in nums { + count[num, default: 0] += 1 + } + + var res = [[Int]]() + for i in 0.. 0 && nums[i] == nums[i - 1] { + continue + } + + for j in (i + 1).. i + 1 && nums[j] == nums[j - 1] { + continue + } + let target = -(nums[i] + nums[j]) + if let cnt = count[target], cnt > 0 { + res.append([nums[i], nums[j], target]) + } + } + + for j in (i + 1).. [[Int]] { + var res = [[Int]]() + var nums = nums.sorted() + + for i in 0.. 0 { + break + } + if i > 0 && a == nums[i - 1] { + continue + } + + var l = i + 1, r = nums.count - 1 + while l < r { + let threeSum = a + nums[l] + nums[r] + if threeSum > 0 { + r -= 1 + } else if threeSum < 0 { + l += 1 + } else { + res.append([a, nums[l], nums[r]]) + l += 1 + r -= 1 + while l < r && nums[l] == nums[l - 1] { + l += 1 + } + } + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. \ No newline at end of file +- Time complexity: $O(n ^ 2)$ +- Space complexity: + - $O(1)$ or $O(n)$ extra space depending on the sorting algorithm. + - $O(m)$ space for the output list. + +> Where $m$ is the number of triplets and $n$ is the length of the given array. diff --git a/articles/time-based-key-value-store.md b/articles/time-based-key-value-store.md index bfdc75b3e..50f1951c7 100644 --- a/articles/time-based-key-value-store.md +++ b/articles/time-based-key-value-store.md @@ -116,7 +116,7 @@ class TimeMap { */ get(key, timestamp) { if (!this.keyStore.has(key)) { - return ""; + return ''; } let seen = 0; @@ -125,7 +125,7 @@ class TimeMap { seen = Math.max(seen, time); } } - return seen === 0 ? "" : this.keyStore.get(key).get(seen).at(-1); + return seen === 0 ? '' : this.keyStore.get(key).get(seen).at(-1); } } ``` @@ -187,14 +187,14 @@ func (this *TimeMap) Get(key string, timestamp int) string { if _, exists := this.keyStore[key]; !exists { return "" } - + seen := 0 for time := range this.keyStore[key] { if time <= timestamp { seen = max(seen, time) } } - + if seen == 0 { return "" } @@ -213,7 +213,7 @@ func max(a, b int) int { ```kotlin class TimeMap() { private val keyStore = HashMap>>() - + fun set(key: String, value: String, timestamp: Int) { if (!keyStore.containsKey(key)) { keyStore[key] = HashMap() @@ -223,19 +223,19 @@ class TimeMap() { } keyStore[key]!![timestamp]!!.add(value) } - + fun get(key: String, timestamp: Int): String { if (!keyStore.containsKey(key)) { return "" } - + var seen = 0 for (time in keyStore[key]!!.keys) { if (time <= timestamp) { seen = maxOf(seen, time) } } - + if (seen == 0) { return "" } @@ -244,12 +244,46 @@ class TimeMap() { } ``` +```swift +class TimeMap { + private var keyStore: [String: [Int: [String]]] + + init() { + self.keyStore = [:] + } + + func set(_ key: String, _ value: String, _ timestamp: Int) { + if keyStore[key] == nil { + keyStore[key] = [:] + } + if keyStore[key]![timestamp] == nil { + keyStore[key]![timestamp] = [] + } + keyStore[key]![timestamp]!.append(value) + } + + func get(_ key: String, _ timestamp: Int) -> String { + guard let timeMap = keyStore[key] else { + return "" + } + + var seen = 0 + for time in timeMap.keys { + if time <= timestamp { + seen = max(seen, time) + } + } + return seen == 0 ? "" : timeMap[seen]!.last! + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ for $set()$ and $O(n)$ for $get()$. -* Space complexity: $O(m * n)$ +- Time complexity: $O(1)$ for $set()$ and $O(n)$ for $get()$. +- Space complexity: $O(m * n)$ > Where $n$ is the total number of unique timestamps associated with a key and $m$ is the total number of keys. @@ -272,10 +306,10 @@ class TimeMap: def get(self, key: str, timestamp: int) -> str: if key not in self.m: return "" - + timestamps = self.m[key] idx = timestamps.bisect_right(timestamp) - 1 - + if idx >= 0: closest_time = timestamps.iloc[idx] return timestamps[closest_time] @@ -386,7 +420,7 @@ public class TimeMap { var timestamps = m[key]; int left = 0; int right = timestamps.Count - 1; - + while (left <= right) { int mid = left + (right - left) / 2; if (timestamps.Keys[mid] == timestamp) { @@ -397,7 +431,7 @@ public class TimeMap { right = mid - 1; } } - + if (right >= 0) { return timestamps.Values[right]; } @@ -430,12 +464,12 @@ func (this *TimeMap) Get(key string, timestamp int) string { if _, exists := this.m[key]; !exists { return "" } - + pairs := this.m[key] idx := sort.Search(len(pairs), func(i int) bool { return pairs[i].timestamp > timestamp }) - + if idx == 0 { return "" } @@ -446,11 +480,11 @@ func (this *TimeMap) Get(key string, timestamp int) string { ```kotlin class TimeMap() { private val m = HashMap>() - + fun set(key: String, value: String, timestamp: Int) { m.computeIfAbsent(key) { TreeMap() }[timestamp] = value } - + fun get(key: String, timestamp: Int): String { if (!m.containsKey(key)) return "" return m[key]!!.floorEntry(timestamp)?.value ?: "" @@ -458,12 +492,50 @@ class TimeMap() { } ``` +```swift +class TimeMap { + private var m: [String: [(Int, String)]] + + init() { + self.m = [:] + } + + func set(_ key: String, _ value: String, _ timestamp: Int) { + if m[key] == nil { + m[key] = [] + } + m[key]!.append((timestamp, value)) + } + + func get(_ key: String, _ timestamp: Int) -> String { + guard let timestamps = m[key] else { + return "" + } + + var l = 0, r = timestamps.count - 1 + var res = "" + + while l <= r { + let mid = (l + r) / 2 + if timestamps[mid].0 <= timestamp { + res = timestamps[mid].1 + l = mid + 1 + } else { + r = mid - 1 + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ for $set()$ and $O(\log n)$ for $get()$. -* Space complexity: $O(m * n)$ +- Time complexity: $O(1)$ for $set()$ and $O(\log n)$ for $get()$. +- Space complexity: $O(m * n)$ > Where $n$ is the total number of values associated with a key and $m$ is the total number of keys. @@ -499,7 +571,7 @@ class TimeMap: ```java public class TimeMap { - + private Map>> keyStore; public TimeMap() { @@ -627,7 +699,7 @@ class TimeMap { ```csharp public class TimeMap { - + private Dictionary>> keyStore; public TimeMap() { @@ -689,10 +761,10 @@ func (this *TimeMap) Get(key string, timestamp int) string { if _, exists := this.m[key]; !exists { return "" } - + pairs := this.m[key] l, r := 0, len(pairs)-1 - + for l <= r { mid := (l + r) / 2 if pairs[mid].timestamp <= timestamp { @@ -711,20 +783,20 @@ func (this *TimeMap) Get(key string, timestamp int) string { ```kotlin class TimeMap() { private val keyStore = HashMap>>() - + fun set(key: String, value: String, timestamp: Int) { if (!keyStore.containsKey(key)) { keyStore[key] = mutableListOf() } keyStore[key]!!.add(Pair(value, timestamp)) } - + fun get(key: String, timestamp: Int): String { var res = "" val values = keyStore[key] ?: return res var l = 0 var r = values.size - 1 - + while (l <= r) { val m = (l + r) / 2 if (values[m].second <= timestamp) { @@ -739,11 +811,49 @@ class TimeMap() { } ``` +```swift +class TimeMap { + private var keyStore: [String: [(String, Int)]] + + init() { + self.keyStore = [:] + } + + func set(_ key: String, _ value: String, _ timestamp: Int) { + if keyStore[key] == nil { + keyStore[key] = [] + } + keyStore[key]!.append((value, timestamp)) + } + + func get(_ key: String, _ timestamp: Int) -> String { + guard let values = keyStore[key] else { + return "" + } + + var res = "" + var l = 0, r = values.count - 1 + + while l <= r { + let m = (l + r) / 2 + if values[m].1 <= timestamp { + res = values[m].0 + l = m + 1 + } else { + r = m - 1 + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(1)$ for $set()$ and $O(\log n)$ for $get()$. -* Space complexity: $O(m * n)$ +- Time complexity: $O(1)$ for $set()$ and $O(\log n)$ for $get()$. +- Space complexity: $O(m * n)$ -> Where $n$ is the total number of values associated with a key and $m$ is the total number of keys. \ No newline at end of file +> Where $n$ is the total number of values associated with a key and $m$ is the total number of keys. diff --git a/articles/time-needed-to-buy-tickets.md b/articles/time-needed-to-buy-tickets.md index b7422f54c..3a46b0ed9 100644 --- a/articles/time-needed-to-buy-tickets.md +++ b/articles/time-needed-to-buy-tickets.md @@ -119,8 +119,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n)$ > Where $n$ is the size of the input array and $m$ is the maximum value in the input array. @@ -146,7 +146,7 @@ class Solution: idx = (idx + 1) % n while tickets[idx] == 0: idx = (idx + 1) % n - + return time ``` @@ -195,7 +195,7 @@ public: idx = (idx + 1) % n; } } - + return time; } }; @@ -236,8 +236,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(1)$ > Where $n$ is the size of the input array and $m$ is the maximum value in the input array. @@ -257,7 +257,7 @@ class Solution: res += min(tickets[i], tickets[k]) else: res += min(tickets[i], tickets[k] - 1) - + return res ``` @@ -325,5 +325,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/time-needed-to-inform-all-employees.md b/articles/time-needed-to-inform-all-employees.md new file mode 100644 index 000000000..b51e1ca7d --- /dev/null +++ b/articles/time-needed-to-inform-all-employees.md @@ -0,0 +1,479 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def numOfMinutes(self, n: int, headID: int, manager: List[int], informTime: List[int]) -> int: + adj = [[] for _ in range(n)] + for i in range(n): + if i != headID: + adj[manager[i]].append(i) + + def dfs(node): + res = 0 + for child in adj[node]: + res = max(res, informTime[node] + dfs(child)) + return res + + return dfs(headID) +``` + +```java +public class Solution { + public int numOfMinutes(int n, int headID, int[] manager, int[] informTime) { + List[] adj = new ArrayList[n]; + for (int i = 0; i < n; i++) { + adj[i] = new ArrayList<>(); + } + for (int i = 0; i < n; i++) { + if (i != headID) { + adj[manager[i]].add(i); + } + } + + return dfs(headID, adj, informTime); + } + + private int dfs(int node, List[] adj, int[] informTime) { + int res = 0; + for (int child : adj[node]) { + res = Math.max(res, informTime[node] + dfs(child, adj, informTime)); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numOfMinutes(int n, int headID, vector& manager, vector& informTime) { + vector> adj(n); + for (int i = 0; i < n; i++) { + if (i != headID) { + adj[manager[i]].push_back(i); + } + } + return dfs(headID, adj, informTime); + } + +private: + int dfs(int node, vector>& adj, vector& informTime) { + int res = 0; + for (int child : adj[node]) { + res = max(res, informTime[node] + dfs(child, adj, informTime)); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} headID + * @param {number[]} manager + * @param {number[]} informTime + * @return {number} + */ + numOfMinutes(n, headID, manager, informTime) { + const adj = Array.from({ length: n }, () => []); + for (let i = 0; i < n; i++) { + if (i !== headID) { + adj[manager[i]].push(i); + } + } + + const dfs = (node) => { + let res = 0; + for (const child of adj[node]) { + res = Math.max(res, informTime[node] + dfs(child)); + } + return res; + }; + + return dfs(headID); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class Solution: + def numOfMinutes(self, n: int, headID: int, manager: List[int], informTime: List[int]) -> int: + adj = defaultdict(list) + for i in range(n): + adj[manager[i]].append(i) + + q = deque([(headID, 0)]) # (id, time) + res = 0 + + while q: + node, time = q.popleft() + res = max(res, time) + for emp in adj[node]: + q.append((emp, time + informTime[node])) + + return res +``` + +```java +public class Solution { + public int numOfMinutes(int n, int headID, int[] manager, int[] informTime) { + Map> adj = new HashMap<>(); + for (int i = 0; i < n; i++) { + adj.computeIfAbsent(manager[i], k -> new ArrayList<>()).add(i); + } + + Queue queue = new LinkedList<>(); + queue.add(new int[]{headID, 0}); + int res = 0; + + while (!queue.isEmpty()) { + int[] curr = queue.poll(); + int id = curr[0], time = curr[1]; + res = Math.max(res, time); + for (int emp : adj.getOrDefault(id, new ArrayList<>())) { + queue.add(new int[]{emp, time + informTime[id]}); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int numOfMinutes(int n, int headID, vector& manager, vector& informTime) { + unordered_map> adj; + for (int i = 0; i < n; ++i) { + adj[manager[i]].push_back(i); + } + + queue> q; // {id, time} + q.push({headID, 0}); + int res = 0; + + while (!q.empty()) { + auto [id, time] = q.front(); + q.pop(); + res = max(res, time); + for (int emp : adj[id]) { + q.push({emp, time + informTime[id]}); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} headID + * @param {number[]} manager + * @param {number[]} informTime + * @return {number} + */ + numOfMinutes(n, headID, manager, informTime) { + const adj = new Map(); + for (let i = 0; i < n; i++) { + if (!adj.has(manager[i])) adj.set(manager[i], []); + adj.get(manager[i]).push(i); + } + + const queue = new Queue([[headID, 0]]); // [id, time] + let res = 0; + + while (!queue.isEmpty()) { + const [id, time] = queue.pop(); + res = Math.max(res, time); + if (adj.has(id)) { + for (const emp of adj.get(id)) { + queue.push([emp, time + informTime[id]]); + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Topological Sort (Kahn's Algorithm) + +::tabs-start + +```python +class Solution: + def numOfMinutes(self, n: int, headID: int, manager: List[int], informTime: List[int]) -> int: + indegree = [0] * n + time = [0] * n + + for i in range(n): + if manager[i] != -1: + indegree[manager[i]] += 1 + + queue = deque() + for i in range(n): + if indegree[i] == 0: + queue.append(i) + + while queue: + node = queue.popleft() + time[node] += informTime[node] + if manager[node] != -1: + time[manager[node]] = max(time[manager[node]], time[node]) + indegree[manager[node]] -= 1 + if indegree[manager[node]] == 0: + queue.append(manager[node]) + + return time[headID] +``` + +```java +public class Solution { + public int numOfMinutes(int n, int headID, int[] manager, int[] informTime) { + int[] indegree = new int[n]; + int[] time = new int[n]; + + for (int i = 0; i < n; i++) { + if (manager[i] != -1) { + indegree[manager[i]]++; + } + } + + Queue queue = new LinkedList<>(); + for (int i = 0; i < n; i++) { + if (indegree[i] == 0) { + queue.add(i); + } + } + + while (!queue.isEmpty()) { + int node = queue.poll(); + time[node] += informTime[node]; + if (manager[node] != -1) { + time[manager[node]] = Math.max(time[manager[node]], time[node]); + indegree[manager[node]]--; + if (indegree[manager[node]] == 0) { + queue.add(manager[node]); + } + } + } + + return time[headID]; + } +} +``` + +```cpp +class Solution { +public: + int numOfMinutes(int n, int headID, vector& manager, vector& informTime) { + vector indegree(n, 0); + vector time(n, 0); + + for (int i = 0; i < n; ++i) { + if (manager[i] != -1) { + indegree[manager[i]]++; + } + } + + queue queue; + for (int i = 0; i < n; ++i) { + if (indegree[i] == 0) { + queue.push(i); + } + } + + while (!queue.empty()) { + int node = queue.front(); + queue.pop(); + time[node] += informTime[node]; + if (manager[node] != -1) { + time[manager[node]] = max(time[manager[node]], time[node]); + indegree[manager[node]]--; + if (indegree[manager[node]] == 0) { + queue.push(manager[node]); + } + } + } + + return time[headID]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} headID + * @param {number[]} manager + * @param {number[]} informTime + * @return {number} + */ + numOfMinutes(n, headID, manager, informTime) { + const indegree = Array(n).fill(0); + const time = Array(n).fill(0); + + for (let i = 0; i < n; i++) { + if (manager[i] !== -1) { + indegree[manager[i]]++; + } + } + + const queue = new Queue(); + for (let i = 0; i < n; i++) { + if (indegree[i] === 0) { + queue.push(i); + } + } + + while (!queue.isEmpty()) { + const node = queue.pop(); + time[node] += informTime[node]; + if (manager[node] !== -1) { + time[manager[node]] = Math.max(time[manager[node]], time[node]); + indegree[manager[node]]--; + if (indegree[manager[node]] === 0) { + queue.push(manager[node]); + } + } + } + + return time[headID]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Depth First Search (Optimal) + +::tabs-start + +```python +class Solution: + def numOfMinutes(self, n: int, headID: int, manager: List[int], informTime: List[int]) -> int: + def dfs(node): + if manager[node] != -1: + informTime[node] += dfs(manager[node]) + manager[node] = -1 + return informTime[node] + + res = 0 + for node in range(n): + res = max(res, dfs(node)) + return res +``` + +```java +public class Solution { + public int numOfMinutes(int n, int headID, int[] manager, int[] informTime) { + int res = 0; + for (int node = 0; node < n; node++) { + res = Math.max(res, dfs(node, manager, informTime)); + } + return res; + } + + private int dfs(int node, int[] manager, int[] informTime) { + if (manager[node] != -1) { + informTime[node] += dfs(manager[node], manager, informTime); + manager[node] = -1; + } + return informTime[node]; + } +} +``` + +```cpp +class Solution { +public: + int numOfMinutes(int n, int headID, vector& manager, vector& informTime) { + function dfs = [&](int node) { + if (manager[node] != -1) { + informTime[node] += dfs(manager[node]); + manager[node] = -1; + } + return informTime[node]; + }; + + int res = 0; + for (int node = 0; node < n; ++node) { + res = max(res, dfs(node)); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number} headID + * @param {number[]} manager + * @param {number[]} informTime + * @return {number} + */ + numOfMinutes(n, headID, manager, informTime) { + const dfs = (node) => { + if (manager[node] !== -1) { + informTime[node] += dfs(manager[node]); + manager[node] = -1; + } + return informTime[node]; + }; + + let res = 0; + for (let node = 0; node < n; node++) { + res = Math.max(res, dfs(node)); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. diff --git a/articles/top-k-elements-in-list.md b/articles/top-k-elements-in-list.md index ae16871e1..c41763d75 100644 --- a/articles/top-k-elements-in-list.md +++ b/articles/top-k-elements-in-list.md @@ -80,10 +80,13 @@ class Solution { count[num] = (count[num] || 0) + 1; } - const arr = Object.entries(count).map(([num, freq]) => [freq, parseInt(num)]); + const arr = Object.entries(count).map(([num, freq]) => [ + freq, + parseInt(num), + ]); arr.sort((a, b) => b[0] - a[0]); - return arr.slice(0, k).map(pair => pair[1]); + return arr.slice(0, k).map((pair) => pair[1]); } } ``` @@ -156,16 +159,40 @@ class Solution { } ``` +```swift +class Solution { + func topKFrequent(_ nums: [Int], _ k: Int) -> [Int] { + var count = [Int: Int]() + for num in nums { + count[num, default: 0] += 1 + } + + var arr = [(Int, Int)]() + for (num, cnt) in count { + arr.append((cnt, num)) + } + arr.sort { $0.0 < $1.0 } + + var res = [Int]() + while res.count < k { + res.append(arr.removeLast().1) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- -## 2. Heap +## 2. Min-Heap ::tabs-start @@ -253,18 +280,18 @@ class Solution { count[num] = (count[num] || 0) + 1; } - const heap = new MinPriorityQueue(x => x[1]); - for(const [num, cnt] of Object.entries(count)){ + const heap = new MinPriorityQueue((x) => x[1]); + for (const [num, cnt] of Object.entries(count)) { heap.enqueue([num, cnt]); if (heap.size() > k) heap.dequeue(); } const res = []; - for(let i = 0; i < k; i++) { + for (let i = 0; i < k; i++) { const [num, cnt] = heap.dequeue(); - res.push(num) + res.push(num); } - return res; + return res; } } ``` @@ -288,7 +315,7 @@ public class Solution { heap.Dequeue(); } } - + var res = new int[k]; for (int i = 0; i < k; i++) { res[i] = heap.Dequeue(); @@ -308,7 +335,7 @@ func topKFrequent(nums []int, k int) []int { heap := priorityqueue.NewWith(func(a, b interface{}) int { freqA := a.([2]int)[0] freqB := b.([2]int)[0] - return utils.IntComparator(freqA, freqB) + return utils.IntComparator(freqA, freqB) }) for num, freq := range count { @@ -320,7 +347,7 @@ func topKFrequent(nums []int, k int) []int { res := make([]int, k) for i := k - 1; i >= 0; i-- { - value, _ := heap.Dequeue() + value, _ := heap.Dequeue() res[i] = value.([2]int)[1] } return res @@ -352,12 +379,47 @@ class Solution { } ``` +```swift +struct NumFreq: Comparable { + let num: Int + let freq: Int + + static func < (lhs: NumFreq, rhs: NumFreq) -> Bool { + return lhs.freq < rhs.freq + } +} + +class Solution { + func topKFrequent(_ nums: [Int], _ k: Int) -> [Int] { + var count = [Int: Int]() + for num in nums { + count[num, default: 0] += 1 + } + + var heap: Heap = [] + for (num, freq) in count { + heap.insert(NumFreq(num: num, freq: freq)) + if heap.count > k { + heap.removeMin() + } + } + + var res = [Int]() + while !heap.isEmpty { + res.append(heap.removeMin().num) + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log k)$ -* Space complexity: $O(n + k)$ +- Time complexity: $O(n \log k)$ +- Space complexity: $O(n + k)$ > Where $n$ is the length of the array and $k$ is the number of top frequent elements. @@ -377,7 +439,7 @@ class Solution: count[num] = 1 + count.get(num, 0) for num, cnt in count.items(): freq[cnt].append(num) - + res = [] for i in range(len(freq) - 1, 0, -1): for num in freq[i]: @@ -564,9 +626,38 @@ class Solution { } ``` +```swift +class Solution { + func topKFrequent(_ nums: [Int], _ k: Int) -> [Int] { + var count = [Int: Int]() + var freq = [[Int]](repeating: [], count: nums.count + 1) + + for num in nums { + count[num, default: 0] += 1 + } + + for (num, cnt) in count { + freq[cnt].append(num) + } + + var res = [Int]() + for i in stride(from: freq.count - 1, through: 1, by: -1) { + for num in freq[i] { + res.append(num) + if res.count == k { + return res + } + } + } + + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/transpose-matrix.md b/articles/transpose-matrix.md index d92b422ab..ded06389b 100644 --- a/articles/transpose-matrix.md +++ b/articles/transpose-matrix.md @@ -57,7 +57,8 @@ class Solution { * @return {number[][]} */ transpose(matrix) { - const ROWS = matrix.length, COLS = matrix[0].length; + const ROWS = matrix.length, + COLS = matrix[0].length; const res = Array.from({ length: COLS }, () => Array(ROWS).fill(0)); for (let r = 0; r < ROWS; r++) { @@ -71,12 +72,34 @@ class Solution { } ``` +```csharp +public class Solution { + public int[][] Transpose(int[][] matrix) { + int ROWS = matrix.Length; + int COLS = matrix[0].Length; + int[][] res = new int[COLS][]; + + for (int i = 0; i < COLS; i++) { + res[i] = new int[ROWS]; + } + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + res[c][r] = matrix[r][c]; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n * m)$ for the output array. +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ for the output array. > Where $n$ is the number of rows and $m$ is the number of columns in the matrix. @@ -95,7 +118,7 @@ class Solution: for r in range(ROWS): for c in range(r): matrix[r][c], matrix[c][r] = matrix[c][r], matrix[r][c] - + return matrix res = [[0] * ROWS for _ in range(COLS)] @@ -111,7 +134,7 @@ class Solution: public class Solution { public int[][] transpose(int[][] matrix) { int ROWS = matrix.length, COLS = matrix[0].length; - + if (ROWS == COLS) { for (int r = 0; r < ROWS; r++) { for (int c = 0; c < r; c++) { @@ -142,14 +165,14 @@ class Solution { public: vector> transpose(vector>& matrix) { int ROWS = matrix.size(), COLS = matrix[0].size(); - + if (ROWS == COLS) { for (int r = 0; r < ROWS; r++) { for (int c = 0; c < r; c++) { swap(matrix[r][c], matrix[c][r]); } } - + return matrix; } @@ -173,18 +196,19 @@ class Solution { * @return {number[][]} */ transpose(matrix) { - const ROWS = matrix.length, COLS = matrix[0].length; + const ROWS = matrix.length, + COLS = matrix[0].length; if (ROWS === COLS) { - for (let r = 0; r < ROWS; r++) { - for (let c = 0; c < r; c++) { - [matrix[r][c], matrix[c][r]] = [matrix[c][r], matrix[r][c]]; - } + for (let r = 0; r < ROWS; r++) { + for (let c = 0; c < r; c++) { + [matrix[r][c], matrix[c][r]] = [matrix[c][r], matrix[r][c]]; } - - return matrix; } + return matrix; + } + const res = Array.from({ length: COLS }, () => Array(ROWS).fill(0)); for (let r = 0; r < ROWS; r++) { @@ -198,11 +222,44 @@ class Solution { } ``` +```csharp +public class Solution { + public int[][] Transpose(int[][] matrix) { + int ROWS = matrix.Length; + int COLS = matrix[0].Length; + + if (ROWS == COLS) { + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < r; c++) { + int temp = matrix[r][c]; + matrix[r][c] = matrix[c][r]; + matrix[c][r] = temp; + } + } + return matrix; + } + + int[][] res = new int[COLS][]; + for (int i = 0; i < COLS; i++) { + res[i] = new int[ROWS]; + } + + for (int r = 0; r < ROWS; r++) { + for (int c = 0; c < COLS; c++) { + res[c][r] = matrix[r][c]; + } + } + + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ -> Where $n$ is the number of rows and $m$ is the number of columns in the matrix. \ No newline at end of file +> Where $n$ is the number of rows and $m$ is the number of columns in the matrix. diff --git a/articles/trapping-rain-water.md b/articles/trapping-rain-water.md index 73635a85d..175aa3dbb 100644 --- a/articles/trapping-rain-water.md +++ b/articles/trapping-rain-water.md @@ -17,7 +17,7 @@ class Solution: leftMax = max(leftMax, height[j]) for j in range(i + 1, n): rightMax = max(rightMax, height[j]) - + res += min(leftMax, rightMax) - height[i] return res ``` @@ -197,12 +197,39 @@ class Solution { } ``` +```swift +class Solution { + func trap(_ height: [Int]) -> Int { + if height.isEmpty { + return 0 + } + let n = height.count + var res = 0 + + for i in 0.. Int { + let n = height.count + if n == 0 { + return 0 + } + + var leftMax = [Int](repeating: 0, count: n) + var rightMax = [Int](repeating: 0, count: n) + + leftMax[0] = height[0] + for i in 1.. stack = new Stack<>(); int res = 0; @@ -537,7 +594,10 @@ class Solution { let res = 0; for (let i = 0; i < height.length; i++) { - while (stack.length > 0 && height[i] >= height[stack[stack.length - 1]]) { + while ( + stack.length > 0 && + height[i] >= height[stack[stack.length - 1]] + ) { const mid = height[stack.pop()]; if (stack.length > 0) { const right = height[i]; @@ -593,12 +653,12 @@ func trap(height []int) int { for i := 0; i < len(height); i++ { for !stack.Empty() { - topIndex, _ := stack.Peek() + topIndex, _ := stack.Peek() if height[i] >= height[topIndex.(int)] { - midIndex, _ := stack.Pop() - mid := height[midIndex.(int)] + midIndex, _ := stack.Pop() + mid := height[midIndex.(int)] if !stack.Empty() { - topIndex, _ := stack.Peek() + topIndex, _ := stack.Peek() right := height[i] left := height[topIndex.(int)] h := min(right, left) - mid @@ -606,7 +666,7 @@ func trap(height []int) int { res += h * w } } else { - break + break } } stack.Push(i) @@ -648,12 +708,39 @@ class Solution { } ``` +```swift +class Solution { + func trap(_ height: [Int]) -> Int { + if height.isEmpty { + return 0 + } + var stack = [Int]() + var res = 0 + + for i in 0..= height[stack.last!] { + let mid = height[stack.removeLast()] + if !stack.isEmpty { + let right = height[i] + let left = height[stack.last!] + let h = min(right, left) - mid + let w = i - stack.last! - 1 + res += h * w + } + } + stack.append(i) + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -679,7 +766,7 @@ class Solution: r -= 1 rightMax = max(rightMax, height[r]) res += rightMax - height[r] - return res + return res ``` ```java @@ -852,9 +939,36 @@ class Solution { } ``` +```swift +class Solution { + func trap(_ height: [Int]) -> Int { + if height.isEmpty { + return 0 + } + + var l = 0, r = height.count - 1 + var leftMax = height[l], rightMax = height[r] + var res = 0 + + while l < r { + if leftMax < rightMax { + l += 1 + leftMax = max(leftMax, height[l]) + res += leftMax - height[l] + } else { + r -= 1 + rightMax = max(rightMax, height[r]) + res += rightMax - height[r] + } + } + return res + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/triangle.md b/articles/triangle.md index 53b994a33..19505370f 100644 --- a/articles/triangle.md +++ b/articles/triangle.md @@ -9,7 +9,7 @@ class Solution: if row >= len(triangle): return 0 return triangle[row][col] + min(dfs(row + 1, col), dfs(row + 1, col + 1)) - + return dfs(0, 0) ``` @@ -56,9 +56,12 @@ class Solution { if (row >= triangle.length) { return 0; } - return triangle[row][col] + Math.min(dfs(row + 1, col), dfs(row + 1, col + 1)); + return ( + triangle[row][col] + + Math.min(dfs(row + 1, col), dfs(row + 1, col + 1)) + ); }; - + return dfs(0, 0); } } @@ -68,8 +71,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n)$ for recursion stack. +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. --- @@ -94,7 +97,7 @@ class Solution: memo[row][col] = triangle[row][col] + min(dfs(row + 1, col), dfs(row + 1, col + 1)) return memo[row][col] - + return dfs(0, 0) ``` @@ -160,7 +163,9 @@ class Solution { * @return {number} */ minimumTotal(triangle) { - const memo = Array.from({ length: triangle.length }, (_, r) => Array(triangle[r].length).fill(Infinity)); + const memo = Array.from({ length: triangle.length }, (_, r) => + Array(triangle[r].length).fill(Infinity), + ); const dfs = (row, col) => { if (row >= triangle.length) { @@ -170,7 +175,9 @@ class Solution { return memo[row][col]; } - memo[row][col] = triangle[row][col] + Math.min(dfs(row + 1, col), dfs(row + 1, col + 1)); + memo[row][col] = + triangle[row][col] + + Math.min(dfs(row + 1, col), dfs(row + 1, col + 1)); return memo[row][col]; }; @@ -183,8 +190,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -198,7 +205,7 @@ class Solution: n = len(triangle) dp = [[0] * len(triangle[row]) for row in range(n)] dp[-1] = triangle[-1][:] - + for row in range(n - 2, -1, -1): for col in range(len(triangle[row])): dp[row][col] = triangle[row][col] + min(dp[row + 1][col], dp[row + 1][col + 1]) @@ -255,14 +262,18 @@ class Solution { */ minimumTotal(triangle) { const n = triangle.length; - const dp = Array.from({ length: n }, (_, i) => Array(triangle[i].length).fill(0)); + const dp = Array.from({ length: n }, (_, i) => + Array(triangle[i].length).fill(0), + ); for (let col = 0; col < triangle[n - 1].length; col++) { dp[n - 1][col] = triangle[n - 1][col]; } for (let row = n - 2; row >= 0; row--) { for (let col = 0; col < triangle[row].length; col++) { - dp[row][col] = triangle[row][col] + Math.min(dp[row + 1][col], dp[row + 1][col + 1]); + dp[row][col] = + triangle[row][col] + + Math.min(dp[row + 1][col], dp[row + 1][col + 1]); } } @@ -275,8 +286,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -363,7 +374,8 @@ class Solution { let nxtDp = new Array(row + 1).fill(0); nxtDp[0] = dp[0] + triangle[row][0]; for (let col = 1; col < row; col++) { - nxtDp[col] = triangle[row][col] + Math.min(dp[col], dp[col - 1]); + nxtDp[col] = + triangle[row][col] + Math.min(dp[col], dp[col - 1]); } nxtDp[row] = dp[row - 1] + triangle[row][row]; dp = nxtDp; @@ -378,8 +390,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ extra space. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ extra space. --- @@ -396,7 +408,7 @@ class Solution: for row in range(n - 2, -1, -1): for col in range(len(triangle[row])): dp[col] = triangle[row][col] + min(dp[col], dp[col + 1]) - + return dp[0] ``` @@ -408,13 +420,13 @@ public class Solution { for (int i = 0; i < n; i++) { dp[i] = triangle.get(n - 1).get(i); } - + for (int row = n - 2; row >= 0; row--) { for (int col = 0; col < triangle.get(row).size(); col++) { dp[col] = triangle.get(row).get(col) + Math.min(dp[col], dp[col + 1]); } } - + return dp[0]; } } @@ -432,7 +444,7 @@ public: dp[col] = triangle[row][col] + min(dp[col], dp[col + 1]); } } - + return dp[0]; } }; @@ -463,8 +475,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ extra space. +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ extra space. --- @@ -478,7 +490,7 @@ class Solution: for row in range(len(triangle) - 2, -1, -1): for col in range(len(triangle[row])): triangle[row][col] += min(triangle[row + 1][col], triangle[row + 1][col + 1]) - + return triangle[0][0] ``` @@ -487,7 +499,7 @@ public class Solution { public int minimumTotal(List> triangle) { for (int row = triangle.size() - 2; row >= 0; row--) { for (int col = 0; col < triangle.get(row).size(); col++) { - triangle.get(row).set(col, triangle.get(row).get(col) + + triangle.get(row).set(col, triangle.get(row).get(col) + Math.min(triangle.get(row + 1).get(col), triangle.get(row + 1).get(col + 1))); } } @@ -519,7 +531,10 @@ class Solution { minimumTotal(triangle) { for (let row = triangle.length - 2; row >= 0; row--) { for (let col = 0; col < triangle[row].length; col++) { - triangle[row][col] += Math.min(triangle[row + 1][col], triangle[row + 1][col + 1]); + triangle[row][col] += Math.min( + triangle[row + 1][col], + triangle[row + 1][col + 1], + ); } } return triangle[0][0]; @@ -531,5 +546,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(1)$ extra space. \ No newline at end of file +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/trim-a-binary-search-tree.md b/articles/trim-a-binary-search-tree.md new file mode 100644 index 000000000..9edd9850d --- /dev/null +++ b/articles/trim-a-binary-search-tree.md @@ -0,0 +1,488 @@ +## 1. Depth First Search + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]: + if not root: + return None + + if root.val > high: + return self.trimBST(root.left, low, high) + if root.val < low: + return self.trimBST(root.right, low, high) + + root.left = self.trimBST(root.left, low, high) + root.right = self.trimBST(root.right, low, high) + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode trimBST(TreeNode root, int low, int high) { + if (root == null) { + return null; + } + + if (root.val > high) { + return trimBST(root.left, low, high); + } + if (root.val < low) { + return trimBST(root.right, low, high); + } + + root.left = trimBST(root.left, low, high); + root.right = trimBST(root.right, low, high); + return root; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* trimBST(TreeNode* root, int low, int high) { + if (!root) return nullptr; + + if (root->val > high) { + return trimBST(root->left, low, high); + } + if (root->val < low) { + return trimBST(root->right, low, high); + } + + root->left = trimBST(root->left, low, high); + root->right = trimBST(root->right, low, high); + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} low + * @param {number} high + * @return {TreeNode} + */ + trimBST(root, low, high) { + if (!root) return null; + + if (root.val > high) return this.trimBST(root.left, low, high); + if (root.val < low) return this.trimBST(root.right, low, high); + + root.left = this.trimBST(root.left, low, high); + root.right = this.trimBST(root.right, low, high); + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Iterative DFS + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def trimBST(self, root, low, high): + while root and (root.val < low or root.val > high): + if root.val < low: + root = root.right + else: + root = root.left + + stack = [root] + while stack: + node = stack.pop() + if not node: + continue + left_out = node.left and node.left.val < low + right_out = node.right and node.right.val > high + if left_out: + node.left = node.left.right + if right_out: + node.right = node.right.left + if left_out or right_out: + stack.append(node) + else: + if node.left: + stack.append(node.left) + if node.right: + stack.append(node.right) + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode trimBST(TreeNode root, int low, int high) { + while (root != null && (root.val < low || root.val > high)) { + root = (root.val < low) ? root.right : root.left; + } + + Stack stack = new Stack<>(); + stack.push(root); + + while (!stack.isEmpty()) { + TreeNode node = stack.pop(); + if (node == null) continue; + + boolean leftOut = (node.left != null && node.left.val < low); + boolean rightOut = (node.right != null && node.right.val > high); + + if (leftOut) node.left = node.left.right; + if (rightOut) node.right = node.right.left; + + if (leftOut || rightOut) { + stack.push(node); + } else { + if (node.left != null) stack.push(node.left); + if (node.right != null) stack.push(node.right); + } + } + + return root; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* trimBST(TreeNode* root, int low, int high) { + while (root && (root->val < low || root->val > high)) { + root = (root->val < low) ? root->right : root->left; + } + + stack stack; + stack.push(root); + + while (!stack.empty()) { + TreeNode* node = stack.top(); + stack.pop(); + if (!node) continue; + + bool leftOut = (node->left && node->left->val < low); + bool rightOut = (node->right && node->right->val > high); + + if (leftOut) node->left = node->left->right; + if (rightOut) node->right = node->right->left; + + if (leftOut || rightOut) { + stack.push(node); + } else { + if (node->left) stack.push(node->left); + if (node->right) stack.push(node->right); + } + } + + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} low + * @param {number} high + * @return {TreeNode} + */ + trimBST(root, low, high) { + while (root && (root.val < low || root.val > high)) { + root = root.val < low ? root.right : root.left; + } + + const stack = [root]; + + while (stack.length > 0) { + let node = stack.pop(); + if (!node) continue; + + let leftOut = node.left && node.left.val < low; + let rightOut = node.right && node.right.val > high; + + if (leftOut) node.left = node.left.right; + if (rightOut) node.right = node.right.left; + + if (leftOut || rightOut) { + stack.push(node); + } else { + if (node.left) stack.push(node.left); + if (node.right) stack.push(node.right); + } + } + + return root; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Iterative DFS (Optimal) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def trimBST(self, root: Optional[TreeNode], low: int, high: int) -> Optional[TreeNode]: + while root and (root.val < low or root.val > high): + root = root.right if root.val < low else root.left + + tmpRoot = root + while root: + while root.left and root.left.val < low: + root.left = root.left.right + root = root.left + + root = tmpRoot + while root: + while root.right and root.right.val > high: + root.right = root.right.left + root = root.right + + return tmpRoot +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public TreeNode trimBST(TreeNode root, int low, int high) { + while (root != null && (root.val < low || root.val > high)) { + root = (root.val < low) ? root.right : root.left; + } + + TreeNode tmpRoot = root; + while (root != null) { + while (root.left != null && root.left.val < low) { + root.left = root.left.right; + } + root = root.left; + } + + root = tmpRoot; + while (root != null) { + while (root.right != null && root.right.val > high) { + root.right = root.right.left; + } + root = root.right; + } + + return tmpRoot; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + TreeNode* trimBST(TreeNode* root, int low, int high) { + while (root && (root->val < low || root->val > high)) { + root = (root->val < low) ? root->right : root->left; + } + + TreeNode* tmpRoot = root; + while (root) { + while (root->left && root->left->val < low) { + root->left = root->left->right; + } + root = root->left; + } + + root = tmpRoot; + while (root) { + while (root->right && root->right->val > high) { + root->right = root->right->left; + } + root = root->right; + } + + return tmpRoot; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {TreeNode} root + * @param {number} low + * @param {number} high + * @return {TreeNode} + */ + trimBST(root, low, high) { + while (root && (root.val < low || root.val > high)) { + root = root.val < low ? root.right : root.left; + } + + let tmpRoot = root; + while (root) { + while (root.left && root.left.val < low) { + root.left = root.left.right; + } + root = root.left; + } + + root = tmpRoot; + while (root) { + while (root.right && root.right.val > high) { + root.right = root.right.left; + } + root = root.right; + } + + return tmpRoot; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/two-city-scheduling.md b/articles/two-city-scheduling.md new file mode 100644 index 000000000..dc8a3e6e9 --- /dev/null +++ b/articles/two-city-scheduling.md @@ -0,0 +1,699 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def twoCitySchedCost(self, costs: List[List[int]]) -> int: + n = len(costs) // 2 + + def dfs(i, aCount, bCount): + if i == len(costs): + return 0 + + res = float("inf") + if aCount > 0: + res = costs[i][0] + dfs(i + 1, aCount - 1, bCount) + + if bCount > 0: + res = min(res, costs[i][1] + dfs(i + 1, aCount, bCount - 1)) + return res + + return dfs(0, n, n) +``` + +```java +public class Solution { + public int twoCitySchedCost(int[][] costs) { + int n = costs.length / 2; + return dfs(costs, 0, n, n); + } + + private int dfs(int[][] costs, int i, int aCount, int bCount) { + if (i == costs.length) { + return 0; + } + + int res = Integer.MAX_VALUE; + if (aCount > 0) { + res = costs[i][0] + dfs(costs, i + 1, aCount - 1, bCount); + } + + if (bCount > 0) { + res = Math.min(res, costs[i][1] + dfs(costs, i + 1, aCount, bCount - 1)); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int twoCitySchedCost(vector>& costs) { + int n = costs.size() / 2; + return dfs(costs, 0, n, n); + } + +private: + int dfs(vector>& costs, int i, int aCount, int bCount) { + if (i == costs.size()) { + return 0; + } + + int res = INT_MAX; + if (aCount > 0) { + res = costs[i][0] + dfs(costs, i + 1, aCount - 1, bCount); + } + + if (bCount > 0) { + res = min(res, costs[i][1] + dfs(costs, i + 1, aCount, bCount - 1)); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + twoCitySchedCost(costs) { + let n = costs.length / 2; + + const dfs = (i, aCount, bCount) => { + if (i === costs.length) { + return 0; + } + + let res = Infinity; + if (aCount > 0) { + res = costs[i][0] + dfs(i + 1, aCount - 1, bCount); + } + + if (bCount > 0) { + res = Math.min( + res, + costs[i][1] + dfs(i + 1, aCount, bCount - 1), + ); + } + + return res; + }; + + return dfs(0, n, n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(2 ^ N)$ +- Space complexity: $O(N)$ for recursion stack. + +> Where $N$ is the size of the array $costs$. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + def twoCitySchedCost(self, costs: List[List[int]]) -> int: + n = len(costs) // 2 + dp = [[-1] * (n + 1) for _ in range(n + 1)] + + def dfs(i, aCount, bCount): + if i == len(costs): + return 0 + if dp[aCount][bCount] != -1: + return dp[aCount][bCount] + + res = float("inf") + if aCount > 0: + res = costs[i][0] + dfs(i + 1, aCount - 1, bCount) + if bCount > 0: + res = min(res, costs[i][1] + dfs(i + 1, aCount, bCount - 1)) + + dp[aCount][bCount] = res + return res + + return dfs(0, n, n) +``` + +```java +public class Solution { + private int[][] dp; + + public int twoCitySchedCost(int[][] costs) { + int n = costs.length / 2; + dp = new int[n + 1][n + 1]; + for (int[] row : dp) { + Arrays.fill(row, -1); + } + return dfs(costs, 0, n, n); + } + + private int dfs(int[][] costs, int i, int aCount, int bCount) { + if (i == costs.length) { + return 0; + } + if (dp[aCount][bCount] != -1) { + return dp[aCount][bCount]; + } + + int res = Integer.MAX_VALUE; + if (aCount > 0) { + res = costs[i][0] + dfs(costs, i + 1, aCount - 1, bCount); + } + if (bCount > 0) { + res = Math.min(res, costs[i][1] + dfs(costs, i + 1, aCount, bCount - 1)); + } + + dp[aCount][bCount] = res; + return res; + } +} +``` + +```cpp +class Solution { +public: + vector> dp; + + int twoCitySchedCost(vector>& costs) { + int n = costs.size() / 2; + dp = vector>(n + 1, vector(n + 1, -1)); + return dfs(costs, 0, n, n); + } + +private: + int dfs(vector>& costs, int i, int aCount, int bCount) { + if (i == costs.size()) { + return 0; + } + if (dp[aCount][bCount] != -1) { + return dp[aCount][bCount]; + } + + int res = INT_MAX; + if (aCount > 0) { + res = costs[i][0] + dfs(costs, i + 1, aCount - 1, bCount); + } + if (bCount > 0) { + res = min(res, costs[i][1] + dfs(costs, i + 1, aCount, bCount - 1)); + } + + dp[aCount][bCount] = res; + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + twoCitySchedCost(costs) { + let n = costs.length / 2; + let dp = Array.from({ length: n + 1 }, () => new Array(n + 1).fill(-1)); + + const dfs = (i, aCount, bCount) => { + if (i === costs.length) { + return 0; + } + if (dp[aCount][bCount] !== -1) { + return dp[aCount][bCount]; + } + + let res = Infinity; + if (aCount > 0) { + res = costs[i][0] + dfs(i + 1, aCount - 1, bCount); + } + if (bCount > 0) { + res = Math.min( + res, + costs[i][1] + dfs(i + 1, aCount, bCount - 1), + ); + } + + dp[aCount][bCount] = res; + return res; + }; + + return dfs(0, n, n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +> Where $n$ is the half of the size of the array $costs$. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def twoCitySchedCost(self, costs: List[List[int]]) -> int: + n = len(costs) // 2 + dp = [[0] * (n + 1) for _ in range(n + 1)] + + for aCount in range(n + 1): + for bCount in range(n + 1): + i = aCount + bCount + if i == 0: + continue + + dp[aCount][bCount] = float("inf") + if aCount > 0: + dp[aCount][bCount] = min(dp[aCount][bCount], dp[aCount - 1][bCount] + costs[i - 1][0]) + if bCount > 0: + dp[aCount][bCount] = min(dp[aCount][bCount], dp[aCount][bCount - 1] + costs[i - 1][1]) + + return dp[n][n] +``` + +```java +public class Solution { + public int twoCitySchedCost(int[][] costs) { + int n = costs.length / 2; + int[][] dp = new int[n + 1][n + 1]; + + for (int aCount = 0; aCount <= n; aCount++) { + for (int bCount = 0; bCount <= n; bCount++) { + int i = aCount + bCount; + if (i == 0) continue; + + dp[aCount][bCount] = Integer.MAX_VALUE; + if (aCount > 0) { + dp[aCount][bCount] = Math.min(dp[aCount][bCount], dp[aCount - 1][bCount] + costs[i - 1][0]); + } + if (bCount > 0) { + dp[aCount][bCount] = Math.min(dp[aCount][bCount], dp[aCount][bCount - 1] + costs[i - 1][1]); + } + } + } + + return dp[n][n]; + } +} +``` + +```cpp +class Solution { +public: + int twoCitySchedCost(vector>& costs) { + int n = costs.size() / 2; + vector> dp(n + 1, vector(n + 1)); + + for (int aCount = 0; aCount <= n; aCount++) { + for (int bCount = 0; bCount <= n; bCount++) { + int i = aCount + bCount; + if (i == 0) continue; + + dp[aCount][bCount] = INT_MAX; + if (aCount > 0) { + dp[aCount][bCount] = min(dp[aCount][bCount], dp[aCount - 1][bCount] + costs[i - 1][0]); + } + if (bCount > 0) { + dp[aCount][bCount] = min(dp[aCount][bCount], dp[aCount][bCount - 1] + costs[i - 1][1]); + } + } + } + + return dp[n][n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + twoCitySchedCost(costs) { + let n = costs.length / 2; + let dp = Array.from({ length: n + 1 }, () => new Array(n + 1).fill(0)); + + for (let aCount = 0; aCount <= n; aCount++) { + for (let bCount = 0; bCount <= n; bCount++) { + let i = aCount + bCount; + if (i === 0) continue; + + dp[aCount][bCount] = Infinity; + if (aCount > 0) { + dp[aCount][bCount] = Math.min( + dp[aCount][bCount], + dp[aCount - 1][bCount] + costs[i - 1][0], + ); + } + if (bCount > 0) { + dp[aCount][bCount] = Math.min( + dp[aCount][bCount], + dp[aCount][bCount - 1] + costs[i - 1][1], + ); + } + } + } + + return dp[n][n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ + +> Where $n$ is the half of the size of the array $costs$. + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +class Solution: + def twoCitySchedCost(self, costs: List[List[int]]) -> int: + n = len(costs) // 2 + dp = [0] * (n + 1) + + for aCount in range(n + 1): + for bCount in range(n + 1): + i = aCount + bCount + if i == 0: + continue + + tmp = dp[bCount] + dp[bCount] = float("inf") + if aCount > 0: + dp[bCount] = min(dp[bCount], tmp + costs[i - 1][0]) + if bCount > 0: + dp[bCount] = min(dp[bCount], dp[bCount - 1] + costs[i - 1][1]) + + return dp[n] +``` + +```java +public class Solution { + public int twoCitySchedCost(int[][] costs) { + int n = costs.length / 2; + int[] dp = new int[n + 1]; + + for (int aCount = 0; aCount <= n; aCount++) { + for (int bCount = 0; bCount <= n; bCount++) { + int i = aCount + bCount; + if (i == 0) continue; + + int tmp = dp[bCount]; + dp[bCount] = Integer.MAX_VALUE; + if (aCount > 0) { + dp[bCount] = Math.min(dp[bCount], tmp + costs[i - 1][0]); + } + if (bCount > 0) { + dp[bCount] = Math.min(dp[bCount], dp[bCount - 1] + costs[i - 1][1]); + } + } + } + + return dp[n]; + } +} +``` + +```cpp +class Solution { +public: + int twoCitySchedCost(vector>& costs) { + int n = costs.size() / 2; + vector dp(n + 1, 0); + + for (int aCount = 0; aCount <= n; aCount++) { + for (int bCount = 0; bCount <= n; bCount++) { + int i = aCount + bCount; + if (i == 0) continue; + + int tmp = dp[bCount]; + dp[bCount] = INT_MAX; + if (aCount > 0) { + dp[bCount] = min(dp[bCount], tmp + costs[i - 1][0]); + } + if (bCount > 0) { + dp[bCount] = min(dp[bCount], dp[bCount - 1] + costs[i - 1][1]); + } + } + } + + return dp[n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + twoCitySchedCost(costs) { + let n = costs.length / 2; + let dp = new Array(n + 1).fill(0); + + for (let aCount = 0; aCount <= n; aCount++) { + for (let bCount = 0; bCount <= n; bCount++) { + let i = aCount + bCount; + if (i === 0) continue; + + let tmp = dp[bCount]; + dp[bCount] = Infinity; + if (aCount > 0) { + dp[bCount] = Math.min(dp[bCount], tmp + costs[i - 1][0]); + } + if (bCount > 0) { + dp[bCount] = Math.min( + dp[bCount], + dp[bCount - 1] + costs[i - 1][1], + ); + } + } + } + + return dp[n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +> Where $n$ is the half of the size of the array $costs$. + +--- + +## 5. Greedy + +::tabs-start + +```python +class Solution: + def twoCitySchedCost(self, costs: List[List[int]]) -> int: + diffs = [] + for c1, c2 in costs: + diffs.append([c2 - c1, c1, c2]) + + diffs.sort() + res = 0 + for i in range(len(diffs)): + if i < len(diffs) // 2: + res += diffs[i][2] + else: + res += diffs[i][1] + + return res +``` + +```java +public class Solution { + public int twoCitySchedCost(int[][] costs) { + List diffs = new ArrayList<>(); + for (int[] cost : costs) { + diffs.add(new int[]{cost[1] - cost[0], cost[0], cost[1]}); + } + + diffs.sort(Comparator.comparingInt(a -> a[0])); + + int res = 0; + for (int i = 0; i < diffs.size(); i++) { + if (i < diffs.size() / 2) { + res += diffs.get(i)[2]; + } else { + res += diffs.get(i)[1]; + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int twoCitySchedCost(vector>& costs) { + vector> diffs; + for (auto& cost : costs) { + diffs.push_back({cost[1] - cost[0], cost[0], cost[1]}); + } + + sort(diffs.begin(), diffs.end()); + + int res = 0; + for (int i = 0; i < diffs.size(); i++) { + if (i < diffs.size() / 2) { + res += diffs[i][2]; + } else { + res += diffs[i][1]; + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + twoCitySchedCost(costs) { + let diffs = []; + for (let cost of costs) { + diffs.push([cost[1] - cost[0], cost[0], cost[1]]); + } + + diffs.sort((a, b) => a[0] - b[0]); + + let res = 0; + for (let i = 0; i < diffs.length; i++) { + if (i < diffs.length / 2) { + res += diffs[i][2]; + } else { + res += diffs[i][1]; + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ + +--- + +## 6. Greedy (Optimal) + +::tabs-start + +```python +class Solution: + def twoCitySchedCost(self, costs: List[List[int]]) -> int: + costs.sort(key=lambda x: x[1] - x[0]) + n, res = len(costs) // 2, 0 + + for i in range(n): + res += costs[i][1] + costs[i + n][0] + return res +``` + +```java +public class Solution { + public int twoCitySchedCost(int[][] costs) { + Arrays.sort(costs, (a, b) -> Integer.compare(a[1] - a[0], b[1] - b[0])); + int n = costs.length / 2, res = 0; + + for (int i = 0; i < n; i++) { + res += costs[i][1] + costs[i + n][0]; + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int twoCitySchedCost(vector>& costs) { + sort(costs.begin(), costs.end(), [](const auto& a, const auto& b) { + return (a[1] - a[0]) < (b[1] - b[0]); + }); + + int n = costs.size() / 2, res = 0; + for (int i = 0; i < n; i++) { + res += costs[i][1] + costs[i + n][0]; + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} costs + * @return {number} + */ + twoCitySchedCost(costs) { + costs.sort((a, b) => a[1] - a[0] - (b[1] - b[0])); + let n = costs.length / 2, + res = 0; + + for (let i = 0; i < n; i++) { + res += costs[i][1] + costs[i + n][0]; + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. diff --git a/articles/two-integer-sum-ii.md b/articles/two-integer-sum-ii.md index 8aea74e9d..95727fe90 100644 --- a/articles/two-integer-sum-ii.md +++ b/articles/two-integer-sum-ii.md @@ -106,12 +106,27 @@ class Solution { } ``` +```swift +class Solution { + func twoSum(_ numbers: [Int], _ target: Int) -> [Int] { + for i in 0.. [Int] { + for i in 0.. [Int] { + var mp = [Int: Int]() + + for i in 0.. [Int] { + var l = 0, r = numbers.count - 1 + + while l < r { + let curSum = numbers[l] + numbers[r] + + if curSum > target { + r -= 1 + } else if curSum < target { + l += 1 + } else { + return [l + 1, r + 1] + } + } + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/two-integer-sum.md b/articles/two-integer-sum.md index 5b08e079d..e02ab8d68 100644 --- a/articles/two-integer-sum.md +++ b/articles/two-integer-sum.md @@ -54,7 +54,7 @@ class Solution { for (let i = 0; i < nums.length; i++) { for (let j = i + 1; j < nums.length; j++) { if (nums[i] + nums[j] === target) { - return [i, j]; + return [i, j]; } } } @@ -69,11 +69,11 @@ public class Solution { for (int i = 0; i < nums.Length; i++) { for (int j = i + 1; j < nums.Length; j++) { if (nums[i] + nums[j] == target) { - return new int[]{i, j}; + return new int[]{i, j}; } } } - return new int[0]; + return new int[0]; } } ``` @@ -106,12 +106,27 @@ class Solution { } ``` +```swift +class Solution { + func twoSum(_ nums: [Int], _ target: Int) -> [Int] { + for i in 0.. a[0] - b[0]); - let i = 0, j = nums.length - 1; + let i = 0, + j = nums.length - 1; while (i < j) { let cur = A[i][0] + A[j][0]; if (cur === target) { - return [Math.min(A[i][1], A[j][1]), - Math.max(A[i][1], A[j][1])]; + return [Math.min(A[i][1], A[j][1]), Math.max(A[i][1], A[j][1])]; } else if (cur < target) { i++; } else { @@ -243,7 +258,7 @@ public class Solution { int cur = A[i][0] + A[j][0]; if (cur == target) { return new int[]{ - Math.Min(A[i][1], A[j][1]), + Math.Min(A[i][1], A[j][1]), Math.Max(A[i][1], A[j][1]) }; } else if (cur < target) { @@ -263,11 +278,11 @@ func twoSum(nums []int, target int) []int { for i, num := range nums { A[i] = [2]int{num, i} } - + sort.Slice(A, func(i, j int) bool { return A[i][0] < A[j][0] }) - + i, j := 0, len(nums)-1 for i < j { cur := A[i][0] + A[j][0] @@ -313,12 +328,40 @@ class Solution { } ``` +```swift +class Solution { + func twoSum(_ nums: [Int], _ target: Int) -> [Int] { + var A = [(Int, Int)]() + for (i, num) in nums.enumerated() { + A.append((num, i)) + } + + A.sort { $0.0 < $1.0 } + var i = 0 + var j = nums.count - 1 + + while i < j { + let cur = A[i].0 + A[j].0 + if cur == target { + return [min(A[i].1, A[j].1), + max(A[i].1, A[j].1)] + } else if cur < target { + i += 1 + } else { + j -= 1 + } + } + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -391,7 +434,7 @@ class Solution { * @return {number[]} */ twoSum(nums, target) { - const indices = {}; // val -> index + const indices = {}; // val -> index for (let i = 0; i < nums.length; i++) { indices[nums[i]] = i; @@ -413,7 +456,7 @@ class Solution { public class Solution { public int[] TwoSum(int[] nums, int target) { // val -> index - Dictionary indices = new Dictionary(); + Dictionary indices = new Dictionary(); for (int i = 0; i < nums.Length; i++) { indices[nums[i]] = i; @@ -469,12 +512,33 @@ class Solution { } ``` +```swift +class Solution { + func twoSum(_ nums: [Int], _ target: Int) -> [Int] { + var indices = [Int: Int]() // val -> index + + for (i, n) in nums.enumerated() { + indices[n] = i + } + + for (i, n) in nums.enumerated() { + let diff = target - n + if let j = indices[diff], j != i { + return [i, j] + } + } + + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -520,7 +584,7 @@ class Solution { public: vector twoSum(vector& nums, int target) { int n = nums.size(); - unordered_map prevMap; + unordered_map prevMap; for (int i = 0; i < n; i++) { int diff = target - nums[i]; @@ -607,9 +671,27 @@ class Solution { } ``` +```swift +class Solution { + func twoSum(_ nums: [Int], _ target: Int) -> [Int] { + var prevMap = [Int: Int]() // val -> index + + for (i, n) in nums.enumerated() { + let diff = target - n + if let index = prevMap[diff] { + return [index, i] + } + prevMap[n] = i + } + + return [] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/ugly-number.md b/articles/ugly-number.md new file mode 100644 index 000000000..f389b697d --- /dev/null +++ b/articles/ugly-number.md @@ -0,0 +1,76 @@ +## 1. Math + +::tabs-start + +```python +class Solution: + def isUgly(self, n: int) -> bool: + if n <= 0: + return False + + for p in [2, 3, 5]: + while n % p == 0: + n //= p + + return n == 1 +``` + +```java +public class Solution { + public boolean isUgly(int n) { + if (n <= 0) return false; + + for (int p = 2; p <= 5 && n > 0; p++) { + while (n % p == 0) { + n /= p; + } + } + + return n == 1; + } +} +``` + +```cpp +class Solution { +public: + bool isUgly(int n) { + if (n <= 0) return false; + + for (int p = 2; p <= 5 && n > 0; p++) { + while (n % p == 0) { + n /= p; + } + } + + return n == 1; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {boolean} + */ + isUgly(n) { + if (n <= 0) return false; + + for (let p of [2, 3, 5]) { + while (n % p == 0) { + n /= p; + } + } + + return n === 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ diff --git a/articles/uncommon-words-from-two-sentences.md b/articles/uncommon-words-from-two-sentences.md new file mode 100644 index 000000000..aedc12901 --- /dev/null +++ b/articles/uncommon-words-from-two-sentences.md @@ -0,0 +1,181 @@ +## 1. Hash Map - I + +::tabs-start + +```python +class Solution: + def uncommonFromSentences(self, s1: str, s2: str) -> List[str]: + count = defaultdict(int) + for w in s1.split(" ") + s2.split(" "): + count[w] += 1 + + res = [] + for w, cnt in count.items(): + if cnt == 1: + res.append(w) + return res +``` + +```java +public class Solution { + public String[] uncommonFromSentences(String s1, String s2) { + String[] words = (s1 + " " + s2).split(" "); + Map count = new HashMap<>(); + + for (String w : words) { + count.put(w, count.getOrDefault(w, 0) + 1); + } + + List res = new ArrayList<>(); + for (Map.Entry entry : count.entrySet()) { + if (entry.getValue() == 1) { + res.add(entry.getKey()); + } + } + + return res.toArray(new String[0]); + } +} +``` + +```cpp +class Solution { +public: + vector uncommonFromSentences(string s1, string s2) { + unordered_map count; + istringstream ss(s1 + " " + s2); + string w; + while (ss >> w) { + count[w]++; + } + + vector res; + for (auto& [word, freq] : count) { + if (freq == 1) { + res.push_back(word); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s1 + * @param {string} s2 + * @return {string[]} + */ + uncommonFromSentences(s1, s2) { + const words = (s1 + ' ' + s2).split(' '); + const count = new Map(); + + for (const w of words) { + count.set(w, (count.get(w) || 0) + 1); + } + + const res = []; + for (const [w, c] of count.entries()) { + if (c === 1) { + res.push(w); + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ + +> Where $n$ and $m$ are the lengths of the strings $s1$ and $s2$, respectively. + +--- + +## 2. Hash Map - II + +::tabs-start + +```python +class Solution: + def uncommonFromSentences(self, s1: str, s2: str) -> List[str]: + return [w for w, cnt in Counter(s1.split(" ") + s2.split(" ")).items() if cnt == 1] +``` + +```java +public class Solution { + public String[] uncommonFromSentences(String s1, String s2) { + String[] words = (s1 + " " + s2).split(" "); + Map count = new HashMap<>(); + + for (String w : words) { + count.put(w, count.getOrDefault(w, 0) + 1); + } + + return count.entrySet() + .stream() + .filter(e -> e.getValue() == 1) + .map(Map.Entry::getKey) + .toArray(String[]::new); + } +} +``` + +```cpp +class Solution { +public: + vector uncommonFromSentences(string s1, string s2) { + unordered_map count; + istringstream ss(s1 + " " + s2); + string w; + while (ss >> w) { + count[w]++; + } + + vector res; + for (auto& [w, c] : count) { + if (c == 1) { + res.push_back(w); + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s1 + * @param {string} s2 + * @return {string[]} + */ + uncommonFromSentences(s1, s2) { + const words = (s1 + ' ' + s2).split(' '); + const count = new Map(); + + for (const w of words) { + count.set(w, (count.get(w) || 0) + 1); + } + + return [...count.entries()].filter(([_, c]) => c === 1).map(([w]) => w); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m)$ +- Space complexity: $O(n + m)$ + +> Where $n$ and $m$ are the lengths of the strings $s1$ and $s2$, respectively. diff --git a/articles/uncrossed-lines.md b/articles/uncrossed-lines.md index a08442f64..2410057a1 100644 --- a/articles/uncrossed-lines.md +++ b/articles/uncrossed-lines.md @@ -8,11 +8,11 @@ class Solution: def dfs(i, j): if i == len(nums1) or j == len(nums2): return 0 - + if nums1[i] == nums2[j]: return 1 + dfs(i + 1, j + 1) return max(dfs(i, j + 1), dfs(i + 1, j)) - + return dfs(0, 0) ``` @@ -40,13 +40,13 @@ class Solution { public: int dfs(vector& nums1, vector& nums2, int i, int j) { if (i == nums1.size() || j == nums2.size()) return 0; - + if (nums1[i] == nums2[j]) { return 1 + dfs(nums1, nums2, i + 1, j + 1); } return max(dfs(nums1, nums2, i, j + 1), dfs(nums1, nums2, i + 1, j)); } - + int maxUncrossedLines(vector& nums1, vector& nums2) { return dfs(nums1, nums2, 0, 0); } @@ -80,8 +80,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ {n + m})$ -* Space complexity: $O(n + m)$ for recursion stack. +- Time complexity: $O(2 ^ {n + m})$ +- Space complexity: $O(n + m)$ for recursion stack. > Where $n$ and $m$ are the sizes of the arrays $nums1$ and $nums2$ respectively. @@ -107,9 +107,9 @@ class Solution: dp[(i, j)] = 1 + dfs(i + 1, j + 1) else: dp[(i, j)] = max(dfs(i, j + 1), dfs(i + 1, j)) - + return dp[(i, j)] - + return dfs(0, 0) ``` @@ -185,7 +185,8 @@ class Solution { * @return {number} */ maxUncrossedLines(nums1, nums2) { - const n = nums1.length, m = nums2.length; + const n = nums1.length, + m = nums2.length; const dp = Array.from({ length: n }, () => Array(m).fill(-1)); const dfs = (i, j) => { @@ -215,8 +216,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ > Where $n$ and $m$ are the sizes of the arrays $nums1$ and $nums2$ respectively. @@ -238,7 +239,7 @@ class Solution: dp[i + 1][j + 1] = 1 + dp[i][j] else: dp[i + 1][j + 1] = max(dp[i][j + 1], dp[i + 1][j]) - + return dp[n][m] ``` @@ -293,7 +294,8 @@ class Solution { * @return {number} */ maxUncrossedLines(nums1, nums2) { - const n = nums1.length, m = nums2.length; + const n = nums1.length, + m = nums2.length; const dp = Array.from({ length: n + 1 }, () => Array(m + 1).fill(0)); for (let i = 0; i < n; i++) { @@ -315,8 +317,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n * m)$ > Where $n$ and $m$ are the sizes of the arrays $nums1$ and $nums2$ respectively. @@ -419,8 +421,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(m)$ > Where $n$ and $m$ are the sizes of the arrays $nums1$ and $nums2$ respectively. @@ -524,7 +526,8 @@ class Solution { * @return {number} */ maxUncrossedLines(nums1, nums2) { - let n = nums1.length, m = nums2.length; + let n = nums1.length, + m = nums2.length; if (m > n) { [nums1, nums2] = [nums2, nums1]; [n, m] = [m, n]; @@ -554,7 +557,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(min(n, m))$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(min(n, m))$ -> Where $n$ and $m$ are the sizes of the arrays $nums1$ and $nums2$ respectively. \ No newline at end of file +> Where $n$ and $m$ are the sizes of the arrays $nums1$ and $nums2$ respectively. diff --git a/articles/unique-binary-search-trees-ii.md b/articles/unique-binary-search-trees-ii.md new file mode 100644 index 000000000..2f73b472c --- /dev/null +++ b/articles/unique-binary-search-trees-ii.md @@ -0,0 +1,672 @@ +## 1. Recursion + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def generateTrees(self, n: int) -> List[Optional[TreeNode]]: + def generate(left, right): + if left > right: + return [None] + + res = [] + for val in range(left, right + 1): + for leftTree in generate(left, val - 1): + for rightTree in generate(val + 1, right): + root = TreeNode(val, leftTree, rightTree) + res.append(root) + return res + + return generate(1, n) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List generateTrees(int n) { + return generate(1, n); + } + + private List generate(int left, int right) { + List res = new ArrayList<>(); + if (left > right) { + res.add(null); + return res; + } + + for (int val = left; val <= right; val++) { + List leftTrees = generate(left, val - 1); + List rightTrees = generate(val + 1, right); + + for (TreeNode leftTree : leftTrees) { + for (TreeNode rightTree : rightTrees) { + res.add(new TreeNode(val, leftTree, rightTree)); + } + } + } + return res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector generateTrees(int n) { + return generate(1, n); + } + +private: + vector generate(int left, int right) { + if (left > right) return {nullptr}; + + vector res; + for (int val = left; val <= right; val++) { + vector leftTrees = generate(left, val - 1); + vector rightTrees = generate(val + 1, right); + + for (auto& leftTree : leftTrees) { + for (auto& rightTree : rightTrees) { + res.push_back(new TreeNode(val, leftTree, rightTree)); + } + } + } + return res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number} n + * @return {TreeNode[]} + */ + generateTrees(n) { + const generate = (left, right) => { + if (left > right) return [null]; + + let res = []; + for (let val = left; val <= right; val++) { + let leftTrees = generate(left, val - 1); + let rightTrees = generate(val + 1, right); + + for (let leftTree of leftTrees) { + for (let rightTree of rightTrees) { + res.push(new TreeNode(val, leftTree, rightTree)); + } + } + } + return res; + }; + + return generate(1, n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\frac {4 ^ n}{\sqrt {n}})$ +- Space complexity: + - $O(n)$ space for recursion stack. + - $O(\frac {4 ^ n}{\sqrt {n}})$ space for the output. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def generateTrees(self, n: int) -> List[Optional[TreeNode]]: + dp = {} + + def generate(left, right): + if left > right: + return [None] + if (left, right) in dp: + return dp[(left, right)] + + res = [] + for val in range(left, right + 1): + for leftTree in generate(left, val - 1): + for rightTree in generate(val + 1, right): + root = TreeNode(val, leftTree, rightTree) + res.append(root) + + dp[(left, right)] = res + return res + + return generate(1, n) +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + private List[][] dp; + + public List generateTrees(int n) { + dp = new ArrayList[n + 1][n + 1]; + return generate(1, n); + } + + private List generate(int left, int right) { + if (left > right) return Collections.singletonList(null); + if (dp[left][right] != null) return dp[left][right]; + + List res = new ArrayList<>(); + for (int val = left; val <= right; val++) { + for (TreeNode leftTree : generate(left, val - 1)) { + for (TreeNode rightTree : generate(val + 1, right)) { + res.add(new TreeNode(val, leftTree, rightTree)); + } + } + } + return dp[left][right] = res; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector>> dp; + + vector generateTrees(int n) { + dp.resize(n + 1, vector>(n + 1)); + return generate(1, n); + } + +private: + vector generate(int left, int right) { + if (left > right) return {nullptr}; + if (!dp[left][right].empty()) return dp[left][right]; + + vector res; + for (int val = left; val <= right; val++) { + for (auto& leftTree : generate(left, val - 1)) { + for (auto& rightTree : generate(val + 1, right)) { + res.push_back(new TreeNode(val, leftTree, rightTree)); + } + } + } + return dp[left][right] = res; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number} n + * @return {TreeNode[]} + */ + generateTrees(n) { + const dp = Array.from({ length: n + 1 }, () => Array(n + 1).fill(null)); + + const generate = (left, right) => { + if (left > right) return [null]; + if (dp[left][right]) return dp[left][right]; + + let res = []; + for (let val = left; val <= right; val++) { + for (let leftTree of generate(left, val - 1)) { + for (let rightTree of generate(val + 1, right)) { + res.push(new TreeNode(val, leftTree, rightTree)); + } + } + } + return (dp[left][right] = res); + }; + + return generate(1, n); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\frac {4 ^ n}{\sqrt {n}})$ +- Space complexity: + - $O(n)$ space for recursion stack. + - $O(n ^ 2)$ extra space. + - $O(\frac {4 ^ n}{\sqrt {n}})$ space for the output. + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def generateTrees(self, n: int) -> List[Optional[TreeNode]]: + dp = [[[] for _ in range(n + 2)] for _ in range(n + 2)] + for i in range(1, n + 2): + dp[i][i - 1] = [None] + + for length in range(1, n + 1): + for left in range(1, n - length + 2): + right = left + length - 1 + dp[left][right] = [] + for val in range(left, right + 1): + for leftTree in dp[left][val - 1]: + for rightTree in dp[val + 1][right]: + root = TreeNode(val, leftTree, rightTree) + dp[left][right].append(root) + + return dp[1][n] +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List generateTrees(int n) { + List[][] dp = new ArrayList[n + 2][n + 2]; + for (int i = 1; i <= n + 1; i++) { + dp[i][i - 1] = new ArrayList<>(); + dp[i][i - 1].add(null); + } + + for (int length = 1; length <= n; length++) { + for (int left = 1; left + length - 1 <= n; left++) { + int right = left + length - 1; + dp[left][right] = new ArrayList<>(); + + for (int val = left; val <= right; val++) { + for (TreeNode leftTree : dp[left][val - 1]) { + for (TreeNode rightTree : dp[val + 1][right]) { + dp[left][right].add(new TreeNode(val, leftTree, rightTree)); + } + } + } + } + } + return dp[1][n]; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector generateTrees(int n) { + vector>> dp(n + 2, vector>(n + 2)); + for (int i = 1; i <= n + 1; i++) { + dp[i][i - 1].push_back(nullptr); + } + + for (int length = 1; length <= n; length++) { + for (int left = 1; left + length - 1 <= n; left++) { + int right = left + length - 1; + + for (int val = left; val <= right; val++) { + for (auto& leftTree : dp[left][val - 1]) { + for (auto& rightTree : dp[val + 1][right]) { + dp[left][right].push_back(new TreeNode(val, leftTree, rightTree)); + } + } + } + } + } + return dp[1][n]; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number} n + * @return {TreeNode[]} + */ + generateTrees(n) { + const dp = Array.from({ length: n + 2 }, () => Array(n + 2).fill(null)); + for (let i = 1; i <= n + 1; i++) { + dp[i][i - 1] = [null]; + } + + for (let length = 1; length <= n; length++) { + for (let left = 1; left + length - 1 <= n; left++) { + let right = left + length - 1; + dp[left][right] = []; + + for (let val = left; val <= right; val++) { + for (let leftTree of dp[left][val - 1]) { + for (let rightTree of dp[val + 1][right]) { + dp[left][right].push( + new TreeNode(val, leftTree, rightTree), + ); + } + } + } + } + } + return dp[1][n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\frac {4 ^ n}{\sqrt {n}})$ +- Space complexity: + - $O(n ^ 2)$ extra space. + - $O(\frac {4 ^ n}{\sqrt {n}})$ space for the output. + +--- + +## 4. Dynamic Programming (Space Optimized) + +::tabs-start + +```python +# Definition for a binary tree node. +# class TreeNode: +# def __init__(self, val=0, left=None, right=None): +# self.val = val +# self.left = left +# self.right = right +class Solution: + def generateTrees(self, n: int) -> list[Optional[TreeNode]]: + dp = [[] for _ in range(n + 1)] + dp[0] = [None] + + for length in range(1, n + 1): + dp[length] = [] + for val in range(1, length + 1): + for leftTree in dp[val - 1]: + for rightTree in dp[length - val]: + root = TreeNode(val) + root.left = leftTree + root.right = self.shift(rightTree, val) + dp[length].append(root) + + return dp[n] + + def shift(self, node: Optional[TreeNode], offset: int) -> Optional[TreeNode]: + if not node: + return None + root = TreeNode(node.val + offset) + root.left = self.shift(node.left, offset) + root.right = self.shift(node.right, offset) + return root +``` + +```java +/** + * Definition for a binary tree node. + * public class TreeNode { + * int val; + * TreeNode left; + * TreeNode right; + * TreeNode() {} + * TreeNode(int val) { this.val = val; } + * TreeNode(int val, TreeNode left, TreeNode right) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +public class Solution { + public List generateTrees(int n) { + List[] dp = new ArrayList[n + 1]; + dp[0] = new ArrayList<>(); + dp[0].add(null); + + for (int length = 1; length <= n; length++) { + dp[length] = new ArrayList<>(); + for (int val = 1; val <= length; val++) { + for (TreeNode leftTree : dp[val - 1]) { + for (TreeNode rightTree : dp[length - val]) { + TreeNode root = new TreeNode(val); + root.left = leftTree; + root.right = shift(rightTree, val); + dp[length].add(root); + } + } + } + } + return dp[n]; + } + + private TreeNode shift(TreeNode node, int offset) { + if (node == null) return null; + TreeNode root = new TreeNode(node.val + offset); + root.left = shift(node.left, offset); + root.right = shift(node.right, offset); + return root; + } +} +``` + +```cpp +/** + * Definition for a binary tree node. + * struct TreeNode { + * int val; + * TreeNode *left; + * TreeNode *right; + * TreeNode() : val(0), left(nullptr), right(nullptr) {} + * TreeNode(int x) : val(x), left(nullptr), right(nullptr) {} + * TreeNode(int x, TreeNode *left, TreeNode *right) : val(x), left(left), right(right) {} + * }; + */ +class Solution { +public: + vector generateTrees(int n) { + vector> dp(n + 1); + dp[0].push_back(nullptr); + + for (int length = 1; length <= n; length++) { + for (int val = 1; val <= length; val++) { + for (auto& leftTree : dp[val - 1]) { + for (auto& rightTree : dp[length - val]) { + TreeNode* root = new TreeNode(val); + root->left = leftTree; + root->right = shift(rightTree, val); + dp[length].push_back(root); + } + } + } + } + return dp[n]; + } + +private: + TreeNode* shift(TreeNode* node, int offset) { + if (!node) return nullptr; + TreeNode* root = new TreeNode(node->val + offset); + root->left = shift(node->left, offset); + root->right = shift(node->right, offset); + return root; + } +}; +``` + +```javascript +/** + * Definition for a binary tree node. + * class TreeNode { + * constructor(val = 0, left = null, right = null) { + * this.val = val; + * this.left = left; + * this.right = right; + * } + * } + */ +class Solution { + /** + * @param {number} n + * @return {TreeNode[]} + */ + generateTrees(n) { + const shift = (node, offset) => { + if (!node) return null; + let root = new TreeNode(node.val + offset); + root.left = shift(node.left, offset); + root.right = shift(node.right, offset); + return root; + }; + + let dp = Array.from({ length: n + 1 }, () => []); + dp[0].push(null); + + for (let length = 1; length <= n; length++) { + for (let val = 1; val <= length; val++) { + for (let leftTree of dp[val - 1]) { + for (let rightTree of dp[length - val]) { + let root = new TreeNode(val); + root.left = leftTree; + root.right = shift(rightTree, val); + dp[length].push(root); + } + } + } + } + return dp[n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\frac {4 ^ n}{\sqrt {n}})$ +- Space complexity: + - $O(n)$ for the recursion stack. + - $O(n)$ extra space. + - $O(\frac {4 ^ n}{\sqrt {n}})$ space for the output. diff --git a/articles/unique-binary-search-trees.md b/articles/unique-binary-search-trees.md new file mode 100644 index 000000000..af8d05ed0 --- /dev/null +++ b/articles/unique-binary-search-trees.md @@ -0,0 +1,411 @@ +## 1. Recursion + +::tabs-start + +```python +class Solution: + def numTrees(self, n: int) -> int: + if n <= 1: + return 1 + + res = 0 + for i in range(1, n + 1): + res += self.numTrees(i - 1) * self.numTrees(n - i) + return res +``` + +```java +public class Solution { + public int numTrees(int n) { + if (n <= 1) { + return 1; + } + + int res = 0; + for (int i = 1; i <= n; i++) { + res += numTrees(i - 1) * numTrees(n - i); + } + return res; + } +} +``` + +```cpp +class Solution { +public: + int numTrees(int n) { + if (n <= 1) { + return 1; + } + + int res = 0; + for (int i = 1; i <= n; i++) { + res += numTrees(i - 1) * numTrees(n - i); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + numTrees(n) { + if (n <= 1) { + return 1; + } + + let res = 0; + for (let i = 1; i <= n; i++) { + res += this.numTrees(i - 1) * this.numTrees(n - i); + } + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(3 ^ n)$ +- Space complexity: $O(n)$ for recursion stack. + +--- + +## 2. Dynamic Programming (Top-Down) + +::tabs-start + +```python +class Solution: + + def __init__(self): + self.dp = {} + + def numTrees(self, n: int) -> int: + if n <= 1: + return 1 + if n in self.dp: + return self.dp[n] + + res = 0 + for i in range(1, n + 1): + res += self.numTrees(i - 1) * self.numTrees(n - i) + + self.dp[n] = res + return res +``` + +```java +public class Solution { + private Map dp = new HashMap<>(); + + public int numTrees(int n) { + if (n <= 1) { + return 1; + } + if (dp.containsKey(n)) { + return dp.get(n); + } + + int res = 0; + for (int i = 1; i <= n; i++) { + res += numTrees(i - 1) * numTrees(n - i); + } + + dp.put(n, res); + return res; + } +} +``` + +```cpp +class Solution { +private: + unordered_map dp; + +public: + int numTrees(int n) { + if (n <= 1) { + return 1; + } + if (dp.find(n) != dp.end()) { + return dp[n]; + } + + int res = 0; + for (int i = 1; i <= n; i++) { + res += numTrees(i - 1) * numTrees(n - i); + } + + dp[n] = res; + return res; + } +}; +``` + +```javascript +class Solution { + constructor() { + this.dp = new Map(); + } + + /** + * @param {number} n + * @return {number} + */ + numTrees(n) { + if (n <= 1) { + return 1; + } + if (this.dp.has(n)) { + return this.dp.get(n); + } + + let res = 0; + for (let i = 1; i <= n; i++) { + res += this.numTrees(i - 1) * this.numTrees(n - i); + } + + this.dp.set(n, res); + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 3. Dynamic Programming (Bottom-Up) + +::tabs-start + +```python +class Solution: + def numTrees(self, n: int) -> int: + numTree = [1] * (n + 1) + + for nodes in range(2, n + 1): + total = 0 + for root in range(1, nodes + 1): + left = root - 1 + right = nodes - root + total += numTree[left] * numTree[right] + numTree[nodes] = total + + return numTree[n] +``` + +```java +public class Solution { + public int numTrees(int n) { + int[] numTree = new int[n + 1]; + numTree[0] = 1; + numTree[1] = 1; + + for (int nodes = 2; nodes <= n; nodes++) { + int total = 0; + for (int root = 1; root <= nodes; root++) { + int left = root - 1; + int right = nodes - root; + total += numTree[left] * numTree[right]; + } + numTree[nodes] = total; + } + + return numTree[n]; + } +} +``` + +```cpp +class Solution { +public: + int numTrees(int n) { + vector numTree(n + 1, 1); + + for (int nodes = 2; nodes <= n; ++nodes) { + int total = 0; + for (int root = 1; root <= nodes; ++root) { + int left = root - 1; + int right = nodes - root; + total += numTree[left] * numTree[right]; + } + numTree[nodes] = total; + } + + return numTree[n]; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + numTrees(n) { + const numTree = Array(n + 1).fill(1); + + for (let nodes = 2; nodes <= n; nodes++) { + let total = 0; + for (let root = 1; root <= nodes; root++) { + let left = root - 1; + let right = nodes - root; + total += numTree[left] * numTree[right]; + } + numTree[nodes] = total; + } + + return numTree[n]; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ + +--- + +## 4. Catalan Numbers - I + +::tabs-start + +```python +class Solution: + def numTrees(self, n: int) -> int: + res = 1 + for i in range(1, n): + res *= (n + i + 1) + res //= i + return res // n +``` + +```java +public class Solution { + public int numTrees(int n) { + long res = 1; + for (int i = 1; i < n; i++) { + res *= (n + i + 1); + res /= i; + } + return (int) (res / n); + } +} +``` + +```cpp +class Solution { +public: + int numTrees(int n) { + long long res = 1; + for (int i = 1; i < n; i++) { + res *= (n + i + 1); + res /= i; + } + return res / n; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + numTrees(n) { + let res = 1n; + for (let i = 1n; i < BigInt(n); i++) { + res *= BigInt(n) + i + 1n; + res /= i; + } + return Number(res / BigInt(n)); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. + +--- + +## 5. Catalan Numbers - II + +::tabs-start + +```python +class Solution: + def numTrees(self, n: int) -> int: + res = 1 + for i in range(n): + res *= (4 * i + 2) / (i + 2) + return int(res) +``` + +```java +public class Solution { + public int numTrees(int n) { + long res = 1; + for (int i = 0; i < n; i++) { + res *= (4 * i + 2) / (i + 2.0); + } + return (int) res; + } +} +``` + +```cpp +class Solution { +public: + int numTrees(int n) { + long long res = 1; + for (int i = 0; i < n; i++) { + res *= (4 * i + 2) / (i + 2.0); + } + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @return {number} + */ + numTrees(n) { + let res = 1; + for (let i = 0; i < n; i++) { + res *= (4 * i + 2) / (i + 2); + } + return Math.floor(res); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/unique-email-addresses.md b/articles/unique-email-addresses.md index 41aead4ae..5a445cafb 100644 --- a/articles/unique-email-addresses.md +++ b/articles/unique-email-addresses.md @@ -19,12 +19,12 @@ class Solution: public class Solution { public int numUniqueEmails(String[] emails) { Set unique = new HashSet<>(); - + for (String e : emails) { String[] parts = e.split("@"); String local = parts[0]; String domain = parts[1]; - + local = local.split("\\+")[0]; local = local.replace(".", ""); unique.add(local + "@" + domain); @@ -39,13 +39,13 @@ class Solution { public: int numUniqueEmails(vector& emails) { unordered_set unique; - + for (string e : emails) { string local = e.substr(0, e.find('@')); local = local.substr(0, local.find('+')); erase(local, '.'); unique.insert(local + e.substr(e.find('@'))); - } + } return unique.size(); } }; @@ -59,7 +59,7 @@ class Solution { */ numUniqueEmails(emails) { const unique = new Set(); - + for (let e of emails) { let [local, domain] = e.split('@'); local = local.split('+')[0]; @@ -75,8 +75,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n)$ > Where $n$ is the number of strings in the array, and $m$ is the average length of these strings. @@ -97,7 +97,7 @@ class Solution: if e[i] != ".": local += e[i] i += 1 - + while e[i] != "@": i += 1 domain = e[i + 1:] @@ -109,7 +109,7 @@ class Solution: public class Solution { public int numUniqueEmails(String[] emails) { Set unique = new HashSet<>(); - + for (String e : emails) { int i = 0; StringBuilder local = new StringBuilder(); @@ -119,10 +119,10 @@ public class Solution { } i++; } - + while (i < e.length() && e.charAt(i) != '@') { i++; - } + } String domain = e.substring(i + 1); unique.add(local.toString() + "@" + domain); } @@ -136,7 +136,7 @@ class Solution { public: int numUniqueEmails(vector& emails) { unordered_set unique; - + for (string e : emails) { int i = 0; string local = ""; @@ -146,7 +146,7 @@ public: } i++; } - + while (i < e.length() && e[i] != '@') { i++; } @@ -166,16 +166,17 @@ class Solution { */ numUniqueEmails(emails) { const unique = new Set(); - + for (let e of emails) { - let i = 0, local = ""; + let i = 0, + local = ''; while (i < e.length && e[i] !== '@' && e[i] !== '+') { if (e[i] !== '.') { local += e[i]; } i++; } - + while (i < e.length && e[i] !== '@') { i++; } @@ -191,7 +192,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(n)$ -> Where $n$ is the number of strings in the array, and $m$ is the average length of these strings. \ No newline at end of file +> Where $n$ is the number of strings in the array, and $m$ is the average length of these strings. diff --git a/articles/unique-length-3-palindromic-subsequences.md b/articles/unique-length-3-palindromic-subsequences.md index 642af0a41..86dee8403 100644 --- a/articles/unique-length-3-palindromic-subsequences.md +++ b/articles/unique-length-3-palindromic-subsequences.md @@ -94,7 +94,7 @@ class Solution { rec(i + 1, cur + s[i]); }; - rec(0, ""); + rec(0, ''); return res.size; } } @@ -104,10 +104,10 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(2 ^ n)$ -* Space complexity: $O(n + m)$ +- Time complexity: $O(2 ^ n)$ +- Space complexity: $O(n + m)$ -> Where $n$ is the length of the string $s$ and $m$ is the number of unique three length pallindromic subsequences (26 * 26 = 676). +> Where $n$ is the length of the string $s$ and $m$ is the number of unique three length pallindromic subsequences (26 \* 26 = 676). --- @@ -198,10 +198,10 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n ^ 3)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(m)$ -> Where $n$ is the length of the string $s$ and $m$ is the number of unique three length pallindromic subsequences (26 * 26 = 676). +> Where $n$ is the length of the string $s$ and $m$ is the number of unique three length pallindromic subsequences (26 \* 26 = 676). --- @@ -288,10 +288,12 @@ class Solution { let res = 0; for (let ends = 'a'.charCodeAt(0); ends <= 'z'.charCodeAt(0); ends++) { for (let mid = 'a'.charCodeAt(0); mid <= 'z'.charCodeAt(0); mid++) { - const seq = String.fromCharCode(ends) + - String.fromCharCode(mid) + - String.fromCharCode(ends); - let idx = 0, found = 0; + const seq = + String.fromCharCode(ends) + + String.fromCharCode(mid) + + String.fromCharCode(ends); + let idx = 0, + found = 0; for (const c of s) { if (seq[idx] === c) { idx++; @@ -313,10 +315,10 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n * m)$ +- Space complexity: $O(1)$ -> Where $n$ is the length of the string $s$ and $m$ is the number of unique three length pallindromic subsequences (26 * 26 = 676). +> Where $n$ is the length of the string $s$ and $m$ is the number of unique three length pallindromic subsequences (26 \* 26 = 676). --- @@ -330,18 +332,18 @@ class Solution: res = set() left = set() right = collections.Counter(s) - + for i in range(len(s)): right[s[i]] -= 1 if right[s[i]] == 0: right.pop(s[i]) - + for j in range(26): c = chr(ord('a') + j) if c in left and c in right: res.add((s[i], c)) left.add(s[i]) - + return len(res) ``` @@ -447,10 +449,10 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(26 * n)$ -* Space complexity: $O(m)$ +- Time complexity: $O(26 * n)$ +- Space complexity: $O(m)$ -> Where $n$ is the length of the string $s$ and $m$ is the number of unique three length pallindromic subsequences (26 * 26 = 676). +> Where $n$ is the length of the string $s$ and $m$ is the number of unique three length pallindromic subsequences (26 \* 26 = 676). --- @@ -586,10 +588,14 @@ class Solution { let res = 0; for (let ends = 0; ends < 26; ends++) { - if (firstIndex[ends] === -1 || firstIndex[ends] === lastIndex[ends]) { + if ( + firstIndex[ends] === -1 || + firstIndex[ends] === lastIndex[ends] + ) { continue; } - const l = firstIndex[ends], r = lastIndex[ends]; + const l = firstIndex[ends], + r = lastIndex[ends]; for (let mid = 0; mid < 26; mid++) { if (prefix[r][mid] - prefix[l + 1][mid] > 0) { res++; @@ -605,8 +611,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(26 * n)$ -* Space complexity: $O(26 * n)$ +- Time complexity: $O(26 * n)$ +- Space complexity: $O(26 * n)$ --- @@ -624,12 +630,12 @@ class Solution: l, r = s.find(c), s.rfind(c) if l == -1 or l == r: continue - + mids = set() for j in range(l + 1, r): mids.add(s[j]) res += len(mids) - + return res ``` @@ -648,7 +654,7 @@ public class Solution { } res += mids.size(); } - + return res; } } @@ -670,7 +676,7 @@ public: } res += mids.size(); } - + return res; } }; @@ -687,7 +693,8 @@ class Solution { for (let i = 0; i < 26; i++) { const c = String.fromCharCode('a'.charCodeAt(0) + i); - const l = s.indexOf(c), r = s.lastIndexOf(c); + const l = s.indexOf(c), + r = s.lastIndexOf(c); if (l === -1 || l === r) continue; const mids = new Set(); @@ -706,8 +713,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(26 * n)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. +- Time complexity: $O(26 * n)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. --- @@ -836,17 +843,21 @@ class Solution { let res = 0; for (let ends = 0; ends < 26; ends++) { - if (firstIndex[ends] === -1 || firstIndex[ends] === lastIndex[ends]) { + if ( + firstIndex[ends] === -1 || + firstIndex[ends] === lastIndex[ends] + ) { continue; } - const l = firstIndex[ends], r = lastIndex[ends]; + const l = firstIndex[ends], + r = lastIndex[ends]; let mask = 0; for (let i = l + 1; i < r; i++) { const c = s.charCodeAt(i) - 'a'.charCodeAt(0); if (mask & (1 << c)) { continue; } - mask |= (1 << c); + mask |= 1 << c; res++; } } @@ -859,5 +870,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(26 * n)$ -* Space complexity: $O(1)$ since we have at most $26$ different characters. \ No newline at end of file +- Time complexity: $O(26 * n)$ +- Space complexity: $O(1)$ since we have at most $26$ different characters. diff --git a/articles/unique-paths-ii.md b/articles/unique-paths-ii.md index 35178ff44..e4eee8a98 100644 --- a/articles/unique-paths-ii.md +++ b/articles/unique-paths-ii.md @@ -86,7 +86,8 @@ class Solution { * @return {number} */ uniquePathsWithObstacles(grid) { - const M = grid.length, N = grid[0].length; + const M = grid.length, + N = grid[0].length; const dp = Array.from({ length: M }, () => Array(N).fill(-1)); const dfs = (r, c) => { @@ -108,12 +109,43 @@ class Solution { } ``` +```csharp +public class Solution { + private int[,] dp; + + public int UniquePathsWithObstacles(int[][] grid) { + int M = grid.Length, N = grid[0].Length; + dp = new int[M, N]; + for (int i = 0; i < M; i++) { + for (int j = 0; j < N; j++) { + dp[i, j] = -1; + } + } + return Dfs(0, 0, grid, M, N); + } + + private int Dfs(int r, int c, int[][] grid, int M, int N) { + if (r == M || c == N || grid[r][c] == 1) { + return 0; + } + if (r == M - 1 && c == N - 1) { + return 1; + } + if (dp[r, c] != -1) { + return dp[r, c]; + } + dp[r, c] = Dfs(r + 1, c, grid, M, N) + Dfs(r, c + 1, grid, M, N); + return dp[r, c]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns. @@ -207,7 +239,8 @@ class Solution { * @return {number} */ uniquePathsWithObstacles(grid) { - const M = grid.length, N = grid[0].length; + const M = grid.length, + N = grid[0].length; if (grid[0][0] === 1 || grid[M - 1][N - 1] === 1) { return 0; } @@ -231,12 +264,39 @@ class Solution { } ``` +```csharp +public class Solution { + public int UniquePathsWithObstacles(int[][] grid) { + int M = grid.Length, N = grid[0].Length; + if (grid[0][0] == 1 || grid[M - 1][N - 1] == 1) { + return 0; + } + + int[,] dp = new int[M + 1, N + 1]; + dp[M - 1, N - 1] = 1; + + for (int r = M - 1; r >= 0; r--) { + for (int c = N - 1; c >= 0; c--) { + if (grid[r][c] == 1) { + dp[r, c] = 0; + } else { + dp[r, c] += dp[r + 1, c]; + dp[r, c] += dp[r, c + 1]; + } + } + } + + return dp[0, 0]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(m * n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(m * n)$ > Where $m$ is the number of rows and $n$ is the number of columns. @@ -259,7 +319,7 @@ class Solution: dp[c] = 0 else: dp[c] += dp[c + 1] - + return dp[0] ``` @@ -315,7 +375,8 @@ class Solution { * @return {number} */ uniquePathsWithObstacles(grid) { - const M = grid.length, N = grid[0].length; + const M = grid.length, + N = grid[0].length; const dp = new Array(N + 1).fill(0); dp[N - 1] = 1; @@ -334,12 +395,34 @@ class Solution { } ``` +```csharp +public class Solution { + public int UniquePathsWithObstacles(int[][] grid) { + int M = grid.Length, N = grid[0].Length; + int[] dp = new int[N + 1]; + dp[N - 1] = 1; + + for (int r = M - 1; r >= 0; r--) { + for (int c = N - 1; c >= 0; c--) { + if (grid[r][c] == 1) { + dp[c] = 0; + } else { + dp[c] += dp[c + 1]; + } + } + } + + return dp[0]; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(m * n)$ +- Space complexity: $O(n)$ > Where $m$ is the number of rows and $n$ is the number of columns. @@ -355,9 +438,9 @@ class Solution: M, N = len(grid), len(grid[0]) if grid[0][0] == 1 or grid[M - 1][N - 1] == 1: return 0 - + grid[M - 1][N - 1] = 1 - + for r in range(M - 1, -1, -1): for c in range(N - 1, -1, -1): if r == M - 1 and c == N - 1: @@ -369,7 +452,7 @@ class Solution: down = grid[r + 1][c] if r + 1 < M else 0 right = grid[r][c + 1] if c + 1 < N else 0 grid[r][c] = down + right - + return grid[0][0] ``` @@ -443,7 +526,8 @@ class Solution { * @return {number} */ uniquePathsWithObstacles(grid) { - const M = grid.length, N = grid[0].length; + const M = grid.length, + N = grid[0].length; if (grid[0][0] === 1 || grid[M - 1][N - 1] === 1) { return 0; } @@ -459,8 +543,39 @@ class Solution { if (grid[r][c] === 1) { grid[r][c] = 0; } else { - const down = (r + 1 < M) ? grid[r + 1][c] : 0; - const right = (c + 1 < N) ? grid[r][c + 1] : 0; + const down = r + 1 < M ? grid[r + 1][c] : 0; + const right = c + 1 < N ? grid[r][c + 1] : 0; + grid[r][c] = down + right; + } + } + } + + return grid[0][0]; + } +} +``` + +```csharp +public class Solution { + public int UniquePathsWithObstacles(int[][] grid) { + int M = grid.Length, N = grid[0].Length; + if (grid[0][0] == 1 || grid[M - 1][N - 1] == 1) { + return 0; + } + + grid[M - 1][N - 1] = 1; + + for (int r = M - 1; r >= 0; r--) { + for (int c = N - 1; c >= 0; c--) { + if (r == M - 1 && c == N - 1) { + continue; + } + + if (grid[r][c] == 1) { + grid[r][c] = 0; + } else { + int down = (r + 1 < M) ? grid[r + 1][c] : 0; + int right = (c + 1 < N) ? grid[r][c + 1] : 0; grid[r][c] = down + right; } } @@ -475,7 +590,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m * n)$ -* Space complexity: $O(1)$ extra space. +- Time complexity: $O(m * n)$ +- Space complexity: $O(1)$ extra space. -> Where $m$ is the number of rows and $n$ is the number of columns. \ No newline at end of file +> Where $m$ is the number of rows and $n$ is the number of columns. diff --git a/articles/valid-binary-search-tree.md b/articles/valid-binary-search-tree.md index fd885ddfc..8405b5be4 100644 --- a/articles/valid-binary-search-tree.md +++ b/articles/valid-binary-search-tree.md @@ -11,17 +11,17 @@ # self.right = right class Solution: - left_check = staticmethod(lambda val, limit: val < limit) - right_check = staticmethod(lambda val, limit: val > limit) + left_check = staticmethod(lambda val, limit: val < limit) + right_check = staticmethod(lambda val, limit: val > limit) def isValidBST(self, root: Optional[TreeNode]) -> bool: if not root: return True - + if (not self.isValid(root.left, root.val, self.left_check) or not self.isValid(root.right, root.val, self.right_check)): return False - + return self.isValidBST(root.left) and self.isValidBST(root.right) def isValid(self, root: Optional[TreeNode], limit: int, check) -> bool: @@ -52,11 +52,11 @@ class Solution: public class Solution { static boolean left_check(int val, int limit) { - return val < limit; + return val < limit; } static boolean right_check(int val, int limit) { - return val > limit; + return val > limit; } public boolean isValidBST(TreeNode root) { @@ -64,7 +64,7 @@ public class Solution { return true; } - if (!isValid(root.left, root.val, Solution::left_check) || + if (!isValid(root.left, root.val, Solution::left_check) || !isValid(root.right, root.val, Solution::right_check)) { return false; } @@ -79,10 +79,10 @@ public class Solution { if (!check.apply(root.val, limit)) { return false; } - return isValid(root.left, limit, check) && + return isValid(root.left, limit, check) && isValid(root.right, limit, check); } - + interface CheckFunction { boolean apply(int val, int limit); } @@ -117,7 +117,7 @@ public: return true; } - if (!isValid(root->left, root->val, left_check) || + if (!isValid(root->left, root->val, left_check) || !isValid(root->right, root->val, right_check)) { return false; } @@ -132,7 +132,7 @@ public: if (!check(root->val, limit)) { return false; } - return isValid(root->left, limit, check) && + return isValid(root->left, limit, check) && isValid(root->right, limit, check); } }; @@ -178,8 +178,10 @@ class Solution { return true; } - if (!this.isValid(root.left, root.val, this.left_check) || - !this.isValid(root.right, root.val, this.right_check)) { + if ( + !this.isValid(root.left, root.val, this.left_check) || + !this.isValid(root.right, root.val, this.right_check) + ) { return false; } @@ -199,8 +201,10 @@ class Solution { if (!check.call(this, root.val, limit)) { return false; } - return this.isValid(root.left, limit, check) && - this.isValid(root.right, limit, check); + return ( + this.isValid(root.left, limit, check) && + this.isValid(root.right, limit, check) + ); } } ``` @@ -222,11 +226,11 @@ class Solution { public class Solution { static bool LeftCheck(int val, int limit) { - return val < limit; + return val < limit; } static bool RightCheck(int val, int limit) { - return val > limit; + return val > limit; } public bool IsValidBST(TreeNode root) { @@ -234,7 +238,7 @@ public class Solution { return true; } - if (!IsValid(root.left, root.val, LeftCheck) || + if (!IsValid(root.left, root.val, LeftCheck) || !IsValid(root.right, root.val, RightCheck)) { return false; } @@ -249,7 +253,7 @@ public class Solution { if (!check(root.val, limit)) { return false; } - return IsValid(root.left, limit, check) && + return IsValid(root.left, limit, check) && IsValid(root.right, limit, check); } } @@ -316,12 +320,50 @@ class Solution { } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isValidBST(_ root: TreeNode?) -> Bool { + guard let root = root else { return true } + if !isValid(root.left, root.val, { $0 < $1 }) || + !isValid(root.right, root.val, { $0 > $1 }) { + return false + } + + return isValidBST(root.left) && isValidBST(root.right) + } + + private func isValid(_ root: TreeNode?, _ limit: Int, _ check: (Int, Int) -> Bool) -> Bool { + guard let root = root else { return true } + if !check(root.val, limit) { + return false + } + + return isValid(root.left, limit, check) && isValid(root.right, limit, check) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -381,7 +423,7 @@ public class Solution { if (!(left < node.val && node.val < right)) { return false; } - return valid(node.left, left, node.val) && + return valid(node.left, left, node.val) && valid(node.right, node.val, right); } } @@ -452,8 +494,10 @@ class Solution { if (!(left < node.val && node.val < right)) { return false; } - return this.valid(node.left, left, node.val) && - this.valid(node.right, node.val, right); + return ( + this.valid(node.left, left, node.val) && + this.valid(node.right, node.val, right) + ); } } ``` @@ -508,12 +552,12 @@ func valid(node *TreeNode, left, right int64) bool { if node == nil { return true } - + val := int64(node.Val) if val <= left || val >= right { return false } - + return valid(node.Left, left, val) && valid(node.Right, val, right) } ``` @@ -533,29 +577,60 @@ class Solution { fun isValidBST(root: TreeNode?): Boolean { return valid(root, Long.MIN_VALUE, Long.MAX_VALUE) } - + private fun valid(node: TreeNode?, left: Long, right: Long): Boolean { if (node == null) { return true } - + val value = node.`val`.toLong() if (value <= left || value >= right) { return false } - - return valid(node.left, left, value) && + + return valid(node.left, left, value) && valid(node.right, value, right) } } ``` +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isValidBST(_ root: TreeNode?) -> Bool { + return valid(root, Int.min, Int.max) + } + + private func valid(_ node: TreeNode?, _ left: Int, _ right: Int) -> Bool { + guard let node = node else { return true } + if !(left < node.val && node.val < right) { + return false + } + return valid(node.left, left, node.val) && valid(node.right, node.val, right) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -708,7 +783,7 @@ class Solution { while (queue.size() > 0) { const [node, left, right] = queue.pop(); - + if (!(left < node.val && node.val < right)) { return false; } @@ -787,18 +862,18 @@ func isValidBST(root *TreeNode) bool { if root == nil { return true } - + queue := []QueueItem{{root, math.MinInt64, math.MaxInt64}} - + for len(queue) > 0 { item := queue[0] queue = queue[1:] - + val := int64(item.node.Val) if val <= item.left || val >= item.right { return false } - + if item.node.Left != nil { queue = append(queue, QueueItem{item.node.Left, item.left, val}) } @@ -806,7 +881,7 @@ func isValidBST(root *TreeNode) bool { queue = append(queue, QueueItem{item.node.Right, val, item.right}) } } - + return true } ``` @@ -828,31 +903,73 @@ class Solution { val left: Long, val right: Long ) - + fun isValidBST(root: TreeNode?): Boolean { if (root == null) { return true } - + val queue = ArrayDeque() queue.addLast(QueueItem(root, Long.MIN_VALUE, Long.MAX_VALUE)) - + while (queue.isNotEmpty()) { val (node, left, right) = queue.removeFirst() - + val value = node.`val`.toLong() if (value <= left || value >= right) { return false } - - node.left?.let { + + node.left?.let { queue.addLast(QueueItem(it, left, value)) } node.right?.let { queue.addLast(QueueItem(it, value, right)) } } - + + return true + } +} +``` + +```swift +/** + * Definition for a binary tree node. + * public class TreeNode { + * public var val: Int + * public var left: TreeNode? + * public var right: TreeNode? + * public init() { self.val = 0; self.left = nil; self.right = nil; } + * public init(_ val: Int) { self.val = val; self.left = nil; self.right = nil; } + * public init(_ val: Int, _ left: TreeNode?, _ right: TreeNode?) { + * self.val = val + * self.left = left + * self.right = right + * } + * } + */ +class Solution { + func isValidBST(_ root: TreeNode?) -> Bool { + guard let root = root else { return true } + + var q = Deque<(TreeNode, Int, Int)>() + q.append((root, Int.min, Int.max)) + + while !q.isEmpty { + let (node, left, right) = q.popFirst()! + + if !(left < node.val && node.val < right) { + return false + } + + if let leftNode = node.left { + q.append((leftNode, left, node.val)) + } + if let rightNode = node.right { + q.append((rightNode, node.val, right)) + } + } return true } } @@ -862,5 +979,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/valid-palindrome-ii.md b/articles/valid-palindrome-ii.md index 05367b687..0fdce66b1 100644 --- a/articles/valid-palindrome-ii.md +++ b/articles/valid-palindrome-ii.md @@ -7,12 +7,12 @@ class Solution: def validPalindrome(self, s: str) -> bool: if s == s[::-1]: return True - + for i in range(len(s)): newS = s[:i] + s[i + 1:] if newS == newS[::-1]: return True - + return False ``` @@ -106,7 +106,8 @@ class Solution { * @return {boolean} */ isPalindrome(s) { - let left = 0, right = s.length - 1; + let left = 0, + right = s.length - 1; while (left < right) { if (s[left] !== s[right]) { return false; @@ -119,12 +120,37 @@ class Solution { } ``` +```csharp +public class Solution { + public bool ValidPalindrome(string s) { + if (IsPalindrome(s)) return true; + + for (int i = 0; i < s.Length; i++) { + string newS = s.Substring(0, i) + s.Substring(i + 1); + if (IsPalindrome(newS)) return true; + } + + return false; + } + + private bool IsPalindrome(string str) { + int left = 0, right = str.Length - 1; + while (left < right) { + if (str[left] != str[right]) return false; + left++; + right--; + } + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -154,7 +180,7 @@ public class Solution { while (l < r) { if (s.charAt(l) != s.charAt(r)) { - return isPalindrome(s.substring(0, l) + s.substring(l + 1)) || + return isPalindrome(s.substring(0, l) + s.substring(l + 1)) || isPalindrome(s.substring(0, r) + s.substring(r + 1)); } l++; @@ -186,7 +212,7 @@ public: while (l < r) { if (s[l] != s[r]) { - return isPalindrome(s.substr(0, l) + s.substr(l + 1)) || + return isPalindrome(s.substr(0, l) + s.substr(l + 1)) || isPalindrome(s.substr(0, r) + s.substr(r + 1)); } l++; @@ -218,12 +244,15 @@ class Solution { * @return {boolean} */ validPalindrome(s) { - let l = 0, r = s.length - 1; + let l = 0, + r = s.length - 1; while (l < r) { if (s[l] !== s[r]) { - return this.isPalindrome(s.slice(0, l) + s.slice(l + 1)) || - this.isPalindrome(s.slice(0, r) + s.slice(r + 1)); + return ( + this.isPalindrome(s.slice(0, l) + s.slice(l + 1)) || + this.isPalindrome(s.slice(0, r) + s.slice(r + 1)) + ); } l++; r--; @@ -237,7 +266,8 @@ class Solution { * @return {boolean} */ isPalindrome(s) { - let left = 0, right = s.length - 1; + let left = 0, + right = s.length - 1; while (left < right) { if (s[left] !== s[right]) { return false; @@ -250,12 +280,42 @@ class Solution { } ``` +```csharp +public class Solution { + public bool ValidPalindrome(string s) { + int l = 0, r = s.Length - 1; + + while (l < r) { + if (s[l] != s[r]) { + string skipL = s.Substring(l + 1, r - l); + string skipR = s.Substring(l, r - l); + return IsPalindrome(skipL) || IsPalindrome(skipR); + } + l++; + r--; + } + + return true; + } + + private bool IsPalindrome(string str) { + int left = 0, right = str.Length - 1; + while (left < right) { + if (str[left] != str[right]) return false; + left++; + right--; + } + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -277,7 +337,7 @@ class Solution: l, r = 0, len(s) - 1 while l < r: if s[l] != s[r]: - return (is_palindrome(l + 1, r) or + return (is_palindrome(l + 1, r) or is_palindrome(l, r - 1)) l += 1 r -= 1 @@ -292,7 +352,7 @@ public class Solution { while (l < r) { if (s.charAt(l) != s.charAt(r)) { - return isPalindrome(s, l + 1, r) || + return isPalindrome(s, l + 1, r) || isPalindrome(s, l, r - 1); } l++; @@ -323,7 +383,7 @@ public: while (l < r) { if (s[l] != s[r]) { - return isPalindrome(s, l + 1, r) || + return isPalindrome(s, l + 1, r) || isPalindrome(s, l, r - 1); } l++; @@ -354,12 +414,15 @@ class Solution { * @return {boolean} */ validPalindrome(s) { - let l = 0, r = s.length - 1; + let l = 0, + r = s.length - 1; while (l < r) { if (s[l] !== s[r]) { - return this.isPalindrome(s, l + 1, r) || - this.isPalindrome(s, l, r - 1); + return ( + this.isPalindrome(s, l + 1, r) || + this.isPalindrome(s, l, r - 1) + ); } l++; r--; @@ -387,9 +450,35 @@ class Solution { } ``` +```csharp +public class Solution { + public bool ValidPalindrome(string s) { + bool IsPalindrome(int l, int r) { + while (l < r) { + if (s[l] != s[r]) return false; + l++; + r--; + } + return true; + } + + int left = 0, right = s.Length - 1; + while (left < right) { + if (s[left] != s[right]) { + return IsPalindrome(left + 1, right) || IsPalindrome(left, right - 1); + } + left++; + right--; + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/valid-parenthesis-string.md b/articles/valid-parenthesis-string.md index 84c0422d8..dceb4b217 100644 --- a/articles/valid-parenthesis-string.md +++ b/articles/valid-parenthesis-string.md @@ -5,13 +5,13 @@ ```python class Solution: def checkValidString(self, s: str) -> bool: - + def dfs(i, open): if open < 0: return False if i == len(s): return open == 0 - + if s[i] == '(': return dfs(i + 1, open + 1) elif s[i] == ')': @@ -26,7 +26,7 @@ class Solution: ```java public class Solution { public boolean checkValidString(String s) { - + return dfs(0, 0, s); } @@ -88,9 +88,11 @@ class Solution { } else if (s[i] === ')') { return dfs(i + 1, open - 1); } else { - return dfs(i + 1, open) || - dfs(i + 1, open + 1) || - dfs(i + 1, open - 1); + return ( + dfs(i + 1, open) || + dfs(i + 1, open + 1) || + dfs(i + 1, open - 1) + ); } } @@ -138,8 +140,8 @@ func checkValidString(s string) bool { } else if s[i] == ')' { return dfs(i+1, open-1) } else { - return (dfs(i+1, open) || - dfs(i+1, open+1) || + return (dfs(i+1, open) || + dfs(i+1, open+1) || dfs(i+1, open-1)) } } @@ -148,15 +150,60 @@ func checkValidString(s string) bool { ``` ```kotlin +class Solution { + fun checkValidString(s: String): Boolean { + + fun dfs(i: Int, open: Int): Boolean { + if (open < 0) { + return false + } + if (i == s.length) { + return open == 0 + } + + return when (s[i]) { + '(' -> dfs(i + 1, open + 1) + ')' -> dfs(i + 1, open - 1) + else -> dfs(i + 1, open) || dfs(i + 1, open + 1) || dfs(i + 1, open - 1) + } + } + + return dfs(0, 0) + } +} +``` + +```swift +class Solution { + func checkValidString(_ s: String) -> Bool { + let chars = Array(s) + + func dfs(_ i: Int, _ open: Int) -> Bool { + if open < 0 { return false } + if i == chars.count { return open == 0 } + + if chars[i] == "(" { + return dfs(i + 1, open + 1) + } else if chars[i] == ")" { + return dfs(i + 1, open - 1) + } else { + return dfs(i + 1, open) || + dfs(i + 1, open + 1) || + dfs(i + 1, open - 1) + } + } + return dfs(0, 0) + } +} ``` ::tabs-end ### Time & Space Complexity -* Time complexity: $O(3 ^ n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(3 ^ n)$ +- Space complexity: $O(n)$ --- @@ -177,16 +224,16 @@ class Solution: return open == 0 if memo[i][open] is not None: return memo[i][open] - + if s[i] == '(': result = dfs(i + 1, open + 1) elif s[i] == ')': result = dfs(i + 1, open - 1) else: - result = (dfs(i + 1, open) or - dfs(i + 1, open + 1) or + result = (dfs(i + 1, open) or + dfs(i + 1, open + 1) or dfs(i + 1, open - 1)) - + memo[i][open] = result return result @@ -213,11 +260,11 @@ public class Solution { } else if (s.charAt(i) == ')') { result = dfs(i + 1, open - 1, s, memo); } else { - result = (dfs(i + 1, open, s, memo) || - dfs(i + 1, open + 1, s, memo) || + result = (dfs(i + 1, open, s, memo) || + dfs(i + 1, open + 1, s, memo) || dfs(i + 1, open - 1, s, memo)); } - + memo[i][open] = result; return result; } @@ -248,11 +295,11 @@ private: } else if (s[i] == ')') { result = dfs(i + 1, open - 1, s); } else { - result = (dfs(i + 1, open, s) || - dfs(i + 1, open + 1, s) || + result = (dfs(i + 1, open, s) || + dfs(i + 1, open + 1, s) || dfs(i + 1, open - 1, s)); } - + memo[i][open] = result ? 1 : 0; return result; } @@ -267,8 +314,9 @@ class Solution { */ checkValidString(s) { const n = s.length; - const memo = Array.from({ length: n + 1 }, () => - Array(n + 1).fill(null)); + const memo = Array.from({ length: n + 1 }, () => + Array(n + 1).fill(null), + ); function dfs(i, open) { if (open < 0) return false; @@ -282,11 +330,12 @@ class Solution { } else if (s[i] === ')') { result = dfs(i + 1, open - 1); } else { - result = dfs(i + 1, open) || - dfs(i + 1, open + 1) || - dfs(i + 1, open - 1); + result = + dfs(i + 1, open) || + dfs(i + 1, open + 1) || + dfs(i + 1, open - 1); } - + memo[i][open] = result; return result; } @@ -316,8 +365,8 @@ public class Solution { } else if (s[i] == ')') { result = Dfs(i + 1, open - 1, s, memo); } else { - result = Dfs(i + 1, open, s, memo) || - Dfs(i + 1, open + 1, s, memo) || + result = Dfs(i + 1, open, s, memo) || + Dfs(i + 1, open + 1, s, memo) || Dfs(i + 1, open - 1, s, memo); } @@ -355,8 +404,8 @@ func checkValidString(s string) bool { } else if s[i] == ')' { result = dfs(i+1, open-1) } else { - result = (dfs(i+1, open) || - dfs(i+1, open+1) || + result = (dfs(i+1, open) || + dfs(i+1, open+1) || dfs(i+1, open-1)) } @@ -383,8 +432,8 @@ class Solution { val result = when (s[i]) { '(' -> dfs(i + 1, open + 1) ')' -> dfs(i + 1, open - 1) - else -> (dfs(i + 1, open) || - dfs(i + 1, open + 1) || + else -> (dfs(i + 1, open) || + dfs(i + 1, open + 1) || dfs(i + 1, open - 1)) } @@ -397,12 +446,53 @@ class Solution { } ``` +```swift +class Solution { + func checkValidString(_ s: String) -> Bool { + let n = s.count + let sArr = Array(s) + var memo = Array( + repeating: Array(repeating: nil, count: n + 1), + count: n + 1 + ) + + func dfs(_ i: Int, _ open: Int) -> Bool { + if open < 0 { + return false + } + if i == n { + return open == 0 + } + if let memoized = memo[i][open] { + return memoized + } + + let result: Bool + if sArr[i] == "(" { + result = dfs(i + 1, open + 1) + } else if sArr[i] == ")" { + result = dfs(i + 1, open - 1) + } else { + result = dfs(i + 1, open) || + dfs(i + 1, open + 1) || + dfs(i + 1, open - 1) + } + + memo[i][open] = result + return result + } + + return dfs(0, 0) + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -502,8 +592,9 @@ class Solution { */ checkValidString(s) { const n = s.length; - const dp = Array.from({ length: n + 1 }, () => - Array(n + 1).fill(false)); + const dp = Array.from({ length: n + 1 }, () => + Array(n + 1).fill(false), + ); dp[n][0] = true; for (let i = n - 1; i >= 0; i--) { @@ -620,12 +711,46 @@ class Solution { } ``` +```swift +class Solution { + func checkValidString(_ s: String) -> Bool { + let n = s.count + var dp = Array(repeating: Array(repeating: false, count: n + 1), count: n + 1) + dp[n][0] = true + + let chars = Array(s) + + for i in stride(from: n - 1, through: 0, by: -1) { + for open in 0.. 0 { + res = res || dp[i + 1][open - 1] + } + res = res || dp[i + 1][open] + } else { + if chars[i] == "(" { + res = res || dp[i + 1][open + 1] + } else if open > 0 { + res = res || dp[i + 1][open - 1] + } + } + dp[i][open] = res + } + } + + return dp[0][0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -644,8 +769,8 @@ class Solution: new_dp = [False] * (n + 1) for open in range(n): if s[i] == '*': - new_dp[open] = (dp[open + 1] or - (open > 0 and dp[open - 1]) or + new_dp[open] = (dp[open + 1] or + (open > 0 and dp[open - 1]) or dp[open]) elif s[i] == '(': new_dp[open] = dp[open + 1] @@ -667,7 +792,7 @@ public class Solution { boolean[] newDp = new boolean[n + 1]; for (int open = 0; open < n; open++) { if (s.charAt(i) == '*') { - newDp[open] = dp[open + 1] || + newDp[open] = dp[open + 1] || (open > 0 && dp[open - 1]) || dp[open]; } else if (s.charAt(i) == '(') { newDp[open] = dp[open + 1]; @@ -694,7 +819,7 @@ public: vector newDp(n + 1, false); for (int open = 0; open < n; ++open) { if (s[i] == '*') { - newDp[open] = dp[open + 1] || + newDp[open] = dp[open + 1] || (open > 0 && dp[open - 1]) || dp[open]; } else if (s[i] == '(') { newDp[open] = dp[open + 1]; @@ -724,8 +849,8 @@ class Solution { const newDp = Array(n + 1).fill(false); for (let open = 0; open < n; open++) { if (s[i] === '*') { - newDp[open] = dp[open + 1] || - (open > 0 && dp[open - 1]) || dp[open]; + newDp[open] = + dp[open + 1] || (open > 0 && dp[open - 1]) || dp[open]; } else if (s[i] === '(') { newDp[open] = dp[open + 1]; } else if (open > 0) { @@ -750,7 +875,7 @@ public class Solution { bool[] newDp = new bool[n + 1]; for (int open = 0; open < n; open++) { if (s[i] == '*') { - newDp[open] = dp[open + 1] || + newDp[open] = dp[open + 1] || (open > 0 && dp[open - 1]) || dp[open]; } else if (s[i] == '(') { newDp[open] = dp[open + 1]; @@ -775,8 +900,8 @@ func checkValidString(s string) bool { newDp := make([]bool, n+1) for open := 0; open < n; open++ { if s[i] == '*' { - newDp[open] = (dp[open+1] || - (open > 0 && dp[open-1]) || + newDp[open] = (dp[open+1] || + (open > 0 && dp[open-1]) || dp[open]) } else if s[i] == '(' { newDp[open] = dp[open+1] @@ -801,8 +926,8 @@ class Solution { val newDp = BooleanArray(n + 1) for (open in 0 until n) { newDp[open] = when (s[i]) { - '*' -> (dp[open + 1] || - (open > 0 && dp[open - 1]) || + '*' -> (dp[open + 1] || + (open > 0 && dp[open - 1]) || dp[open]) '(' -> dp[open + 1] else -> open > 0 && dp[open - 1] @@ -815,12 +940,40 @@ class Solution { } ``` +```swift +class Solution { + func checkValidString(_ s: String) -> Bool { + let n = s.count + var dp = Array(repeating: false, count: n + 1) + dp[0] = true + + let chars = Array(s) + + for i in stride(from: n - 1, through: 0, by: -1) { + var new_dp = Array(repeating: false, count: n + 1) + for open in 0.. 0 && dp[open - 1]) || dp[open] + } else if chars[i] == "(" { + new_dp[open] = dp[open + 1] + } else if open > 0 { + new_dp[open] = dp[open - 1] + } + } + dp = new_dp + } + + return dp[0] + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -845,7 +998,7 @@ class Solution: left.pop() else: star.pop() - + while left and star: if left.pop() > star.pop(): return False @@ -869,11 +1022,11 @@ public class Solution { left.pop(); } else{ star.pop(); - } + } } } while (!left.isEmpty() && !star.isEmpty()) { - if (left.pop() > star.pop()) + if (left.pop() > star.pop()) return false; } return left.isEmpty(); @@ -900,7 +1053,7 @@ public: } } } - + while (!left.empty() && !star.empty()) { if (left.top() > star.top()) return false; left.pop(); @@ -937,7 +1090,7 @@ class Solution { } } } - + while (left.length > 0 && star.length > 0) { if (left.pop() > star.pop()) return false; } @@ -966,7 +1119,7 @@ public class Solution { } } } - + while (left.Count > 0 && star.Count > 0) { if (left.Pop() > star.Pop()) return false; } @@ -1034,12 +1187,50 @@ class Solution { } ``` +```swift +class Solution { + func checkValidString(_ s: String) -> Bool { + var left = [Int]() + var star = [Int]() + + let chars = Array(s) + + for (i, ch) in chars.enumerated() { + if ch == "(" { + left.append(i) + } else if ch == "*" { + star.append(i) + } else { + if left.isEmpty && star.isEmpty { + return false + } + if !left.isEmpty { + left.popLast() + } else { + star.popLast() + } + } + } + + while !left.isEmpty && !star.isEmpty { + if left.last! > star.last! { + return false + } + left.popLast() + star.popLast() + } + + return left.isEmpty + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ --- @@ -1236,9 +1427,38 @@ class Solution { } ``` +```swift +class Solution { + func checkValidString(_ s: String) -> Bool { + var leftMin = 0 + var leftMax = 0 + + for c in s { + if c == "(" { + leftMin += 1 + leftMax += 1 + } else if c == ")" { + leftMin -= 1 + leftMax -= 1 + } else { + leftMin -= 1 + leftMax += 1 + } + if leftMax < 0 { + return false + } + if leftMin < 0 { + leftMin = 0 + } + } + return leftMin == 0 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/valid-perfect-square.md b/articles/valid-perfect-square.md new file mode 100644 index 000000000..ea3223888 --- /dev/null +++ b/articles/valid-perfect-square.md @@ -0,0 +1,540 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + for i in range(1, num + 1): + sq = i * i + if sq > num: + return False + if sq == num: + return True +``` + +```java +public class Solution { + public boolean isPerfectSquare(int num) { + for (long i = 1; i <= num; i++) { + long sq = i * i; + if (sq > num) { + return false; + } + if (sq == num) { + return true; + } + } + return false; + } +} +``` + +```cpp +class Solution { +public: + bool isPerfectSquare(int num) { + for (long long i = 1; i <= num; i++) { + long long sq = i * i; + if (sq > num) { + return false; + } + if (sq == num) { + return true; + } + } + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {boolean} + */ + isPerfectSquare(num) { + for (let i = 1; i <= num; i++) { + let sq = i * i; + if (sq > num) { + return false; + } + if (sq === num) { + return true; + } + } + return false; + } +} +``` + +```csharp +public class Solution { + public bool IsPerfectSquare(int num) { + for (long i = 1; i <= num; i++) { + long sq = i * i; + if (sq > num) { + return false; + } + if (sq == num) { + return true; + } + } + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\sqrt {n})$ +- Space complexity: $O(1)$ + +--- + +## 2. In-Built Function + +::tabs-start + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + sqRoot = int(sqrt(num)) + return sqRoot * sqRoot == num +``` + +```java +public class Solution { + public boolean isPerfectSquare(int num) { + int sqRoot = (int) Math.sqrt(num); + return sqRoot * sqRoot == num; + } +} +``` + +```cpp +class Solution { +public: + bool isPerfectSquare(int num) { + int sqRoot = (int) sqrt(num); + return sqRoot * sqRoot == num; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {boolean} + */ + isPerfectSquare(num) { + let sqRoot = Math.floor(Math.sqrt(num)); + return sqRoot * sqRoot === num; + } +} +``` + +```csharp +public class Solution { + public bool IsPerfectSquare(int num) { + int sqRoot = (int)Math.Sqrt(num); + return sqRoot * sqRoot == num; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ +- Space complexity: $O(1)$ + +--- + +## 3. Binary Search + +::tabs-start + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + l, r = 1, num + + while l <= r: + m = l + (r - l) // 2 + sq = m * m + if sq > num: + r = m - 1 + elif sq < num: + l = m + 1 + else: + return True + + return False +``` + +```java +public class Solution { + public boolean isPerfectSquare(int num) { + long l = 1, r = num; + + while (l <= r) { + long m = l + (r - l) / 2; + long sq = m * m; + if (sq > num) { + r = m - 1; + } else if (sq < num) { + l = m + 1; + } else { + return true; + } + } + + return false; + } +} +``` + +```cpp +class Solution { +public: + bool isPerfectSquare(int num) { + long long l = 1, r = num; + + while (l <= r) { + long long m = l + (r - l) / 2; + long long sq = m * m; + if (sq > num) { + r = m - 1; + } else if (sq < num) { + l = m + 1; + } else { + return true; + } + } + + return false; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {boolean} + */ + isPerfectSquare(num) { + let l = 1, + r = num; + + while (l <= r) { + let m = Math.floor(l + (r - l) / 2); + let sq = m * m; + if (sq > num) { + r = m - 1; + } else if (sq < num) { + l = m + 1; + } else { + return true; + } + } + + return false; + } +} +``` + +```csharp +public class Solution { + public bool IsPerfectSquare(int num) { + long l = 1, r = num; + + while (l <= r) { + long m = l + (r - l) / 2; + long sq = m * m; + if (sq > num) { + r = m - 1; + } else if (sq < num) { + l = m + 1; + } else { + return true; + } + } + + return false; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ + +--- + +## 4. Math + +::tabs-start + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + i = 1 + while num > 0: + num -= i + i += 2 + return num == 0 +``` + +```java +public class Solution { + public boolean isPerfectSquare(int num) { + int i = 1; + while (num > 0) { + num -= i; + i += 2; + } + return num == 0; + } +} +``` + +```cpp +class Solution { +public: + bool isPerfectSquare(int num) { + int i = 1; + while (num > 0) { + num -= i; + i += 2; + } + return num == 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {boolean} + */ + isPerfectSquare(num) { + let i = 1; + while (num > 0) { + num -= i; + i += 2; + } + return num === 0; + } +} +``` + +```csharp +public class Solution { + public bool IsPerfectSquare(int num) { + int i = 1; + while (num > 0) { + num -= i; + i += 2; + } + return num == 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\sqrt {n})$ +- Space complexity: $O(1)$ + +--- + +## 5. Newton's Method + +::tabs-start + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + r = num + while r * r > num: + r = (r + (num // r)) // 2 + return r * r == num +``` + +```java +public class Solution { + public boolean isPerfectSquare(int num) { + long r = num; + while (r * r > num) { + r = (r + num / r) / 2; + } + return r * r == num; + } +} +``` + +```cpp +class Solution { +public: + bool isPerfectSquare(int num) { + long long r = num; + while (r * r > num) { + r = (r + num / r) / 2; + } + return r * r == num; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {boolean} + */ + isPerfectSquare(num) { + let r = num; + while (r * r > num) { + r = Math.floor((r + Math.floor(num / r)) / 2); + } + return r * r === num; + } +} +``` + +```csharp +public class Solution { + public bool IsPerfectSquare(int num) { + long r = num; + while (r * r > num) { + r = (r + num / r) / 2; + } + return r * r == num; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(\log n)$ +- Space complexity: $O(1)$ + +--- + +## 6. Bit Manipulation + +::tabs-start + +```python +class Solution: + def isPerfectSquare(self, num: int) -> bool: + r, mask = 0, 1 << 15 + + while mask > 0: + r |= mask + if r > (num // r): + r ^= mask + mask >>= 1 + + return r * r == num +``` + +```java +public class Solution { + public boolean isPerfectSquare(int num) { + int r = 0, mask = 1 << 15; + + while (mask > 0) { + r |= mask; + if (r > (num / r)) { + r ^= mask; + } + mask >>= 1; + } + + return r * r == num; + } +} +``` + +```cpp +class Solution { +public: + bool isPerfectSquare(int num) { + int r = 0, mask = 1 << 15; + + while (mask > 0) { + r |= mask; + if (r > (num / r)) { + r ^= mask; + } + mask >>= 1; + } + + return r * r == num; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} num + * @return {boolean} + */ + isPerfectSquare(num) { + let r = 0, + mask = 1 << 15; + + while (mask > 0) { + r |= mask; + if (r > Math.floor(num / r)) { + r ^= mask; + } + mask >>= 1; + } + + return r * r === num; + } +} +``` + +```csharp +public class Solution { + public bool IsPerfectSquare(int num) { + int r = 0, mask = 1 << 15; + + while (mask > 0) { + r |= mask; + if (r > (num / r)) { + r ^= mask; + } + mask >>= 1; + } + + return r * r == num; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(1)$ since we iterate at most $15$ times. +- Space complexity: $O(1)$ diff --git a/articles/valid-sudoku.md b/articles/valid-sudoku.md index 14c8dc735..e2498f6ed 100644 --- a/articles/valid-sudoku.md +++ b/articles/valid-sudoku.md @@ -8,12 +8,12 @@ class Solution: for row in range(9): seen = set() for i in range(9): - if board[row][i] == ".": + if board[row][i] == ".": continue if board[row][i] in seen: return False seen.add(board[row][i]) - + for col in range(9): seen = set() for i in range(9): @@ -22,7 +22,7 @@ class Solution: if board[i][col] in seen: return False seen.add(board[i][col]) - + for square in range(9): seen = set() for i in range(3): @@ -48,7 +48,7 @@ public class Solution { seen.add(board[row][i]); } } - + for (int col = 0; col < 9; col++) { Set seen = new HashSet<>(); for (int i = 0; i < 9; i++) { @@ -57,7 +57,7 @@ public class Solution { seen.add(board[i][col]); } } - + for (int square = 0; square < 9; square++) { Set seen = new HashSet<>(); for (int i = 0; i < 3; i++) { @@ -70,7 +70,7 @@ public class Solution { } } } - + return true; } } @@ -88,7 +88,7 @@ public: seen.insert(board[row][i]); } } - + for (int col = 0; col < 9; col++) { unordered_set seen; for (int i = 0; i < 9; i++) { @@ -97,7 +97,7 @@ public: seen.insert(board[i][col]); } } - + for (int square = 0; square < 9; square++) { unordered_set seen; for (int i = 0; i < 3; i++) { @@ -110,7 +110,7 @@ public: } } } - + return true; } }; @@ -131,7 +131,7 @@ class Solution { seen.add(board[row][i]); } } - + for (let col = 0; col < 9; col++) { let seen = new Set(); for (let i = 0; i < 9; i++) { @@ -140,7 +140,7 @@ class Solution { seen.add(board[i][col]); } } - + for (let square = 0; square < 9; square++) { let seen = new Set(); for (let i = 0; i < 3; i++) { @@ -153,7 +153,7 @@ class Solution { } } } - + return true; } } @@ -170,7 +170,7 @@ public class Solution { seen.Add(board[row][i]); } } - + for (int col = 0; col < 9; col++) { HashSet seen = new HashSet(); for (int i = 0; i < 9; i++) { @@ -179,7 +179,7 @@ public class Solution { seen.Add(board[i][col]); } } - + for (int square = 0; square < 9; square++) { HashSet seen = new HashSet(); for (int i = 0; i < 3; i++) { @@ -192,7 +192,7 @@ public class Solution { } } } - + return true; } } @@ -284,12 +284,51 @@ class Solution { } ``` +```swift +class Solution { + func isValidSudoku(_ board: [[Character]]) -> Bool { + for row in 0..<9 { + var seen = Set() + for i in 0..<9 { + if board[row][i] == "." { continue } + if seen.contains(board[row][i]) { return false } + seen.insert(board[row][i]) + } + } + + for col in 0..<9 { + var seen = Set() + for i in 0..<9 { + if board[i][col] == "." { continue } + if seen.contains(board[i][col]) { return false } + seen.insert(board[i][col]) + } + } + + for square in 0..<9 { + var seen = Set() + for i in 0..<3 { + for j in 0..<3 { + let row = (square / 3) * 3 + i + let col = (square % 3) * 3 + j + if board[row][col] == "." { continue } + if seen.contains(board[row][col]) { return false } + seen.insert(board[row][col]) + } + } + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -302,7 +341,7 @@ class Solution: def isValidSudoku(self, board: List[List[str]]) -> bool: cols = defaultdict(set) rows = defaultdict(set) - squares = defaultdict(set) + squares = defaultdict(set) for r in range(9): for c in range(9): @@ -359,7 +398,7 @@ public: for (int r = 0; r < 9; r++) { for (int c = 0; c < 9; c++) { if (board[r][c] == '.') continue; - + pair squareKey = {r / 3, c / 3}; if (rows[r].count(board[r][c]) || cols[c].count(board[r][c]) || squares[squareKey].count(board[r][c])) { @@ -393,9 +432,12 @@ class Solution { const squareKey = `${Math.floor(r / 3)},${Math.floor(c / 3)}`; - if ((rows.get(r) && rows.get(r).has(board[r][c])) || + if ( + (rows.get(r) && rows.get(r).has(board[r][c])) || (cols.get(c) && cols.get(c).has(board[r][c])) || - (squares.get(squareKey) && squares.get(squareKey).has(board[r][c]))) { + (squares.get(squareKey) && + squares.get(squareKey).has(board[r][c])) + ) { return false; } @@ -466,7 +508,7 @@ func isValidSudoku(board [][]byte) bool { val := board[r][c] squareIdx := (r/3)*3 + c/3 - if rows[r][val] || cols[c][val] || + if rows[r][val] || cols[c][val] || squares[squareIdx][val] { return false } @@ -494,7 +536,7 @@ class Solution { if (value == '.') continue val squareIdx = (r / 3) * 3 + (c / 3) - if (value in rows[r] || value in cols[c] || + if (value in rows[r] || value in cols[c] || value in squares[squareIdx]) { return false } @@ -510,12 +552,42 @@ class Solution { } ``` +```swift +class Solution { + func isValidSudoku(_ board: [[Character]]) -> Bool { + var cols = [Int: Set]() + var rows = [Int: Set]() + var squares = [String: Set]() + + for r in 0..<9 { + for c in 0..<9 { + if board[r][c] == "." { continue } + + let squareKey = "\(r / 3),\(c / 3)" + + if rows[r]?.contains(board[r][c]) == true || + cols[c]?.contains(board[r][c]) == true || + squares[squareKey]?.contains(board[r][c]) == true { + return false + } + + rows[r, default: []].insert(board[r][c]) + cols[c, default: []].insert(board[r][c]) + squares[squareKey, default: []].insert(board[r][c]) + } + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n ^ 2)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n ^ 2)$ --- @@ -534,7 +606,7 @@ class Solution: for c in range(9): if board[r][c] == ".": continue - + val = int(board[r][c]) - 1 if (1 << val) & rows[r]: return False @@ -542,7 +614,7 @@ class Solution: return False if (1 << val) & squares[(r // 3) * 3 + (c // 3)]: return False - + rows[r] |= (1 << val) cols[c] |= (1 << val) squares[(r // 3) * 3 + (c // 3)] |= (1 << val) @@ -563,7 +635,7 @@ public class Solution { int val = board[r][c] - '1'; - if ((rows[r] & (1 << val)) > 0 || (cols[c] & (1 << val)) > 0 || + if ((rows[r] & (1 << val)) > 0 || (cols[c] & (1 << val)) > 0 || (squares[(r / 3) * 3 + (c / 3)] & (1 << val)) > 0) { return false; } @@ -620,14 +692,18 @@ class Solution { let val = board[r][c] - '1'; - if ((rows[r] & (1 << val)) || (cols[c] & (1 << val)) || - (squares[Math.floor(r / 3) * 3 + Math.floor(c / 3)] & (1 << val))) { + if ( + rows[r] & (1 << val) || + cols[c] & (1 << val) || + squares[Math.floor(r / 3) * 3 + Math.floor(c / 3)] & + (1 << val) + ) { return false; } - rows[r] |= (1 << val); - cols[c] |= (1 << val); - squares[Math.floor(r / 3) * 3 + Math.floor(c / 3)] |= (1 << val); + rows[r] |= 1 << val; + cols[c] |= 1 << val; + squares[Math.floor(r / 3) * 3 + Math.floor(c / 3)] |= 1 << val; } } return true; @@ -648,7 +724,7 @@ public class Solution { int val = board[r][c] - '1'; - if ((rows[r] & (1 << val)) > 0 || (cols[c] & (1 << val)) > 0 || + if ((rows[r] & (1 << val)) > 0 || (cols[c] & (1 << val)) > 0 || (squares[(r / 3) * 3 + (c / 3)] & (1 << val)) > 0) { return false; } @@ -674,16 +750,16 @@ func isValidSudoku(board [][]byte) bool { if board[r][c] == '.' { continue } - + val := board[r][c] - '1' bit := 1 << val squareIdx := (r/3)*3 + c/3 - if rows[r]&bit != 0 || cols[c]&bit != 0 || + if rows[r]&bit != 0 || cols[c]&bit != 0 || squares[squareIdx]&bit != 0 { return false } - + rows[r] |= bit cols[c] |= bit squares[squareIdx] |= bit @@ -704,12 +780,12 @@ class Solution { for (r in 0 until 9) { for (c in 0 until 9) { if (board[r][c] == '.') continue - + val value = board[r][c] - '1' val bit = 1 shl value val squareIdx = (r / 3) * 3 + (c / 3) - if ((rows[r] and bit) != 0 || (cols[c] and bit) != 0 || + if ((rows[r] and bit) != 0 || (cols[c] and bit) != 0 || (squares[squareIdx] and bit) != 0) { return false } @@ -725,9 +801,38 @@ class Solution { } ``` +```swift +class Solution { + func isValidSudoku(_ board: [[Character]]) -> Bool { + var rows = [Int](repeating: 0, count: 9) + var cols = [Int](repeating: 0, count: 9) + var squares = [Int](repeating: 0, count: 9) + + for r in 0..<9 { + for c in 0..<9 { + if board[r][c] == "." { continue } + + let val = Int(board[r][c].asciiValue! - Character("0").asciiValue!) + let bitmask = 1 << (val - 1) + + if (rows[r] & bitmask) != 0 { return false } + if (cols[c] & bitmask) != 0 { return false } + if (squares[(r / 3) * 3 + (c / 3)] & bitmask) != 0 { return false } + + rows[r] |= bitmask + cols[c] |= bitmask + squares[(r / 3) * 3 + (c / 3)] |= bitmask + } + } + + return true + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ diff --git a/articles/valid-tree.md b/articles/valid-tree.md index a343b676e..198762e4d 100644 --- a/articles/valid-tree.md +++ b/articles/valid-tree.md @@ -7,17 +7,17 @@ class Solution: def validTree(self, n: int, edges: List[List[int]]) -> bool: if len(edges) > (n - 1): return False - + adj = [[] for _ in range(n)] for u, v in edges: adj[u].append(v) adj[v].append(u) - + visit = set() def dfs(node, par): if node in visit: return False - + visit.add(node) for nei in adj[node]: if nei == par: @@ -25,7 +25,7 @@ class Solution: if not dfs(nei, node): return False return True - + return dfs(0, -1) and len(visit) == n ``` @@ -50,16 +50,16 @@ public class Solution { if (!dfs(0, -1, visit, adj)) { return false; } - + return visit.size() == n; } - private boolean dfs(int node, int parent, Set visit, + private boolean dfs(int node, int parent, Set visit, List> adj) { if (visit.contains(node)) { return false; } - + visit.add(node); for (int nei : adj.get(node)) { if (nei == parent) { @@ -97,7 +97,7 @@ public: } private: - bool dfs(int node, int parent, unordered_set& visit, + bool dfs(int node, int parent, unordered_set& visit, vector>& adj) { if (visit.count(node)) { return false; @@ -183,7 +183,7 @@ public class Solution { return visit.Count == n; } - private bool Dfs(int node, int parent, HashSet visit, + private bool Dfs(int node, int parent, HashSet visit, List> adj) { if (visit.Contains(node)) { return false; @@ -208,7 +208,7 @@ func validTree(n int, edges [][]int) bool { if len(edges) > n-1 { return false } - + adj := make([][]int, n) for _, edge := range edges { u, v := edge[0], edge[1] @@ -242,15 +242,15 @@ func validTree(n int, edges [][]int) bool { class Solution { fun validTree(n: Int, edges: Array): Boolean { if (edges.size > n - 1) return false - + val adj = Array(n) { mutableListOf() } for ((u, v) in edges) { adj[u].add(v) adj[v].add(u) } - + val visit = HashSet() - + fun dfs(node: Int, parent: Int): Boolean { if (node in visit) return false visit.add(node) @@ -260,18 +260,56 @@ class Solution { } return true } - + return dfs(0, -1) && visit.size == n } } ``` +```swift +class Solution { + func validTree(_ n: Int, _ edges: [[Int]]) -> Bool { + if edges.count > (n - 1) { + return false + } + + var adj = Array(repeating: [Int](), count: n) + for edge in edges { + let u = edge[0] + let v = edge[1] + adj[u].append(v) + adj[v].append(u) + } + + var visited = Set() + + func dfs(_ node: Int, _ parent: Int) -> Bool { + if visited.contains(node) { + return false + } + visited.insert(node) + for nei in adj[node] { + if nei == parent { + continue + } + if !dfs(nei, node) { + return false + } + } + return true + } + + return dfs(0, -1) && visited.count == n + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V + E)$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ > Where $V$ is the number vertices and $E$ is the number of edges in the graph. @@ -286,16 +324,16 @@ class Solution: def validTree(self, n: int, edges: List[List[int]]) -> bool: if len(edges) > n - 1: return False - + adj = [[] for _ in range(n)] for u, v in edges: adj[u].append(v) adj[v].append(u) - + visit = set() q = deque([(0, -1)]) # (current node, parent node) visit.add(0) - + while q: node, parent = q.popleft() for nei in adj[node]: @@ -305,7 +343,7 @@ class Solution: return False visit.add(nei) q.append((nei, node)) - + return len(visit) == n ``` @@ -409,7 +447,7 @@ class Solution { } const visit = new Set(); - const q = new Queue([[0, -1]]); // [current node, parent node] + const q = new Queue([[0, -1]]); // [current node, parent node] visit.add(0); while (!q.isEmpty()) { @@ -537,12 +575,51 @@ class Solution { } ``` +```swift +class Solution { + func validTree(_ n: Int, _ edges: [[Int]]) -> Bool { + if edges.count > n - 1 { + return false + } + + var adj = [[Int]](repeating: [], count: n) + for edge in edges { + let u = edge[0] + let v = edge[1] + adj[u].append(v) + adj[v].append(u) + } + + var visit = Set() + var q = Deque<(Int, Int)>() // (current node, parent node) + q.append((0, -1)) + visit.insert(0) + + while !q.isEmpty { + let (node, parent) = q.removeFirst() + for nei in adj[node] { + if nei == parent { + continue + } + if visit.contains(nei) { + return false + } + visit.insert(nei) + q.append((nei, node)) + } + } + + return visit.count == n + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V + E)$ -* Space complexity: $O(V + E)$ +- Time complexity: $O(V + E)$ +- Space complexity: $O(V + E)$ > Where $V$ is the number vertices and $E$ is the number of edges in the graph. @@ -576,7 +653,7 @@ class DSU: self.Size[pu] += self.Size[pv] self.Parent[pv] = pu return True - + def components(self): return self.comps @@ -584,7 +661,7 @@ class Solution: def validTree(self, n: int, edges: List[List[int]]) -> bool: if len(edges) > n - 1: return False - + dsu = DSU(n) for u, v in edges: if not dsu.union(u, v): @@ -593,7 +670,7 @@ class Solution: ``` ```java -public class DSU { +class DSU { int[] Parent, Size; int comps; @@ -932,11 +1009,70 @@ class Solution { } ``` +```swift +class DSU { + var comps: Int + var parent: [Int] + var size: [Int] + + init(_ n: Int) { + comps = n + parent = Array(0.. Int { + if parent[node] != node { + parent[node] = find(parent[node]) + } + return parent[node] + } + + func union(_ u: Int, _ v: Int) -> Bool { + let pu = find(u) + let pv = find(v) + if pu == pv { + return false + } + comps -= 1 + if size[pu] < size[pv] { + parent[pu] = pv + size[pv] += size[pu] + } else { + parent[pv] = pu + size[pu] += size[pv] + } + return true + } + + func components() -> Int { + return comps + } +} + +class Solution { + func validTree(_ n: Int, _ edges: [[Int]]) -> Bool { + if edges.count > n - 1 { + return false + } + + let dsu = DSU(n) + for edge in edges { + let u = edge[0], v = edge[1] + if !dsu.union(u, v) { + return false + } + } + return dsu.components() == 1 + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(V + (E * α(V)))$ -* Space complexity: $O(V)$ +- Time complexity: $O(V + (E * α(V)))$ +- Space complexity: $O(V)$ -> Where $V$ is the number of vertices and $E$ is the number of edges in the graph. $α()$ is used for amortized complexity. \ No newline at end of file +> Where $V$ is the number of vertices and $E$ is the number of edges in the graph. $α()$ is used for amortized complexity. diff --git a/articles/valid-word-abbreviation.md b/articles/valid-word-abbreviation.md new file mode 100644 index 000000000..3b417b460 --- /dev/null +++ b/articles/valid-word-abbreviation.md @@ -0,0 +1,166 @@ +## 1. Two Pointers + +::tabs-start + +```python +class Solution: + def validWordAbbreviation(self, word: str, abbr: str) -> bool: + n, m = len(word), len(abbr) + i = j = 0 + + while i < n and j < m: + if abbr[j] == '0': + return False + + if word[i] == abbr[j]: + i, j = i + 1, j + 1 + elif abbr[j].isalpha(): + return False + else: + subLen = 0 + while j < m and abbr[j].isdigit(): + subLen = subLen * 10 + int(abbr[j]) + j += 1 + i += subLen + + return i == n and j == m +``` + +```java +public class Solution { + public boolean validWordAbbreviation(String word, String abbr) { + int n = word.length(), m = abbr.length(); + int i = 0, j = 0; + + while (i < n && j < m) { + if (abbr.charAt(j) == '0') return false; + + if (Character.isLetter(abbr.charAt(j))) { + if (i < n && word.charAt(i) == abbr.charAt(j)) { + i++; + j++; + } else { + return false; + } + } else { + int subLen = 0; + while (j < m && Character.isDigit(abbr.charAt(j))) { + subLen = subLen * 10 + (abbr.charAt(j) - '0'); + j++; + } + i += subLen; + } + } + + return i == n && j == m; + } +} +``` + +```cpp +class Solution { +public: + bool validWordAbbreviation(string word, string abbr) { + int n = word.length(), m = abbr.length(); + int i = 0, j = 0; + + while (i < n && j < m) { + if (abbr[j] == '0') return false; + + if (isalpha(abbr[j])) { + if (word[i] == abbr[j]) { + i++; j++; + } else { + return false; + } + } else { + int subLen = 0; + while (j < m && isdigit(abbr[j])) { + subLen = subLen * 10 + (abbr[j] - '0'); + j++; + } + i += subLen; + } + } + + return i == n && j == m; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} word + * @param {string} abbr + * @return {boolean} + */ + validWordAbbreviation(word, abbr) { + let n = word.length, + m = abbr.length; + let i = 0, + j = 0; + + while (i < n && j < m) { + if (abbr[j] === '0') return false; + + if (isNaN(abbr[j])) { + if (word[i] === abbr[j]) { + i++; + j++; + } else { + return false; + } + } else { + let subLen = 0; + while (j < m && !isNaN(abbr[j]) && abbr[j] !== ' ') { + subLen = subLen * 10 + parseInt(abbr[j]); + j++; + } + i += subLen; + } + } + + return i === n && j === m; + } +} +``` + +```csharp +public class Solution { + public bool ValidWordAbbreviation(string word, string abbr) { + int n = word.Length, m = abbr.Length; + int i = 0, j = 0; + + while (i < n && j < m) { + if (abbr[j] == '0') return false; + + if (char.IsLetter(abbr[j])) { + if (i < n && word[i] == abbr[j]) { + i++; j++; + } else { + return false; + } + } else { + int subLen = 0; + while (j < m && char.IsDigit(abbr[j])) { + subLen = subLen * 10 + (abbr[j] - '0'); + j++; + } + i += subLen; + } + } + + return i == n && j == m; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n + m)$ +- Space complexity: $O(1)$ + +> Where $n$ and $m$ are the lengths of the strings $word$ and $abbr$, respectively. diff --git a/articles/validate-binary-tree-nodes.md b/articles/validate-binary-tree-nodes.md new file mode 100644 index 000000000..52d6939e2 --- /dev/null +++ b/articles/validate-binary-tree-nodes.md @@ -0,0 +1,670 @@ +## 1. Depth First Search + +::tabs-start + +```python +class Solution: + def validateBinaryTreeNodes(self, n: int, leftChild: List[int], rightChild: List[int]) -> bool: + hasParent = set(leftChild + rightChild) + hasParent.discard(-1) + if len(hasParent) == n: + return False + + root = -1 + for i in range(n): + if i not in hasParent: + root = i + break + + visit = set() + def dfs(i): + if i == -1: + return True + if i in visit: + return False + visit.add(i) + return dfs(leftChild[i]) and dfs(rightChild[i]) + + return dfs(root) and len(visit) == n +``` + +```java +public class Solution { + private Set visit; + + public boolean validateBinaryTreeNodes(int n, int[] leftChild, int[] rightChild) { + Set hasParent = new HashSet<>(); + for (int c : leftChild) if (c != -1) hasParent.add(c); + for (int c : rightChild) if (c != -1) hasParent.add(c); + if (hasParent.size() == n) return false; + + int root = -1; + for (int i = 0; i < n; i++) { + if (!hasParent.contains(i)) { + root = i; + break; + } + } + visit = new HashSet<>(); + return dfs(root, leftChild, rightChild) && visit.size() == n; + } + + private boolean dfs(int i, int[] leftChild, int[] rightChild) { + if (i == -1) return true; + if (visit.contains(i)) return false; + visit.add(i); + return dfs(leftChild[i], leftChild, rightChild) && + dfs(rightChild[i], leftChild, rightChild); + } +} +``` + +```cpp +class Solution { +public: + unordered_set visit; + + bool validateBinaryTreeNodes(int n, vector& leftChild, vector& rightChild) { + unordered_set hasParent; + for (int c : leftChild) if (c != -1) hasParent.insert(c); + for (int c : rightChild) if (c != -1) hasParent.insert(c); + if (hasParent.size() == n) return false; + + int root = -1; + for (int i = 0; i < n; i++) { + if (!hasParent.count(i)) { + root = i; + break; + } + } + return dfs(root, leftChild, rightChild) && visit.size() == n; + } + +private: + bool dfs(int i, vector& leftChild, vector& rightChild) { + if (i == -1) return true; + if (visit.count(i)) return false; + visit.insert(i); + return dfs(leftChild[i], leftChild, rightChild) && + dfs(rightChild[i], leftChild, rightChild); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[]} leftChild + * @param {number[]} rightChild + * @return {boolean} + */ + validateBinaryTreeNodes(n, leftChild, rightChild) { + let hasParent = new Set( + [...leftChild, ...rightChild].filter((c) => c !== -1), + ); + if (hasParent.size === n) return false; + + let root = 0; + for (let i = 0; i < n; i++) { + if (!hasParent.has(i)) { + root = i; + break; + } + } + + const visit = new Set(); + const dfs = (i) => { + if (i === -1) return true; + if (visit.has(i)) return false; + visit.add(i); + return dfs(leftChild[i]) && dfs(rightChild[i]); + }; + + return dfs(root) && visit.size === n; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Breadth First Search + +::tabs-start + +```python +class Solution: + def validateBinaryTreeNodes(self, n: int, leftChild: list[int], rightChild: list[int]) -> bool: + indegree = [0] * n + for i in range(n): + if leftChild[i] != -1: + indegree[leftChild[i]] += 1 + if indegree[leftChild[i]] > 1: + return False + if rightChild[i] != -1: + indegree[rightChild[i]] += 1 + if indegree[rightChild[i]] > 1: + return False + + root = -1 + for i in range(n): + if indegree[i] == 0: + if root != -1: + return False + root = i + + if root == -1: + return False + + count = 0 + q = deque([root]) + while q: + i = q.popleft() + count += 1 + if leftChild[i] != -1: + q.append(leftChild[i]) + if rightChild[i] != -1: + q.append(rightChild[i]) + return count == n +``` + +```java +public class Solution { + public boolean validateBinaryTreeNodes(int n, int[] leftChild, int[] rightChild) { + int[] indegree = new int[n]; + for (int i = 0; i < n; i++) { + if (leftChild[i] != -1) { + if (++indegree[leftChild[i]] > 1) return false; + } + if (rightChild[i] != -1) { + if (++indegree[rightChild[i]] > 1) return false; + } + } + + int root = -1; + for (int i = 0; i < n; i++) { + if (indegree[i] == 0) { + if (root != -1) return false; + root = i; + } + } + + if (root == -1) return false; + + int count = 0; + Queue q = new LinkedList<>(); + q.offer(root); + + while (!q.isEmpty()) { + int i = q.poll(); + count++; + if (leftChild[i] != -1) q.offer(leftChild[i]); + if (rightChild[i] != -1) q.offer(rightChild[i]); + } + return count == n; + } +} +``` + +```cpp +class Solution { +public: + bool validateBinaryTreeNodes(int n, vector& leftChild, vector& rightChild) { + vector indegree(n, 0); + for (int i = 0; i < n; i++) { + if (leftChild[i] != -1) { + if (++indegree[leftChild[i]] > 1) return false; + } + if (rightChild[i] != -1) { + if (++indegree[rightChild[i]] > 1) return false; + } + } + + int root = -1; + for (int i = 0; i < n; i++) { + if (indegree[i] == 0) { + if (root != -1) return false; + root = i; + } + } + + if (root == -1) return false; + + int count = 0; + queue q; + q.push(root); + + while (!q.empty()) { + int i = q.front();q.pop(); + count++; + if (leftChild[i] != -1) q.push(leftChild[i]); + if (rightChild[i] != -1) q.push(rightChild[i]); + } + return count == n; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[]} leftChild + * @param {number[]} rightChild + * @return {boolean} + */ + validateBinaryTreeNodes(n, leftChild, rightChild) { + let indegree = new Array(n).fill(0); + for (let i = 0; i < n; i++) { + if (leftChild[i] !== -1) { + if (++indegree[leftChild[i]] > 1) return false; + } + if (rightChild[i] !== -1) { + if (++indegree[rightChild[i]] > 1) return false; + } + } + + let root = -1; + for (let i = 0; i < n; i++) { + if (indegree[i] === 0) { + if (root !== -1) return false; + root = i; + } + } + + if (root === -1) return false; + + let count = 0; + let q = new Queue([root]); + + while (!q.isEmpty()) { + let i = q.pop(); + count++; + if (leftChild[i] !== -1) q.push(leftChild[i]); + if (rightChild[i] !== -1) q.push(rightChild[i]); + } + return count === n; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 3. Iterative DFS + +::tabs-start + +```python +class Solution: + def validateBinaryTreeNodes(self, n: int, leftChild: list[int], rightChild: list[int]) -> bool: + indegree = [0] * n + for i in range(n): + if leftChild[i] != -1: + indegree[leftChild[i]] += 1 + if indegree[leftChild[i]] > 1: + return False + if rightChild[i] != -1: + indegree[rightChild[i]] += 1 + if indegree[rightChild[i]] > 1: + return False + + root = next((i for i in range(n) if indegree[i] == 0), -1) + if root == -1: + return False + + count, stack = 0, [root] + while stack: + node = stack.pop() + count += 1 + if leftChild[node] != -1: + stack.append(leftChild[node]) + if rightChild[node] != -1: + stack.append(rightChild[node]) + + return count == n +``` + +```java +public class Solution { + public boolean validateBinaryTreeNodes(int n, int[] leftChild, int[] rightChild) { + int[] indegree = new int[n]; + for (int i = 0; i < n; i++) { + if (leftChild[i] != -1) { + if (++indegree[leftChild[i]] > 1) return false; + } + if (rightChild[i] != -1) { + if (++indegree[rightChild[i]] > 1) return false; + } + } + + int root = -1; + for (int i = 0; i < n; i++) { + if (indegree[i] == 0) { + if (root != -1) return false; + root = i; + } + } + + if (root == -1) return false; + + int count = 0; + Stack stack = new Stack<>(); + stack.push(root); + + while (!stack.isEmpty()) { + int node = stack.pop(); + count++; + if (leftChild[node] != -1) stack.push(leftChild[node]); + if (rightChild[node] != -1) stack.push(rightChild[node]); + } + return count == n; + } +} +``` + +```cpp +class Solution { +public: + bool validateBinaryTreeNodes(int n, vector& leftChild, vector& rightChild) { + vector indegree(n, 0); + for (int i = 0; i < n; i++) { + if (leftChild[i] != -1 && ++indegree[leftChild[i]] > 1) return false; + if (rightChild[i] != -1 && ++indegree[rightChild[i]] > 1) return false; + } + + int root = -1; + for (int i = 0; i < n; i++) { + if (indegree[i] == 0) { + if (root != -1) return false; + root = i; + } + } + + if (root == -1) return false; + + int count = 0; + stack stk; + stk.push(root); + + while (!stk.empty()) { + int node = stk.top(); stk.pop(); + count++; + if (leftChild[node] != -1) stk.push(leftChild[node]); + if (rightChild[node] != -1) stk.push(rightChild[node]); + } + return count == n; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number} n + * @param {number[]} leftChild + * @param {number[]} rightChild + * @return {boolean} + */ + validateBinaryTreeNodes(n, leftChild, rightChild) { + let indegree = new Array(n).fill(0); + for (let i = 0; i < n; i++) { + if (leftChild[i] !== -1) { + if (++indegree[leftChild[i]] > 1) return false; + } + if (rightChild[i] !== -1) { + if (++indegree[rightChild[i]] > 1) return false; + } + } + + let root = -1; + for (let i = 0; i < n; i++) { + if (indegree[i] === 0) { + if (root !== -1) return false; + root = i; + } + } + + if (root === -1) return false; + + let count = 0; + let stack = [root]; + + while (stack.length) { + let node = stack.pop(); + count++; + if (leftChild[node] !== -1) stack.push(leftChild[node]); + if (rightChild[node] !== -1) stack.push(rightChild[node]); + } + return count === n; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 4. Disjoint Set Union + +::tabs-start + +```python +class DSU: + def __init__(self, n): + self.Parent = list(range(n)) + self.Components = n + + def find(self, node): + if self.Parent[node] != node: + self.Parent[node] = self.find(self.Parent[node]) + return self.Parent[node] + + def union(self, parent, child): + parentRoot = self.find(parent) + childRoot = self.find(child) + if childRoot != child or parentRoot == childRoot: + return False + + self.Components -= 1 + self.Parent[childRoot] = parentRoot + return True + +class Solution: + def validateBinaryTreeNodes(self, n: int, leftChild: list[int], rightChild: list[int]) -> bool: + dsu = DSU(n) + + for parent in range(n): + for child in (leftChild[parent], rightChild[parent]): + if child == -1: + continue + if not dsu.union(parent, child): + return False + + return dsu.Components == 1 +``` + +```java +class DSU { + int[] Parent; + int Components; + + public DSU(int n) { + Parent = new int[n]; + for (int i = 0; i < n; i++) { + Parent[i] = i; + } + Components = n; + } + + public int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + public boolean union(int parent, int child) { + int parentRoot = find(parent); + int childRoot = find(child); + if (childRoot != child || parentRoot == childRoot) { + return false; + } + + Components--; + Parent[childRoot] = parentRoot; + return true; + } +} + +class Solution { + public boolean validateBinaryTreeNodes(int n, int[] leftChild, int[] rightChild) { + DSU dsu = new DSU(n); + + for (int parent = 0; parent < n; parent++) { + for (int child : new int[]{leftChild[parent], rightChild[parent]}) { + if (child == -1) continue; + if (!dsu.union(parent, child)) return false; + } + } + + return dsu.Components == 1; + } +} +``` + +```cpp +class DSU { +public: + vector Parent; + int Components; + + DSU(int n) { + Parent.resize(n); + iota(Parent.begin(), Parent.end(), 0); + Components = n; + } + + int find(int node) { + if (Parent[node] != node) { + Parent[node] = find(Parent[node]); + } + return Parent[node]; + } + + bool unionSets(int parent, int child) { + int parentRoot = find(parent); + int childRoot = find(child); + if (childRoot != child || parentRoot == childRoot) { + return false; + } + + Components--; + Parent[childRoot] = parentRoot; + return true; + } +}; + +class Solution { +public: + bool validateBinaryTreeNodes(int n, vector& leftChild, vector& rightChild) { + DSU dsu(n); + + for (int parent = 0; parent < n; parent++) { + for (int child : {leftChild[parent], rightChild[parent]}) { + if (child == -1) continue; + if (!dsu.unionSets(parent, child)) return false; + } + } + + return dsu.Components == 1; + } +}; +``` + +```javascript +class DSU { + /** + * @constructor + * @param {number} n + */ + constructor(n) { + this.Parent = Array.from({ length: n }, (_, i) => i); + this.Components = n; + } + + /** + * @param {number} node + * @return {number} + */ + find(node) { + if (this.Parent[node] !== node) { + this.Parent[node] = this.find(this.Parent[node]); + } + return this.Parent[node]; + } + + /** + * @param {number} parent + * @param {number} child + * @return {boolean} + */ + union(parent, child) { + let parentRoot = this.find(parent); + let childRoot = this.find(child); + if (childRoot !== child || parentRoot === childRoot) { + return false; + } + + this.Components--; + this.Parent[childRoot] = parentRoot; + return true; + } +} + +class Solution { + /** + * @param {number} n + * @param {number[]} leftChild + * @param {number[]} rightChild + * @return {boolean} + */ + validateBinaryTreeNodes(n, leftChild, rightChild) { + let dsu = new DSU(n); + + for (let parent = 0; parent < n; parent++) { + for (let child of [leftChild[parent], rightChild[parent]]) { + if (child === -1) continue; + if (!dsu.union(parent, child)) return false; + } + } + + return dsu.Components === 1; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/validate-parentheses.md b/articles/validate-parentheses.md index fc97eac24..b900e101b 100644 --- a/articles/validate-parentheses.md +++ b/articles/validate-parentheses.md @@ -57,12 +57,12 @@ class Solution { * @return {boolean} */ isValid(s) { - while (s.includes("()") || s.includes("{}") || s.includes("[]")) { - s = s.replace("()", ""); - s = s.replace("{}", ""); - s = s.replace("[]", ""); + while (s.includes('()') || s.includes('{}') || s.includes('[]')) { + s = s.replace('()', ''); + s = s.replace('{}', ''); + s = s.replace('[]', ''); } - return s === ""; + return s === ''; } } ``` @@ -105,12 +105,26 @@ class Solution { } ``` +```swift +class Solution { + func isValid(_ s: String) -> Bool { + var str = s + while str.contains("()") || str.contains("{}") || str.contains("[]") { + str = str.replacingOccurrences(of: "()", with: "") + str = str.replacingOccurrences(of: "{}", with: "") + str = str.replacingOccurrences(of: "[]", with: "") + } + return str.isEmpty + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n ^ 2)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n ^ 2)$ +- Space complexity: $O(n)$ --- @@ -132,7 +146,7 @@ class Solution: return False else: stack.append(c) - + return True if not stack else False ``` @@ -199,12 +213,15 @@ class Solution { const closeToOpen = { ')': '(', ']': '[', - '}': '{' + '}': '{', }; for (let c of s) { if (closeToOpen[c]) { - if (stack.length > 0 && stack[stack.length - 1] === closeToOpen[c]) { + if ( + stack.length > 0 && + stack[stack.length - 1] === closeToOpen[c] + ) { stack.pop(); } else { return false; @@ -291,9 +308,32 @@ class Solution { } ``` +```swift +class Solution { + func isValid(_ s: String) -> Bool { + var stack = [Character]() + let closeToOpen: [Character: Character] = [")": "(", "]": "[", "}": "{"] + + for c in s { + if let open = closeToOpen[c] { + if !stack.isEmpty && stack.last! == open { + stack.popLast() + } else { + return false + } + } else { + stack.append(c) + } + } + + return stack.isEmpty + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(n)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ diff --git a/articles/validate-stack-sequences.md b/articles/validate-stack-sequences.md new file mode 100644 index 000000000..911c0204a --- /dev/null +++ b/articles/validate-stack-sequences.md @@ -0,0 +1,165 @@ +## 1. Stack + +::tabs-start + +```python +class Solution: + def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool: + i = 0 + stack = [] + for n in pushed: + stack.append(n) + while i < len(popped) and stack and popped[i] == stack[-1]: + stack.pop() + i += 1 + return not stack +``` + +```java +public class Solution { + public boolean validateStackSequences(int[] pushed, int[] popped) { + Stack stack = new Stack<>(); + int i = 0; + for (int n : pushed) { + stack.push(n); + while (i < popped.length && !stack.isEmpty() && popped[i] == stack.peek()) { + stack.pop(); + i++; + } + } + return stack.isEmpty(); + } +} +``` + +```cpp +class Solution { +public: + bool validateStackSequences(vector& pushed, vector& popped) { + stack stk; + int i = 0; + for (int n : pushed) { + stk.push(n); + while (i < popped.size() && !stk.empty() && popped[i] == stk.top()) { + stk.pop(); + i++; + } + } + return stk.empty(); + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} pushed + * @param {number[]} popped + * @return {boolean} + */ + validateStackSequences(pushed, popped) { + const stack = []; + let i = 0; + for (const n of pushed) { + stack.push(n); + while ( + i < popped.length && + stack.length > 0 && + popped[i] === stack[stack.length - 1] + ) { + stack.pop(); + i++; + } + } + return stack.length === 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ + +--- + +## 2. Two Pointers + +::tabs-start + +```python +class Solution: + def validateStackSequences(self, pushed: List[int], popped: List[int]) -> bool: + l = r = 0 + for num in pushed: + pushed[l] = num + l += 1 + while l > 0 and pushed[l - 1] == popped[r]: + r += 1 + l -= 1 + return l == 0 +``` + +```java +public class Solution { + public boolean validateStackSequences(int[] pushed, int[] popped) { + int l = 0, r = 0; + for (int num : pushed) { + pushed[l++] = num; + while (l > 0 && pushed[l - 1] == popped[r]) { + r++; + l--; + } + } + return l == 0; + } +} +``` + +```cpp +class Solution { +public: + bool validateStackSequences(vector& pushed, vector& popped) { + int l = 0, r = 0; + for (int& num : pushed) { + pushed[l++] = num; + while (l > 0 && pushed[l - 1] == popped[r]) { + r++; + l--; + } + } + return l == 0; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[]} pushed + * @param {number[]} popped + * @return {boolean} + */ + validateStackSequences(pushed, popped) { + let l = 0, + r = 0; + for (const num of pushed) { + pushed[l++] = num; + while (l > 0 && pushed[l - 1] === popped[r]) { + r++; + l--; + } + } + return l === 0; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ extra space. diff --git a/articles/verifying-an-alien-dictionary.md b/articles/verifying-an-alien-dictionary.md index 7ab6ac58d..cd9e67deb 100644 --- a/articles/verifying-an-alien-dictionary.md +++ b/articles/verifying-an-alien-dictionary.md @@ -6,10 +6,10 @@ class Solution: def isAlienSorted(self, words: List[str], order: str) -> bool: order_index = {c: i for i, c in enumerate(order)} - + def compare(word): return [order_index[c] for c in word] - + return words == sorted(words, key=compare) ``` @@ -19,7 +19,7 @@ public class Solution { int[] orderIndex = new int[26]; for (int i = 0; i < order.length(); i++) orderIndex[order.charAt(i) - 'a'] = i; - + Comparator compare = (w1, w2) -> { for (int i = 0; i < Math.min(w1.length(), w2.length()); i++) { if (w1.charAt(i) != w2.charAt(i)) @@ -42,7 +42,7 @@ public: int orderIndex[26]; for (int i = 0; i < order.size(); ++i) orderIndex[order[i] - 'a'] = i; - + auto compare = [&](const string &a, const string &b) { for (int i = 0; i < min(a.size(), b.size()); ++i) { if (a[i] != b[i]) @@ -72,7 +72,10 @@ class Solution { const compare = (w1, w2) => { for (let i = 0; i < Math.min(w1.length, w2.length); i++) { if (w1[i] !== w2[i]) { - return orderIndex[w1.charCodeAt(i) - 97] - orderIndex[w2.charCodeAt(i) - 97]; + return ( + orderIndex[w1.charCodeAt(i) - 97] - + orderIndex[w2.charCodeAt(i) - 97] + ); } } return w1.length - w2.length; @@ -84,12 +87,41 @@ class Solution { } ``` +```csharp +public class Solution { + public bool IsAlienSorted(string[] words, string order) { + int[] orderIndex = new int[26]; + for (int i = 0; i < order.Length; i++) { + orderIndex[order[i] - 'a'] = i; + } + + string[] sortedWords = (string[])words.Clone(); + Array.Sort(sortedWords, (w1, w2) => { + for (int i = 0; i < Math.Min(w1.Length, w2.Length); i++) { + if (w1[i] != w2[i]) { + return orderIndex[w1[i] - 'a'] - orderIndex[w2[i] - 'a']; + } + } + return w1.Length - w2.Length; + }); + + for (int i = 0; i < words.Length; i++) { + if (!words[i].Equals(sortedWords[i])) { + return false; + } + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m\log n)$ -* Space complexity: $O(n * m)$ +- Time complexity: $O(n * m\log n)$ +- Space complexity: $O(n * m)$ > Where $n$ is the number of words and $m$ is the average length of a word. @@ -103,14 +135,14 @@ class Solution { class Solution: def isAlienSorted(self, words: List[str], order: str) -> bool: order_index = {c: i for i, c in enumerate(order)} - + for i in range(len(words) - 1): w1, w2 = words[i], words[i + 1] - + for j in range(len(w1)): if j == len(w2): return False - + if w1[j] != w2[j]: if order_index[w1[j]] > order_index[w2[j]]: return False @@ -124,11 +156,11 @@ public class Solution { int[] orderIndex = new int[26]; for (int i = 0; i < order.length(); i++) orderIndex[order.charAt(i) - 'a'] = i; - + for (int i = 0; i < words.length - 1; i++) { String w1 = words[i], w2 = words[i + 1]; int j = 0; - + for (; j < w1.length(); j++) { if (j == w2.length()) return false; if (w1.charAt(j) != w2.charAt(j)) { @@ -151,11 +183,11 @@ public: int orderIndex[26] = {0}; for (int i = 0; i < order.size(); ++i) orderIndex[order[i] - 'a'] = i; - + for (int i = 0; i < words.size() - 1; ++i) { string w1 = words[i], w2 = words[i + 1]; int j = 0; - + for (; j < w1.size(); ++j) { if (j == w2.size()) return false; if (w1[j] != w2[j]) { @@ -182,15 +214,19 @@ class Solution { for (let i = 0; i < order.length; i++) { orderIndex[order.charCodeAt(i) - 97] = i; } - + for (let i = 0; i < words.length - 1; i++) { - let w1 = words[i], w2 = words[i + 1]; - + let w1 = words[i], + w2 = words[i + 1]; + for (let j = 0; j < w1.length; j++) { if (j === w2.length) return false; - + if (w1[j] !== w2[j]) { - if (orderIndex[w1.charCodeAt(j) - 97] > orderIndex[w2.charCodeAt(j) - 97]) + if ( + orderIndex[w1.charCodeAt(j) - 97] > + orderIndex[w2.charCodeAt(j) - 97] + ) return false; break; } @@ -201,11 +237,42 @@ class Solution { } ``` +```csharp +public class Solution { + public bool IsAlienSorted(string[] words, string order) { + Dictionary orderIndex = new Dictionary(); + for (int i = 0; i < order.Length; i++) { + orderIndex[order[i]] = i; + } + + for (int i = 0; i < words.Length - 1; i++) { + string w1 = words[i]; + string w2 = words[i + 1]; + + for (int j = 0; j < w1.Length; j++) { + if (j == w2.Length) { + return false; + } + + if (w1[j] != w2[j]) { + if (orderIndex[w1[j]] > orderIndex[w2[j]]) { + return false; + } + break; + } + } + } + + return true; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(n * m)$ -* Space complexity: $O(1)$ since we have $26$ different characters. +- Time complexity: $O(n * m)$ +- Space complexity: $O(1)$ since we have $26$ different characters. -> Where $n$ is the number of words and $m$ is the average length of a word. \ No newline at end of file +> Where $n$ is the number of words and $m$ is the average length of a word. diff --git a/articles/widest-vertical-area-between-two-points-containing-no-points.md b/articles/widest-vertical-area-between-two-points-containing-no-points.md new file mode 100644 index 000000000..9b08fdf4e --- /dev/null +++ b/articles/widest-vertical-area-between-two-points-containing-no-points.md @@ -0,0 +1,213 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def maxWidthOfVerticalArea(self, points: List[List[int]]) -> int: + n = len(points) + res = 0 + + for i in range(1, n): + x1 = points[i][0] + for j in range(i): + x2 = points[j][0] + hasPoints = False + for k in range(n): + if k == i or k == j: + continue + + x3 = points[k][0] + if x3 > min(x1, x2) and x3 < max(x1, x2): + hasPoints = True + break + + if not hasPoints: + res = max(res, abs(x1 - x2)) + + return res +``` + +```java +public class Solution { + public int maxWidthOfVerticalArea(int[][] points) { + int n = points.length, res = 0; + + for (int i = 1; i < n; i++) { + int x1 = points[i][0]; + for (int j = 0; j < i; j++) { + int x2 = points[j][0]; + boolean hasPoints = false; + + for (int k = 0; k < n; k++) { + if (k == i || k == j) continue; + + int x3 = points[k][0]; + if (x3 > Math.min(x1, x2) && x3 < Math.max(x1, x2)) { + hasPoints = true; + break; + } + } + + if (!hasPoints) { + res = Math.max(res, Math.abs(x1 - x2)); + } + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxWidthOfVerticalArea(vector>& points) { + int n = points.size(), res = 0; + + for (int i = 1; i < n; i++) { + int x1 = points[i][0]; + for (int j = 0; j < i; j++) { + int x2 = points[j][0]; + bool hasPoints = false; + + for (int k = 0; k < n; k++) { + if (k == i || k == j) continue; + + int x3 = points[k][0]; + if (x3 > min(x1, x2) && x3 < max(x1, x2)) { + hasPoints = true; + break; + } + } + + if (!hasPoints) { + res = max(res, abs(x1 - x2)); + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + maxWidthOfVerticalArea(points) { + let n = points.length, + res = 0; + + for (let i = 1; i < n; i++) { + let x1 = points[i][0]; + for (let j = 0; j < i; j++) { + let x2 = points[j][0]; + let hasPoints = false; + + for (let k = 0; k < n; k++) { + if (k === i || k === j) continue; + + let x3 = points[k][0]; + if (x3 > Math.min(x1, x2) && x3 < Math.max(x1, x2)) { + hasPoints = true; + break; + } + } + + if (!hasPoints) { + res = Math.max(res, Math.abs(x1 - x2)); + } + } + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n ^ 3)$ +- Space complexity: $O(1)$ + +--- + +## 2. Sorting + +::tabs-start + +```python +class Solution: + def maxWidthOfVerticalArea(self, points: List[List[int]]) -> int: + points.sort() + res = 0 + for i in range(len(points) - 1): + res = max(res, points[i + 1][0] - points[i][0]) + return res +``` + +```java +public class Solution { + public int maxWidthOfVerticalArea(int[][] points) { + Arrays.sort(points, Comparator.comparingInt(a -> a[0])); + int res = 0; + + for (int i = 0; i < points.length - 1; i++) { + res = Math.max(res, points[i + 1][0] - points[i][0]); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + int maxWidthOfVerticalArea(vector>& points) { + sort(points.begin(), points.end(), [](const auto& a, const auto& b) { + return a[0] < b[0]; + }); + + int res = 0; + for (int i = 0; i < points.size() - 1; i++) { + res = max(res, points[i + 1][0] - points[i][0]); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {number[][]} points + * @return {number} + */ + maxWidthOfVerticalArea(points) { + points.sort((a, b) => a[0] - b[0]); + let res = 0; + + for (let i = 0; i < points.length - 1; i++) { + res = Math.max(res, points[i + 1][0] - points[i][0]); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. diff --git a/articles/wiggle-sort.md b/articles/wiggle-sort.md index d18f99598..250815c41 100644 --- a/articles/wiggle-sort.md +++ b/articles/wiggle-sort.md @@ -67,7 +67,7 @@ class Solution { */ wiggleSort(nums) { const maxHeap = new PriorityQueue((a, b) => b - a); - nums.forEach(num => maxHeap.enqueue(num)); + nums.forEach((num) => maxHeap.enqueue(num)); for (let i = 1; i < nums.length; i += 2) { nums[i] = maxHeap.dequeue(); @@ -83,8 +83,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(n)$ +- Time complexity: $O(n \log n)$ +- Space complexity: $O(n)$ --- @@ -148,8 +148,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n \log n)$ -* Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. +- Time complexity: $O(n \log n)$ +- Space complexity: $O(1)$ or $O(n)$ depending on the sorting algorithm. --- @@ -163,7 +163,7 @@ class Solution: """ Do not return anything, modify nums in-place instead. """ - + for i in range(1, len(nums)): if ((i % 2 == 1 and nums[i] < nums[i - 1]) or (i % 2 == 0 and nums[i] > nums[i - 1]) @@ -208,8 +208,10 @@ class Solution { */ wiggleSort(nums) { for (let i = 1; i < nums.length; i++) { - if ((i % 2 == 1 && nums[i] < nums[i - 1]) || - (i % 2 == 0 && nums[i] > nums[i - 1])) { + if ( + (i % 2 == 1 && nums[i] < nums[i - 1]) || + (i % 2 == 0 && nums[i] > nums[i - 1]) + ) { [nums[i], nums[i - 1]] = [nums[i - 1], nums[i]]; } } @@ -221,8 +223,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ --- @@ -236,7 +238,7 @@ class Solution: """ Do not return anything, modify nums in-place instead. """ - + for i in range(1, len(nums)): if (i % 2) ^ (nums[i] > nums[i - 1]): nums[i], nums[i - 1] = nums[i - 1], nums[i] @@ -276,8 +278,8 @@ class Solution { * @return {void} Do not return anything, modify nums in-place instead. */ wiggleSort(nums) { - for(var i = 1; i < nums.length; i++) { - if ((i % 2) ^ (nums[i] > nums[i - 1])) { + for (var i = 1; i < nums.length; i++) { + if (i % 2 ^ (nums[i] > nums[i - 1])) { [nums[i], nums[i - 1]] = [nums[i - 1], nums[i]]; } } @@ -289,5 +291,5 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n)$ -* Space complexity: $O(1)$ \ No newline at end of file +- Time complexity: $O(n)$ +- Space complexity: $O(1)$ diff --git a/articles/word-break-ii.md b/articles/word-break-ii.md index c075d2b67..01c43f537 100644 --- a/articles/word-break-ii.md +++ b/articles/word-break-ii.md @@ -111,7 +111,7 @@ class Solution { const backtrack = (i) => { if (i === s.length) { - res.push(cur.join(" ")); + res.push(cur.join(' ')); return; } @@ -131,12 +131,41 @@ class Solution { } ``` +```csharp +public class Solution { + public List WordBreak(string s, List wordDict) { + HashSet wordSet = new HashSet(wordDict); + List res = new List(); + List cur = new List(); + + void Backtrack(int i) { + if (i == s.Length) { + res.Add(string.Join(" ", cur)); + return; + } + + for (int j = i; j < s.Length; j++) { + string word = s.Substring(i, j - i + 1); + if (wordSet.Contains(word)) { + cur.Add(word); + Backtrack(j + 1); + cur.RemoveAt(cur.Count - 1); + } + } + } + + Backtrack(0); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n * 2 ^ n)$ -* Space complexity: $O(m + 2 ^ n)$ +- Time complexity: $O(m + n * 2 ^ n)$ +- Space complexity: $O(m + 2 ^ n)$ > Where $n$ is the length of the string $s$ and $m$ is the sum of the lengths of the strings in the $wordDict$. @@ -155,7 +184,7 @@ class TrieNode: class Trie: def __init__(self): self.root = TrieNode() - + def addWord(self, word): curr = self.root for c in word: @@ -169,27 +198,27 @@ class Solution: trie = Trie() for word in wordDict: trie.addWord(word) - + def backtrack(i, path): if i == len(s): res.append(" ".join(path)) return - + node = trie.root word = [] for i in range(i, len(s)): char = s[i] if char not in node.children: break - + word.append(char) node = node.children[char] - + if node.isWord: path.append("".join(word)) backtrack(i + 1, path) path.pop() - + res = [] backtrack(0, []) return res @@ -372,12 +401,12 @@ class Solution { const res = []; const backtrack = (index, path) => { if (index === s.length) { - res.push(path.join(" ")); + res.push(path.join(' ')); return; } let node = trie.root; - let word = ""; + let word = ''; for (let i = index; i < s.length; i++) { const char = s[i]; if (!node.children.has(char)) { @@ -401,12 +430,72 @@ class Solution { } ``` +```csharp +public class TrieNode { + public Dictionary children = new Dictionary(); + public bool isWord = false; +} + +public class Trie { + public TrieNode root = new TrieNode(); + + public void AddWord(string word) { + TrieNode curr = root; + foreach (char c in word) { + if (!curr.children.ContainsKey(c)) { + curr.children[c] = new TrieNode(); + } + curr = curr.children[c]; + } + curr.isWord = true; + } +} + +public class Solution { + public List WordBreak(string s, List wordDict) { + Trie trie = new Trie(); + foreach (string word in wordDict) { + trie.AddWord(word); + } + + List res = new List(); + + void Backtrack(int index, List path) { + if (index == s.Length) { + res.Add(string.Join(" ", path)); + return; + } + + TrieNode node = trie.root; + StringBuilder word = new StringBuilder(); + + for (int i = index; i < s.Length; i++) { + char c = s[i]; + if (!node.children.ContainsKey(c)) break; + + word.Append(c); + node = node.children[c]; + + if (node.isWord) { + path.Add(word.ToString()); + Backtrack(i + 1, path); + path.RemoveAt(path.Count - 1); + } + } + } + + Backtrack(0, new List()); + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n * 2 ^ n)$ -* Space complexity: $O(m + 2 ^ n)$ +- Time complexity: $O(m + n * 2 ^ n)$ +- Space complexity: $O(m + 2 ^ n)$ > Where $n$ is the length of the string $s$ and $m$ is the sum of the lengths of the strings in the $wordDict$. @@ -532,7 +621,7 @@ class Solution { const backtrack = (i) => { if (i === s.length) { - return [""]; + return ['']; } if (cache.has(i)) { return cache.get(i); @@ -547,7 +636,7 @@ class Solution { for (const substr of strings) { let sentence = w; if (substr) { - sentence += " " + substr; + sentence += ' ' + substr; } res.push(sentence); } @@ -561,12 +650,46 @@ class Solution { } ``` +```csharp +public class Solution { + public List WordBreak(string s, List wordDictList) { + HashSet wordDict = new HashSet(wordDictList); + Dictionary> cache = new Dictionary>(); + + List Backtrack(int i) { + if (i == s.Length) return new List { "" }; + if (cache.ContainsKey(i)) return cache[i]; + + List res = new List(); + for (int j = i; j < s.Length; j++) { + string w = s.Substring(i, j - i + 1); + if (!wordDict.Contains(w)) continue; + + List substrings = Backtrack(j + 1); + foreach (string substr in substrings) { + string sentence = w; + if (!string.IsNullOrEmpty(substr)) { + sentence += " " + substr; + } + res.Add(sentence); + } + } + + cache[i] = res; + return res; + } + + return Backtrack(0); + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n * 2 ^ n)$ -* Space complexity: $O(m + n * 2 ^ n)$ +- Time complexity: $O(m + n * 2 ^ n)$ +- Space complexity: $O(m + n * 2 ^ n)$ > Where $n$ is the length of the string $s$ and $m$ is the sum of the lengths of the strings in the $wordDict$. @@ -627,7 +750,7 @@ public: int n = s.size(); vector> dp(n + 1); dp[0] = {""}; - + for (int i = 1; i <= n; ++i) { for (int j = 0; j < i; ++j) { string word = s.substr(j, i - j); @@ -642,7 +765,7 @@ public: } } } - + return dp[n]; } }; @@ -659,13 +782,41 @@ class Solution { const wordSet = new Set(wordDict); const n = s.length; const dp = Array.from({ length: n + 1 }, () => []); - dp[0].push(""); + dp[0].push(''); for (let i = 1; i <= n; i++) { for (let j = 0; j < i; j++) { if (wordSet.has(s.substring(j, i))) { for (const sentence of dp[j]) { - dp[i].push((sentence + " " + s.substring(j, i)).trim()); + dp[i].push((sentence + ' ' + s.substring(j, i)).trim()); + } + } + } + } + + return dp[n]; + } +} +``` + +```csharp +public class Solution { + public List WordBreak(string s, List wordDictList) { + HashSet wordSet = new HashSet(wordDictList); + int n = s.Length; + List[] dp = new List[n + 1]; + for (int i = 0; i <= n; i++) { + dp[i] = new List(); + } + dp[0].Add(""); + + for (int i = 1; i <= n; i++) { + for (int j = 0; j < i; j++) { + string word = s.Substring(j, i - j); + if (wordSet.Contains(word)) { + foreach (string sentence in dp[j]) { + string space = string.IsNullOrEmpty(sentence) ? "" : " "; + dp[i].Add(sentence + space + word); } } } @@ -680,8 +831,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(m + n * 2 ^ n)$ -* Space complexity: $O(m + n * 2 ^ n)$ +- Time complexity: $O(m + n * 2 ^ n)$ +- Space complexity: $O(m + n * 2 ^ n)$ > Where $n$ is the length of the string $s$ and $m$ is the sum of the lengths of the strings in the $wordDict$. @@ -700,7 +851,7 @@ class TrieNode: class Trie: def __init__(self): self.root = TrieNode() - + def addWord(self, word): curr = self.root for c in word: @@ -714,15 +865,15 @@ class Solution: trie = Trie() for word in wordDict: trie.addWord(word) - + cache = {} - + def backtrack(index): if index == len(s): return [""] if index in cache: return cache[index] - + res = [] curr = trie.root for i in range(index, len(s)): @@ -736,10 +887,10 @@ class Solution: res.append(s[index:i + 1] + " " + suffix) else: res.append(s[index:i + 1]) - + cache[index] = res return res - + return backtrack(0) ``` @@ -930,7 +1081,7 @@ class Solution { const backtrack = (index) => { if (index === s.length) { - return [""]; + return ['']; } if (cache.has(index)) { return cache.get(index); @@ -948,7 +1099,7 @@ class Solution { if (curr.isWord) { for (const suffix of backtrack(i + 1)) { if (suffix) { - res.push(s.slice(index, i + 1) + " " + suffix); + res.push(s.slice(index, i + 1) + ' ' + suffix); } else { res.push(s.slice(index, i + 1)); } @@ -965,11 +1116,73 @@ class Solution { } ``` +```csharp +public class TrieNode { + public Dictionary Children = new Dictionary(); + public bool IsWord = false; +} + +public class Trie { + public TrieNode Root = new TrieNode(); + + public void AddWord(string word) { + TrieNode curr = Root; + foreach (char c in word) { + if (!curr.Children.ContainsKey(c)) { + curr.Children[c] = new TrieNode(); + } + curr = curr.Children[c]; + } + curr.IsWord = true; + } +} + +public class Solution { + private Dictionary> cache = new Dictionary>(); + + public List WordBreak(string s, List wordDict) { + Trie trie = new Trie(); + foreach (string word in wordDict) { + trie.AddWord(word); + } + return Backtrack(0, s, trie.Root, trie); + } + + private List Backtrack(int index, string s, TrieNode root, Trie trie) { + if (index == s.Length) return new List { "" }; + if (cache.ContainsKey(index)) return cache[index]; + + List res = new List(); + TrieNode curr = root; + + for (int i = index; i < s.Length; i++) { + char c = s[i]; + if (!curr.Children.ContainsKey(c)) break; + + curr = curr.Children[c]; + if (curr.IsWord) { + List suffixes = Backtrack(i + 1, s, root, trie); + foreach (string suffix in suffixes) { + if (suffix == "") { + res.Add(s.Substring(index, i - index + 1)); + } else { + res.Add(s.Substring(index, i - index + 1) + " " + suffix); + } + } + } + } + + cache[index] = res; + return res; + } +} +``` + ::tabs-end ### Time & Space Complexity -* Time complexity: $O(m + n * 2 ^ n)$ -* Space complexity: $O(m + n * 2 ^ n)$ +- Time complexity: $O(m + n * 2 ^ n)$ +- Space complexity: $O(m + n * 2 ^ n)$ -> Where $n$ is the length of the string $s$ and $m$ is the sum of the lengths of the strings in the $wordDict$. \ No newline at end of file +> Where $n$ is the length of the string $s$ and $m$ is the sum of the lengths of the strings in the $wordDict$. diff --git a/articles/word-break.md b/articles/word-break.md index 908708670..4b03965f5 100644 --- a/articles/word-break.md +++ b/articles/word-break.md @@ -9,15 +9,15 @@ class Solution: def dfs(i): if i == len(s): return True - + for w in wordDict: - if ((i + len(w)) <= len(s) and + if ((i + len(w)) <= len(s) and s[i : i + len(w)] == w ): if dfs(i + len(w)): return True return False - + return dfs(0) ``` @@ -26,14 +26,14 @@ public class Solution { public boolean wordBreak(String s, List wordDict) { return dfs(s, wordDict, 0); } - + private boolean dfs(String s, List wordDict, int i) { if (i == s.length()) { return true; } for (String w : wordDict) { - if (i + w.length() <= s.length() && + if (i + w.length() <= s.length() && s.substring(i, i + w.length()).equals(w)) { if (dfs(s, wordDict, i + w.length())) { return true; @@ -59,7 +59,7 @@ private: } for (const string& w : wordDict) { - if (i + w.length() <= s.length() && + if (i + w.length() <= s.length() && s.substr(i, w.length()) == w) { if (dfs(s, wordDict, i + w.length())) { return true; @@ -94,8 +94,10 @@ class Solution { } for (let w of wordDict) { - if (i + w.length <= s.length && - s.substring(i, i + w.length) === w) { + if ( + i + w.length <= s.length && + s.substring(i, i + w.length) === w + ) { if (this.dfs(s, wordDict, i + w.length)) { return true; } @@ -118,7 +120,7 @@ public class Solution { } foreach (string w in wordDict) { - if (i + w.Length <= s.Length && + if (i + w.Length <= s.Length && s.Substring(i, w.Length) == w) { if (Dfs(s, wordDict, i + w.Length)) { return true; @@ -176,12 +178,38 @@ class Solution { } ``` +```swift +class Solution { + func wordBreak(_ s: String, _ wordDict: [String]) -> Bool { + let chars = Array(s) + + func dfs(_ i: Int) -> Bool { + if i == chars.count { + return true + } + + for w in wordDict { + if i + w.count <= chars.count, + String(chars[i.. Where $n$ is the length of the string $s$, $m$ is the number of words in $wordDict$ and $t$ is the maximum length of any word in $wordDict$. @@ -199,13 +227,13 @@ class Solution: def dfs(i): if i == len(s): return True - + for j in range(i, len(s)): if s[i : j + 1] in wordSet: if dfs(j + 1): return True return False - + return dfs(0) ``` @@ -281,7 +309,7 @@ class Solution { } } return false; - } + }; return dfs(0); } @@ -363,14 +391,40 @@ class Solution { } ``` +```swift +class Solution { + func wordBreak(_ s: String, _ wordDict: [String]) -> Bool { + let wordSet = Set(wordDict) + let chars = Array(s) + + func dfs(_ i: Int) -> Bool { + if i == chars.count { + return true + } + + for j in i..Where $n$ is the length of the string $s$ and $m$ is the number of words in $wordDict$. +> Where $n$ is the length of the string $s$ and $m$ is the number of words in $wordDict$. --- @@ -385,9 +439,9 @@ class Solution: def dfs(i): if i in memo: return memo[i] - + for w in wordDict: - if ((i + len(w)) <= len(s) and + if ((i + len(w)) <= len(s) and s[i : i + len(w)] == w ): if dfs(i + len(w)): @@ -395,7 +449,7 @@ class Solution: return True memo[i] = False return False - + return dfs(0) ``` @@ -415,7 +469,7 @@ public class Solution { } for (String w : wordDict) { - if (i + w.length() <= s.length() && + if (i + w.length() <= s.length() && s.substring(i, i + w.length()).equals(w)) { if (dfs(s, wordDict, i + w.length())) { memo.put(i, true); @@ -445,7 +499,7 @@ public: } for (const string& w : wordDict) { - if (i + w.length() <= s.length() && + if (i + w.length() <= s.length() && s.substr(i, w.length()) == w) { if (dfs(s, wordDict, i + w.length())) { memo[i] = true; @@ -487,8 +541,10 @@ class Solution { } for (let w of wordDict) { - if (i + w.length <= s.length && - s.substring(i, i + w.length) === w) { + if ( + i + w.length <= s.length && + s.substring(i, i + w.length) === w + ) { if (this.dfs(s, wordDict, i + w.length)) { this.memo[i] = true; return true; @@ -516,7 +572,7 @@ public class Solution { } foreach (var w in wordDict) { - if (i + w.Length <= s.Length && + if (i + w.Length <= s.Length && s.Substring(i, w.Length) == w) { if (Dfs(s, wordDict, i + w.Length)) { memo[i] = true; @@ -567,7 +623,7 @@ class Solution { memo[i]?.let { return it } for (w in wordDict) { - if (i + w.length <= s.length && + if (i + w.length <= s.length && s.substring(i, i + w.length) == w) { if (dfs(i + w.length)) { memo[i] = true @@ -585,12 +641,42 @@ class Solution { } ``` +```swift +class Solution { + func wordBreak(_ s: String, _ wordDict: [String]) -> Bool { + var memo = [Int: Bool]() + memo[s.count] = true + let chars = Array(s) + + func dfs(_ i: Int) -> Bool { + if let cached = memo[i] { + return cached + } + + for w in wordDict { + if i + w.count <= chars.count, + String(chars[i.. Where $n$ is the length of the string $s$, $m$ is the number of words in $wordDict$ and $t$ is the maximum length of any word in $wordDict$. @@ -621,7 +707,7 @@ class Solution: return True memo[i] = False return False - + return dfs(0) ``` @@ -851,12 +937,48 @@ class Solution { } ``` +```swift +class Solution { + func wordBreak(_ s: String, _ wordDict: [String]) -> Bool { + let wordSet = Set(wordDict) + var maxLen = 0 + for w in wordDict { + maxLen = max(maxLen, w.count) + } + + var memo = [Int: Bool]() + let chars = Array(s) + + func dfs(_ i: Int) -> Bool { + if let cached = memo[i] { + return cached + } + if i == chars.count { + return true + } + for j in i.. Where $n$ is the length of the string $s$, $m$ is the number of words in $wordDict$ and $t$ is the maximum length of any word in $wordDict$. @@ -890,7 +1012,7 @@ public class Solution { for (int i = s.length() - 1; i >= 0; i--) { for (String w : wordDict) { - if ((i + w.length()) <= s.length() && + if ((i + w.length()) <= s.length() && s.substring(i, i + w.length()).equals(w)) { dp[i] = dp[i + w.length()]; } @@ -914,7 +1036,7 @@ public: for (int i = s.size() - 1; i >= 0; i--) { for (const auto& w : wordDict) { - if ((i + w.size()) <= s.size() && + if ((i + w.size()) <= s.size() && s.substr(i, w.size()) == w) { dp[i] = dp[i + w.size()]; } @@ -942,8 +1064,10 @@ class Solution { for (let i = s.length - 1; i >= 0; i--) { for (const w of wordDict) { - if ( i + w.length <= s.length && - s.slice(i, i + w.length) === w) { + if ( + i + w.length <= s.length && + s.slice(i, i + w.length) === w + ) { dp[i] = dp[i + w.length]; } if (dp[i]) { @@ -965,7 +1089,7 @@ public class Solution { for (int i = s.Length - 1; i >= 0; i--) { foreach (string w in wordDict) { - if ((i + w.Length) <= s.Length && + if ((i + w.Length) <= s.Length && s.Substring(i, w.Length) == w) { dp[i] = dp[i + w.Length]; } @@ -1008,7 +1132,7 @@ class Solution { for (i in s.length - 1 downTo 0) { for (w in wordDict) { - if (i + w.length <= s.length && + if (i + w.length <= s.length && s.substring(i, i + w.length) == w) { dp[i] = dp[i + w.length] } @@ -1021,12 +1145,35 @@ class Solution { } ``` +```swift +class Solution { + func wordBreak(_ s: String, _ wordDict: [String]) -> Bool { + var dp = Array(repeating: false, count: s.count + 1) + dp[s.count] = true + let chars = Array(s) + + for i in stride(from: s.count - 1, through: 0, by: -1) { + for w in wordDict { + if i + w.count <= chars.count, String(chars[i.. Where $n$ is the length of the string $s$, $m$ is the number of words in $wordDict$ and $t$ is the maximum length of any word in $wordDict$. @@ -1074,7 +1221,7 @@ class Solution: t = 0 for w in wordDict: t = max(t, len(w)) - + for i in range(len(s), -1, -1): for j in range(i, min(len(s), i + t)): if trie.search(s, i, j): @@ -1086,7 +1233,7 @@ class Solution: ``` ```java -public class TrieNode { +class TrieNode { HashMap children; boolean isWord; @@ -1096,7 +1243,7 @@ public class TrieNode { } } -public class Trie { +class Trie { TrieNode root; public Trie() { @@ -1497,11 +1644,75 @@ class Solution { } ``` +```swift +class TrieNode { + var children = [Character: TrieNode]() + var isWord = false +} + +class Trie { + private let root = TrieNode() + + func insert(_ word: String) { + var node = root + for char in word { + if node.children[char] == nil { + node.children[char] = TrieNode() + } + node = node.children[char]! + } + node.isWord = true + } + + func search(_ s: [Character], _ i: Int, _ j: Int) -> Bool { + var node = root + for idx in i...j { + if node.children[s[idx]] == nil { + return false + } + node = node.children[s[idx]]! + } + return node.isWord + } +} + +class Solution { + func wordBreak(_ s: String, _ wordDict: [String]) -> Bool { + let trie = Trie() + for word in wordDict { + trie.insert(word) + } + + var dp = Array(repeating: false, count: s.count + 1) + dp[s.count] = true + let chars = Array(s) + + var maxLen = 0 + for word in wordDict { + maxLen = max(maxLen, word.count) + } + + for i in stride(from: s.count, through: 0, by: -1) { + for j in i.. Where $n$ is the length of the string $s$, $m$ is the number of words in $wordDict$ and $t$ is the maximum length of any word in $wordDict$. \ No newline at end of file +> Where $n$ is the length of the string $s$, $m$ is the number of words in $wordDict$ and $t$ is the maximum length of any word in $wordDict$. diff --git a/articles/word-ladder.md b/articles/word-ladder.md index 2bc3893bf..a6a564c8a 100644 --- a/articles/word-ladder.md +++ b/articles/word-ladder.md @@ -7,7 +7,7 @@ class Solution: def ladderLength(self, beginWord: str, endWord: str, wordList: List[str]) -> int: if (endWord not in wordList) or (beginWord == endWord): return 0 - + n, m = len(wordList), len(wordList[0]) adj = [[] for _ in range(n)] mp = {} @@ -23,7 +23,7 @@ class Solution: if cnt == 1: adj[i].append(j) adj[j].append(i) - + q, res = deque(), 1 visit = set() for i in range(m): @@ -34,7 +34,7 @@ class Solution: if word in mp and mp[word] not in visit: q.append(mp[word]) visit.add(mp[word]) - + while q: res += 1 for i in range(len(q)): @@ -45,7 +45,7 @@ class Solution: if nei not in visit: visit.add(nei) q.append(nei) - + return 0 ``` @@ -55,14 +55,14 @@ public class Solution { if (!wordList.contains(endWord) || beginWord.equals(endWord)) { return 0; } - + int n = wordList.size(); int m = wordList.get(0).length(); List> adj = new ArrayList<>(n); for (int i = 0; i < n; i++) { adj.add(new ArrayList<>()); } - + Map mp = new HashMap<>(); for (int i = 0; i < n; i++) { mp.put(wordList.get(i), i); @@ -86,7 +86,7 @@ public class Solution { Queue q = new LinkedList<>(); int res = 1; Set visit = new HashSet<>(); - + for (int i = 0; i < m; i++) { for (char c = 'a'; c <= 'z'; c++) { if (c == beginWord.charAt(i)) { @@ -116,7 +116,7 @@ public class Solution { } } } - + return 0; } } @@ -126,11 +126,11 @@ public class Solution { class Solution { public: int ladderLength(string beginWord, string endWord, vector& wordList) { - if (find(wordList.begin(), wordList.end(), endWord) == wordList.end() || + if (find(wordList.begin(), wordList.end(), endWord) == wordList.end() || beginWord == endWord) { return 0; } - + int n = wordList.size(); int m = wordList[0].size(); vector> adj(n); @@ -157,7 +157,7 @@ public: queue q; int res = 1; unordered_set visit; - + for (int i = 0; i < m; i++) { for (char c = 'a'; c <= 'z'; c++) { if (c == beginWord[i]) { @@ -188,7 +188,7 @@ public: } } } - + return 0; } }; @@ -203,8 +203,7 @@ class Solution { * @return {number} */ ladderLength(beginWord, endWord, wordList) { - if (!wordList.includes(endWord) || - beginWord === endWord) { + if (!wordList.includes(endWord) || beginWord === endWord) { return 0; } @@ -212,7 +211,7 @@ class Solution { const m = wordList[0].length; const adj = Array.from({ length: n }, () => []); const mp = new Map(); - + for (let i = 0; i < n; i++) { mp.set(wordList[i], i); } @@ -241,8 +240,10 @@ class Solution { if (String.fromCharCode(c) === beginWord[i]) { continue; } - const word = beginWord.slice(0, i) + - String.fromCharCode(c) + beginWord.slice(i + 1); + const word = + beginWord.slice(0, i) + + String.fromCharCode(c) + + beginWord.slice(i + 1); if (mp.has(word) && !visit.has(mp.get(word))) { q.push(mp.get(word)); visit.add(mp.get(word)); @@ -266,7 +267,7 @@ class Solution { } } } - + return 0; } } @@ -278,14 +279,14 @@ public class Solution { if (!wordList.Contains(endWord) || beginWord == endWord) { return 0; } - + int n = wordList.Count; int m = wordList[0].Length; List> adj = new List>(n); for (int i = 0; i < n; i++) { adj.Add(new List()); } - + Dictionary mp = new Dictionary(); for (int i = 0; i < n; i++) { mp[wordList[i]] = i; @@ -309,13 +310,13 @@ public class Solution { Queue q = new Queue(); int res = 1; HashSet visit = new HashSet(); - + for (int i = 0; i < m; i++) { for (char c = 'a'; c <= 'z'; c++) { if (c == beginWord[i]) { continue; } - string word = beginWord.Substring(0, i) + c + + string word = beginWord.Substring(0, i) + c + beginWord.Substring(i + 1); if (mp.ContainsKey(word) && !visit.Contains(mp[word])) { q.Enqueue(mp[word]); @@ -340,7 +341,7 @@ public class Solution { } } } - + return 0; } } @@ -492,12 +493,90 @@ class Solution { } ``` +```swift +class Solution { + func ladderLength(_ beginWord: String, _ endWord: String, _ wordList: [String]) -> Int { + if !wordList.contains(endWord) || beginWord == endWord { + return 0 + } + + let n = wordList.count + let m = wordList[0].count + var adj = [[Int]](repeating: [], count: n) + var mp = [String: Int]() + + for i in 0..() + var res = 1 + var visit = Set() + let beginChars = Array(beginWord) + + for i in 0.. Where $n$ is the number of words and $m$ is the length of the word. @@ -539,7 +618,7 @@ public class Solution { int res = 0; Queue q = new LinkedList<>(); q.offer(beginWord); - + while (!q.isEmpty()) { res++; for (int i = q.size(); i > 0; i--) { @@ -571,7 +650,7 @@ public: int res = 0; queue q; q.push(beginWord); - + while (!q.empty()) { res++; int len = q.size(); @@ -613,7 +692,7 @@ class Solution { } let res = 0; const q = new Queue([beginWord]); - + while (!q.isEmpty()) { res++; let len = q.size(); @@ -625,9 +704,10 @@ class Solution { if (String.fromCharCode(c) === node[j]) { continue; } - const nei = node.slice(0, j) + - String.fromCharCode(c) + - node.slice(j + 1); + const nei = + node.slice(0, j) + + String.fromCharCode(c) + + node.slice(j + 1); if (words.has(nei)) { q.push(nei); words.delete(nei); @@ -649,7 +729,7 @@ public class Solution { int res = 0; var q = new Queue(); q.Enqueue(beginWord); - + while (q.Count > 0) { res++; int len = q.Count; @@ -697,7 +777,7 @@ func ladderLength(beginWord string, endWord string, wordList []string) int { for i := 0; i < size; i++ { node := q[0] q = q[1:] - + if node == endWord { return res } @@ -744,7 +824,7 @@ class Solution { res++ repeat(q.size) { val node = q.removeFirst() - + if (node == endWord) { return res } @@ -767,12 +847,55 @@ class Solution { } ``` +```swift +class Solution { + func ladderLength(_ beginWord: String, _ endWord: String, _ wordList: [String]) -> Int { + if !wordList.contains(endWord) || beginWord == endWord { + return 0 + } + + var words = Set(wordList) + var queue = Deque() + queue.append(beginWord) + var res = 0 + + while !queue.isEmpty { + res += 1 + for _ in 0.. Where $n$ is the number of words and $m$ is the length of the word. @@ -920,8 +1043,8 @@ class Solution { wordList.push(beginWord); for (const word of wordList) { for (let j = 0; j < word.length; ++j) { - const pattern = word.substring(0, j) + - '*' + word.substring(j + 1); + const pattern = + word.substring(0, j) + '*' + word.substring(j + 1); if (!nei[pattern]) { nei[pattern] = []; } @@ -930,7 +1053,7 @@ class Solution { } const visit = new Set([beginWord]); - const q =new Queue([beginWord]); + const q = new Queue([beginWord]); let res = 1; while (!q.isEmpty()) { const size = q.size(); @@ -940,8 +1063,8 @@ class Solution { return res; } for (let j = 0; j < word.length; ++j) { - const pattern = word.substring(0, j) + - '*' + word.substring(j + 1); + const pattern = + word.substring(0, j) + '*' + word.substring(j + 1); for (const neiWord of nei[pattern]) { if (!visit.has(neiWord)) { visit.add(neiWord); @@ -968,7 +1091,7 @@ public class Solution { wordList.Add(beginWord); foreach (string word in wordList) { for (int j = 0; j < word.Length; j++) { - string pattern = word.Substring(0, j) + + string pattern = word.Substring(0, j) + "*" + word.Substring(j + 1); if (!nei.ContainsKey(pattern)) { nei[pattern] = new List(); @@ -989,7 +1112,7 @@ public class Solution { return res; } for (int j = 0; j < word.Length; j++) { - string pattern = word.Substring(0, j) + + string pattern = word.Substring(0, j) + "*" + word.Substring(j + 1); if (nei.ContainsKey(pattern)) { foreach (string neiWord in nei[pattern]) { @@ -1033,7 +1156,7 @@ func ladderLength(beginWord string, endWord string, wordList []string) int { for i := len(q); i > 0; i-- { word := q[0] q = q[1:] - + if word == endWord { return res } @@ -1087,7 +1210,7 @@ class Solution { while (q.isNotEmpty()) { repeat(q.size) { val word = q.removeFirst() - + if (word == endWord) { return res } @@ -1108,12 +1231,67 @@ class Solution { } ``` +```swift +class Solution { + func ladderLength(_ beginWord: String, _ endWord: String, _ wordList: [String]) -> Int { + if !wordList.contains(endWord) { + return 0 + } + + var nei = [String: [String]]() + var wordList = wordList + wordList.append(beginWord) + + for word in wordList { + let wordArray = Array(word) + for j in 0.. = [beginWord] + var queue = Deque() + queue.append(beginWord) + var res = 1 + + while !queue.isEmpty { + for _ in 0.. Where $n$ is the number of words and $m$ is the length of the word. @@ -1132,7 +1310,7 @@ class Solution: wordSet = set(wordList) qb, qe = deque([beginWord]), deque([endWord]) fromBegin, fromEnd = {beginWord: 1}, {endWord: 1} - + while qb and qe: if len(qb) > len(qe): qb, qe = qe, qb @@ -1169,7 +1347,7 @@ public class Solution { qe.add(endWord); fromBegin.put(beginWord, 1); fromEnd.put(endWord, 1); - + while (!qb.isEmpty() && !qe.isEmpty()) { if (qb.size() > qe.size()) { Queue tempQ = qb; @@ -1187,7 +1365,7 @@ public class Solution { for (char c = 'a'; c <= 'z'; c++) { if (c == word.charAt(i)) continue; - String nei = word.substring(0, i) + + String nei = word.substring(0, i) + c + word.substring(i + 1); if (!wordSet.contains(nei)) continue; @@ -1210,7 +1388,7 @@ public class Solution { class Solution { public: int ladderLength(string beginWord, string endWord, vector& wordList) { - if (find(wordList.begin(), wordList.end(), endWord) == wordList.end() || + if (find(wordList.begin(), wordList.end(), endWord) == wordList.end() || beginWord == endWord) return 0; int m = wordList[0].size(); @@ -1221,7 +1399,7 @@ public: qe.push(endWord); fromBegin[beginWord] = 1; fromEnd[endWord] = 1; - + while (!qb.empty() && !qe.empty()) { if (qb.size() > qe.size()) { swap(qb, qe); @@ -1236,7 +1414,7 @@ public: for (char c = 'a'; c <= 'z'; c++) { if (c == word[i]) continue; - string nei = word.substr(0, i) + + string nei = word.substr(0, i) + c + word.substr(i + 1); if (!wordSet.count(nei)) continue; @@ -1264,8 +1442,7 @@ class Solution { * @return {number} */ ladderLength(beginWord, endWord, wordList) { - if (!wordList.includes(endWord) || - beginWord === endWord) { + if (!wordList.includes(endWord) || beginWord === endWord) { return 0; } const m = wordList[0].length; @@ -1286,13 +1463,12 @@ class Solution { const steps = fromBegin[word]; for (let i = 0; i < m; i++) { for (let c = 97; c <= 122; c++) { - if (String.fromCharCode(c) === word[i]) - continue; - const nei = word.slice(0, i) + - String.fromCharCode(c) + - word.slice(i + 1); - if (!wordSet.has(nei)) - continue; + if (String.fromCharCode(c) === word[i]) continue; + const nei = + word.slice(0, i) + + String.fromCharCode(c) + + word.slice(i + 1); + if (!wordSet.has(nei)) continue; if (fromEnd[nei] !== undefined) return steps + fromEnd[nei]; if (fromBegin[nei] === undefined) { @@ -1316,13 +1492,13 @@ public class Solution { int m = wordList[0].Length; HashSet wordSet = new HashSet(wordList); Queue qb = new Queue(), qe = new Queue(); - Dictionary fromBegin = new Dictionary(), + Dictionary fromBegin = new Dictionary(), fromEnd = new Dictionary(); qb.Enqueue(beginWord); qe.Enqueue(endWord); fromBegin[beginWord] = 1; fromEnd[endWord] = 1; - + while (qb.Count > 0 && qe.Count > 0) { if (qb.Count > qe.Count) { var tempQ = qb; @@ -1340,7 +1516,7 @@ public class Solution { for (char c = 'a'; c <= 'z'; c++) { if (c == word[i]) continue; - string nei = word.Substring(0, i) + + string nei = word.Substring(0, i) + c + word.Substring(i + 1); if (!wordSet.Contains(nei)) continue; @@ -1364,34 +1540,34 @@ func ladderLength(beginWord string, endWord string, wordList []string) int { if len(wordList) == 0 || len(beginWord) != len(wordList[0]) { return 0 } - + wordSet := make(map[string]bool) for _, word := range wordList { wordSet[word] = true } - + if !wordSet[endWord] || beginWord == endWord { return 0 } - + m := len(beginWord) qb := []string{beginWord} qe := []string{endWord} fromBegin := map[string]int{beginWord: 1} fromEnd := map[string]int{endWord: 1} - + for len(qb) > 0 && len(qe) > 0 { if len(qb) > len(qe) { qb, qe = qe, qb fromBegin, fromEnd = fromEnd, fromBegin } - + size := len(qb) for i := 0; i < size; i++ { word := qb[0] qb = qb[1:] steps := fromBegin[word] - + wordBytes := []byte(word) for j := 0; j < m; j++ { orig := wordBytes[j] @@ -1401,7 +1577,7 @@ func ladderLength(beginWord string, endWord string, wordList []string) int { } wordBytes[j] = c nei := string(wordBytes) - + if !wordSet[nei] { continue } @@ -1427,29 +1603,29 @@ class Solution { if (!wordList.contains(endWord) || beginWord == endWord) { return 0 } - + val m = wordList[0].length val wordSet = wordList.toSet() val qb = ArrayDeque().apply { add(beginWord) } val qe = ArrayDeque().apply { add(endWord) } val fromBegin = hashMapOf(beginWord to 1) val fromEnd = hashMapOf(endWord to 1) - + while (qb.isNotEmpty() && qe.isNotEmpty()) { if (qb.size > qe.size) { qb.swap(qe) fromBegin.swap(fromEnd) } - + repeat(qb.size) { val word = qb.removeFirst() val steps = fromBegin[word]!! - + for (i in 0 until m) { for (c in 'a'..'z') { if (c == word[i]) continue val nei = word.substring(0, i) + c + word.substring(i + 1) - + if (!wordSet.contains(nei)) continue fromEnd[nei]?.let { return steps + it } if (nei !in fromBegin) { @@ -1462,7 +1638,7 @@ class Solution { } return 0 } - + private fun ArrayDeque.swap(other: ArrayDeque) { val temp = ArrayDeque(this) this.clear() @@ -1470,7 +1646,7 @@ class Solution { other.clear() other.addAll(temp) } - + private fun HashMap.swap(other: HashMap) { val temp = HashMap() temp.putAll(this) @@ -1482,11 +1658,66 @@ class Solution { } ``` +```swift +class Solution { + func ladderLength(_ beginWord: String, _ endWord: String, _ wordList: [String]) -> Int { + if !wordList.contains(endWord) || beginWord == endWord { + return 0 + } + + let m = wordList[0].count + var wordSet = Set(wordList) + var qb = Deque([beginWord]) + var qe = Deque([endWord]) + var fromBegin = [beginWord: 1] + var fromEnd = [endWord: 1] + + while !qb.isEmpty && !qe.isEmpty { + if qb.count > qe.count { + swap(&qb, &qe) + swap(&fromBegin, &fromEnd) + } + + for _ in 0.. Where $n$ is the number of words and $m$ is the length of the word. \ No newline at end of file +> Where $n$ is the number of words and $m$ is the length of the word. diff --git a/articles/word-pattern.md b/articles/word-pattern.md index c09b50aa1..9aed8cbe2 100644 --- a/articles/word-pattern.md +++ b/articles/word-pattern.md @@ -97,7 +97,7 @@ class Solution { * @return {boolean} */ wordPattern(pattern, s) { - const words = s.split(" "); + const words = s.split(' '); if (pattern.length !== words.length) { return false; } @@ -128,8 +128,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(m)$ > Where $n$ is the length of the string $pattern$ and $m$ is the length of the string $s$. @@ -164,24 +164,24 @@ public class Solution { Map charToWord = new HashMap<>(); Map wordToChar = new HashMap<>(); String[] words = s.split(" "); - + if (words.length != pattern.length()) return false; - + for (int i = 0; i < pattern.length(); i++) { - if (charToWord.containsKey(pattern.charAt(i)) && + if (charToWord.containsKey(pattern.charAt(i)) && !words[charToWord.get(pattern.charAt(i))].equals(words[i])) { return false; } - - if (wordToChar.containsKey(words[i]) && + + if (wordToChar.containsKey(words[i]) && pattern.charAt(wordToChar.get(words[i])) != pattern.charAt(i)) { return false; } - + charToWord.put(pattern.charAt(i), i); wordToChar.put(words[i], i); } - + return true; } } @@ -216,20 +216,20 @@ class Solution { wordPattern(pattern, s) { const charToWord = new Map(); const wordToChar = new Map(); - const words = s.split(" "); - + const words = s.split(' '); + if (pattern.length !== words.length) { return false; } - + for (let i = 0; i < words.length; i++) { const c = pattern[i]; const word = words[i]; - + if ((charToWord.get(c) || 0) !== (wordToChar.get(word) || 0)) { return false; } - + charToWord.set(c, i + 1); wordToChar.set(word, i + 1); } @@ -243,8 +243,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(m)$ > Where $n$ is the length of the string $pattern$ and $m$ is the length of the string $s$. @@ -260,10 +260,10 @@ class Solution: words = s.split() if len(pattern) != len(words): return False - + charToWord = {} store = set() - + for i, (c, w) in enumerate(zip(pattern, words)): if c in charToWord: if words[charToWord[c]] != w: @@ -274,7 +274,7 @@ class Solution: charToWord[c] = i store.add(w) - return True + return True ``` ```java @@ -282,13 +282,13 @@ public class Solution { public boolean wordPattern(String pattern, String s) { String[] words = s.split(" "); if (pattern.length() != words.length) return false; - + Map charToWord = new HashMap<>(); Set store = new HashSet<>(); - + for (int i = 0; i < pattern.length(); i++) { char c = pattern.charAt(i); - + if (charToWord.containsKey(c)) { if (!words[charToWord.get(c)].equals(words[i])) { return false; @@ -301,7 +301,7 @@ public class Solution { store.add(words[i]); } } - + return true; } } @@ -314,19 +314,19 @@ public: stringstream ss(s); string word; vector words; - + while (ss >> word) { words.push_back(word); } - + if (pattern.length() != words.size()) return false; - + unordered_map charToWord; set store; - + for (int i = 0; i < pattern.length(); i++) { char c = pattern[i]; - + if (charToWord.count(c)) { if (words[charToWord[c]] != words[i]) { return false; @@ -339,7 +339,7 @@ public: store.insert(words[i]); } } - + return true; } }; @@ -355,20 +355,20 @@ class Solution { wordPattern(pattern, s) { const charToWord = new Map(); const wordToChar = new Map(); - const words = s.split(" "); - + const words = s.split(' '); + if (pattern.length !== words.length) { return false; } - + for (let i = 0; i < words.length; i++) { const c = pattern[i]; const word = words[i]; - + if ((charToWord.get(c) || 0) !== (wordToChar.get(word) || 0)) { return false; } - + charToWord.set(c, i + 1); wordToChar.set(word, i + 1); } @@ -382,8 +382,8 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(m)$ > Where $n$ is the length of the string $pattern$ and $m$ is the length of the string $s$. @@ -399,9 +399,9 @@ class Solution: words = s.split() if len(pattern) != len(words): return False - + charToWord = {} - + for i, (c, w) in enumerate(zip(pattern, words)): if c in charToWord: if words[charToWord[c]] != w: @@ -413,7 +413,7 @@ class Solution: return False charToWord[c] = i - return True + return True ``` ```java @@ -457,7 +457,7 @@ public: while (ss >> word) { words.push_back(word); } - + if (pattern.size() != words.size()) { return false; } @@ -494,7 +494,7 @@ class Solution { * @return {boolean} */ wordPattern(pattern, s) { - const words = s.split(" "); + const words = s.split(' '); if (pattern.length !== words.length) { return false; } @@ -517,7 +517,7 @@ class Solution { charToWord.set(c, i); } } - + return true; } } @@ -527,7 +527,7 @@ class Solution { ### Time & Space Complexity -* Time complexity: $O(n + m)$ -* Space complexity: $O(m)$ +- Time complexity: $O(n + m)$ +- Space complexity: $O(m)$ -> Where $n$ is the length of the string $pattern$ and $m$ is the length of the string $s$. \ No newline at end of file +> Where $n$ is the length of the string $pattern$ and $m$ is the length of the string $s$. diff --git a/articles/word-subsets.md b/articles/word-subsets.md new file mode 100644 index 000000000..cb9fdcbb6 --- /dev/null +++ b/articles/word-subsets.md @@ -0,0 +1,293 @@ +## 1. Brute Force + +::tabs-start + +```python +class Solution: + def wordSubsets(self, words1: List[str], words2: List[str]) -> List[str]: + res = [] + for w1 in words1: + count1 = Counter(w1) + is_subset = True + + for w2 in words2: + count2 = Counter(w2) + for c in count2: + if count2[c] > count1[c]: + is_subset = False + break + + if not is_subset: break + + if is_subset: + res.append(w1) + + return res +``` + +```java +public class Solution { + public List wordSubsets(String[] words1, String[] words2) { + List res = new ArrayList<>(); + + for (String w1 : words1) { + int[] count1 = new int[26]; + for (char c : w1.toCharArray()) count1[c - 'a']++; + + boolean isSubset = true; + for (String w2 : words2) { + int[] count2 = new int[26]; + for (char c : w2.toCharArray()) count2[c - 'a']++; + + for (int i = 0; i < 26; i++) { + if (count2[i] > count1[i]) { + isSubset = false; + break; + } + } + + if (!isSubset) break; + } + + if (isSubset) res.add(w1); + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector wordSubsets(vector& words1, vector& words2) { + vector res; + + for (const string& w1 : words1) { + vector count1(26, 0); + for (char c : w1) count1[c - 'a']++; + + bool isSubset = true; + for (const string& w2 : words2) { + vector count2(26, 0); + for (char c : w2) count2[c - 'a']++; + + for (int i = 0; i < 26; i++) { + if (count2[i] > count1[i]) { + isSubset = false; + break; + } + } + + if (!isSubset) break; + } + + if (isSubset) res.push_back(w1); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words1 + * @param {string[]} words2 + * @return {string[]} + */ + wordSubsets(words1, words2) { + const res = []; + + for (const w1 of words1) { + const count1 = Array(26).fill(0); + for (const c of w1) count1[c.charCodeAt(0) - 97]++; + + let isSubset = true; + for (const w2 of words2) { + const count2 = Array(26).fill(0); + for (const c of w2) count2[c.charCodeAt(0) - 97]++; + + for (let i = 0; i < 26; i++) { + if (count2[i] > count1[i]) { + isSubset = false; + break; + } + } + + if (!isSubset) break; + } + + if (isSubset) res.push(w1); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(N * n + N * M * m)$ +- Space complexity: + - $O(1)$ extra space, since we have at most $26$ different characters. + - $O(N * n)$ space for the output list. + +> Where $N$ is the size of the array $words1$, $n$ is the length of the longest word in $words1$, $M$ is the size of the array $words2$, and $m$ is the length of the longest word in $words2$. + +--- + +## 2. Greedy + Hash Map + +::tabs-start + +```python +class Solution: + def wordSubsets(self, words1: List[str], words2: List[str]) -> List[str]: + count_2 = defaultdict(int) + for w in words2: + count_w = Counter(w) + for c, cnt in count_w.items(): + count_2[c] = max(count_2[c], cnt) + + res = [] + for w in words1: + count_w = Counter(w) + flag = True + for c, cnt in count_2.items(): + if count_w[c] < cnt: + flag = False + break + if flag: + res.append(w) + + return res +``` + +```java +public class Solution { + public List wordSubsets(String[] words1, String[] words2) { + int[] count2 = new int[26]; + for (String w : words2) { + int[] countW = new int[26]; + for (char c : w.toCharArray()) { + countW[c - 'a']++; + } + for (int i = 0; i < 26; i++) { + count2[i] = Math.max(count2[i], countW[i]); + } + } + + List res = new ArrayList<>(); + for (String w : words1) { + int[] countW = new int[26]; + for (char c : w.toCharArray()) { + countW[c - 'a']++; + } + + boolean flag = true; + for (int i = 0; i < 26; i++) { + if (countW[i] < count2[i]) { + flag = false; + break; + } + } + + if (flag) { + res.add(w); + } + } + + return res; + } +} +``` + +```cpp +class Solution { +public: + vector wordSubsets(vector& words1, vector& words2) { + vector count2(26, 0); + for (string& w : words2) { + vector countW(26, 0); + for (char c : w) countW[c - 'a']++; + for (int i = 0; i < 26; ++i) + count2[i] = max(count2[i], countW[i]); + } + + vector res; + for (string& w : words1) { + vector countW(26, 0); + for (char c : w) countW[c - 'a']++; + + bool flag = true; + for (int i = 0; i < 26; ++i) { + if (countW[i] < count2[i]) { + flag = false; + break; + } + } + + if (flag) res.push_back(w); + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string[]} words1 + * @param {string[]} words2 + * @return {string[]} + */ + wordSubsets(words1, words2) { + const count2 = new Array(26).fill(0); + for (let w of words2) { + const countW = new Array(26).fill(0); + for (let c of w) { + countW[c.charCodeAt(0) - 97]++; + } + for (let i = 0; i < 26; i++) { + count2[i] = Math.max(count2[i], countW[i]); + } + } + + const res = []; + for (let w of words1) { + const countW = new Array(26).fill(0); + for (let c of w) { + countW[c.charCodeAt(0) - 97]++; + } + + let flag = true; + for (let i = 0; i < 26; i++) { + if (countW[i] < count2[i]) { + flag = false; + break; + } + } + + if (flag) res.push(w); + } + + return res; + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(N * n + M * m)$ +- Space complexity: + - $O(1)$ extra space, since we have at most $26$ different characters. + - $O(N * n)$ space for the output list. + +> Where $N$ is the size of the array $words1$, $n$ is the length of the longest word in $words1$, $M$ is the size of the array $words2$, and $m$ is the length of the longest word in $words2$. diff --git a/articles/zigzag-conversion.md b/articles/zigzag-conversion.md new file mode 100644 index 000000000..e0a388017 --- /dev/null +++ b/articles/zigzag-conversion.md @@ -0,0 +1,281 @@ +## 1. Iteration - I + +::tabs-start + +```python +class Solution: + def convert(self, s: str, numRows: int) -> str: + if numRows == 1: + return s + + res = [] + for r in range(numRows): + increment = 2 * (numRows - 1) + for i in range(r, len(s), increment): + res.append(s[i]) + if r > 0 and r < numRows - 1 and i + increment - 2 * r < len(s): + res.append(s[i + increment - 2 * r]) + + return ''.join(res) +``` + +```java +public class Solution { + public String convert(String s, int numRows) { + if (numRows == 1) { + return s; + } + + StringBuilder res = new StringBuilder(); + int len = s.length(); + + for (int r = 0; r < numRows; r++) { + int increment = 2 * (numRows - 1); + for (int i = r; i < len; i += increment) { + res.append(s.charAt(i)); + if (r > 0 && r < numRows - 1 && i + increment - 2 * r < len) { + res.append(s.charAt(i + increment - 2 * r)); + } + } + } + + return res.toString(); + } +} +``` + +```cpp +class Solution { +public: + string convert(string s, int numRows) { + if (numRows == 1) { + return s; + } + + string res; + int len = s.size(); + + for (int r = 0; r < numRows; r++) { + int increment = 2 * (numRows - 1); + for (int i = r; i < len; i += increment) { + res += s[i]; + if (r > 0 && r < numRows - 1 && i + increment - 2 * r < len) { + res += s[i + increment - 2 * r]; + } + } + } + + return res; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {number} numRows + * @return {string} + */ + convert(s, numRows) { + if (numRows === 1) { + return s; + } + + let res = []; + const len = s.length; + + for (let r = 0; r < numRows; r++) { + const increment = 2 * (numRows - 1); + for (let i = r; i < len; i += increment) { + res.push(s[i]); + if (r > 0 && r < numRows - 1 && i + increment - 2 * r < len) { + res.push(s[i + increment - 2 * r]); + } + } + } + + return res.join(''); + } +} +``` + +```csharp +public class Solution { + public string Convert(string s, int numRows) { + if (numRows == 1) { + return s; + } + + var res = new StringBuilder(); + int increment = 2 * (numRows - 1); + for (int r = 0; r < numRows; r++) { + for (int i = r; i < s.Length; i += increment) { + res.Append(s[i]); + int secondIdx = i + increment - 2 * r; + if (r > 0 && r < numRows - 1 && secondIdx < s.Length) { + res.Append(s[secondIdx]); + } + } + } + + return res.ToString(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for the ouput string. + +--- + +## 2. Iteration - II + +::tabs-start + +```python +class Solution: + def convert(self, s: str, numRows: int) -> str: + if numRows == 1 or numRows >= len(s): + return s + + res = [[] for _ in range(numRows)] + row, dir = 0, 1 + for c in s: + res[row].append(c) + row += dir + if row == 0 or row == (numRows - 1): + dir *= -1 + + return ''.join([''.join(row) for row in res]) +``` + +```java +public class Solution { + public String convert(String s, int numRows) { + if (numRows == 1 || numRows >= s.length()) { + return s; + } + + List[] res = new ArrayList[numRows]; + for (int i = 0; i < numRows; i++) { + res[i] = new ArrayList<>(); + } + + int row = 0, dir = 1; + for (int i = 0; i < s.length(); i++) { + res[row].add(s.charAt(i)); + row += dir; + if (row == 0 || row == numRows - 1) { + dir *= -1; + } + } + + StringBuilder result = new StringBuilder(); + for (List rowList : res) { + for (char c : rowList) { + result.append(c); + } + } + return result.toString(); + } +} +``` + +```cpp +class Solution { +public: + string convert(string s, int numRows) { + if (numRows == 1 || numRows >= s.size()) { + return s; + } + + vector res(numRows); + int row = 0, dir = 1; + + for (char& c : s) { + res[row] += c; + row += dir; + if (row == 0 || row == numRows - 1) { + dir *= -1; + } + } + + string result; + for (string& rowString : res) { + result += rowString; + } + return result; + } +}; +``` + +```javascript +class Solution { + /** + * @param {string} s + * @param {number} numRows + * @return {string} + */ + convert(s, numRows) { + if (numRows === 1 || numRows >= s.length) { + return s; + } + + const res = Array.from({ length: numRows }, () => []); + let row = 0, + dir = 1; + + for (const c of s) { + res[row].push(c); + row += dir; + if (row === 0 || row === numRows - 1) { + dir *= -1; + } + } + + return res.map((row) => row.join('')).join(''); + } +} +``` + +```csharp +public class Solution { + public string Convert(string s, int numRows) { + if (numRows == 1 || numRows >= s.Length) { + return s; + } + + var res = new List(numRows); + for (int i = 0; i < numRows; i++) { + res.Add(new StringBuilder()); + } + + int row = 0, dir = 1; + foreach (char c in s) { + res[row].Append(c); + row += dir; + if (row == 0 || row == numRows - 1) { + dir = -dir; + } + } + + var result = new StringBuilder(); + foreach (var sb in res) { + result.Append(sb); + } + return result.ToString(); + } +} +``` + +::tabs-end + +### Time & Space Complexity + +- Time complexity: $O(n)$ +- Space complexity: $O(n)$ for the output string. diff --git a/hints/add-two-numbers.md b/hints/add-two-numbers.md index 2cdafc4fa..5813a0333 100644 --- a/hints/add-two-numbers.md +++ b/hints/add-two-numbers.md @@ -20,4 +20,4 @@

We track the extra value, carry, here as well. We iterate through the lists l1 and l2 until both lists reach null. We add the values of both nodes as well as the carry. If either of the nodes is null, we add 0 in its place and continue the process while tracking the carry simultaneously. Once we complete the process, if we are left with any carry, we add an extra node with that carry value and return the head of the result list.

- \ No newline at end of file + diff --git a/hints/anagram-groups.md b/hints/anagram-groups.md index b77b383f8..34708db8c 100644 --- a/hints/anagram-groups.md +++ b/hints/anagram-groups.md @@ -28,4 +28,4 @@

We can simply use an array of size O(26), since the character set is a through z (26 continuous characters), to count the frequency of each character in a string. Then, we can use this array as the key in the hash map to group the strings.

- \ No newline at end of file + diff --git a/hints/balanced-binary-tree.md b/hints/balanced-binary-tree.md index 51473ca01..aa4796f99 100644 --- a/hints/balanced-binary-tree.md +++ b/hints/balanced-binary-tree.md @@ -20,4 +20,4 @@

We can use the Depth First Search (DFS) algorithm to compute the heights at each node. While calculating the heights of the left and right subtrees, we also check if the tree rooted at the current node is balanced. If leftHeight - rightHeight > 1, we update a global variable, such as isBalanced = False. After traversing all the nodes, the value of isBalanced indicates whether the entire tree is balanced or not.

- \ No newline at end of file + diff --git a/hints/binary-search.md b/hints/binary-search.md index a1a01c8e2..f46678074 100644 --- a/hints/binary-search.md +++ b/hints/binary-search.md @@ -36,4 +36,4 @@

Because the array is sorted, all elements to the left of mid (including 3) are guaranteed to be smaller than the target. Therefore, we can safely eliminate that half of the array from consideration, narrowing the search to the right half and repeat this search until we find the target.

- \ No newline at end of file + diff --git a/hints/binary-tree-diameter.md b/hints/binary-tree-diameter.md index d8c6b6ec3..654308abe 100644 --- a/hints/binary-tree-diameter.md +++ b/hints/binary-tree-diameter.md @@ -36,4 +36,4 @@

We can use the Depth First Search (DFS) algorithm to calculate the height of the tree. At each node, the subtrees return their respective heights (leftHeight and rightHeight). Then we calculate the diameter at that node as d = leftHeight + rightHeight. We use a global variable to update the maximum diameter as needed during the traversal.

- \ No newline at end of file + diff --git a/hints/binary-tree-from-preorder-and-inorder-traversal.md b/hints/binary-tree-from-preorder-and-inorder-traversal.md index d46b6141c..0b5f198ab 100644 --- a/hints/binary-tree-from-preorder-and-inorder-traversal.md +++ b/hints/binary-tree-from-preorder-and-inorder-traversal.md @@ -44,4 +44,4 @@

We use Depth First Search (DFS) to construct the tree. A global variable tracks the current index in the pre-order array. Indices l and r represent the segment in the in-order array for the current subtree. For each node in the pre-order array, we create a node, find its index in the in-order array using the hash map, and recursively build the left and right subtrees by splitting the range [l, r] into two parts for the left and right subtrees.

- \ No newline at end of file + diff --git a/hints/binary-tree-maximum-path-sum.md b/hints/binary-tree-maximum-path-sum.md index 318e1a388..c6db48d91 100644 --- a/hints/binary-tree-maximum-path-sum.md +++ b/hints/binary-tree-maximum-path-sum.md @@ -36,4 +36,4 @@

We return the maximum path sum from the current node to its parent, considering only one of the subtrees (either left or right) to extend the path. While calculating the left and right subtree path sums, we also ensure that we take the maximum with 0 to avoid negative sums, indicating that we should not include the subtree path in the calculation of the maximum path at the current node.

- \ No newline at end of file + diff --git a/hints/binary-tree-right-side-view.md b/hints/binary-tree-right-side-view.md index a02d2c585..c1ad99fe3 100644 --- a/hints/binary-tree-right-side-view.md +++ b/hints/binary-tree-right-side-view.md @@ -28,4 +28,4 @@

We can use the Breadth First Search (BFS) algorithm to traverse the tree level by level. Once we completely visit a level, we take the last node of that level and add it to the result array. After processing all levels, we return the result.

- \ No newline at end of file + diff --git a/hints/burst-balloons.md b/hints/burst-balloons.md new file mode 100644 index 000000000..10e8011cb --- /dev/null +++ b/hints/burst-balloons.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n ^ 3) time and O(n ^ 2) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ Try to simulate the process recursively by passing the array to the recursive function. At each step, iterate through the array, pop an element, and recursively apply the same process to the two subarrays on both sides of the popped element, returning the maximum result from all recursive paths. This approach is exponential. Can you think of a way to optimize it? Maybe you should consider observing the subproblems instead of modifying the array. +

+
+ +
+
+ Hint 2 +

+ Instead of passing the array, we can pass the range of indices l and r that need to be processed. We pad the input array with 1s on both sides for easier computation, but l and r represent the first and last indices of the original input array. Can you think of a reverse engineering approach for popping elements? +

+
+ +
+
+ Hint 3 +

+ We determine the result by considering each element as the last one to be popped in the current range. For each element, we calculate its value by multiplying it with the elements at l - 1 and r + 1, then recursively solve the subproblems for the ranges (l, i - 1) and (i + 1, r), where i is the current element in the given range. Can you think of a way to optimize and avoid redundant calculations? +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results of recursive calls and avoid redundant calculations. A hash map or a 2D array can be used to store results since the recursive function parameters l and r are within the range of the input array size. +

+
diff --git a/hints/buy-and-sell-crypto-with-cooldown.md b/hints/buy-and-sell-crypto-with-cooldown.md new file mode 100644 index 000000000..b62688da9 --- /dev/null +++ b/hints/buy-and-sell-crypto-with-cooldown.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(n) time and O(n) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ Try to think in terms of recursion and visualize it as a decision tree. Can you determine the possible decisions at each recursion step? Also, can you identify the base cases and the essential information that needs to be tracked during recursion? +

+
+ +
+
+ Hint 2 +

+ At each recursion step, we can buy only if we haven't already bought a coin, or we can sell if we own one. When buying, we subtract the coin value, and when selling, we add it. We explore all possible buying and selling options recursively, iterating through the coins from left to right using index i. For the cooldown condition, if we buy a coin, we increment the index i by two. +

+
+ +
+
+ Hint 3 +

+ We can use a boolean variable canBuy to indicate whether buying is allowed at the current recursive step. If we go out of bounds, we return 0. This approach is exponential. Can you think of a way to optimize it? +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results of recursive calls and avoid recalculations. A hash map or a 2D array can be used to store these results. +

+
diff --git a/hints/buy-and-sell-crypto.md b/hints/buy-and-sell-crypto.md index 0597ae13a..19f125d59 100644 --- a/hints/buy-and-sell-crypto.md +++ b/hints/buy-and-sell-crypto.md @@ -36,4 +36,4 @@

We are trying to maximize profit = sell - buy. If the current i is the sell value, we want to choose the minimum buy value to the left of i to maximize the profit. The result will be the maximum profit among all. However, if all profits are negative, we can return 0 since we are allowed to skip doing transaction.

- \ No newline at end of file + diff --git a/hints/car-fleet.md b/hints/car-fleet.md index 23c63e134..350b5ee6a 100644 --- a/hints/car-fleet.md +++ b/hints/car-fleet.md @@ -36,4 +36,4 @@

We can use a stack to maintain the times of the fleets. As we iterate through the array (sorted in descending order of positions), we compute the time for each car to reach the target and check if it can form a fleet with the car ahead. If the current car's time is less than or equal to the top of the stack, it joins the same fleet. Otherwise, it forms a new fleet, and we push its time onto the stack. The length of the stack at the end represents the total number of fleets formed.

- \ No newline at end of file + diff --git a/hints/cheapest-flight-path.md b/hints/cheapest-flight-path.md index b42275442..865960823 100644 --- a/hints/cheapest-flight-path.md +++ b/hints/cheapest-flight-path.md @@ -28,4 +28,4 @@

At each level of iteration, we go through the given flights and use them to update the price array with the minimum costs compared to the previous level. We use a temporary prices array at each level to store the updated costs. After completing all levels, we return the result stored in prices[dst]. If that value is Infinity, we return -1 instead.

- \ No newline at end of file + diff --git a/hints/climbing-stairs.md b/hints/climbing-stairs.md index 78e5ce36b..72d35d8a4 100644 --- a/hints/climbing-stairs.md +++ b/hints/climbing-stairs.md @@ -36,4 +36,4 @@

At each recursion, we perform two recursive calls: one for climbing one step and another for climbing two steps. The minimum return value between the two is the result for the current recursion. The base condition is to return 0 if i == n. This is a one-dimensional dynamic programming problem, which can be further optimized using more advanced techniques.

- \ No newline at end of file + diff --git a/hints/clone-graph.md b/hints/clone-graph.md index 1e332bf4a..337204291 100644 --- a/hints/clone-graph.md +++ b/hints/clone-graph.md @@ -28,4 +28,4 @@

We stop this recursive path when we encounter a node that has already been cloned or visited. This DFS approach creates an exact clone of the given graph, and we return the clone of the given node.

- \ No newline at end of file + diff --git a/hints/coin-change-ii.md b/hints/coin-change-ii.md new file mode 100644 index 000000000..dadc9b273 --- /dev/null +++ b/hints/coin-change-ii.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(n * a) time and O(n * a) space, where n is the number of coins and a is the given amount. +

+
+ +
+
+ Hint 1 +

+ As we need to find the total number of combinations, think in terms of recursion and visualize it as a decision tree where multiple coin choices are available at each recursion step. Can you determine a way to allow picking the same coin multiple times? Maybe you should consider the decisions made at each recursion step. +

+
+ +
+
+ Hint 2 +

+ The given coins are unique. We recursively iterate through the coins array using index i, tracking the collected amount along the current path. At each step, we can either skip the current coin or pick it, ensuring the total does not exceed the target. To allow picking the same coin multiple times, we recurse with the same index but an updated amount, generating different combinations. +

+
+ +
+
+ Hint 3 +

+ If we reach the target amount, we return 1. The recursion stops if the index goes out of bounds. We count all possible ways and return the total. This approach is exponential. Can you think of a way to optimize it? Maybe you should consider an approach to avoid redundant computations. +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results of recursive calls and avoid redundant computations. A hash map or a 2D array can be used to store these results. +

+
diff --git a/hints/coin-change.md b/hints/coin-change.md index c8522e7cb..15bc86ed2 100644 --- a/hints/coin-change.md +++ b/hints/coin-change.md @@ -28,4 +28,4 @@

We can use memoization to avoid the repeated work of calculating the result for each recursive call. A hash map or an array of size t can be used to cache the computed values for a specific amount. At each recursion step, we iterate over every coin and extend only the valid paths. If a result has already been computed, we return it from the cache instead of recalculating it.

- \ No newline at end of file + diff --git a/hints/combination-target-sum-ii.md b/hints/combination-target-sum-ii.md index ef8aabd56..4d2115d9c 100644 --- a/hints/combination-target-sum-ii.md +++ b/hints/combination-target-sum-ii.md @@ -28,4 +28,4 @@

We recursively traverse the given array starting at index i, with a variable sum representing the sum of the picked elements. We explore elements from i to the end of the array and extend the recursive path if adding the current element results in sum <= target. When we processed an element, we backtrack and proceed to the next distinct element, skipping any similar elements in the middle to avoid duplicate combinations.

- \ No newline at end of file + diff --git a/hints/combination-target-sum.md b/hints/combination-target-sum.md index 1eca71f3f..c4cd75c35 100644 --- a/hints/combination-target-sum.md +++ b/hints/combination-target-sum.md @@ -28,4 +28,4 @@

We recursively traverse the array starting from index i. At each step, we select an element from i to the end of the array. We extend the recursive path with elements where sum <= target after including that element. This creates multiple recursive paths, and we append the current list to the result whenever the base condition is met.

- \ No newline at end of file + diff --git a/hints/combinations-of-a-phone-number.md b/hints/combinations-of-a-phone-number.md index 7154a859d..f500d84c5 100644 --- a/hints/combinations-of-a-phone-number.md +++ b/hints/combinations-of-a-phone-number.md @@ -28,4 +28,4 @@

We initialize an empty string that represents the choices of the characters throughout the current recursive path. When the index i reaches the end of the string, we add the current string to the result list and return.

- \ No newline at end of file + diff --git a/hints/copy-linked-list-with-random-pointer.md b/hints/copy-linked-list-with-random-pointer.md index 73a1417ae..05dc7eec3 100644 --- a/hints/copy-linked-list-with-random-pointer.md +++ b/hints/copy-linked-list-with-random-pointer.md @@ -28,4 +28,4 @@

We can use a hash data structure, such as a hash map, which takes O(1) time to retrieve data. This can help by mapping the original nodes to their corresponding copies. This way, we can easily retrieve the copy of any node and assign the random pointers in a subsequent pass after creating copies of all nodes in the first pass.

- \ No newline at end of file + diff --git a/hints/count-connected-components.md b/hints/count-connected-components.md index 4998f22ad..50dc73666 100644 --- a/hints/count-connected-components.md +++ b/hints/count-connected-components.md @@ -28,4 +28,4 @@

We create an object of the DSU and initialize the result variable res = n, which indicates that there are n components initially. We then iterate through the given edges. For each edge, we attempt to connect the nodes using the union function of the DSU. If the union is successful, we decrement res; otherwise, we continue. Finally, we return res as the number of components.

- \ No newline at end of file + diff --git a/hints/count-good-nodes-in-binary-tree.md b/hints/count-good-nodes-in-binary-tree.md index 39e8783d5..f9296abf7 100644 --- a/hints/count-good-nodes-in-binary-tree.md +++ b/hints/count-good-nodes-in-binary-tree.md @@ -28,4 +28,4 @@

While traversing the tree, we should track the maximum value along the current path. This allows us to determine whether the nodes we encounter are good. We can use a global variable to count the number of good nodes.

- \ No newline at end of file + diff --git a/hints/count-number-of-islands.md b/hints/count-number-of-islands.md index a8cb92e6f..a7c1d8537 100644 --- a/hints/count-number-of-islands.md +++ b/hints/count-number-of-islands.md @@ -20,4 +20,4 @@

We can use the Depth First Search (DFS) algorithm to traverse each group independently. We iterate through each cell of the grid. When we encounter a 1, we perform a DFS starting at that cell and recursively visit every other 1 that is reachable. During this process, we mark the visited 1's as 0 to ensure we don't revisit them, as they belong to the same group. The number of groups corresponds to the number of islands.

- \ No newline at end of file + diff --git a/hints/count-paths.md b/hints/count-paths.md new file mode 100644 index 000000000..5f8bd1d96 --- /dev/null +++ b/hints/count-paths.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(m * n) time and O(m * n) space, where m is the number of rows and n is the number of columns in the grid. +

+
+ +
+
+ Hint 1 +

+ Try to think in terms of recursion and visualize it as a decision tree, where we have two choices at each step. Can you determine the base condition and recurrence relation? +

+
+ +
+
+ Hint 2 +

+ We recursively traverse the grid using row i and column j. At each step, we explore both possibilities: moving down or moving right, ensuring we do not go out of bounds. If we reach the bottom-right cell, we return 1. +

+
+ +
+
+ Hint 3 +

+ This approach has exponential complexity. Can you think of a way to optimize the recursion? Maybe you should consider using a dynamic programming approach. +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results of recursive calls and avoid recalculations. A hash map or a 2D array can be used to store these results. +

+
diff --git a/hints/count-squares.md b/hints/count-squares.md new file mode 100644 index 000000000..9e632b81f --- /dev/null +++ b/hints/count-squares.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(1) time for each add() call, O(n) time for each count() call, and O(n) space, where n is the total number of points. +

+
+ +
+
+ Hint 1 +

+ Initially, we can store the points in a global list for the add() call. For the count() call, a brute force approach would use three nested loops to check other points except for the query point, resulting in an O(n^3) time solution. Can you think of a better way? Maybe you should consider the observation that can be drawn from the diagonal of a square. +

+
+ +
+
+ Hint 2 +

+ In a square's diagonal, the absolute difference between the x-coordinates is equal to the absolute difference between the y-coordinates of the two endpoints, and neither difference can be zero. Using these two points, we can determine the other diagonal endpoints. +

+
+ +
+
+ Hint 3 +

+ We store points in a hash map instead of a list for O(1) lookups, treating duplicate points as one while tracking their frequencies. For the count() function, we iterate through points that, along with the query point, can form a diagonal. Let the query point be (qx, qy) and the other point be (x, y), ensuring they form a diagonal. What could be the other two points? Maybe you should consider the points forming a right-to-left diagonal, treating (qx, qy) as the top-right corner. +

+
+ +
+
+ Hint 4 +

+ The other two points are point1 (x, qy) and point2 (qx, y). For counting, we simply add count of point1 * count of point2 to the result res. +

+
diff --git a/hints/count-subsequences.md b/hints/count-subsequences.md new file mode 100644 index 000000000..39e022cdd --- /dev/null +++ b/hints/count-subsequences.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(m * n) time and O(m * n) space, where m is the length of the string s and n is the length of the string t. +

+
+ +
+
+ Hint 1 +

+ Try to think in terms of recursion and visualize it as a decision tree, as we need to explore all subsequences of s. Can you determine the possible decisions at each recursion step? +

+
+ +
+
+ Hint 2 +

+ We recursively iterate through the strings using indices i and j for s and t, respectively. At each recursion step, we can either skip the current character of s or include it in the current path if it matches the current character of t. Can you determine the base conditions for this recursive function? +

+
+ +
+
+ Hint 3 +

+ If index j goes out of bounds, we return 1 as a valid subsequence is found. If index i goes out of bounds first, we return 0. At each recursion step, we return the sum of both paths. This approach is exponential. Can you think of a way to optimize it? +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results of recursive calls and avoid redundant computations. A hash map or a 2D array can be used to store these results. +

+
diff --git a/hints/counting-bits.md b/hints/counting-bits.md new file mode 100644 index 000000000..90f0fb120 --- /dev/null +++ b/hints/counting-bits.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(n) space, where n is the given integer. +

+
+ +
+
+ Hint 1 +

+ A straightforward approach would be to iterate from 0 to n using i, and for each i, iterate through its bits to count the number of set bits. This would result in an O(n \log n) approach. Can you think of a better way? Maybe you should try identifying a pattern by observing the bitwise representation of consecutive numbers. +

+
+ +
+
+ Hint 2 +

+ For example, to compute set bits for 7, add 1 to the count of set bits in 3, which was previously computed by adding 1 to the count of set bits in 1. Observing the pattern, for numbers less than 4, add 1 to the count from two positions before. For numbers less than 8, add 1 to the count from four positions before. Can you derive a dynamic programming relation from this? +

+
+ +
+
+ Hint 3 +

+ We find an offset for the current number based on the number before offset positions. The dynamic programming relation is dp[i] = 1 + dp[i - offset], where dp[i] represents the number of set bits in i. The offset starts at 1 and updates when encountering a power of 2. To simplify the power of 2 check, if offset * 2 equals the current number, we update offset to the current number. +

+
diff --git a/hints/course-schedule-ii.md b/hints/course-schedule-ii.md index e187980f9..e551ae0b8 100644 --- a/hints/course-schedule-ii.md +++ b/hints/course-schedule-ii.md @@ -28,4 +28,4 @@

We compute the indegrees of all the nodes. Then, we perform a BFS starting from the nodes that have no parents (indegree[node] == 0). At each level, we traverse these nodes, decrement the indegree of their child nodes, and append those child nodes to the queue if their indegree becomes 0. We only append nodes whose indegree is 0 or becomes 0 during the BFS to our result array. If the length of the result array is not equal to the number of courses, we return an empty array.

- \ No newline at end of file + diff --git a/hints/course-schedule.md b/hints/course-schedule.md index 1392ac134..ac08d3837 100644 --- a/hints/course-schedule.md +++ b/hints/course-schedule.md @@ -28,4 +28,4 @@

We run a DFS starting from each course by initializing a hash set, path, to track the nodes in the current DFS call. At each step of the DFS, we return false if the current node is already in the path, indicating a cycle. We recursively traverse the neighbors of the current node, and if any of the neighbor DFS calls detect a cycle, we immediately return false. Additionally, we clear the neighbors list of a node when no cycle is found from that node to avoid revisiting those paths again.

- \ No newline at end of file + diff --git a/hints/daily-temperatures.md b/hints/daily-temperatures.md index 64c1a171e..bd589fb24 100644 --- a/hints/daily-temperatures.md +++ b/hints/daily-temperatures.md @@ -36,4 +36,4 @@

In the array [2, 1, 1, 3], we don't perform any pop operations while processing [2, 1, 1] because these elements are already in decreasing order. However, when we reach 3, we pop elements from the stack until the top element of the stack is no longer less than the current element. For each popped element, we compute the difference between the indices and store it in the position corresponding to the popped element.

- \ No newline at end of file + diff --git a/hints/decode-ways.md b/hints/decode-ways.md index 56c40d46a..411886000 100644 --- a/hints/decode-ways.md +++ b/hints/decode-ways.md @@ -36,4 +36,4 @@

The base condition is to return 1 if i goes out of bounds. If the current digit is '0', return 0, as no character maps to '0', making the string invalid. Use memoization to avoid repeated work by caching recursion results in an array or hash map and returning the stored value when the result is already calculated.

- \ No newline at end of file + diff --git a/hints/depth-of-binary-tree.md b/hints/depth-of-binary-tree.md index 51538e4c8..8aafe8820 100644 --- a/hints/depth-of-binary-tree.md +++ b/hints/depth-of-binary-tree.md @@ -28,4 +28,4 @@

The +1 accounts for the current node, as it contributes to the current depth in the recursion call. We pass the maximum depth from the current node's left and right subtrees to its parent because the current maximum depth determines the longest path from the parent to a leaf node through this subtree.

- \ No newline at end of file + diff --git a/hints/design-twitter-feed.md b/hints/design-twitter-feed.md index 4dcbd38e4..e108c6ffb 100644 --- a/hints/design-twitter-feed.md +++ b/hints/design-twitter-feed.md @@ -2,7 +2,7 @@
Recommended Time & Space Complexity

- You should aim for a solution with O(n) time for each getNewsFeed() function call, O(1) time for the remaining methods, and O((N * m) + (N * M) + n) space, where n is the number of followeeIds associated with the userId, m is the maximum number of tweets by any user, N is the total number of userIds, and M is the maximum number of followees for any user. + You should aim for a solution with O(nlogn) time for each getNewsFeed() function call, O(1) time for the remaining methods, and O((N * m) + (N * M) + n) space, where n is the number of followeeIds associated with the userId, m is the maximum number of tweets by any user, N is the total number of userIds, and M is the maximum number of followees for any user.

@@ -36,4 +36,4 @@

We can use a Max-Heap to efficiently retrieve the top 10 most recent tweets. For each followee and the userId, we insert their most recent tweet from the tweetMap into the heap, along with the tweet's count and its index in the tweet list. This index is necessary because after processing a tweet, we can insert the next most recent tweet from the same user's list. By always pushing and popping tweets from the heap, we ensure that the 10 most recent tweets are retrieved without sorting all tweets.

- \ No newline at end of file + diff --git a/hints/design-word-search-data-structure.md b/hints/design-word-search-data-structure.md index db99718c2..d647440ce 100644 --- a/hints/design-word-search-data-structure.md +++ b/hints/design-word-search-data-structure.md @@ -28,4 +28,4 @@

We traverse the word with index i, starting at the root of the Trie. For normal characters, we search as usual. When encountering a dot ('.'), we try all possible characters by recursively extending the search in each direction. If any path leads to a valid word, we return true; otherwise, we return false. Although we try all paths for a dot, the time complexity is still O(n) because there are at most two dots ('.') in the word, making the complexity O((26^2) * n).

- \ No newline at end of file + diff --git a/hints/eating-bananas.md b/hints/eating-bananas.md index 41bb76a40..69410d87f 100644 --- a/hints/eating-bananas.md +++ b/hints/eating-bananas.md @@ -44,4 +44,4 @@

Rather than linearly scanning, we can use binary search. The upper bound of k is max(piles) and since we are only dealing with positive values, the lower bound is 1. The search space of our binary search is 1 through max(piles). This allows us to find the smallest possible k using binary search.

- \ No newline at end of file + diff --git a/hints/edit-distance.md b/hints/edit-distance.md new file mode 100644 index 000000000..7f7a88d8a --- /dev/null +++ b/hints/edit-distance.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(m * n) time and O(m * n) space, where m and n are the lengths of the strings word1 and word2, respectively. +

+
+ +
+
+ Hint 1 +

+ Try to think in terms of recursion and visualize it as a decision tree, as we have choices at each recursion step. Can you determine the recurrence relation and base cases? +

+
+ +
+
+ Hint 2 +

+ We recursively iterate through the strings using indices i and j for word1 and word2, respectively. If the characters at the current indices match, we increment both indices without counting an operation. Otherwise, we have three choices: insert the character at the current index of word1 (increment j), delete the current character of word1 (increment i), or replace the character at index i in word1 (increment both i and j). +

+
+ +
+
+ Hint 3 +

+ If index i goes out of bounds, we return the number of remaining characters in word2 (using insert operations). If index j goes out of bounds, we return the number of remaining characters in word1 (using delete operations). At each step, we return the minimum operation path. This approach is exponential. Can you think of a way to optimize it? +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results and avoid redundant calculations. A hash map or a 2D array can be used to store these results. +

+
diff --git a/hints/evaluate-reverse-polish-notation.md b/hints/evaluate-reverse-polish-notation.md index 8e63e0dfd..c58d671b3 100644 --- a/hints/evaluate-reverse-polish-notation.md +++ b/hints/evaluate-reverse-polish-notation.md @@ -28,4 +28,4 @@

As the array has postfix expression, stack helps us to maintain the correct order of operations by ensuring that we always use the most recent operands (those closest to the operator) when performing the operation. After the iteration, the final result is left in the stack.

- \ No newline at end of file + diff --git a/hints/find-duplicate-integer.md b/hints/find-duplicate-integer.md index e399acf89..284a71781 100644 --- a/hints/find-duplicate-integer.md +++ b/hints/find-duplicate-integer.md @@ -36,4 +36,4 @@

For example, in the array [2, 1, 2, 3], where 2 is repeated, we mark the index corresponding to each element as negative. If we encounter a number whose corresponding position is already negative, it means the number is a duplicate, and we return it.

- \ No newline at end of file + diff --git a/hints/find-median-in-a-data-stream.md b/hints/find-median-in-a-data-stream.md index ea07e7519..fd0b89e02 100644 --- a/hints/find-median-in-a-data-stream.md +++ b/hints/find-median-in-a-data-stream.md @@ -36,4 +36,4 @@

We initialize a Max-Heap and a Min-Heap. When adding an element, if the element is greater than the minimum element of the Min-Heap, we push it into the Min-Heap; otherwise, we push it into the Max-Heap. If the size difference between the two heaps becomes greater than one, we rebalance them by popping an element from the larger heap and pushing it into the smaller heap. This process ensures that the elements are evenly distributed between the two heaps, allowing us to retrieve the middle element or elements in O(1) time.

- \ No newline at end of file + diff --git a/hints/find-minimum-in-rotated-sorted-array.md b/hints/find-minimum-in-rotated-sorted-array.md index 568e4ef1f..b0f9559ae 100644 --- a/hints/find-minimum-in-rotated-sorted-array.md +++ b/hints/find-minimum-in-rotated-sorted-array.md @@ -35,6 +35,6 @@ Hint 4

There will be two conditions where l and mid will be in left sorted segment or mid and r will be in right sorted segement. - If l and mid in sorted segement, then nums[l] < nums[mid] and the minimum element will be in the right part. If mid and r in sorted segment, then nums[m] < nums[r] and the minimum element will be in the left part. After the binary search we end up finding the minimum element. + If l and mid in sorted segement, then nums[l] < nums[mid] and the minimum element will be in the right part. If mid and r in sorted segment, then nums[mid] < nums[r] and the minimum element will be in the left part. After the binary search we end up finding the minimum element.

- \ No newline at end of file + diff --git a/hints/find-target-in-rotated-sorted-array.md b/hints/find-target-in-rotated-sorted-array.md index 7133b3821..504264627 100644 --- a/hints/find-target-in-rotated-sorted-array.md +++ b/hints/find-target-in-rotated-sorted-array.md @@ -37,4 +37,4 @@ There are two cases: l and mid belong to the left sorted segment, or mid and r belong to the right sorted segment. If l and mid are in the same segment, nums[l] < nums[mid], so the pivot index must lie in the right part. If mid and r are in the same segment, nums[mid] < nums[r], so the pivot index must lie in the left part. After the binary search, we eventually find the pivot index. Once the pivot is found, it's straightforward to select the segment where the target lies and perform a binary search on that segement to find its position. If we don't find the target, we return -1.

- \ No newline at end of file + diff --git a/hints/foreign-dictionary.md b/hints/foreign-dictionary.md index 9837818a0..e7c30969c 100644 --- a/hints/foreign-dictionary.md +++ b/hints/foreign-dictionary.md @@ -36,4 +36,4 @@

When we visit a node and its children and don't find a cycle, we mark the node as False in the map and append it to the result, treating this as a post-order traversal. If we find a cycle, we return an empty string; otherwise, we return the result list.

- \ No newline at end of file + diff --git a/hints/gas-station.md b/hints/gas-station.md new file mode 100644 index 000000000..7c961b748 --- /dev/null +++ b/hints/gas-station.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would be to start at each gas station, simulate the process, and return the index where completing the circuit is possible. This would be an O(n^2) time solution. Can you think of a better way? Maybe a greedy approach works. +

+
+ +
+
+ Hint 2 +

+ We can immediately return -1 if sum(gas) < sum(cost), as completing the circuit is impossible due to insufficient gas. Otherwise, a solution always exists because the total gas is sufficient to cover the total cost, meaning there must be a valid starting point that allows completing the circuit. +

+
+ +
+
+ Hint 3 +

+ We start with a variable total to track the gas balance and initialize the result index to 0. As we iterate through the array with index i, we accumulate the difference (gas[i] - cost[i]). If total becomes negative at any index, we reset it to 0 and update the result index to (i + 1). +

+
diff --git a/hints/generate-parentheses.md b/hints/generate-parentheses.md index 454a10e81..61ab3d1bf 100644 --- a/hints/generate-parentheses.md +++ b/hints/generate-parentheses.md @@ -28,4 +28,4 @@

When the count of closing brackets exceeds the count of opening brackets, the string becomes invalid. Therefore, we can maintain two variables, open and close, to track the number of opening and closing brackets. We avoid exploring paths where close > open. Once the string length reaches 2n, we add it to the result.

- \ No newline at end of file + diff --git a/hints/hand-of-straights.md b/hints/hand-of-straights.md new file mode 100644 index 000000000..25ebfe9c8 --- /dev/null +++ b/hints/hand-of-straights.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(nlogn) time and O(n) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ It is observed that to form a group, the minimum value should be the starting value of the group. Additionally, the minimum value in the array serves as the starting value for one or more groups based on its frequency. Can you think of an efficient way to determine the frequencies of array elements? Maybe a specific data structure can be useful here. +

+
+ +
+
+ Hint 2 +

+ We can use a hash map to store the elements along with their frequencies. Additionally, we sort the given array. Then, we iterate through the sorted array and try to form groups by decrementing the frequency count. If we fail to form a group at any step, we immediately return false. Can you think why this works? +

+
+ +
+
+ Hint 3 +

+ Sorting ensures we start with the smallest available value, while the hash map helps track element availability using frequency counts. At each step, we pick the smallest available value x and attempt to form a group from x to x + groupSize - 1. If all elements are present based on their frequency counts, we decrement their counts as we iterate. If we successfully form all groups, we return true; otherwise, we return false. +

+
diff --git a/hints/house-robber-ii.md b/hints/house-robber-ii.md index 1cc52b34d..4d17802c8 100644 --- a/hints/house-robber-ii.md +++ b/hints/house-robber-ii.md @@ -36,4 +36,4 @@

We can create two arrays from the given array. The first will include houses from the first house to the second-to-last house, and the second will include houses from the second house to the last house. We can run the recursive function on both arrays independently and return the maximum result between the two. Advanced techniques such as bottom-up dynamic programming can further optimize the solution.

- \ No newline at end of file + diff --git a/hints/house-robber.md b/hints/house-robber.md index 2a1e5d7c8..13b851233 100644 --- a/hints/house-robber.md +++ b/hints/house-robber.md @@ -36,4 +36,4 @@

We can use Memoization to avoid recalculating the result multiple times for a recursive call. By storing the result of each recursive call in a hash map or an array using i as the parameter, we can immediately return the stored result if the recursion is called with the same i value again. Further optimization can be achieved using advanced techniques like Bottom-Up dynamic programming.

- \ No newline at end of file + diff --git a/hints/implement-prefix-tree.md b/hints/implement-prefix-tree.md index f2908be7f..f118b254f 100644 --- a/hints/implement-prefix-tree.md +++ b/hints/implement-prefix-tree.md @@ -28,4 +28,4 @@

Searching for a word is similar to inserting, but instead of creating new nodes, we return false if we don't find a character in the path while iterating or if the end-of-word marker is not set to true when we reach the end of the word.

- \ No newline at end of file + diff --git a/hints/insert-new-interval.md b/hints/insert-new-interval.md new file mode 100644 index 000000000..b287929f7 --- /dev/null +++ b/hints/insert-new-interval.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) extra space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ The given intervals are non-overlapping and sorted in ascending order based on the start value. Try to visualize them as line segments and consider how a new interval can be inserted. Maybe you should analyze different cases of inserting a new interval. +

+
+ +
+
+ Hint 2 +

+ First, we append all intervals to the output list that have an end value smaller than the start value of the new interval. Then, we encounter one of three cases: we have appended all intervals, we reach an interval whose start value is greater than the new interval’s end, or we find an overlapping interval. Can you think of a way to handle these cases efficiently? +

+
+ +
+
+ Hint 3 +

+ We iterate through the remaining intervals, updating the new interval if its end value is greater than or equal to the current interval's start value. We adjust the start and end of the new interval to the minimum and maximum values, respectively. After this, any remaining intervals are appended to the output list, and we return the result. +

+
diff --git a/hints/interleaving-string.md b/hints/interleaving-string.md new file mode 100644 index 000000000..b4811f4e2 --- /dev/null +++ b/hints/interleaving-string.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(m * n) time and O(m * n) space, where m is the length of the string s1 and n is the length of the string s2. +

+
+ +
+
+ Hint 1 +

+ If the sum of the characters in s1 and s2 does not equal s3, we return false. Think in terms of recursion and visualize it as a decision tree, where we explore different combinations of portions from both strings. Can you determine the possible decisions at each recursion step? +

+
+ +
+
+ Hint 2 +

+ We recursively iterate through the strings using indices i, j, and k for s1, s2, and s3, respectively. At each step, we extend the current path in two directions based on whether the k-th character of s3 matches the current character of s1 or s2. If any path returns true, we immediately return true. If k goes out of bounds, it means we have successfully formed the interleaved string, so we return true. +

+
+ +
+
+ Hint 3 +

+ This approach is exponential. Can you think of a way to optimize it? Since k depends on i and j, it can be treated as a constant, as we can derive k using i + j. +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results of recursive calls and avoid redundant computations. Treating i and j as states, we can use a hash map or a 2D array to store the results. +

+
diff --git a/hints/invert-a-binary-tree.md b/hints/invert-a-binary-tree.md index eacb6582d..596ab0506 100644 --- a/hints/invert-a-binary-tree.md +++ b/hints/invert-a-binary-tree.md @@ -20,4 +20,4 @@

We can use the Depth First Search (DFS) algorithm. At each node, we swap its left and right children by swapping their pointers. This inverts the current node, but every node in the tree also needs to be inverted. To achieve this, we recursively visit the left and right children and perform the same operation. If the current node is null, we simply return.

- \ No newline at end of file + diff --git a/hints/is-anagram.md b/hints/is-anagram.md index 8454011d2..e775554df 100644 --- a/hints/is-anagram.md +++ b/hints/is-anagram.md @@ -28,4 +28,4 @@

We can just consider maintaining the frequency of each character. We can do this by having two separate hash tables for the two strings. Then, we can check whether the frequency of each character in string s is equal to that in string t and vice versa.

- \ No newline at end of file + diff --git a/hints/is-palindrome.md b/hints/is-palindrome.md index 697108060..e7eaef8e9 100644 --- a/hints/is-palindrome.md +++ b/hints/is-palindrome.md @@ -28,4 +28,4 @@

A palindrome string is a string that is read the same from the start as well as from the end. This means the character at the start should match the character at the end at the same index. We can use the two pointer algorithm to do this efficiently.

- \ No newline at end of file + diff --git a/hints/islands-and-treasure.md b/hints/islands-and-treasure.md index b7ef502de..2234fc59f 100644 --- a/hints/islands-and-treasure.md +++ b/hints/islands-and-treasure.md @@ -28,4 +28,4 @@

We insert all the cells (row, col) that represent the treasure chests into the queue. Then, we process the cells level by level, handling all the current cells in the queue at once. For each cell, we mark it as visited and store the current level value as the distance at that cell. We then try to add the neighboring cells (adjacent cells) to the queue, but only if they have not been visited and are land cells.

- \ No newline at end of file + diff --git a/hints/jump-game-ii.md b/hints/jump-game-ii.md new file mode 100644 index 000000000..54d12dd0b --- /dev/null +++ b/hints/jump-game-ii.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would be to recursively explore all paths from index 0 to its reachable indices, then process those indices similarly and return the minimum steps to reach the last index. This would be an exponential approach. Can you think of a better way? Maybe a greedy approach works. +

+
+ +
+
+ Hint 2 +

+ We maintain two pointers, l and r, initially set to 0, representing the range of reachable indices. At each step, we iterate through the indices in the range l to r and determine the farthest index that can be reached from the current range. +

+
+ +
+
+ Hint 3 +

+ We then update the pointers l and r to the next range, setting l to r + 1 and r to the farthest index reachable from the current range. We continue this process until the pointers go out of bounds. +

+
+ +
+
+ Hint 4 +

+ The number of steps taken represents the minimum steps required to reach the last index, as it is guaranteed that we can reach it. +

+
diff --git a/hints/jump-game.md b/hints/jump-game.md new file mode 100644 index 000000000..990af601a --- /dev/null +++ b/hints/jump-game.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of input array. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would be to recursively explore all paths from index 0 to its reachable indices, then process those indices similarly, returning true if we reach the last index. This would be an exponential approach. Can you think of a better way? Maybe a greedy approach works. +

+
+ +
+
+ Hint 2 +

+ Instead of processing the array from index 0, start from the last index. Let the target index be goal = n - 1. Iterate in reverse from index n - 2. +

+
+ +
+
+ Hint 3 +

+ At each iteration, we check whether the current index can reach goal. If it can, we update goal to the current index, as reaching the current index means we can also reach the goal. +

+
+ +
+
+ Hint 4 +

+ To determine if we can reach the last index, the goal should be 0 after the iteration. Otherwise, reaching the last index is not possible. +

+
diff --git a/hints/k-closest-points-to-origin.md b/hints/k-closest-points-to-origin.md index 277e19160..d0676f0de 100644 --- a/hints/k-closest-points-to-origin.md +++ b/hints/k-closest-points-to-origin.md @@ -28,4 +28,4 @@

We initialize a Max-Heap that orders points based on their distances from the origin. Starting with an empty heap, we iterate through the array of points, inserting each point into the heap. If the size of the heap exceeds k, we remove the farthest point (the maximum element in the heap). After completing the iteration, the heap will contain the k closest points to the origin. Finally, we convert the heap into an array and return it.

- \ No newline at end of file + diff --git a/hints/kth-largest-element-in-an-array.md b/hints/kth-largest-element-in-an-array.md index 8d68feba3..1a3a12263 100644 --- a/hints/kth-largest-element-in-an-array.md +++ b/hints/kth-largest-element-in-an-array.md @@ -36,4 +36,4 @@

We initialize an empty Min-Heap. We iterate through the array and add elements to the heap. When the size of the heap exceeds k, we pop from the heap and continue. After the iteration, the top element of the heap is the k-th largest element.

- \ No newline at end of file + diff --git a/hints/kth-largest-integer-in-a-stream.md b/hints/kth-largest-integer-in-a-stream.md index 2d7d952e8..232b94f16 100644 --- a/hints/kth-largest-integer-in-a-stream.md +++ b/hints/kth-largest-integer-in-a-stream.md @@ -36,4 +36,4 @@

We initialize a Min-Heap with the elements of the input array. When the add() function is called, we insert the new element into the heap. If the heap size exceeds k, we remove the smallest element (the root of the heap). Finally, the top element of the heap represents the k-th largest element and is returned.

- \ No newline at end of file + diff --git a/hints/kth-smallest-integer-in-bst.md b/hints/kth-smallest-integer-in-bst.md index 2af2e63de..8943884a3 100644 --- a/hints/kth-smallest-integer-in-bst.md +++ b/hints/kth-smallest-integer-in-bst.md @@ -28,4 +28,4 @@

We keep a counter variable cnt to track the position of the current node in the ascending order of values. When cnt == k, we store the current node's value in a global variable and return. This allows us to identify and return the k-th smallest element during the in-order traversal.

- \ No newline at end of file + diff --git a/hints/largest-rectangle-in-histogram.md b/hints/largest-rectangle-in-histogram.md index 35976b385..c4841aa48 100644 --- a/hints/largest-rectangle-in-histogram.md +++ b/hints/largest-rectangle-in-histogram.md @@ -36,4 +36,4 @@

We can use a stack with a monotonically strictly increasing nature, but instead of storing values, we store indices in the stack and perform operations based on the values at those indices. The top of the stack will represent the smaller bar that we encounter while extending the current bar. To find the left and right boundaries, we perform this algorithm from left to right and vice versa, storing the boundaries. Then, we iterate through the array to find the area for each bar and return the maximum area we get.

- \ No newline at end of file + diff --git a/hints/last-stone-weight.md b/hints/last-stone-weight.md index 5404da55d..9422e4480 100644 --- a/hints/last-stone-weight.md +++ b/hints/last-stone-weight.md @@ -20,4 +20,4 @@

We can use a Max-Heap, which allows us to retrieve the maximum element in O(1) time. We initially insert all the weights into the Max-Heap, which takes O(logn) time per insertion. We then simulate the process until only one or no element remains in the Max-Heap. At each step, we pop two elements from the Max-Heap which takes O(logn) time. If they are equal, we do not insert anything back into the heap and continue. Otherwise, we insert the difference of the two elements back into the heap.

- \ No newline at end of file + diff --git a/hints/level-order-traversal-of-binary-tree.md b/hints/level-order-traversal-of-binary-tree.md index e59c454b5..3f65a426c 100644 --- a/hints/level-order-traversal-of-binary-tree.md +++ b/hints/level-order-traversal-of-binary-tree.md @@ -28,4 +28,4 @@

The number of times we iterate the queue corresponds to the number of levels in the tree. At each step, we pop all nodes from the queue for the current level and add them collectively to the resultant array. This ensures that we capture all nodes at each level of the tree.

- \ No newline at end of file + diff --git a/hints/linked-list-cycle-detection.md b/hints/linked-list-cycle-detection.md index 04c8f4623..79ee9808b 100644 --- a/hints/linked-list-cycle-detection.md +++ b/hints/linked-list-cycle-detection.md @@ -28,4 +28,4 @@

When there is no cycle in the list, the loop ends when the fast pointer becomes null. If a cycle exists, the fast pointer moves faster and continuously loops through the cycle. With each step, it reduces the gap between itself and the slow pointer by one node. For example, if the gap is 10, the slow pointer moves by 1, increasing the gap to 11, while the fast pointer moves by 2, reducing the gap to 9. This process continues until the fast pointer catches up to the slow pointer, confirming a cycle.

- \ No newline at end of file + diff --git a/hints/longest-common-subsequence.md b/hints/longest-common-subsequence.md new file mode 100644 index 000000000..a874fdde1 --- /dev/null +++ b/hints/longest-common-subsequence.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(m * n) time and O(m * n) space, where m is the length of the string text1 and n is the length of the string text2. +

+
+ +
+
+ Hint 1 +

+ Try to think in terms of recursion and visualize it as a decision tree. Can you determine the possible decisions at each step? Maybe you should consider iterating through both strings recursively at the same time. +

+
+ +
+
+ Hint 2 +

+ At each recursion step, we have two choices: if the characters at the current indices of both strings match, we move both indices forward and extend the subsequence. Otherwise, we explore two paths by advancing one index at a time and recursively finding the longest subsequence. We return the maximum length between these two choices. This approach is exponential. Can you think of a way to optimize it? +

+
+ +
+
+ Hint 3 +

+ We return 0 if either index goes out of bounds. To optimize, we can use memoization to cache recursive call results and avoid redundant calculations. A hash map or a 2D array can be used to store these results. +

+
diff --git a/hints/longest-consecutive-sequence.md b/hints/longest-consecutive-sequence.md index 7065b8463..151b9f32b 100644 --- a/hints/longest-consecutive-sequence.md +++ b/hints/longest-consecutive-sequence.md @@ -28,4 +28,4 @@

We can consider a number num as the start of a sequence if and only if num - 1 does not exist in the given array. We iterate through the array and only start building the sequence if it is the start of a sequence. This avoids repeated work. We can use a hash set for O(1) lookups by converting the array to a hash set.

- \ No newline at end of file + diff --git a/hints/longest-increasing-path-in-matrix.md b/hints/longest-increasing-path-in-matrix.md new file mode 100644 index 000000000..e202e0205 --- /dev/null +++ b/hints/longest-increasing-path-in-matrix.md @@ -0,0 +1,23 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(m * n) time and O(m * n) space, where m is the number of rows and n is the number of columns in the given matrix. +

+
+ +
+
+ Hint 1 +

+ If we move from one cell to an adjacent cell with a greater value, we won't revisit a cell, as the path is strictly increasing. A brute force approach would be to run a dfs from every cell and return the longest path found. This approach is exponential. Can you think of a way to optimize it to avoid redundant calculations? +

+
+ +
+
+ Hint 2 +

+ We can use memoization to cache the results of recursive calls and avoid redundant computations. A hash map or a 2D array can be used to store these results. +

+
diff --git a/hints/longest-increasing-subsequence.md b/hints/longest-increasing-subsequence.md new file mode 100644 index 000000000..f63de4455 --- /dev/null +++ b/hints/longest-increasing-subsequence.md @@ -0,0 +1,47 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(n ^ 2) time and O(n ^ 2) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ A subsequence is formed by selecting elements while maintaining their order. Using recursion, we can generate all subsequences. The recursive function returns the length of the longest increasing subsequence up to index i, processing from left to right. At each step, we decide whether to include or exclude the current element. +

+
+ +
+
+ Hint 2 +

+ Since the sequence must be increasing, we represent choices by adding 1 when including an element and 0 when excluding it. In recursion, how can we ensure the current element is greater than the previous one? Perhaps additional information is needed to process it. +

+
+ +
+
+ Hint 3 +

+ We can store the index of the previously chosen element as j, making it easier to process the current element at index i. If and only if j == -1 or nums[i] > nums[j], we include the current element and extend the recursive path. Can you determine the recurrence relation? At most, two recursive calls are made at each recursion step. +

+
+ +
+
+ Hint 4 +

+ We stop the recursion when index i goes out of bounds and return 0 since no more elements can be added. The initial recursion call starts with j = -1. At each step, we include the current element if it is greater than the previous one and continue the recursion, or we exclude it and explore the next possibility. We return the maximum value obtained from both paths. +

+
+ +
+
+ Hint 5 +

+ The time complexity of this approach is exponential. We can use memoization to store results of recursive calls and avoid recalculations. A hash map or a 2D array can be used to cache these results. +

+
diff --git a/hints/longest-palindromic-substring.md b/hints/longest-palindromic-substring.md index 9d4dc9eb9..d9637bb74 100644 --- a/hints/longest-palindromic-substring.md +++ b/hints/longest-palindromic-substring.md @@ -36,4 +36,4 @@

For an even-length palindrome, consider expanding from indices i and i + 1. This two-pointer approach, extending from the center of the palindrome, will help find all palindromic substrings in the given string. Update the two result variables and return the substring starting at res with a length of resLen.

- \ No newline at end of file + diff --git a/hints/longest-repeating-substring-with-replacement.md b/hints/longest-repeating-substring-with-replacement.md index 808ff742f..7cd03766b 100644 --- a/hints/longest-repeating-substring-with-replacement.md +++ b/hints/longest-repeating-substring-with-replacement.md @@ -36,4 +36,4 @@

We can use the sliding window approach. The window size will be dynamic, and we will shrink the window when the number of replacements exceeds k. The result will be the maximum window size observed at each iteration.

- \ No newline at end of file + diff --git a/hints/longest-substring-without-duplicates.md b/hints/longest-substring-without-duplicates.md index 42c7ca28a..3ae36748f 100644 --- a/hints/longest-substring-without-duplicates.md +++ b/hints/longest-substring-without-duplicates.md @@ -28,4 +28,4 @@

We can iterate through the given string with index r as the right boundary and l as the left boundary of the window. We use a hash set to check if the character is present in the window or not. When we encounter a character at index r that is already present in the window, we shrink the window by incrementing the l pointer until the window no longer contains any duplicates. Also, we remove characters from the hash set that are excluded from the window as the l pointer moves. At each iteration, we update the result with the length of the current window, r - l + 1, if this length is greater than the current result.

- \ No newline at end of file + diff --git a/hints/lowest-common-ancestor-in-binary-search-tree.md b/hints/lowest-common-ancestor-in-binary-search-tree.md index b7357e2b3..780244839 100644 --- a/hints/lowest-common-ancestor-in-binary-search-tree.md +++ b/hints/lowest-common-ancestor-in-binary-search-tree.md @@ -36,4 +36,4 @@

The LCA can also be one of the nodes, p or q, if the current node is equal to either of them. This is because if we encounter either p or q during the traversal, that node is the LCA.

- \ No newline at end of file + diff --git a/hints/lru-cache.md b/hints/lru-cache.md index 7db2c01ef..34a265e39 100644 --- a/hints/lru-cache.md +++ b/hints/lru-cache.md @@ -44,4 +44,4 @@

We can use a doubly linked list where key-value pairs are stored as nodes, with the least recently used (LRU) node at the head and the most recently used (MRU) node at the tail. Whenever a key is accessed using get() or put(), we remove the corresponding node and reinsert it at the tail. When the cache reaches its capacity, we remove the LRU node from the head of the list. Additionally, we use a hash map to store each key and the corresponding address of its node, enabling efficient operations in O(1) time.

- \ No newline at end of file + diff --git a/hints/max-area-of-island.md b/hints/max-area-of-island.md index a8502e52a..ebcfe2c4d 100644 --- a/hints/max-area-of-island.md +++ b/hints/max-area-of-island.md @@ -28,4 +28,4 @@

We traverse the grid, and when we encounter a 1, we initialize a variable area. We then start a DFS from that cell to visit all connected 1's recursively, marking them as 0 to indicate they are visited. At each recursion step, we increment area. After completing the DFS, we update maxArea, which tracks the maximum area of an island in the grid, if maxArea < area. Finally, after traversing the grid, we return maxArea.

- \ No newline at end of file + diff --git a/hints/max-water-container.md b/hints/max-water-container.md index 02fb8859b..e70a10c7a 100644 --- a/hints/max-water-container.md +++ b/hints/max-water-container.md @@ -36,4 +36,4 @@

In the formula, the amount of water depends only on the minimum height. Therefore, it is appropriate to replace the smaller height value.

- \ No newline at end of file + diff --git a/hints/maximum-product-subarray.md b/hints/maximum-product-subarray.md new file mode 100644 index 000000000..67d0db63c --- /dev/null +++ b/hints/maximum-product-subarray.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ A brute force solution would be to find the product for every subarray and then return the maximum among all the products. This would be an O(n ^ 2) approach. Can you think of a better way? Maybe you should think of a dynamic programming approach. +

+
+ +
+
+ Hint 2 +

+ Try to identify a pattern by finding the maximum product for an array with two elements and determining what values are needed when increasing the array size to three. Perhaps you only need two values when introducing a new element. +

+
+ +
+
+ Hint 3 +

+ We maintain both the minimum and maximum product values and update them when introducing a new element by considering three cases: starting a new subarray, multiplying with the previous max product, or multiplying with the previous min product. The max product is updated to the maximum of these three, while the min product is updated to the minimum. We also track a global max product for the result. This approach is known as Kadane's algorithm. +

+
diff --git a/hints/maximum-subarray.md b/hints/maximum-subarray.md new file mode 100644 index 000000000..c536cb675 --- /dev/null +++ b/hints/maximum-subarray.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would be to compute the sum of every subarray and return the maximum among them. This would be an O(n^2) approach. Can you think of a better way? Maybe you should consider a dynamic programming-based approach. +

+
+ +
+
+ Hint 2 +

+ Instead of calculating the sum for every subarray, try maintaining a running sum. Maybe you should consider whether extending the previous sum or starting fresh with the current element gives a better result. Can you think of a way to track this efficiently? +

+
+ +
+
+ Hint 3 +

+ We use a variable curSum to track the sum of the elements. At each index, we have two choices: either add the current element to curSum or start a new subarray by resetting curSum to the current element. Maybe you should track the maximum sum at each step and update the global maximum accordingly. +

+
+ +
+
+ Hint 4 +

+ This algorithm is known as Kadane's algorithm. +

+
diff --git a/hints/median-of-two-sorted-arrays.md b/hints/median-of-two-sorted-arrays.md index bfbe9c032..72202ba47 100644 --- a/hints/median-of-two-sorted-arrays.md +++ b/hints/median-of-two-sorted-arrays.md @@ -44,4 +44,4 @@

For example, consider the arrays A = [1, 2, 3, 4, 5] and B = [1, 2, 3, 4, 5, 6, 7, 8]. When we select x = 2, we take 4 elements from array B. However, this partition is not valid because value 4 from the left partition of array B is greater than the value 3 from the right partition of array A. So, we should try to take more elements from array A to make the partition valid. Binary search will eventually help us find a valid partition.

- \ No newline at end of file + diff --git a/hints/meeting-schedule-ii.md b/hints/meeting-schedule-ii.md new file mode 100644 index 000000000..40b3cd26f --- /dev/null +++ b/hints/meeting-schedule-ii.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(nlogn) time and O(n) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ Try to visualize the meetings as line segments on a number line representing start and end times. The number of rooms required is the maximum number of overlapping meetings at any point on the number line. Can you think of a way to determine this efficiently? +

+
+ +
+
+ Hint 2 +

+ We create two arrays, start and end, containing the start and end times of all meetings, respectively. After sorting both arrays, we use a two-pointer based approach. How do you implement this? +

+
+ +
+
+ Hint 3 +

+ We use two pointers, s and e, for the start and end arrays, respectively. We also maintain a variable count to track the current number of active meetings. At each iteration, we increment s while the start time is less than the current end time and increase count, as these meetings must begin before the earliest ongoing meeting ends. +

+
+ +
+
+ Hint 4 +

+ Then, we increment e and decrement count as a meeting has ended. At each step, we update the result with the maximum value of active meetings stored in count. +

+
diff --git a/hints/meeting-schedule.md b/hints/meeting-schedule.md new file mode 100644 index 000000000..3f56c079b --- /dev/null +++ b/hints/meeting-schedule.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(nlogn) time and O(n) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ If two intervals are sorted in ascending order by their start values, they overlap if the start value of the second interval is less than the end value of the first interval. And these are called overlapping intervals. +

+
+ +
+
+ Hint 2 +

+ A brute force approach would be to check every pair of intervals and return false if any overlap is found. This would be an O(n^2) solution. Can you think of a better way? Maybe you should visualize the given intervals as line segments. +

+
+ +
+
+ Hint 3 +

+ We should sort the given intervals based on their start values, as this makes it easier to check for overlaps by comparing adjacent intervals. We then iterate through the intervals from left to right and return false if any adjacent intervals overlap. +

+
diff --git a/hints/merge-intervals.md b/hints/merge-intervals.md new file mode 100644 index 000000000..829f38ed8 --- /dev/null +++ b/hints/merge-intervals.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(nlogn) time and O(n) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ Sorting the given intervals in ascending order based on their start values is beneficial, as it helps in identifying overlapping intervals efficiently. How can you determine if two intervals overlap? +

+
+ +
+
+ Hint 2 +

+ If two intervals are sorted in ascending order by their start values, they overlap if the start value of the second interval is less than or equal to the end value of the first interval. +

+
+ +
+
+ Hint 3 +

+ We iterate through the sorted intervals from left to right, starting with the first interval in the output list. From the second interval onward, we compare each interval with the last appended interval. Can you determine the possible cases for this comparison? +

+
+ +
+
+ Hint 4 +

+ The two cases are: if the current interval overlaps with the last appended interval, we update its end value to the maximum of both intervals' end values and continue. Otherwise, we append the current interval and proceed. +

+
diff --git a/hints/merge-k-sorted-linked-lists.md b/hints/merge-k-sorted-linked-lists.md index aec8ab73a..e731fbeb0 100644 --- a/hints/merge-k-sorted-linked-lists.md +++ b/hints/merge-k-sorted-linked-lists.md @@ -28,4 +28,4 @@

We iterate through the list array with index i, starting at i = 1. We merge the linked lists using mergeTwoLists(lists[i], lists[i - 1]), which returns the head of the merged list. This head is stored in lists[i], and the process continues. Finally, the merged list is obtained at the last index, and we return its head.

- \ No newline at end of file + diff --git a/hints/merge-triplets-to-form-target.md b/hints/merge-triplets-to-form-target.md new file mode 100644 index 000000000..04490ad72 --- /dev/null +++ b/hints/merge-triplets-to-form-target.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ An important observation is that we can ignore triplets with values greater than the target triplet. +

+
+ +
+
+ Hint 2 +

+ Specifically, if a triplet t has any element greater than the corresponding value in target (i.e., t[0] > target[0], t[1] > target[1], or t[2] > target[2]), we can discard it. This is because using such a triplet in operations would exceed the target values, making it invalid. +

+
+ +
+
+ Hint 3 +

+ Now, from the remaining valid triplets, we only need to check whether the target triplet values exist. Since all values in the valid triplets are less than or equal to the corresponding values in the target triplet, finding the target triplet among them guarantees that we can achieve it. +

+
diff --git a/hints/merge-two-sorted-linked-lists.md b/hints/merge-two-sorted-linked-lists.md index 5fbfafd3c..4a64a6312 100644 --- a/hints/merge-two-sorted-linked-lists.md +++ b/hints/merge-two-sorted-linked-lists.md @@ -28,4 +28,4 @@ For example, consider list1 = [1, 2, 3] and list2 = [2, 3, 4]. While iterating through the lists, we move the pointers by comparing the node values from both lists. We link the next pointer of the iterator to the node with the smaller value. For instance, when l1 = 1 and l2 = 2, since l1 < l2, we point the iterator's next pointer to l1 and proceed.

- \ No newline at end of file + diff --git a/hints/min-cost-climbing-stairs.md b/hints/min-cost-climbing-stairs.md index 258121826..7114a62bf 100644 --- a/hints/min-cost-climbing-stairs.md +++ b/hints/min-cost-climbing-stairs.md @@ -36,4 +36,4 @@

The base condition would be to return 0 if we are at the top of the staircase i >= n. This is a one-dimensional dynamic programming problem. We can further optimize the memoization solution by using advanced techniques such as Bottom-Up dynamic programming based on the recurrance relation.

- \ No newline at end of file + diff --git a/hints/min-cost-to-connect-points.md b/hints/min-cost-to-connect-points.md index cc585977d..3f9d2c0fb 100644 --- a/hints/min-cost-to-connect-points.md +++ b/hints/min-cost-to-connect-points.md @@ -28,4 +28,4 @@

We create the possible edges by iterating through every pair of points and calculating the weights as the Manhattan distance between them. Next, we sort the edges in ascending order based on their weights, as we aim to minimize the cost. Then, we traverse through these edges, connecting the nodes and adding the weight of the edge to the total cost if the edge is successfully added. The final result will be the minimum cost.

- \ No newline at end of file + diff --git a/hints/minimum-interval-including-query.md b/hints/minimum-interval-including-query.md new file mode 100644 index 000000000..e01b04e17 --- /dev/null +++ b/hints/minimum-interval-including-query.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(nlogn + mlogm) time and O(n + m) space, where m is the size of the array queries and n is the size of the array intervals. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would be to iterate through each query and, for each query, check all intervals to find the result. This would be an O(m * n) solution. Can you think of a better way? Maybe processing the queries in sorted order could help. +

+
+ +
+
+ Hint 2 +

+ We sort the intervals by start value and process the queries in ascending order. Using a pointer i, we add intervals to a min-heap while their start values are less than or equal to the query, storing their end values and sizes. +

+
+ +
+
+ Hint 3 +

+ The min-heap is ordered by interval size. We remove elements from the heap while the top element’s end value is less than the current query. The result for the query is the top element’s size if the heap is non-empty; otherwise, it is -1. +

+
diff --git a/hints/minimum-stack.md b/hints/minimum-stack.md index 411e300dd..8a7776224 100644 --- a/hints/minimum-stack.md +++ b/hints/minimum-stack.md @@ -28,4 +28,4 @@

We use an additional stack to maintain the prefix minimum element. When popping elements from the main stack, we should also pop from this extra stack. However, when pushing onto the extra stack, we should push the minimum of the top element of the extra stack and the current element onto this extra stack.

- \ No newline at end of file + diff --git a/hints/minimum-window-with-characters.md b/hints/minimum-window-with-characters.md index 3df37fff9..c3a431b8a 100644 --- a/hints/minimum-window-with-characters.md +++ b/hints/minimum-window-with-characters.md @@ -36,4 +36,4 @@

We should ensure that we maintain the result substring and only update it if we find a shorter valid substring. Additionally, we need to keep track of the result substring's length so that we can return an empty string if no valid substring is found.

- \ No newline at end of file + diff --git a/hints/missing-number.md b/hints/missing-number.md new file mode 100644 index 000000000..be960c8fd --- /dev/null +++ b/hints/missing-number.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would iterate through the range of numbers from 0 to n, checking if each number is present in the given array. If a number is missing, it is returned. This results in an O(n^2) solution. Can you think of a better way? Maybe a data structure could help optimize this process. +

+
+ +
+
+ Hint 2 +

+ We can use a hash set by inserting the given array elements into it. Then, we iterate through the range of numbers from 0 to n and use the hash set for O(1) lookups to find the missing number. Can you think of a way to further optimize this? Maybe a bitwise operator could be useful. +

+
+ +
+
+ Hint 3 +

+ We can use bitwise XOR. When two identical numbers are XORed, the result is 0. Using this property, we can efficiently find the missing number. +

+
+ +
+
+ Hint 4 +

+ We first compute the bitwise XOR of numbers from 0 to n. Then, we iterate through the array and XOR its elements as well. The missing number remains in the final XOR result since all other numbers appear twice—once in the range and once in the array—while the missing number is XORed only once. +

+
diff --git a/hints/multiply-strings.md b/hints/multiply-strings.md new file mode 100644 index 000000000..5ba886df0 --- /dev/null +++ b/hints/multiply-strings.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(m*n) time and O(m+n) space, where m is the length of the string num1 and n is the length of the string num2. +

+
+ +
+
+ Hint 1 +

+ Implement a helper function that takes two number strings and returns their sum. Ensure that the length of num1 is greater than num2, swapping them if necessary. Can you think of a way to multiply the strings? Maybe you should first consider basic multiplication, where num1 is multiplied by each digit of num2. +

+
+ +
+
+ Hint 2 +

+ When multiplying num1 with each digit of num2, we iterate through num2 in reverse order. Based on the digit's position, we pad zeros to the multiplication result accordingly—no padding for the last digit, one zero for the second last, and so on. What should be the next step after each multiplication? Maybe you should implement a helper function to handle this. +

+
+ +
+
+ Hint 3 +

+ We implement a helper function that takes num1, a digit, and a variable zeroes, returning the multiplication result with zeroes padded at the end. A global string res stores the final result. +

+
+ +
+
+ Hint 4 +

+ In the main function, we iterate through num2 in reverse order, calling the helper function to multiply num1 with the current digit and append the appropriate number of padding zeros. We then call another helper function that takes this multiplication result and the global result string res, adds them, and updates res. +

+
diff --git a/hints/n-queens.md b/hints/n-queens.md index 60c5f6fef..0499f72c3 100644 --- a/hints/n-queens.md +++ b/hints/n-queens.md @@ -28,4 +28,4 @@

We initialize an empty board and recursively go through each column. For each column, we check each cell to see if we can place a queen there. We use a function to check if the cell is suitable by iterating along the left directions and verifying if the same row, left diagonal, or left bottom diagonal are free. If it is possible, we place the queen on the board, move along the recursive path, and then backtrack by removing the queen to continue to the next cell in the column.

- \ No newline at end of file + diff --git a/hints/network-delay-time.md b/hints/network-delay-time.md index 901cefb98..8a3688e94 100644 --- a/hints/network-delay-time.md +++ b/hints/network-delay-time.md @@ -28,4 +28,4 @@

We use a Min-Heap as we need to find the minimum time. We create an adjacency list for the given times (weighted edges). We also initialize an array dist[] of size n (number of nodes) which represents the distance from the source to all nodes, initialized with infinity. We put dist[source] = 0. Then we continue the algorithm. After the heap becomes empty, if we don't visit any node, we return -1; otherwise, we return the time.

- \ No newline at end of file + diff --git a/hints/non-cyclical-number.md b/hints/non-cyclical-number.md new file mode 100644 index 000000000..d8a3b3050 --- /dev/null +++ b/hints/non-cyclical-number.md @@ -0,0 +1,23 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(logn) time and O(logn) space, where n is the given integer. +

+
+ +
+
+ Hint 1 +

+ Create a helper function that returns the sum of the squares of a number's digits. Then, simulate the given process. If we reach 1, return true. However, we may get stuck in a cycle if a number is processed more than once. What data structure can be used to detect if a number has already been processed? +

+
+ +
+
+ Hint 2 +

+ We can use a hash set to detect if a number has already been processed. At each step, we update n with the return value of the helper function. If the result is 1, we return true. If n is already in the set, we return false. Otherwise, we add n to the hash set and continue. +

+
diff --git a/hints/non-overlapping-intervals.md b/hints/non-overlapping-intervals.md new file mode 100644 index 000000000..15c86ea85 --- /dev/null +++ b/hints/non-overlapping-intervals.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(nlogn) time and O(n) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ If two intervals are sorted in ascending order by their start values, they overlap if the start value of the second interval is less than the end value of the first interval. And these are called overlapping intervals. +

+
+ +
+
+ Hint 2 +

+ A brute force approach would be to sort the given intervals in ascending order based on their start values and recursively explore all possibilities. This would be an exponential approach. Can you think of a better way? Maybe a greedy approach works here. +

+
+ +
+
+ Hint 3 +

+ We first sort the given intervals based on their start values to efficiently check for overlaps by comparing adjacent intervals. We then iterate through the sorted intervals from left to right, keeping track of the previous interval’s end value as prevEnd, initially set to the end value of the first interval. +

+
+ +
+
+ Hint 4 +

+ We then iterate from the second interval. If the current interval doesn't overlap, we update prevEnd to the current interval's end and continue. Otherwise, we set prevEnd to the minimum of prevEnd and the current interval’s end, greedily removing the interval that ends last to retain as many intervals as possible. +

+
diff --git a/hints/number-of-one-bits.md b/hints/number-of-one-bits.md new file mode 100644 index 000000000..ed0db85d2 --- /dev/null +++ b/hints/number-of-one-bits.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(1) time and O(1) space. +

+
+ +
+
+ Hint 1 +

+ The given integer is a 32-bit integer. Can you think of using bitwise operators to iterate through its bits? Maybe you should consider iterating 32 times. +

+
+ +
+
+ Hint 2 +

+ We iterate 32 times (0 to 31) using index i. The expression (1 << i) creates a bitmask with a set bit at the i-th position. How can you check whether the i-th bit is set in the given number? Maybe you should consider using the bitwise-AND ("&"). +

+
+ +
+
+ Hint 3 +

+ Since the mask has a set bit at the i-th position and all 0s elsewhere, we can perform a bitwise-AND with n. If n has a set bit at the i-th position, the result is positive; otherwise, it is 0. We increment the global count if the result is positive and return it after the iteration. +

+
diff --git a/hints/pacific-atlantic-water-flow.md b/hints/pacific-atlantic-water-flow.md index 6ed584779..e79541816 100644 --- a/hints/pacific-atlantic-water-flow.md +++ b/hints/pacific-atlantic-water-flow.md @@ -28,4 +28,4 @@

We perform DFS from the border cells, using their respective hash sets. During the DFS, we recursively visit the neighbouring cells that are unvisited and have height greater than or equal to the current cell's height and add the current cell's coordinates to the corresponding hash set. Once the DFS completes, we traverse the grid and check if a cell exists in both the hash sets. If so, we add that cell to the result list.

- \ No newline at end of file + diff --git a/hints/palindrome-partitioning.md b/hints/palindrome-partitioning.md index a2d81783f..d293d2ca7 100644 --- a/hints/palindrome-partitioning.md +++ b/hints/palindrome-partitioning.md @@ -28,4 +28,4 @@

We start with j = 0, i = 0 and a temporary list which stores the substrings from the partitions. Then we recursively iterate the string with the index i. At each step we apply the 2 decisions accordingly. At the base condition of the recursive path, we make a copy of the current partition list and add it to the result.

- \ No newline at end of file + diff --git a/hints/palindromic-substrings.md b/hints/palindromic-substrings.md index 5e994313c..607b4174f 100644 --- a/hints/palindromic-substrings.md +++ b/hints/palindromic-substrings.md @@ -36,4 +36,4 @@

For an even-length palindrome, consider expanding from indices i and i + 1. This two-pointer approach, extending from the center of the palindrome, will help find all palindromic substrings in the given string and return its count.

- \ No newline at end of file + diff --git a/hints/partition-equal-subset-sum.md b/hints/partition-equal-subset-sum.md new file mode 100644 index 000000000..e0411dee4 --- /dev/null +++ b/hints/partition-equal-subset-sum.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(n * t) time and O(n * t) space, where n is the size of the input array and t is half the sum of the array elements. +

+
+ +
+
+ Hint 1 +

+ If the sum of the array elements is not even, we can immediately return false. Think in terms of recursion, where we try to build a subset with a sum equal to half of the total sum. If we find such a subset, the remaining elements will automatically form another subset with the same sum. The entire array can also be considered as one subset, with the other being empty. Can you visualize this as a decision tree to process the array recursively? +

+
+ +
+
+ Hint 2 +

+ We recursively iterate through the array with index i. At each step, we decide whether to include the current element in the subset or not. Instead of forming the subset explicitly, can you think of a better approach? Maybe you only need to track the subset sum rather than generating the subset itself. +

+
+ +
+
+ Hint 3 +

+ We can track the subset sum using a variable curSum. At each step, we make two recursive calls. If adding the current element does not exceed the target, we include it. If either path leads to a solution, we immediately return true. Can you determine the base case for this recursion? All elements in the array are positive. +

+
+ +
+
+ Hint 4 +

+ If curSum equals half the sum of the array elements, we return true. If index i goes out of bounds, we return false. This solution is exponential, but we can use memoization to cache recursive call results and avoid redundant computations. We can use a hash map or a 2D array with dimensions n * t, where n is the size of the input array and t is half the sum of the input array elements. +

+
diff --git a/hints/partition-labels.md b/hints/partition-labels.md new file mode 100644 index 000000000..57defc3df --- /dev/null +++ b/hints/partition-labels.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(m) space, where n is the length of the string s and m is the number of unique characters in the string s. +

+
+ +
+
+ Hint 1 +

+ A character has a first and last index in the given string. Can you think of a greedy approach to solve this problem? Maybe you should try iterating over one of these two indices. +

+
+ +
+
+ Hint 2 +

+ We store the last index of each character in a hash map or an array. As we iterate through the string, treating each index as a potential start of a partition, we track the end of the partition using the maximum last index of the characters seen so far in the current partition. Additionally, we maintain the size of the current partition using a variable, say size. +

+
+ +
+
+ Hint 3 +

+ We update the end of the current partition based on the maximum last index of the characters, extending the partition as needed. When the current index reaches the partition’s end, we finalize the partition, append its size to the output list, reset the size to 0, and continue the same process for the remaining string. +

+
diff --git a/hints/permutation-string.md b/hints/permutation-string.md index 5abcaddf0..d00c4e9e7 100644 --- a/hints/permutation-string.md +++ b/hints/permutation-string.md @@ -28,4 +28,4 @@

We use a sliding window approach on s2 with a fixed window size equal to the length of s1. To track the current window, we maintain a running frequency count of characters in s2. This frequency count represents the characters in the current window. At each step, if the frequency count matches that of s1, we return true.

- \ No newline at end of file + diff --git a/hints/permutations.md b/hints/permutations.md index 3f3d59477..f0cdd994c 100644 --- a/hints/permutations.md +++ b/hints/permutations.md @@ -28,4 +28,4 @@

We observe that every permutation has the same size as the input array. Therefore, we can append a copy of the list of chosen elements in the current path to the result list if the size of the list equals the size of the input array terminating the current recursive path.

- \ No newline at end of file + diff --git a/hints/plus-one.md b/hints/plus-one.md new file mode 100644 index 000000000..9845a3840 --- /dev/null +++ b/hints/plus-one.md @@ -0,0 +1,23 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(n) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ There are two cases when adding 1 to a number. If the rightmost digit is less than 9, we simply increment it. Otherwise, we set it to 0 and apply the same process to the preceding digit. +

+
+ +
+
+ Hint 2 +

+ We iterate through the given digits from right to left using index i. If the current digit is less than 9, we increment it and return the array. Otherwise, we set the digit to 0 and continue. If the loop completes without returning, we insert 1 at the beginning of the array and return it. +

+
diff --git a/hints/pow-x-n.md b/hints/pow-x-n.md new file mode 100644 index 000000000..f66941947 --- /dev/null +++ b/hints/pow-x-n.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(logn) time and O(logn) space, where n is the given integer. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would be to iterate linearly up to n, multiplying by x each time to find (x^n). If n is negative, return (1 / (x^n)); otherwise, return (x^n). Can you think of a better way? Maybe a recursive approach would be more efficient. +

+
+ +
+
+ Hint 2 +

+ For example, to calculate 2^6, instead of multiplying 2 six times, we compute 2^3 and square the result. The same logic applies recursively to find 2^3 and further break down the multiplication. What should be the base case for this recursion? Maybe you should consider the term that cannot be further broken down. +

+
+ +
+
+ Hint 3 +

+ In (x^n), if x is 0, we return 0. If n is 0, we return 1, as any number raised to the power of 0 is 1. Otherwise, we compute (x^(n/2)) recursively and square the result. If n is odd, we multiply the final result by x. What should be the logic if n is negative? +

+
+ +
+
+ Hint 4 +

+ We start the recursion with the absolute value of n. After computing the result as res, we return res if n is non-negative; otherwise, we return (1 / res). +

+
diff --git a/hints/products-of-array-discluding-self.md b/hints/products-of-array-discluding-self.md index bab9964c9..f1692f173 100644 --- a/hints/products-of-array-discluding-self.md +++ b/hints/products-of-array-discluding-self.md @@ -36,4 +36,4 @@

We can use the stored prefix and suffix products to compute the result array by iterating through the array and simply multiplying the prefix and suffix products at each index.

- \ No newline at end of file + diff --git a/hints/reconstruct-flight-path.md b/hints/reconstruct-flight-path.md index 43f336c17..326a59ac1 100644 --- a/hints/reconstruct-flight-path.md +++ b/hints/reconstruct-flight-path.md @@ -36,4 +36,4 @@

We can use Hierholzer's algorithm, a modified DFS approach. Instead of appending the node to the result list immediately, we first visit all its neighbors. This results in a post-order traversal. After completing all the DFS calls, we reverse the path to obtain the final path, which is also called Euler's path.

- \ No newline at end of file + diff --git a/hints/redundant-connection.md b/hints/redundant-connection.md index cdd3217fe..38a354115 100644 --- a/hints/redundant-connection.md +++ b/hints/redundant-connection.md @@ -28,4 +28,4 @@

We create an instance of the DSU object and traverse through the given edges. For each edge, we attempt to connect the nodes using the union function. If the union function returns false, indicating that the current edge forms a cycle, we immediately return that edge.

- \ No newline at end of file + diff --git a/hints/regular-expression-matching.md b/hints/regular-expression-matching.md new file mode 100644 index 000000000..7afa136e0 --- /dev/null +++ b/hints/regular-expression-matching.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(m * n) time and O(m * n) space, where m is the length of the string s and n is the length of the string p. +

+
+ +
+
+ Hint 1 +

+ Try to think in terms of recursion and visualize it as a decision tree, where we explore different combinations to match the strings when encountering *. Multiple decisions are made at each step to find a valid matching path. Can you determine the possible decisions at each recursion step? +

+
+ +
+
+ Hint 2 +

+ We recursively iterate through the strings using indices i and j for s and p, respectively. If the characters match or p[j] is '.', we increment both i and j to process the remaining strings. When the next character of string p is '*', we have two choices: skip it (treating it as zero occurrences) or match one or more characters (if s[i] matches p[j]), incrementing i accordingly. +

+
+ +
+
+ Hint 3 +

+ If both indices go out of bounds, we return true; otherwise, we return false. If any recursive path returns true, we immediately return true. This approach is exponential. Can you think of a way to optimize it? +

+
+ +
+
+ Hint 4 +

+ We can use memoization to cache the results of recursive calls and avoid redundant calculations. A hash map or a 2D array can be used to store these results. +

+
diff --git a/hints/remove-node-from-end-of-linked-list.md b/hints/remove-node-from-end-of-linked-list.md index d73855f6f..227e124de 100644 --- a/hints/remove-node-from-end-of-linked-list.md +++ b/hints/remove-node-from-end-of-linked-list.md @@ -44,4 +44,4 @@

This greedy approach works because the second pointer is n nodes behind the first pointer. When the first pointer reaches the end, the second pointer is exactly n nodes from the end. This positioning allows us to remove the nth node from the end efficiently.

- \ No newline at end of file + diff --git a/hints/reverse-a-linked-list.md b/hints/reverse-a-linked-list.md index 9d8db81d4..d7cde3482 100644 --- a/hints/reverse-a-linked-list.md +++ b/hints/reverse-a-linked-list.md @@ -36,4 +36,4 @@

We can reverse the linked list in place by reversing the pointers between two nodes while keeping track of the next node's address. Before changing the next pointer of the current node, we must store the next node to ensure we don't lose the rest of the list during the reversal. This way, we can safely update the links between the previous and current nodes.

- \ No newline at end of file + diff --git a/hints/reverse-bits.md b/hints/reverse-bits.md new file mode 100644 index 000000000..72c3d9ba0 --- /dev/null +++ b/hints/reverse-bits.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(1) time and O(1) space. +

+
+ +
+
+ Hint 1 +

+ Given a 32-bit integer, what is the position of bit i after reversing the bits? Maybe you should observe the bit positions before and after reversal to find a pattern. +

+
+ +
+
+ Hint 2 +

+ After reversing the bits, the bit at position i moves to position 31 - i. Can you use this observation to construct the reversed number efficiently? +

+
+ +
+
+ Hint 3 +

+ We initialize res to 0 and iterate through the bits of the given integer n. We extract the bit at the i-th position using ((n >> i) & 1). If it is 1, we set the corresponding bit in res at position (31 - i) using (res |= (1 << (31 - i))). +

+
diff --git a/hints/reverse-integer.md b/hints/reverse-integer.md new file mode 100644 index 000000000..63ffb1c5a --- /dev/null +++ b/hints/reverse-integer.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(1) time and O(1) space. +

+
+ +
+
+ Hint 1 +

+ A straightforward approach would be to convert the given integer to a string, reverse it, convert it back to an integer using a long type, and return 0 if the result exceeds the integer range. Can you think of a better way? +

+
+ +
+
+ Hint 2 +

+ We initially declare the result res as an int with a value of 0. We iterate through the given integer, extracting digits one by one. Before appending a digit to res, we consider multiple cases. Can you determine them? Maybe you should think about overflow. +

+
+ +
+
+ Hint 3 +

+ Let MAX be the maximum positive integer and MIN be the minimum negative integer. We iterate through each digit and check for overflow before updating res. If res > MAX / 10 or res < MIN / 10, return 0. If res == MAX / 10 and the current digit is greater than MAX % 10, return 0. If res == MIN / 10 and the current digit is less than MIN % 10, return 0. Otherwise, append the digit to res and continue. +

+
diff --git a/hints/reverse-nodes-in-k-group.md b/hints/reverse-nodes-in-k-group.md index b686ce645..3ee3fe0af 100644 --- a/hints/reverse-nodes-in-k-group.md +++ b/hints/reverse-nodes-in-k-group.md @@ -28,4 +28,4 @@

We create a dummy node to handle modifications to the head of the linked list, pointing its next pointer to the current head. We then iterate k nodes, storing the address of the next group's head and tracking the tail of the previous group. After reversing the current group, we reconnect it by linking the previous group's tail to the new head and the current group's tail to the next group's head. This process is repeated for all groups, and we return the new head of the linked list.

- \ No newline at end of file + diff --git a/hints/rotate-matrix.md b/hints/rotate-matrix.md new file mode 100644 index 000000000..983307b08 --- /dev/null +++ b/hints/rotate-matrix.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n^2) time and O(1) space, where n is the length of the side of the given square matrix. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would use O(n^2) extra space to solve the problem. Can you think of a way to avoid using extra space? Maybe you should consider observing the positions of the elements before rotating and after rotating of the matrix. +

+
+ +
+
+ Hint 2 +

+ We can rotate the matrix in two steps. First, we reverse the matrix vertically, meaning the first row becomes the last, the second row becomes the second last, and so on. Next, we transpose the reversed matrix, meaning rows become columns and columns become rows. How would you transpose the matrix? +

+
+ +
+
+ Hint 3 +

+ Since the given matrix is a square matrix, we only need to iterate over the upper triangular part, meaning the right upper portion of the main diagonal. In this way, we can transpose a matrix. +

+
diff --git a/hints/rotting-fruit.md b/hints/rotting-fruit.md index 76ce34b5b..6d9b27717 100644 --- a/hints/rotting-fruit.md +++ b/hints/rotting-fruit.md @@ -28,4 +28,4 @@

We traverse the grid and store the rotten oranges in a queue. We then run a BFS, processing the current level of rotten oranges and visiting the adjacent cells of each rotten orange. We only insert the adjacent cell into the queue if it contains a fresh orange. This process continues until the queue is empty. The level at which the BFS stops is the answer. However, we also need to check whether all oranges have rotted by traversing the grid. If any fresh orange is found, we return -1; otherwise, we return the level.

- \ No newline at end of file + diff --git a/hints/same-binary-tree.md b/hints/same-binary-tree.md index 3a79a39f2..096eca0dc 100644 --- a/hints/same-binary-tree.md +++ b/hints/same-binary-tree.md @@ -28,4 +28,4 @@

We traverse both trees starting from their root nodes. At each step in the recursion, we check if the current nodes in both trees are either null or have the same value. If one node is null while the other is not, or if their values differ, we return false. If the values match, we recursively check their left and right subtrees. If any recursive call returns false, the result for the current recursive call is false.

- \ No newline at end of file + diff --git a/hints/search-2d-matrix.md b/hints/search-2d-matrix.md index 53153f798..46743ed57 100644 --- a/hints/search-2d-matrix.md +++ b/hints/search-2d-matrix.md @@ -36,4 +36,4 @@

Once we identify the potential row where the target might exist, we can perform a binary search on that row which acts as a one dimensional array. It takes O(logn) time, where n is the number of columns in the row.

- \ No newline at end of file + diff --git a/hints/search-for-word-ii.md b/hints/search-for-word-ii.md index 205964c7e..cbfea32f0 100644 --- a/hints/search-for-word-ii.md +++ b/hints/search-for-word-ii.md @@ -36,4 +36,4 @@

We insert all the words into the Trie with their indices marked. Then, we iterate through each cell in the grid. At each cell, we start at the root of the Trie and explore all possible paths. As we traverse, we match characters in the cell with those in the Trie nodes. If we encounter the end of a word, we take the index at that node and add the corresponding word to the result list. Afterward, we unmark that index and continue exploring further paths.

- \ No newline at end of file + diff --git a/hints/search-for-word.md b/hints/search-for-word.md index 9dcdf4102..1c671ebd1 100644 --- a/hints/search-for-word.md +++ b/hints/search-for-word.md @@ -28,4 +28,4 @@

We can use backtracking, starting from each cell on the board with coordinates (row, col) and index i for the given word. We return false if (row, col) is out of bounds or if board[row][col] != word[i]. When i reaches the end of the word, we return true, indicating a valid path. At each step, we add (row, col) to a hash set to avoid revisiting cells. After exploring the four possible directions, we backtrack and remove (row, col) from the hash set.

- \ No newline at end of file + diff --git a/hints/serialize-and-deserialize-binary-tree.md b/hints/serialize-and-deserialize-binary-tree.md index a93feef8e..c3a00ebcd 100644 --- a/hints/serialize-and-deserialize-binary-tree.md +++ b/hints/serialize-and-deserialize-binary-tree.md @@ -28,4 +28,4 @@

We can use the Depth First Search (DFS) algorithm for both serialization and deserialization. During serialization, we traverse the tree and add node values to the result string separated by a delimiter, inserting N whenever we encounter a null node. During deserialization, we process the serialized string using an index i, create nodes for valid values, and return from the current path whenever we encounter N, reconstructing the tree accurately.

- \ No newline at end of file + diff --git a/hints/set-zeroes-in-matrix.md b/hints/set-zeroes-in-matrix.md new file mode 100644 index 000000000..27a9c7fee --- /dev/null +++ b/hints/set-zeroes-in-matrix.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(m*n) time and O(1) space, where m is the number of rows and n is the number of columns in the given matrix. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would iterate through the given matrix and update the corresponding row and column in a new matrix on the fly. This would result in an O((m*n)*(m+n)) time and O(m*n) space solution. Can you think of a better way? Maybe you should consider using a single variable for a row and a single variable for a column instead of updating entire row and column. +

+
+ +
+
+ Hint 2 +

+ A better approach is to use O(m+n) boolean arrays. We iterate through the matrix, and when encountering a zero, we mark the respective row and column as true. In the second iteration, we set a cell to 0 if its corresponding row or column is marked true. Can you think of a way to optimize the space further? +

+
+ +
+
+ Hint 3 +

+ We can use the topmost row and leftmost column of the matrix as boolean arrays by marking 0 instead of true. However, since they overlap at one cell, we use a single variable to track the top row separately. We then iterate through the matrix and mark zeros accordingly. +

+
+ +
+
+ Hint 4 +

+ In the second iteration, we update all cells that are not part of the top row or left column accordingly. After making the necessary changes, we check the top-leftmost cell and update the corresponding column. Finally, we check the extra variable and update the top row accordingly. +

+
diff --git a/hints/single-number.md b/hints/single-number.md new file mode 100644 index 000000000..64bb2a062 --- /dev/null +++ b/hints/single-number.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(n) time and O(1) space, where n is the size of the input array. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would iterate through the array, checking each element using a nested loop. If a duplicate is found, we continue to the next element; otherwise, the current element is the required number. This results in an O(n^2) solution. Can you think of a better way? Maybe a data structure can help detect duplicates efficiently. +

+
+ +
+
+ Hint 2 +

+ We use a hash set, iterating through the array and adding elements that are not in the set while removing those that are already present. After the iteration, the required number remains in the hash set. This results in an O(n) space solution. Can you further optimize it? Maybe a bitwise operator could be useful here. +

+
+ +
+
+ Hint 3 +

+ Think about the bitwise XOR ("^"). What is the result when two identical numbers are XORed? +

+
+ +
+
+ Hint 4 +

+ When two identical numbers are XORed, they cancel out, resulting in zero. Since every number appears twice except for one, the XOR of the entire array gives the number that appears only once. +

+
diff --git a/hints/sliding-window-maximum.md b/hints/sliding-window-maximum.md index 3506407c3..8f8571cd2 100644 --- a/hints/sliding-window-maximum.md +++ b/hints/sliding-window-maximum.md @@ -36,4 +36,4 @@

We can ignore those elements that are no longer part of the current window, except when the maximum value is outside the window. In that case, we remove elements from the max-heap until the maximum value belongs to the current window. Why? Because those elements will be eventually removed when the maximum element goes out of the window.

- \ No newline at end of file + diff --git a/hints/spiral-matrix.md b/hints/spiral-matrix.md new file mode 100644 index 000000000..30cdc6d98 --- /dev/null +++ b/hints/spiral-matrix.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(m*n) time and O(1) extra space, where m is the number of rows and n is the number of columns in the given matrix. +

+
+ +
+
+ Hint 1 +

+ Try to simulate the process as described in the problem. Think in terms of matrix layers, starting from the outermost boundaries and moving inward. Can you determine an efficient way to implement this? +

+
+ +
+
+ Hint 2 +

+ Each boundary consists of four parts: the top row, right column, bottom row, and left column, which follow the spiral order and act as four pointers. For each layer, the top pointer increments by one, the right pointer decrements by one, the left pointer increments by one, and the bottom pointer decrements by one. +

+
+ +
+
+ Hint 3 +

+ At each layer, four loops traverse the matrix: one moves left to right along the top row, another moves top to bottom along the right column, the next moves right to left along the bottom row, and the last moves bottom to top along the left column. This process generates the spiral order. +

+
diff --git a/hints/string-encode-and-decode.md b/hints/string-encode-and-decode.md index 39083d5be..2dd2df0a4 100644 --- a/hints/string-encode-and-decode.md +++ b/hints/string-encode-and-decode.md @@ -2,7 +2,7 @@
Recommended Time & Space Complexity

- You should aim for a solution with O(m) time and O(1) space for each encode() and decode() call, where m is the sum of lengths of all the strings. + You should aim for a solution with O(m) time for each encode() and decode() call and O(m+n) space, where m is the sum of lengths of all the strings and n is the number of strings.

@@ -28,4 +28,4 @@

We can use an encoding approach where we start with a number representing the length of the string, followed by a separator character (let's use # for simplicity), and then the string itself. To decode, we read the number until we reach a #, then use that number to read the specified number of characters as the string.

- \ No newline at end of file + diff --git a/hints/subsets-ii.md b/hints/subsets-ii.md index 4001ea052..ae0cc1186 100644 --- a/hints/subsets-ii.md +++ b/hints/subsets-ii.md @@ -28,4 +28,4 @@

We start by sorting the input array. Then, we recursively iterate through the array from left to right, extending recursive paths by including or excluding each element. To avoid duplicate subsets, we skip an element if it is the same as the previous one. Finally, we return the generated subsets as a list.

- \ No newline at end of file + diff --git a/hints/subsets.md b/hints/subsets.md index 63a694ba2..e4e038fa5 100644 --- a/hints/subsets.md +++ b/hints/subsets.md @@ -36,4 +36,4 @@

When the index i reaches the end of the array, we append a copy of the subset formed in that particular recursive path to the result list and return. All subsets of the given array are generated from these different recursive paths, which represent various combinations of "include" and "not include" steps for the elements of the array. As we are only iterating from left to right in the array, we don't pick an element more than once.

- \ No newline at end of file + diff --git a/hints/subtree-of-a-binary-tree.md b/hints/subtree-of-a-binary-tree.md index 79aaf1a57..c101a8622 100644 --- a/hints/subtree-of-a-binary-tree.md +++ b/hints/subtree-of-a-binary-tree.md @@ -28,4 +28,4 @@

We traverse the given root, and at each node, we check if the subtree rooted at that node is identical to the given subRoot. We use a helper function, sameTree(root1, root2), to determine whether the two trees passed to it are identical in both structure and values.

- \ No newline at end of file + diff --git a/hints/sum-of-two-integers.md b/hints/sum-of-two-integers.md new file mode 100644 index 000000000..d5aa04b02 --- /dev/null +++ b/hints/sum-of-two-integers.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution with O(1) time and O(1) space. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would use the addition operator. Can you think of a way to perform addition without using it? Maybe you should consider solving this using bit manipulation. +

+
+ +
+
+ Hint 2 +

+ We can use the bitwise XOR operator to perform addition. If both a and b have 1 at the same bit position, the sum at that position is 0, and a carry of 1 is generated. If the bits are different, the sum at that position is 1. Additionally, we account for the carry from the previous step in the next iteration. +

+
+ +
+
+ Hint 3 +

+ We iterate bit by bit from 0 to 31 since the given integers are 32-bit. We track the carry, initially set to 0, and initialize the result as res. During iteration, the XOR of the bits at the i-th position of both integers and the carry determines the current bit of res. How can you handle negative numbers? +

+
+ +
+
+ Hint 4 +

+ To handle negative numbers, if the final result exceeds the maximum positive 32-bit integer, it means the number should be negative. We adjust it using bitwise operations: flipping the bits with res ^ ((2 ^ 32) - 1) and applying ~ to restore the correct two’s complement representation. This ensures the result correctly represents signed 32-bit integers. +

+
diff --git a/hints/surrounded-regions.md b/hints/surrounded-regions.md index d61a1db78..49e38646d 100644 --- a/hints/surrounded-regions.md +++ b/hints/surrounded-regions.md @@ -28,4 +28,4 @@

We run the DFS from every 'O' on the border of the matrix, visiting the neighboring cells that are equal to 'O' recursively and marking them as '#' to avoid revisiting. After completing all the DFS calls, we traverse the matrix again and capture the cells where matrix[i][j] == 'O', and unmark the cells back to 'O' where matrix[i][j] == '#'.

- \ No newline at end of file + diff --git a/hints/swim-in-rising-water.md b/hints/swim-in-rising-water.md index 5e098b6f0..432e6515e 100644 --- a/hints/swim-in-rising-water.md +++ b/hints/swim-in-rising-water.md @@ -28,4 +28,4 @@

We can use Dijkstra's algorithm. We initialize a Min-heap and a matrix with infinity. We run the algorithm starting from the source (0, 0), and we track the maximum elevation encountered along the paths. This maximum elevation is used as the key for comparison in Dijkstra's algorithm. If we encounter the destination (n - 1, n - 1), we return the maximum elevation of the path that reached the destination.

- \ No newline at end of file + diff --git a/hints/target-sum.md b/hints/target-sum.md new file mode 100644 index 000000000..0ce4f950c --- /dev/null +++ b/hints/target-sum.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(n * m) time and O(n * m) space, where n is the size of the input array and m is the sum of all the elements in the array. +

+
+ +
+
+ Hint 1 +

+ Try to think in terms of recursion and visualize it as a decision tree, where we have two choices at each recursion step: assigning a positive or negative sign. +

+
+ +
+
+ Hint 2 +

+ We recursively iterate through the array using index i, tracking the current sum along the recursive path. Each step branches into two paths, and we sum the number of ways to reach the target. If the index i goes out of bounds, we return 1 if the current sum equals the target; otherwise, we return 0. +

+
+ +
+
+ Hint 3 +

+ This approach is exponential. We can use memoization to cache recursive call results and avoid redundant calculations. A hash map or a 2D array with modifications can be used for caching. If using a 2D array, the dimensions can be (n * (2m + 1)), where n is the array size and m represents the sum of the array elements. +

+
diff --git a/hints/task-scheduling.md b/hints/task-scheduling.md index 1b351db49..f1e745890 100644 --- a/hints/task-scheduling.md +++ b/hints/task-scheduling.md @@ -36,4 +36,4 @@

We start by calculating the frequency of each task and initialize a variable time to track the total processing time. The task frequencies are inserted into a Max-Heap. We also use a queue to store tasks along with the time they become available after the cooldown. At each step, if the Max-Heap is empty, we update time to match the next available task in the queue, covering idle time. Otherwise, we process the most frequent task from the heap, decrement its frequency, and if it's still valid, add it back to the queue with its next available time. If the task at the front of the queue becomes available, we pop it and reinsert it into the heap.

- \ No newline at end of file + diff --git a/hints/time-based-key-value-store.md b/hints/time-based-key-value-store.md index 5b4e80ea6..2f2949ed0 100644 --- a/hints/time-based-key-value-store.md +++ b/hints/time-based-key-value-store.md @@ -36,4 +36,4 @@

We can use binary search because the timestamps in the values list are sorted in ascending order. This makes it straightforward to find the value with the most recent timestamp that is less than or equal to the given timestamp.

- \ No newline at end of file + diff --git a/hints/top-k-elements-in-list.md b/hints/top-k-elements-in-list.md index 566ec05de..e22b83718 100644 --- a/hints/top-k-elements-in-list.md +++ b/hints/top-k-elements-in-list.md @@ -28,4 +28,4 @@

Use the bucket sort algorithm to create n buckets, grouping numbers based on their frequencies from 1 to n. Then, pick the top k numbers from the buckets, starting from n down to 1.

- \ No newline at end of file + diff --git a/hints/trapping-rain-water.md b/hints/trapping-rain-water.md index 2ae54b063..1623cfc80 100644 --- a/hints/trapping-rain-water.md +++ b/hints/trapping-rain-water.md @@ -36,4 +36,4 @@

We can store the prefix maximum in an array by iterating from left to right and the suffix maximum in another array by iterating from right to left. For example, in [1, 5, 2, 3, 4], for the element 3, the prefix maximum is 5, and the suffix maximum is 4. Once these arrays are built, we can iterate through the array with index i and calculate the total water trapped at each position using the formula: min(prefix[i], suffix[i]) - height[i].

- \ No newline at end of file + diff --git a/hints/two-integer-sum-ii.md b/hints/two-integer-sum-ii.md index a07baf4ac..3d31dbae2 100644 --- a/hints/two-integer-sum-ii.md +++ b/hints/two-integer-sum-ii.md @@ -36,4 +36,4 @@

We keep two pointers, one at the start and the other at the end of the array. If the sum of the numbers at the two pointers is greater than the target, decrement the right pointer, else increment the left pointer. Repeat this process until you find a valid pair.

- \ No newline at end of file + diff --git a/hints/two-integer-sum.md b/hints/two-integer-sum.md index 948aae221..c517dd472 100644 --- a/hints/two-integer-sum.md +++ b/hints/two-integer-sum.md @@ -28,4 +28,4 @@

we can iterate through nums with index i. Let difference = target - nums[i] and check if difference exists in the hash map as we iterate through the array, else store the current element in the hashmap with its index and continue. We use a hashmap for O(1) lookups.

- \ No newline at end of file + diff --git a/hints/valid-binary-search-tree.md b/hints/valid-binary-search-tree.md index 9a691ece8..b6b87249d 100644 --- a/hints/valid-binary-search-tree.md +++ b/hints/valid-binary-search-tree.md @@ -28,4 +28,4 @@

We start with the interval [-infinity, infinity] for the root node. As we traverse the tree, when checking the left subtree, we update the maximum value limit because all values in the left subtree must be less than the current node's value. Conversely, when checking the right subtree, we update the minimum value limit because all values in the right subtree must be greater than the current node's value.

- \ No newline at end of file + diff --git a/hints/valid-parenthesis-string.md b/hints/valid-parenthesis-string.md new file mode 100644 index 000000000..81ff9bcff --- /dev/null +++ b/hints/valid-parenthesis-string.md @@ -0,0 +1,39 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(n) time and O(n) space, where n is the length of the input string. +

+
+ +
+
+ Hint 1 +

+ A brute force approach would try all possibilities when encountering a '*' and recursively solve the problem, leading to an exponential approach. Can you think of a better way? Maybe a data structure commonly used in parenthesis problems could be useful. +

+
+ +
+
+ Hint 2 +

+ We can solve the problem using a stack-based approach. We maintain two stacks: one for tracking the indices of left parentheses and another for star indices. As we iterate through the string from left to right, we push indices onto their respective stacks when encountering a left parenthesis '(' or a star '*'. Can you determine the logic for the right parentesis case? +

+
+ +
+
+ Hint 3 +

+ If the left parenthesis stack is not empty, we pop from it. Otherwise, we pop from the star stack, treating the star as a left parenthesis to keep the string valid. After iterating the string, the stacks might be non-empty? Can you determine the logic for this case? +

+
+ +
+
+ Hint 4 +

+ Now, we try to match the remaining left parentheses with stars, ensuring the stars appear after the left parentheses in the string. We simultaneously pop from both stacks, and if the index of a left parenthesis is greater than that of a star, the string is invalid as there is no matching right parenthesis. In this case, we return false. +

+
diff --git a/hints/valid-sudoku.md b/hints/valid-sudoku.md index 51655ed8b..6b10bc68e 100644 --- a/hints/valid-sudoku.md +++ b/hints/valid-sudoku.md @@ -28,4 +28,4 @@

We can find the index of each square by the equation (row / 3) * 3 + (col / 3). Then we use hash set for O(1) lookups while inserting the number into its row, column and square it belongs to. We use separate hash maps for rows, columns, and squares.

- \ No newline at end of file + diff --git a/hints/valid-tree.md b/hints/valid-tree.md index 7e7d37358..fbeebf0ae 100644 --- a/hints/valid-tree.md +++ b/hints/valid-tree.md @@ -28,4 +28,4 @@

We start DFS from node 0, assuming -1 as its parent. We initialize a hash set visit to track the visited nodes in the graph. During the DFS, we first check if the current node is already in visit. If it is, we return false, detecting a cycle. Otherwise, we mark the node as visited and perform DFS on its neighbors, skipping the parent node to avoid revisiting it. After all DFS calls, if we have visited all nodes, we return true, as the graph is connected. Otherwise, we return false because a tree must contain all nodes.

- \ No newline at end of file + diff --git a/hints/validate-parentheses.md b/hints/validate-parentheses.md index ec5216bb4..908d06dba 100644 --- a/hints/validate-parentheses.md +++ b/hints/validate-parentheses.md @@ -28,4 +28,4 @@

In a valid parenthesis expression, every opening bracket must have a corresponding closing bracket. The stack is used to process the valid string, and it should be empty after the entire process. This ensures that there is a valid substring between each opening and closing bracket.

- \ No newline at end of file + diff --git a/hints/word-break.md b/hints/word-break.md new file mode 100644 index 000000000..6b8b32d7f --- /dev/null +++ b/hints/word-break.md @@ -0,0 +1,31 @@ +
+
+ Recommended Time & Space Complexity +

+ You should aim for a solution as good or better than O(n * m * t) time and O(n) space, where n is the length of the string s, m is the number of words in wordDict, and t is the maximum length of any word in wordDict. +

+
+ +
+
+ Hint 1 +

+ Try to think of this problem in terms of recursion, where we explore all possibilities. We iterate through the given string s, attempting to pick a word from wordDict that matches a portion of s, and then recursively continue processing the remaining string. Can you determine the recurrence relation and base condition? +

+
+ +
+
+ Hint 2 +

+ The base condition is to return true if we reach the end of the string s. At each recursive call with index i iterating through s, we check all words in wordDict and recursively process the remaining string by incrementing i by the length of the matched word. If any recursive path returns true, we immediately return true. However, this solution is exponential. Can you think of an optimization? Maybe you should consider an approach that avoids repeated work. +

+
+ +
+
+ Hint 3 +

+ We can avoid recalculating results for recursive calls by using memoization. Since we iterate with index i, we can use a hash map or an array of the same length as s to cache the results of recursive calls and prevent redundant computations. +

+
diff --git a/hints/word-ladder.md b/hints/word-ladder.md index efdd32a2c..5d065be31 100644 --- a/hints/word-ladder.md +++ b/hints/word-ladder.md @@ -28,4 +28,4 @@

When visiting a node during BFS, if the word matches the endWord, we immediately return true. Otherwise, we generate the pattern words that can be formed from the current word and attempt to visit the words connected to these pattern words. We add only unvisited words to the queue. If we exhaust all possibilities without finding the endWord, we return false.

- \ No newline at end of file + diff --git a/javascript/0001-two-sum.js b/javascript/0001-two-sum.js index 68c0fafce..272eb004d 100644 --- a/javascript/0001-two-sum.js +++ b/javascript/0001-two-sum.js @@ -7,19 +7,21 @@ * @return {number[]} */ var twoSum = (nums, target) => { - for (let curr = 0; curr < nums.length; curr++) {/* Time O(N) */ + for (let curr = 0; curr < nums.length; curr++) { + /* Time O(N) */ const complement = target - nums[curr]; - for (let next = (curr + 1); next < nums.length; next++) {/* Time O(N) */ + for (let next = curr + 1; next < nums.length; next++) { + /* Time O(N) */ const num = nums[next]; - const isTarget = num === complement - if (isTarget) return [ curr, next ]; + const isTarget = num === complement; + if (isTarget) return [curr, next]; } } - return [ -1, -1 ]; -} + return [-1, -1]; +}; /** * Hash Map - 2 Pass @@ -30,30 +32,32 @@ var twoSum = (nums, target) => { * @return {number[]} */ var twoSum = (nums, target) => { - const map = getMap(nums); /* Time O(N) | Space O(N) */ + const map = getMap(nums); /* Time O(N) | Space O(N) */ - return getSum(nums, target, map)/* Time O(N) */ -} + return getSum(nums, target, map); /* Time O(N) */ +}; const getMap = (nums, map = new Map()) => { - for (let index = 0; index < nums.length; index++) {/* Time O(N) */ - map.set(nums[index], index); /* Space O(N) */ + for (let index = 0; index < nums.length; index++) { + /* Time O(N) */ + map.set(nums[index], index); /* Space O(N) */ } - return map -} + return map; +}; const getSum = (nums, target, map) => { - for (let index = 0; index < nums.length; index++) {/* Time O(N) */ + for (let index = 0; index < nums.length; index++) { + /* Time O(N) */ const complement = target - nums[index]; const sumIndex = map.get(complement); - const isTarget = map.has(complement) && (map.get(complement) !== index) - if (isTarget) return [ index, sumIndex ] + const isTarget = map.has(complement) && map.get(complement) !== index; + if (isTarget) return [index, sumIndex]; } - return [ -1, -1 ]; -} + return [-1, -1]; +}; /** * Hash Map - 1 Pass @@ -64,16 +68,17 @@ const getSum = (nums, target, map) => { * @return {number[]} */ var twoSum = (nums, target, map = new Map()) => { - for (let index = 0; index < nums.length; index++) {/* Time O(N) */ + for (let index = 0; index < nums.length; index++) { + /* Time O(N) */ const num = nums[index]; - const complement = (target - num); + const complement = target - num; const sumIndex = map.get(complement); - const isTarget = map.has(complement) - if (isTarget) return [ index, sumIndex ]; + const isTarget = map.has(complement); + if (isTarget) return [index, sumIndex]; - map.set(num, index); /* Space O(N) */ + map.set(num, index); /* Space O(N) */ } - return [ -1, -1 ]; -} \ No newline at end of file + return [-1, -1]; +}; diff --git a/javascript/0002-add-two-numbers.js b/javascript/0002-add-two-numbers.js index 129cf39c8..4f4e5ff96 100644 --- a/javascript/0002-add-two-numbers.js +++ b/javascript/0002-add-two-numbers.js @@ -5,18 +5,29 @@ * @param {ListNode} l2 * @return {ListNode} */ -var addTwoNumbers = function(l1, l2) { - let sentinel = tail = new ListNode(); +var addTwoNumbers = function (l1, l2) { + let sentinel = (tail = new ListNode()); - return add(l1, l2, tail, sentinel); /* Time O(MAX(N, M)) | Space O(MAX(N, M)) */ -} + return add( + l1, + l2, + tail, + sentinel, + ); /* Time O(MAX(N, M)) | Space O(MAX(N, M)) */ +}; const add = (l1, l2, tail, sentinel, carry = 0) => { const isBaseCase = !(l1 || l2 || carry); if (isBaseCase) return sentinel.next; - return dfs(l1, l2, tail, sentinel, carry);/* Time O(MAX(N, M)) | Space O(MAX(N, M)) */ -} + return dfs( + l1, + l2, + tail, + sentinel, + carry, + ); /* Time O(MAX(N, M)) | Space O(MAX(N, M)) */ +}; const dfs = (l1, l2, tail, sentinel, carry) => { const sum = (l1?.val || 0) + (l2?.val || 0) + carry; @@ -29,10 +40,16 @@ const dfs = (l1, l2, tail, sentinel, carry) => { l1 = l1?.next || null; l2 = l2?.next || null; - add(l1, l2, tail, sentinel, carry); /* Time O(MAX(N, M)) | Space O(MAX(N, M)) */ + add( + l1, + l2, + tail, + sentinel, + carry, + ); /* Time O(MAX(N, M)) | Space O(MAX(N, M)) */ return sentinel.next; -} +}; /** * https://leetcode.com/problems/add-two-numbers/ @@ -41,10 +58,11 @@ const dfs = (l1, l2, tail, sentinel, carry) => { * @param {ListNode} l2 * @return {ListNode} */ -var addTwoNumbers = function(l1, l2, carry = 0) { - let sentinel = tail = new ListNode(); +var addTwoNumbers = function (l1, l2, carry = 0) { + let sentinel = (tail = new ListNode()); - while (l1 || l2 || carry) {/* Time O(MAX(N, M)) */ + while (l1 || l2 || carry) { + /* Time O(MAX(N, M)) */ const sum = (l1?.val || 0) + (l2?.val || 0) + carry; const val = sum % 10; carry = Math.floor(sum / 10); diff --git a/javascript/0004-median-of-two-sorted-arrays.js b/javascript/0004-median-of-two-sorted-arrays.js index 7aa178d9d..119ac337f 100644 --- a/javascript/0004-median-of-two-sorted-arrays.js +++ b/javascript/0004-median-of-two-sorted-arrays.js @@ -20,7 +20,7 @@ var findMedianSortedArrays = function (nums1, nums2) { nums1, mid1, nums2, - mid2 + mid2, ); const isTarget = aLeft <= bRight && bLeft <= aRight; diff --git a/javascript/0005-longest-palindromic-substring.js b/javascript/0005-longest-palindromic-substring.js index c52a3dbec..ae9e0b547 100644 --- a/javascript/0005-longest-palindromic-substring.js +++ b/javascript/0005-longest-palindromic-substring.js @@ -9,35 +9,42 @@ var longestPalindrome = (s) => { const isEmpty = s.length === 0; if (isEmpty) return ''; - const [ left, right ] = search(s);/* Time O(N * N) */ + const [left, right] = search(s); /* Time O(N * N) */ - return s.slice(left, (right + 1));/* Time O(N * N) | Ignore Auxillary Space (N) */ -} + return s.slice( + left, + right + 1, + ); /* Time O(N * N) | Ignore Auxillary Space (N) */ +}; const search = (s, left = 0, right = 0) => { - for (let index = 0; index < s.length; index++) {/* Time O(N) */ - const len1 = getLength(s, index, index); /* Time O(N) */ - const len2 = getLength(s, index, (index + 1)); /* Time O(N) */ - const [ length, window ] = [ (Math.max(len1, len2)), (right - left) ]; + for (let index = 0; index < s.length; index++) { + /* Time O(N) */ + const len1 = getLength(s, index, index); /* Time O(N) */ + const len2 = getLength(s, index, index + 1); /* Time O(N) */ + const [length, window] = [Math.max(len1, len2), right - left]; - const canSkip = (length <= window); + const canSkip = length <= window; if (canSkip) continue; - left = (index - ((length - 1) >> 1)); - right = (index + (length >> 1)); + left = index - ((length - 1) >> 1); + right = index + (length >> 1); } - return [ left, right ]; -} + return [left, right]; +}; const getLength = (s, left, right) => { - const canExpand = () => ((0 <= left) && (right < s.length)); - const isSame = () => (s[left] === s[right]); + const canExpand = () => 0 <= left && right < s.length; + const isSame = () => s[left] === s[right]; - const isPalindrome = () => (canExpand() && isSame()); - while (isPalindrome()) { left--; right++; }/* Time O(N) */ + const isPalindrome = () => canExpand() && isSame(); + while (isPalindrome()) { + left--; + right++; + } /* Time O(N) */ - const window = ((right - left) - 1); + const window = right - left - 1; return window; -} +}; diff --git a/javascript/0007-reverse-integer.js b/javascript/0007-reverse-integer.js index 551e87ad7..fa26a6d70 100644 --- a/javascript/0007-reverse-integer.js +++ b/javascript/0007-reverse-integer.js @@ -4,27 +4,27 @@ * @param {number} x * @return {number} */ -var reverse = function(x, result = 0) { +var reverse = function (x, result = 0) { while (x !== 0) { - const digit = (x % 10) + const digit = x % 10; if (isOutOfBounds(digit, result)) return 0; x = Math.trunc(x / 10); - result = (result * 10) + digit; + result = result * 10 + digit; } return result; }; const isOutOfBounds = (digit, result) => { - const [ max, min ] = [ ((2 ** 31) - 1), (-(2 ** 31)) ]; - const [ maxProduct, maxRemainder ] = [ (max / 10), (max % 10) ]; - const [ minProduct, minRemainder ] = [ (min / 10), (min % 10) ]; + const [max, min] = [2 ** 31 - 1, -(2 ** 31)]; + const [maxProduct, maxRemainder] = [max / 10, max % 10]; + const [minProduct, minRemainder] = [min / 10, min % 10]; const isTarget = result === maxProduct; - const isMaxOut = ((maxProduct < result) || (isTarget && (maxRemainder <= digit))); - const isMinOut = ((result < minProduct) || (isTarget && (digit <= minRemainder))); + const isMaxOut = maxProduct < result || (isTarget && maxRemainder <= digit); + const isMinOut = result < minProduct || (isTarget && digit <= minRemainder); return isMaxOut || isMinOut; -} +}; diff --git a/javascript/0009-palindrome-number.js b/javascript/0009-palindrome-number.js index 9312c1033..a53ac2113 100644 --- a/javascript/0009-palindrome-number.js +++ b/javascript/0009-palindrome-number.js @@ -27,7 +27,7 @@ var isPalindrome = function (x) { * @param {number} x * @return {boolean} */ - var isPalindrome = function(x) { +var isPalindrome = function (x) { if (x < 0) return false; const inputX = x; @@ -37,7 +37,7 @@ var isPalindrome = function (x) { revX += x % 10; x = Math.floor(x / 10); - if (x > 0) revX *= 10 + if (x > 0) revX *= 10; } return revX === inputX; diff --git a/javascript/0010-regular-expression-matching.js b/javascript/0010-regular-expression-matching.js index 81a21f2c9..a93f05c2d 100644 --- a/javascript/0010-regular-expression-matching.js +++ b/javascript/0010-regular-expression-matching.js @@ -7,17 +7,18 @@ * @return {boolean} */ var isMatch = (text, pattern) => { - const isBaseCase = (pattern.length === 0); - if (isBaseCase) return (text.length === 0); - - const isTextAndPatternEqual = (pattern[0] === text[0]), - isPatternPeriod = (pattern[0] === '.'), - isFirstMatch = (text && (isTextAndPatternEqual || isPatternPeriod)), - isNextPatternWildCard = (pattern.length >= 2 && pattern[1] === '*'); - - return isNextPatternWildCard/* Time O((N + M) * 2^(N + (M / 2))) | Space O(N^2 + M^2) */ - ? (isMatch(text, pattern.slice(2)) || (isFirstMatch && isMatch(text.slice(1), pattern))) - : (isFirstMatch && isMatch(text.slice(1), pattern.slice(1))); + const isBaseCase = pattern.length === 0; + if (isBaseCase) return text.length === 0; + + const isTextAndPatternEqual = pattern[0] === text[0], + isPatternPeriod = pattern[0] === '.', + isFirstMatch = text && (isTextAndPatternEqual || isPatternPeriod), + isNextPatternWildCard = pattern.length >= 2 && pattern[1] === '*'; + + return isNextPatternWildCard /* Time O((N + M) * 2^(N + (M / 2))) | Space O(N^2 + M^2) */ + ? isMatch(text, pattern.slice(2)) || + (isFirstMatch && isMatch(text.slice(1), pattern)) + : isFirstMatch && isMatch(text.slice(1), pattern.slice(1)); }; /** @@ -29,33 +30,52 @@ var isMatch = (text, pattern) => { * @param {string} p * @return {boolean} */ -var isMatch = (text, pattern, row = 0, col = 0, memo = initMemo(text, pattern)) => { - const hasSeen = (memo[row][col]); +var isMatch = ( + text, + pattern, + row = 0, + col = 0, + memo = initMemo(text, pattern), +) => { + const hasSeen = memo[row][col]; if (hasSeen) return memo[row][col]; - const isEqual = (col === pattern.length); + const isEqual = col === pattern.length; const ans = isEqual ? row === text.length - : check(text, pattern, row, col, memo);/* Time O(N * M) | Space O(N * M) */ + : check( + text, + pattern, + row, + col, + memo, + ); /* Time O(N * M) | Space O(N * M) */ memo[row][col] = ans; return ans; -} +}; -var initMemo = (text, pattern) => new Array((text.length + 1)).fill()/* Time O(N) | Space O(N) */ - .map(() => new Array((pattern.length + 1)).fill(false)) /* Time O(M) | Space O(M) */ +var initMemo = (text, pattern) => + new Array(text.length + 1) + .fill() /* Time O(N) | Space O(N) */ + .map(() => + new Array(pattern.length + 1).fill(false), + ); /* Time O(M) | Space O(M) */ var check = (text, pattern, row, col, memo) => { - const isTextDefined = (row < text.length), - isTextAndPatternEqual = (pattern[col] === text[row]), - isPatternPeriod = (pattern[col] === '.'), - isFirstMatch = (isTextDefined && (isTextAndPatternEqual || isPatternPeriod)), - isNextPatternWildCard = (((col + 1) < pattern.length) && pattern[col + 1] === '*'); - - return isNextPatternWildCard/* Time O(N * M) | Space O(N * M) */ - ? (isMatch(text, pattern, row, (col + 2), memo) || isFirstMatch && isMatch(text, pattern, (row + 1), col, memo)) - : (isFirstMatch && isMatch(text, pattern, (row + 1), (col + 1), memo)); -} + const isTextDefined = row < text.length, + isTextAndPatternEqual = pattern[col] === text[row], + isPatternPeriod = pattern[col] === '.', + isFirstMatch = + isTextDefined && (isTextAndPatternEqual || isPatternPeriod), + isNextPatternWildCard = + col + 1 < pattern.length && pattern[col + 1] === '*'; + + return isNextPatternWildCard /* Time O(N * M) | Space O(N * M) */ + ? isMatch(text, pattern, row, col + 2, memo) || + (isFirstMatch && isMatch(text, pattern, row + 1, col, memo)) + : isFirstMatch && isMatch(text, pattern, row + 1, col + 1, memo); +}; /** * Time O(N * M) | Space O(N * M) @@ -64,35 +84,41 @@ var check = (text, pattern, row, col, memo) => { * @return {boolean} */ var isMatch = (text, pattern) => { - const tabu = initTabu(text, pattern);/* Time O(N * M) | Space O(N * M) */ + const tabu = initTabu(text, pattern); /* Time O(N * M) | Space O(N * M) */ - search(text, pattern, tabu); /* Time O(N * M) | Space O(N * M) */ + search(text, pattern, tabu); /* Time O(N * M) | Space O(N * M) */ return tabu[0][0]; - -} +}; var initTabu = (text, pattern) => { - const tabu = new Array((text.length + 1)).fill() /* Time O(N) | Space O(N) */ - .map(() => new Array((pattern.length + 1)).fill(false));/* Time O(M) | Space O(M) */ + const tabu = new Array(text.length + 1) + .fill() /* Time O(N) | Space O(N) */ + .map(() => + new Array(pattern.length + 1).fill(false), + ); /* Time O(M) | Space O(M) */ - tabu[text.length][pattern.length] = true; /* | Space O(N * M) */ + tabu[text.length][pattern.length] = true; /* | Space O(N * M) */ - return tabu -} + return tabu; +}; var search = (text, pattern, tabu) => { - for (let row = text.length; 0 <= row; row--){ /* Time O(N) */ - for (let col = (pattern.length - 1); (0 <= col); col--){/* Time O(M) */ + for (let row = text.length; 0 <= row; row--) { + /* Time O(N) */ + for (let col = pattern.length - 1; 0 <= col; col--) { + /* Time O(M) */ const isTextDefined = row < text.length, isTextAndPatternEqual = pattern[col] === text[row], isPatternPeriod = pattern[col] === '.', - isFirstMatch = isTextDefined && (isTextAndPatternEqual || isPatternPeriod), - isNextPatternWildCard = col + 1 < pattern.length && pattern[col + 1] === '*'; + isFirstMatch = + isTextDefined && (isTextAndPatternEqual || isPatternPeriod), + isNextPatternWildCard = + col + 1 < pattern.length && pattern[col + 1] === '*'; - tabu[row][col] = isNextPatternWildCard /* Space O(N * M) */ + tabu[row][col] = isNextPatternWildCard /* Space O(N * M) */ ? tabu[row][col + 2] || (isFirstMatch && tabu[row + 1][col]) : isFirstMatch && tabu[row + 1][col + 1]; } } -} \ No newline at end of file +}; diff --git a/javascript/0012-integer-to-roman.js b/javascript/0012-integer-to-roman.js index 8f79ee3d2..503d864e6 100644 --- a/javascript/0012-integer-to-roman.js +++ b/javascript/0012-integer-to-roman.js @@ -4,80 +4,79 @@ * @return {string} */ -var intToRoman = function(num) { - let ans = ""; - - while(num !== 0){ +var intToRoman = function (num) { + let ans = ''; + while (num !== 0) { //M == 1000 - if(num >= 1000){ + if (num >= 1000) { num -= 1000; - ans += "M"; + ans += 'M'; } //CM == 900 - else if(num >= 900){ + else if (num >= 900) { num -= 900; - ans += "CM"; + ans += 'CM'; } //D == 500 - else if(num >= 500){ + else if (num >= 500) { num -= 500; - ans += "D"; + ans += 'D'; } //CD == 400 - else if(num >= 400){ + else if (num >= 400) { num -= 400; - ans += "CD" + ans += 'CD'; } //C == 100 - else if(num >= 100){ + else if (num >= 100) { num -= 100; - ans += "C"; + ans += 'C'; } //XC == 90 - else if(num >= 90){ + else if (num >= 90) { num -= 90; - ans += "XC"; + ans += 'XC'; } //L == 50; - else if(num >= 50){ + else if (num >= 50) { num -= 50; - ans += "L"; + ans += 'L'; } //XL == 40 - else if(num >= 40){ + else if (num >= 40) { num -= 40; - ans += "XL"; + ans += 'XL'; } //X == 10 - else if(num >= 10){ + else if (num >= 10) { num -= 10; - ans += "X"; + ans += 'X'; } //IX == 9 - else if(num >= 9){ + else if (num >= 9) { num -= 9; - ans += "IX"; + ans += 'IX'; } //V == 5 - else if(num >= 5){ + else if (num >= 5) { num -= 5; - ans += "V"; + ans += 'V'; } //IV == 4 - else if(num >= 4){ + else if (num >= 4) { num -= 4; - ans += "IV"; + ans += 'IV'; } //II == 2 - else if(num >= 2){ + else if (num >= 2) { num -= 2; - ans += "II"; + ans += 'II'; } //I == 1 - else{ + else { num -= 1; - ans += "I"; + ans += 'I'; } } return ans; diff --git a/javascript/0013-roman-to-integer.js b/javascript/0013-roman-to-integer.js index f6bd00410..0490953ae 100644 --- a/javascript/0013-roman-to-integer.js +++ b/javascript/0013-roman-to-integer.js @@ -65,29 +65,29 @@ var romanToInt = function (s) { // Memory Usage: 47.5 MB, less than 18.15% of JavaScript online submissions for Roman to Integer. function romanToInt(s) { - let sum = 0 - let next = null + let sum = 0; + let next = null; const romanArr = { - "I": 1, - "V": 5, - "X": 10, - "L": 50, - "C": 100, - "D": 500, - "M": 1000 - } - for (let i = 0; i < s.length; i++ ) { - next = s[i + 1] || null - const curr = s[i] + I: 1, + V: 5, + X: 10, + L: 50, + C: 100, + D: 500, + M: 1000, + }; + for (let i = 0; i < s.length; i++) { + next = s[i + 1] || null; + const curr = s[i]; if (romanArr[next] > romanArr[curr]) { - sum -= romanArr[curr] - continue + sum -= romanArr[curr]; + continue; } - sum += romanArr[curr] + sum += romanArr[curr]; } - return sum -}; + return sum; +} // Runtime 97 ms // Memory usage: 47.8 MB -// https://leetcode.com/problems/roman-to-integer/submissions/1020204566/ \ No newline at end of file +// https://leetcode.com/problems/roman-to-integer/submissions/1020204566/ diff --git a/javascript/0014-longest-common-prefix.js b/javascript/0014-longest-common-prefix.js index 783c06261..e31d59255 100644 --- a/javascript/0014-longest-common-prefix.js +++ b/javascript/0014-longest-common-prefix.js @@ -3,19 +3,16 @@ * @param {string[]} strs * @return {string} */ -var longestCommonPrefix = function(strs) { - +var longestCommonPrefix = function (strs) { let pre = strs[0]; - - for(let word of strs) { - - for(let i = pre.length - 1; i >= 0; i--) { - - if(pre[i] !== word[i]) { + + for (let word of strs) { + for (let i = pre.length - 1; i >= 0; i--) { + if (pre[i] !== word[i]) { pre = pre.slice(0, i); } } } - + return pre; }; diff --git a/javascript/0015-3sum.js b/javascript/0015-3sum.js index 1f099451a..680920659 100644 --- a/javascript/0015-3sum.js +++ b/javascript/0015-3sum.js @@ -2,9 +2,9 @@ * @param {number[]} nums * @return {number[][]} */ -var threeSum = function(nums) { +var threeSum = function (nums) { const res = []; - nums.sort((a,b) => a-b) + nums.sort((a, b) => a - b); for (let i = 0; i < nums.length; i++) { const a = nums[i]; @@ -30,5 +30,4 @@ var threeSum = function(nums) { } } return res; -} - +}; diff --git a/javascript/0017-letter-combinations-of-a-phone-number.js b/javascript/0017-letter-combinations-of-a-phone-number.js index 3aaa12557..44159caeb 100644 --- a/javascript/0017-letter-combinations-of-a-phone-number.js +++ b/javascript/0017-letter-combinations-of-a-phone-number.js @@ -1,39 +1,43 @@ -/** - * https://leetcode.com/problems/letter-combinations-of-a-phone-number/ - * Time O(N * 4^N) | Space O(N) - * @param {string} digits - * @return {string[]} - */ - var letterCombinations = function(digits, combination = [], combinations = []) { - const isBaseCase = !digits - if (isBaseCase) { - if (combination.length) combinations.push(combination.join('')) - - return combinations; - } - - const letters = phoneButtons[ digits[0] ]; - - for (const char of letters) { - backTrack(digits, char, combination, combinations); - } - - return combinations; -}; - -const backTrack = (digits, char, combination, combinations) => { - combination.push(char) - letterCombinations(digits.slice(1), combination, combinations) - combination.pop() -} - -const phoneButtons = ({ - 2: ['a', 'b', 'c'], - 3: ['d', 'e', 'f'], - 4: ['g', 'h', 'i'], - 5: ['j', 'k', 'l'], - 6: ['m', 'n', 'o'], - 7: ['p', 'q', 'r', 's'], - 8: ['t', 'u', 'v'], - 9: ['w', 'x', 'y', 'z'], -}) +/** + * https://leetcode.com/problems/letter-combinations-of-a-phone-number/ + * Time O(N * 4^N) | Space O(N) + * @param {string} digits + * @return {string[]} + */ +var letterCombinations = function ( + digits, + combination = [], + combinations = [], +) { + const isBaseCase = !digits; + if (isBaseCase) { + if (combination.length) combinations.push(combination.join('')); + + return combinations; + } + + const letters = phoneButtons[digits[0]]; + + for (const char of letters) { + backTrack(digits, char, combination, combinations); + } + + return combinations; +}; + +const backTrack = (digits, char, combination, combinations) => { + combination.push(char); + letterCombinations(digits.slice(1), combination, combinations); + combination.pop(); +}; + +const phoneButtons = { + 2: ['a', 'b', 'c'], + 3: ['d', 'e', 'f'], + 4: ['g', 'h', 'i'], + 5: ['j', 'k', 'l'], + 6: ['m', 'n', 'o'], + 7: ['p', 'q', 'r', 's'], + 8: ['t', 'u', 'v'], + 9: ['w', 'x', 'y', 'z'], +}; diff --git a/javascript/0018-4sum.js b/javascript/0018-4sum.js index fe342ed84..085350aa6 100644 --- a/javascript/0018-4sum.js +++ b/javascript/0018-4sum.js @@ -30,7 +30,7 @@ var fourSum = function (nums, target) { right--; } else { res.push( - quad.concat([sortedNums[left], sortedNums[right]]) + quad.concat([sortedNums[left], sortedNums[right]]), ); left++; while ( diff --git a/javascript/0019-remove-nth-node-from-end-of-list.js b/javascript/0019-remove-nth-node-from-end-of-list.js index 082779863..de5518cc4 100644 --- a/javascript/0019-remove-nth-node-from-end-of-list.js +++ b/javascript/0019-remove-nth-node-from-end-of-list.js @@ -5,13 +5,13 @@ * @param {number} n * @return {ListNode} */ - var removeNthFromEnd = function(head, n) { +var removeNthFromEnd = function (head, n) { const sentinel = new ListNode(); sentinel.next = head; - const fast = moveFast(sentinel, n); /* Time O(N) */ - const slow = moveSlow(sentinel, fast);/* Time O(N) */ + const fast = moveFast(sentinel, n); /* Time O(N) */ + const slow = moveSlow(sentinel, fast); /* Time O(N) */ slow.next = slow.next.next || null; @@ -19,21 +19,23 @@ }; const moveFast = (fast, n) => { - for (let i = 1; i <= (n + 1); i++) {/* Time O(N) */ + for (let i = 1; i <= n + 1; i++) { + /* Time O(N) */ fast = fast.next; } return fast; -} +}; const moveSlow = (slow, fast) => { - while (fast) { /* Time O(N) */ + while (fast) { + /* Time O(N) */ slow = slow.next; fast = fast.next; } return slow; -} +}; /** * https://leetcode.com/problems/remove-nth-node-from-end-of-list/ @@ -42,33 +44,35 @@ const moveSlow = (slow, fast) => { * @param {number} n * @return {ListNode} */ - var removeNthFromEnd = function(head, n) { - const length = getNthFromEnd(head, n);/* Time O(N) */ +var removeNthFromEnd = function (head, n) { + const length = getNthFromEnd(head, n); /* Time O(N) */ const isHead = length < 0; if (isHead) return head.next; - const curr = moveNode(head, length); /* Time O(N) */ + const curr = moveNode(head, length); /* Time O(N) */ curr.next = curr.next.next; - return head + return head; }; const getNthFromEnd = (curr, n, length = 0) => { - while (curr) { /* Time O(N) */ + while (curr) { + /* Time O(N) */ curr = curr.next; length++; } - return (length - n) - 1; -} + return length - n - 1; +}; const moveNode = (curr, length) => { - while (length) { /* Time O(N) */ + while (length) { + /* Time O(N) */ curr = curr.next; length--; } return curr; -} +}; diff --git a/javascript/0020-valid-parentheses.js b/javascript/0020-valid-parentheses.js index c262edd16..e064db845 100644 --- a/javascript/0020-valid-parentheses.js +++ b/javascript/0020-valid-parentheses.js @@ -4,16 +4,17 @@ * @param {string} s * @return {boolean} */ - var isValid = (s, stack = []) => { - for (const bracket of s.split('')) {/* Time O(N) */ +var isValid = (s, stack = []) => { + for (const bracket of s.split('')) { + /* Time O(N) */ const isParenthesis = bracket === '('; - if (isParenthesis) stack.push(')'); /* Space O(N) */ + if (isParenthesis) stack.push(')'); /* Space O(N) */ const isCurlyBrace = bracket === '{'; - if (isCurlyBrace) stack.push('}'); /* Space O(N) */ + if (isCurlyBrace) stack.push('}'); /* Space O(N) */ const isSquareBracket = bracket === '['; - if (isSquareBracket) stack.push(']');/* Space O(N) */ + if (isSquareBracket) stack.push(']'); /* Space O(N) */ const isOpenPair = isParenthesis || isCurlyBrace || isSquareBracket; if (isOpenPair) continue; @@ -24,7 +25,7 @@ if (isInvalid) return false; } - return (stack.length === 0); + return stack.length === 0; }; /** @@ -39,16 +40,23 @@ var isValid = (s, stack = []) => { ']': '[', ')': '(', }; - - for (const char of s) {/* Time O(N) */ - const isBracket = (char in map) - if (!isBracket) { stack.push(char); continue; }/* Space O(N) */ - const isEqual = (stack[stack.length - 1] === map[char]) - if (isEqual) { stack.pop(); continue; } + for (const char of s) { + /* Time O(N) */ + const isBracket = char in map; + if (!isBracket) { + stack.push(char); + continue; + } /* Space O(N) */ + + const isEqual = stack[stack.length - 1] === map[char]; + if (isEqual) { + stack.pop(); + continue; + } return false; } - return (stack.length === 0); + return stack.length === 0; }; diff --git a/javascript/0021-merge-two-sorted-lists.js b/javascript/0021-merge-two-sorted-lists.js index ede603e51..6f9f04dcf 100644 --- a/javascript/0021-merge-two-sorted-lists.js +++ b/javascript/0021-merge-two-sorted-lists.js @@ -5,7 +5,7 @@ * @param {ListNode} list2 * @return {ListNode} */ - var mergeTwoLists = function(list1, list2) { +var mergeTwoLists = function (list1, list2) { const isBaseCase1 = list1 === null; if (isBaseCase1) return list2; @@ -14,18 +14,24 @@ const isL2Greater = list1.val <= list2.val; if (isL2Greater) { - list1.next = mergeTwoLists(list1.next, list2);/* Time O(N + M) | Space O(N + M) */ + list1.next = mergeTwoLists( + list1.next, + list2, + ); /* Time O(N + M) | Space O(N + M) */ return list1; } const isL2Less = list2.val <= list1.val; if (isL2Less) { - list2.next = mergeTwoLists(list1, list2.next);/* Time O(N + M) | Space O(N + M) */ + list2.next = mergeTwoLists( + list1, + list2.next, + ); /* Time O(N + M) | Space O(N + M) */ return list2; } -} +}; /** * https://leetcode.com/problems/merge-two-sorted-lists/ @@ -34,10 +40,11 @@ * @param {ListNode} list2 * @return {ListNode} */ -var mergeTwoLists = function(list1, list2) { - let sentinel = tail = new ListNode(); +var mergeTwoLists = function (list1, list2) { + let sentinel = (tail = new ListNode()); - while (list1 && list2) {/* Time O(N + M) */ + while (list1 && list2) { + /* Time O(N + M) */ const isL2Greater = list1.val <= list2.val; if (isL2Greater) { @@ -54,4 +61,4 @@ var mergeTwoLists = function(list1, list2) { tail.next = list1 || list2; return sentinel.next; -}; \ No newline at end of file +}; diff --git a/javascript/0022-generate-parentheses.js b/javascript/0022-generate-parentheses.js index 436d607b7..3ad89766f 100644 --- a/javascript/0022-generate-parentheses.js +++ b/javascript/0022-generate-parentheses.js @@ -1,98 +1,115 @@ -/** - * DFS - * Time O(((4^N) / (N * SQRT(N)))) | Space O(((4^N) / (N * SQRT(N)))) - * Time O(2^N) | Space O(2^N) - * https://leetcode.com/problems/generate-parentheses - * @param {number} n - * @return {string[]} - */ -var generateParenthesis = (n) => dfs(n); - -const dfs = (n, combos = [], open = 0, close = 0, path = []) => { - const isBaseCase = (path.length === (n * 2)); - if (isBaseCase) { - combos.push(path.join(''));/* Space O(N + N) */ - - return combos; - } - - const isOpen = open < n; - if (isOpen) backTrackOpen(n, combos, open, close, path); /* Time O(2^N) | Space O(2^N) */ - - const isClose = close < open; - if (isClose) backTrackClose(n, combos, open, close, path);/* Time O(2^N) | Space O(2^N) */ - - return combos; -} - -const backTrackOpen = (n, combos, open, close, path) => { - path.push('(');/* Space O(N) */ - dfs(n, combos, (open + 1), close, path);/* Time O(2^N) | Space O(2^N) */ - path.pop(); -} - -const backTrackClose = (n, combos, open, close, path) => { - path.push(')');/* Space O(N) */ - dfs(n, combos, open, (close + 1), path);/* Time O(2^N) | Space O(2^N) */ - path.pop(); -} - -/** - * BFS - * Time O(((4^N) / (N * SQRT(N)))) | Space O(((4^N) / (N * SQRT(N)))) - * Time O(2^N) | Space O(2^N) - * https://leetcode.com/problems/generate-parentheses - * @param {number} n - * @return {string[]} - */ -var generateParenthesis = (n) => bfs(n); - -const bfs = (n, combos = []) => { - const queue = new Queue([ ['', 0, 0] ]); - - while (!queue.isEmpty()) {/* Time O(2^N) */ - const [ str, open, close ] = queue.dequeue(); - - const isBaseCase = ((open === n) && (close === n)); - if (isBaseCase) { - combos.push(str); /* Space O(N) */ - - continue; - } - - const isOpen = open < n; - if (isOpen) queue.enqueue([ (`${str}(`), (open + 1), close ]); /* Space O(2^N) */ - - const isClose = close < open; - if (isClose) queue.enqueue([ (`${str})`), open, (close + 1) ]);/* Space O(2^N) */ - } - - return combos; -} - -/** - * DFS - * Time O(((4^N) / (N * SQRT(N)))) | Space O(((4^N) / (N * SQRT(N)))) - * Time O(2^N) | Space O(2^N) - * https://leetcode.com/problems/generate-parentheses - * @param {number} n - * @return {string[]} - */ -var generateParenthesis = (n, combos = []) => { - const isBaseCase = (n === 0); - if (isBaseCase) { - combos.push(''); - - return combos - } - - for (let c = 0; (c < n); c++) { - for (const left of generateParenthesis(c)) { - for (const right of generateParenthesis(((n - 1) - c))) { - combos.push(`(${left})${right}`); - } - } - } - - return combos -} +/** + * DFS + * Time O(((4^N) / (N * SQRT(N)))) | Space O(((4^N) / (N * SQRT(N)))) + * Time O(2^N) | Space O(2^N) + * https://leetcode.com/problems/generate-parentheses + * @param {number} n + * @return {string[]} + */ +var generateParenthesis = (n) => dfs(n); + +const dfs = (n, combos = [], open = 0, close = 0, path = []) => { + const isBaseCase = path.length === n * 2; + if (isBaseCase) { + combos.push(path.join('')); /* Space O(N + N) */ + + return combos; + } + + const isOpen = open < n; + if (isOpen) + backTrackOpen( + n, + combos, + open, + close, + path, + ); /* Time O(2^N) | Space O(2^N) */ + + const isClose = close < open; + if (isClose) + backTrackClose( + n, + combos, + open, + close, + path, + ); /* Time O(2^N) | Space O(2^N) */ + + return combos; +}; + +const backTrackOpen = (n, combos, open, close, path) => { + path.push('('); /* Space O(N) */ + dfs(n, combos, open + 1, close, path); /* Time O(2^N) | Space O(2^N) */ + path.pop(); +}; + +const backTrackClose = (n, combos, open, close, path) => { + path.push(')'); /* Space O(N) */ + dfs(n, combos, open, close + 1, path); /* Time O(2^N) | Space O(2^N) */ + path.pop(); +}; + +/** + * BFS + * Time O(((4^N) / (N * SQRT(N)))) | Space O(((4^N) / (N * SQRT(N)))) + * Time O(2^N) | Space O(2^N) + * https://leetcode.com/problems/generate-parentheses + * @param {number} n + * @return {string[]} + */ +var generateParenthesis = (n) => bfs(n); + +const bfs = (n, combos = []) => { + const queue = new Queue([['', 0, 0]]); + + while (!queue.isEmpty()) { + /* Time O(2^N) */ + const [str, open, close] = queue.dequeue(); + + const isBaseCase = open === n && close === n; + if (isBaseCase) { + combos.push(str); /* Space O(N) */ + + continue; + } + + const isOpen = open < n; + if (isOpen) + queue.enqueue([`${str}(`, open + 1, close]); /* Space O(2^N) */ + + const isClose = close < open; + if (isClose) + queue.enqueue([`${str})`, open, close + 1]); /* Space O(2^N) */ + } + + return combos; +}; + +/** + * DFS + * Time O(((4^N) / (N * SQRT(N)))) | Space O(((4^N) / (N * SQRT(N)))) + * Time O(2^N) | Space O(2^N) + * https://leetcode.com/problems/generate-parentheses + * @param {number} n + * @return {string[]} + */ +var generateParenthesis = (n, combos = []) => { + const isBaseCase = n === 0; + if (isBaseCase) { + combos.push(''); + + return combos; + } + + for (let c = 0; c < n; c++) { + for (const left of generateParenthesis(c)) { + for (const right of generateParenthesis(n - 1 - c)) { + combos.push(`(${left})${right}`); + } + } + } + + return combos; +}; diff --git a/javascript/0023-merge-k-sorted-lists.js b/javascript/0023-merge-k-sorted-lists.js index b84454b1e..3ed4f8f0d 100644 --- a/javascript/0023-merge-k-sorted-lists.js +++ b/javascript/0023-merge-k-sorted-lists.js @@ -4,7 +4,7 @@ * @param {ListNode[]} lists * @return {ListNode} */ - var mergeKLists = function(lists) { +var mergeKLists = function (lists) { let previous = null; for (let i = 0; i < lists.length; i++) { @@ -14,8 +14,8 @@ return previous; }; -var mergeTwoLists = function(list1, list2) { - let sentinel = tail = new ListNode(0); +var mergeTwoLists = function (list1, list2) { + let sentinel = (tail = new ListNode(0)); while (list1 && list2) { const canAddL1 = list1.val <= list2.val; @@ -41,10 +41,10 @@ var mergeTwoLists = function(list1, list2) { * @param {ListNode[]} lists * @return {ListNode} */ - var mergeKLists = function(lists) { +var mergeKLists = function (lists) { const minHeap = getMinHeap(lists); - return mergeLists(minHeap) + return mergeLists(minHeap); }; const getMinHeap = (lists) => { @@ -57,11 +57,10 @@ const getMinHeap = (lists) => { } return heap; -} - +}; const mergeLists = (minHeap) => { - let sentinel = tail = new ListNode(); + let sentinel = (tail = new ListNode()); while (!minHeap.isEmpty()) { const node = minHeap.dequeue().element; @@ -75,4 +74,4 @@ const mergeLists = (minHeap) => { } return sentinel.next; -} +}; diff --git a/javascript/0025-reverse-nodes-in-k-group.js b/javascript/0025-reverse-nodes-in-k-group.js index 26504326c..24f9b8882 100644 --- a/javascript/0025-reverse-nodes-in-k-group.js +++ b/javascript/0025-reverse-nodes-in-k-group.js @@ -5,14 +5,14 @@ * @param {number} k * @return {ListNode} */ - var reverseKGroup = function(head, k) { - const sentinel = tail = new ListNode(0, head); +var reverseKGroup = function (head, k) { + const sentinel = (tail = new ListNode(0, head)); while (true) { - let [ start, last ]= moveNode(tail, k); + let [start, last] = moveNode(tail, k); if (!last) break; - reverse([ start, tail.next, start ]) + reverse([start, tail.next, start]); const next = tail.next; tail.next = last; @@ -29,10 +29,10 @@ const moveNode = (curr, k) => { k--; } - return [ (curr?.next || null), curr ]; -} + return [curr?.next || null, curr]; +}; -const reverse = ([ prev, curr, start ]) => { +const reverse = ([prev, curr, start]) => { const isSame = () => curr === start; while (!isSame()) { const next = curr.next; @@ -41,4 +41,4 @@ const reverse = ([ prev, curr, start ]) => { prev = curr; curr = next; } -} +}; diff --git a/javascript/0026-remove-duplicates-from-sorted-array.js b/javascript/0026-remove-duplicates-from-sorted-array.js index cc4ae0995..7f103276c 100644 --- a/javascript/0026-remove-duplicates-from-sorted-array.js +++ b/javascript/0026-remove-duplicates-from-sorted-array.js @@ -6,13 +6,13 @@ * @return {number} */ var removeDuplicates = function (nums) { - let swap = 1; + let swap = 1; - for (let i = 1; i < nums.length; i++) { - if (nums[i] != nums[i - 1]) { - nums[swap] = nums[i]; - swap++; + for (let i = 1; i < nums.length; i++) { + if (nums[i] != nums[i - 1]) { + nums[swap] = nums[i]; + swap++; + } } - } - return swap; + return swap; }; diff --git a/javascript/0027-remove-element.js b/javascript/0027-remove-element.js index 236c11b7a..4a8256abf 100644 --- a/javascript/0027-remove-element.js +++ b/javascript/0027-remove-element.js @@ -4,52 +4,49 @@ * @param {number} val * @return {number} */ -var removeElement = function(nums, val) { +var removeElement = function (nums, val) { let ptr1 = nums.length - 2; let ptr2 = nums.length - 1; - - if(!nums) return 0; - if(nums.length === 1) { - if(nums[0] === val) return 0; + + if (!nums) return 0; + if (nums.length === 1) { + if (nums[0] === val) return 0; return 1; } - - while(ptr1 > -1) { - if(nums[ptr2] === val) { + + while (ptr1 > -1) { + if (nums[ptr2] === val) { ptr2--; - - while(nums[ptr1] === val) { + + while (nums[ptr1] === val) { ptr2--; ptr1--; - } - } - else if(nums[ptr1] === val) { + } + } else if (nums[ptr1] === val) { let temp = nums[ptr1]; nums[ptr1] = nums[ptr2]; nums[ptr2] = temp; ptr2--; - } ptr1--; } - + return ptr2 + 1; }; - /** * @param {number[]} nums * @param {number} val * @return {number} */ -var removeElement = function(nums, val) { - for(let i = 0; i < nums.length; i++) { - if(nums[i] === val) { +var removeElement = function (nums, val) { + for (let i = 0; i < nums.length; i++) { + if (nums[i] === val) { nums.splice(i, 1); - i--; + i--; } } - + return nums.length; }; diff --git a/javascript/0028-find-the-index-of-the-first-occurrence-in-a-string.js b/javascript/0028-find-the-index-of-the-first-occurrence-in-a-string.js index b1bd50934..9d019eb9a 100644 --- a/javascript/0028-find-the-index-of-the-first-occurrence-in-a-string.js +++ b/javascript/0028-find-the-index-of-the-first-occurrence-in-a-string.js @@ -1,5 +1,5 @@ /** - * Submission Details: + * Submission Details: * https://leetcode.com/problems/find-the-index-of-the-first-occurrence-in-a-string/ * Time O(n * m), Space O(1) * Runtime: 48ms (beats 91.92%) || 41.6mb (beats 78.25%) @@ -10,14 +10,15 @@ * @param {string} needle * @return {number} */ -var strStr = function(haystack, needle) { +var strStr = function (haystack, needle) { if (needle.length == 0) return 0; for (let i = 0; i < haystack.length; i++) { - let k = i, j = 0; + let k = i, + j = 0; while (haystack[k] == needle[j] && j < needle.length) { - k++, j++; + (k++, j++); } if (j == needle.length) return i; } - return -1; -} \ No newline at end of file + return -1; +}; diff --git a/javascript/0034-find-first-and-last-position-of-element-in-sorted-array.js b/javascript/0034-find-first-and-last-position-of-element-in-sorted-array.js index c11490e11..fbee52dbe 100644 --- a/javascript/0034-find-first-and-last-position-of-element-in-sorted-array.js +++ b/javascript/0034-find-first-and-last-position-of-element-in-sorted-array.js @@ -6,8 +6,7 @@ * @param {number} target * @return {number[]} */ -var searchRange = function(nums, target) { - +var searchRange = function (nums, target) { const result = []; result.push(binarySearch(true, nums, target)); @@ -17,31 +16,30 @@ var searchRange = function(nums, target) { }; var binarySearch = (isLeftBias, nums, target) => { - let left = 0; - let right = nums.length - 1; - let index = -1; + let left = 0; + let right = nums.length - 1; + let index = -1; - while(left <= right) { - + while (left <= right) { const mid = (left + right) >> 1; - if(target > nums[mid]) { - left = mid+1; + if (target > nums[mid]) { + left = mid + 1; } - if(target < nums[mid]) { - right = mid-1; + if (target < nums[mid]) { + right = mid - 1; } - + const isTarget = target === nums[mid]; - if(isTarget) { - if(isLeftBias) { - index = mid; - right = mid - 1; - } else { - index = mid; - left = mid + 1; - } + if (isTarget) { + if (isLeftBias) { + index = mid; + right = mid - 1; + } else { + index = mid; + left = mid + 1; + } } - } - return index; -} + } + return index; +}; diff --git a/javascript/0036-valid-sudoku.js b/javascript/0036-valid-sudoku.js index dd1256860..8b550066e 100644 --- a/javascript/0036-valid-sudoku.js +++ b/javascript/0036-valid-sudoku.js @@ -6,7 +6,7 @@ * @return {boolean} */ - var isValidSudoku = function (board) { +var isValidSudoku = function (board) { let row = []; let col = []; let squares = new Map(); @@ -20,7 +20,7 @@ squares.set(`${Math.floor(i / 3)}:${Math.floor(j / 3)}`, new Set()); } } - + for (let i = 0; i < 9; i++) { for (let j = 0; j < 9; j++) { if (board[i][j] === '.') { @@ -52,45 +52,55 @@ * @param {character[][]} board * @return {boolean} */ - var isValidSudoku = (board) => { +var isValidSudoku = (board) => { const boards = 3; - const [ boxes, cols, rows ] = getBoards(boards);/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ - - return searchGrid(board, boxes, cols, rows); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ + const [boxes, cols, rows] = + getBoards(boards); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ + + return searchGrid( + board, + boxes, + cols, + rows, + ); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ }; -var initBoard = (rows, cols) => new Array(rows).fill() - .map(() => new Array(cols).fill(false)); +var initBoard = (rows, cols) => + new Array(rows).fill().map(() => new Array(cols).fill(false)); var getBoards = (boards) => { - const [ rows, cols ] = [ 9, 9 ]; + const [rows, cols] = [9, 9]; - return new Array(boards).fill() - .map(() => initBoard(rows, cols)) -} + return new Array(boards).fill().map(() => initBoard(rows, cols)); +}; var searchGrid = (board, boxes, cols, rows) => { - const [ _rows, _cols ] = [ 9, 9 ]; + const [_rows, _cols] = [9, 9]; - for (let row = 0; row < _rows; row++) {/* Time O(ROWS)*/ - for (let col = 0; col < _cols; col++) {/* Time O(COLS)*/ + for (let row = 0; row < _rows; row++) { + /* Time O(ROWS)*/ + for (let col = 0; col < _cols; col++) { + /* Time O(COLS)*/ const char = board[row][col]; - const index = (Math.floor(row / 3) * 3) + Math.floor(col / 3); + const index = Math.floor(row / 3) * 3 + Math.floor(col / 3); const isEmpty = char === '.'; if (isEmpty) continue; - const hasMoved = boxes[index][(char - 1)] || cols[col][(char - 1)] || rows[row][(char - 1)]; + const hasMoved = + boxes[index][char - 1] || + cols[col][char - 1] || + rows[row][char - 1]; if (hasMoved) return false; - rows[row][(char - 1)] = true; /* Space O(ROWS * COLS)*/ - cols[col][(char - 1)] = true; /* Space O(ROWS * COLS)*/ - boxes[index][(char - 1)] = true; /* Space O(ROWS * COLS)*/ + rows[row][char - 1] = true; /* Space O(ROWS * COLS)*/ + cols[col][char - 1] = true; /* Space O(ROWS * COLS)*/ + boxes[index][char - 1] = true; /* Space O(ROWS * COLS)*/ } } return true; -} +}; /** * Array - Fixed Size @@ -99,36 +109,49 @@ var searchGrid = (board, boxes, cols, rows) => { * @param {character[][]} board * @return {boolean} */ - var isValidSudoku = (board) => { - const [ boards, cells ] = [ 3, 9]; - const [ boxes, rows, cols ] = getBoards(boards, cells);/* Time O(ROWS * COLS) | Space O(CELLS) */ - - return searchGrid(board, boxes, rows, cols); /* Time O(ROWS * COLS) | Space O(CELLS) */ -} +var isValidSudoku = (board) => { + const [boards, cells] = [3, 9]; + const [boxes, rows, cols] = getBoards( + boards, + cells, + ); /* Time O(ROWS * COLS) | Space O(CELLS) */ + + return searchGrid( + board, + boxes, + rows, + cols, + ); /* Time O(ROWS * COLS) | Space O(CELLS) */ +}; -var getBoards = (boards, cells) => new Array(boards).fill() - .map(() => new Array(cells).fill(0)); +var getBoards = (boards, cells) => + new Array(boards).fill().map(() => new Array(cells).fill(0)); var searchGrid = (board, boxes, rows, cols) => { - const [ _rows, _cols ] = [ 9, 9 ]; + const [_rows, _cols] = [9, 9]; - for (let row = 0; row < _rows; row++) {/* Time O(ROWS)*/ - for (let col = 0; col < _cols; col++) {/* Time O(COLS)*/ + for (let row = 0; row < _rows; row++) { + /* Time O(ROWS)*/ + for (let col = 0; col < _cols; col++) { + /* Time O(COLS)*/ const char = board[row][col]; const position = 1 << (char - 1); - const index = (Math.floor(row / 3) * 3) + Math.floor(col / 3); + const index = Math.floor(row / 3) * 3 + Math.floor(col / 3); const isEmpty = char === '.'; if (isEmpty) continue; - const hasMoved = (boxes[index] & position) || (cols[col] & position) || (rows[row] & position); + const hasMoved = + boxes[index] & position || + cols[col] & position || + rows[row] & position; if (hasMoved) return false; - rows[row] |= position; /* Space O(CELLS)*/ - cols[col] |= position; /* Space O(CELLS)*/ - boxes[index] |= position; /* Space O(CELLS)*/ + rows[row] |= position; /* Space O(CELLS)*/ + cols[col] |= position; /* Space O(CELLS)*/ + boxes[index] |= position; /* Space O(CELLS)*/ } } return true; -} +}; diff --git a/javascript/0039-combination-sum.js b/javascript/0039-combination-sum.js index 4850e5c9c..185826ee7 100644 --- a/javascript/0039-combination-sum.js +++ b/javascript/0039-combination-sum.js @@ -5,7 +5,13 @@ * @param {number} target * @return {number[][]} */ - var combinationSum = function (candidates, target, index = 0, combination = [], combinations = []) { +var combinationSum = function ( + candidates, + target, + index = 0, + combination = [], + combinations = [], +) { const isBaseCase = target < 0; if (isBaseCase) return combinations; @@ -17,10 +23,16 @@ } return combinations; -} +}; const backTrack = (candidates, target, i, combination, combinations) => { combination.push(candidates[i]); - combinationSum(candidates, (target - candidates[i]), i, combination, combinations); + combinationSum( + candidates, + target - candidates[i], + i, + combination, + combinations, + ); combination.pop(); -} \ No newline at end of file +}; diff --git a/javascript/0040-combination-sum-ii.js b/javascript/0040-combination-sum-ii.js index 8002c31db..c726a9ccc 100644 --- a/javascript/0040-combination-sum-ii.js +++ b/javascript/0040-combination-sum-ii.js @@ -5,13 +5,19 @@ * @param {number} target * @return {number[][]} */ - var combinationSum2 = function(candidates, target) { - candidates.sort((a, b) => a - b) +var combinationSum2 = function (candidates, target) { + candidates.sort((a, b) => a - b); - return dfs(candidates, target) + return dfs(candidates, target); }; -const dfs = (candidates, target, index = 0, combination = [], combinations = []) => { +const dfs = ( + candidates, + target, + index = 0, + combination = [], + combinations = [], +) => { const isBaseCase = target < 0; if (isBaseCase) return combinations; @@ -19,21 +25,21 @@ const dfs = (candidates, target, index = 0, combination = [], combinations = []) if (isTarget) { if (combination.length) combinations.push(combination.slice()); - return combinations + return combinations; } for (let i = index; i < candidates.length; i++) { - const isDuplicate = (index < i) && (candidates[i - 1] === candidates[i]); + const isDuplicate = index < i && candidates[i - 1] === candidates[i]; if (isDuplicate) continue; backTrack(candidates, target, i, combination, combinations); } return combinations; -} +}; const backTrack = (candidates, target, i, combination, combinations) => { - combination.push(candidates[i]) - dfs(candidates, (target - candidates[i]), (i + 1), combination, combinations) - combination.pop() -} + combination.push(candidates[i]); + dfs(candidates, target - candidates[i], i + 1, combination, combinations); + combination.pop(); +}; diff --git a/javascript/0041-first-missing-positive.js b/javascript/0041-first-missing-positive.js index a22dc1cc8..32f38aee2 100644 --- a/javascript/0041-first-missing-positive.js +++ b/javascript/0041-first-missing-positive.js @@ -6,51 +6,47 @@ * @return {number} */ var firstMissingPositive = (nums) => { - cyclicSort(nums); + cyclicSort(nums); - return search(nums); + return search(nums); }; const cyclicSort = (nums, index = 0) => { - while (index < nums.length) { - const num = nums[index]; - const indexKey = (num - 1); - const indexNum = nums[indexKey]; - - if (canSwap(nums, num, indexNum)) { - swap(nums, index, indexKey); - continue; - } + while (index < nums.length) { + const num = nums[index]; + const indexKey = num - 1; + const indexNum = nums[indexKey]; + + if (canSwap(nums, num, indexNum)) { + swap(nums, index, indexKey); + continue; + } - index += 1; - } -} + index += 1; + } +}; const search = (nums, index = 0) => { - while (index < nums.length) { - const num = nums[index]; - const indexKey = (index + 1); + while (index < nums.length) { + const num = nums[index]; + const indexKey = index + 1; - if (!isEqual(num, indexKey)) return indexKey; + if (!isEqual(num, indexKey)) return indexKey; - index += 1; - } + index += 1; + } - return (nums.length + 1); -} + return nums.length + 1; +}; const canSwap = (nums, num, indexNum) => - isPositive(num) && - isInBound(num, nums) && - !isEqual(num, indexNum); - -const swap = (nums, index, indexKey) => - [nums[index], nums[indexKey]] = [nums[indexKey], nums[index]]; - -const isPositive = (num) => (0 < num); + isPositive(num) && isInBound(num, nums) && !isEqual(num, indexNum); -const isInBound = (num, nums) => (num <= nums.length); +const swap = (nums, index, indexKey) => + ([nums[index], nums[indexKey]] = [nums[indexKey], nums[index]]); -const isEqual = (num, indexNum) => (num === indexNum); +const isPositive = (num) => 0 < num; +const isInBound = (num, nums) => num <= nums.length; +const isEqual = (num, indexNum) => num === indexNum; diff --git a/javascript/0042-trapping-rain-water.js b/javascript/0042-trapping-rain-water.js index 299612d4c..ded4c4682 100644 --- a/javascript/0042-trapping-rain-water.js +++ b/javascript/0042-trapping-rain-water.js @@ -1,38 +1,37 @@ /** * Linear - * Time O(n) | Space O(n) + * Time O(n) | Space O(n) * https://leetcode.com/problems/trapping-rain-water * @param {number[]} height * @return {number} - * + * */ -var trap = function(height) { - +var trap = function (height) { const maxLeft = []; const maxRight = []; const minLeftRight = []; let current = 0; - for(let i = 0; i < height.length; i++) { - maxLeft.push(current); - current = Math.max(current, height[i]); + for (let i = 0; i < height.length; i++) { + maxLeft.push(current); + current = Math.max(current, height[i]); } current = 0; - for(let i = height.length - 1; i > -1; i--) { + for (let i = height.length - 1; i > -1; i--) { maxRight.push(current); current = Math.max(current, height[i]); } - // because the elements were added reverse. + // because the elements were added reverse. maxRight.reverse(); - for(let i = 0; i < height.length; i++) { - const minofLeftRight = Math.min(maxLeft[i],maxRight[i]); + for (let i = 0; i < height.length; i++) { + const minofLeftRight = Math.min(maxLeft[i], maxRight[i]); minLeftRight.push(minofLeftRight); } let water = 0; - for(let i = 0; i < height.length; i++) { - if(minLeftRight[i] - height[i] > 0) { + for (let i = 0; i < height.length; i++) { + if (minLeftRight[i] - height[i] > 0) { water += minLeftRight[i] - height[i]; } } @@ -40,7 +39,6 @@ var trap = function(height) { return water; }; - /** * https://leetcode.com/problems/trapping-rain-water/ * Time O(N) | Space O(1) @@ -58,7 +56,7 @@ var trap = function (height) { left, maxLeft, right, - maxRight + maxRight, ); const isRightGreater = leftHeight <= rightHeight; diff --git a/javascript/0043-multiply-strings.js b/javascript/0043-multiply-strings.js index 8a1e007ec..d95d17f13 100644 --- a/javascript/0043-multiply-strings.js +++ b/javascript/0043-multiply-strings.js @@ -7,58 +7,60 @@ * @return {string} */ var multiply = (num1, num2) => { - const isZero = ((num1 === '0') || (num2 === '0')); + const isZero = num1 === '0' || num2 === '0'; if (isZero) return '0'; - const buffer = initBuffer(num1, num2);/* | Space (N + M) */ + const buffer = initBuffer(num1, num2); /* | Space (N + M) */ - multiplication(num1, num2, buffer) /* Time O(N * M) */ - removeLeadingZero(buffer); /* Time O(N + M) | Time O(N + M)*/ + multiplication(num1, num2, buffer); /* Time O(N * M) */ + removeLeadingZero(buffer); /* Time O(N + M) | Time O(N + M)*/ - return buffer.join(''); /* Time O(N + M) | Space O(N + M) */ + return buffer.join(''); /* Time O(N + M) | Space O(N + M) */ }; var initBuffer = (num1, num2) => { - const size = (num1.length + num2.length); - - return new Array(size).fill(0);/* Space (N + M) */ -} + const size = num1.length + num2.length; + + return new Array(size).fill(0); /* Space (N + M) */ +}; var multiplication = (num1, num2, buffer) => { - for (let i = (num1.length - 1); (0 <= i); i--) {/* Time O(N) */ - for (let j = (num2.length - 1); (0 <= j); j--) {/* Time O(M) */ - update(num1, i, num2, j, buffer); /* Space O(N + M) */ + for (let i = num1.length - 1; 0 <= i; i--) { + /* Time O(N) */ + for (let j = num2.length - 1; 0 <= j; j--) { + /* Time O(M) */ + update(num1, i, num2, j, buffer); /* Space O(N + M) */ } } -} +}; var removeLeadingZero = (buffer) => { - const isLeadZero = (buffer[0] === 0); + const isLeadZero = buffer[0] === 0; if (!isLeadZero) return; - buffer.shift();/* Time O(N + M) | Time O(N + M) */ -} + buffer.shift(); /* Time O(N + M) | Time O(N + M) */ +}; var update = (num1, i, num2, j, buffer) => { - const curPos = (i + j); + const curPos = i + j; const prevPos = curPos + 1; const carry = buffer[prevPos]; const product = getProduct(num1, i, num2, j); - const sum = (carry + product); + const sum = carry + product; - const remainder = (sum % 10); - const value = ((sum - remainder) / 10); + const remainder = sum % 10; + const value = (sum - remainder) / 10; - buffer[prevPos] = remainder;/* Space O(N + M) */ - buffer[curPos] += value; /* Space O(N + M) */ -} + buffer[prevPos] = remainder; /* Space O(N + M) */ + buffer[curPos] += value; /* Space O(N + M) */ +}; var getProduct = (num1, i, num2, j) => { - const [ iNum, jNum ] = [ Number(num1[i]), Number(num2[j]) ]; + const [iNum, jNum] = [Number(num1[i]), Number(num2[j])]; - return (iNum * jNum); -} + return iNum * jNum; +}; /** * Matrix @@ -69,48 +71,51 @@ var getProduct = (num1, i, num2, j) => { * @return {string} */ var multiply = (num1, num2) => { - const isZero = ((num1 === '0') || (num2 === '0')); + const isZero = num1 === '0' || num2 === '0'; if (isZero) return '0'; - const buffer = initBuffer(num1, num2);/* | Space O(N + M) */ + const buffer = initBuffer(num1, num2); /* | Space O(N + M) */ - multiplication(num1, num2, buffer); /* Time O(N * M) | Space O(N + M) */ - removeLeadingZero(buffer); /* Time O(N + M) | Space O(N + M) */ + multiplication(num1, num2, buffer); /* Time O(N * M) | Space O(N + M) */ + removeLeadingZero(buffer); /* Time O(N + M) | Space O(N + M) */ - return buffer.join(''); /* Time O(N + M) | Space O(N + M) */ + return buffer.join(''); /* Time O(N + M) | Space O(N + M) */ }; -var initBuffer = (num1, num2) => new Array(num1.length + num2.length).fill(0);/* Space O(N + M) */ +var initBuffer = (num1, num2) => + new Array(num1.length + num2.length).fill(0); /* Space O(N + M) */ var multiplication = (num1, num2, buffer) => { - [ num1, num2 ] = /* Time O(N + M) */ - [ reverse(num1), reverse(num2) ]; + [num1, num2] = /* Time O(N + M) */ [reverse(num1), reverse(num2)]; - for (var i1 in num1) {/* Time O(N) */ - for (var i2 in num2) {/* Time O(M) */ - update(num1, i1, num2, i2, buffer);/* Space O(N + M) */ + for (var i1 in num1) { + /* Time O(N) */ + for (var i2 in num2) { + /* Time O(M) */ + update(num1, i1, num2, i2, buffer); /* Space O(N + M) */ } } - buffer.reverse();/* Time O(N + M) */ -} + buffer.reverse(); /* Time O(N + M) */ +}; -const reverse = (s) => s - .split('') /* Time O(K) | Space O (K) */ - .reverse();/* Time O(K) */ +const reverse = (s) => + s + .split('') /* Time O(K) | Space O (K) */ + .reverse(); /* Time O(K) */ var update = (num1, i1, num2, i2, buffer) => { const product = num1[i1] * num2[i2]; const index = Number(i1) + Number(i2); - buffer[index] += product; /* Space O(N + M) */ - buffer[(index + 1)] += Math.floor(buffer[index] / 10);/* Space O(N + M) */ - buffer[index] = (buffer[index] % 10); /* Space O(N + M) */ -} + buffer[index] += product; /* Space O(N + M) */ + buffer[index + 1] += Math.floor(buffer[index] / 10); /* Space O(N + M) */ + buffer[index] = buffer[index] % 10; /* Space O(N + M) */ +}; var removeLeadingZero = (buffer) => { - const isZero = (buffer[0] === 0); + const isZero = buffer[0] === 0; if (!isZero) return; - buffer.shift();/* Time O(N + M) | Space O(N + M) */ -} \ No newline at end of file + buffer.shift(); /* Time O(N + M) | Space O(N + M) */ +}; diff --git a/javascript/0045-jump-game-ii.js b/javascript/0045-jump-game-ii.js index 1fe87cf54..43bdcd08f 100644 --- a/javascript/0045-jump-game-ii.js +++ b/javascript/0045-jump-game-ii.js @@ -5,7 +5,7 @@ * @return {number} */ var jump = function (nums) { - let [ left, right, jumps ] = [ 0, 0, 0 ]; + let [left, right, jumps] = [0, 0, 0]; while (right < nums.length - 1) { const maxReach = getMaxReach(nums, left, right); @@ -25,7 +25,7 @@ const getMaxReach = (nums, left, right, maxReach = 0) => { } return maxReach; -} +}; /** * https://leetcode.com/problems/jump-game-ii/ @@ -33,15 +33,18 @@ const getMaxReach = (nums, left, right, maxReach = 0) => { * @param {number[]} nums * @return {number} */ - var jump = function(nums) { - let [ jumps, currentJumpEnd, farthest ] = [ 0, 0, 0]; - +var jump = function (nums) { + let [jumps, currentJumpEnd, farthest] = [0, 0, 0]; + for (let i = 0; i < nums.length - 1; i++) { - farthest = Math.max(farthest, (i + nums[i])); + farthest = Math.max(farthest, i + nums[i]); - const canJump = i === currentJumpEnd - if (canJump) { jumps++; currentJumpEnd = farthest; } + const canJump = i === currentJumpEnd; + if (canJump) { + jumps++; + currentJumpEnd = farthest; + } } return jumps; -} \ No newline at end of file +}; diff --git a/javascript/0046-permutations.js b/javascript/0046-permutations.js index aec6eda35..6f724df0d 100644 --- a/javascript/0046-permutations.js +++ b/javascript/0046-permutations.js @@ -1,66 +1,69 @@ -/** - * https://leetcode.com/problems/permutations/solution/ - * Time O(N!) | Space(N!) - * @param {number[]} nums - * @return {number[][]} - */ - var permute = function(nums) { - return dfs(nums) -} - -var dfs = function(nums, permutation = [], permutations = []) { - const isBaseCase = nums.length === permutation.length - if (isBaseCase) return permutations.push(permutation.slice()) - - for (let i = 0; i < nums.length; i++) { - if (permutation.includes(nums[i])) continue; - - backTrack(nums, i, permutation, permutations); - } - - return permutations; -} - -const backTrack = (nums, i, permutation, permutations) => { - permutation.push(nums[i]) - dfs(nums, permutation, permutations) - permutation.pop() -} - -/** - * https://leetcode.com/problems/permutations/solution/ - * Time O(N!) | Space(N!) - * @param {number[]} nums - * @return {number[][]} - */ -var permute = function(nums) { - return bfs(nums) -} - -const bfs = (nums, levels = [[]], permutations = []) => { - for (const num of nums) { - for (let i = (levels.length - 1); 0 <= i; i--) { - const previousLevel = levels.shift() - - for (let index = 0; index < (previousLevel.length + 1); index++) { - const level = reArrangeSet(previousLevel, num, index) - - const isBaseCase = level.length === nums.length; - if (isBaseCase) { - permutations.push(level); - continue - } - - levels.push(level) - } - } - } - - return permutations -} - -const reArrangeSet = (previousLevel, num, index) => { - const [ before, after ] = [ previousLevel.slice(0, index), previousLevel.slice(index) ] - - return [...before, num, ...after] -} +/** + * https://leetcode.com/problems/permutations/solution/ + * Time O(N!) | Space(N!) + * @param {number[]} nums + * @return {number[][]} + */ +var permute = function (nums) { + return dfs(nums); +}; + +var dfs = function (nums, permutation = [], permutations = []) { + const isBaseCase = nums.length === permutation.length; + if (isBaseCase) return permutations.push(permutation.slice()); + + for (let i = 0; i < nums.length; i++) { + if (permutation.includes(nums[i])) continue; + + backTrack(nums, i, permutation, permutations); + } + + return permutations; +}; + +const backTrack = (nums, i, permutation, permutations) => { + permutation.push(nums[i]); + dfs(nums, permutation, permutations); + permutation.pop(); +}; + +/** + * https://leetcode.com/problems/permutations/solution/ + * Time O(N!) | Space(N!) + * @param {number[]} nums + * @return {number[][]} + */ +var permute = function (nums) { + return bfs(nums); +}; + +const bfs = (nums, levels = [[]], permutations = []) => { + for (const num of nums) { + for (let i = levels.length - 1; 0 <= i; i--) { + const previousLevel = levels.shift(); + + for (let index = 0; index < previousLevel.length + 1; index++) { + const level = reArrangeSet(previousLevel, num, index); + + const isBaseCase = level.length === nums.length; + if (isBaseCase) { + permutations.push(level); + continue; + } + + levels.push(level); + } + } + } + + return permutations; +}; + +const reArrangeSet = (previousLevel, num, index) => { + const [before, after] = [ + previousLevel.slice(0, index), + previousLevel.slice(index), + ]; + + return [...before, num, ...after]; +}; diff --git a/javascript/0048-rotate-image.js b/javascript/0048-rotate-image.js index 5dde51336..45003145c 100644 --- a/javascript/0048-rotate-image.js +++ b/javascript/0048-rotate-image.js @@ -4,36 +4,48 @@ * @param {number[][]} matrix * @return {void} Do not return anything, modify matrix in-place instead. */ - var rotate = (matrix) => { - transpose(matrix);/* Time O(ROWS * COLS) */ - reflect(matrix); /* Time O(ROWS * COLS) */ +var rotate = (matrix) => { + transpose(matrix); /* Time O(ROWS * COLS) */ + reflect(matrix); /* Time O(ROWS * COLS) */ }; var transpose = (matrix) => { const rows = matrix.length; - for (let row = 0; (row < rows); row++) {/* Time O(ROWS) */ - for (let col = (row + 1); (col < rows); col++) {/* Time O(COLS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = row + 1; col < rows; col++) { + /* Time O(COLS) */ swap1(matrix, row, col); } } }; -var swap1 = (matrix, row, col) => [matrix[row][col], matrix[col][row]] = [matrix[col][row], matrix[row][col]]; +var swap1 = (matrix, row, col) => + ([matrix[row][col], matrix[col][row]] = [ + matrix[col][row], + matrix[row][col], + ]); var reflect = (matrix) => { const rows = matrix.length; - for (let row = 0; (row < rows); row++) {/* Time O(ROWS) */ - for (let col = 0; (col < (rows / 2)); col++) {/* Time O(COLS) */ - const reflection = ((rows - col) - 1); + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 0; col < rows / 2; col++) { + /* Time O(COLS) */ + const reflection = rows - col - 1; swap2(matrix, row, col, reflection); } } -} +}; -var swap2 = (matrix, row, col, reflection) => [matrix[row][col], matrix[row][reflection]] = [matrix[row][reflection], matrix[row][col]]; +var swap2 = (matrix, row, col, reflection) => + ([matrix[row][col], matrix[row][reflection]] = [ + matrix[row][reflection], + matrix[row][col], + ]); /** * Time O(ROWS * COLS) | Space O(1) @@ -41,9 +53,9 @@ var swap2 = (matrix, row, col, reflection) => [matrix[row][col], matrix[row][ref * @param {number[][]} matrix * @return {void} Do not return anything, modify matrix in-place instead. */ - var rotate = (matrix) => { - reverse(matrix); /* Time O(ROWS) */ - transpose(matrix);/* Time O(ROWS * COLS) */ +var rotate = (matrix) => { + reverse(matrix); /* Time O(ROWS) */ + transpose(matrix); /* Time O(ROWS * COLS) */ }; var reverse = (matrix) => matrix.reverse(); @@ -51,11 +63,17 @@ var reverse = (matrix) => matrix.reverse(); var transpose = (matrix) => { const rows = matrix.length; - for (let row = 0; (row < rows); row++) {/* Time O(ROWS) */ - for (let col = 0; (col < row); col++) {/* Time O(COLS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 0; col < row; col++) { + /* Time O(COLS) */ swap(matrix, row, col); } } -} +}; -var swap = (matrix, row, col) => [matrix[row][col], matrix[col][row]] = [matrix[col][row], matrix[row][col]]; \ No newline at end of file +var swap = (matrix, row, col) => + ([matrix[row][col], matrix[col][row]] = [ + matrix[col][row], + matrix[row][col], + ]); diff --git a/javascript/0049-group-anagrams.js b/javascript/0049-group-anagrams.js index 409d31a36..5c9c24bbe 100644 --- a/javascript/0049-group-anagrams.js +++ b/javascript/0049-group-anagrams.js @@ -9,25 +9,29 @@ var groupAnagrams = (words, map = new Map()) => { if (!words.length) return []; - groupWords(words, map); /* Time O(N * (K * log(K)) | Space O(N * K) */ + groupWords(words, map); /* Time O(N * (K * log(K)) | Space O(N * K) */ - return [ ...map.values() ];/* Time O(N) | Space O(N * K) */ + return [...map.values()]; /* Time O(N) | Space O(N * K) */ }; var groupWords = (words, map) => { - for (const original of words) {/* Time O(N) */ - const sorted = reorder(original);/* Time O(K * log(K)) | Space O(K) */ + for (const original of words) { + /* Time O(N) */ + const sorted = reorder(original); /* Time O(K * log(K)) | Space O(K) */ const values = map.get(sorted) || []; - values.push(original); /* | Space O(N) */ - map.set(sorted, values); /* | Space O(N * K) */ + values.push(original); /* | Space O(N) */ + map.set(sorted, values); /* | Space O(N * K) */ } -} +}; -const reorder = (str) => str - .split('') /* Time O(K) | Space O(K) */ - .sort((a, b) => a.localeCompare(b))/* Time O(K * log(K)) | Space O(1 || log(K)) */ - .join(''); /* Time O(K) | Space O(K) */ +const reorder = (str) => + str + .split('') /* Time O(K) | Space O(K) */ + .sort((a, b) => + a.localeCompare(b), + ) /* Time O(K * log(K)) | Space O(1 || log(K)) */ + .join(''); /* Time O(K) | Space O(K) */ /** * Hash Map @@ -39,35 +43,35 @@ const reorder = (str) => str var groupAnagrams = (words, map = new Map()) => { if (!words.length) return []; - groupWords(words, map); /* Time O(N * K) | Space O(N * K) */ + groupWords(words, map); /* Time O(N * K) | Space O(N * K) */ - return [ ...map.values() ];/* Time O(N) | Space O(N * K) */ -} + return [...map.values()]; /* Time O(N) | Space O(N * K) */ +}; var groupWords = (words, map) => { - for (const original of words) {/* Time O(N) */ + for (const original of words) { + /* Time O(N) */ const hash = getHash(original); /* Time O(K) | Space O(1) */ const values = map.get(hash) || []; - values.push(original); /* | Space O(N) */ - map.set(hash, values); /* | Space O(N * K) */ + values.push(original); /* | Space O(N) */ + map.set(hash, values); /* | Space O(N * K) */ } -} +}; const getHash = (word) => { const frequency = new Array(26).fill(0); - for (const char of word) {/* Time O(K) */ - const charCode = getCode(char);/* Time O(1) | Space (1) */ + for (const char of word) { + /* Time O(K) */ + const charCode = getCode(char); /* Time O(1) | Space (1) */ - frequency[charCode]++; /* | Space O(1) */ + frequency[charCode]++; /* | Space O(1) */ } - return buildHash(frequency) -} + return buildHash(frequency); +}; const getCode = (char) => char.charCodeAt(0) - 'a'.charCodeAt(0); const buildHash = (frequency) => frequency.toString(); - - diff --git a/javascript/0050-powx-n.js b/javascript/0050-powx-n.js index 8e8c03b7a..6eda4c383 100644 --- a/javascript/0050-powx-n.js +++ b/javascript/0050-powx-n.js @@ -6,25 +6,26 @@ * @param {number} n * @return {number} */ - var myPow = (x, n) => { +var myPow = (x, n) => { if (n < 0) { - x = (1 / x); - n = (-n); + x = 1 / x; + n = -n; } - return getPow(x, n);/* Time O(N) */ -} + return getPow(x, n); /* Time O(N) */ +}; var getPow = (x, n, pow = 1) => { - for (let i = 0; i < n; i++) {/* Time O(N) */ + for (let i = 0; i < n; i++) { + /* Time O(N) */ pow = pow * x; } return pow; -} +}; /** - * DFS + * DFS * Time (log(N)) | Space O(log(N)) * https://leetcode.com/problems/powx-n/ * @param {number} x @@ -32,19 +33,21 @@ var getPow = (x, n, pow = 1) => { * @return {number} */ var myPow = (x, n) => { - const isBaseCase1 = ((x === 1.0) || (n === 0)); + const isBaseCase1 = x === 1.0 || n === 0; if (isBaseCase1) return 1; - const isBaseCase2 = (n === 1); + const isBaseCase2 = n === 1; if (isBaseCase2) return x; - const isEven = ((n % 2) === 0); - if (isEven) return myPow((x * x), (n / 2));/* Time O(log(N)) | Space O(log(N)) */ + const isEven = n % 2 === 0; + if (isEven) + return myPow(x * x, n / 2); /* Time O(log(N)) | Space O(log(N)) */ - const isOdd = ((n % 2) === 1); - if (isOdd) return (x * myPow(x, (n - 1)));/* Time O(log(N)) | Space O(log(N)) */ + const isOdd = n % 2 === 1; + if (isOdd) + return x * myPow(x, n - 1); /* Time O(log(N)) | Space O(log(N)) */ - return (1 / myPow(x, -n)); + return 1 / myPow(x, -n); }; /** @@ -56,52 +59,51 @@ var myPow = (x, n) => { * @return {number} */ var myPow = (x, n) => { - const isBaseCase = (n === 0); + const isBaseCase = n === 0; if (isBaseCase) return 1; const abs = Math.abs(n); - const isEven = ((abs % 2) === 0); + const isEven = abs % 2 === 0; const power = isEven - ? myPow((x * x), (abs / 2)) /* Time O(log(N)) | Space O(log(N)) */ - : (myPow((x * x), ((abs - 1) / 2)) * x);/* Time O(log(N)) | Space O(log(N)) */ + ? myPow(x * x, abs / 2) /* Time O(log(N)) | Space O(log(N)) */ + : myPow(x * x, (abs - 1) / 2) * + x; /* Time O(log(N)) | Space O(log(N)) */ - const isNegative = (n < 0); + const isNegative = n < 0; - return isNegative - ? (1 / power) - : power; + return isNegative ? 1 / power : power; }; /** - * Fast Power - Recursive + * Fast Power - Recursive * Time O(log(N)) | Space O(log(N)) * https://leetcode.com/problems/powx-n/ * @param {number} x * @param {number} n * @return {number} */ - var myPow = (x, n) => { +var myPow = (x, n) => { if (n < 0) { x = 1 / x; n = -n; } - return fastPow(x, n);/* Time O(log(N)) | Space O(log(N)) */ -} + return fastPow(x, n); /* Time O(log(N)) | Space O(log(N)) */ +}; var fastPow = (x, n) => { const isBaseCase = n === 0; if (isBaseCase) return 1.0; - const half = fastPow(x, n / 2);/* Time O(log(N)) | Space O(log(N)) */ + const half = fastPow(x, n / 2); /* Time O(log(N)) | Space O(log(N)) */ - const isEven = ((n % 2) === 0); - if (isEven) return (half * half); + const isEven = n % 2 === 0; + if (isEven) return half * half; - const isOdd = ((n % 2) === 1); - if (isOdd) return ((half * half) * x); -} + const isOdd = n % 2 === 1; + if (isOdd) return half * half * x; +}; /** * Fast Power - Iterative @@ -111,25 +113,26 @@ var fastPow = (x, n) => { * @param {number} n * @return {number} */ - var myPow = (x, n) => { +var myPow = (x, n) => { if (n < 0) { - x = (1 / x); - n = (-n); + x = 1 / x; + n = -n; } - let [ pow, product ] = [ 1, x ]; + let [pow, product] = [1, x]; - for (let i = n; (0 < i); i = (i >> 1)) {/* Time O(log(N)) */ - const isOdd = ((i % 2) === 1); - if (isOdd) pow = (pow * product); + for (let i = n; 0 < i; i = i >> 1) { + /* Time O(log(N)) */ + const isOdd = i % 2 === 1; + if (isOdd) pow = pow * product; - product = (product * product); + product = product * product; } return pow; -} - - /** +}; + +/** * Number - Math * Time O(1) | Space O(1) * https://leetcode.com/problems/powx-n/ @@ -137,6 +140,6 @@ var fastPow = (x, n) => { * @param {number} n * @return {number} */ - var myPow = (x, n) => { - return Math.pow(x,n).toFixed(5); -} +var myPow = (x, n) => { + return Math.pow(x, n).toFixed(5); +}; diff --git a/javascript/0051-n-queens.js b/javascript/0051-n-queens.js index ad9d7a37b..ab78d40ed 100644 --- a/javascript/0051-n-queens.js +++ b/javascript/0051-n-queens.js @@ -4,7 +4,12 @@ * @param {number} n * @return {string[][]} */ -function solveNQueens(n, colSet = new Set(), posDiagSet = new Set(), negDiagSet = new Set()) { +function solveNQueens( + n, + colSet = new Set(), + posDiagSet = new Set(), + negDiagSet = new Set(), +) { const board = new Array(n).fill().map(() => new Array(n).fill('.')); return dfs(board, n, colSet, posDiagSet, negDiagSet); @@ -13,7 +18,7 @@ function solveNQueens(n, colSet = new Set(), posDiagSet = new Set(), negDiagSet const dfs = (board, n, colSet, posDiagSet, negDiagSet, row = 0, moves = []) => { const isBaseCase = row === n; if (isBaseCase) { - const rows = board.map((_row) => _row.join('')) + const rows = board.map((_row) => _row.join('')); moves.push(rows); @@ -21,25 +26,37 @@ const dfs = (board, n, colSet, posDiagSet, negDiagSet, row = 0, moves = []) => { } for (let col = 0; col < n; col++) { - const hasQueen = colSet.has(col) || posDiagSet.has(row + col) || negDiagSet.has(row - col) + const hasQueen = + colSet.has(col) || + posDiagSet.has(row + col) || + negDiagSet.has(row - col); if (hasQueen) continue; backTrack(board, n, row, col, colSet, posDiagSet, negDiagSet, moves); } - return moves -} - -const backTrack = (board, n, row, col, colSet, posDiagSet, negDiagSet, moves) => { + return moves; +}; + +const backTrack = ( + board, + n, + row, + col, + colSet, + posDiagSet, + negDiagSet, + moves, +) => { colSet.add(col); posDiagSet.add(row + col); negDiagSet.add(row - col); - board[row][col] = "Q"; + board[row][col] = 'Q'; - dfs(board, n, colSet, posDiagSet, negDiagSet, (row + 1), moves); + dfs(board, n, colSet, posDiagSet, negDiagSet, row + 1, moves); colSet.delete(col); posDiagSet.delete(row + col); negDiagSet.delete(row - col); - board[row][col] = "."; -} + board[row][col] = '.'; +}; diff --git a/javascript/0053-maximum-subarray.js b/javascript/0053-maximum-subarray.js index 3280515a9..6f22d2a2f 100644 --- a/javascript/0053-maximum-subarray.js +++ b/javascript/0053-maximum-subarray.js @@ -4,7 +4,7 @@ * @param {number[]} nums * @return {number} */ - var maxSubArray = function(nums, maxSum = -Infinity) { +var maxSubArray = function (nums, maxSum = -Infinity) { for (let i = 0, sum = 0; i < nums.length; i++) { for (let j = i; j < nums.length; j++) { sum += nums[j]; @@ -13,7 +13,7 @@ } return maxSum; -} +}; /** * https://leetcode.com/problems/maximum-subarray/ @@ -21,39 +21,39 @@ * @param {number[]} nums * @return {number} */ -var maxSubArray = function(nums, left = 0, right = nums.length - 1) { - const isBaseCase = (right < left) +var maxSubArray = function (nums, left = 0, right = nums.length - 1) { + const isBaseCase = right < left; if (isBaseCase) return -Infinity; const mid = (left + right) >> 1; const guess = nums[mid]; - const leftSum = getLeftSumFromMid(nums, mid, left) - const rightSum = getRightSumFromMid(nums, mid, right) + const leftSum = getLeftSumFromMid(nums, mid, left); + const rightSum = getRightSumFromMid(nums, mid, right); const sum = guess + leftSum + rightSum; - - const leftHalf = maxSubArray(nums, left, (mid - 1)); - const rightHalf = maxSubArray(nums, (mid + 1), right); + + const leftHalf = maxSubArray(nums, left, mid - 1); + const rightHalf = maxSubArray(nums, mid + 1, right); return Math.max(sum, leftHalf, rightHalf); -} +}; const getLeftSumFromMid = (nums, mid, left, sum = 0, maxSum = 0) => { - for (let i = (mid - 1); left <= i; i--) { + for (let i = mid - 1; left <= i; i--) { sum += nums[i]; maxSum = Math.max(maxSum, sum); } - + return maxSum; -} +}; const getRightSumFromMid = (nums, mid, right, sum = 0, maxSum = 0) => { - for (let i = (mid + 1); i <= right; i++) { + for (let i = mid + 1; i <= right; i++) { sum += nums[i]; maxSum = Math.max(maxSum, sum); } - + return maxSum; -} +}; /** * https://leetcode.com/problems/maximum-subarray/ @@ -61,16 +61,16 @@ const getRightSumFromMid = (nums, mid, right, sum = 0, maxSum = 0) => { * @param {number[]} nums * @return {number} */ -var maxSubArray = function(nums) { - let [ runningSum, maxSum ] = [ nums[0], nums[0] ] - +var maxSubArray = function (nums) { + let [runningSum, maxSum] = [nums[0], nums[0]]; + for (let i = 1; i < nums.length; i++) { - const num = nums[i] - const sum = runningSum + num - - runningSum = Math.max(num, sum) - maxSum = Math.max(maxSum, runningSum) + const num = nums[i]; + const sum = runningSum + num; + + runningSum = Math.max(num, sum); + maxSum = Math.max(maxSum, runningSum); } - - return maxSum -}; \ No newline at end of file + + return maxSum; +}; diff --git a/javascript/0054-spiral-matrix.js b/javascript/0054-spiral-matrix.js index 9eb94dcb4..f065f1ccc 100644 --- a/javascript/0054-spiral-matrix.js +++ b/javascript/0054-spiral-matrix.js @@ -6,65 +6,98 @@ * @param {number[][]} matrix * @return {number[]} */ - var spiralOrder = function(matrix, order = []) { - const [ rows, cols ] = [ (matrix.length - 1), (matrix[0].length - 1) ]; - let [ top, bot, left, right ] = [ 0, rows, 0, cols ]; +var spiralOrder = function (matrix, order = []) { + const [rows, cols] = [matrix.length - 1, matrix[0].length - 1]; + let [top, bot, left, right] = [0, rows, 0, cols]; - const isInBounds = () => ((left <= right) && (top <= bot)); - while (isInBounds()) {/* Time O(ROWS * COLS) */ + const isInBounds = () => left <= right && top <= bot; + while (isInBounds()) { + /* Time O(ROWS * COLS) */ addTop( - matrix, top, bot, left, right, order - ); /* Time O(COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ + matrix, + top, + bot, + left, + right, + order, + ); /* Time O(COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ top++; addRight( - matrix, top, bot, left, right, order - ); /* Time O(ROWS) | Ignore Auxilary Spsace O(ROWS * COLS) */ + matrix, + top, + bot, + left, + right, + order, + ); /* Time O(ROWS) | Ignore Auxilary Spsace O(ROWS * COLS) */ right--; - const hasRow = (top <= bot); + const hasRow = top <= bot; if (hasRow) { addBot( - matrix, top, bot, left, right, order - ); /* Time O(COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ + matrix, + top, + bot, + left, + right, + order, + ); /* Time O(COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ bot--; } - const hasCol = (left <= right); + const hasCol = left <= right; if (hasCol) { addLeft( - matrix, top, bot, left, right, order - ); /* Time O(ROWS) | Ignore Auxilary Spsace O(ROWS * COLS) */ + matrix, + top, + bot, + left, + right, + order, + ); /* Time O(ROWS) | Ignore Auxilary Spsace O(ROWS * COLS) */ left++; } } - + return order; }; var addTop = (matrix, top, bot, left, right, order) => { - for (let col = left; col <= right; col++) {/* Time O(COLS) */ - order.push(matrix[top][col]); /* Ignore Auxilary Spsace O(ROWS * COLS) */ + for (let col = left; col <= right; col++) { + /* Time O(COLS) */ + order.push( + matrix[top][col], + ); /* Ignore Auxilary Spsace O(ROWS * COLS) */ } -} +}; var addRight = (matrix, top, bot, left, right, order) => { - for (let row = top; row <= bot; row++) {/* Time O(ROWS) */ - order.push(matrix[row][right]); /* Ignore Auxilary Spsace O(ROWS * COLS) */ + for (let row = top; row <= bot; row++) { + /* Time O(ROWS) */ + order.push( + matrix[row][right], + ); /* Ignore Auxilary Spsace O(ROWS * COLS) */ } -} +}; var addBot = (matrix, top, bot, left, right, order) => { - for (let col = right; left <= col; col--) {/* Time O(COLS) */ - order.push(matrix[bot][col]); /* Ignore Auxilary Spsace O(ROWS * COLS) */ + for (let col = right; left <= col; col--) { + /* Time O(COLS) */ + order.push( + matrix[bot][col], + ); /* Ignore Auxilary Spsace O(ROWS * COLS) */ } -} +}; var addLeft = (matrix, top, bot, left, right, order) => { - for (let row = bot; top <= row; row--) {/* Time O(ROWS) */ - order.push(matrix[row][left]); /* Ignore Auxilary Spsace O(ROWS * COLS) */ + for (let row = bot; top <= row; row--) { + /* Time O(ROWS) */ + order.push( + matrix[row][left], + ); /* Ignore Auxilary Spsace O(ROWS * COLS) */ } -} +}; /** * Matrix - Spiral Traversal Post Update @@ -75,58 +108,106 @@ var addLeft = (matrix, top, bot, left, right, order) => { * @return {number[]} */ var spiralOrder = (matrix, order = []) => { - const [ rows, cols ] = [ matrix.length, matrix[0].length ]; - const cells = (rows * cols); - let [ top, bot, left, right ] = [ 0, (rows - 1), 0, (cols - 1) ]; + const [rows, cols] = [matrix.length, matrix[0].length]; + const cells = rows * cols; + let [top, bot, left, right] = [0, rows - 1, 0, cols - 1]; - while (order.length < cells) {/* Time O(ROWS * COLS) */ + while (order.length < cells) { + /* Time O(ROWS * COLS) */ traverse( - matrix, top, bot, left, right, order - ); /* Time O(ROWS * COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ + matrix, + top, + bot, + left, + right, + order, + ); /* Time O(ROWS * COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ - top++; bot--; - left++; right--; + top++; + bot--; + left++; + right--; } - + return order; -} +}; var traverse = (matrix, top, bot, left, right, order) => { - addTop(matrix, top, bot, left, right, order); /* Time O(COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ - addRight(matrix, top, bot, left, right, order);/* Time O(ROWS) | Ignore Auxilary Spsace O(ROWS * COLS)*/ - addBot(matrix, top, bot, left, right, order); /* Time O(COLS) | Ignore Auxilary Spsace O(ROWS * COLS)*/ - addLeft(matrix, top, bot, left, right, order); /* Time O(ROWS) | Ignore Auxilary Spsace O(ROWS * COLS. */ -} + addTop( + matrix, + top, + bot, + left, + right, + order, + ); /* Time O(COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ + addRight( + matrix, + top, + bot, + left, + right, + order, + ); /* Time O(ROWS) | Ignore Auxilary Spsace O(ROWS * COLS)*/ + addBot( + matrix, + top, + bot, + left, + right, + order, + ); /* Time O(COLS) | Ignore Auxilary Spsace O(ROWS * COLS)*/ + addLeft( + matrix, + top, + bot, + left, + right, + order, + ); /* Time O(ROWS) | Ignore Auxilary Spsace O(ROWS * COLS. */ +}; var addTop = (matrix, top, bot, left, right, order) => { - for (let col = left; (col <= right); col++) {/* Time O(COLS) */ - order.push(matrix[top][col]); /* Ignore Auxilary Spsace O(ROWS * COLS) */ + for (let col = left; col <= right; col++) { + /* Time O(COLS) */ + order.push( + matrix[top][col], + ); /* Ignore Auxilary Spsace O(ROWS * COLS) */ } -} +}; var addRight = (matrix, top, bot, left, right, order) => { - for (let row = (top + 1); (row <= bot); row++) {/* Time O(ROWS) */ - order.push(matrix[row][right]); /* Ignore Auxilary Spsace O(ROWS * COLS) */ + for (let row = top + 1; row <= bot; row++) { + /* Time O(ROWS) */ + order.push( + matrix[row][right], + ); /* Ignore Auxilary Spsace O(ROWS * COLS) */ } -} +}; var addBot = (matrix, top, bot, left, right, order) => { - for (let col = (right - 1); (left <= col); col--) {/* Time O(COLS) */ + for (let col = right - 1; left <= col; col--) { + /* Time O(COLS) */ const isOutOfBounds = top === bot; if (isOutOfBounds) return; - - order.push(matrix[bot][col]); /* Ignore Auxilary Spsace O(ROWS * COLS) */ + + order.push( + matrix[bot][col], + ); /* Ignore Auxilary Spsace O(ROWS * COLS) */ } -} +}; var addLeft = (matrix, top, bot, left, right, order) => { - for (let row = bot - 1; row >= top + 1; row--) {/* Time O(ROWS) */ + for (let row = bot - 1; row >= top + 1; row--) { + /* Time O(ROWS) */ const isOutOfBounds = left === right; if (isOutOfBounds) return; - order.push(matrix[row][left]); /* Ignore Auxilary Spsace O(ROWS * COLS) */ + order.push( + matrix[row][left], + ); /* Ignore Auxilary Spsace O(ROWS * COLS) */ } -} +}; /** * Matrix - Mark Visited In Place @@ -136,84 +217,109 @@ var addLeft = (matrix, top, bot, left, right, order) => { * @param {number[][]} matrix * @return {number[]} */ - var spiralOrder = (matrix) => { - const order = initOrder(matrix);/* | Ignore Auxilary Spsace O(ROWS * COLS) */ +var spiralOrder = (matrix) => { + const order = + initOrder( + matrix, + ); /* | Ignore Auxilary Spsace O(ROWS * COLS) */ - spiral(matrix, order); /* Time O(ROWS * COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ + spiral( + matrix, + order, + ); /* Time O(ROWS * COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ return order; -} +}; const initOrder = (matrix, VISITED = 101) => { - const order = [ matrix[0][0] ];/* Ignore Auxilary Spsace O(ROWS * COLS) */ + const order = [matrix[0][0]]; /* Ignore Auxilary Spsace O(ROWS * COLS) */ - matrix[0][0] = VISITED; /* Ignore Auxilary Spsace O(ROWS * COLS) */ + matrix[0][0] = VISITED; /* Ignore Auxilary Spsace O(ROWS * COLS) */ return order; -} +}; var spiral = (matrix, order) => { - let [ row, col, direction, changeDirection ] = [ 0, 0, 0, 0 ]; + let [row, col, direction, changeDirection] = [0, 0, 0, 0]; - while (changeDirection < 2) { /* Time O(ROWS * COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ - [ row, col, direction, changeDirection ] =/* Time O(ROWS * COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ + while (changeDirection < 2) { + /* Time O(ROWS * COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ + [row, col, direction, changeDirection] = + /* Time O(ROWS * COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ getPointers(matrix, row, col, direction, changeDirection, order); } -} +}; const getPointers = (matrix, row, col, direction, changeDirection, order) => { - [ row, col, direction, changeDirection ] =/* Time O(ROWS * COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ + [row, col, direction, changeDirection] = + /* Time O(ROWS * COLS) | Ignore Auxilary Spsace O(ROWS * COLS) */ move(matrix, row, col, direction, changeDirection, order); - direction = ((direction + 1) % 4); + direction = (direction + 1) % 4; changeDirection += 1; - return [ row, col, direction, changeDirection ]; -} - -const move = (matrix, row, col, direction, changeDirection, order, VISITED = 101) => { - const [ rows, cols ] = [ matrix.length, matrix[0].length ]; - - while (canMove(matrix, row, rows, col, cols, direction)) {/* Time O(ROWS * COLS) */ - [ row, col ] = getCell(row, col, direction); + return [row, col, direction, changeDirection]; +}; - order.push(matrix[row][col]); /* | Ignore Auxilary Spsace O(ROWS * COLS) */ +const move = ( + matrix, + row, + col, + direction, + changeDirection, + order, + VISITED = 101, +) => { + const [rows, cols] = [matrix.length, matrix[0].length]; + + while (canMove(matrix, row, rows, col, cols, direction)) { + /* Time O(ROWS * COLS) */ + [row, col] = getCell(row, col, direction); + + order.push( + matrix[row][col], + ); /* | Ignore Auxilary Spsace O(ROWS * COLS) */ matrix[row][col] = VISITED; changeDirection = 0; } - return [ row, col, direction, changeDirection ]; -} + return [row, col, direction, changeDirection]; +}; const canMove = (matrix, row, rows, col, cols, direction) => { if (!isInBounds(row, rows, col, cols, direction)) return false; - return !hasSeen(matrix, row, col, direction) -} + return !hasSeen(matrix, row, col, direction); +}; const isInBounds = (row, rows, col, cols, direction) => { - const [ _row, _col ] = getCell(row, col, direction); - const isRowInBounds = ((0 <= _row) && (_row < rows)); - const isColInBounds = ((0 <= _col) && (_col < cols)); + const [_row, _col] = getCell(row, col, direction); + const isRowInBounds = 0 <= _row && _row < rows; + const isColInBounds = 0 <= _col && _col < cols; - return (isRowInBounds && isColInBounds); -} + return isRowInBounds && isColInBounds; +}; const hasSeen = (matrix, row, col, direction, VISITED = 101) => { - const [ _row, _col ] = getCell(row, col, direction); + const [_row, _col] = getCell(row, col, direction); - return (matrix[_row][_col] === VISITED); -} + return matrix[_row][_col] === VISITED; +}; const getDirection = (direction) => { - const directions = [ [0, 1], [1, 0], [0, -1], [-1, 0] ]; - /* RIGHT BOT LEFT TOP */ + const directions = [ + [0, 1], + [1, 0], + [0, -1], + [-1, 0], + ]; + /* RIGHT BOT LEFT TOP */ return directions[direction]; -} +}; const getCell = (row, col, direction) => { - const [ _row, _col ] = getDirection(direction); + const [_row, _col] = getDirection(direction); - return [ (row + _row), (col + _col) ]; -} + return [row + _row, col + _col]; +}; diff --git a/javascript/0055-jump-game.js b/javascript/0055-jump-game.js index 7441763d8..f600fc7cc 100644 --- a/javascript/0055-jump-game.js +++ b/javascript/0055-jump-game.js @@ -3,17 +3,17 @@ * @param {number[]} nums * @return {boolean} */ - var canJump = (nums, index = 0) => { +var canJump = (nums, index = 0) => { const isBaseCase = index === nums.length - 1; if (isBaseCase) return true; - const furthestJump = Math.min(index + nums[index], (nums.length - 1)); - for (let nextIndex = (index + 1); nextIndex <= furthestJump; nextIndex++) { + const furthestJump = Math.min(index + nums[index], nums.length - 1); + for (let nextIndex = index + 1; nextIndex <= furthestJump; nextIndex++) { if (canJump(nums, nextIndex)) return true; } return false; -} +}; /** * Time O(N^2) | Space O(N) @@ -23,16 +23,16 @@ var canJump = (nums) => { const memo = new Array(nums.length).fill(0); memo[memo.length - 1] = 1; - + return canJumpFromIndex(nums, memo); -} +}; const canJumpFromIndex = (nums, memo, index = 0) => { if (memo[index] !== 0) return memo[index] === 1; const furthestJump = Math.min(index + nums[index], nums.length - 1); - for (let nextIndex = (index + 1); nextIndex <= furthestJump; nextIndex++) { - if (!canJumpFromIndex(nums, memo, nextIndex)) continue + for (let nextIndex = index + 1; nextIndex <= furthestJump; nextIndex++) { + if (!canJumpFromIndex(nums, memo, nextIndex)) continue; memo[index] = 1; return true; @@ -40,7 +40,7 @@ const canJumpFromIndex = (nums, memo, index = 0) => { memo[index] = -1; return false; -} +}; /** * Time O(N^2) | Space O(N) @@ -48,19 +48,22 @@ const canJumpFromIndex = (nums, memo, index = 0) => { * @return {boolean} */ var canJump = (nums) => { - const memo = new Array(nums.length).fill(0) + const memo = new Array(nums.length).fill(0); memo[memo.length - 1] = 1; - for (let i = (nums.length - 2); 0 <= i; i--) { + for (let i = nums.length - 2; 0 <= i; i--) { const furthestJump = Math.min(i + nums[i], nums.length - 1); - for (let j = (i + 1); j <= furthestJump; j++) { - const isGood = memo[j] === 1 - if (isGood) { memo[i] = 1; break; } + for (let j = i + 1; j <= furthestJump; j++) { + const isGood = memo[j] === 1; + if (isGood) { + memo[i] = 1; + break; + } } } return memo[0] === 1; -} +}; /** * Time O(N) | Space O(1) @@ -69,18 +72,18 @@ var canJump = (nums) => { */ var canJump = (nums, max = 0, index = 0) => { while (index < nums.length) { - const num = nums[index] - const jumps = num + index - - const canNotReachEnd = max < index - if (canNotReachEnd) return false - - max = Math.max(max, jumps) - index++ + const num = nums[index]; + const jumps = num + index; + + const canNotReachEnd = max < index; + if (canNotReachEnd) return false; + + max = Math.max(max, jumps); + index++; } - return true -} + return true; +}; /** * Time O(N) | Space O(1) @@ -89,10 +92,9 @@ var canJump = (nums, max = 0, index = 0) => { */ var canJump = (nums, right = nums.length - 1) => { for (let i = right; 0 <= i; i--) { - const isJumpable = right <= (i + nums[i]) + const isJumpable = right <= i + nums[i]; if (isJumpable) right = i; } return right === 0; -} - +}; diff --git a/javascript/0056-merge-intervals.js b/javascript/0056-merge-intervals.js index 9ef5779d0..7fb625db6 100644 --- a/javascript/0056-merge-intervals.js +++ b/javascript/0056-merge-intervals.js @@ -6,7 +6,7 @@ */ var merge = function (intervals) { intervals.sort(([aStart, aEnd], [bStart, bEnd]) => - aStart !== bStart ? aStart - bStart : aEnd - bEnd + aStart !== bStart ? aStart - bStart : aEnd - bEnd, ); return mergerInterval(intervals); diff --git a/javascript/0058-length-of-last-word.js b/javascript/0058-length-of-last-word.js index 4ecad082f..d2b940207 100644 --- a/javascript/0058-length-of-last-word.js +++ b/javascript/0058-length-of-last-word.js @@ -2,12 +2,12 @@ * @param {string} s * @return {number} */ - var lengthOfLastWord = function(s) { +var lengthOfLastWord = function (s) { let len = 0; - - for(let i in s) { - if(s[i] != ' ') { - if(s[i-1] == ' ') len = 1; + + for (let i in s) { + if (s[i] != ' ') { + if (s[i - 1] == ' ') len = 1; else len += 1; } } @@ -15,17 +15,16 @@ }; // another approach. starting out from the last so we don't have to go all the way to the end. -var lengthOfLastWord = function(s) { - +var lengthOfLastWord = function (s) { let firstCharOccurance = false; let lastWordLen = 0; - for(let i = s.length - 1; i > -1; i--) { - if(s[i] !== ' ') { + for (let i = s.length - 1; i > -1; i--) { + if (s[i] !== ' ') { firstCharOccurance = true; lastWordLen++; } - if(firstCharOccurance && s[i] === ' ') { + if (firstCharOccurance && s[i] === ' ') { break; } } diff --git a/javascript/0059-spiral-matrix-ii.js b/javascript/0059-spiral-matrix-ii.js index a644bb094..970a24ff2 100644 --- a/javascript/0059-spiral-matrix-ii.js +++ b/javascript/0059-spiral-matrix-ii.js @@ -3,30 +3,32 @@ * @param {number} n * @return {number[][]} */ -var generateMatrix = function(n) { - let matrix = Array.from(Array(n),() => Array(n)); - - let top = 0,bottom = n-1,left = 0,right = n-1; - let element = 1; +var generateMatrix = function (n) { + let matrix = Array.from(Array(n), () => Array(n)); - while(top <= bottom && left <= right){ + let top = 0, + bottom = n - 1, + left = 0, + right = n - 1; + let element = 1; - for(let i = left;i <= right; i++){ + while (top <= bottom && left <= right) { + for (let i = left; i <= right; i++) { matrix[top][i] = element++; } top++; - for(let i = top;i <= bottom; i++){ + for (let i = top; i <= bottom; i++) { matrix[i][right] = element++; } right--; - for(let i = right; i>= left; i--){ + for (let i = right; i >= left; i--) { matrix[bottom][i] = element++; } bottom--; - for(let i = bottom;i >= top; i--){ + for (let i = bottom; i >= top; i--) { matrix[i][left] = element++; } left++; diff --git a/javascript/0062-unique-paths.js b/javascript/0062-unique-paths.js index 9859331d3..c1c0b1e06 100644 --- a/javascript/0062-unique-paths.js +++ b/javascript/0062-unique-paths.js @@ -6,19 +6,19 @@ * @param {number} n * @return {number} */ - var uniquePaths = (row, col) => { - const isBaseCase = ((row == 1) || (col == 1)); +var uniquePaths = (row, col) => { + const isBaseCase = row == 1 || col == 1; if (isBaseCase) return 1; - return dfs(row, col);/* Time O(2^N) | Space O(HEIGHT) */ -} + return dfs(row, col); /* Time O(2^N) | Space O(HEIGHT) */ +}; var dfs = (row, col) => { - const left = uniquePaths((row - 1), col); /* Time O(2^N) | Space O(HEIGHT) */ - const right = uniquePaths(row, (col - 1));/* Time O(2^N) | Space O(HEIGHT) */ + const left = uniquePaths(row - 1, col); /* Time O(2^N) | Space O(HEIGHT) */ + const right = uniquePaths(row, col - 1); /* Time O(2^N) | Space O(HEIGHT) */ - return (left + right); -} + return left + right; +}; /** * DP - Top Down @@ -30,25 +30,42 @@ var dfs = (row, col) => { * @return {number} */ var uniquePaths = (row, col, memo = getMemo(row, col)) => { - const isBaseCase = ((row === 1) || (col === 1)); + const isBaseCase = row === 1 || col === 1; if (isBaseCase) return 1; - const hasSeen = (memo[row][col] !== 0); + const hasSeen = memo[row][col] !== 0; if (hasSeen) return memo[row][col]; - return dfs(row, col, memo);/* Time O(ROWS * COLS) | Space O((ROWS * COLS) + HEIGHT) */ + return dfs( + row, + col, + memo, + ); /* Time O(ROWS * COLS) | Space O((ROWS * COLS) + HEIGHT) */ }; -var getMemo = (row, col) => new Array((row + 1)).fill()/* Time O(ROWS)| Space O(ROWS) */ - .map(() => new Array((col + 1)).fill(0)); /* Time O(COLS)| Space O(COLS) */ +var getMemo = (row, col) => + new Array(row + 1) + .fill() /* Time O(ROWS)| Space O(ROWS) */ + .map(() => + new Array(col + 1).fill(0), + ); /* Time O(COLS)| Space O(COLS) */ var dfs = (row, col, memo) => { - const left = uniquePaths((row - 1), col, memo); /* Time O(ROWS * COLS) | Space O(HEIGHT) */ - const right = uniquePaths(row, (col - 1), memo);/* Time O(ROWS * COLS) | Space O(HEIGHT) */ - - memo[row][col] = (left + right); /* | Space O(ROWS * COLS) */ + const left = uniquePaths( + row - 1, + col, + memo, + ); /* Time O(ROWS * COLS) | Space O(HEIGHT) */ + const right = uniquePaths( + row, + col - 1, + memo, + ); /* Time O(ROWS * COLS) | Space O(HEIGHT) */ + + memo[row][col] = + left + right; /* | Space O(ROWS * COLS) */ return memo[row][col]; -} +}; /** * DP - Bottom Up @@ -60,38 +77,46 @@ var dfs = (row, col, memo) => { * @return {number} */ var uniquePaths = (row, col) => { - const tabu = initTabu(row, col);/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ + const tabu = initTabu( + row, + col, + ); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ - search(row, col, tabu); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ + search(row, col, tabu); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ return tabu[row - 1][col - 1]; }; var search = (row, col, tabu) => { - for (let _row = 1; (_row < row); _row++) {/* Time O(ROWS)*/ - for (let _col = 1; (_col < col); _col++) {/* Time O(COLS)*/ - const left = (tabu[(_row - 1)][_col]) - const right = (tabu[_row][(_col - 1)]); - - tabu[_row][_col] = (left + right); /* Space O(ROWS * COLS) */ + for (let _row = 1; _row < row; _row++) { + /* Time O(ROWS)*/ + for (let _col = 1; _col < col; _col++) { + /* Time O(COLS)*/ + const left = tabu[_row - 1][_col]; + const right = tabu[_row][_col - 1]; + + tabu[_row][_col] = left + right; /* Space O(ROWS * COLS) */ } } -} +}; var initTabu = (row, col) => { - const tabu = new Array(row).fill() /* Time O(ROWS) | Space O(ROWS) */ - .map(() => new Array(col).fill(0)); /* Time O(COLS) | Space O(COLS) */ - - for (let _row = 0; (_row < row); _row++) {/* Time O(ROWS) */ - tabu[_row][0] = 1; /* | Space O(ROWS * COLS) */ + const tabu = new Array(row) + .fill() /* Time O(ROWS) | Space O(ROWS) */ + .map(() => new Array(col).fill(0)); /* Time O(COLS) | Space O(COLS) */ + + for (let _row = 0; _row < row; _row++) { + /* Time O(ROWS) */ + tabu[_row][0] = 1; /* | Space O(ROWS * COLS) */ } - for (let _col = 0; (_col < col); _col++) {/* Time O(COLS) */ - tabu[0][_col] = 1; /* | Space O(ROWS * COLS) */ + for (let _col = 0; _col < col; _col++) { + /* Time O(COLS) */ + tabu[0][_col] = 1; /* | Space O(ROWS * COLS) */ } return tabu; -} +}; /** * DP - Bottom Up @@ -103,21 +128,24 @@ var initTabu = (row, col) => { * @return {number} */ var uniquePaths = (row, col) => { - const tabu = initTabu(col);/* Time O(COLS) | Space O(COLS) */ + const tabu = initTabu(col); /* Time O(COLS) | Space O(COLS) */ - search(row, col, tabu); /* Time O(ROWS * COLS) | Space O(COLS) */ + search(row, col, tabu); /* Time O(ROWS * COLS) | Space O(COLS) */ - return tabu[(col - 1)]; + return tabu[col - 1]; }; -var initTabu = (col) => new Array(col).fill(1); /* Time O(COLS) | Space O(COLS) */ +var initTabu = (col) => + new Array(col).fill(1); /* Time O(COLS) | Space O(COLS) */ var search = (row, col, tabu) => { - for (let _row = 1; (_row < row); _row++) {/* Time O(ROWS) */ - for (let _col = 1; (_col < col); _col++) {/* Time O(COLS) */ - const prev = tabu[(_col - 1)]; + for (let _row = 1; _row < row; _row++) { + /* Time O(ROWS) */ + for (let _col = 1; _col < col; _col++) { + /* Time O(COLS) */ + const prev = tabu[_col - 1]; - tabu[_col] += prev; /* Space O(COLS) */ + tabu[_col] += prev; /* Space O(COLS) */ } } -} \ No newline at end of file +}; diff --git a/javascript/0066-plus-one.js b/javascript/0066-plus-one.js index a8d528f19..16b29abc8 100644 --- a/javascript/0066-plus-one.js +++ b/javascript/0066-plus-one.js @@ -4,33 +4,34 @@ * @param {number[]} digits * @return {number[]} */ - var plusOne = (digits) => { +var plusOne = (digits) => { add(digits); - carry(digits); /* Time O(N) */ - addLeading(digits);/* | Space O(N) */ + carry(digits); /* Time O(N) */ + addLeading(digits); /* | Space O(N) */ return digits; }; -var add = (digits) => digits[digits.length - 1] += 1; +var add = (digits) => (digits[digits.length - 1] += 1); var carry = (digits) => { - for (let digit = (digits.length - 1); (0 < digit); digit--) {/* Time O(N) */ - const canCarry = (digits[digit] === 10); + for (let digit = digits.length - 1; 0 < digit; digit--) { + /* Time O(N) */ + const canCarry = digits[digit] === 10; if (!canCarry) break; - + digits[digit] = 0; - digits[(digit - 1)] += 1; + digits[digit - 1] += 1; } -} +}; const addLeading = (digits) => { - const canCarry = (digits[0] === 10); + const canCarry = digits[0] === 10; if (!canCarry) return; digits[0] = 1; - digits.push(0);/* Space O(N) */ -} + digits.push(0); /* Space O(N) */ +}; /** * Time O(N) | Space O(N) @@ -39,16 +40,20 @@ const addLeading = (digits) => { * @return {number[]} */ var plusOne = (digits) => { - for (let digit = (digits.length - 1); (0 <= digit); digit--) {/* Time O(N) */ + for (let digit = digits.length - 1; 0 <= digit; digit--) { + /* Time O(N) */ const canCarry = digits[digit] === 9; - if (canCarry) { digits[digit] = 0; continue; } + if (canCarry) { + digits[digit] = 0; + continue; + } digits[digit]++; return digits; } - digits.unshift(1); /* Time O(N) | Space O(N) */ + digits.unshift(1); /* Time O(N) | Space O(N) */ return digits; }; @@ -59,19 +64,19 @@ var plusOne = (digits) => { * @param {number[]} digits * @return {number[]} */ -var plusOne = function(digits) { - var i = digits.length - 1 +var plusOne = function (digits) { + var i = digits.length - 1; while (digits[i] + 1 === 10) { - digits[i] = 0 - i -= 1 + digits[i] = 0; + i -= 1; } if (i < 0) { - digits.unshift(1) + digits.unshift(1); } else { - digits[i] += 1 + digits[i] += 1; } - return digits + return digits; }; diff --git a/javascript/0069-sqrtx.js b/javascript/0069-sqrtx.js index 62f41b53b..923de2635 100644 --- a/javascript/0069-sqrtx.js +++ b/javascript/0069-sqrtx.js @@ -1,24 +1,24 @@ /** - * Binary Search + * Binary Search * https://leetcode.com/problems/sqrtx/ - * + * * Time O(log(n)) | Space O(1) * @param {number} x * @return {number} */ -var mySqrt = function(x) { +var mySqrt = function (x) { let left = 1; let right = x; - - while(left <= right) { + + while (left <= right) { const mid = (left + right) >> 1; - if(mid * mid <= x && (mid+1) * (mid+1) > x) return mid; - if(mid * mid < x) { + if (mid * mid <= x && (mid + 1) * (mid + 1) > x) return mid; + if (mid * mid < x) { left = mid + 1; } else { - right = mid -1; + right = mid - 1; } - } - + } + return 0; - }; +}; diff --git a/javascript/0070-climbing-stairs.js b/javascript/0070-climbing-stairs.js index 4a9cf40e7..30d5dbb2e 100644 --- a/javascript/0070-climbing-stairs.js +++ b/javascript/0070-climbing-stairs.js @@ -5,19 +5,19 @@ * @param {number} n * @return {number} */ - var climbStairs = (n, index = 0) => { - const isBaseCase1 = (n < index); +var climbStairs = (n, index = 0) => { + const isBaseCase1 = n < index; if (isBaseCase1) return 0; - const isBaseCase2 = (index === n); + const isBaseCase2 = index === n; if (isBaseCase2) return 1; - const [ next, nextNext ] = [ (index + 1), (index + 2) ]; - const left = climbStairs(n, next); /* Time O(2^N) | Space O(N) */ - const right = climbStairs(n, nextNext);/* Time O(2^N) | Space O(N) */ + const [next, nextNext] = [index + 1, index + 2]; + const left = climbStairs(n, next); /* Time O(2^N) | Space O(N) */ + const right = climbStairs(n, nextNext); /* Time O(2^N) | Space O(N) */ - return (left + right); -} + return left + right; +}; /** * DP - Top Down @@ -28,20 +28,20 @@ * @return {number} */ var climbStairs = (n, index = 0, memo = Array(n + 1).fill(0)) => { - const isBaseCase1 = (n < index); + const isBaseCase1 = n < index; if (isBaseCase1) return 0; - const isBaseCase2 = (index === n); + const isBaseCase2 = index === n; if (isBaseCase2) return 1; - const hasSeen = (memo[index] !== 0); + const hasSeen = memo[index] !== 0; if (hasSeen) return memo[index]; - const [ next, nextNext ] = [ (index + 1), (index + 2) ]; - const left = climbStairs(n, next, memo); /* Time O(N) | Space O(N) */ - const right = climbStairs(n, nextNext, memo);/* Time O(N) | Space O(N) */ + const [next, nextNext] = [index + 1, index + 2]; + const left = climbStairs(n, next, memo); /* Time O(N) | Space O(N) */ + const right = climbStairs(n, nextNext, memo); /* Time O(N) | Space O(N) */ - memo[index] = (left + right); /* | Space O(N) */ + memo[index] = left + right; /* | Space O(N) */ return memo[index]; }; @@ -54,10 +54,10 @@ var climbStairs = (n, index = 0, memo = Array(n + 1).fill(0)) => { * @return {number} */ var climbStairs = (n) => { - const isBaseCase = (n === 1); + const isBaseCase = n === 1; if (isBaseCase) return 1; - const tabu = initTabu(n);/* Space O(N) */ + const tabu = initTabu(n); /* Space O(N) */ search(n, tabu); @@ -71,15 +71,16 @@ var initTabu = (n) => { tabu[2] = 2; return tabu; -} +}; var search = (n, tabu) => { - for (let index = 3; (index <= n); index++) {/* Time O(N) */ - const [ prev, prevPrev ] = [ (index - 1), (index - 2) ]; + for (let index = 3; index <= n; index++) { + /* Time O(N) */ + const [prev, prevPrev] = [index - 1, index - 2]; - tabu[index] = (tabu[prev] + tabu[prevPrev]);/* Space O(N) */ + tabu[index] = tabu[prev] + tabu[prevPrev]; /* Space O(N) */ } -} +}; /** * DP - Fibonacci Number @@ -89,14 +90,15 @@ var search = (n, tabu) => { * @return {number} */ var climbStairs = (n) => { - const isBaseCase = (n === 1); + const isBaseCase = n === 1; if (isBaseCase) return 1; - let [ next, nextNext ] = [ 1, 2 ]; + let [next, nextNext] = [1, 2]; + + for (let index = 3; index <= n; index++) { + /* Time O(N) */ + const temp = next + nextNext; - for (let index = 3; (index <= n); index++) {/* Time O(N) */ - const temp = (next + nextNext); - next = nextNext; nextNext = temp; } @@ -111,44 +113,50 @@ var climbStairs = (n) => { * @param {number} n * @return {number} */ - var climbStairs = (n) => { - const prev = [ [1, 1], [1, 0] ]; - const next = power(n, prev);/* Time O(log(N)) */ +var climbStairs = (n) => { + const prev = [ + [1, 1], + [1, 0], + ]; + const next = power(n, prev); /* Time O(log(N)) */ return next[0][0]; -} +}; -const power = (n, prev) => { - let next = [ [1, 0], [0, 1] ]; +const power = (n, prev) => { + let next = [ + [1, 0], + [0, 1], + ]; const isEmpty = () => n === 0; - while (!isEmpty()) {/* Time O(log(N)) */ + while (!isEmpty()) { + /* Time O(log(N)) */ const isBit = (n & 1) === 1; - if (isBit) next = multiply(next, prev);/* Time O(1) | Space O(1) */ + if (isBit) next = multiply(next, prev); /* Time O(1) | Space O(1) */ n >>= 1; - prev = multiply(prev, prev); /* Time O(1) | Space O(1) */ + prev = multiply(prev, prev); /* Time O(1) | Space O(1) */ } return next; -} +}; const multiply = (prev, next) => { - const [ rows, cols ] = [ 2, 2 ]; - const matrix = new Array(rows).fill() - .map(() => new Array(cols).fill(0)); + const [rows, cols] = [2, 2]; + const matrix = new Array(rows).fill().map(() => new Array(cols).fill(0)); - for (let row = 0; (row < rows); row++) { - for (let col = 0; (col < cols); col++) { - const left = (prev[row][0] * next[0][col]); - const right = (prev[row][1] * next[1][col]); + for (let row = 0; row < rows; row++) { + for (let col = 0; col < cols; col++) { + const left = prev[row][0] * next[0][col]; + const right = prev[row][1] * next[1][col]; - matrix[row][col] = (left + right); + matrix[row][col] = left + right; } } return matrix; -} +}; /** * Math - Fibonacci Formula @@ -158,11 +166,11 @@ const multiply = (prev, next) => { * @return {number} */ var climbStairs = (n, sqrt5 = Math.sqrt(5)) => { - const phi = ((sqrt5 + 1) / 2); - const psi = ((sqrt5 - 1) / 2); + const phi = (sqrt5 + 1) / 2; + const psi = (sqrt5 - 1) / 2; - const phiPow = Math.pow(phi, (n + 1)); - const psiPow = Math.pow(psi, (n + 1)); + const phiPow = Math.pow(phi, n + 1); + const psiPow = Math.pow(psi, n + 1); - return ((phiPow - psiPow) / sqrt5); -} + return (phiPow - psiPow) / sqrt5; +}; diff --git a/javascript/0071-simplify-path.js b/javascript/0071-simplify-path.js index 0bdaef80b..4089b0962 100644 --- a/javascript/0071-simplify-path.js +++ b/javascript/0071-simplify-path.js @@ -1,4 +1,3 @@ - /** * Stack * Time O(N) | Space O(N) @@ -6,7 +5,7 @@ * @param {string} path * @return {string} */ -var simplifyPath = (path, slash = '/', stack = []) => { +var simplifyPath = (path, slash = '/', stack = []) => { const paths = path.split(slash).filter(Boolean); for (const _path of paths) traversePath(_path, stack); @@ -20,17 +19,13 @@ const traversePath = (path, stack) => { if (canPop(path, stack)) stack.pop(); }; -const canPush = (path) => !( - isCurrentDirectory(path) || - isParentDirectory(path) -); +const canPush = (path) => + !(isCurrentDirectory(path) || isParentDirectory(path)); -const canPop = (path, stack) => - isParentDirectory(path) && - !isEmpty(stack); +const canPop = (path, stack) => isParentDirectory(path) && !isEmpty(stack); -const isCurrentDirectory = (path) => (path === '.'); +const isCurrentDirectory = (path) => path === '.'; -const isParentDirectory = (path) => (path === '..'); +const isParentDirectory = (path) => path === '..'; -const isEmpty = ({ length }) => (0 === length); +const isEmpty = ({ length }) => 0 === length; diff --git a/javascript/0072-edit-distance.js b/javascript/0072-edit-distance.js index d4522c974..7303c0b67 100644 --- a/javascript/0072-edit-distance.js +++ b/javascript/0072-edit-distance.js @@ -6,29 +6,55 @@ * @param {string} word2 * @return {number} */ - var minDistance = (word1, word2, i = 0, j = 0) => { - const isBaseCase1 = ((word1.length * word2.length) === 0); - if (isBaseCase1) return (word1.length + word2.length); +var minDistance = (word1, word2, i = 0, j = 0) => { + const isBaseCase1 = word1.length * word2.length === 0; + if (isBaseCase1) return word1.length + word2.length; - const isBaseCase2 = (word1.length === i); - if (isBaseCase2) return (word2.length - j); + const isBaseCase2 = word1.length === i; + if (isBaseCase2) return word2.length - j; - const isBaseCase3 = (word2.length === j); - if (isBaseCase3) return (word1.length - i); + const isBaseCase3 = word2.length === j; + if (isBaseCase3) return word1.length - i; - return dfs(word1, word2, i, j);/* Time O(2^(N + M)) | Space O((N * M) + HEIGHT) */ -} + return dfs( + word1, + word2, + i, + j, + ); /* Time O(2^(N + M)) | Space O((N * M) + HEIGHT) */ +}; var dfs = (word1, word2, i, j) => { - const isEqual = (word1[i] === word2[j]); - if (isEqual) return minDistance(word1, word2, (i + 1), (j + 1));/* Time O(2^(N + M)) | Space O((N * M) + HEIGHT) */ - - const insert = minDistance(word1, word2, i, (j + 1)); /* Time O(2^(N + M)) | Space O((N * M) + HEIGHT) */ - const _delete = minDistance(word1, word2, (i + 1), j); /* Time O(2^(N + M)) | Space O((N * M) + HEIGHT) */ - const replace = minDistance(word1, word2, (i + 1), (j + 1)); /* Time O(2^(N + M)) | Space O((N * M) + HEIGHT) */ - - return (Math.min(insert, _delete, replace) + 1); -} + const isEqual = word1[i] === word2[j]; + if (isEqual) + return minDistance( + word1, + word2, + i + 1, + j + 1, + ); /* Time O(2^(N + M)) | Space O((N * M) + HEIGHT) */ + + const insert = minDistance( + word1, + word2, + i, + j + 1, + ); /* Time O(2^(N + M)) | Space O((N * M) + HEIGHT) */ + const _delete = minDistance( + word1, + word2, + i + 1, + j, + ); /* Time O(2^(N + M)) | Space O((N * M) + HEIGHT) */ + const replace = minDistance( + word1, + word2, + i + 1, + j + 1, + ); /* Time O(2^(N + M)) | Space O((N * M) + HEIGHT) */ + + return Math.min(insert, _delete, replace) + 1; +}; /** * DP - Top Down @@ -39,39 +65,81 @@ var dfs = (word1, word2, i, j) => { * @param {string} word2 * @return {number} */ - var minDistance = (word1, word2, i = 0, j = 0, memo = initMemo(word1, word2)) => { - const isBaseCase1 = ((word1.length * word2.length) === 0); - if (isBaseCase1) return (word1.length + word2.length); - - const isBaseCase2 = (word1.length === i); - if (isBaseCase2) return (word2.length - j); - - const isBaseCase3 = (word2.length === j); - if (isBaseCase3) return (word1.length - i); - - const hasSeen = (memo[i][j] !== -1); +var minDistance = ( + word1, + word2, + i = 0, + j = 0, + memo = initMemo(word1, word2), +) => { + const isBaseCase1 = word1.length * word2.length === 0; + if (isBaseCase1) return word1.length + word2.length; + + const isBaseCase2 = word1.length === i; + if (isBaseCase2) return word2.length - j; + + const isBaseCase3 = word2.length === j; + if (isBaseCase3) return word1.length - i; + + const hasSeen = memo[i][j] !== -1; if (hasSeen) return memo[i][j]; - return dfs(word1, word2, i, j, memo);/* Time O(N * M) | Space O((N * M) + HEIGHT) */ -} - -var initMemo = (word1, word2) => new Array(word1.length).fill()/* Time O(N) | Space O(N) */ - .map(() => new Array(word2.length).fill(-1)); /* Time O(N) | Space O(N) */ + return dfs( + word1, + word2, + i, + j, + memo, + ); /* Time O(N * M) | Space O((N * M) + HEIGHT) */ +}; + +var initMemo = (word1, word2) => + new Array(word1.length) + .fill() /* Time O(N) | Space O(N) */ + .map(() => + new Array(word2.length).fill(-1), + ); /* Time O(N) | Space O(N) */ var dfs = (word1, word2, i, j, memo) => { - const isEqual = (word1[i] === word2[j]); + const isEqual = word1[i] === word2[j]; if (isEqual) { - memo[i][j] = minDistance(word1, word2, (i + 1), (j + 1), memo);/* Time O(N * M) | Space O(HEIGHT) */ + memo[i][j] = minDistance( + word1, + word2, + i + 1, + j + 1, + memo, + ); /* Time O(N * M) | Space O(HEIGHT) */ return memo[i][j]; } - const insert = minDistance(word1, word2, i, (j + 1), memo); /* Time O(N * M) | Space O(HEIGHT) */ - const _delete = minDistance(word1, word2, (i + 1), j, memo); /* Time O(N * M) | Space O(HEIGHT) */ - const replace = minDistance(word1, word2, (i + 1), (j + 1), memo); /* Time O(N * M) | Space O(HEIGHT) */ - - memo[i][j] = (Math.min(insert, _delete, replace) + 1); /* | Space O(N * M) */ + const insert = minDistance( + word1, + word2, + i, + j + 1, + memo, + ); /* Time O(N * M) | Space O(HEIGHT) */ + const _delete = minDistance( + word1, + word2, + i + 1, + j, + memo, + ); /* Time O(N * M) | Space O(HEIGHT) */ + const replace = minDistance( + word1, + word2, + i + 1, + j + 1, + memo, + ); /* Time O(N * M) | Space O(HEIGHT) */ + + memo[i][j] = + Math.min(insert, _delete, replace) + + 1; /* | Space O(N * M) */ return memo[i][j]; -} +}; /** * DP - Bottom Up @@ -83,44 +151,51 @@ var dfs = (word1, word2, i, j, memo) => { * @return {number} */ var minDistance = (word1, word2) => { - const isEmpty = ((word1.length * word2.length) === 0); - if (isEmpty) return (word1.length + word2.length); + const isEmpty = word1.length * word2.length === 0; + if (isEmpty) return word1.length + word2.length; - const tabu = initTabu(word1, word2);/* Time O(N * M) | Space O(N * M) */ + const tabu = initTabu(word1, word2); /* Time O(N * M) | Space O(N * M) */ - search(word1, word2, tabu); /* Time O(N * M) | Space O(N * M) */ + search(word1, word2, tabu); /* Time O(N * M) | Space O(N * M) */ return tabu[word1.length][word2.length]; -} +}; var initTabu = (word1, word2) => { - const tabu = new Array((word1.length + 1)).fill()/* Time O(N) | Space O(N) */ - .map(() => new Array((word2.length + 1)).fill(0));/* Time O(M) | Space O(M) */ - - for (let i = 0; (i < (word1.length + 1)); i++) { /* Time O(N) */ - tabu[i][0] = i; /* | Space O(N * M) */ + const tabu = new Array(word1.length + 1) + .fill() /* Time O(N) | Space O(N) */ + .map(() => + new Array(word2.length + 1).fill(0), + ); /* Time O(M) | Space O(M) */ + + for (let i = 0; i < word1.length + 1; i++) { + /* Time O(N) */ + tabu[i][0] = i; /* | Space O(N * M) */ } - for (let j = 0; (j < (word2.length + 1)); j++) { /* Time O(M) */ - tabu[0][j] = j; /* | Space O(N * M) */ + for (let j = 0; j < word2.length + 1; j++) { + /* Time O(M) */ + tabu[0][j] = j; /* | Space O(N * M) */ } return tabu; -} +}; var search = (word1, word2, tabu) => { - for (let i = 1; (i < (word1.length + 1)); i++) {/* Time O(N) */ - for (let j = 1; (j < (word2.length + 1)); j++) {/* Time O(M) */ - const left = (tabu[(i - 1)][j] + 1); - const down = (tabu[i][(j - 1)] + 1); + for (let i = 1; i < word1.length + 1; i++) { + /* Time O(N) */ + for (let j = 1; j < word2.length + 1; j++) { + /* Time O(M) */ + const left = tabu[i - 1][j] + 1; + const down = tabu[i][j - 1] + 1; - const isEqual = (word1[(i - 1)] === word2[(j - 1)]); - const leftDown = (tabu[(i - 1)][(j - 1)] + Number(!isEqual)); + const isEqual = word1[i - 1] === word2[j - 1]; + const leftDown = tabu[i - 1][j - 1] + Number(!isEqual); - tabu[i][j] = Math.min(left, down, leftDown); /* Space O(N * M) */ + tabu[i][j] = Math.min(left, down, leftDown); /* Space O(N * M) */ } } -} +}; /** * DP - Bottom Up @@ -131,42 +206,52 @@ var search = (word1, word2, tabu) => { * @param {string} word2 * @return {number} */ - var minDistance = (word1, word2) => { - const tabu = initTabu(word2);/* Time O(M) | Space O(M) */ +var minDistance = (word1, word2) => { + const tabu = initTabu(word2); /* Time O(M) | Space O(M) */ - search(word1, word2, tabu); /* Time O(N * M) | Space O(M) */ + search(word1, word2, tabu); /* Time O(N * M) | Space O(M) */ return tabu[word2.length]; -} +}; var initTabu = (word2) => { - const tabu = new Array((word2.length + 1)).fill(0);/* Time O(M) | Space O(M) */ + const tabu = new Array(word2.length + 1).fill( + 0, + ); /* Time O(M) | Space O(M) */ - for (let j = 1; (j <= word2.length); j++) { /* Time O(M) */ - tabu[j] = j; /* | Space O(M) */ + for (let j = 1; j <= word2.length; j++) { + /* Time O(M) */ + tabu[j] = j; /* | Space O(M) */ } return tabu; -} +}; var search = (word1, word2, tabu) => { - for (let i = 1; (i <= word1.length); i++) {/* Time O(N) */ - tabu[word2.length] = update(word1, word2, i, tabu);/* Time O(M) | Space (M) */ + for (let i = 1; i <= word1.length; i++) { + /* Time O(N) */ + tabu[word2.length] = update( + word1, + word2, + i, + tabu, + ); /* Time O(M) | Space (M) */ } -} +}; const update = (word1, word2, i, tabu) => { let temp = i; - for (let j = 1; (j <= word2.length); ++j) {/* Time O(M */ - const isEqual = (word1[(i - 1)] === word2[(j - 1)]) + for (let j = 1; j <= word2.length; ++j) { + /* Time O(M */ + const isEqual = word1[i - 1] === word2[j - 1]; const cur = isEqual - ? tabu[(j - 1)] - : (Math.min(tabu[(j - 1)], tabu[j], temp) + 1); + ? tabu[j - 1] + : Math.min(tabu[j - 1], tabu[j], temp) + 1; - tabu[(j - 1)] = temp; /* Space (M) */ + tabu[j - 1] = temp; /* Space (M) */ temp = cur; } return temp; -} \ No newline at end of file +}; diff --git a/javascript/0073-set-matrix-zeroes.js b/javascript/0073-set-matrix-zeroes.js index 1d34684c6..e0f1ee4d0 100644 --- a/javascript/0073-set-matrix-zeroes.js +++ b/javascript/0073-set-matrix-zeroes.js @@ -6,45 +6,53 @@ * @param {number[][]} matrix * @return {void} Do not return anything, modify matrix in-place instead. */ - var setZeroes = function (matrix) { - const [ rows, cols ] = [ matrix.length, matrix[0].length ]; - const [ _row, _col ] = initTabu(rows, cols);/* Space (ROWS + COLS) */ - - fillPlacements(matrix, _row, _col); /* Time O(ROWS * COLS) | Space (ROWS + COLS) */ - setZero(matrix, _row, _col); /* Time O(ROWS * COLS) */ +var setZeroes = function (matrix) { + const [rows, cols] = [matrix.length, matrix[0].length]; + const [_row, _col] = initTabu(rows, cols); /* Space (ROWS + COLS) */ + + fillPlacements( + matrix, + _row, + _col, + ); /* Time O(ROWS * COLS) | Space (ROWS + COLS) */ + setZero(matrix, _row, _col); /* Time O(ROWS * COLS) */ }; const initTabu = (rows, cols) => [ - new Array(rows).fill(1),/* Space O(ROWS) */ - new Array(cols).fill(1) /* Space O(COLS) */ + new Array(rows).fill(1) /* Space O(ROWS) */, + new Array(cols).fill(1) /* Space O(COLS) */, ]; const fillPlacements = (matrix, _row, _col) => { - const [ rows, cols ] = [ matrix.length, matrix[0].length ]; + const [rows, cols] = [matrix.length, matrix[0].length]; - for (let row = 0; (row < rows); row++) {/* Time (ROWS) */ - for (let col = 0; (col < cols); col++) {/* Time (COLS) */ - const isZero = (matrix[row][col] === 0); + for (let row = 0; row < rows; row++) { + /* Time (ROWS) */ + for (let col = 0; col < cols; col++) { + /* Time (COLS) */ + const isZero = matrix[row][col] === 0; if (!isZero) continue; - _row[row] = 0; /* Space (ROWS) */ - _col[col] = 0; /* Space (COLS) */ + _row[row] = 0; /* Space (ROWS) */ + _col[col] = 0; /* Space (COLS) */ } } -} +}; const setZero = (matrix, _row, _col) => { - const [ rows, cols ] = [ matrix.length, matrix[0].length ]; + const [rows, cols] = [matrix.length, matrix[0].length]; - for (let row = 0; (row < rows); row++) {/* Time (ROWS) */ - for (let col = 0; (col < cols); col++) {/* Time (COLS) */ - const canSet = ((_row[row] === 0) || (_col[col] === 0)); + for (let row = 0; row < rows; row++) { + /* Time (ROWS) */ + for (let col = 0; col < cols; col++) { + /* Time (COLS) */ + const canSet = _row[row] === 0 || _col[col] === 0; if (!canSet) continue; matrix[row][col] = 0; } } -} +}; /** * Constant Space @@ -54,20 +62,22 @@ const setZero = (matrix, _row, _col) => { * @return {void} Do not return anything, modify matrix in-place instead. */ var setZeroes = (matrix) => { - const _isColZero = isColZero(matrix);/* Time O(ROWS) */ + const _isColZero = isColZero(matrix); /* Time O(ROWS) */ - setEdgesToZero(matrix); /* Time O(ROWS) */ - setCellsToZero(matrix, _isColZero); /* Time O(ROWS * COLS) */ -} + setEdgesToZero(matrix); /* Time O(ROWS) */ + setCellsToZero(matrix, _isColZero); /* Time O(ROWS * COLS) */ +}; -var isColZero = (matrix) => matrix - .some((row) => row[0] === 0);/* Time O(ROWS) */ +var isColZero = (matrix) => + matrix.some((row) => row[0] === 0); /* Time O(ROWS) */ var setEdgesToZero = (matrix) => { - const [ rows, cols ] = [ matrix.length, matrix[0].length ]; + const [rows, cols] = [matrix.length, matrix[0].length]; - for (let row = 0; (row < rows); row++) {/* Time (ROWS) */ - for (let col = 1; (col < cols); col++) {/* Time (COLS) */ + for (let row = 0; row < rows; row++) { + /* Time (ROWS) */ + for (let col = 1; col < cols; col++) { + /* Time (COLS) */ const canSet = matrix[row][col] === 0; if (!canSet) continue; @@ -75,13 +85,15 @@ var setEdgesToZero = (matrix) => { matrix[0][col] = 0; } } -} +}; var setCellsToZero = (matrix, isColZero) => { - const [ rows, cols ] = [ matrix.length, matrix[0].length ]; + const [rows, cols] = [matrix.length, matrix[0].length]; - for (let row = (rows - 1); (0 <= row); row--) {/* Time (ROWS) */ - for (let col = (cols - 1); (1 <= col); col--) {/* Time (COLS) */ + for (let row = rows - 1; 0 <= row; row--) { + /* Time (ROWS) */ + for (let col = cols - 1; 1 <= col; col--) { + /* Time (COLS) */ if (!isZero(matrix, row, col)) continue; matrix[row][col] = 0; @@ -89,13 +101,13 @@ var setCellsToZero = (matrix, isColZero) => { if (isColZero) matrix[row][0] = 0; } -} +}; var isZero = (matrix, row, col) => { - const [ rowLeftEdge, colTopEdge ] = [ matrix[row][0], matrix[0][col] ]; + const [rowLeftEdge, colTopEdge] = [matrix[row][0], matrix[0][col]]; - return ((rowLeftEdge === 0) || (colTopEdge === 0)); -} + return rowLeftEdge === 0 || colTopEdge === 0; +}; /** * Constant Space @@ -104,56 +116,62 @@ var isZero = (matrix, row, col) => { * @param {number[][]} matrix * @return {void} Do not return anything, modify matrix in-place instead. */ - var setZeroes = (matrix) => { - const isColZero = setEdgesToZero(matrix);/* Time O(ROWS * COLS) */ +var setZeroes = (matrix) => { + const isColZero = setEdgesToZero(matrix); /* Time O(ROWS * COLS) */ - setCellsToZero(matrix); /* Time O(ROWS * COLS) */ + setCellsToZero(matrix); /* Time O(ROWS * COLS) */ - const isZero = (matrix[0][0] === 0); - if (isZero) setFirstRowZero(matrix); /* Time O(COLS) */ + const isZero = matrix[0][0] === 0; + if (isZero) setFirstRowZero(matrix); /* Time O(COLS) */ - if (isColZero) setFirstColZero(matrix); /* Time O(ROWS) */ -} + if (isColZero) setFirstColZero(matrix); /* Time O(ROWS) */ +}; var setCellsToZero = (matrix) => { - const [ rows, cols ] = [ matrix.length, matrix[0].length ]; + const [rows, cols] = [matrix.length, matrix[0].length]; - for (let row = 1; (row < rows); row++) {/* Time O(ROWS) */ - for (let col = 1; (col < cols); col++) {/* Time O(COLS) */ - const isZero = ((matrix[row][0] === 0) || (matrix[0][col] == 0)); + for (let row = 1; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 1; col < cols; col++) { + /* Time O(COLS) */ + const isZero = matrix[row][0] === 0 || matrix[0][col] == 0; if (!isZero) continue; matrix[row][col] = 0; } } -} +}; var setEdgesToZero = (matrix, isColZero = false) => { - const [ rows, cols ] = [ matrix.length, matrix[0].length ]; + const [rows, cols] = [matrix.length, matrix[0].length]; - for (let row = 0; (row < rows); row++) {/* Time O(ROWS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ if (matrix[row][0] === 0) isColZero = true; - for (let col = 1; (col < cols); col++) {/* Time O(COLS) */ - const canSet = (matrix[row][col] === 0); + for (let col = 1; col < cols; col++) { + /* Time O(COLS) */ + const canSet = matrix[row][col] === 0; if (!canSet) continue; - + matrix[0][col] = 0; matrix[row][0] = 0; } } return isColZero; -} +}; -var setFirstRowZero = (matrix, cols = matrix[0].length) => { - for (let col = 0; (col < cols); col++) {/* Time O(COLS) */ +var setFirstRowZero = (matrix, cols = matrix[0].length) => { + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ matrix[0][col] = 0; } -} +}; var setFirstColZero = (matrix, rows = matrix.length) => { - for (let row = 0; (row < rows); row++) {/* Time O(ROWS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ matrix[row][0] = 0; } -} \ No newline at end of file +}; diff --git a/javascript/0074-search-a-2d-matrix.js b/javascript/0074-search-a-2d-matrix.js index d5231ee86..52169916e 100644 --- a/javascript/0074-search-a-2d-matrix.js +++ b/javascript/0074-search-a-2d-matrix.js @@ -7,34 +7,34 @@ * @param {number} target * @return {boolean} */ -var searchMatrix = function(matrix, target) { +var searchMatrix = function (matrix, target) { let [rows, cols] = [matrix.length, matrix[0].length]; - let [top, bot] = [0, rows-1]; - - while(top <= bot){ - let row = Math.floor((top + bot) / 2); - if(target > matrix[row][cols-1]) { + let [top, bot] = [0, rows - 1]; + + while (top <= bot) { + let row = Math.floor((top + bot) / 2); + if (target > matrix[row][cols - 1]) { top = row + 1; - } else if(target < matrix[row][0]) { - bot = row - 1; + } else if (target < matrix[row][0]) { + bot = row - 1; } else { break; } } - - if(!(top <= bot)) { + + if (!(top <= bot)) { return false; } - + let row = Math.floor((top + bot) / 2); - let [l, r] = [0, cols-1]; - while(l<=r){ - let m = Math.floor((l + r) /2); - if(target > matrix[row][m]) { - l = m +1; - } else if(target < matrix[row][m]) { + let [l, r] = [0, cols - 1]; + while (l <= r) { + let m = Math.floor((l + r) / 2); + if (target > matrix[row][m]) { + l = m + 1; + } else if (target < matrix[row][m]) { r = m - 1; - } else if(target == matrix[row][m]) { + } else if (target == matrix[row][m]) { return true; } } diff --git a/javascript/0075-sort-colors.js b/javascript/0075-sort-colors.js index ec2d37752..f827004f5 100644 --- a/javascript/0075-sort-colors.js +++ b/javascript/0075-sort-colors.js @@ -1,21 +1,19 @@ // problem link https://leetcode.com/problems/sort-colors // brute force approche O(n^2); -var sortColors = function(nums) { - - for(let i = 0; i < nums.length; i++) { - for(let j = i +1; j < nums.length; j++) { - if(nums[j] < nums[i]) { +var sortColors = function (nums) { + for (let i = 0; i < nums.length; i++) { + for (let j = i + 1; j < nums.length; j++) { + if (nums[j] < nums[i]) { swap(nums, j, i); } } - } - + } + return nums; - }; - -function swap(nums, j, i) { +}; +function swap(nums, j, i) { const temp = nums[j]; nums[j] = nums[i]; nums[i] = temp; @@ -24,28 +22,27 @@ function swap(nums, j, i) { // optimized approche O(n); function sortColors(nums) { - let i = 0; let l = 0; let r = nums.length - 1; - - while(i <= r) { + + while (i <= r) { const num = nums[i]; - if(num === 0) { - swap(nums,i,l); + if (num === 0) { + swap(nums, i, l); i++; l++; - } else if(num === 2) { - swap(nums,i,r); + } else if (num === 2) { + swap(nums, i, r); r--; } else { i++; } - } - + } + return nums; - } - - function swap(nums,i,j) { - [nums[i], nums[j]] = [nums[j],nums[i]]; - } +} + +function swap(nums, i, j) { + [nums[i], nums[j]] = [nums[j], nums[i]]; +} diff --git a/javascript/0078-subsets.js b/javascript/0078-subsets.js index e467f0ea8..fa6850a73 100644 --- a/javascript/0078-subsets.js +++ b/javascript/0078-subsets.js @@ -1,53 +1,53 @@ -/** - * https://leetcode.com/problems/subsets/ - * Time O(N * 2^N) | Space(N) - * @param {number[]} nums - * @return {number[][]} - */ - var subsets = (nums) => { - nums.sort((a, b) => a -b); - - return dfs(nums) -} - -var dfs = (nums, level = 0, set = [], subset = []) => { - subset.push(set.slice()); - - for (let i = level; i < nums.length; i++){ - backTrack(nums, i, set, subset); - } - - return subset -} - -const backTrack = (nums, i, set, subset) => { - set.push(nums[i]); - dfs(nums, (i + 1), set, subset); - set.pop(); -} - -/** - * https://leetcode.com/problems/subsets/ - * Time O(N * 2^N) | Space(N * 2^N) - * @param {number[]} nums - * @return {number[][]} - */ - var subsets = (nums) => { - nums.sort((a, b) => a -b); - - return bfs(nums) -} - -const bfs = (nums, subsets = [[]]) => { - for (const num of nums) { - const levels = subsets.length - - for (let level = 0; level < levels; level++) { - const nextLevel = [ ...subsets[level], num ] - - subsets.push(nextLevel) - } - } - - return subsets -} +/** + * https://leetcode.com/problems/subsets/ + * Time O(N * 2^N) | Space(N) + * @param {number[]} nums + * @return {number[][]} + */ +var subsets = (nums) => { + nums.sort((a, b) => a - b); + + return dfs(nums); +}; + +var dfs = (nums, level = 0, set = [], subset = []) => { + subset.push(set.slice()); + + for (let i = level; i < nums.length; i++) { + backTrack(nums, i, set, subset); + } + + return subset; +}; + +const backTrack = (nums, i, set, subset) => { + set.push(nums[i]); + dfs(nums, i + 1, set, subset); + set.pop(); +}; + +/** + * https://leetcode.com/problems/subsets/ + * Time O(N * 2^N) | Space(N * 2^N) + * @param {number[]} nums + * @return {number[][]} + */ +var subsets = (nums) => { + nums.sort((a, b) => a - b); + + return bfs(nums); +}; + +const bfs = (nums, subsets = [[]]) => { + for (const num of nums) { + const levels = subsets.length; + + for (let level = 0; level < levels; level++) { + const nextLevel = [...subsets[level], num]; + + subsets.push(nextLevel); + } + } + + return subsets; +}; diff --git a/javascript/0079-word-search.js b/javascript/0079-word-search.js index f483a1831..5808ee855 100644 --- a/javascript/0079-word-search.js +++ b/javascript/0079-word-search.js @@ -5,41 +5,40 @@ * @param {string} word * @return {boolean} */ -var exist = function(board, word) { - for(let row = 0; row < board.length; row++) { - for(let col = 0; col < board[0].length; col++){ +var exist = function (board, word) { + for (let row = 0; row < board.length; row++) { + for (let col = 0; col < board[0].length; col++) { if (dfs(board, row, col, word, 0)) return true; } } return false; -} +}; const dfs = (board, row, col, word, index) => { if (index === word.length) return true; if (isOutOfBound(board, row, col)) return false; - if (board[row][col] !== word[index]) return false - + if (board[row][col] !== word[index]) return false; + board[row][col] = '*'; - - const hasWord = Object - .values(directions(row, col)) - .filter(([r, c]) => dfs(board, r, c, word, index + 1)) - .length - + + const hasWord = Object.values(directions(row, col)).filter(([r, c]) => + dfs(board, r, c, word, index + 1), + ).length; + board[row][col] = word[index]; return hasWord; -} +}; const isOutOfBound = (board, row, col) => { - const isRowOutOfBound = row < 0 || board.length - 1 < row - const isColOutOfBound = col < 0 || board[0].length - 1 < col - return isRowOutOfBound || isColOutOfBound -} + const isRowOutOfBound = row < 0 || board.length - 1 < row; + const isColOutOfBound = col < 0 || board[0].length - 1 < col; + return isRowOutOfBound || isColOutOfBound; +}; const directions = (row, col) => ({ up: [row - 1, col], down: [row + 1, col], - left: [row, col - 1,], - right: [row, col + 1] -}) + left: [row, col - 1], + right: [row, col + 1], +}); diff --git a/javascript/0080-remove-duplicates-from-sorted-array-ii.js b/javascript/0080-remove-duplicates-from-sorted-array-ii.js index 15eb88c99..c3a51b22a 100644 --- a/javascript/0080-remove-duplicates-from-sorted-array-ii.js +++ b/javascript/0080-remove-duplicates-from-sorted-array-ii.js @@ -1,44 +1,44 @@ /** -* https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/ -* -* Time O(n) | Space O(1) -* @param {number[]} nums -* @return {number} -*/ -var removeDuplicates = function(nums) { - let current = nums[0]; - let sameElCount = 0; + * https://leetcode.com/problems/remove-duplicates-from-sorted-array-ii/ + * + * Time O(n) | Space O(1) + * @param {number[]} nums + * @return {number} + */ +var removeDuplicates = function (nums) { + let current = nums[0]; + let sameElCount = 0; - for(let i = 0; i < nums.length; i++) { - if(current === nums[i]) { - sameElCount++; - } - if(current !== nums[i]) { - current = nums[i]; - sameElCount = 1; - } - if(sameElCount > 2) { - nums.splice(i,1); - i--; + for (let i = 0; i < nums.length; i++) { + if (current === nums[i]) { + sameElCount++; + } + if (current !== nums[i]) { + current = nums[i]; + sameElCount = 1; + } + if (sameElCount > 2) { + nums.splice(i, 1); + i--; + } } - } }; - /** -* Two pointer -* Time O(n^2) | Space O(1) -* @param {number[]} nums -* @return {number} -*/ -var removeDuplicates2 = function(nums) { - const isEdgeCase = (nums.length < 2) + * Two pointer + * Time O(n^2) | Space O(1) + * @param {number[]} nums + * @return {number} + */ +var removeDuplicates2 = function (nums) { + const isEdgeCase = nums.length < 2; if (isEdgeCase) return nums.length; - let [ left, right ] = [ 2, 2 ]; + let [left, right] = [2, 2]; - while (right < nums.length) {/* Time O(N) */ - const isEqual = (nums[(left - 2)] === nums[right]); + while (right < nums.length) { + /* Time O(N) */ + const isEqual = nums[left - 2] === nums[right]; if (!isEqual) { nums[left] = nums[right]; left += 1; diff --git a/javascript/0084-largest-rectangle-in-histogram.js b/javascript/0084-largest-rectangle-in-histogram.js index a05690713..e52d385a2 100644 --- a/javascript/0084-largest-rectangle-in-histogram.js +++ b/javascript/0084-largest-rectangle-in-histogram.js @@ -4,23 +4,26 @@ * @param {number[]} heights * @return {number} */ -var largestRectangleArea = function(heights, maxArea = 0) { - for (let i = 0; i < heights.length; i++) {/* Time O(N) */ - for (let j = i; j < heights.length; j++) {/* Time O(N) */ +var largestRectangleArea = function (heights, maxArea = 0) { + for (let i = 0; i < heights.length; i++) { + /* Time O(N) */ + for (let j = i; j < heights.length; j++) { + /* Time O(N) */ let min = Infinity; - for (let k = i; k <= j; k++) { /* Time O(N) */ + for (let k = i; k <= j; k++) { + /* Time O(N) */ min = Math.min(min, heights[k]); } - const area = min * ((j - i) + 1); + const area = min * (j - i + 1); maxArea = Math.max(maxArea, area); } } return maxArea; -} +}; /** * https://leetcode.com/problems/largest-rectangle-in-histogram/solution/ @@ -28,21 +31,23 @@ var largestRectangleArea = function(heights, maxArea = 0) { * @param {number[]} heights * @return {number} */ -var largestRectangleArea = function(heights, maxArea = 0) { - for (let i = 0; i < heights.length; i++) {/* Time O(N) */ +var largestRectangleArea = function (heights, maxArea = 0) { + for (let i = 0; i < heights.length; i++) { + /* Time O(N) */ let min = Infinity; - for (let j = i; j < heights.length; j++) {/* Time O(N) */ + for (let j = i; j < heights.length; j++) { + /* Time O(N) */ min = Math.min(min, heights[j]); - const area = min * ((j - i) + 1); + const area = min * (j - i + 1); maxArea = Math.max(maxArea, area); } } return maxArea; -} +}; /** * https://leetcode.com/problems/largest-rectangle-in-histogram/solution/ @@ -50,29 +55,46 @@ var largestRectangleArea = function(heights, maxArea = 0) { * @param {number[]} heights * @return {number} */ -var largestRectangleArea = function(heights, left = 0, right = (heights.length - 1)) { +var largestRectangleArea = function ( + heights, + left = 0, + right = heights.length - 1, +) { const isBaseCase = right < left; if (isBaseCase) return 0; - return divideAndConquer(heights, left, right); /* Time O(N^2) | Space O(N) */ -} + return divideAndConquer( + heights, + left, + right, + ); /* Time O(N^2) | Space O(N) */ +}; const divideAndConquer = (heights, left, right, min = left) => { - for (let i = left; i <= right; i++) { /* Time O(N) */ + for (let i = left; i <= right; i++) { + /* Time O(N) */ const isMinGreater = heights[i] < heights[min]; if (!isMinGreater) continue; min = i; } - const window = (right - left) + 1; + const window = right - left + 1; const area = heights[min] * window; - const leftArea = largestRectangleArea(heights, (min + 1), right)/* Time O(N^2) | Space O(N) */ - const rightArea = largestRectangleArea(heights, left, (min - 1))/* Time O(N^2) | Space O(N) */ + const leftArea = largestRectangleArea( + heights, + min + 1, + right, + ); /* Time O(N^2) | Space O(N) */ + const rightArea = largestRectangleArea( + heights, + left, + min - 1, + ); /* Time O(N^2) | Space O(N) */ return Math.max(area, leftArea, rightArea); -} +}; /** * https://leetcode.com/problems/largest-rectangle-in-histogram/solution/ @@ -80,20 +102,24 @@ const divideAndConquer = (heights, left, right, min = left) => { * @param {number[]} heights * @return {number} */ -var largestRectangleArea = function(heights) { - const { stack, maxArea } = fillStack(heights); /* Time O(N) | Space O(N) */ +var largestRectangleArea = function (heights) { + const { stack, maxArea } = fillStack(heights); /* Time O(N) | Space O(N) */ - return getMaxArea(heights, stack, maxArea); /* Time O(N) */ + return getMaxArea(heights, stack, maxArea); /* Time O(N) */ }; const fillStack = (heights, stack = [], maxArea = 0) => { - for (let index = 0; index < heights.length; index++) {/* Time O(N + N) */ + for (let index = 0; index < heights.length; index++) { + /* Time O(N + N) */ let start = index; - const isCurrHeightLess = ([ prevIndex, prevHeight ], currHeight) => currHeight < prevHeight; - const canShrink = () => isCurrHeightLess(stack[stack.length - 1], heights[index]); - while (stack.length && canShrink()) { /* Time O(N + N) */ - const [ _index, _height ] = stack.pop(); + const isCurrHeightLess = ([prevIndex, prevHeight], currHeight) => + currHeight < prevHeight; + const canShrink = () => + isCurrHeightLess(stack[stack.length - 1], heights[index]); + while (stack.length && canShrink()) { + /* Time O(N + N) */ + const [_index, _height] = stack.pop(); const width = index - _index; const area = _height * width; @@ -101,14 +127,15 @@ const fillStack = (heights, stack = [], maxArea = 0) => { start = _index; } - stack.push([ start, heights[index] ]); /* Space O(N) */ + stack.push([start, heights[index]]); /* Space O(N) */ } - return { stack, maxArea } -} + return { stack, maxArea }; +}; const getMaxArea = (heights, stack, maxArea) => { - for (const [ index, height ] of stack) { /* Time O(N) */ + for (const [index, height] of stack) { + /* Time O(N) */ const width = heights.length - index; const area = height * width; @@ -116,7 +143,4 @@ const getMaxArea = (heights, stack, maxArea) => { } return maxArea; -} - - - +}; diff --git a/javascript/0088-merge-sorted-array.js b/javascript/0088-merge-sorted-array.js index f6b3ac58c..875d1bfcc 100644 --- a/javascript/0088-merge-sorted-array.js +++ b/javascript/0088-merge-sorted-array.js @@ -1,5 +1,5 @@ /** - * Linear + * Linear * Time O(N) | Space O(1) * https://leetcode.com/problems/merge-sorted-array/ * @param {number[]} nums1 @@ -8,8 +8,7 @@ * @param {number} n * @return {void} Do not return anything, modify nums1 in-place instead. */ -var merge = function(nums1, m, nums2, n) { - +var merge = function (nums1, m, nums2, n) { let k = m + n - 1; m = m - 1; n = n - 1; diff --git a/javascript/0090-subsets-ii.js b/javascript/0090-subsets-ii.js index fd614fec8..57b49ddc2 100644 --- a/javascript/0090-subsets-ii.js +++ b/javascript/0090-subsets-ii.js @@ -4,31 +4,30 @@ * @param {number[]} nums * @return {number[][]} */ - var subsetsWithDup = function(nums) { +var subsetsWithDup = function (nums) { nums.sort((a, b) => a - b); return dfs(nums); }; const dfs = (nums, index = 0, set = [], subset = []) => { - subset.push(set.slice()) + subset.push(set.slice()); for (let i = index; i < nums.length; i++) { - const isDuplicate = (index < i) && (nums[i - 1] === nums[i]) + const isDuplicate = index < i && nums[i - 1] === nums[i]; if (isDuplicate) continue; backTrack(nums, i, set, subset); } - return subset -} + return subset; +}; const backTrack = (nums, i, set, subset) => { set.push(nums[i]); - dfs(nums, (i + 1), set, subset); + dfs(nums, i + 1, set, subset); set.pop(); -} - +}; /** * https://leetcode.com/problems/subsets-ii/ @@ -36,29 +35,27 @@ const backTrack = (nums, i, set, subset) => { * @param {number[]} nums * @return {number[][]} */ - var subsetsWithDup = (nums) => { +var subsetsWithDup = (nums) => { nums.sort((a, b) => a - b); - return bfs(nums) -} + return bfs(nums); +}; const bfs = (nums, subsets = [[]]) => { - let levels = subsets.length - 1 + let levels = subsets.length - 1; for (let i = 0; i < nums.length; i++) { - const isPrevDuplicate = (0 < i) && (nums[i - 1] === nums[i]) - const start = isPrevDuplicate - ? (levels + 1) - : 0 + const isPrevDuplicate = 0 < i && nums[i - 1] === nums[i]; + const start = isPrevDuplicate ? levels + 1 : 0; - levels = subsets.length - 1 + levels = subsets.length - 1; - for (let level = start; level < (levels + 1); level++) { - const nextLevel = [ ...subsets[level], nums[i] ] + for (let level = start; level < levels + 1; level++) { + const nextLevel = [...subsets[level], nums[i]]; - subsets.push(nextLevel) + subsets.push(nextLevel); } } - return subsets -} \ No newline at end of file + return subsets; +}; diff --git a/javascript/0091-decode-ways.js b/javascript/0091-decode-ways.js index 74962cf5c..f1dc8a506 100644 --- a/javascript/0091-decode-ways.js +++ b/javascript/0091-decode-ways.js @@ -7,7 +7,7 @@ * @return {number} */ var numDecodings = (str, index = 0, memo = new Map()) => { - const isBaseCase1 = !str.length || (str[index] === '0'); + const isBaseCase1 = !str.length || str[index] === '0'; if (isBaseCase1) return 0; const isisBaseCase2 = index === str.length; @@ -19,22 +19,22 @@ var numDecodings = (str, index = 0, memo = new Map()) => { }; const dfs = (str, index, memo) => { - let count = numDecodings(str, (index + 1), memo); + let count = numDecodings(str, index + 1, memo); if (isTwoDigit(str, index)) { - count += numDecodings(str, (index + 2), memo); + count += numDecodings(str, index + 2, memo); } memo.set(index, count); return count; -} +}; var isTwoDigit = (str, index) => { - const twoDigit = Number(str.slice(index, (index + 2))); + const twoDigit = Number(str.slice(index, index + 2)); - return (10 <= twoDigit) && (twoDigit <= 26); -} + return 10 <= twoDigit && twoDigit <= 26; +}; /** * DP - Bottom Up @@ -45,7 +45,7 @@ var isTwoDigit = (str, index) => { * @return {number} */ var numDecodings = (s) => { - const isBaseCase = !s.length || s[0] === '0' + const isBaseCase = !s.length || s[0] === '0'; if (isBaseCase) return 0; const tabu = getTabu(s); @@ -53,34 +53,32 @@ var numDecodings = (s) => { decode(s, tabu); return tabu[s.length]; -} +}; const getTabu = (s) => { const tabu = new Array(s.length + 1).fill(0); tabu[0] = 1; - tabu[1] = (s[1] === '0') - ? 0 - : 1; + tabu[1] = s[1] === '0' ? 0 : 1; return tabu; -} +}; var decode = (s, tabu) => { for (let curr = 2; curr < tabu.length; curr++) { - const [ prev, prevPrev ] = [ (curr - 1), (curr - 2) ]; + const [prev, prevPrev] = [curr - 1, curr - 2]; const isEqual = s[prev] === '0'; if (!isEqual) tabu[curr] += tabu[prev]; if (isTwoDigit(s, curr)) tabu[curr] += tabu[prevPrev]; } -} +}; var isTwoDigit = (s, index) => { - const twoDigit = Number(s.slice((index - 2), index)); + const twoDigit = Number(s.slice(index - 2, index)); return 10 <= twoDigit && twoDigit <= 26; -} +}; /** * 2 Pointer - previous + previousPrevious @@ -94,10 +92,10 @@ var numDecodings = (s) => { if (isBaseCase) return 0; return decode(s); -} +}; var decode = (s) => { - let [ prev, prevPrev ] = [ 1, 1 ]; + let [prev, prevPrev] = [1, 1]; for (let curr = 1; curr < s.length; curr++) { const temp = prev; @@ -111,12 +109,12 @@ var decode = (s) => { } return prev; -} +}; var isTwoDigit = (s, i) => { - const [ prevChar, curChar ] = [ (s[i - 1]), s[i] ]; + const [prevChar, curChar] = [s[i - 1], s[i]]; const is10 = prevChar === '1'; - const is20 = (prevChar === '2' && curChar <= '6'); + const is20 = prevChar === '2' && curChar <= '6'; return is10 || is20; -} \ No newline at end of file +}; diff --git a/javascript/0093-restore-ip-addresses.js b/javascript/0093-restore-ip-addresses.js index 4e670d8ee..0133cb31f 100644 --- a/javascript/0093-restore-ip-addresses.js +++ b/javascript/0093-restore-ip-addresses.js @@ -26,7 +26,7 @@ var restoreIpAddresses = function (s) { backtracking( j + 1, dots + 1, - currentIP + s.slice(i, j + 1) + '.' + currentIP + s.slice(i, j + 1) + '.', ); } } diff --git a/javascript/0094-binary-tree-inorder-traversal.js b/javascript/0094-binary-tree-inorder-traversal.js index a590b39e7..ceda5b7d5 100644 --- a/javascript/0094-binary-tree-inorder-traversal.js +++ b/javascript/0094-binary-tree-inorder-traversal.js @@ -1,22 +1,21 @@ -/** - * Definition for a binary tree node. - * function TreeNode(val, left, right) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } - */ -/** - * @param {TreeNode} root - * @return {number[]} - */ - var inorderTraversal = function (root, list = []) { - - if (!root) return []; - - inorderTraversal(root.left, list); - list.push(root.val) - inorderTraversal(root.right, list); - - return list -}; +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @return {number[]} + */ +var inorderTraversal = function (root, list = []) { + if (!root) return []; + + inorderTraversal(root.left, list); + list.push(root.val); + inorderTraversal(root.right, list); + + return list; +}; diff --git a/javascript/0095-unique-binary-search-trees-ii.js b/javascript/0095-unique-binary-search-trees-ii.js index 7810bb5e1..1ccf54afe 100644 --- a/javascript/0095-unique-binary-search-trees-ii.js +++ b/javascript/0095-unique-binary-search-trees-ii.js @@ -9,39 +9,37 @@ /** * Recursion * Time O(4^n) | Space O(n) - * https://leetcode.com/problems/unique-binary-search-trees-ii/ + * https://leetcode.com/problems/unique-binary-search-trees-ii/ * @param {number} n * @return {TreeNode[]} */ -var generateTrees = function(n) { - +var generateTrees = function (n) { const dfs = (start, end) => { - const result = []; - if(start === end) { + if (start === end) { result.push(new TreeNode(start)); return result; - }; - if(start > end) { + } + if (start > end) { result.push(null); return result; - }; + } - for(let i = start; i < end + 1; i++) { + for (let i = start; i < end + 1; i++) { const leftSubTrees = dfs(start, i - 1); - const rightSubTrees = dfs(i + 1 , end); + const rightSubTrees = dfs(i + 1, end); leftSubTrees.forEach((leftSubTree) => { rightSubTrees.forEach((rightSubTree) => { - const root = new TreeNode(i, leftSubTree, rightSubTree); + const root = new TreeNode(i, leftSubTree, rightSubTree); result.push(root); }); - }); + }); } return result; - } + }; return dfs(1, n); }; diff --git a/javascript/0096-unique-binary-search-trees.js b/javascript/0096-unique-binary-search-trees.js index eabc140d7..fddd021be 100644 --- a/javascript/0096-unique-binary-search-trees.js +++ b/javascript/0096-unique-binary-search-trees.js @@ -5,22 +5,21 @@ * @param {number} n * @return {number} */ -var numTrees = function(n) { - +var numTrees = function (n) { const cache = {}; const dfs = (n) => { - if(n <= 1) return 1; - if(cache[n]) return cache[n]; + if (n <= 1) return 1; + if (cache[n]) return cache[n]; let total = 0; - for(let i = 0; i < n; i++) { + for (let i = 0; i < n; i++) { total += dfs(i) * dfs(n - 1 - i); } cache[n] = total; return total; - } + }; return dfs(n); }; diff --git a/javascript/0097-interleaving-string.js b/javascript/0097-interleaving-string.js index edb454ed9..dec1eba5f 100644 --- a/javascript/0097-interleaving-string.js +++ b/javascript/0097-interleaving-string.js @@ -7,25 +7,41 @@ * @param {string} s3 * @return {boolean} */ - var isInterleave = (s1, s2, s3, i = 0, j = 0, res = '') => { - const isBaseCase1 = (s3.length !== (s1.length + s2.length)); +var isInterleave = (s1, s2, s3, i = 0, j = 0, res = '') => { + const isBaseCase1 = s3.length !== s1.length + s2.length; if (isBaseCase1) return false; - const isBaseCase2 = ((res === s3) && (i == s1.length) && (j == s2.length)); + const isBaseCase2 = res === s3 && i == s1.length && j == s2.length; if (isBaseCase2) return true; - return dfs(s1, s2, s3, i, j, res);/* Time O(2^(N + M)) | Space O(N + M) */ -} + return dfs(s1, s2, s3, i, j, res); /* Time O(2^(N + M)) | Space O(N + M) */ +}; var dfs = (s1, s2, s3, i, j, res, ans = false) => { - const hasLeft = (i < s1.length); - if (hasLeft) ans |= isInterleave(s1, s2, s3, (i + 1), j, `${res}${s1[i]}`); /* Time O(2^(N + M)) | Space O(N) */ - - const hasRight = (j < s2.length); - if (hasRight) ans |= isInterleave(s1, s2, s3, i, (j + 1), `${res}${s2[j]}`);/* Time O(2^(N + M)) | Space O(M) */ + const hasLeft = i < s1.length; + if (hasLeft) + ans |= isInterleave( + s1, + s2, + s3, + i + 1, + j, + `${res}${s1[i]}`, + ); /* Time O(2^(N + M)) | Space O(N) */ + + const hasRight = j < s2.length; + if (hasRight) + ans |= isInterleave( + s1, + s2, + s3, + i, + j + 1, + `${res}${s2[j]}`, + ); /* Time O(2^(N + M)) | Space O(M) */ return ans; -} +}; /** * DP - Top Down @@ -37,32 +53,74 @@ var dfs = (s1, s2, s3, i, j, res, ans = false) => { * @param {string} s3 * @return {boolean} */ -var isInterleave = (s1, s2, s3, i = 0, j = 0, k = 0, memo = initMemo(s1, s2)) => { - const isBaseCase1 = (s3.length !== (s1.length + s2.length)); +var isInterleave = ( + s1, + s2, + s3, + i = 0, + j = 0, + k = 0, + memo = initMemo(s1, s2), +) => { + const isBaseCase1 = s3.length !== s1.length + s2.length; if (isBaseCase1) return false; - const isBaseCase2 = (i === s1.length); - if (isBaseCase2) return (s2.slice(j) === s3.slice(k));/* Time O(M + K) | Space O(M + K) */ + const isBaseCase2 = i === s1.length; + if (isBaseCase2) + return s2.slice(j) === s3.slice(k); /* Time O(M + K) | Space O(M + K) */ - const isBaseCase3 = (j === s2.length); - if (isBaseCase3) return (s1.slice(i) === s3.slice(k));/* Time O(N + K) | Space O(N + K) */ + const isBaseCase3 = j === s2.length; + if (isBaseCase3) + return s1.slice(i) === s3.slice(k); /* Time O(N + K) | Space O(N + K) */ - const hasSeen = (memo[i][j] !== null); + const hasSeen = memo[i][j] !== null; if (hasSeen) return memo[i][j]; - return dfs(s1, s2, s3, i, j, k, memo);/* Time O(N * M) | Space O((N * M) + HEIGHT) */ -} + return dfs( + s1, + s2, + s3, + i, + j, + k, + memo, + ); /* Time O(N * M) | Space O((N * M) + HEIGHT) */ +}; -var initMemo = (s1, s2) => new Array(s1.length).fill()/* Time O(N) | Space O(N) */ - .map(() => new Array(s2.length).fill(null)); /* Time O(M) | Space O(M) */ +var initMemo = (s1, s2) => + new Array(s1.length) + .fill() /* Time O(N) | Space O(N) */ + .map(() => + new Array(s2.length).fill(null), + ); /* Time O(M) | Space O(M) */ var dfs = (s1, s2, s3, i, j, k, memo) => { - const left = ((s3[k] === s1[i]) && isInterleave(s1, s2, s3, (i + 1), j, (k + 1), memo)); /* Time O(N) | Space O(HEIGHT) */ - const right = ((s3[k] === s2[j]) && isInterleave(s1, s2, s3, i, (j + 1), (k + 1), memo));/* Time O(M) | Space O(HEIGHT) */ - - memo[i][j] = left || right; /* | Space O(N * M) */ + const left = + s3[k] === s1[i] && + isInterleave( + s1, + s2, + s3, + i + 1, + j, + k + 1, + memo, + ); /* Time O(N) | Space O(HEIGHT) */ + const right = + s3[k] === s2[j] && + isInterleave( + s1, + s2, + s3, + i, + j + 1, + k + 1, + memo, + ); /* Time O(M) | Space O(HEIGHT) */ + + memo[i][j] = left || right; /* | Space O(N * M) */ return memo[i][j]; -} +}; /** * DP - Bottom Up @@ -75,49 +133,58 @@ var dfs = (s1, s2, s3, i, j, k, memo) => { * @return {boolean} */ var isInterleave = (s1, s2, s3) => { - const isBaseCase = (s3.length !== s1.length + s2.length); + const isBaseCase = s3.length !== s1.length + s2.length; if (isBaseCase) return false; - const tabu = initTabu(s1, s2);/* Time O(N * M) | Space O(N * M) */ + const tabu = initTabu(s1, s2); /* Time O(N * M) | Space O(N * M) */ - search(s1, s2, s3, tabu); /* Time O(N * M) | Space O(N * M) */ + search(s1, s2, s3, tabu); /* Time O(N * M) | Space O(N * M) */ return tabu[s1.length][s2.length]; -} +}; -var initTabu = (s1, s2) => new Array((s1.length + 1)).fill()/* Time O(N) | Space O(N) */ - .map(() => new Array((s2.length + 1)).fill(null)) /* Time O(M) | Space O(M) */ +var initTabu = (s1, s2) => + new Array(s1.length + 1) + .fill() /* Time O(N) | Space O(N) */ + .map(() => + new Array(s2.length + 1).fill(null), + ); /* Time O(M) | Space O(M) */ var search = (s1, s2, s3, tabu) => { - const [ rows, cols ] = [ s1.length, s2.length ]; - - for (let row = 0; (row <= rows); row++) {/* Time O(N) */ - for (let col = 0; (col <= cols); col++) {/* Time O(M) */ - tabu[row][col] = /* Space O(N * M) */ + const [rows, cols] = [s1.length, s2.length]; + + for (let row = 0; row <= rows; row++) { + /* Time O(N) */ + for (let col = 0; col <= cols; col++) { + /* Time O(M) */ + tabu[row][col] = + /* Space O(N * M) */ hasMatch(s1, s2, s3, row, col, tabu); } } -} +}; var hasMatch = (s1, s2, s3, i, j, tabu) => { - const isBaseCase1 = ((i === 0) && (j === 0)); + const isBaseCase1 = i === 0 && j === 0; if (isBaseCase1) return true; - const isBaseCase2 = (i === 0); + const isBaseCase2 = i === 0; if (isBaseCase2) return getRight(i, j, s2, s3, tabu); - const isBaseCase3 = (j === 0); + const isBaseCase3 = j === 0; if (isBaseCase3) return getLeft(i, j, s1, s3, tabu); const left = getLeft(i, j, s1, s3, tabu); - const right = getRight(i, j, s2, s3, tabu) + const right = getRight(i, j, s2, s3, tabu); - return (left || right); -} + return left || right; +}; -var getLeft = (i, j, s1, s3, tabu) => ((tabu[(i - 1)][j] && s1[(i - 1)]) === s3[((i + j) - 1)]); +var getLeft = (i, j, s1, s3, tabu) => + (tabu[i - 1][j] && s1[i - 1]) === s3[i + j - 1]; -var getRight = (i, j, s2, s3, tabu) => ((tabu[i][(j - 1)] && s2[(j - 1)]) === s3[((i + j) - 1)]); +var getRight = (i, j, s2, s3, tabu) => + (tabu[i][j - 1] && s2[j - 1]) === s3[i + j - 1]; /** * DP - Bottom Up @@ -130,43 +197,45 @@ var getRight = (i, j, s2, s3, tabu) => ((tabu[i][(j - 1)] && s2[(j - 1)]) === s3 * @return {boolean} */ var isInterleave = (s1, s2, s3) => { - const isBaseCase = (s3.length !== (s1.length + s2.length)); + const isBaseCase = s3.length !== s1.length + s2.length; if (isBaseCase) return false; - const tabu = initTabu(s2);/* Time O(M) | Space O(M) */ + const tabu = initTabu(s2); /* Time O(M) | Space O(M) */ search(s1, s2, s3, tabu); /* Time O(N * M) | Space O(M) */ return tabu[s2.length]; }; -var initTabu = (s2) => new Array((s2.length + 1)).fill(false);/* Time O(M) | Space O(M) */ +var initTabu = (s2) => + new Array(s2.length + 1).fill(false); /* Time O(M) | Space O(M) */ var search = (s1, s2, s3, tabu) => { - const [ rows, cols ] = [ s1.length, s2.length ]; + const [rows, cols] = [s1.length, s2.length]; - for (let row = 0; (row <= rows); row++) {/* Time O(N)*/ - for (let col = 0; (col <= cols); col++) {/* Time O(M)*/ - tabu[col] = /* Space O(M)*/ - hasMatch(s1, s2, s3, row, col, tabu); + for (let row = 0; row <= rows; row++) { + /* Time O(N)*/ + for (let col = 0; col <= cols; col++) { + /* Time O(M)*/ + tabu[col] = /* Space O(M)*/ hasMatch(s1, s2, s3, row, col, tabu); } } -} +}; var hasMatch = (s1, s2, s3, i, j, tabu) => { - const isBaseCase1 = ((i === 0) && (j === 0)); + const isBaseCase1 = i === 0 && j === 0; if (isBaseCase1) return true; - const isBaseCase2 = (i === 0); - if (isBaseCase2) return getRight(i, j, s2, s3, tabu) + const isBaseCase2 = i === 0; + if (isBaseCase2) return getRight(i, j, s2, s3, tabu); - const isBaseCase3 = (j === 0); - if (isBaseCase3) return getLeft(i, j, s1, s3, tabu);; + const isBaseCase3 = j === 0; + if (isBaseCase3) return getLeft(i, j, s1, s3, tabu); return getLeft(i, j, s1, s3, tabu) || getRight(i, j, s2, s3, tabu); -} - -var getLeft = (i, j, s1, s3, tabu) => (tabu[j] && (s1[(i - 1)] === s3[((i + j) - 1)])); +}; -var getRight = (i, j, s2, s3, tabu) => (tabu[(j - 1)] && (s2[(j - 1)] === s3[((i + j) - 1)])); +var getLeft = (i, j, s1, s3, tabu) => tabu[j] && s1[i - 1] === s3[i + j - 1]; +var getRight = (i, j, s2, s3, tabu) => + tabu[j - 1] && s2[j - 1] === s3[i + j - 1]; diff --git a/javascript/0098-validate-binary-search-tree.js b/javascript/0098-validate-binary-search-tree.js index 6b6cc12ee..16c2dffd8 100644 --- a/javascript/0098-validate-binary-search-tree.js +++ b/javascript/0098-validate-binary-search-tree.js @@ -4,11 +4,11 @@ * @param {TreeNode} root * @return {boolean} */ -var isValidBST = function(root, min = -Infinity, max = Infinity) { +var isValidBST = function (root, min = -Infinity, max = Infinity) { const isBaseCase = root === null; if (isBaseCase) return true; - const isInvalid = (root.val <= min) || (max <= root.val); + const isInvalid = root.val <= min || max <= root.val; if (isInvalid) return false; return dfs(root, min, max); @@ -19,7 +19,7 @@ const dfs = (root, min, max) => { const right = isValidBST(root.right, root.val, max); return left && right; -} +}; // TODO /** * https://leetcode.com/problems/validate-binary-search-tree/ @@ -27,19 +27,19 @@ const dfs = (root, min, max) => { * @param {TreeNode} root * @return {boolean} */ - var isValidBST = function(root, prev = [ null ]) { +var isValidBST = function (root, prev = [null]) { const isBaseCase = root === null; if (isBaseCase) return true; if (!isValidBST(root.left, prev)) return false; - const isInvalid = (prev[0] !== null) && (root.val <= prev[0]); + const isInvalid = prev[0] !== null && root.val <= prev[0]; if (isInvalid) return false; prev[0] = root.val; return isValidBST(root.right, prev); -} +}; /** * https://leetcode.com/problems/validate-binary-search-tree/ @@ -47,14 +47,14 @@ const dfs = (root, min, max) => { * @param {TreeNode} root * @return {boolean} */ -var isValidBST = function(root, stack = []) { +var isValidBST = function (root, stack = []) { let prev = null; while (stack.length || root) { moveLeft(stack, root); root = stack.pop(); - const isInvalid = prev && (root.val <= prev.val); + const isInvalid = prev && root.val <= prev.val; if (isInvalid) return false; prev = root; @@ -62,11 +62,11 @@ var isValidBST = function(root, stack = []) { } return true; -} +}; const moveLeft = (stack, root) => { while (root) { stack.push(root); root = root.left; } -} \ No newline at end of file +}; diff --git a/javascript/0101-symmetric-tree.js b/javascript/0101-symmetric-tree.js index 8c311f51f..e956fda43 100644 --- a/javascript/0101-symmetric-tree.js +++ b/javascript/0101-symmetric-tree.js @@ -13,12 +13,11 @@ * @param {TreeNode} root * @return {boolean} */ -var isSymmetric = function(root) { +var isSymmetric = function (root) { return dfs(root.left, root.right); }; - -const dfs = (node1, node2) => { +const dfs = (node1, node2) => { if (!node1 && !node2) return true; if (node1 && !node2) return false; @@ -26,4 +25,4 @@ const dfs = (node1, node2) => { if (node1.val !== node2.val) return false; return dfs(node1.right, node2.left) && dfs(node1.left, node2.right); -} +}; diff --git a/javascript/0102-binary-tree-level-order-traversal.js b/javascript/0102-binary-tree-level-order-traversal.js index 62e4d2d83..7e2cc5fce 100644 --- a/javascript/0102-binary-tree-level-order-traversal.js +++ b/javascript/0102-binary-tree-level-order-traversal.js @@ -5,18 +5,19 @@ * @param {TreeNode} root * @return {number[][]} */ -var levelOrder = function(root) { +var levelOrder = function (root) { const isBaseCase = root === null; if (isBaseCase) return []; - return bfs([ root ]); + return bfs([root]); }; const bfs = (queue /* Space O(W) */, levels = []) => { - while (queue.length) { // Time O(N) + while (queue.length) { + // Time O(N) const level = []; - for (let i = (queue.length - 1); 0 <= i; i--) { + for (let i = queue.length - 1; 0 <= i; i--) { const node = queue.shift(); // Time O(N) ... This can be O(1) if we use an actual queue data structure if (node.left) queue.push(node.left); @@ -29,7 +30,7 @@ const bfs = (queue /* Space O(W) */, levels = []) => { } return levels; -} +}; /** * https://leetcode.com/problems/binary-tree-level-order-traversal/ @@ -37,7 +38,7 @@ const bfs = (queue /* Space O(W) */, levels = []) => { * @param {TreeNode} root * @return {number[]} */ - var levelOrder = function(root, level = 0, levels = []) { +var levelOrder = function (root, level = 0, levels = []) { const isBaseCase = root === null; if (isBaseCase) return levels; @@ -47,11 +48,11 @@ const bfs = (queue /* Space O(W) */, levels = []) => { levels[level].push(root.val); return dfs(root, level, levels); // Time O(N) | Space O(H) -} +}; const dfs = (root, level, levels) => { - if (root.left) levelOrder(root.left, (level + 1), levels); - if (root.right) levelOrder(root.right, (level + 1), levels); + if (root.left) levelOrder(root.left, level + 1, levels); + if (root.right) levelOrder(root.right, level + 1, levels); return levels; -} +}; diff --git a/javascript/0103-binary-tree-zigzag-level-order-traversal.js b/javascript/0103-binary-tree-zigzag-level-order-traversal.js index fccd8f7bf..a83e68076 100644 --- a/javascript/0103-binary-tree-zigzag-level-order-traversal.js +++ b/javascript/0103-binary-tree-zigzag-level-order-traversal.js @@ -6,36 +6,37 @@ * @return {number[][]} */ var zigzagLevelOrder = (root) => { - const isEdgeBase = (root === null); + const isEdgeBase = root === null; if (isEdgeBase) return []; - - return search(root);/* Time O(N) | Space O(N) */ + + return search(root); /* Time O(N) | Space O(N) */ }; var search = (root, isZigZag = true, order = []) => { - const queue = new Queue([ root ]); - - while (!queue.isEmpty()) { /* Time O(N) */ + const queue = new Queue([root]); + + while (!queue.isEmpty()) { + /* Time O(N) */ const levels = []; bfs(queue, isZigZag, levels); /* Time O(WIDTH) | Space O(WIDTH) */ - order.push(levels); /* Space O(N) */ + order.push(levels); /* Space O(N) */ isZigZag = !isZigZag; } - + return order; -} +}; const bfs = (queue, isZigZag, levels) => { - for (let level = queue.size(); (0 < level); level--) {/* Time O(WIDTH) */ + for (let level = queue.size(); 0 < level; level--) { + /* Time O(WIDTH) */ const { left, val, right } = queue.dequeue(); - - if (left) queue.enqueue(left); /* Space O(WIDTH) */ - if (right) queue.enqueue(right);/* Space O(WIDTH) */ - - levels.push(val); /* Space O(N) */ + + if (left) queue.enqueue(left); /* Space O(WIDTH) */ + if (right) queue.enqueue(right); /* Space O(WIDTH) */ + + levels.push(val); /* Space O(N) */ } if (!isZigZag) levels.reverse(); -} - +}; diff --git a/javascript/0104-maximum-depth-of-binary-tree.js b/javascript/0104-maximum-depth-of-binary-tree.js index 9b2b7a8af..ffb4310f3 100644 --- a/javascript/0104-maximum-depth-of-binary-tree.js +++ b/javascript/0104-maximum-depth-of-binary-tree.js @@ -4,7 +4,7 @@ * @param {TreeNode} root * @return {number} */ -var maxDepth = function(root) { +var maxDepth = function (root) { const isBaseCase = root === null; if (isBaseCase) return 0; @@ -26,7 +26,7 @@ const dfs = (root) => { * @param {TreeNode} root * @return {number} */ -var maxDepth = function(root) { +var maxDepth = function (root) { const isBaseCase = root === null; if (isBaseCase) return 0; @@ -52,22 +52,22 @@ const iterativeDfs = (stack, height = 0) => { * @param {TreeNode} root * @return {number} */ -var maxDepth = function(root) { +var maxDepth = function (root) { const isBaseCase = root === null; if (isBaseCase) return 0; - return bfs([[ root, 0 ]]); + return bfs([[root, 0]]); }; const bfs = (queue, height = 0) => { while (queue.length) { - for (let i = (queue.length - 1); 0 <= i; i--) { - const [ root, depth ] = queue.shift(); + for (let i = queue.length - 1; 0 <= i; i--) { + const [root, depth] = queue.shift(); - height = Math.max(height, (depth + 1)); + height = Math.max(height, depth + 1); - if (root.left) queue.push([ root.left, (depth + 1) ]); - if (root.right) queue.push([ root.right, (depth + 1) ]); + if (root.left) queue.push([root.left, depth + 1]); + if (root.right) queue.push([root.right, depth + 1]); } } diff --git a/javascript/0105-construct-binary-tree-from-preorder-and-inorder-traversal.js b/javascript/0105-construct-binary-tree-from-preorder-and-inorder-traversal.js index 53a6fccda..7267d0cde 100644 --- a/javascript/0105-construct-binary-tree-from-preorder-and-inorder-traversal.js +++ b/javascript/0105-construct-binary-tree-from-preorder-and-inorder-traversal.js @@ -1,62 +1,67 @@ -/** - * https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ - * Time O(N^2) | Space(H) - * @param {number[]} preorder - * @param {number[]} inorder - * @return {TreeNode} - */ - var buildTree = function(preorder, inorder) { - const isBaseCase = !preorder.length || !inorder.length; - if (isBaseCase) return null; - - return dfs(preorder, inorder); -} - -var dfs = (preorder, inorder) => { - const { leftInorder, mid, rightInorder } = getPointers(preorder, inorder); - const root = new TreeNode(inorder[mid]); - - root.left = buildTree(preorder, leftInorder); - root.right = buildTree(preorder, rightInorder); - - return root; -} - -const getPointers = (preorder, inorder) => { - const next = preorder.shift(); - const mid = inorder.indexOf(next); - const leftInorder = inorder.slice(0, mid); - const rightInorder = inorder.slice(mid + 1); - - return { leftInorder, mid, rightInorder }; -} - -/** - * https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ - * Time O(N) | Space(H) - * @param {number[]} preorder - * @param {number[]} inorder - * @return {TreeNode} - */ - var buildTree = function(preorder, inorder, max = -Infinity, indices = { preorder: 0, inorder: 0 }) { - const isBaseCase = preorder.length <= indices.inorder; - if (isBaseCase) return null; - - const isAtEnd = inorder[indices.inorder] === max; - if (isAtEnd) { - indices.inorder++; - return null; - } - - return dfs(preorder, inorder, max, indices); -} - -var dfs = (preorder, inorder, max, indices) => { - const val = preorder[indices.preorder++] - const root = new TreeNode(val); - - root.left = buildTree(preorder, inorder, root.val, indices); - root.right = buildTree(preorder, inorder, max, indices); - - return root; -} +/** + * https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ + * Time O(N^2) | Space(H) + * @param {number[]} preorder + * @param {number[]} inorder + * @return {TreeNode} + */ +var buildTree = function (preorder, inorder) { + const isBaseCase = !preorder.length || !inorder.length; + if (isBaseCase) return null; + + return dfs(preorder, inorder); +}; + +var dfs = (preorder, inorder) => { + const { leftInorder, mid, rightInorder } = getPointers(preorder, inorder); + const root = new TreeNode(inorder[mid]); + + root.left = buildTree(preorder, leftInorder); + root.right = buildTree(preorder, rightInorder); + + return root; +}; + +const getPointers = (preorder, inorder) => { + const next = preorder.shift(); + const mid = inorder.indexOf(next); + const leftInorder = inorder.slice(0, mid); + const rightInorder = inorder.slice(mid + 1); + + return { leftInorder, mid, rightInorder }; +}; + +/** + * https://leetcode.com/problems/construct-binary-tree-from-preorder-and-inorder-traversal/ + * Time O(N) | Space(H) + * @param {number[]} preorder + * @param {number[]} inorder + * @return {TreeNode} + */ +var buildTree = function ( + preorder, + inorder, + max = -Infinity, + indices = { preorder: 0, inorder: 0 }, +) { + const isBaseCase = preorder.length <= indices.inorder; + if (isBaseCase) return null; + + const isAtEnd = inorder[indices.inorder] === max; + if (isAtEnd) { + indices.inorder++; + return null; + } + + return dfs(preorder, inorder, max, indices); +}; + +var dfs = (preorder, inorder, max, indices) => { + const val = preorder[indices.preorder++]; + const root = new TreeNode(val); + + root.left = buildTree(preorder, inorder, root.val, indices); + root.right = buildTree(preorder, inorder, max, indices); + + return root; +}; diff --git a/javascript/0106-construct-binary-tree-from-inorder-and-postorder-traversal.js b/javascript/0106-construct-binary-tree-from-inorder-and-postorder-traversal.js index a5fa99148..a902086c9 100644 --- a/javascript/0106-construct-binary-tree-from-inorder-and-postorder-traversal.js +++ b/javascript/0106-construct-binary-tree-from-inorder-and-postorder-traversal.js @@ -14,23 +14,21 @@ * @param {number[]} postorder * @return {TreeNode} */ -var buildTree = function(inorder, postorder) { - - +var buildTree = function (inorder, postorder) { let globleIdx = inorder.length - 1; const dfs = (start, end) => { - if(start === end) { + if (start === end) { globleIdx--; return new TreeNode(inorder[start]); } - if(start > end) return null; + if (start > end) return null; let i = start; - while(i < end + 1){ - if(inorder[i] === postorder[globleIdx]) break; + while (i < end + 1) { + if (inorder[i] === postorder[globleIdx]) break; i++; } @@ -41,7 +39,7 @@ var buildTree = function(inorder, postorder) { currRoot.left = dfs(start, i - 1); return currRoot; - } + }; return dfs(0, globleIdx); }; diff --git a/javascript/0108-convert-sorted-array-to-binary-search-tree.js b/javascript/0108-convert-sorted-array-to-binary-search-tree.js index 77f799832..76a9cf56d 100644 --- a/javascript/0108-convert-sorted-array-to-binary-search-tree.js +++ b/javascript/0108-convert-sorted-array-to-binary-search-tree.js @@ -14,23 +14,33 @@ * @param {number[]} nums * @return {TreeNode} */ -var sortedArrayToBST = (nums, left = 0, right = (nums.length - 1)) => { - const isBaseCase = (right < left); +var sortedArrayToBST = (nums, left = 0, right = nums.length - 1) => { + const isBaseCase = right < left; if (isBaseCase) return null; - return dfs(nums, left, right);/* Time O(N) | Space O(log(N)) */ + return dfs(nums, left, right); /* Time O(N) | Space O(log(N)) */ }; var dfs = (nums, left, right) => { const mid = (left + right) >> 1; - const root = new TreeNode(nums[mid]); /* | Ignore Auxillary Space O(N) */ - - root.left = sortedArrayToBST(nums, left, (mid - 1)); /* Time O(N) | Space O(log(N)) */ - root.right = sortedArrayToBST(nums, (mid + 1), right);/* Time O(N) | Space O(log(N)) */ - + const root = new TreeNode( + nums[mid], + ); /* | Ignore Auxillary Space O(N) */ + + root.left = sortedArrayToBST( + nums, + left, + mid - 1, + ); /* Time O(N) | Space O(log(N)) */ + root.right = sortedArrayToBST( + nums, + mid + 1, + right, + ); /* Time O(N) | Space O(log(N)) */ + return root; -} +}; /** * DFS - Preorder | Right as mid @@ -39,26 +49,36 @@ var dfs = (nums, left, right) => { * @param {number[]} nums * @return {TreeNode} */ -var sortedArrayToBST = (nums, left = 0, right = (nums.length - 1)) => { - const isBaseCase = (right < left); +var sortedArrayToBST = (nums, left = 0, right = nums.length - 1) => { + const isBaseCase = right < left; if (isBaseCase) return null; - return dfs(nums, left, right);/* Time O(N) | Space O(log(N)) */ + return dfs(nums, left, right); /* Time O(N) | Space O(log(N)) */ }; var dfs = (nums, left, right) => { let mid = (left + right) >> 1; - - const isOdd = (((left + right) % 2) === 1); + + const isOdd = (left + right) % 2 === 1; if (isOdd) mid += 1; - const root = new TreeNode(nums[mid]); /* | Ignore Auxillary Space O(N) */ - - root.left = sortedArrayToBST(nums, left, (mid - 1)); /* Time O(N) | Space O(log(N)) */ - root.right = sortedArrayToBST(nums, (mid + 1), right);/* Time O(N) | Space O(log(N)) */ - + const root = new TreeNode( + nums[mid], + ); /* | Ignore Auxillary Space O(N) */ + + root.left = sortedArrayToBST( + nums, + left, + mid - 1, + ); /* Time O(N) | Space O(log(N)) */ + root.right = sortedArrayToBST( + nums, + mid + 1, + right, + ); /* Time O(N) | Space O(log(N)) */ + return root; -} +}; /** * DFS - Preorder | Random as mid @@ -67,23 +87,33 @@ var dfs = (nums, left, right) => { * @param {number[]} nums * @return {TreeNode} */ -var sortedArrayToBST = (nums, left = 0, right = (nums.length - 1)) => { - const isBaseCase = (right < left); +var sortedArrayToBST = (nums, left = 0, right = nums.length - 1) => { + const isBaseCase = right < left; if (isBaseCase) return null; - return dfs(nums, left, right);/* Time O(N) | Space O(log(N)) */ + return dfs(nums, left, right); /* Time O(N) | Space O(log(N)) */ }; var dfs = (nums, left, right) => { let mid = (left + right) >> 1; - - const isOdd = (((left + right) % 2) === 1); + + const isOdd = (left + right) % 2 === 1; if (isOdd) mid += Math.floor(Math.random() * 2); - const root = new TreeNode(nums[mid]); /* | Ignore Auxillary Space O(N) */ - - root.left = sortedArrayToBST(nums, left, (mid - 1)); /* Time O(N) | Space O(log(N)) */ - root.right = sortedArrayToBST(nums, (mid + 1), right);/* Time O(N) | Space O(log(N)) */ - + const root = new TreeNode( + nums[mid], + ); /* | Ignore Auxillary Space O(N) */ + + root.left = sortedArrayToBST( + nums, + left, + mid - 1, + ); /* Time O(N) | Space O(log(N)) */ + root.right = sortedArrayToBST( + nums, + mid + 1, + right, + ); /* Time O(N) | Space O(log(N)) */ + return root; -} +}; diff --git a/javascript/0110-balanced-binary-tree.js b/javascript/0110-balanced-binary-tree.js index 30dacdd8c..5b5e51252 100644 --- a/javascript/0110-balanced-binary-tree.js +++ b/javascript/0110-balanced-binary-tree.js @@ -4,21 +4,21 @@ * @param {TreeNode} root * @return {boolean} */ -var isBalanced = function(root) { +var isBalanced = function (root) { const isBaseCase = root === null; if (isBaseCase) return true; if (!isAcceptableHeight(root)) return false; if (!isChildBalanced(root)) return false; return true; -} +}; const isChildBalanced = (root) => { const left = isBalanced(root.left); const right = isBalanced(root.right); - return left && right -} + return left && right; +}; const isAcceptableHeight = (root) => { const left = getHeight(root.left); @@ -27,23 +27,23 @@ const isAcceptableHeight = (root) => { const difference = Math.abs(left - right); return difference <= 1; -} +}; const getHeight = (root) => { const isBaseCase = root === null; if (isBaseCase) return 0; return dfs(root); -} +}; var dfs = (root) => { - const left = getHeight(root.left) + const left = getHeight(root.left); const right = getHeight(root.right); const height = Math.max(left, right); return height + 1; -} +}; /** * https://leetcode.com/problems/balanced-binary-tree/ @@ -51,28 +51,31 @@ var dfs = (root) => { * @param {TreeNode} root * @return {boolean} */ - var isBalanced = function (root) { - const [ _height, _isBalanced ] = isRootBalanced(root); +var isBalanced = function (root) { + const [_height, _isBalanced] = isRootBalanced(root); return _isBalanced; }; var isRootBalanced = (root) => { - const isBaseCase = root === null - if (isBaseCase) return [ -1, true ]; + const isBaseCase = root === null; + if (isBaseCase) return [-1, true]; - return dfs(root) -} + return dfs(root); +}; var dfs = (root) => { - const [ left, isLeftBalanced ] = isRootBalanced(root.left); - const [ right, isRightBalanced ] = isRootBalanced(root.right); - const [ height, difference ] = [ Math.max(left, right), Math.abs(left - right) ]; + const [left, isLeftBalanced] = isRootBalanced(root.left); + const [right, isRightBalanced] = isRootBalanced(root.right); + const [height, difference] = [ + Math.max(left, right), + Math.abs(left - right), + ]; const isAcceptableHeight = difference <= 1; const _isBalanced = isLeftBalanced && isRightBalanced; const _isRootBalanced = _isBalanced && isAcceptableHeight; - return [ (height + 1), _isRootBalanced ]; -} + return [height + 1, _isRootBalanced]; +}; diff --git a/javascript/0112-path-sum.js b/javascript/0112-path-sum.js index 626496eb0..0d491ef3f 100644 --- a/javascript/0112-path-sum.js +++ b/javascript/0112-path-sum.js @@ -1,21 +1,19 @@ // problem link https://leetcode.com/problems/path-sum/ // time complexity O(n) // whatever the number of nodes are. -var hasPathSum = function(root, targetSum) { - +var hasPathSum = function (root, targetSum) { const ans = []; function goDFS(node, curruntSum) { - - if(!node) return; - - if(!node.left && !node.right) { + if (!node) return; + + if (!node.left && !node.right) { ans.push(node.val + curruntSum); } - + goDFS(node.left, curruntSum + node.val); goDFS(node.right, curruntSum + node.val); } goDFS(root, 0); - + return ans.includes(targetSum); }; diff --git a/javascript/0115-distinct-subsequences.js b/javascript/0115-distinct-subsequences.js index 440d0094c..c5fd61070 100644 --- a/javascript/0115-distinct-subsequences.js +++ b/javascript/0115-distinct-subsequences.js @@ -7,37 +7,55 @@ * @param {string} t * @return {number} */ - var numDistinct = (s, t, i = 0, j = 0, memo = initMemo(s, t)) => { - const isBaseCase1 = (s.length < t.length); +var numDistinct = (s, t, i = 0, j = 0, memo = initMemo(s, t)) => { + const isBaseCase1 = s.length < t.length; if (isBaseCase1) return 0; - const isBaseCase2 = (j === t.length); + const isBaseCase2 = j === t.length; if (isBaseCase2) return 1; - const isBaseCase3 = (i === s.length); + const isBaseCase3 = i === s.length; if (isBaseCase3) return 0; - const hasSeen = (memo[i][j] !== null); + const hasSeen = memo[i][j] !== null; if (hasSeen) return memo[i][j]; - return dfs(s, t, i, j, memo);/* Time O(N * M) | Space O((N * M) + HEIGHT) */ -} + return dfs( + s, + t, + i, + j, + memo, + ); /* Time O(N * M) | Space O((N * M) + HEIGHT) */ +}; -var initMemo = (s, t) => new Array(s.length).fill() - .map(() => new Array(t.length).fill(null)); +var initMemo = (s, t) => + new Array(s.length).fill().map(() => new Array(t.length).fill(null)); var dfs = (s, t, i, j, memo) => { - const left = numDistinct(s, t, (i + 1), j, memo);/* Time O(N * M) | Space O(HEIGHT) */ + const left = numDistinct( + s, + t, + i + 1, + j, + memo, + ); /* Time O(N * M) | Space O(HEIGHT) */ - const isEqual = (s[i] === t[j]); + const isEqual = s[i] === t[j]; const right = isEqual - ? numDistinct(s, t, (i + 1), (j + 1), memo) /* Time O(N * M) | Space O(HEIGHT) */ + ? numDistinct( + s, + t, + i + 1, + j + 1, + memo, + ) /* Time O(N * M) | Space O(HEIGHT) */ : 0; - memo[i][j] = (left + right); /* | Space O(N * M) */ + memo[i][j] = left + right; /* | Space O(N * M) */ return memo[i][j]; -} +}; /** * DP - Bottom Up @@ -49,41 +67,43 @@ var dfs = (s, t, i, j, memo) => { * @return {number} */ var numDistinct = (s, t) => { - const tabu = initTabu(s, t);/* Time O(N * M) | Space O(N * M) */ + const tabu = initTabu(s, t); /* Time O(N * M) | Space O(N * M) */ - search(s, t, tabu); /* Time O(N * M) | Space O(N * M) */ + search(s, t, tabu); /* Time O(N * M) | Space O(N * M) */ return tabu[0][0]; -} +}; var initTabu = (s, t) => { - const tabu = new Array(s.length + 1).fill()/* Time O(N) | Space O(N) */ - .map(() => new Array(t.length + 1)); /* Time O(M) | Space O(M) */ + const tabu = new Array(s.length + 1) + .fill() /* Time O(N) | Space O(N) */ + .map(() => new Array(t.length + 1)); /* Time O(M) | Space O(M) */ - tabu[s.length].fill(0); /* | Space O(N * M) */ + tabu[s.length].fill(0); /* | Space O(N * M) */ - for (let r = 0; r <= s.length; ++r) { /* Time O(N) */ - tabu[r][t.length] = 1; /* | Space O(N * M) */ + for (let r = 0; r <= s.length; ++r) { + /* Time O(N) */ + tabu[r][t.length] = 1; /* | Space O(N * M) */ } return tabu; -} +}; var search = (s, t, tabu) => { - for (let r = (s.length - 1); (0 <= r); r--) {/* Time O(N) */ - for (let c = (t.length - 1); (0 <= c); c--) {/* Time O(M) */ + for (let r = s.length - 1; 0 <= r; r--) { + /* Time O(N) */ + for (let c = t.length - 1; 0 <= c; c--) { + /* Time O(M) */ const left = tabu[r + 1][c]; - const isEqual = (s[r] === t[c]); + const isEqual = s[r] === t[c]; - const right = isEqual - ? tabu[r + 1][c + 1] - : 0 - - tabu[r][c] = left + right; /* Space O(N * M) */ + const right = isEqual ? tabu[r + 1][c + 1] : 0; + + tabu[r][c] = left + right; /* Space O(N * M) */ } } -} +}; /** * DP - Bottom Up @@ -95,26 +115,28 @@ var search = (s, t, tabu) => { * @return {number} */ var numDistinct = (s, t) => { - const tabu = initTabu(t);/* Time O(M) | Space O(M) */ + const tabu = initTabu(t); /* Time O(M) | Space O(M) */ - search(s, t, tabu); /* Time O(N * M) | Space O(M) */ + search(s, t, tabu); /* Time O(N * M) | Space O(M) */ return tabu[0]; -} +}; -var initTabu = (t) => new Array(t.length).fill(0);/* Time O(M) | Space O(M) */ +var initTabu = (t) => new Array(t.length).fill(0); /* Time O(M) | Space O(M) */ var search = (s, t, tabu) => { - for (let row = (s.length - 1); (0 <= row); row--) {/* Time O(N) */ + for (let row = s.length - 1; 0 <= row; row--) { + /* Time O(N) */ let prev = 1; - for (let col = (t.length - 1); (0 <= col); col--) {/* Time O(M) */ + for (let col = t.length - 1; 0 <= col; col--) { + /* Time O(M) */ const curr = tabu[col]; - const isEqual = (s[row] === t[col]); - if (isEqual) tabu[col] += prev; /* Space O(M) */ + const isEqual = s[row] === t[col]; + if (isEqual) tabu[col] += prev; /* Space O(M) */ prev = curr; } } -} +}; diff --git a/javascript/0116-populating-next-right-pointers-in-each-node.js b/javascript/0116-populating-next-right-pointers-in-each-node.js index e9e11cd6c..5359e10e0 100644 --- a/javascript/0116-populating-next-right-pointers-in-each-node.js +++ b/javascript/0116-populating-next-right-pointers-in-each-node.js @@ -1,7 +1,7 @@ /** * BFS * Time O(n) | Space O(1) - * + * * https://leetcode.com/problems/populating-next-right-pointers-in-each-node/ * // Definition for a Node. * function Node(val, left, right, next) { @@ -16,18 +16,17 @@ * @return {Node} */ -var connect = function(root) { - +var connect = function (root) { let currentNode = root; let nextLevelNode = root && root.left; - while(currentNode && nextLevelNode) { + while (currentNode && nextLevelNode) { currentNode.left.next = currentNode.right; - if(currentNode.next) { + if (currentNode.next) { currentNode.right.next = currentNode.next.left; } currentNode = currentNode.next; - if(!currentNode) { + if (!currentNode) { currentNode = nextLevelNode; nextLevelNode = currentNode.left; } diff --git a/javascript/0118-pascals-triangle.js b/javascript/0118-pascals-triangle.js index 9d2152d3f..9acb9a980 100644 --- a/javascript/0118-pascals-triangle.js +++ b/javascript/0118-pascals-triangle.js @@ -1,17 +1,16 @@ - // link to the problem https://leetcode.com/problems/pascals-triangle/ // the time complexity will basically be the number of elements in pascale tringle. roughly height of tringle * number of honeycomb in each row. // O(n^2); var generate = function (numRows) { - const res = [[1]]; + const res = [[1]]; - for (let i = 1; i < numRows; i++) { + for (let i = 1; i < numRows; i++) { res[i] = []; - for (let k = 0; k < i + 1; k++) { - res[i][k] = (res[i - 1][k] || 0) + (res[i - 1][k - 1] || 0); - } - } + for (let k = 0; k < i + 1; k++) { + res[i][k] = (res[i - 1][k] || 0) + (res[i - 1][k - 1] || 0); + } + } return res; }; diff --git a/javascript/0122-best-time-to-buy-and-sell-stock-ii.js b/javascript/0122-best-time-to-buy-and-sell-stock-ii.js index 9057b1fe1..245de778a 100644 --- a/javascript/0122-best-time-to-buy-and-sell-stock-ii.js +++ b/javascript/0122-best-time-to-buy-and-sell-stock-ii.js @@ -1,11 +1,11 @@ // problem link https://leetcode.com/problems/best-time-to-buy-and-sell-stock-ii // time coplexity O(n) -var maxProfit = function(prices) { +var maxProfit = function (prices) { let maxProfit = 0; - for(let i = 0; i < prices.length; i++) { - if(prices[i] < prices[i+1]) { - maxProfit += prices[i+1] - prices[i]; + for (let i = 0; i < prices.length; i++) { + if (prices[i] < prices[i + 1]) { + maxProfit += prices[i + 1] - prices[i]; } } diff --git a/javascript/0124-binary-tree-maximum-path-sum.js b/javascript/0124-binary-tree-maximum-path-sum.js index ad41a02c3..8bc5a6d26 100644 --- a/javascript/0124-binary-tree-maximum-path-sum.js +++ b/javascript/0124-binary-tree-maximum-path-sum.js @@ -4,7 +4,7 @@ * @param {TreeNode} root * @return {number} */ - var maxPathSum = function(root, maxValue = [ -Infinity ]) { +var maxPathSum = function (root, maxValue = [-Infinity]) { pathSum(root, maxValue); return maxValue[0]; @@ -15,7 +15,7 @@ const pathSum = (root, maxValue) => { if (isBaseCase) return 0; return dfs(root, maxValue); -} +}; const dfs = (node, maxValue) => { const left = Math.max(0, pathSum(node.left, maxValue)); @@ -25,4 +25,4 @@ const dfs = (node, maxValue) => { maxValue[0] = Math.max(maxValue[0], sum); return Math.max(left, right) + node.val; -} +}; diff --git a/javascript/0125-valid-palindrome.js b/javascript/0125-valid-palindrome.js index 7e3785007..c68e9e1b8 100644 --- a/javascript/0125-valid-palindrome.js +++ b/javascript/0125-valid-palindrome.js @@ -5,23 +5,28 @@ * @param {string} s * @return {boolean} */ -var isPalindrome = function(s) { +var isPalindrome = function (s) { if (!s.length) return true; - - const alphaNumeric = filterAlphaNumeric(s);/* Time O(N) | Space O(N) */ - const reversed = reverse(alphaNumeric); /* Time O(N) | Space O(N) */ - + + const alphaNumeric = filterAlphaNumeric(s); /* Time O(N) | Space O(N) */ + const reversed = reverse(alphaNumeric); /* Time O(N) | Space O(N) */ + return alphaNumeric === reversed; }; -const filterAlphaNumeric = (s, nonAlphaNumeric = new RegExp('[^a-z0-9]','gi')) => s - .toLowerCase() /* Time O(N) | Space O(N) */ - .replace(nonAlphaNumeric, '')/* Time O(N) | Space O(N) */ +const filterAlphaNumeric = ( + s, + nonAlphaNumeric = new RegExp('[^a-z0-9]', 'gi'), +) => + s + .toLowerCase() /* Time O(N) | Space O(N) */ + .replace(nonAlphaNumeric, ''); /* Time O(N) | Space O(N) */ -const reverse = (s) => s - .split('')/* Time O(N) | Space O(N) */ - .reverse()/* Time O(N) | Space O(N) */ - .join('');/* Time O(N) | Space O(N) */ +const reverse = (s) => + s + .split('') /* Time O(N) | Space O(N) */ + .reverse() /* Time O(N) | Space O(N) */ + .join(''); /* Time O(N) | Space O(N) */ /** * 2 Pointer | Midde Convergence @@ -30,15 +35,15 @@ const reverse = (s) => s * @param {string} s * @return {boolean} */ -var isPalindrome = function(s) { +var isPalindrome = function (s) { if (s.length <= 1) return true; - + let [left, right] = [0, s.length - 1]; let leftChar, rightChar; while (left < right) { leftChar = s[left]; rightChar = s[right]; - + // skip char if non-alphanumeric if (!/[a-zA-Z0-9]/.test(leftChar)) { left++; @@ -64,24 +69,35 @@ var isPalindrome = function(s) { * @return {boolean} */ var isPalindrome = function (s) { - const isAlphaNumeric = c => (c.toLowerCase() >= 'a' && c.toLowerCase() <= 'z') || c >= '0' && c <= '9' + const isAlphaNumeric = (c) => + (c.toLowerCase() >= 'a' && c.toLowerCase() <= 'z') || + (c >= '0' && c <= '9'); + + let left = 0; + let right = s.length - 1; + let skipLeft, + skipRight, + endsEqual = false; - let left = 0; - let right = s.length - 1; - let skipLeft, skipRight, endsEqual = false; - - while (left < right) { - skipLeft = !isAlphaNumeric(s.charAt(left)) - if (skipLeft) { left++; continue; } + while (left < right) { + skipLeft = !isAlphaNumeric(s.charAt(left)); + if (skipLeft) { + left++; + continue; + } - skipRight = !isAlphaNumeric(s.charAt(right)) - if (skipRight) { right--; continue; } + skipRight = !isAlphaNumeric(s.charAt(right)); + if (skipRight) { + right--; + continue; + } - endsEqual = s.charAt(left).toLowerCase() === s.charAt(right).toLowerCase() - if (!endsEqual) return false + endsEqual = + s.charAt(left).toLowerCase() === s.charAt(right).toLowerCase(); + if (!endsEqual) return false; - left++ - right-- - } - return true + left++; + right--; + } + return true; }; diff --git a/javascript/0127-word-ladder.js b/javascript/0127-word-ladder.js index cb8d991b7..2e2ae3991 100644 --- a/javascript/0127-word-ladder.js +++ b/javascript/0127-word-ladder.js @@ -6,26 +6,35 @@ * @param {string[]} wordList * @return {number} */ - var ladderLength = function(beginWord, endWord, wordList) { - const [ queue, wordSet, seen ] = [ new Queue([[ beginWord, 1 ]]), new Set(wordList), new Set([ beginWord ]) ]; - - return bfs(queue, wordSet, seen, endWord);/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ +var ladderLength = function (beginWord, endWord, wordList) { + const [queue, wordSet, seen] = [ + new Queue([[beginWord, 1]]), + new Set(wordList), + new Set([beginWord]), + ]; + + return bfs( + queue, + wordSet, + seen, + endWord, + ); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ }; const bfs = (queue, wordSet, seen, endWord) => { while (!queue.isEmpty()) { - for (let i = (queue.size() - 1); 0 <= i; i--) { - const [ word, depth ] = queue.dequeue(); + for (let i = queue.size() - 1; 0 <= i; i--) { + const [word, depth] = queue.dequeue(); - const isTarget = word === endWord - if (isTarget) return depth + const isTarget = word === endWord; + if (isTarget) return depth; - transform(queue, wordSet, seen, word, depth) + transform(queue, wordSet, seen, word, depth); } } - return 0 -} + return 0; +}; const transform = (queue, wordSet, seen, word, depth) => { for (const index in word) { @@ -35,11 +44,11 @@ const transform = (queue, wordSet, seen, word, depth) => { const hasSeen = !wordSet.has(neighbor) || seen.has(neighbor); if (hasSeen) continue; - queue.enqueue([ neighbor, (depth + 1) ]); + queue.enqueue([neighbor, depth + 1]); seen.add(neighbor); } } -} +}; const getNeighbor = (word, index, char) => { const neighbor = word.split(''); @@ -47,4 +56,4 @@ const getNeighbor = (word, index, char) => { neighbor[index] = char; return neighbor.join(''); -} +}; diff --git a/javascript/0128-longest-consecutive-sequence.js b/javascript/0128-longest-consecutive-sequence.js index 02e753678..72a2b3dba 100644 --- a/javascript/0128-longest-consecutive-sequence.js +++ b/javascript/0128-longest-consecutive-sequence.js @@ -6,11 +6,13 @@ * @param {number[]} nums * @return {number} */ - var longestConsecutive = (nums, maxScore = 0) => { - for (const num of nums) {/* Time O(N) */ - let [ currNum, score ] = [ num, 1 ]; +var longestConsecutive = (nums, maxScore = 0) => { + for (const num of nums) { + /* Time O(N) */ + let [currNum, score] = [num, 1]; - while (isStreak(nums, (currNum + 1))) {/* Time O(N * N) */ + while (isStreak(nums, currNum + 1)) { + /* Time O(N * N) */ currNum++; score++; } @@ -19,16 +21,17 @@ } return maxScore; -} +}; const isStreak = (nums, num) => { - for (let i = 0; i < nums.length; i++) {/* Time O(N) */ - const isEqual = nums[i] === num + for (let i = 0; i < nums.length; i++) { + /* Time O(N) */ + const isEqual = nums[i] === num; if (isEqual) return true; } return false; -} +}; /** * Sort - HeapSort Space O(1) | QuickSort Space O(log(K)) @@ -38,30 +41,34 @@ const isStreak = (nums, num) => { * @param {number[]} nums * @return {number} */ - var longestConsecutive = (nums) => { +var longestConsecutive = (nums) => { if (!nums.length) return 0; - nums.sort((a, b) => a - b);/* Time O(N * log(N)) | Space O(1 || log(N)) */ + nums.sort((a, b) => a - b); /* Time O(N * log(N)) | Space O(1 || log(N)) */ - return search(nums); /* Time O(N) */ -} + return search(nums); /* Time O(N) */ +}; const search = (nums) => { - let [ maxScore, score ] = [ 1, 1 ]; + let [maxScore, score] = [1, 1]; - for (let i = 1; i < nums.length; i++) {/* Time O(N) */ - const isPrevDuplicate = nums[i - 1] === nums[i] - if (isPrevDuplicate) continue + for (let i = 1; i < nums.length; i++) { + /* Time O(N) */ + const isPrevDuplicate = nums[i - 1] === nums[i]; + if (isPrevDuplicate) continue; - const isStreak = nums[i] === ((nums[i - 1]) + 1) - if (isStreak) { score++; continue; } + const isStreak = nums[i] === nums[i - 1] + 1; + if (isStreak) { + score++; + continue; + } maxScore = Math.max(maxScore, score); score = 1; } return Math.max(maxScore, score); -} +}; /** * Hash Set - Intelligent Sequence @@ -71,18 +78,20 @@ const search = (nums) => { * @param {number[]} nums * @return {number} */ - var longestConsecutive = (nums, maxScore = 0) => { - const numSet = new Set(nums); /* Time O(N) | Space O(N) */ +var longestConsecutive = (nums, maxScore = 0) => { + const numSet = new Set(nums); /* Time O(N) | Space O(N) */ - for (const num of [ ...numSet ]) { /* Time O(N) */ + for (const num of [...numSet]) { + /* Time O(N) */ const prevNum = num - 1; - if (numSet.has(prevNum)) continue;/* Time O(N) */ + if (numSet.has(prevNum)) continue; /* Time O(N) */ - let [ currNum, score ] = [ num, 1 ]; + let [currNum, score] = [num, 1]; - const isStreak = () => numSet.has(currNum + 1) - while (isStreak()) { /* Time O(N) */ + const isStreak = () => numSet.has(currNum + 1); + while (isStreak()) { + /* Time O(N) */ currNum++; score++; } @@ -91,4 +100,4 @@ const search = (nums) => { } return maxScore; -} \ No newline at end of file +}; diff --git a/javascript/0129-sum-root-to-leaf-numbers.js b/javascript/0129-sum-root-to-leaf-numbers.js index 45a4883b6..beb7f3e69 100644 --- a/javascript/0129-sum-root-to-leaf-numbers.js +++ b/javascript/0129-sum-root-to-leaf-numbers.js @@ -13,20 +13,19 @@ * @param {TreeNode} root * @return {number} */ -var sumNumbers = function(root) { - - let total = 0; - const dfs = (node, num) => { - if(!node.left && !node.right) { - num = num + node.val; - total += +num; - return; - } +var sumNumbers = function (root) { + let total = 0; + const dfs = (node, num) => { + if (!node.left && !node.right) { + num = num + node.val; + total += +num; + return; + } - node.left && dfs(node.left, num + node.val); - node.right && dfs(node.right, num + node.val); - } + node.left && dfs(node.left, num + node.val); + node.right && dfs(node.right, num + node.val); + }; - dfs(root, ""); - return total; + dfs(root, ''); + return total; }; diff --git a/javascript/0130-surrounded-regions.js b/javascript/0130-surrounded-regions.js index 3fb409c1d..ff097cb91 100644 --- a/javascript/0130-surrounded-regions.js +++ b/javascript/0130-surrounded-regions.js @@ -4,35 +4,39 @@ * @param {character[][]} board * @return {void} Do not return anything, modify board in-place instead. */ - var solve = function solve(board) { - searchRows(board);/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ - searchCols(board);/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ - searchGrid(board);/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ -} +var solve = function solve(board) { + searchRows(board); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ + searchCols(board); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ + searchGrid(board); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ +}; var searchRows = (board) => { - const [ rows, cols ] = [ board.length, board[0].length ]; + const [rows, cols] = [board.length, board[0].length]; - for (let row = 0; row < rows; row++) { /* Time O(ROWS) */ - dfs(board, row, rows, 0, cols); /* Space O(ROWS) */ - dfs(board, row, rows, (cols - 1), cols);/* Space O(ROWS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + dfs(board, row, rows, 0, cols); /* Space O(ROWS) */ + dfs(board, row, rows, cols - 1, cols); /* Space O(ROWS) */ } -} +}; var searchCols = (board) => { - const [ rows, cols ] = [ board.length, board[0].length ]; + const [rows, cols] = [board.length, board[0].length]; - for (let col = 1; col < (cols - 1); col++) {/* Time O(COLS) */ - dfs(board, 0, rows, col, cols); /* Space O(COLS) */ - dfs(board, (rows - 1), rows, col, cols);/* Space O(COLS) */ + for (let col = 1; col < cols - 1; col++) { + /* Time O(COLS) */ + dfs(board, 0, rows, col, cols); /* Space O(COLS) */ + dfs(board, rows - 1, rows, col, cols); /* Space O(COLS) */ } -} +}; var searchGrid = (board) => { - const [ rows, cols ] = [ board.length, board[0].length ]; + const [rows, cols] = [board.length, board[0].length]; - for (let row = 0; row < rows; row++) {/* Time O(ROWS) */ - for (let col = 0; col < cols; col++) {/* Time O(COLS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ const isO = board[row][col] === 'O'; if (isO) board[row][col] = 'X'; @@ -40,7 +44,7 @@ var searchGrid = (board) => { if (isStar) board[row][col] = 'O'; } } -} +}; const dfs = (board, row, rows, col, cols) => { const isBaseCase = board[row][col] !== 'O'; @@ -48,15 +52,29 @@ const dfs = (board, row, rows, col, cols) => { board[row][col] = '*'; - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) { - dfs(board, _row, rows, _col, cols);/* Time O(HEIGHT) | Space O(HEIGHT) */ + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { + dfs( + board, + _row, + rows, + _col, + cols, + ); /* Time O(HEIGHT) | Space O(HEIGHT) */ } -} - -var getNeighbors = (row, rows, col, cols) => [ [0, 1], [0, -1], [1, 0], [-1, 0] ] - .map(([ _row, _col ]) => [ (row + _row), (col + _col)]) - .filter(([ _row, _col ]) => (0 <= _row) && (_row < rows) && (0 <= _col) && (_col < cols)) - +}; + +var getNeighbors = (row, rows, col, cols) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + .map(([_row, _col]) => [row + _row, col + _col]) + .filter( + ([_row, _col]) => + 0 <= _row && _row < rows && 0 <= _col && _col < cols, + ); /** * https://leetcode.com/problems/surrounded-regions/ @@ -64,55 +82,60 @@ var getNeighbors = (row, rows, col, cols) => [ [0, 1], [0, -1], [1, 0], [-1, 0] * @param {character[][]} board * @return {void} Do not return anything, modify board in-place instead. */ - var solve = function solve(board, queue = new Queue([])) { - searchRows(board, queue);/* Time O(ROWS + COLS) | Space O(ROWS + COLS) */ - searchCols(board, queue);/* Time O(ROWS + COLS) | Space O(ROWS + COLS) */ - bfs(board, queue); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ - searchGrid(board); /* Time O(ROWS * COLS) */ -} +var solve = function solve(board, queue = new Queue([])) { + searchRows(board, queue); /* Time O(ROWS + COLS) | Space O(ROWS + COLS) */ + searchCols(board, queue); /* Time O(ROWS + COLS) | Space O(ROWS + COLS) */ + bfs(board, queue); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ + searchGrid(board); /* Time O(ROWS * COLS) */ +}; var searchRows = (board, queue) => { - const [ rows, cols ] = [ board.length, board[0].length ] + const [rows, cols] = [board.length, board[0].length]; - for (let row = 0; row < rows; row++) { /* Time O(ROWS) */ - queue.enqueue([ row, 0 ]); /* Space O(ROWS) */ - queue.enqueue([ row, (cols - 1) ]);/* Space O(ROWS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + queue.enqueue([row, 0]); /* Space O(ROWS) */ + queue.enqueue([row, cols - 1]); /* Space O(ROWS) */ } -} +}; var searchCols = (board, queue) => { - const [ rows, cols ] = [ board.length, board[0].length ] + const [rows, cols] = [board.length, board[0].length]; - for (let col = 0; col < (cols - 1); col++) {/* Time O(COLS) */ - queue.enqueue([ 0, col ]); /* Space O(COLS) */ - queue.enqueue([ (rows - 1), col ]); /* Space O(COLS) */ + for (let col = 0; col < cols - 1; col++) { + /* Time O(COLS) */ + queue.enqueue([0, col]); /* Space O(COLS) */ + queue.enqueue([rows - 1, col]); /* Space O(COLS) */ } -} +}; var bfs = (board, queue) => { - const [ rows, cols ] = [ board.length, board[0].length ]; + const [rows, cols] = [board.length, board[0].length]; while (!queue.isEmpty()) { - for (let i = (queue.size() - 1); 0 <= i; i--) {/* Time O(WIDTH) */ - const [ row, col ] = queue.dequeue(); + for (let i = queue.size() - 1; 0 <= i; i--) { + /* Time O(WIDTH) */ + const [row, col] = queue.dequeue(); const isBaseCase = board[row][col] !== 'O'; if (isBaseCase) continue; board[row][col] = '*'; - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) { - queue.enqueue([ _row, _col ]); /* Space O(WIDTH) */ + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { + queue.enqueue([_row, _col]); /* Space O(WIDTH) */ } } - } -} + } +}; var searchGrid = (board) => { - const [ rows, cols ] = [ board.length, board[0].length ]; + const [rows, cols] = [board.length, board[0].length]; - for (let row = 0; row < rows; row++) {/* Time O(ROWS) */ - for (let col = 0; col < cols; col++) {/* Time O(COLS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ const isO = board[row][col] === 'O'; if (isO) board[row][col] = 'X'; @@ -120,4 +143,4 @@ var searchGrid = (board) => { if (isStar) board[row][col] = 'O'; } } -} \ No newline at end of file +}; diff --git a/javascript/0131-palindrome-partitioning.js b/javascript/0131-palindrome-partitioning.js index 7c904589e..dcced546e 100644 --- a/javascript/0131-palindrome-partitioning.js +++ b/javascript/0131-palindrome-partitioning.js @@ -1,39 +1,40 @@ -/** - * https://leetcode.com/problems/palindrome-partitioning/ - * Time O(N * 2^N) | Space O(N^2) - * @param {string} s - * @return {string[][]} - */ -function partition(s, left = 0, _partition = [], partitions = []) { - const isBaseCase = s.length <= left - if (isBaseCase) { - if (_partition.length) partitions.push(_partition.slice()); - - return partitions - } - - for (let right = left; right < s.length; right++) { - if (!isPalindrome(s, left, right)) continue; - - backTrack(s, left, right, _partition, partitions) - } - - return partitions -} - -const backTrack = (s, left, right, _partition, partitions) => { - _partition.push(s.slice(left, (right + 1))); - partition(s, (right + 1), _partition, partitions); - _partition.pop(); -} - -const isPalindrome = (str, left, right) => { - while (left < right) { - const isSame = str[left] === str[right]; - if (!isSame) return false; - - left++; right--; - } - - return true; -} +/** + * https://leetcode.com/problems/palindrome-partitioning/ + * Time O(N * 2^N) | Space O(N^2) + * @param {string} s + * @return {string[][]} + */ +function partition(s, left = 0, _partition = [], partitions = []) { + const isBaseCase = s.length <= left; + if (isBaseCase) { + if (_partition.length) partitions.push(_partition.slice()); + + return partitions; + } + + for (let right = left; right < s.length; right++) { + if (!isPalindrome(s, left, right)) continue; + + backTrack(s, left, right, _partition, partitions); + } + + return partitions; +} + +const backTrack = (s, left, right, _partition, partitions) => { + _partition.push(s.slice(left, right + 1)); + partition(s, right + 1, _partition, partitions); + _partition.pop(); +}; + +const isPalindrome = (str, left, right) => { + while (left < right) { + const isSame = str[left] === str[right]; + if (!isSame) return false; + + left++; + right--; + } + + return true; +}; diff --git a/javascript/0133-clone-graph.js b/javascript/0133-clone-graph.js index 5cd7f307d..289eb8235 100644 --- a/javascript/0133-clone-graph.js +++ b/javascript/0133-clone-graph.js @@ -4,28 +4,33 @@ * @param {Node} node * @return {Node} */ -var cloneGraph = function(node, seen = new Map()) { +var cloneGraph = function (node, seen = new Map()) { const isBaseCase = node === null; if (isBaseCase) return null; if (seen.has(node)) return seen.get(node); - return dfs(node, seen); /* Time O(V + E) | Space O(N) */ -} + return dfs(node, seen); /* Time O(V + E) | Space O(N) */ +}; const dfs = (node, seen) => { const clone = new Node(node.val); - seen.set(node, clone); /* | Space O(N) */ + seen.set(node, clone); /* | Space O(N) */ for (const neighbor of node.neighbors) { - const cloneNeighbor = cloneGraph(neighbor, seen);/* Time O(V + E) | Space O(H) */ - - clone.neighbors.push(cloneNeighbor); /* | Space O(V + E) */ + const cloneNeighbor = cloneGraph( + neighbor, + seen, + ); /* Time O(V + E) | Space O(H) */ + + clone.neighbors.push( + cloneNeighbor, + ); /* | Space O(V + E) */ } return clone; -} +}; /** * https://leetcode.com/problems/clone-graph/ @@ -33,36 +38,41 @@ const dfs = (node, seen) => { * @param {Node} node * @return {Node} */ - var cloneGraph = function(node, seen = new Map()) { +var cloneGraph = function (node, seen = new Map()) { const isBaseCase = node === null; if (isBaseCase) return null; - seen.set(node, new Node(node.val)); /* | Space O(N) */ + seen.set(node, new Node(node.val)); /* | Space O(N) */ - bfs(new Queue([ node ]), seen); /* Time O(V + E) | Space O(N) */ + bfs(new Queue([node]), seen); /* Time O(V + E) | Space O(N) */ return seen.get(node); }; const bfs = (queue, seen) => { - while (!queue.isEmpty()) { /* Time O(V + E) */ - for (let i = (queue.size() - 1); 0 <= i; i--) {/* Time O(W) */ + while (!queue.isEmpty()) { + /* Time O(V + E) */ + for (let i = queue.size() - 1; 0 <= i; i--) { + /* Time O(W) */ const node = queue.dequeue(); - cloneNeighbors(node, seen, queue); /* Space O(N) */ + cloneNeighbors(node, seen, queue); /* Space O(N) */ } } -} +}; const cloneNeighbors = (node, seen, queue) => { for (const neighbor of node.neighbors) { if (!seen.has(neighbor)) { - seen.set(neighbor, new Node(neighbor.val));/* Space O(N) */ - queue.enqueue(neighbor); /* Space O(W) */ + seen.set(neighbor, new Node(neighbor.val)); /* Space O(N) */ + queue.enqueue(neighbor); /* Space O(W) */ } - const [ parentClone, neighborClone ] = [ seen.get(node), seen.get(neighbor) ]; + const [parentClone, neighborClone] = [ + seen.get(node), + seen.get(neighbor), + ]; - parentClone.neighbors.push(neighborClone); /* Space O(V + E) */ + parentClone.neighbors.push(neighborClone); /* Space O(V + E) */ } -} +}; diff --git a/javascript/0134-gas-station.js b/javascript/0134-gas-station.js index 3f4404917..ff8537d28 100644 --- a/javascript/0134-gas-station.js +++ b/javascript/0134-gas-station.js @@ -10,7 +10,8 @@ var canCompleteCircuit = function (gas, cost) { let res = 0; //Checks if theres enough gas to complete a cycle - if (gas.reduce((a, b) => a + b) - cost.reduce((a, b) => a + b) < 0) return -1; + if (gas.reduce((a, b) => a + b) - cost.reduce((a, b) => a + b) < 0) + return -1; // Finds the first appearence of a positive netDistance, if the cycle can't // be completed (netDistance < 0), starts cycle again @ the next positive netDistance value. @@ -22,7 +23,7 @@ var canCompleteCircuit = function (gas, cost) { res = i + 1; } } - + return res; }; @@ -31,18 +32,19 @@ var canCompleteCircuit = function (gas, cost) { * @param {number[]} cost * @return {number} */ - var canCompleteCircuit = function(gas, cost) { - let [ totalTank, currTank, startingStation ] = [ 0, 0, 0 ] +var canCompleteCircuit = function (gas, cost) { + let [totalTank, currTank, startingStation] = [0, 0, 0]; for (let i = 0; i < gas.length; i++) { totalTank += gas[i] - cost[i]; currTank += gas[i] - cost[i]; - + const isEmpty = currTank < 0; - if (isEmpty) { startingStation = (i + 1); currTank = 0; } + if (isEmpty) { + startingStation = i + 1; + currTank = 0; + } } - - return 0 <= totalTank - ? startingStation - : -1; -} \ No newline at end of file + + return 0 <= totalTank ? startingStation : -1; +}; diff --git a/javascript/0135-candy.js b/javascript/0135-candy.js index f3d275b81..80b0d05d9 100644 --- a/javascript/0135-candy.js +++ b/javascript/0135-candy.js @@ -5,27 +5,26 @@ * @param {number[]} ratings * @return {number} */ -var candy = function(ratings) { - +var candy = function (ratings) { const ltr = new Array(ratings.length).fill(1); const rtl = new Array(ratings.length).fill(1); // go from left to right for (let i = 1; i < ratings.length; i++) { - if (ratings[i] > ratings[i - 1]) { - ltr[i] = ltr[i - 1] + 1; - } + if (ratings[i] > ratings[i - 1]) { + ltr[i] = ltr[i - 1] + 1; + } } // go from right to left for (let i = ratings.length - 2; i > -1; i--) { - if (ratings[i] > ratings[i + 1]) { - rtl[i] = rtl[i + 1] + 1; - } + if (ratings[i] > ratings[i + 1]) { + rtl[i] = rtl[i + 1] + 1; + } } - // calc minimum + // calc minimum let candy = 0; for (let i = 0; i < ratings.length; i++) { - candy += Math.max(ltr[i], rtl[i]); + candy += Math.max(ltr[i], rtl[i]); } return candy; }; diff --git a/javascript/0138-copy-list-with-random-pointer.js b/javascript/0138-copy-list-with-random-pointer.js index 5536d3b03..9aa2d6ae8 100644 --- a/javascript/0138-copy-list-with-random-pointer.js +++ b/javascript/0138-copy-list-with-random-pointer.js @@ -4,18 +4,21 @@ * @param {Node} head * @return {Node} */ -var copyRandomList = function(head, map = new Map()) { +var copyRandomList = function (head, map = new Map()) { if (!head) return null; if (map.has(head)) return map.get(head); const clone = new Node(head.val); - map.set(head, clone); /* | Space O(N) */ - clone.next = copyRandomList(head.next, map); /* Time O(N) | Space O(N) */ - clone.random = copyRandomList(head.random, map);/* Time O(N) | Space O(N) */ + map.set(head, clone); /* | Space O(N) */ + clone.next = copyRandomList(head.next, map); /* Time O(N) | Space O(N) */ + clone.random = copyRandomList( + head.random, + map, + ); /* Time O(N) | Space O(N) */ return clone; -} +}; /** * https://leetcode.com/problems/copy-list-with-random-pointer/ @@ -23,17 +26,18 @@ var copyRandomList = function(head, map = new Map()) { * @param {Node} head * @return {Node} */ -var copyRandomList = function(head) { +var copyRandomList = function (head) { if (!head) return null; - cloneNode(head); /* Time O(N) */ + cloneNode(head); /* Time O(N) */ connectRandomNode(head); /* Time O(N) */ - return connectNode(head);/* Time O(N) */ + return connectNode(head); /* Time O(N) */ }; const cloneNode = (curr) => { - while (curr) { /* Time O(N) */ + while (curr) { + /* Time O(N) */ const node = new Node(curr.val); node.next = curr.next; @@ -42,24 +46,26 @@ const cloneNode = (curr) => { } return curr; -} +}; const connectRandomNode = (curr) => { - while (curr) { /* Time O(N) */ + while (curr) { + /* Time O(N) */ curr.next.random = curr.random?.next || null; curr = curr.next.next; } -} +}; const connectNode = (head) => { - let [ prev, curr, next ] = [ head, head.next, head.next ]; + let [prev, curr, next] = [head, head.next, head.next]; - while (prev) { /* Time O(N) */ + while (prev) { + /* Time O(N) */ prev.next = prev.next.next; curr.next = curr?.next?.next || null; prev = prev.next; curr = curr.next; } - return next -} \ No newline at end of file + return next; +}; diff --git a/javascript/0139-word-break.js b/javascript/0139-word-break.js index 42daf415b..24e095ac8 100644 --- a/javascript/0139-word-break.js +++ b/javascript/0139-word-break.js @@ -7,30 +7,32 @@ * @param {string[]} wordDict * @return {boolean} */ - var wordBreak = (s, wordDict) => { - const wordSet = new Set(wordDict);/* Time O(N) | Space O(N) */ +var wordBreak = (s, wordDict) => { + const wordSet = new Set(wordDict); /* Time O(N) | Space O(N) */ - return canBreak(s, wordSet); /* Time O(2^N) | Space O(N) */ + return canBreak(s, wordSet); /* Time O(2^N) | Space O(N) */ }; var canBreak = (s, wordSet, start = 0) => { - const isBaseCase = (start === s.length); + const isBaseCase = start === s.length; if (isBaseCase) return true; - return dfs(s, wordSet, start);/* Time O(2^N) | Space O(N) */ -} + return dfs(s, wordSet, start); /* Time O(2^N) | Space O(N) */ +}; var dfs = (s, wordSet, start) => { - for (let end = (start + 1); end <= s.length; end++) {/* Time O(N) */ - const word = s.slice(start, end); /* Time O(N) | Space O(N) */ + for (let end = start + 1; end <= s.length; end++) { + /* Time O(N) */ + const word = s.slice(start, end); /* Time O(N) | Space O(N) */ - const _canBreak = wordSet.has(word) - && canBreak(s, wordSet, end); /* Time O(2^N) | Space O(N) */ + const _canBreak = + wordSet.has(word) && + canBreak(s, wordSet, end); /* Time O(2^N) | Space O(N) */ if (_canBreak) return true; } return false; -} +}; /** * DP - Top Down @@ -43,29 +45,38 @@ var dfs = (s, wordSet, start) => { * @return {boolean} */ var wordBreak = (s, wordDict) => { - const wordSet = new Set(wordDict); /* Time O(N) | Space O(N) */ - const memo = new Array(s.length).fill(null); /* | Space O(N) */ + const wordSet = new Set(wordDict); /* Time O(N) | Space O(N) */ + const memo = new Array(s.length).fill( + null, + ); /* | Space O(N) */ const start = 0; - return canBreak(s, wordSet, start, memo); /* Time O(N * N * N) | Space O(N) */ -} + return canBreak( + s, + wordSet, + start, + memo, + ); /* Time O(N * N * N) | Space O(N) */ +}; var canBreak = (s, wordSet, start, memo) => { - const isBaseCase1 = (s.length === start); + const isBaseCase1 = s.length === start; if (isBaseCase1) return true; - const hasSeen = (memo[start] !== null); + const hasSeen = memo[start] !== null; if (hasSeen) return memo[start]; - return dfs(s, wordSet, start, memo);/* Time O(N * N * N) | Space O(N) */ -} + return dfs(s, wordSet, start, memo); /* Time O(N * N * N) | Space O(N) */ +}; var dfs = (s, wordSet, start, memo) => { - for (let end = (start + 1); (end <= s.length); end++) {/* Time O(N) */ - const word = s.slice(start, end); /* Time O(N) | Space O(N) */ + for (let end = start + 1; end <= s.length; end++) { + /* Time O(N) */ + const word = s.slice(start, end); /* Time O(N) | Space O(N) */ - const _canBreak = wordSet.has(word) - && canBreak(s, wordSet, end, memo); /* Time O(N * N) */ + const _canBreak = + wordSet.has(word) && + canBreak(s, wordSet, end, memo); /* Time O(N * N) */ if (_canBreak) { memo[start] = true; return true; @@ -74,7 +85,7 @@ var dfs = (s, wordSet, start, memo) => { memo[start] = false; return false; -} +}; /** * DP - Bottom Up @@ -86,32 +97,34 @@ var dfs = (s, wordSet, start, memo) => { * @param {string[]} wordDict * @return {boolean} */ - var wordBreak = (s, wordDict) => { - const wordSet = new Set(wordDict);/* Time O(N) | Space O(N) */ - const tabu = initTabu(s); /* | Space O(N) */ +var wordBreak = (s, wordDict) => { + const wordSet = new Set(wordDict); /* Time O(N) | Space O(N) */ + const tabu = initTabu(s); /* | Space O(N) */ - canBreak(s, wordSet, tabu); /* Time O(N * N * N) | Space O(N) */ + canBreak(s, wordSet, tabu); /* Time O(N * N * N) | Space O(N) */ return tabu[s.length]; -} +}; const initTabu = (s) => { - const tabu = new Array((s.length + 1)).fill(false);/* Space O(N) */ + const tabu = new Array(s.length + 1).fill(false); /* Space O(N) */ tabu[0] = true; return tabu; -} +}; var canBreak = (s, wordSet, tabu) => { - for (let end = 1; (end <= s.length); end++) {/* Time O(N) */ - checkWord(s, wordSet, end, tabu); /* Time O(N * N) | Space O(N) */ + for (let end = 1; end <= s.length; end++) { + /* Time O(N) */ + checkWord(s, wordSet, end, tabu); /* Time O(N * N) | Space O(N) */ } -} +}; var checkWord = (s, wordSet, end, tabu) => { - for (let start = 0; (start < end); start++) {/* Time O(N) */ - const word = s.slice(start, end); /* Time O(N) | Space O(N) */ + for (let start = 0; start < end; start++) { + /* Time O(N) */ + const word = s.slice(start, end); /* Time O(N) | Space O(N) */ const canBreak = tabu[start] && wordSet.has(word); if (!canBreak) continue; @@ -120,7 +133,7 @@ var checkWord = (s, wordSet, end, tabu) => { return; } -} +}; /** * Tree Traversal - BFS @@ -133,23 +146,32 @@ var checkWord = (s, wordSet, end, tabu) => { * @param {string[]} wordDict * @return {boolean} */ -var wordBreak = function(s, wordDict) { - const wordSet = new Set(wordDict); /* Time O(N) | Space O(N) */ - const queue = new Queue([ 0 ]); /* | Space O(N) */ - const seen = new Array(s.length).fill(false);/* | Space O(N) */ - - return bfs(queue, s, wordSet, seen); /* Time O(N * N * N) | Space O(N + WIDTH) */ -} +var wordBreak = function (s, wordDict) { + const wordSet = new Set(wordDict); /* Time O(N) | Space O(N) */ + const queue = new Queue([0]); /* | Space O(N) */ + const seen = new Array(s.length).fill( + false, + ); /* | Space O(N) */ + + return bfs( + queue, + s, + wordSet, + seen, + ); /* Time O(N * N * N) | Space O(N + WIDTH) */ +}; const bfs = (queue, s, wordSet, seen) => { while (!queue.isEmpty()) { - for (let level = (queue.size() - 1); (0 <= level); level--) {/* Time O(N) */ - if (canWordBreak(queue, s, wordSet, seen)) return true; /* Time O(N * N) | Space O(N + WIDTH) */ + for (let level = queue.size() - 1; 0 <= level; level--) { + /* Time O(N) */ + if (canWordBreak(queue, s, wordSet, seen)) + return true; /* Time O(N * N) | Space O(N + WIDTH) */ } } return false; -} +}; var canWordBreak = (queue, s, wordSet, seen) => { const start = queue.dequeue(); @@ -157,23 +179,25 @@ var canWordBreak = (queue, s, wordSet, seen) => { const hasSeen = seen[start]; if (hasSeen) return false; - if (canBreak(queue, s, start, wordSet)) return true;/* Time O(N * N) | Space O(N + WIDTH) */ + if (canBreak(queue, s, start, wordSet)) + return true; /* Time O(N * N) | Space O(N + WIDTH) */ - seen[start] = true; /* | Space O(N) */ + seen[start] = true; /* | Space O(N) */ return false; -} +}; var canBreak = (queue, s, start, wordSet) => { - for (let end = start + 1; end <= s.length; end++) {/* Time O(N) */ - const word = s.slice(start, end); /* Time O(N) | Space O(N) */ + for (let end = start + 1; end <= s.length; end++) { + /* Time O(N) */ + const word = s.slice(start, end); /* Time O(N) | Space O(N) */ if (!wordSet.has(word)) continue; - queue.enqueue(end); /* | Space O(WIDTH) */ + queue.enqueue(end); /* | Space O(WIDTH) */ const _canBreak = end === s.length; if (_canBreak) return true; } - return false -} + return false; +}; diff --git a/javascript/0141-linked-list-cycle.js b/javascript/0141-linked-list-cycle.js index 7ea5826e3..6de880470 100644 --- a/javascript/0141-linked-list-cycle.js +++ b/javascript/0141-linked-list-cycle.js @@ -4,16 +4,17 @@ * @param {ListNode} head * @return {boolean} */ -var hasCycle = function(head, seen = new Set()) { - while (head) {/* Time O(N) */ +var hasCycle = function (head, seen = new Set()) { + while (head) { + /* Time O(N) */ if (seen.has(head)) return true; - seen.add(head);/* Space O(N) */ + seen.add(head); /* Space O(N) */ head = head.next; } return false; -} +}; /** * https://leetcode.com/problems/linked-list-cycle/ @@ -21,10 +22,11 @@ var hasCycle = function(head, seen = new Set()) { * @param {ListNode} head * @return {boolean} */ -var hasCycle = function(head) { - let [ slow, fast ] = [ head, head]; +var hasCycle = function (head) { + let [slow, fast] = [head, head]; - while (fast && fast.next) {/* Time O(N) */ + while (fast && fast.next) { + /* Time O(N) */ slow = slow.next; fast = fast.next.next; @@ -33,4 +35,4 @@ var hasCycle = function(head) { } return false; -}; \ No newline at end of file +}; diff --git a/javascript/0143-reorder-list.js b/javascript/0143-reorder-list.js index 690ba2a12..b4c5ef3e6 100644 --- a/javascript/0143-reorder-list.js +++ b/javascript/0143-reorder-list.js @@ -4,28 +4,30 @@ * @param {ListNode} head * @return {void} Do not return anything, modify head in-place instead. */ -var reorderList = function(head) { - const mid = getMid(head); /* Time O(N) */ - const reversedFromMid = reverse(mid);/* Time O(N) */ +var reorderList = function (head) { + const mid = getMid(head); /* Time O(N) */ + const reversedFromMid = reverse(mid); /* Time O(N) */ - reorder(head, reversedFromMid); /* Time O(N) */ + reorder(head, reversedFromMid); /* Time O(N) */ }; const getMid = (head) => { - let [ slow, fast ] = [ head, head ]; + let [slow, fast] = [head, head]; - while (fast && fast.next) { /* Time O(N) */ + while (fast && fast.next) { + /* Time O(N) */ slow = slow.next; fast = fast.next.next; } return slow; -} +}; const reverse = (head) => { - let [ prev, curr, next ] = [ null, head, null ]; + let [prev, curr, next] = [null, head, null]; - while (curr) { /* Time O(N) */ + while (curr) { + /* Time O(N) */ next = curr.next; curr.next = prev; @@ -34,12 +36,13 @@ const reverse = (head) => { } return prev; -} +}; const reorder = (l1, l2) => { - let [ first, next, second ] = [ l1, null, l2 ]; + let [first, next, second] = [l1, null, l2]; - while (second.next) { /* Time O(N) */ + while (second.next) { + /* Time O(N) */ next = first.next; first.next = second; first = next; @@ -48,4 +51,4 @@ const reorder = (l1, l2) => { second.next = first; second = next; } -} +}; diff --git a/javascript/0144-binary-tree-preorder-traversal.js b/javascript/0144-binary-tree-preorder-traversal.js index 8ba1f7cf8..88f2f4247 100644 --- a/javascript/0144-binary-tree-preorder-traversal.js +++ b/javascript/0144-binary-tree-preorder-traversal.js @@ -13,15 +13,14 @@ * @param {TreeNode} root * @return {number[]} */ -var preorderTraversal = function(root) { - +var preorderTraversal = function (root) { const dfs = (node, pre) => { if (!node) return pre; pre.push(node.val); dfs(node.left, pre); dfs(node.right, pre); return pre; - } + }; return dfs(root, []); }; diff --git a/javascript/0145-binary-tree-postorder-traversal.js b/javascript/0145-binary-tree-postorder-traversal.js index 7092bc337..aed30cdee 100644 --- a/javascript/0145-binary-tree-postorder-traversal.js +++ b/javascript/0145-binary-tree-postorder-traversal.js @@ -13,14 +13,13 @@ * @param {TreeNode} root * @return {number[]} */ -var postorderTraversal = function(root) { - +var postorderTraversal = function (root) { const dfs = (node, pot) => { if (!node) return pot; dfs(node.left, pot); dfs(node.right, pot); pot.push(node.val); return pot; - } + }; return dfs(root, []); }; diff --git a/javascript/0146-lru-cache.js b/javascript/0146-lru-cache.js index 2d450f135..b54df21b9 100644 --- a/javascript/0146-lru-cache.js +++ b/javascript/0146-lru-cache.js @@ -1,4 +1,4 @@ -/** +/** * https://leetcode.com/problems/lru-cache/ * Time O(1) | Space O(N) * Your LRUCache object will be instantiated and called as such: @@ -6,7 +6,7 @@ * var param_1 = obj.get(key) * obj.put(key,value) */ - class LRUCache { +class LRUCache { constructor(capacity) { this.capacity = capacity; this.map = new Map(); @@ -18,18 +18,22 @@ this.tail.prev = this.head; } - removeLastUsed () { - const [ key, next, prev ] = [ this.head.next.key, this.head.next.next, this.head ]; + removeLastUsed() { + const [key, next, prev] = [ + this.head.next.key, + this.head.next.next, + this.head, + ]; this.map.delete(key); this.head.next = next; this.head.next.prev = prev; } - put (key, value) { + put(key, value) { const hasKey = this.get(key) !== -1; const isAtCapacity = this.map.size === this.capacity; - + if (hasKey) return (this.tail.prev.value = value); if (isAtCapacity) this.removeLastUsed(); @@ -38,32 +42,32 @@ this.moveToFront(node); } - moveToFront (node) { - const [ prev, next ] = [ this.tail.prev, this.tail ]; + moveToFront(node) { + const [prev, next] = [this.tail.prev, this.tail]; this.tail.prev.next = node; this.connectNode(node, { prev, next }); this.tail.prev = node; } - connectNode (node, top) { + connectNode(node, top) { node.prev = top.prev; node.next = top.next; } - get (key) { + get(key) { const hasKey = this.map.has(key); if (!hasKey) return -1; const node = this.map.get(key); - + this.disconnectNode(node); this.moveToFront(node); return node.value; } - disconnectNode (node) { + disconnectNode(node) { node.next.prev = node.prev; node.prev.next = node.next; } diff --git a/javascript/0150-evaluate-reverse-polish-notation.js b/javascript/0150-evaluate-reverse-polish-notation.js index 26160454e..bc63b9c80 100644 --- a/javascript/0150-evaluate-reverse-polish-notation.js +++ b/javascript/0150-evaluate-reverse-polish-notation.js @@ -4,15 +4,16 @@ * @param {string[]} tokens * @return {number} */ -var evalRPN = function(tokens, index = 0) { - while (1 < tokens.length) {/* Time O(N) */ +var evalRPN = function (tokens, index = 0) { + while (1 < tokens.length) { + /* Time O(N) */ const isOperation = () => tokens[index] in OPERATORS; - while (!isOperation()) index++;/* Time O(N) */ + while (!isOperation()) index++; /* Time O(N) */ const value = performOperation(tokens, index); tokens[index] = value; - tokens.splice((index - 2), 2);/* Time O(N) */ + tokens.splice(index - 2, 2); /* Time O(N) */ index--; } @@ -27,11 +28,14 @@ var OPERATORS = { }; var performOperation = (tokens, index) => { - const [ rightNum, leftNum ] = [ Number(tokens[index - 1]), Number(tokens[index - 2]) ] + const [rightNum, leftNum] = [ + Number(tokens[index - 1]), + Number(tokens[index - 2]), + ]; const operation = OPERATORS[tokens[index]]; return operation(leftNum, rightNum); -} +}; /** * https://leetcode.com/problems/evaluate-reverse-polish-notation @@ -40,32 +44,33 @@ var performOperation = (tokens, index) => { * @return {number} */ var evalRPN = function (tokens, stack = []) { - for (const char of tokens) {/* Time O(N) */ + for (const char of tokens) { + /* Time O(N) */ const isOperation = char in OPERATORS; if (isOperation) { const value = performOperation(char, stack); - stack.push(value); /* Space O(N) */ + stack.push(value); /* Space O(N) */ continue; } - stack.push(Number(char)); /* Space O(N) */ + stack.push(Number(char)); /* Space O(N) */ } return stack.pop(); -} +}; var OPERATORS = { '+': (a, b) => a + b, '-': (a, b) => a - b, '*': (a, b) => a * b, - '/': (a, b) => Math.trunc(a / b) + '/': (a, b) => Math.trunc(a / b), }; var performOperation = (char, stack) => { - const [ rightNum, leftNum ] = [ stack.pop(), stack.pop() ]; + const [rightNum, leftNum] = [stack.pop(), stack.pop()]; const operation = OPERATORS[char]; return operation(leftNum, rightNum); -} \ No newline at end of file +}; diff --git a/javascript/0152-maximum-product-subarray.js b/javascript/0152-maximum-product-subarray.js index b2ceeb9fa..33c680939 100644 --- a/javascript/0152-maximum-product-subarray.js +++ b/javascript/0152-maximum-product-subarray.js @@ -5,29 +5,31 @@ * @param {number[]} nums * @return {number} */ - var maxProduct = (nums) => { +var maxProduct = (nums) => { const isEmpty = nums.length === 0; if (isEmpty) return 0; - return linearSearch(nums);/* Time O(N * N) */ -} + return linearSearch(nums); /* Time O(N * N) */ +}; const linearSearch = (nums, max = nums[0]) => { - for (let index = 0; index < nums.length; index++) {/* Time O(N) */ - max = getMax(nums, index, max); /* Time O(N) */ + for (let index = 0; index < nums.length; index++) { + /* Time O(N) */ + max = getMax(nums, index, max); /* Time O(N) */ } return max; -} +}; const getMax = (nums, index, max, product = 1) => { - for (let num = index; num < nums.length; num++) {/* Time O(N) */ + for (let num = index; num < nums.length; num++) { + /* Time O(N) */ product *= nums[num]; max = Math.max(max, product); } return max; -} +}; /** * Greedy - product @@ -40,14 +42,15 @@ var maxProduct = (nums) => { const isEmpty = nums.length === 0; if (isEmpty) return 0; - return greedySearch(nums);/* Time O(N) */ + return greedySearch(nums); /* Time O(N) */ }; const greedySearch = (nums) => { - let min = max = product = nums[0]; + let min = (max = product = nums[0]); - for (let num = 1; num < nums.length; num++) {/* Time O(N) */ - const [ minProduct, maxProduct ] = [ (min * nums[num]), (max * nums[num]) ]; + for (let num = 1; num < nums.length; num++) { + /* Time O(N) */ + const [minProduct, maxProduct] = [min * nums[num], max * nums[num]]; min = Math.min(maxProduct, minProduct, nums[num]); max = Math.max(maxProduct, minProduct, nums[num]); @@ -56,4 +59,4 @@ const greedySearch = (nums) => { } return product; -} \ No newline at end of file +}; diff --git a/javascript/0155-min-stack.js b/javascript/0155-min-stack.js index a84c66b5b..7dfb08b93 100644 --- a/javascript/0155-min-stack.js +++ b/javascript/0155-min-stack.js @@ -1,4 +1,4 @@ -/** +/** * https://leetcode.com/problems/min-stack * Time O(1) | Space O(N) * Your MinStack object will be instantiated and called as such: @@ -12,7 +12,7 @@ class MinStack { /** * @constructor */ - constructor () { + constructor() { this.stack = []; this.minStack = []; } @@ -21,45 +21,42 @@ class MinStack { * @param {number} val * @return {void} */ - push (val, { minStack } = this) { - this.stack.push(val); /* Space O(N) */ + push(val, { minStack } = this) { + this.stack.push(val); /* Space O(N) */ const isMinEmpty = !minStack.length; const hasNewMin = val <= this.top(minStack); const canAddMin = isMinEmpty || hasNewMin; - if (canAddMin) minStack.push(val);/* Space O(N) */ + if (canAddMin) minStack.push(val); /* Space O(N) */ } /** * @return {void} */ - pop ({ stack, minStack } = this) { - const top = stack.pop(); /* Time O(1) */ + pop({ stack, minStack } = this) { + const top = stack.pop(); /* Time O(1) */ const canPopMin = top === this.getMin(); - if (canPopMin) minStack.pop(); /* Time O(1) */ + if (canPopMin) minStack.pop(); /* Time O(1) */ } /** * @param {Array} * @return {number} */ - top (stack = this.stack) { - return stack.length - ? stack[stack.length - 1] /* Time O(1) */ - : null; + top(stack = this.stack) { + return stack.length ? stack[stack.length - 1] /* Time O(1) */ : null; } /** * @return {number} */ - getMin (minStack = this.minStack) { - return this.top(minStack); /* Time O(1) */ + getMin(minStack = this.minStack) { + return this.top(minStack); /* Time O(1) */ } } - -/** +/** * https://leetcode.com/problems/min-stack * Time O(1) | Space O(1) * Your MinStack object will be instantiated and called as such: @@ -70,31 +67,31 @@ class MinStack { * var param_4 = obj.getMin() */ class MinStack { - constructor () { - this.head = null + constructor() { + this.head = null; } - push (val) { - this.head = (!this.head) /* Space O(1) */ + push(val) { + this.head = !this.head /* Space O(1) */ ? new Node(val, val, null) : new Node(val, Math.min(val, this.head.min), this.head); } - pop () { - this.head = this.head.next;/* Time O(1) */ + pop() { + this.head = this.head.next; /* Time O(1) */ } - top () { - return this.head.val; /* Time O(1) */ + top() { + return this.head.val; /* Time O(1) */ } - getMin () { - return this.head.min; /* Time O(1) */ + getMin() { + return this.head.min; /* Time O(1) */ } } class Node { - constructor (val, min, next) { + constructor(val, min, next) { this.val = val; this.min = min; this.next = next; diff --git a/javascript/0162-find-peak-element.js b/javascript/0162-find-peak-element.js index cabcc5fc5..88f3589e2 100644 --- a/javascript/0162-find-peak-element.js +++ b/javascript/0162-find-peak-element.js @@ -3,18 +3,16 @@ * @param {number[]} nums * @return {number} */ -var findPeakElement = function(nums) { +var findPeakElement = function (nums) { let [l, r] = [0, nums.length - 1]; let mid = null; - while (l <= r){ + while (l <= r) { mid = (l + r) >> 1; - if (mid < nums.length - 1 && nums[mid] < nums[mid+1]){ + if (mid < nums.length - 1 && nums[mid] < nums[mid + 1]) { l = mid + 1; - } - else if (mid > 0 && nums[mid] < nums[mid-1]) { + } else if (mid > 0 && nums[mid] < nums[mid - 1]) { r = mid - 1; - } - else { + } else { break; } } diff --git a/javascript/0169-majority-element.js b/javascript/0169-majority-element.js index 97b4f366d..c491e68e6 100644 --- a/javascript/0169-majority-element.js +++ b/javascript/0169-majority-element.js @@ -7,18 +7,18 @@ */ var majorityElement = function (nums) { - let res = nums[0]; - let count = 1; + let res = nums[0]; + let count = 1; - for (let i = 1; i < nums.length - 1; i++) { - if (nums[i] === res) count++; - else if (!--count) { - res = nums[i + 1]; - count = 0; - } - } + for (let i = 1; i < nums.length - 1; i++) { + if (nums[i] === res) count++; + else if (!--count) { + res = nums[i + 1]; + count = 0; + } + } - return res; + return res; }; /** @@ -30,18 +30,18 @@ var majorityElement = function (nums) { */ var majorityElement = function (nums) { - const occuranceOfElement = new Map(); - - for (let i = 0; i < nums.length; i++) { - if (occuranceOfElement.has(nums[i])) { - let occurance = occuranceOfElement.get(nums[i]); - occuranceOfElement.set(nums[i], occurance + 1); - } else { - occuranceOfElement.set(nums[i], 1); - } - } + const occuranceOfElement = new Map(); - for (let [key, value] of occuranceOfElement) { - if (value > nums.length / 2) return key; - } + for (let i = 0; i < nums.length; i++) { + if (occuranceOfElement.has(nums[i])) { + let occurance = occuranceOfElement.get(nums[i]); + occuranceOfElement.set(nums[i], occurance + 1); + } else { + occuranceOfElement.set(nums[i], 1); + } + } + + for (let [key, value] of occuranceOfElement) { + if (value > nums.length / 2) return key; + } }; diff --git a/javascript/0173-binary-search-tree-iterator.js b/javascript/0173-binary-search-tree-iterator.js index ae547001b..5da2d3e99 100644 --- a/javascript/0173-binary-search-tree-iterator.js +++ b/javascript/0173-binary-search-tree-iterator.js @@ -14,18 +14,19 @@ * @param {TreeNode} root */ class BSTIterator { - constructor (root) { - this.stack = []; /* | Space O(N) */ - this.getLeft(root);/* Time O(N) | Space O(N)*/ + constructor(root) { + this.stack = []; /* | Space O(N) */ + this.getLeft(root); /* Time O(N) | Space O(N)*/ } /** * Time O(N) | Space O(H) * @return {number} */ - getLeft (root, { stack } = this) { - while (root !== null) {/* Time O(N) */ - stack.push(root); /* Space O(N) */ + getLeft(root, { stack } = this) { + while (root !== null) { + /* Time O(N) */ + stack.push(root); /* Space O(N) */ root = root.left; } } @@ -35,25 +36,25 @@ class BSTIterator { * @return the next smallest number * @return {number} */ - next ({ stack } = this) { + next({ stack } = this) { const node = stack.pop(); - if (node.right) this.getLeft(node.right);/* Time O(N) | Space O(N) */ + if (node.right) this.getLeft(node.right); /* Time O(N) | Space O(N) */ return node.val; - }; + } /** * Time O(1) | Space O(1) * @return whether we have a next smallest number * @return {boolean} */ - hasNext ({ stack } = this) { - return (stack.length !== 0); + hasNext({ stack } = this) { + return stack.length !== 0; } } -/** +/** * Your BSTIterator object will be instantiated and called as such: * var obj = new BSTIterator(root) * var param_1 = obj.next() diff --git a/javascript/0189-rotate-array.js b/javascript/0189-rotate-array.js index b8ff1562c..4442d98d7 100644 --- a/javascript/0189-rotate-array.js +++ b/javascript/0189-rotate-array.js @@ -1,64 +1,60 @@ /** * Two Pointers * https://leetcode.com/problems/rotate-array/ - * + * * Time O(n) | Space O(1) * @param {number[]} nums * @param {number} k * @return {void} Do not return anything, modify nums in-place instead. */ - var rotate = function(nums, k) { - +var rotate = function (nums, k) { // if the k exceeds the length of nums. k = k % nums.length; nums.reverse(); reversePortionOfArray(nums, 0, k - 1); - reversePortionOfArray(nums,k, nums.length - 1); + reversePortionOfArray(nums, k, nums.length - 1); }; -var reversePortionOfArray = function(nums,start,end) { - while(start < end) { - [nums[start],nums[end]] = [nums[end],nums[start]]; +var reversePortionOfArray = function (nums, start, end) { + while (start < end) { + [nums[start], nums[end]] = [nums[end], nums[start]]; start++; end--; - } -} - + } +}; /** * Two Pointers * https://leetcode.com/problems/rotate-array/ - * + * * Time O(n) | Space O(1) * @param {number[]} nums * @param {number} k * @return {void} Do not return anything, modify nums in-place instead. */ -var rotate = function(nums, k) { - - k = k % nums.length; - - let l = 0; - let r = nums.length - 1; +var rotate = function (nums, k) { + k = k % nums.length; + + let l = 0; + let r = nums.length - 1; - while (l < r) { - [nums[l], nums[r]] = [nums[r], nums[l]]; - l += 1; - r -= 1; - } - l = 0, - r = k - 1; - while (l < r) { - [nums[l], nums[r]] = [nums[r], nums[l]]; - l += 1; - r -= 1; - } - l = k; - r = nums.length - 1; - while (l < r) { - [nums[l], nums[r]] = [nums[r], nums[l]]; - l += 1; - r -= 1; - } + while (l < r) { + [nums[l], nums[r]] = [nums[r], nums[l]]; + l += 1; + r -= 1; + } + ((l = 0), (r = k - 1)); + while (l < r) { + [nums[l], nums[r]] = [nums[r], nums[l]]; + l += 1; + r -= 1; + } + l = k; + r = nums.length - 1; + while (l < r) { + [nums[l], nums[r]] = [nums[r], nums[l]]; + l += 1; + r -= 1; + } }; diff --git a/javascript/0190-reverse-bits.js b/javascript/0190-reverse-bits.js index fc286c4a7..20d55ba2e 100644 --- a/javascript/0190-reverse-bits.js +++ b/javascript/0190-reverse-bits.js @@ -6,9 +6,9 @@ */ var reverseBits = function (n, bit = 0) { for (let i = 0; i < 32; i++) { - bit <<= 1; // Double * 2 - bit |= (n & 1); // Flip - n >>= 1; // Reduce * 0.5 + bit <<= 1; // Double * 2 + bit |= n & 1; // Flip + n >>= 1; // Reduce * 0.5 } return bit >>> 0; diff --git a/javascript/0191-number-of-1-bits.js b/javascript/0191-number-of-1-bits.js index d98d2e8eb..259509bd1 100644 --- a/javascript/0191-number-of-1-bits.js +++ b/javascript/0191-number-of-1-bits.js @@ -4,17 +4,17 @@ * @param {number} n - a positive integer * @return {number} */ - var hammingWeight = function(n) { - let [ bits, mask ] = [ 0, 1 ] - +var hammingWeight = function (n) { + let [bits, mask] = [0, 1]; + for (let i = 0; i < 32; i++) { - const hasBit = ((n & mask) !== 0) - if (hasBit) bits++ - - mask <<= 1 + const hasBit = (n & mask) !== 0; + if (hasBit) bits++; + + mask <<= 1; } - - return bits + + return bits; }; /** @@ -23,11 +23,11 @@ * @param {number} n - a positive integer * @return {number} */ - var hammingWeight = function(n, sum = 0) { +var hammingWeight = function (n, sum = 0) { while (n !== 0) { - n &= (n - 1) - sum++ + n &= n - 1; + sum++; } - - return sum -} + + return sum; +}; diff --git a/javascript/0198-house-robber.js b/javascript/0198-house-robber.js index 34ef665c5..c41e0d1da 100644 --- a/javascript/0198-house-robber.js +++ b/javascript/0198-house-robber.js @@ -9,10 +9,10 @@ var rob = (nums, i = 0) => { const isBaseCase = nums <= i; if (isBaseCase) return 0; - const [ next, nextNext ] = [ (i + 1), (i + 2) ]; + const [next, nextNext] = [i + 1, i + 2]; const right = nums[i]; - const mid = rob(nums, next); /* Time O(2^N) | Space O(N) */ - const left = rob(nums, nextNext);/* Time O(2^N) | Space O(N) */ + const mid = rob(nums, next); /* Time O(2^N) | Space O(N) */ + const left = rob(nums, nextNext); /* Time O(2^N) | Space O(N) */ const house = left + right; return Math.max(house, mid); @@ -33,13 +33,13 @@ var rob = (nums, i = 0, memo = initMemo(nums)) => { const hasSeen = 0 <= memo[i]; if (hasSeen) return memo[i]; - const [ next, nextNext ] = [ (i + 1), (i + 2) ]; + const [next, nextNext] = [i + 1, i + 2]; const right = nums[i]; - const mid = rob(nums, next, memo); /* Time O(N) | Space O(N) */ - const left = rob(nums, nextNext, memo);/* Time O(N) | Space O(N) */ + const mid = rob(nums, next, memo); /* Time O(N) | Space O(N) */ + const left = rob(nums, nextNext, memo); /* Time O(N) | Space O(N) */ const house = left + right; - memo[i] = Math.max(mid, house); /* | Space O(N) */ + memo[i] = Math.max(mid, house); /* | Space O(N) */ return memo[i]; }; @@ -59,16 +59,17 @@ var rob = (nums) => { const tabu = initTabu(nums); - for (let i = 1; i < nums.length; i++) {/* Time O(N) */ + for (let i = 1; i < nums.length; i++) { + /* Time O(N) */ const right = nums[i]; const mid = tabu[i]; const left = tabu[i - 1]; const house = left + right; - tabu[i + 1] = Math.max(mid, house); /* Space O(N) */ + tabu[i + 1] = Math.max(mid, house); /* Space O(N) */ } - return tabu[nums.length] + return tabu[nums.length]; }; const initTabu = (nums) => { @@ -77,7 +78,7 @@ const initTabu = (nums) => { tabu[1] = nums[0]; return tabu; -} +}; /** * DP - Bottom Up @@ -89,9 +90,10 @@ const initTabu = (nums) => { var rob = (nums) => { if (!nums.length) return 0; - let [ left, mid ] = [ 0, 0 ]; + let [left, mid] = [0, 0]; - for (const right of nums) {/* Time O(N) */ + for (const right of nums) { + /* Time O(N) */ const temp = mid; const house = left + right; @@ -100,4 +102,4 @@ var rob = (nums) => { } return mid; -}; \ No newline at end of file +}; diff --git a/javascript/0199-binary-tree-right-side-view.js b/javascript/0199-binary-tree-right-side-view.js index 35fb95b62..37e7a08d5 100644 --- a/javascript/0199-binary-tree-right-side-view.js +++ b/javascript/0199-binary-tree-right-side-view.js @@ -4,18 +4,18 @@ * @param {TreeNode} root * @return {number[]} */ - var rightSideView = function(root) { +var rightSideView = function (root) { const isBaseCase = root === null; if (isBaseCase) return []; - return bfs([ root ]); + return bfs([root]); }; const bfs = (queue, rightSide = []) => { while (queue.length) { let prev = null; - for (let i = (queue.length - 1); 0 <= i; i--) { + for (let i = queue.length - 1; 0 <= i; i--) { const node = queue.shift(); prev = node; @@ -28,7 +28,7 @@ const bfs = (queue, rightSide = []) => { } return rightSide; -} +}; /** * https://leetcode.com/problems/binary-tree-right-side-view/ @@ -36,20 +36,19 @@ const bfs = (queue, rightSide = []) => { * @param {TreeNode} root * @return {number[]} */ - var rightSideView = function(root, level = 0, rightSide = []) { +var rightSideView = function (root, level = 0, rightSide = []) { const isBaseCase = root === null; if (isBaseCase) return rightSide; - const isLastNode = level === rightSide.length + const isLastNode = level === rightSide.length; if (isLastNode) rightSide.push(root.val); - return dfs(root, level, rightSide) -} + return dfs(root, level, rightSide); +}; const dfs = (root, level, rightSide) => { - if (root.right) rightSideView(root.right, (level + 1), rightSide); - if (root.left) rightSideView(root.left, (level + 1), rightSide); - - return rightSide -} + if (root.right) rightSideView(root.right, level + 1, rightSide); + if (root.left) rightSideView(root.left, level + 1, rightSide); + return rightSide; +}; diff --git a/javascript/0200-number-of-islands.js b/javascript/0200-number-of-islands.js index e0ba467a4..b1bfd473f 100644 --- a/javascript/0200-number-of-islands.js +++ b/javascript/0200-number-of-islands.js @@ -4,19 +4,21 @@ * @param {character[][]} grid * @return {number} */ -var numIslands = function(grid, connectedComponents = 0) { - const [ rows, cols ] = [ grid.length, grid[0].length ] +var numIslands = function (grid, connectedComponents = 0) { + const [rows, cols] = [grid.length, grid[0].length]; - for (let row = 0; row < rows; row++) {/* Time O(ROWS) */ - for (let col = 0; col < cols; col++) {/* Time O(COLS) */ - const isIsland = grid[row][col] === '1' - if (isIsland) connectedComponents++ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ + const isIsland = grid[row][col] === '1'; + if (isIsland) connectedComponents++; - dfs(grid, row, rows, col, cols); /* Space O(ROWS * COLS) */ + dfs(grid, row, rows, col, cols); /* Space O(ROWS * COLS) */ } } - return connectedComponents + return connectedComponents; }; const dfs = (grid, row, rows, col, cols) => { @@ -25,14 +27,23 @@ const dfs = (grid, row, rows, col, cols) => { grid[row][col] = '0'; - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) { - dfs(grid, _row, rows, _col, cols); /* Space O(ROWS * COLS) */ + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { + dfs(grid, _row, rows, _col, cols); /* Space O(ROWS * COLS) */ } -} +}; -var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ] - .map(([ _row, _col ]) => [ (row + _row), (col + _col) ]) - .filter(([ _row, _col ]) => (0 <= _row) && (_row < rows) && (0 <= _col) && (_col < cols)) +var getNeighbors = (row, rows, col, cols) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + .map(([_row, _col]) => [row + _row, col + _col]) + .filter( + ([_row, _col]) => + 0 <= _row && _row < rows && 0 <= _col && _col < cols, + ); /** * https://leetcode.com/problems/number-of-islands/ @@ -40,41 +51,58 @@ var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ * @param {character[][]} grid * @return {number} */ - var numIslands = function(grid, connectedComponents = 0) { - const [ rows, cols ] = [ grid.length, grid[0].length ] +var numIslands = function (grid, connectedComponents = 0) { + const [rows, cols] = [grid.length, grid[0].length]; - for (let row = 0; row < rows; row++) {/* Time O(ROWS) */ - for (let col = 0; col < cols; col++) {/* Time O(COLS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ const isIsland = grid[row][col] === '1'; if (isIsland) connectedComponents++; - bfs(grid, rows, cols, new Queue([ [ row, col ] ]));/* Space O(MIN(ROWS,COLS)) */ + bfs( + grid, + rows, + cols, + new Queue([[row, col]]), + ); /* Space O(MIN(ROWS,COLS)) */ } } - return connectedComponents - } + return connectedComponents; +}; - const bfs = (grid, rows, cols, queue) => { +const bfs = (grid, rows, cols, queue) => { while (!queue.isEmpty()) { - for (let i = (queue.size() - 1); 0 <= i; i--) {/* Time O(WIDTH) */ - const [ row, col ] = queue.dequeue(); + for (let i = queue.size() - 1; 0 <= i; i--) { + /* Time O(WIDTH) */ + const [row, col] = queue.dequeue(); const isWater = grid[row][col] === '0'; if (isWater) continue; grid[row][col] = '0'; - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) { - queue.enqueue([ _row, _col ]); /* Space O(MIN(ROWS,COLS)) */ + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { + queue.enqueue([_row, _col]); /* Space O(MIN(ROWS,COLS)) */ } } } - } +}; -var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ] - .map(([ _row, _col]) => [ (row + _row), (col + _col) ]) - .filter(([ _row, _col ]) => (0 <= _row) && (_row < rows) && (0 <= _col) && (_col < cols)); +var getNeighbors = (row, rows, col, cols) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + .map(([_row, _col]) => [row + _row, col + _col]) + .filter( + ([_row, _col]) => + 0 <= _row && _row < rows && 0 <= _col && _col < cols, + ); /** * https://leetcode.com/problems/number-of-islands/ @@ -83,18 +111,22 @@ var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ * @return {number} */ var numIslands = function (grid) { - const unionFind = new UnionFind(grid);/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ + const unionFind = new UnionFind( + grid, + ); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ - searchGrid(grid, unionFind); /* Time O(ROWS * COLS) */ + searchGrid(grid, unionFind); /* Time O(ROWS * COLS) */ return unionFind.connectedComponents; -} +}; var searchGrid = (grid, unionFind) => { - const [ rows, cols ] = [ grid.length, grid[0].length ]; + const [rows, cols] = [grid.length, grid[0].length]; - for (let row = 0; row < rows; row++) {/* Time O(ROWS) */ - for (let col = 0; col < cols; col++) {/* Time O(COLS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ const isWater = grid[row][col] === '0'; if (isWater) continue; @@ -104,27 +136,29 @@ var searchGrid = (grid, unionFind) => { searchCols(unionFind, grid, row, rows, col, cols); } } -} +}; -const searchRows = (unionFind, grid, row, rows, col, cols) => [ 1, -1 ] - .map((_row) => row + _row) - .filter((_row) => isInBound(_row, rows) && isIsland(grid[_row][col])) - .map((_row) => [ index(row, cols, col), index(_row, cols, col) ]) - .forEach(([ x, y ]) => unionFind.union(x, y)); +const searchRows = (unionFind, grid, row, rows, col, cols) => + [1, -1] + .map((_row) => row + _row) + .filter((_row) => isInBound(_row, rows) && isIsland(grid[_row][col])) + .map((_row) => [index(row, cols, col), index(_row, cols, col)]) + .forEach(([x, y]) => unionFind.union(x, y)); -const isInBound = (val, vals) => (0 <= val) && (val < vals) -const isIsland = (cell) => cell === '1' -const index = (row, cols, col) => ((row * cols) + col) +const isInBound = (val, vals) => 0 <= val && val < vals; +const isIsland = (cell) => cell === '1'; +const index = (row, cols, col) => row * cols + col; -const searchCols = (unionFind, grid, row, rows, col, cols) => [ 1, -1 ] - .map((_col) => col + _col) - .filter((_col) => isInBound(_col, cols) && isIsland(grid[row][_col])) - .map((_col) => [ index(row, cols, col), index(row, cols, _col) ]) - .forEach(([ x, y ]) => unionFind.union(x, y)); +const searchCols = (unionFind, grid, row, rows, col, cols) => + [1, -1] + .map((_col) => col + _col) + .filter((_col) => isInBound(_col, cols) && isIsland(grid[row][_col])) + .map((_col) => [index(row, cols, col), index(row, cols, _col)]) + .forEach(([x, y]) => unionFind.union(x, y)); class UnionFind { - constructor (grid) { - const [ rows, cols ] = [ grid.length, grid[0].length ]; + constructor(grid) { + const [rows, cols] = [grid.length, grid[0].length]; this.connectedComponents = 0; this.grid = grid; @@ -136,21 +170,23 @@ class UnionFind { this.findIslands(); } - findIslands ({ grid, rows, cols, parent } = this) { - for (let row = 0; row < rows; row++) {/* Time O(ROWS) */ - for (let col = 0; col < cols; col++) {/* Time O(COLS) */ + findIslands({ grid, rows, cols, parent } = this) { + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ const isWater = grid[row][col] === '0'; if (isWater) continue; - const index = (row * cols) + col; + const index = row * cols + col; - parent[index] = index;/* Space O(ROWS * COLS) */ + parent[index] = index; /* Space O(ROWS * COLS) */ this.connectedComponents++; } } } - find (index, { parent } = this) { + find(index, { parent } = this) { const isEqual = () => parent[index] === index; while (!isEqual()) { index = parent[index]; @@ -159,8 +195,8 @@ class UnionFind { return parent[index]; } - union (x, y, { parent, rank } = this) { - const [ rootX, rootY ] = [ this.find(x), this.find(y) ]; + union(x, y, { parent, rank } = this) { + const [rootX, rootY] = [this.find(x), this.find(y)]; const hasCycle = rootX === rootY; if (hasCycle) return; @@ -168,12 +204,12 @@ class UnionFind { this.connectedComponents--; const isXGreater = rank[rootY] < rank[rootX]; - if (isXGreater) return parent[rootY] = rootX; + if (isXGreater) return (parent[rootY] = rootX); const isYGreater = rank[rootX] < rank[rootY]; - if (isYGreater) return parent[rootX] = rootY; + if (isYGreater) return (parent[rootX] = rootY); - parent[rootY] = rootX; /* Space O(ROWS * COLS) */ - rank[rootX]++; /* Space O(ROWS * COLS) */ + parent[rootY] = rootX; /* Space O(ROWS * COLS) */ + rank[rootX]++; /* Space O(ROWS * COLS) */ } } diff --git a/javascript/0202-happy-number.js b/javascript/0202-happy-number.js index c2a2efece..faa6c4917 100644 --- a/javascript/0202-happy-number.js +++ b/javascript/0202-happy-number.js @@ -5,26 +5,28 @@ * @param {number} n * @return {boolean} */ - var isHappy = (n, seen = new Set()) => { - const hasCycle = () => ((n === 1) || (seen.has(n))); - while (!hasCycle()) {/* Time O(log(N)) */ - seen.add(n); /* Space O(log(N)) */ - n = getNext(n); /* Time O(log(N)) */ +var isHappy = (n, seen = new Set()) => { + const hasCycle = () => n === 1 || seen.has(n); + while (!hasCycle()) { + /* Time O(log(N)) */ + seen.add(n); /* Space O(log(N)) */ + n = getNext(n); /* Time O(log(N)) */ } - return (n === 1); + return n === 1; }; var getNext = (n, sum = 0) => { - while (0 < n) {/* Time O(log(N)) */ - const remainder = (n % 10); + while (0 < n) { + /* Time O(log(N)) */ + const remainder = n % 10; - n = Math.floor((n / 10)); - sum += (remainder * remainder); + n = Math.floor(n / 10); + sum += remainder * remainder; } return sum; -} +}; /** * Hash Set - seen static @@ -34,27 +36,29 @@ var getNext = (n, sum = 0) => { * @return {boolean} */ var isHappy = (n) => { - const cycles = [ 4, 16, 37, 58, 89, 145, 42, 20 ]; - const seen = new Set(cycles);/* Time O(1) | Space O(1) */ + const cycles = [4, 16, 37, 58, 89, 145, 42, 20]; + const seen = new Set(cycles); /* Time O(1) | Space O(1) */ - const hasCycle = () => ((n === 1) || (seen.has(n))); - while (!hasCycle()) { /* Time O(log(N)) | Space O(1) */ + const hasCycle = () => n === 1 || seen.has(n); + while (!hasCycle()) { + /* Time O(log(N)) | Space O(1) */ n = getNext(n); } return n === 1; -} +}; var getNext = (n, sum = 0) => { - while (0 < n) {/* Time O(log(N)) */ - const remainder = (n % 10); + while (0 < n) { + /* Time O(log(N)) */ + const remainder = n % 10; - n = Math.floor((n / 10)); - sum += (remainder * remainder); + n = Math.floor(n / 10); + sum += remainder * remainder; } return sum; -} +}; /** * Pointer - n === 1 || n === 4 @@ -64,24 +68,26 @@ var getNext = (n, sum = 0) => { * @return {boolean} */ var isHappy = (n) => { - const hasCycle = () => ((n === 1) || (n === 4)); - while (!hasCycle()) {/* Time O(log(N)) */ - n = getNext(n); /* Time O(log(N)) */ + const hasCycle = () => n === 1 || n === 4; + while (!hasCycle()) { + /* Time O(log(N)) */ + n = getNext(n); /* Time O(log(N)) */ } return n === 1; -} +}; var getNext = (n, sum = 0) => { - while (0 < n) {/* Time O(log(N)) */ - const remainder = (n % 10); - - n = Math.floor((n / 10)); - sum += (remainder * remainder); + while (0 < n) { + /* Time O(log(N)) */ + const remainder = n % 10; + + n = Math.floor(n / 10); + sum += remainder * remainder; } return sum; -} +}; /** * Slow Fast @@ -91,24 +97,26 @@ var getNext = (n, sum = 0) => { * @return {boolean} */ var isHappy = (n) => { - let [ slow, fast ] = [ n, getNext(n) ]; - - const hasCyle = () => ((fast === 1) || (slow === fast)); - while (!hasCyle()) { /* Time O(log(N)) */ - slow = getNext(slow); /* Time O(log(N)) */ - fast = getNext(getNext(fast));/* Time O(log(N)) */ + let [slow, fast] = [n, getNext(n)]; + + const hasCyle = () => fast === 1 || slow === fast; + while (!hasCyle()) { + /* Time O(log(N)) */ + slow = getNext(slow); /* Time O(log(N)) */ + fast = getNext(getNext(fast)); /* Time O(log(N)) */ } - return (fast === 1); -} + return fast === 1; +}; var getNext = (n, sum = 0) => { - while (0 < n) {/* Time O(log(N)) */ - const remainder = (n % 10); + while (0 < n) { + /* Time O(log(N)) */ + const remainder = n % 10; - n = Math.floor((n / 10)); - sum += (remainder * remainder); + n = Math.floor(n / 10); + sum += remainder * remainder; } return sum; -} \ No newline at end of file +}; diff --git a/javascript/0203-remove-linked-list-elements.js b/javascript/0203-remove-linked-list-elements.js index 298626e72..f4f30b356 100644 --- a/javascript/0203-remove-linked-list-elements.js +++ b/javascript/0203-remove-linked-list-elements.js @@ -1,32 +1,31 @@ -/** - * Definition for singly-linked list. - * function ListNode(val, next) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - */ -/** - * @param {ListNode} head - * @param {number} val - * @return {ListNode} - */ -var removeElements = function (head, val) { - - let sentinel_node = new ListNode(0, head); - let slow_pointer = sentinel_node; - let fast_pointer = null; - - while (slow_pointer) { - // get next legible node - fast_pointer = slow_pointer.next; - while (fast_pointer && fast_pointer.val === val) { - fast_pointer = fast_pointer.next; - } - - // Set next node to the legible node - slow_pointer.next = fast_pointer; - slow_pointer = slow_pointer.next; - } - - return sentinel_node.next; -}; +/** + * Definition for singly-linked list. + * function ListNode(val, next) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + */ +/** + * @param {ListNode} head + * @param {number} val + * @return {ListNode} + */ +var removeElements = function (head, val) { + let sentinel_node = new ListNode(0, head); + let slow_pointer = sentinel_node; + let fast_pointer = null; + + while (slow_pointer) { + // get next legible node + fast_pointer = slow_pointer.next; + while (fast_pointer && fast_pointer.val === val) { + fast_pointer = fast_pointer.next; + } + + // Set next node to the legible node + slow_pointer.next = fast_pointer; + slow_pointer = slow_pointer.next; + } + + return sentinel_node.next; +}; diff --git a/javascript/0206-reverse-linked-list.js b/javascript/0206-reverse-linked-list.js index 5ad06b365..798c8ff85 100644 --- a/javascript/0206-reverse-linked-list.js +++ b/javascript/0206-reverse-linked-list.js @@ -8,17 +8,17 @@ var reverseList = function (head) { const isBaseCase = !head?.next; if (isBaseCase) return head; - return dfs(head); /* Time O(N) | Space O(N) */ -} + return dfs(head); /* Time O(N) | Space O(N) */ +}; const dfs = (curr) => { - const prev = reverseList(curr.next);/* Time O(N) | Space O(N) */ + const prev = reverseList(curr.next); /* Time O(N) | Space O(N) */ curr.next.next = curr; curr.next = null; return prev; -} +}; /** * https://leetcode.com/problems/reverse-linked-list/ @@ -26,10 +26,11 @@ const dfs = (curr) => { * @param {ListNode} head * @return {ListNode} */ - var reverseList = function (head) { - let [ prev, curr, next ] = [ null, head, null ]; +var reverseList = function (head) { + let [prev, curr, next] = [null, head, null]; - while (curr) {/* Time O(N) */ + while (curr) { + /* Time O(N) */ next = curr.next; curr.next = prev; @@ -38,4 +39,4 @@ const dfs = (curr) => { } return prev; -}; \ No newline at end of file +}; diff --git a/javascript/0207-course-schedule.js b/javascript/0207-course-schedule.js index 7f604d3a8..c211ff747 100644 --- a/javascript/0207-course-schedule.js +++ b/javascript/0207-course-schedule.js @@ -5,22 +5,22 @@ * @param {number[][]} prerequisites * @return {boolean} */ -var canFinish = function(numCourses, prerequisites) { +var canFinish = function (numCourses, prerequisites) { const { graph, path } = buildGraph(numCourses, prerequisites); return hasPath(numCourses, graph, path); -} +}; var initGraph = (numCourses) => ({ graph: new Array(numCourses).fill().map(() => []), - path: new Array(numCourses).fill(false) -}) + path: new Array(numCourses).fill(false), +}); var buildGraph = (numCourses, prerequisites) => { const { graph, path } = initGraph(numCourses); - for (const [ src, dst ] of prerequisites) { - const neighbors = (graph[dst] || []); + for (const [src, dst] of prerequisites) { + const neighbors = graph[dst] || []; neighbors.push(src); @@ -28,7 +28,7 @@ var buildGraph = (numCourses, prerequisites) => { } return { graph, path }; -} +}; var hasPath = (numCourses, graph, path) => { for (let course = 0; course < numCourses; course++) { @@ -36,33 +36,33 @@ var hasPath = (numCourses, graph, path) => { } return true; -} +}; var isCyclic = (currCourse, graph, path) => { - const hasSeen = path[currCourse] - if (hasSeen) return true + const hasSeen = path[currCourse]; + if (hasSeen) return true; - const isMissingNext = !(currCourse in graph) + const isMissingNext = !(currCourse in graph); if (isMissingNext) return false; return backTrack(currCourse, graph, path); -} +}; var backTrack = (currCourse, graph, path) => { path[currCourse] = true; - const _hasCycle = hasCycle(currCourse, graph, path) + const _hasCycle = hasCycle(currCourse, graph, path); path[currCourse] = false; - return _hasCycle -} + return _hasCycle; +}; var hasCycle = (currCourse, graph, path) => { for (const neighbor of graph[currCourse]) { if (isCyclic(neighbor, graph, path)) return true; } - return false -} + return false; +}; /** * https://leetcode.com/problems/course-schedule/ @@ -71,27 +71,27 @@ var hasCycle = (currCourse, graph, path) => { * @param {number[][]} prerequisites * @return {boolean} */ -var canFinish = function(numCourses, prerequisites) { - const { graph, visited, path } = buildGraph(numCourses, prerequisites); +var canFinish = function (numCourses, prerequisites) { + const { graph, visited, path } = buildGraph(numCourses, prerequisites); for (let currCourse = 0; currCourse < numCourses; currCourse++) { if (isCyclic(currCourse, graph, visited, path)) return false; } return true; -} +}; var initGraph = (numCourses) => ({ graph: new Array(numCourses).fill().map(() => []), visited: new Array(numCourses).fill(false), - path: new Array(numCourses).fill(false) -}) + path: new Array(numCourses).fill(false), +}); var buildGraph = (numCourses, prerequisites) => { const { graph, visited, path } = initGraph(numCourses); - for (const [ src, dst ] of prerequisites) { - const neighbors = (graph[dst] || []); + for (const [src, dst] of prerequisites) { + const neighbors = graph[dst] || []; neighbors.push(src); @@ -99,40 +99,40 @@ var buildGraph = (numCourses, prerequisites) => { } return { graph, visited, path }; -} +}; var isCyclic = (currCourse, graph, visited, path) => { - const isVisited = visited[currCourse] + const isVisited = visited[currCourse]; if (isVisited) return false; - const hasSeen = path[currCourse] + const hasSeen = path[currCourse]; if (hasSeen) return true; - const isMissingNext = !(currCourse in graph) + const isMissingNext = !(currCourse in graph); if (isMissingNext) return false; const _isCyclic = backTrack(currCourse, graph, visited, path); visited[currCourse] = true; - return _isCyclic -} + return _isCyclic; +}; var backTrack = (currCourse, graph, visited, path) => { path[currCourse] = true; - const _hasCycle = hasCycle(currCourse, graph, visited, path) + const _hasCycle = hasCycle(currCourse, graph, visited, path); path[currCourse] = false; - return _hasCycle -} + return _hasCycle; +}; var hasCycle = (currCourse, graph, visited, path) => { for (const neighbor of graph[currCourse]) { if (isCyclic(neighbor, graph, visited, path)) return true; } - return false -} + return false; +}; /** * https://leetcode.com/problems/course-schedule/ @@ -141,7 +141,7 @@ var hasCycle = (currCourse, graph, visited, path) => { * @param {number[][]} prerequisites * @return {boolean} */ -var canFinish = function(numCourses, prerequisites) { +var canFinish = function (numCourses, prerequisites) { const { graph, indegree } = buildGraph(numCourses, prerequisites); const topologicalOrder = topologicalSort(graph, indegree); const isDirectedAcyclicGraph = topologicalOrder.length === numCourses; @@ -151,19 +151,19 @@ var canFinish = function(numCourses, prerequisites) { var initGraph = (numCourses) => ({ graph: new Array(numCourses).fill().map(() => []), - indegree: new Array(numCourses).fill(0) -}) + indegree: new Array(numCourses).fill(0), +}); var buildGraph = (numCourses, prerequisites) => { const { graph, indegree } = initGraph(numCourses); - for (const [ src, dst ] of prerequisites){ + for (const [src, dst] of prerequisites) { graph[src].push(dst); indegree[dst]++; } return { graph, indegree }; -} +}; var topologicalSort = (graph, indegree, order = []) => { const queue = searchGraph(graph, indegree); @@ -171,7 +171,7 @@ var topologicalSort = (graph, indegree, order = []) => { bfs(graph, indegree, queue, order); return order; -} +}; var searchGraph = (graph, indegree, queue = new Queue([])) => { for (const node in graph) { @@ -180,15 +180,15 @@ var searchGraph = (graph, indegree, queue = new Queue([])) => { } return queue; -} +}; var bfs = (graph, indegree, queue, order) => { while (!queue.isEmpty()) { - for (let i = (queue.size() - 1); 0 <= i; i--) { + for (let i = queue.size() - 1; 0 <= i; i--) { checkNeighbors(graph, indegree, queue, order); } } -} +}; var checkNeighbors = (graph, indegree, queue, order) => { const node = queue.dequeue(); @@ -201,4 +201,4 @@ var checkNeighbors = (graph, indegree, queue, order) => { const isSource = indegree[neighbor] === 0; if (isSource) queue.enqueue(neighbor); } -} +}; diff --git a/javascript/0210-course-schedule-ii.js b/javascript/0210-course-schedule-ii.js index 33ccf0b1f..988d312c7 100644 --- a/javascript/0210-course-schedule-ii.js +++ b/javascript/0210-course-schedule-ii.js @@ -5,67 +5,105 @@ * @param {number[][]} prerequisites * @return {number[]} */ -var findOrder = function(numCourses, prerequisites) { - const { graph, color, isDirectedAcyclicGraph, topologicalOrder } = buildGraph(numCourses, prerequisites); +var findOrder = function (numCourses, prerequisites) { + const { graph, color, isDirectedAcyclicGraph, topologicalOrder } = + buildGraph(numCourses, prerequisites); - search(numCourses, graph, color, topologicalOrder, isDirectedAcyclicGraph) + search(numCourses, graph, color, topologicalOrder, isDirectedAcyclicGraph); - return isDirectedAcyclicGraph[0] - ? topologicalOrder.reverse() - : [] -} + return isDirectedAcyclicGraph[0] ? topologicalOrder.reverse() : []; +}; var initGraph = (numCourses) => ({ graph: new Array(numCourses).fill().map(() => []), color: new Array(numCourses).fill(1), // White - isDirectedAcyclicGraph: [ true ], - topologicalOrder: [] -}) + isDirectedAcyclicGraph: [true], + topologicalOrder: [], +}); var buildGraph = (numCourses, prerequisites) => { - const { graph, color, isDirectedAcyclicGraph, topologicalOrder } = initGraph(numCourses); + const { graph, color, isDirectedAcyclicGraph, topologicalOrder } = + initGraph(numCourses); - for (const [ src, dst ] of prerequisites) { - const neighbors = (graph[dst] || []); + for (const [src, dst] of prerequisites) { + const neighbors = graph[dst] || []; neighbors.push(src); graph[dst] = neighbors; } - return { graph, color, isDirectedAcyclicGraph, topologicalOrder } -} + return { graph, color, isDirectedAcyclicGraph, topologicalOrder }; +}; -var search = (numCourses, graph, color, topologicalOrder, isDirectedAcyclicGraph) => { +var search = ( + numCourses, + graph, + color, + topologicalOrder, + isDirectedAcyclicGraph, +) => { for (let i = 0; i < numCourses; i++) { - const isNew = color[i] === 1 // White - if (isNew) dfs(i, graph, color, topologicalOrder, isDirectedAcyclicGraph); + const isNew = color[i] === 1; // White + if (isNew) + dfs(i, graph, color, topologicalOrder, isDirectedAcyclicGraph); } -} +}; var dfs = (node, graph, color, topologicalOrder, isDirectedAcyclicGraph) => { - const hasCycle = !isDirectedAcyclicGraph[0] + const hasCycle = !isDirectedAcyclicGraph[0]; if (hasCycle) return; - colorBackTrack(node, graph, color, topologicalOrder, isDirectedAcyclicGraph) + colorBackTrack( + node, + graph, + color, + topologicalOrder, + isDirectedAcyclicGraph, + ); topologicalOrder.push(node); -} +}; -const colorBackTrack = (node, graph, color, topologicalOrder, isDirectedAcyclicGraph) => { +const colorBackTrack = ( + node, + graph, + color, + topologicalOrder, + isDirectedAcyclicGraph, +) => { color[node] = 2; // Grey - checkNeighbors(node, graph, color, topologicalOrder, isDirectedAcyclicGraph) + checkNeighbors( + node, + graph, + color, + topologicalOrder, + isDirectedAcyclicGraph, + ); color[node] = 3; // Black -} +}; -var checkNeighbors = (node, graph, color, topologicalOrder, isDirectedAcyclicGraph) => { +var checkNeighbors = ( + node, + graph, + color, + topologicalOrder, + isDirectedAcyclicGraph, +) => { for (const neighbor of graph[node]) { - const isNew = color[neighbor] === 1 // White - if (isNew) dfs(neighbor, graph, color, topologicalOrder, isDirectedAcyclicGraph); - - const isCycle = color[neighbor] === 2 // Grey + const isNew = color[neighbor] === 1; // White + if (isNew) + dfs( + neighbor, + graph, + color, + topologicalOrder, + isDirectedAcyclicGraph, + ); + + const isCycle = color[neighbor] === 2; // Grey if (isCycle) isDirectedAcyclicGraph[0] = false; } -} +}; /** * https://leetcode.com/problems/course-schedule-ii/ @@ -74,37 +112,36 @@ var checkNeighbors = (node, graph, color, topologicalOrder, isDirectedAcyclicGra * @param {number[][]} prerequisites * @return {number[]} */ -var findOrder = function(numCourses, prerequisites) { +var findOrder = function (numCourses, prerequisites) { const { graph, indegree } = buildGraph(numCourses, prerequisites); const reversedTopologicalOrder = topologicalSort(graph, indegree); - const isDirectedAcyclicGraph = reversedTopologicalOrder.length === numCourses; + const isDirectedAcyclicGraph = + reversedTopologicalOrder.length === numCourses; - return isDirectedAcyclicGraph - ? reversedTopologicalOrder - : []; + return isDirectedAcyclicGraph ? reversedTopologicalOrder : []; }; var initGraph = (numCourses) => ({ graph: new Array(numCourses).fill().map(() => []), - indegree: new Array(numCourses).fill(0) -}) + indegree: new Array(numCourses).fill(0), +}); var buildGraph = (numCourses, prerequisites) => { const { graph, indegree } = initGraph(numCourses); - for (const [ src, dst ] of prerequisites){ + for (const [src, dst] of prerequisites) { graph[src].push(dst); indegree[dst]++; } return { graph, indegree }; -} +}; var topologicalSort = (graph, indegree) => { const queue = searchGraph(graph, indegree); return bfs(graph, indegree, queue); -} +}; var isSource = (count) => count === 0; @@ -114,17 +151,17 @@ var searchGraph = (graph, indegree, queue = new Queue([])) => { } return queue; -} +}; var bfs = (graph, indegree, queue, reversedOrder = []) => { while (!queue.isEmpty()) { - for (let i = (queue.size() - 1); 0 <= i; i--) { + for (let i = queue.size() - 1; 0 <= i; i--) { checkNeighbors(graph, indegree, queue, reversedOrder); } } return reversedOrder.reverse(); -} +}; var checkNeighbors = (graph, indegree, queue, reversedOrder) => { const node = queue.dequeue(); @@ -136,4 +173,4 @@ var checkNeighbors = (graph, indegree, queue, reversedOrder) => { if (isSource(indegree[neighbor])) queue.enqueue(neighbor); } -} \ No newline at end of file +}; diff --git a/javascript/0213-house-robber-ii.js b/javascript/0213-house-robber-ii.js index c23a7c691..694cf3b01 100644 --- a/javascript/0213-house-robber-ii.js +++ b/javascript/0213-house-robber-ii.js @@ -6,22 +6,23 @@ * @return {number} */ var rob = (nums) => { - const isBaseCase1 = (nums.length === 0); + const isBaseCase1 = nums.length === 0; if (isBaseCase1) return 0; - const isBaseCase2 = (nums.length === 1); - if (isBaseCase2) return nums[0] + const isBaseCase2 = nums.length === 1; + if (isBaseCase2) return nums[0]; - const left = search(nums, 0, (nums.length - 2)); /* Time O(N) */ - const right = search(nums, 1, (nums.length - 1));/* Time O(N) */ + const left = search(nums, 0, nums.length - 2); /* Time O(N) */ + const right = search(nums, 1, nums.length - 1); /* Time O(N) */ return Math.max(left, right); }; const search = (nums, start, end) => { - let [ left, mid ] = [ 0, 0 ]; + let [left, mid] = [0, 0]; - for (let i = start; i <= end; i++) {/* Time O(N) */ + for (let i = start; i <= end; i++) { + /* Time O(N) */ const temp = mid; const right = nums[i]; const house = left + right; @@ -31,6 +32,4 @@ const search = (nums, start, end) => { } return mid; -} - - +}; diff --git a/javascript/0215-kth-largest-element-in-an-array.js b/javascript/0215-kth-largest-element-in-an-array.js index 8204d4aaa..22f45ee42 100644 --- a/javascript/0215-kth-largest-element-in-an-array.js +++ b/javascript/0215-kth-largest-element-in-an-array.js @@ -5,11 +5,12 @@ * @param {number} k * @return {number} */ - var findKthLargest = function(nums, k) { return nums - .sort((a, b) => a - b) - .reverse() - .slice(k - 1) - .shift() +var findKthLargest = function (nums, k) { + return nums + .sort((a, b) => a - b) + .reverse() + .slice(k - 1) + .shift(); }; /** @@ -19,8 +20,8 @@ * @param {number} k * @return {number} */ - var findKthLargest = function(nums, k) { - const minHeap = new MinPriorityQueue() +var findKthLargest = function (nums, k) { + const minHeap = new MinPriorityQueue(); for (const num of nums) { minHeap.enqueue(num); @@ -29,5 +30,5 @@ if (isAtCapacity) minHeap.dequeue(); } - return minHeap.front().element + return minHeap.front().element; }; diff --git a/javascript/0217-contains-duplicate.js b/javascript/0217-contains-duplicate.js index 7242fe2dd..ed946be59 100644 --- a/javascript/0217-contains-duplicate.js +++ b/javascript/0217-contains-duplicate.js @@ -6,15 +6,17 @@ * @return {boolean} */ var containsDuplicate = (nums) => { - for (let right = 0; right < nums.length; right++) {/* Time O(N) */ - for (let left = 0; left < right; left++) { /* Time O(N) */ + for (let right = 0; right < nums.length; right++) { + /* Time O(N) */ + for (let left = 0; left < right; left++) { + /* Time O(N) */ const isDuplicate = nums[left] === nums[right]; if (isDuplicate) return true; } } return false; -} +}; /** * Sort - HeapSort Space O(1) | QuickSort Space O(log(N)) @@ -24,21 +26,22 @@ var containsDuplicate = (nums) => { * @return {boolean} */ var containsDuplicate = (nums) => { - nums.sort((a, b) => a - b);/* Time O(N * log(N)) | Space O(1 || log(N)) */ + nums.sort((a, b) => a - b); /* Time O(N * log(N)) | Space O(1 || log(N)) */ return hasDuplicate(nums); -} +}; const hasDuplicate = (nums) => { - for (let curr = 0; curr < (nums.length - 1); curr++) {/* Time O(N) */ - const next = (curr + 1); + for (let curr = 0; curr < nums.length - 1; curr++) { + /* Time O(N) */ + const next = curr + 1; const isNextDuplicate = nums[curr] === nums[next]; if (isNextDuplicate) return true; } return false; -} +}; /** * Hash Set @@ -48,7 +51,7 @@ const hasDuplicate = (nums) => { * @return {boolean} */ var containsDuplicate = (nums) => { - const numsSet = new Set(nums);/* Time O(N) | Space O(N) */ + const numsSet = new Set(nums); /* Time O(N) | Space O(N) */ const isEqual = numsSet.size === nums.length; return !isEqual; @@ -62,11 +65,12 @@ var containsDuplicate = (nums) => { * @return {boolean} */ var containsDuplicate = (nums, numsSet = new Set()) => { - for (const num of nums) {/* Time O(N) */ + for (const num of nums) { + /* Time O(N) */ if (numsSet.has(num)) return true; - numsSet.add(num); /* Space O(N) */ + numsSet.add(num); /* Space O(N) */ } return false; -}; \ No newline at end of file +}; diff --git a/javascript/0219-contains-duplicate-ii.js b/javascript/0219-contains-duplicate-ii.js index a72e225f8..1cd15b3fb 100644 --- a/javascript/0219-contains-duplicate-ii.js +++ b/javascript/0219-contains-duplicate-ii.js @@ -8,18 +8,18 @@ * @param {number} k * @return {boolean} */ -var containsNearbyDuplicate = function(nums, k) { +var containsNearbyDuplicate = function (nums, k) { const window = new Set(); let L = 0; for (let R = 0; R < nums.length; R++) { if (!window.has(nums[R])) { window.add(nums[R]); } else { - return true + return true; } if (R - L + 1 > k) { - window.delete(nums[L]) + window.delete(nums[L]); L++; } } diff --git a/javascript/0225-implement-stack-using-queues.js b/javascript/0225-implement-stack-using-queues.js index b484845a2..20560b49e 100644 --- a/javascript/0225-implement-stack-using-queues.js +++ b/javascript/0225-implement-stack-using-queues.js @@ -1,27 +1,25 @@ -var MyStack = function() { +var MyStack = function () { this.q = []; }; -MyStack.prototype.push = function(x) { +MyStack.prototype.push = function (x) { this.q.push(x); }; -MyStack.prototype.pop = function() { +MyStack.prototype.pop = function () { let size = this.q.length; - for(let i = 0; i < size - 1; i++) - this.push(this.q.shift()); + for (let i = 0; i < size - 1; i++) this.push(this.q.shift()); return this.q.shift(); }; -MyStack.prototype.top = function() { +MyStack.prototype.top = function () { let size = this.q.length; - for(let i = 0; i < size - 1; i++) - this.push(this.q.shift()); + for (let i = 0; i < size - 1; i++) this.push(this.q.shift()); let res = this.q.shift(); this.push(res); return res; }; -MyStack.prototype.empty = function() { - return this.q.length == 0 +MyStack.prototype.empty = function () { + return this.q.length == 0; }; diff --git a/javascript/0226-invert-binary-tree.js b/javascript/0226-invert-binary-tree.js index 55438b15e..d8f79f843 100644 --- a/javascript/0226-invert-binary-tree.js +++ b/javascript/0226-invert-binary-tree.js @@ -9,7 +9,7 @@ var invertTree = (root) => { if (isBaseCase) return root; return dfs(root); -} +}; const dfs = (root) => { const left = invertTree(root.left); @@ -19,7 +19,7 @@ const dfs = (root) => { root.right = left; return root; -} +}; /** * https://leetcode.com/problems/invert-binary-tree/ @@ -27,18 +27,18 @@ const dfs = (root) => { * @param {TreeNode} root * @return {TreeNode} */ -var invertTree = (root,) => { +var invertTree = (root) => { const isBaseCase = root === null; if (isBaseCase) return root; - bfs([ root ]); + bfs([root]); return root; -} +}; const bfs = (queue) => { while (queue.length) { - for (let i = (queue.length - 1); 0 <= i; i--) { + for (let i = queue.length - 1; 0 <= i; i--) { const node = queue.shift(); const left = node.right; const right = node.left; @@ -50,5 +50,4 @@ const bfs = (queue) => { if (node.right) queue.push(node.right); } } -} - +}; diff --git a/javascript/0230-kth-smallest-element-in-a-bst.js b/javascript/0230-kth-smallest-element-in-a-bst.js index 3cb704080..a40149147 100644 --- a/javascript/0230-kth-smallest-element-in-a-bst.js +++ b/javascript/0230-kth-smallest-element-in-a-bst.js @@ -1,49 +1,49 @@ -/** - * https://leetcode.com/problems/kth-smallest-element-in-a-bst/ - * Time O(N + K) | Space O(H) - * @param {TreeNode} root - * @param {number} k - * @return {number} - */ - var kthSmallest = function(root, k, inOrder = []) { - if (!root) return inOrder - - return dfs(root, k, inOrder); -}; - -const dfs = (root, k, inOrder) => { - if (root.left) kthSmallest(root.left, k, inOrder); - - inOrder.push(root.val); - - if (root.right) kthSmallest(root.right, k, inOrder); - - return inOrder[(k - 1)]; -} - -/** - * https://leetcode.com/problems/kth-smallest-element-in-a-bst/ - * Time O(N + K) | Space O(H) - * @param {TreeNode} root - * @param {number} k - * @return {number} - */ - var kthSmallest = function(root, k, stack = []) { - while (k--) { - root = moveLeft(root, stack); - - const isSmallest = k === 0; - if (isSmallest) return root.val; - - root = root.right; - } -} - -const moveLeft = (root, stack) => { - while (root !== null) { - stack.push(root); - root = root.left; - } - - return stack.pop(); -} +/** + * https://leetcode.com/problems/kth-smallest-element-in-a-bst/ + * Time O(N + K) | Space O(H) + * @param {TreeNode} root + * @param {number} k + * @return {number} + */ +var kthSmallest = function (root, k, inOrder = []) { + if (!root) return inOrder; + + return dfs(root, k, inOrder); +}; + +const dfs = (root, k, inOrder) => { + if (root.left) kthSmallest(root.left, k, inOrder); + + inOrder.push(root.val); + + if (root.right) kthSmallest(root.right, k, inOrder); + + return inOrder[k - 1]; +}; + +/** + * https://leetcode.com/problems/kth-smallest-element-in-a-bst/ + * Time O(N + K) | Space O(H) + * @param {TreeNode} root + * @param {number} k + * @return {number} + */ +var kthSmallest = function (root, k, stack = []) { + while (k--) { + root = moveLeft(root, stack); + + const isSmallest = k === 0; + if (isSmallest) return root.val; + + root = root.right; + } +}; + +const moveLeft = (root, stack) => { + while (root !== null) { + stack.push(root); + root = root.left; + } + + return stack.pop(); +}; diff --git a/javascript/0232-implement-queue-using-stacks.js b/javascript/0232-implement-queue-using-stacks.js index c728e2daa..d34669fb9 100644 --- a/javascript/0232-implement-queue-using-stacks.js +++ b/javascript/0232-implement-queue-using-stacks.js @@ -1,25 +1,25 @@ // https://leetcode.com/problems/implement-queue-using-stacks/ -var MyQueue = function() { +var MyQueue = function () { this.stack1 = []; - this.stack2 = []; + this.stack2 = []; }; -/** +/** * @param {number} x * @return {void} */ -MyQueue.prototype.push = function(x) { +MyQueue.prototype.push = function (x) { this.stack1.push(x); }; /** * @return {number} */ -MyQueue.prototype.pop = function() { +MyQueue.prototype.pop = function () { this.swappingStacks(); - - if(!this.stack2.length){ + + if (!this.stack2.length) { return null; } return this.stack2.pop(); @@ -28,26 +28,26 @@ MyQueue.prototype.pop = function() { /** * @return {number} */ -MyQueue.prototype.peek = function() { +MyQueue.prototype.peek = function () { this.swappingStacks(); - return this.stack2.length == 0 ? null : this.stack2[this.stack2.length-1] + return this.stack2.length == 0 ? null : this.stack2[this.stack2.length - 1]; }; /** * @return {boolean} */ -MyQueue.prototype.empty = function() { +MyQueue.prototype.empty = function () { return this.stack1.length === 0 && this.stack2.length === 0; }; -MyQueue.prototype.swappingStacks = function() { +MyQueue.prototype.swappingStacks = function () { if (this.stack1.length) { this.stack2 = [...this.stack1.reverse(), ...this.stack2]; this.stack1 = []; } -} +}; -/** +/** * Your MyQueue object will be instantiated and called as such: * var obj = new MyQueue() * obj.push(x) diff --git a/javascript/0235-lowest-common-ancestor-of-a-binary-search-tree.js b/javascript/0235-lowest-common-ancestor-of-a-binary-search-tree.js index ee8396413..37a3a0606 100644 --- a/javascript/0235-lowest-common-ancestor-of-a-binary-search-tree.js +++ b/javascript/0235-lowest-common-ancestor-of-a-binary-search-tree.js @@ -6,11 +6,11 @@ * @param {TreeNode} q * @return {TreeNode} */ - var lowestCommonAncestor = function(root, p, q) { - const isGreater = (p.val < root.val) && (q.val < root.val); +var lowestCommonAncestor = function (root, p, q) { + const isGreater = p.val < root.val && q.val < root.val; if (isGreater) return lowestCommonAncestor(root.left, p, q); - const isLess = (root.val < p.val) && (root.val < q.val); + const isLess = root.val < p.val && root.val < q.val; if (isLess) return lowestCommonAncestor(root.right, p, q); return root; @@ -24,15 +24,15 @@ * @param {TreeNode} q * @return {TreeNode} */ - var lowestCommonAncestor = function(root, p, q) { +var lowestCommonAncestor = function (root, p, q) { while (root !== null) { - const isGreater = (root.val < p.val) && (root.val < q.val) + const isGreater = root.val < p.val && root.val < q.val; if (isGreater) { root = root.right; continue; } - const isLess = (p.val < root.val) && (q.val < root.val);; + const isLess = p.val < root.val && q.val < root.val; if (isLess) { root = root.left; continue; diff --git a/javascript/0238-product-of-array-except-self.js b/javascript/0238-product-of-array-except-self.js index a3ef93d0b..e2edb0a54 100644 --- a/javascript/0238-product-of-array-except-self.js +++ b/javascript/0238-product-of-array-except-self.js @@ -5,11 +5,11 @@ * @param {number[]} nums * @return {number[]} */ - function productExceptSelf(nums) { +function productExceptSelf(nums) { const result = []; let prefix = 1; let postfix = 1; - + for (let i = 0; i < nums.length; i++) { result[i] = prefix; prefix *= nums[i]; @@ -18,6 +18,6 @@ postfix *= nums[i + 1]; result[i] *= postfix; } - + return result; -}; \ No newline at end of file +} diff --git a/javascript/0242-valid-anagram.js b/javascript/0242-valid-anagram.js index 9fc874482..c58292a48 100644 --- a/javascript/0242-valid-anagram.js +++ b/javascript/0242-valid-anagram.js @@ -13,10 +13,13 @@ var isAnagram = (s, t) => { return reorder(s) === reorder(t); /* Time O(N * logN) | Space O(N) */ }; -const reorder = (str) => str - .split('') /* Time O(N) | Space O(N) */ - .sort((a, b) => a.localeCompare(b))/* Time O(N * log(N)) | Space O(1 || log(N)) */ - .join(''); /* Time O(N) | Space O(N) */ +const reorder = (str) => + str + .split('') /* Time O(N) | Space O(N) */ + .sort((a, b) => + a.localeCompare(b), + ) /* Time O(N * log(N)) | Space O(1 || log(N)) */ + .join(''); /* Time O(N) | Space O(N) */ /** * Hash Map - Frequency Counter @@ -30,35 +33,38 @@ var isAnagram = (s, t, map = new Map()) => { const isEqual = s.length === t.length; if (!isEqual) return false; - addFrequency(s, map); /* Time O(N) | Space O(1) */ + addFrequency(s, map); /* Time O(N) | Space O(1) */ subtractFrequency(t, map); /* Time O(N) | Space O(1) */ - return checkFrequency(map);/* Time O(N) */ + return checkFrequency(map); /* Time O(N) */ }; const addFrequency = (str, map) => { - for (const char of str) {/* Time O(N) */ + for (const char of str) { + /* Time O(N) */ const count = (map.get(char) || 0) + 1; - map.set(char, count); /* Space O(1) */ + map.set(char, count); /* Space O(1) */ } -} +}; const subtractFrequency = (str, map) => { - for (const char of str) {/* Time O(N) */ + for (const char of str) { + /* Time O(N) */ if (!map.has(char)) continue; const count = map.get(char) - 1; - map.set(char, count); /* Space O(1) */ + map.set(char, count); /* Space O(1) */ } }; const checkFrequency = (map) => { - for (const [ char, count ] of map) {/* Time O(N) */ + for (const [char, count] of map) { + /* Time O(N) */ const isEmpty = count === 0; if (!isEmpty) return false; } return true; -} +}; diff --git a/javascript/0252-meeting-rooms.js b/javascript/0252-meeting-rooms.js index bdd933a51..caa80a0dd 100644 --- a/javascript/0252-meeting-rooms.js +++ b/javascript/0252-meeting-rooms.js @@ -6,7 +6,7 @@ */ var canAttendMeetings = function (intervals) { intervals.sort(([aStart, aEnd], [bStart, bEnd]) => - aStart !== bStart ? aStart - bStart : aEnd - bEnd + aStart !== bStart ? aStart - bStart : aEnd - bEnd, ); return canAttend(intervals); diff --git a/javascript/0261-graph-valid-tree.js b/javascript/0261-graph-valid-tree.js index 0f88af14a..e376ef6ca 100644 --- a/javascript/0261-graph-valid-tree.js +++ b/javascript/0261-graph-valid-tree.js @@ -5,32 +5,32 @@ * @param {number[][]} edges * @return {boolean} */ -var validTree = function(n, edges, root = 0) { - const isEqual = edges.length === (n - 1) +var validTree = function (n, edges, root = 0) { + const isEqual = edges.length === n - 1; if (!isEqual) return false; - const { graph, visited } = buildGraph(n, edges) + const { graph, visited } = buildGraph(n, edges); dfs(root, graph, visited); return visited.size === n; -} +}; var initGraph = (n) => ({ graph: new Array(n).fill().map(() => []), - visited: new Set() -}) + visited: new Set(), +}); var buildGraph = (n, edges) => { - const { graph, visited } = initGraph(n) + const { graph, visited } = initGraph(n); - for (const [ src, dst ] of edges) { + for (const [src, dst] of edges) { graph[src].push(dst); graph[dst].push(src); } - return { graph, visited } -} + return { graph, visited }; +}; const dfs = (node, graph, visited) => { if (visited.has(node)) return; @@ -39,7 +39,7 @@ const dfs = (node, graph, visited) => { for (const neighbor of graph[node]) { dfs(neighbor, graph, visited); } -} +}; /** * https://leetcode.com/problems/graph-valid-tree/ @@ -48,28 +48,28 @@ const dfs = (node, graph, visited) => { * @param {number[][]} edges * @return {boolean} */ -var validTree = function(n, edges) { - const isEqual = edges.length === (n - 1) +var validTree = function (n, edges) { + const isEqual = edges.length === n - 1; if (!isEqual) return false; - const { graph, visited, queue } = buildGraph(n, edges) + const { graph, visited, queue } = buildGraph(n, edges); - bfs(graph, visited, queue) + bfs(graph, visited, queue); return visited.size === n; -} +}; var initGraph = (n) => ({ graph: new Array(n).fill().map(() => []), visited: new Set(), queue: new Queue(), - root: 0 -}) + root: 0, +}); var buildGraph = (n, edges) => { - const { graph, visited, queue, root } = initGraph(n) + const { graph, visited, queue, root } = initGraph(n); - for (const [ src, dst ] of edges) { + for (const [src, dst] of edges) { graph[src].push(dst); graph[dst].push(src); } @@ -77,16 +77,16 @@ var buildGraph = (n, edges) => { queue.enqueue(root); visited.add(root); - return { graph, visited, queue } -} + return { graph, visited, queue }; +}; const bfs = (graph, visited, queue) => { while (!queue.isEmpty()) { - for (let i = (queue.size() - 1); 0 <= i; i--) { - checkNeighbor(graph, visited, queue) + for (let i = queue.size() - 1; 0 <= i; i--) { + checkNeighbor(graph, visited, queue); } } -} +}; const checkNeighbor = (graph, visited, queue) => { const node = queue.dequeue(); @@ -97,7 +97,7 @@ const checkNeighbor = (graph, visited, queue) => { queue.enqueue(neighbor); } -} +}; /** * https://leetcode.com/problems/graph-valid-tree/ @@ -106,31 +106,31 @@ const checkNeighbor = (graph, visited, queue) => { * @param {number[][]} edges * @return {boolean} */ -var validTree = function(n, edges) { - const union = new Array(n).fill(-1) +var validTree = function (n, edges) { + const union = new Array(n).fill(-1); - for (const [ src, dst ] of edges) { - const [ x, y ] = [ find(union, src), find(union, dst) ] + for (const [src, dst] of edges) { + const [x, y] = [find(union, src), find(union, dst)]; - const hasCycle = x === y - if (hasCycle) return false + const hasCycle = x === y; + if (hasCycle) return false; - compress(union, x, y) + compress(union, x, y); } - const isValid = edges.length === (n - 1) - return isValid + const isValid = edges.length === n - 1; + return isValid; }; -const compress = (union, i, head) => union[i] = head +const compress = (union, i, head) => (union[i] = head); const find = (union, i, num = union[i]) => { - const isEmpty = num === -1 - if (isEmpty) return i + const isEmpty = num === -1; + if (isEmpty) return i; - const head = find(union, num) + const head = find(union, num); - compress(union, i, head) + compress(union, i, head); - return union[i] -} + return union[i]; +}; diff --git a/javascript/0263-ugly-number.js b/javascript/0263-ugly-number.js index 3f5997772..ef3b5c75d 100644 --- a/javascript/0263-ugly-number.js +++ b/javascript/0263-ugly-number.js @@ -1,9 +1,6 @@ -var isUgly = function(n) { - if(n <= 0) - return false; - - for(const p of [2, 3, 5]) - while(n % p == 0) - n = n / p; +var isUgly = function (n) { + if (n <= 0) return false; + + for (const p of [2, 3, 5]) while (n % p == 0) n = n / p; return n == 1; }; diff --git a/javascript/0268-missing-number.js b/javascript/0268-missing-number.js index 5d6e60928..5cb91cf8e 100644 --- a/javascript/0268-missing-number.js +++ b/javascript/0268-missing-number.js @@ -6,7 +6,7 @@ */ var missingNumber = function (nums, missingNumber = nums.length) { for (let i = 0; i < nums.length; i++) { - const xor = (i ^ nums[i]); + const xor = i ^ nums[i]; missingNumber ^= xor; } diff --git a/javascript/0269-alien-dictionary.js b/javascript/0269-alien-dictionary.js index 6638e7c78..8ba2efc61 100644 --- a/javascript/0269-alien-dictionary.js +++ b/javascript/0269-alien-dictionary.js @@ -4,7 +4,7 @@ * @param {string[]} words * @return {string} */ - var alienOrder = function(words) { +var alienOrder = function (words) { const { graph, frequencyMap, queue, buffer } = buildGraph(words); if (!canBuildGraph(words, graph, frequencyMap)) return ''; @@ -12,17 +12,15 @@ queueSources(queue, frequencyMap); bfs(queue, frequencyMap, graph, buffer); - return (frequencyMap.size <= buffer.length) - ? buffer.join('') - : ''; -} + return frequencyMap.size <= buffer.length ? buffer.join('') : ''; +}; var initGraph = () => ({ graph: new Map(), frequencyMap: new Map(), queue: new Queue(), buffer: [], -}) +}); var buildGraph = (words) => { const { graph, frequencyMap, queue, buffer } = initGraph(); @@ -38,19 +36,19 @@ var buildGraph = (words) => { }; var canBuildGraph = (words, graph, frequencyMap) => { - for (let index = 0; (index < words.length - 1); index++) { - const [ word1, word2 ] = [ words[index], words[(index + 1)] ]; - const minLength = Math.min(word1.length, word2.length) + for (let index = 0; index < words.length - 1; index++) { + const [word1, word2] = [words[index], words[index + 1]]; + const minLength = Math.min(word1.length, word2.length); - const isWord1Longer = (word2.length < word1.length); + const isWord1Longer = word2.length < word1.length; const isPrefix = isWord1Longer && word1.startsWith(word2); if (isPrefix) return false; - for (let j = 0; (j < minLength); j++) { - const [ char1, char2 ] = [ word1[j], word2[j] ]; + for (let j = 0; j < minLength; j++) { + const [char1, char2] = [word1[j], word2[j]]; - const isEqual = (char1 === char2); + const isEqual = char1 === char2; if (isEqual) continue; graph.get(char1).push(char2); @@ -65,8 +63,8 @@ var canBuildGraph = (words, graph, frequencyMap) => { const bfs = (queue, frequencyMap, graph, buffer) => { while (!queue.isEmpty()) { - for (let level = (queue.size() - 1); (0 <= level); level--) { - checkNeighbors(queue, frequencyMap, graph, buffer) + for (let level = queue.size() - 1; 0 <= level; level--) { + checkNeighbors(queue, frequencyMap, graph, buffer); } } }; @@ -77,25 +75,25 @@ var checkNeighbors = (queue, frequencyMap, graph, buffer) => { buffer.push(char); for (const next of graph.get(char)) { - const value = (frequencyMap.get(next) - 1); + const value = frequencyMap.get(next) - 1; frequencyMap.set(next, value); - const isEmpty = (frequencyMap.get(next) === 0); + const isEmpty = frequencyMap.get(next) === 0; if (!isEmpty) continue; queue.enqueue(next); } -} +}; const queueSources = (queue, frequencyMap) => { - for (const [ key, value ] of frequencyMap) { - const isEmpty = (frequencyMap.get(key) === 0); + for (const [key, value] of frequencyMap) { + const isEmpty = frequencyMap.get(key) === 0; if (!isEmpty) continue; queue.enqueue(key); } -} +}; /** * DFS @@ -103,23 +101,23 @@ const queueSources = (queue, frequencyMap) => { * @param {string[]} words * @return {string} */ - var alienOrder = function(words) { +var alienOrder = function (words) { const { graph, seen, buffer } = buildGraph(words); if (!canBuildGraph(words, graph)) return ''; - for (const [ char ] of graph) { + for (const [char] of graph) { if (!dfs(char, graph, seen, buffer)) return ''; } - return buffer.reverse().join('') -} + return buffer.reverse().join(''); +}; var initGraph = () => ({ graph: new Map(), seen: new Map(), buffer: [], -}) +}); var buildGraph = (words) => { const { graph, seen, buffer } = initGraph(); @@ -134,23 +132,23 @@ var buildGraph = (words) => { }; var canBuildGraph = (words, graph) => { - for (let index = 0; (index < words.length - 1); index++) { - const [ word1, word2 ] = [ words[index], words[(index + 1)] ]; - const minLength = Math.min(word1.length, word2.length) + for (let index = 0; index < words.length - 1; index++) { + const [word1, word2] = [words[index], words[index + 1]]; + const minLength = Math.min(word1.length, word2.length); - const isWord1Longer = (word2.length < word1.length); + const isWord1Longer = word2.length < word1.length; const isPrefix = isWord1Longer && word1.startsWith(word2); if (isPrefix) return false; - for (let j = 0; (j < minLength); j++) { - const [ char1, char2 ] = [ word1[j], word2[j] ]; + for (let j = 0; j < minLength; j++) { + const [char1, char2] = [word1[j], word2[j]]; - const isEqual = (char1 === char2); + const isEqual = char1 === char2; if (isEqual) continue; graph.get(char1).push(char2); - + break; } } @@ -166,14 +164,14 @@ const dfs = (char, graph, seen, buffer) => { buffer.push(char); return true; -} +}; const backTrack = (char, graph, seen, buffer) => { seen.set(char, false); - for (const neighbor of graph.get(char)) { - if (!dfs(neighbor, graph, seen, buffer)) return false; - } + for (const neighbor of graph.get(char)) { + if (!dfs(neighbor, graph, seen, buffer)) return false; + } seen.set(char, true); return true; -} \ No newline at end of file +}; diff --git a/javascript/0271-encode-and-decode-strings.js b/javascript/0271-encode-and-decode-strings.js index 2b16eea97..2b59bcd85 100644 --- a/javascript/0271-encode-and-decode-strings.js +++ b/javascript/0271-encode-and-decode-strings.js @@ -7,9 +7,11 @@ */ var encode = (strs) => { return strs - .map((str) => `${str.length}#${str}`)/* Time O(N) | Ignore Auxillary Space O(N) */ - .join(''); /* Time O(N) | Ignore Auxillary Space O(N) */ -} + .map( + (str) => `${str.length}#${str}`, + ) /* Time O(N) | Ignore Auxillary Space O(N) */ + .join(''); /* Time O(N) | Ignore Auxillary Space O(N) */ +}; /** * String - Delimiter @@ -19,27 +21,36 @@ var encode = (strs) => { * @return {string[]} */ var decode = (str, index = 0, decodedWords = []) => { - while (index < str.length) {/* Time O(N) */ - const { nextIndex, word } = delimitWord(str, index);/* Time O(K) | Ignore Auxillary Space Space (K) */ + while (index < str.length) { + /* Time O(N) */ + const { nextIndex, word } = delimitWord( + str, + index, + ); /* Time O(K) | Ignore Auxillary Space Space (K) */ - decodedWords.push(word); /* | Ignore Auxillary Space O(N * K ) */ + decodedWords.push( + word, + ); /* | Ignore Auxillary Space O(N * K ) */ index = nextIndex; } return decodedWords; -} +}; const delimitWord = (str, index) => { - const delimiter = str.indexOf('#', index); /* Time O(K) */ - const length = Number(str.slice(index, delimiter)); /* Time O(K) */ - const [ start, end ] = [ (delimiter + 1), ((delimiter + length) + 1) ]; - const word = str.slice(start, end); /* Time O(K) | Ignore Auxillary Space O(K) */ + const delimiter = str.indexOf('#', index); /* Time O(K) */ + const length = Number(str.slice(index, delimiter)); /* Time O(K) */ + const [start, end] = [delimiter + 1, delimiter + length + 1]; + const word = str.slice( + start, + end, + ); /* Time O(K) | Ignore Auxillary Space O(K) */ return { - nextIndex: end, - word + nextIndex: end, + word, }; -} +}; /** * Non-ASCII Delimiter - Ignore Auxiliary Space @@ -49,7 +60,9 @@ const delimitWord = (str, index) => { * @return {string} */ var encode = (strs, nonASCIICode = String.fromCharCode(257)) => { - return strs.join(nonASCIICode);/* Time O(N) | Ignore Auxillary Space O(N) */ + return strs.join( + nonASCIICode, + ); /* Time O(N) | Ignore Auxillary Space O(N) */ }; /** @@ -60,7 +73,9 @@ var encode = (strs, nonASCIICode = String.fromCharCode(257)) => { * @return {string} */ var decode = (strs, nonASCIICode = String.fromCharCode(257)) => { - return strs.split(nonASCIICode);/* Time O(N) | Ignore Auxillary Space O(N) */ + return strs.split( + nonASCIICode, + ); /* Time O(N) | Ignore Auxillary Space O(N) */ }; /** @@ -71,20 +86,18 @@ var decode = (strs, nonASCIICode = String.fromCharCode(257)) => { * @return {string} */ var encode = (strs, sb = []) => { - for (const str of strs) {/* Time O(N) */ - const code = getCode(str);/* Time O(1) */ + for (const str of strs) { + /* Time O(N) */ + const code = getCode(str); /* Time O(1) */ const encoding = `${code}${str}`; - sb.push(encoding); + sb.push(encoding); } return sb.join(''); /* Time O(N) | Ignore Auxillary Space O(N) */ -} +}; -const getCode = (str) => str - .length - .toString(2) - .padStart(8,'0'); +const getCode = (str) => str.length.toString(2).padStart(8, '0'); /** * Chunk Transfer Encoding @@ -94,16 +107,24 @@ const getCode = (str) => str * @return {string[]} */ var decode = (str, output = []) => { - for (let left = 0, right = (left + 8),length = 0; + for ( + let left = 0, right = left + 8, length = 0; left < str.length; - left = (right + length), right = (left + 8) - ) { /* Time O(N) */ - const countString = str.slice(left, right); /* | Ignore Auxillary Space O(K) */ + left = right + length, right = left + 8 + ) { + /* Time O(N) */ + const countString = str.slice( + left, + right, + ); /* | Ignore Auxillary Space O(K) */ length = parseInt(countString, 2); - const decoding = str.slice(right, (right + length)); /* Time O(K) | Ignore Auxillary Space O(N * K) */ - output.push(decoding); /* | Ignore Auxillary Space O(N * K) */ + const decoding = str.slice( + right, + right + length, + ); /* Time O(K) | Ignore Auxillary Space O(N * K) */ + output.push(decoding); /* | Ignore Auxillary Space O(N * K) */ } return output; -} +}; diff --git a/javascript/0273-integer-to-english-words.js b/javascript/0273-integer-to-english-words.js index f86df2ae0..4065977c2 100644 --- a/javascript/0273-integer-to-english-words.js +++ b/javascript/0273-integer-to-english-words.js @@ -6,45 +6,75 @@ */ var convertToWords = function (num) { - var belowTwenty = ["", "One", "Two", "Three", "Four", "Five", "Six", "Seven", "Eight", "Nine", "Ten", "Eleven", "Twelve", "Thirteen", "Fourteen", "Fifteen", "Sixteen", "Seventeen", "Eighteen", "Nineteen"]; - var belowHundred = ["", "Ten", "Twenty", "Thirty", "Forty", "Fifty", "Sixty", "Seventy", "Eighty", "Ninety"]; - var thousands = ["" , "Thousand", "Million", "Billion"] + var belowTwenty = [ + '', + 'One', + 'Two', + 'Three', + 'Four', + 'Five', + 'Six', + 'Seven', + 'Eight', + 'Nine', + 'Ten', + 'Eleven', + 'Twelve', + 'Thirteen', + 'Fourteen', + 'Fifteen', + 'Sixteen', + 'Seventeen', + 'Eighteen', + 'Nineteen', + ]; + var belowHundred = [ + '', + 'Ten', + 'Twenty', + 'Thirty', + 'Forty', + 'Fifty', + 'Sixty', + 'Seventy', + 'Eighty', + 'Ninety', + ]; + var thousands = ['', 'Thousand', 'Million', 'Billion']; var pointer = 0; - result = ""; + result = ''; while (num > 0) { - var words = ""; + var words = ''; reminder = num % 1000; num = Math.floor(num / 1000); if (reminder > 0) { if (reminder >= 100) { - words += belowTwenty[Math.floor(reminder / 100)] + " Hundred "; + words += belowTwenty[Math.floor(reminder / 100)] + ' Hundred '; reminder %= 100; } if (reminder >= 20) { - words += belowHundred[Math.floor(reminder / 10)] + " "; + words += belowHundred[Math.floor(reminder / 10)] + ' '; reminder %= 10; } if (reminder > 0) { - words += belowTwenty[Math.floor(reminder)] + " "; + words += belowTwenty[Math.floor(reminder)] + ' '; } - - result = words + thousands[pointer] + " " + result; + + result = words + thousands[pointer] + ' ' + result; } pointer += 1; } return result.trim(); -} +}; var numberToWords = function (num) { if (num == 0) { - return "Zero"; - } - else { + return 'Zero'; + } else { return convertToWords(num); } - -}; \ No newline at end of file +}; diff --git a/javascript/0283-move-zeroes.js b/javascript/0283-move-zeroes.js index dff8f4e2e..5b6fddf4f 100644 --- a/javascript/0283-move-zeroes.js +++ b/javascript/0283-move-zeroes.js @@ -5,14 +5,13 @@ * @param {number[]} nums * @return {void} Do not return anything, modify nums in-place instead. */ -var moveZeroes = function(nums) { - +var moveZeroes = function (nums) { const arr = new Array(nums.length).fill(0); let [left, right] = [0, 0]; while (right < nums.length) { - const isZero = (nums[right] === 0); + const isZero = nums[right] === 0; if (!isZero) { arr[left] = nums[right]; left++; @@ -32,10 +31,10 @@ var moveZeroes = function(nums) { * @return {void} Do not return anything, modify nums in-place instead. */ var moveZeroes = (nums) => { - let [ left, right ] = [ 0, 0 ]; + let [left, right] = [0, 0]; while (right < nums.length) { - const canSwap = (nums[right] !== 0) + const canSwap = nums[right] !== 0; if (canSwap) { [nums[left], nums[right]] = [nums[right], nums[left]]; left++; diff --git a/javascript/0286-walls-and-gates.js b/javascript/0286-walls-and-gates.js index cb5324d13..11d4e9fc0 100644 --- a/javascript/0286-walls-and-gates.js +++ b/javascript/0286-walls-and-gates.js @@ -4,8 +4,8 @@ * @param {number[][]} rooms * @return {void} Do not return anything, modify rooms in-place instead. */ -var wallsAndGates = function(rooms) { - const [ rows, cols ] = [ rooms.length, rooms[0].length ]; +var wallsAndGates = function (rooms) { + const [rows, cols] = [rooms.length, rooms[0].length]; for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { @@ -15,24 +15,34 @@ var wallsAndGates = function(rooms) { dfs(rooms, row, col); } } -} +}; const dfs = (rooms, row, col) => { - const [ rows, cols ] = [ rooms.length, rooms[0].length ]; + const [rows, cols] = [rooms.length, rooms[0].length]; - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) { - const isPreviousDistanceGreater = rooms[_row][_col] <= (rooms[row][col] + 1); + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { + const isPreviousDistanceGreater = + rooms[_row][_col] <= rooms[row][col] + 1; if (isPreviousDistanceGreater) continue; - rooms[_row][_col] = (rooms[row][col] + 1); + rooms[_row][_col] = rooms[row][col] + 1; dfs(rooms, _row, _col); } -} +}; -var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ],[ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ] - .map(([ _row, _col ]) => [ (row + _row), (col + _col) ]) - .filter(([ _row, _col ]) => (0 <= _row) && (0 <= _col) && (_row < rows) && (_col < cols)); +var getNeighbors = (row, rows, col, cols) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + .map(([_row, _col]) => [row + _row, col + _col]) + .filter( + ([_row, _col]) => + 0 <= _row && 0 <= _col && _row < rows && _col < cols, + ); /** * https://leetcode.com/problems/walls-and-gates/ @@ -40,48 +50,57 @@ var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ],[ 0, -1 ], [ 1, 0 ], [ - * @param {number[][]} rooms * @return {void} Do not return anything, modify rooms in-place instead. */ -var wallsAndGates = function(rooms) { +var wallsAndGates = function (rooms) { const queue = searchGrid(rooms); bfs(rooms, queue); }; const searchGrid = (rooms, queue = new Queue([])) => { - const [ rows, cols ] = [ rooms.length, rooms[0].length ]; + const [rows, cols] = [rooms.length, rooms[0].length]; for (let row = 0; row < rows; row++) { for (let col = 0; col < cols; col++) { const isGate = rooms[row][col] === 0; if (!isGate) continue; - queue.enqueue([ row, col ]); + queue.enqueue([row, col]); } } return queue; -} +}; const bfs = (rooms, queue) => { while (!queue.isEmpty()) { - for (let i = (queue.size() - 1); 0 <= i; i--) { + for (let i = queue.size() - 1; 0 <= i; i--) { checkNeighbors(rooms, queue); } } -} +}; const checkNeighbors = (rooms, queue) => { - const [ rows, cols ] = [ rooms.length, rooms[0].length ]; - const [ row, col ] = queue.dequeue(); + const [rows, cols] = [rooms.length, rooms[0].length]; + const [row, col] = queue.dequeue(); - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) { + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { const isINF = rooms[_row][_col] === 2147483647; /* (2 ** 31) - 1 */ if (!isINF) continue; - rooms[_row][_col] = (rooms[row][col] + 1); - queue.enqueue([ _row, _col ]); + rooms[_row][_col] = rooms[row][col] + 1; + queue.enqueue([_row, _col]); } -} +}; -var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ],[ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ] - .map(([ _row, _col ]) => [ (row + _row), (col + _col) ]) - .filter(([ _row, _col ]) => (0 <= _row) && (0 <= _col) && (_row < rows) && (_col < cols)); +var getNeighbors = (row, rows, col, cols) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + .map(([_row, _col]) => [row + _row, col + _col]) + .filter( + ([_row, _col]) => + 0 <= _row && 0 <= _col && _row < rows && _col < cols, + ); diff --git a/javascript/0287-find-the-duplicate-number.js b/javascript/0287-find-the-duplicate-number.js index e3578386b..5cd8812cb 100644 --- a/javascript/0287-find-the-duplicate-number.js +++ b/javascript/0287-find-the-duplicate-number.js @@ -1,257 +1,277 @@ -/** - * https://leetcode.com/problems/find-the-duplicate-number/ - * Time O(N * log(N)) | Space O(1) - * @param {number[]} nums - * @return {number} - */ -var findDuplicate = function(nums) { - nums.sort((a, b) => a - b);/* Time O(N * log(N)) | HeapSort Space O(1) | QuickSort Space O(log(N)) */ - - for (let i = 1; i < nums.length; i++) {/* Time O(N) */ - const isPrevDuplicate = nums[i - 1] === nums[i] - if (isPrevDuplicate) return nums[i]; - } - - return -1; -} - -/** - * https://leetcode.com/problems/find-the-duplicate-number/ - * Time O(N * log(N)) | Space O(1) - * @param {number[]} nums - * @return {number} - */ -var findDuplicate = function(nums) { - let [ left, right, duplicate ] = [ 1, (nums.length - 1), -1 ]; - - while (left <= right) {/* Time O(log(N)) */ - const mid = (left + right) >> 1; - const count = getCount(mid, nums);/* Time O(N) */ - - const isMidGreater = count <= mid - if (isMidGreater) left = mid + 1; - - const isMidLess = mid < count - if (isMidLess) { - duplicate = mid; - right = mid - 1; - } - } - - return duplicate; -} - -const getCount = (mid, nums, count = 0) => { - for (const num of nums) {/* Time O(N) */ - const isMidGreater = num <= mid - if (isMidGreater) count++; - } - - return count; -} - -/** - * https://leetcode.com/problems/find-the-duplicate-number/ - * Time O(N * log(N)) | Space O(1) - * @param {number[]} nums - * @return {number} - */ -var findDuplicate = function(nums, duplicate = 0) { - const mostSignificantBit = calcMaxBit(nums); /* Time O(N) */ - - for (let bit = 0; bit < mostSignificantBit; bit++) {/* Time O(log(N)) */ - const [ baseCount, numsCount, mask ] = count(nums, bit);/* Time O(N) */ - - const isMoreFrequentlySet = baseCount < numsCount - if (isMoreFrequentlySet) duplicate |= mask; - } - - return duplicate; -} - -const calcMaxBit = (nums, bits = 0) => { - let max = Math.max(0, ...nums);/* Time O(N) */ - - while (max) {/* Time O(log(MAX)) */ - max >>= 1; - bits++; - } - - return bits; -} - -const count = (nums, bit) => { - let [ baseCount, numsCount, mask ] = [ 0, 0, (1 << bit) ]; - - for (let i = 0; i < nums.length; i++) {/* Time O(N) */ - const isBaseBitSet = 0 < (i & mask); - if (isBaseBitSet) baseCount++; - - const isNumBitSet = 0 < (nums[i] & mask); - if (isNumBitSet) numsCount++; - } - - return [ baseCount, numsCount, mask ]; -} - -/** - * https://leetcode.com/problems/find-the-duplicate-number/ - * Time O(N) | Space O(N) - * @param {number[]} nums - * @return {number} - */ -var findDuplicate = function(nums, curr = 0) { - const isBaseCase = curr === nums[curr] - if (isBaseCase) return curr; - - const next = nums[curr]; - - nums[curr] = curr; - - return findDuplicate(nums, next);/* Time O(N) | Space O(N) */ -} - -/** - * https://leetcode.com/problems/find-the-duplicate-number/ - * Time O(N) | Space O(N) - * @param {number[]} nums - * @return {number} - */ - var findDuplicate = function(nums, seen = new Set()) { - for (const num of nums) {/* Time O(N) */ - if (seen.has(num)) return num; - - seen.add(num); /* Space O(N) */ - } - - return -1; -} - -/** - * https://leetcode.com/problems/find-the-duplicate-number/ - * Time O(N) | Space O(1) - * @param {number[]} nums - * @return {number} - */ -var findDuplicate = function(nums) { - cyclicSort(nums); /* Time O(N) */ - - return search(nums); /* Time O(N) */ -} - -const cyclicSort = (nums, index = 0) => { - const swap = (arr, a, b) => [arr[a], arr[b]] = [arr[b], arr[a]]; - - while (index < nums.length) { /* Time O(N) */ - const [ num, arrayIndex, arrayNum ] = [ nums[index], (nums[index] - 1), nums[(nums[index] - 1)] ]; - - const canSwap = !isSame(num, arrayNum); - if (canSwap) { - swap(nums, index, arrayIndex); - - continue; - } - - index++; - } -} -const isSame = (a, b) => a === b; - -const search = (nums) => { - for (let index = 0; index < nums.length; index++) {/* Time O(N) */ - const [ num, arrayIndex ] = [ nums[index], (index + 1) ]; - - if (!isSame(num, arrayIndex)) return num; - } - - return nums.length; -} - -/** - * https://leetcode.com/problems/find-the-duplicate-number/ - * Time O(N) | Space O(1) - * @param {number[]} nums - * @return {number} - */ -var findDuplicate = function(nums) { - const duplicate = negativeMarking(nums);/* Time O(N) */ - - restoreToPositiveNumbers(nums); /* Time O(N) */ - - return duplicate; -} - -const negativeMarking = (nums) => { - for (let i = 0; i < nums.length; i++) {/* Time O(N) */ - const curr = Math.abs(nums[i]); - - const isNegative = nums[curr] < 0; - if (isNegative) return curr; - - nums[curr] *= -1; - } - - return -1 -} - -const restoreToPositiveNumbers = (nums) => { - for (let i = 0; i < nums.length; i++) {/* Time O(N) */ - nums[i] = Math.abs(nums[i]); - } -} - -/** - * https://leetcode.com/problems/find-the-duplicate-number/ - * Time O(N) | Space O(1) - * @param {number[]} nums - * @return {number} - */ - var findDuplicate = function(nums, start = 0) { - const swap = (arr, a, b) => [arr[a], arr[b]] = [arr[b], arr[a]]; - - const isSame = () => nums[start] === nums[nums[start]]; - while (!isSame()) {/* Time O(N) */ - swap(nums, start, nums[start]); - } - - return nums[start]; -} - -/** - * https://leetcode.com/problems/find-the-duplicate-number/ - * Time O(N) | Space O(1) - * @param {number[]} nums - * @return {number} - */ - var findDuplicate = function(nums) { - if (!nums.length) return -1 - - let [ slow, fast ] = moveFast(nums); /* Time O(N) */ - [ slow, fast ] = moveSlow(nums, slow, fast);/* Time O(N) */ - - return slow; -}; - -const moveFast = (nums, start = 0) => { - let [ slow, fast ] = [ nums[start], nums[nums[start]] ]; - - const isSame = () => slow === fast; - while (!isSame()) { /* Time O(N) */ - slow = nums[slow]; - fast = nums[nums[fast]]; - } - - fast = start; - - return [ slow, fast ]; -} - -const moveSlow = (nums, slow, fast) => { - const isSame = () => slow === fast; - while (!isSame()) { /* Time O(N) */ - slow = nums[slow]; - fast = nums[fast]; - } - - return [ slow, fast ]; -} \ No newline at end of file +/** + * https://leetcode.com/problems/find-the-duplicate-number/ + * Time O(N * log(N)) | Space O(1) + * @param {number[]} nums + * @return {number} + */ +var findDuplicate = function (nums) { + nums.sort( + (a, b) => a - b, + ); /* Time O(N * log(N)) | HeapSort Space O(1) | QuickSort Space O(log(N)) */ + + for (let i = 1; i < nums.length; i++) { + /* Time O(N) */ + const isPrevDuplicate = nums[i - 1] === nums[i]; + if (isPrevDuplicate) return nums[i]; + } + + return -1; +}; + +/** + * https://leetcode.com/problems/find-the-duplicate-number/ + * Time O(N * log(N)) | Space O(1) + * @param {number[]} nums + * @return {number} + */ +var findDuplicate = function (nums) { + let [left, right, duplicate] = [1, nums.length - 1, -1]; + + while (left <= right) { + /* Time O(log(N)) */ + const mid = (left + right) >> 1; + const count = getCount(mid, nums); /* Time O(N) */ + + const isMidGreater = count <= mid; + if (isMidGreater) left = mid + 1; + + const isMidLess = mid < count; + if (isMidLess) { + duplicate = mid; + right = mid - 1; + } + } + + return duplicate; +}; + +const getCount = (mid, nums, count = 0) => { + for (const num of nums) { + /* Time O(N) */ + const isMidGreater = num <= mid; + if (isMidGreater) count++; + } + + return count; +}; + +/** + * https://leetcode.com/problems/find-the-duplicate-number/ + * Time O(N * log(N)) | Space O(1) + * @param {number[]} nums + * @return {number} + */ +var findDuplicate = function (nums, duplicate = 0) { + const mostSignificantBit = calcMaxBit(nums); /* Time O(N) */ + + for (let bit = 0; bit < mostSignificantBit; bit++) { + /* Time O(log(N)) */ + const [baseCount, numsCount, mask] = count(nums, bit); /* Time O(N) */ + + const isMoreFrequentlySet = baseCount < numsCount; + if (isMoreFrequentlySet) duplicate |= mask; + } + + return duplicate; +}; + +const calcMaxBit = (nums, bits = 0) => { + let max = Math.max(0, ...nums); /* Time O(N) */ + + while (max) { + /* Time O(log(MAX)) */ + max >>= 1; + bits++; + } + + return bits; +}; + +const count = (nums, bit) => { + let [baseCount, numsCount, mask] = [0, 0, 1 << bit]; + + for (let i = 0; i < nums.length; i++) { + /* Time O(N) */ + const isBaseBitSet = 0 < (i & mask); + if (isBaseBitSet) baseCount++; + + const isNumBitSet = 0 < (nums[i] & mask); + if (isNumBitSet) numsCount++; + } + + return [baseCount, numsCount, mask]; +}; + +/** + * https://leetcode.com/problems/find-the-duplicate-number/ + * Time O(N) | Space O(N) + * @param {number[]} nums + * @return {number} + */ +var findDuplicate = function (nums, curr = 0) { + const isBaseCase = curr === nums[curr]; + if (isBaseCase) return curr; + + const next = nums[curr]; + + nums[curr] = curr; + + return findDuplicate(nums, next); /* Time O(N) | Space O(N) */ +}; + +/** + * https://leetcode.com/problems/find-the-duplicate-number/ + * Time O(N) | Space O(N) + * @param {number[]} nums + * @return {number} + */ +var findDuplicate = function (nums, seen = new Set()) { + for (const num of nums) { + /* Time O(N) */ + if (seen.has(num)) return num; + + seen.add(num); /* Space O(N) */ + } + + return -1; +}; + +/** + * https://leetcode.com/problems/find-the-duplicate-number/ + * Time O(N) | Space O(1) + * @param {number[]} nums + * @return {number} + */ +var findDuplicate = function (nums) { + cyclicSort(nums); /* Time O(N) */ + + return search(nums); /* Time O(N) */ +}; + +const cyclicSort = (nums, index = 0) => { + const swap = (arr, a, b) => ([arr[a], arr[b]] = [arr[b], arr[a]]); + + while (index < nums.length) { + /* Time O(N) */ + const [num, arrayIndex, arrayNum] = [ + nums[index], + nums[index] - 1, + nums[nums[index] - 1], + ]; + + const canSwap = !isSame(num, arrayNum); + if (canSwap) { + swap(nums, index, arrayIndex); + + continue; + } + + index++; + } +}; +const isSame = (a, b) => a === b; + +const search = (nums) => { + for (let index = 0; index < nums.length; index++) { + /* Time O(N) */ + const [num, arrayIndex] = [nums[index], index + 1]; + + if (!isSame(num, arrayIndex)) return num; + } + + return nums.length; +}; + +/** + * https://leetcode.com/problems/find-the-duplicate-number/ + * Time O(N) | Space O(1) + * @param {number[]} nums + * @return {number} + */ +var findDuplicate = function (nums) { + const duplicate = negativeMarking(nums); /* Time O(N) */ + + restoreToPositiveNumbers(nums); /* Time O(N) */ + + return duplicate; +}; + +const negativeMarking = (nums) => { + for (let i = 0; i < nums.length; i++) { + /* Time O(N) */ + const curr = Math.abs(nums[i]); + + const isNegative = nums[curr] < 0; + if (isNegative) return curr; + + nums[curr] *= -1; + } + + return -1; +}; + +const restoreToPositiveNumbers = (nums) => { + for (let i = 0; i < nums.length; i++) { + /* Time O(N) */ + nums[i] = Math.abs(nums[i]); + } +}; + +/** + * https://leetcode.com/problems/find-the-duplicate-number/ + * Time O(N) | Space O(1) + * @param {number[]} nums + * @return {number} + */ +var findDuplicate = function (nums, start = 0) { + const swap = (arr, a, b) => ([arr[a], arr[b]] = [arr[b], arr[a]]); + + const isSame = () => nums[start] === nums[nums[start]]; + while (!isSame()) { + /* Time O(N) */ + swap(nums, start, nums[start]); + } + + return nums[start]; +}; + +/** + * https://leetcode.com/problems/find-the-duplicate-number/ + * Time O(N) | Space O(1) + * @param {number[]} nums + * @return {number} + */ +var findDuplicate = function (nums) { + if (!nums.length) return -1; + + let [slow, fast] = moveFast(nums); /* Time O(N) */ + [slow, fast] = moveSlow(nums, slow, fast); /* Time O(N) */ + + return slow; +}; + +const moveFast = (nums, start = 0) => { + let [slow, fast] = [nums[start], nums[nums[start]]]; + + const isSame = () => slow === fast; + while (!isSame()) { + /* Time O(N) */ + slow = nums[slow]; + fast = nums[nums[fast]]; + } + + fast = start; + + return [slow, fast]; +}; + +const moveSlow = (nums, slow, fast) => { + const isSame = () => slow === fast; + while (!isSame()) { + /* Time O(N) */ + slow = nums[slow]; + fast = nums[fast]; + } + + return [slow, fast]; +}; diff --git a/javascript/0290-word-pattern.js b/javascript/0290-word-pattern.js index 94787dd98..ae399d1be 100644 --- a/javascript/0290-word-pattern.js +++ b/javascript/0290-word-pattern.js @@ -2,26 +2,27 @@ // time coplexity O(n) // space complexity O(n) -var wordPattern = function(pattern, s) { - -s = s.split(' '); +var wordPattern = function (pattern, s) { + s = s.split(' '); -if(s.length !== pattern.length) return false; + if (s.length !== pattern.length) return false; -wordToChar = new Map(); -charToWord = new Map(); - -for(let i = 0; i < pattern.length; i++) { - wordToChar.set(s[i], pattern[i]); - charToWord.set(pattern[i], s[i]); -}; + wordToChar = new Map(); + charToWord = new Map(); + for (let i = 0; i < pattern.length; i++) { + wordToChar.set(s[i], pattern[i]); + charToWord.set(pattern[i], s[i]); + } -for(let i = 0; i < pattern.length; i++) { - if(charToWord.get(pattern[i]) !== s[i] || pattern[i] !== wordToChar.get(s[i])) { - return false; + for (let i = 0; i < pattern.length; i++) { + if ( + charToWord.get(pattern[i]) !== s[i] || + pattern[i] !== wordToChar.get(s[i]) + ) { + return false; + } } -} -return true; + return true; }; diff --git a/javascript/0295-find-median-from-data-stream.js b/javascript/0295-find-median-from-data-stream.js index 492039ff9..d0d6993d8 100644 --- a/javascript/0295-find-median-from-data-stream.js +++ b/javascript/0295-find-median-from-data-stream.js @@ -1,4 +1,4 @@ -/** +/** * https://leetcode.com/problems/find-median-from-data-stream/ * Your MedianFinder object will be instantiated and called as such: * var obj = new MedianFinder() @@ -6,51 +6,47 @@ * var param_2 = obj.findMedian() */ class MedianFinder { - constructor () { - this.maxHeap = new MaxPriorityQueue() - this.minHeap = new MinPriorityQueue() + constructor() { + this.maxHeap = new MaxPriorityQueue(); + this.minHeap = new MinPriorityQueue(); } /* Time O(log(N)) | Space (N) */ - insertNum (num) { - this.addNum(num) + insertNum(num) { + this.addNum(num); } - addNum (num, heap = this.getHeap(num)) { - heap.enqueue(num) - this.rebalance() + addNum(num, heap = this.getHeap(num)) { + heap.enqueue(num); + this.rebalance(); } - getHeap (num, { maxHeap, minHeap } = this) { - const isFirst = maxHeap.isEmpty() + getHeap(num, { maxHeap, minHeap } = this) { + const isFirst = maxHeap.isEmpty(); const isGreater = num <= this.top(maxHeap); - const isMaxHeap = (isFirst || isGreater); - return (isMaxHeap) - ? maxHeap - : minHeap + const isMaxHeap = isFirst || isGreater; + return isMaxHeap ? maxHeap : minHeap; } - rebalance ({ maxHeap, minHeap } = this) { - const canShiftMax = (minHeap.size() + 1) < maxHeap.size() - if (canShiftMax) return minHeap.enqueue(maxHeap.dequeue().element) + rebalance({ maxHeap, minHeap } = this) { + const canShiftMax = minHeap.size() + 1 < maxHeap.size(); + if (canShiftMax) return minHeap.enqueue(maxHeap.dequeue().element); - const canShiftMin = maxHeap.size() < minHeap.size() - if (canShiftMin) return maxHeap.enqueue(minHeap.dequeue().element) + const canShiftMin = maxHeap.size() < minHeap.size(); + if (canShiftMin) return maxHeap.enqueue(minHeap.dequeue().element); } /* Time O(1) | Space (1) */ - findMedian ({ maxHeap, minHeap } = this) { - const isEven = maxHeap.size() === minHeap.size() - return (isEven) - ? this.average(maxHeap, minHeap) - : this.top(maxHeap) + findMedian({ maxHeap, minHeap } = this) { + const isEven = maxHeap.size() === minHeap.size(); + return isEven ? this.average(maxHeap, minHeap) : this.top(maxHeap); } - average (maxHeap, minHeap) { - return (this.top(maxHeap) + this.top(minHeap)) / 2 + average(maxHeap, minHeap) { + return (this.top(maxHeap) + this.top(minHeap)) / 2; } - top (heap) { - return heap.front()?.element || 0 + top(heap) { + return heap.front()?.element || 0; } } diff --git a/javascript/0297-serialize-and-deserialize-binary-tree.js b/javascript/0297-serialize-and-deserialize-binary-tree.js index 96c3341de..22b7e792c 100644 --- a/javascript/0297-serialize-and-deserialize-binary-tree.js +++ b/javascript/0297-serialize-and-deserialize-binary-tree.js @@ -1,85 +1,85 @@ -/** - * Encodes a tree to a single string. - * https://leetcode.com/problems/serialize-and-deserialize-binary-tree/solution/ - * Time O(N) | Space O(H) - * @param {TreeNode} root - * @return {string} - */ - var serialize = function(root, result = []) { - serial(root, result); - - return result; -}; - -const serial = (root, result) => { - const isBase = root === null; - if (isBase) return result.push(null); - - dfsSerialize(root, result); -} - -const dfsSerialize = (node, result) => { - result.push(node.val); - serial(node.left, result); - serial(node.right, result); -}; - -/** - * Encodes a tree to a single string. - * https://leetcode.com/problems/serialize-and-deserialize-binary-tree/solution/ - * Time O(N) | Space O(H) - * @param {TreeNode} root - * @return {string} - */ -var serialize = function(root) { - const isBaseCase = root === null; - if (isBaseCase) return [ null ]; - - return dfsSerializeIterative([ root ]); -}; - -const dfsSerializeIterative = (stack, result = []) => { - while (stack.length) { - const curr = stack.pop(); - - const isNull = curr === null; - if (isNull) { - result.push(null); - continue; - } - - result.push(curr.val); - stack.push(curr.right); - stack.push(curr.left); - } - - return result; -} - -/** -* Decodes your encoded data to tree. -* https://leetcode.com/problems/serialize-and-deserialize-binary-tree/solution/ -* Time O(N) | Space O(H) -* @param {string} data -* @return {TreeNode} -*/ -var deserialize = function(data) { - const isBaseCase = !data.length; - if (isBaseCase) return null; - - const val = data.shift(); - - const isNull = val === null; - if (isNull) return null; - - return dfsDeserialize(val, data) -}; - -const dfsDeserialize = (val, data) => { - const node = new TreeNode(val); - - node.left = deserialize(data); - node.right = deserialize(data); - - return node; -} +/** + * Encodes a tree to a single string. + * https://leetcode.com/problems/serialize-and-deserialize-binary-tree/solution/ + * Time O(N) | Space O(H) + * @param {TreeNode} root + * @return {string} + */ +var serialize = function (root, result = []) { + serial(root, result); + + return result; +}; + +const serial = (root, result) => { + const isBase = root === null; + if (isBase) return result.push(null); + + dfsSerialize(root, result); +}; + +const dfsSerialize = (node, result) => { + result.push(node.val); + serial(node.left, result); + serial(node.right, result); +}; + +/** + * Encodes a tree to a single string. + * https://leetcode.com/problems/serialize-and-deserialize-binary-tree/solution/ + * Time O(N) | Space O(H) + * @param {TreeNode} root + * @return {string} + */ +var serialize = function (root) { + const isBaseCase = root === null; + if (isBaseCase) return [null]; + + return dfsSerializeIterative([root]); +}; + +const dfsSerializeIterative = (stack, result = []) => { + while (stack.length) { + const curr = stack.pop(); + + const isNull = curr === null; + if (isNull) { + result.push(null); + continue; + } + + result.push(curr.val); + stack.push(curr.right); + stack.push(curr.left); + } + + return result; +}; + +/** + * Decodes your encoded data to tree. + * https://leetcode.com/problems/serialize-and-deserialize-binary-tree/solution/ + * Time O(N) | Space O(H) + * @param {string} data + * @return {TreeNode} + */ +var deserialize = function (data) { + const isBaseCase = !data.length; + if (isBaseCase) return null; + + const val = data.shift(); + + const isNull = val === null; + if (isNull) return null; + + return dfsDeserialize(val, data); +}; + +const dfsDeserialize = (val, data) => { + const node = new TreeNode(val); + + node.left = deserialize(data); + node.right = deserialize(data); + + return node; +}; diff --git a/javascript/0300-longest-increasing-subsequence.js b/javascript/0300-longest-increasing-subsequence.js index ad4720dd5..9884edb72 100644 --- a/javascript/0300-longest-increasing-subsequence.js +++ b/javascript/0300-longest-increasing-subsequence.js @@ -7,26 +7,28 @@ * @return {number} */ var lengthOfLIS = (nums) => { - const tabu = initTabu(nums);/* | Space O(N) */ + const tabu = initTabu(nums); /* | Space O(N) */ - linearSearch(nums, tabu); /* Time O(N * N) | Space O(N)*/ + linearSearch(nums, tabu); /* Time O(N * N) | Space O(N)*/ - return Math.max(...tabu); /* Time O(N) */ + return Math.max(...tabu); /* Time O(N) */ }; const initTabu = (nums) => new Array(nums.length).fill(1); var linearSearch = (nums, tabu) => { - for (let right = 1; (right < nums.length); right++) {/* Time O(N) */ - for (let left = 0; (left < right); left++) { /* Time O(N) */ + for (let right = 1; right < nums.length; right++) { + /* Time O(N) */ + for (let left = 0; left < right; left++) { + /* Time O(N) */ const canUpdate = nums[left] < nums[right]; if (!canUpdate) continue; - const [ _left, _right ] = [ (tabu[left] + 1), tabu[right] ]; - tabu[right] = Math.max(_right, _left); /* Space O(N) */ + const [_left, _right] = [tabu[left] + 1, tabu[right]]; + tabu[right] = Math.max(_right, _left); /* Space O(N) */ } } -} +}; /** * Array - Subsequence @@ -36,33 +38,36 @@ var linearSearch = (nums, tabu) => { * @return {number} */ var lengthOfLIS = (nums) => { - const subsequence = linearSort(nums);/* Time O(N * N) | Space O(N) */ + const subsequence = linearSort(nums); /* Time O(N * N) | Space O(N) */ return subsequence.length; -} +}; var linearSort = (nums, subsequence = []) => { - for (const num of nums) {/* Time O(N) */ + for (const num of nums) { + /* Time O(N) */ const max = subsequence[subsequence.length - 1]; const canAdd = max < num; - if (canAdd) { subsequence.push(num); continue; }/* Space O(N) */ + if (canAdd) { + subsequence.push(num); + continue; + } /* Space O(N) */ - const index = getMax(subsequence, num); /* Time O(N) */ + const index = getMax(subsequence, num); /* Time O(N) */ subsequence[index] = num; } return subsequence; -} - +}; const getMax = (subsequence, num, index = 0) => { const isLess = () => subsequence[index] < num; - while (isLess()) index++;/* Time O(N) */ + while (isLess()) index++; /* Time O(N) */ return index; -} +}; /** * Array - Subsequence @@ -72,42 +77,47 @@ const getMax = (subsequence, num, index = 0) => { * @return {number} */ var lengthOfLIS = (nums) => { - const subsequence = logarithmicSort(nums);/* Time O(N * log(N) */ + const subsequence = logarithmicSort(nums); /* Time O(N * log(N) */ return subsequence.length; -} +}; var logarithmicSort = (nums, subsequence = []) => { - for (const num of nums) {/* Time O(N) */ - const max = subsequence[(subsequence.length - 1)]; + for (const num of nums) { + /* Time O(N) */ + const max = subsequence[subsequence.length - 1]; - const canAdd = (max < num); - if (canAdd) { subsequence.push(num); continue; }/* Space O(N) */ + const canAdd = max < num; + if (canAdd) { + subsequence.push(num); + continue; + } /* Space O(N) */ - const index = binarySearch(num, subsequence); /* Time O(log(N)) */ + const index = binarySearch(num, subsequence); /* Time O(log(N)) */ subsequence[index] = num; } return subsequence; -} +}; const binarySearch = (num, subsequence) => { - let [ left, right ] = [ 0, (subsequence.length - 1) ]; + let [left, right] = [0, subsequence.length - 1]; - while (left < right) {/* Time O(log(N)) */ - const mid = ((left + right) >> 1); + while (left < right) { + /* Time O(log(N)) */ + const mid = (left + right) >> 1; const guess = subsequence[mid]; - const isNumTarget = (num === guess); + const isNumTarget = num === guess; if (isNumTarget) return mid; - const isNumGreater = (guess < num); - if (isNumGreater) left = (mid + 1); + const isNumGreater = guess < num; + if (isNumGreater) left = mid + 1; - const isNumLess = (num < guess); + const isNumLess = num < guess; if (isNumLess) right = mid; } return left; -} \ No newline at end of file +}; diff --git a/javascript/0303-range-sum-query-immutable.js b/javascript/0303-range-sum-query-immutable.js index a09d46b69..c69118fcb 100644 --- a/javascript/0303-range-sum-query-immutable.js +++ b/javascript/0303-range-sum-query-immutable.js @@ -7,9 +7,9 @@ class NumArray { this.arr = nums; } - /** + /** * Time O(n) | Space O(1) - * @param {number} left + * @param {number} left * @param {number} right * @return {number} */ @@ -22,7 +22,7 @@ class NumArray { } } -/** +/** * Your NumArray object will be instantiated and called as such: * var obj = new NumArray(nums) * var param_1 = obj.sumRange(left,right) diff --git a/javascript/0304-range-sum-query-2d-immutable.js b/javascript/0304-range-sum-query-2d-immutable.js index 2319ae5af..2b71097fb 100644 --- a/javascript/0304-range-sum-query-2d-immutable.js +++ b/javascript/0304-range-sum-query-2d-immutable.js @@ -4,32 +4,32 @@ * @param {number[][]} matrix */ class NumMatrix { - constructor(matrix) { - this.matrix = matrix; - } + constructor(matrix) { + this.matrix = matrix; + } - /** - * - * m = row2 - row1; n = col2 - col1 - * Time O(m*n) | Space O(1) - * @param {number} row1 - * @param {number} col1 - * @param {number} row2 - * @param {number} col2 - * @return {number} - */ - sumRegion(row1, col1, row2, col2) { - let sum = 0; - for (let i = row1; i < row2 + 1; i++) { - for (let j = col1; j < col2 + 1; j++) { - sum += this.matrix[i][j]; - } + /** + * + * m = row2 - row1; n = col2 - col1 + * Time O(m*n) | Space O(1) + * @param {number} row1 + * @param {number} col1 + * @param {number} row2 + * @param {number} col2 + * @return {number} + */ + sumRegion(row1, col1, row2, col2) { + let sum = 0; + for (let i = row1; i < row2 + 1; i++) { + for (let j = col1; j < col2 + 1; j++) { + sum += this.matrix[i][j]; + } + } + return sum; } - return sum; - } } -/** +/** * Your NumMatrix object will be instantiated and called as such: * var obj = new NumMatrix(matrix) * var param_1 = obj.sumRegion(row1,col1,row2,col2) diff --git a/javascript/0309-best-time-to-buy-and-sell-stock-with-cooldown.js b/javascript/0309-best-time-to-buy-and-sell-stock-with-cooldown.js index ad34f2512..8bb721e88 100644 --- a/javascript/0309-best-time-to-buy-and-sell-stock-with-cooldown.js +++ b/javascript/0309-best-time-to-buy-and-sell-stock-with-cooldown.js @@ -5,25 +5,26 @@ * @param {number[]} prices * @return {number} */ - var maxProfit = (prices) => { - let [ sold, held, reset ] = [ (-Infinity), (-Infinity), 0 ]; +var maxProfit = (prices) => { + let [sold, held, reset] = [-Infinity, -Infinity, 0]; - [ sold, reset ] = search(prices, sold, held, reset);/* Time O(N) */ + [sold, reset] = search(prices, sold, held, reset); /* Time O(N) */ return Math.max(sold, reset); -} +}; var search = (prices, sold, held, reset) => { - for (const price of prices) {/* Time O(N) */ + for (const price of prices) { + /* Time O(N) */ const preSold = sold; - sold = (held + price); - held = Math.max(held, (reset - price)); + sold = held + price; + held = Math.max(held, reset - price); reset = Math.max(reset, preSold); } - return [ sold, reset ]; -} + return [sold, reset]; +}; /** * DP - Bottom Up @@ -34,30 +35,32 @@ var search = (prices, sold, held, reset) => { * @return {number} */ var maxProfit = (prices) => { - const tabu = initTabu(prices);/* Space O(N) */ + const tabu = initTabu(prices); /* Space O(N) */ - search(prices, tabu);/* Time O(N * N) */ + search(prices, tabu); /* Time O(N * N) */ return tabu[0]; -} +}; var initTabu = (prices) => new Array(prices.length + 2).fill(0); var search = (prices, tabu) => { - for (let i = (prices.length - 1); (0 <= i); i--) {/* Time O(N) */ - const prev = buyAndSell(prices, i, tabu); /* Time O(N) */ + for (let i = prices.length - 1; 0 <= i; i--) { + /* Time O(N) */ + const prev = buyAndSell(prices, i, tabu); /* Time O(N) */ const next = tabu[i + 1]; - tabu[i] = Math.max(prev, next); /* Space O(N) */ + tabu[i] = Math.max(prev, next); /* Space O(N) */ } -} +}; const buyAndSell = (prices, i, tabu, max = 0) => { - for (let sell = (i + 1); (sell < prices.length); sell++) {/* Time O(N) */ - const profit = ((prices[sell] - prices[i]) + tabu[(sell + 2)]); + for (let sell = i + 1; sell < prices.length; sell++) { + /* Time O(N) */ + const profit = prices[sell] - prices[i] + tabu[sell + 2]; max = Math.max(max, profit); } return max; -} \ No newline at end of file +}; diff --git a/javascript/0312-burst-balloons.js b/javascript/0312-burst-balloons.js index 7dd519e09..3b875f91c 100644 --- a/javascript/0312-burst-balloons.js +++ b/javascript/0312-burst-balloons.js @@ -6,38 +6,64 @@ * @param {number[]} nums * @return {number} */ - var maxCoins = (nums) => { - const _nums = [ 1, ...nums, 1 ];/* Time O(N) | Space O(N) */ +var maxCoins = (nums) => { + const _nums = [1, ...nums, 1]; /* Time O(N) | Space O(N) */ - return search(_nums); /* Time O(N * N * N) | Space O((N * N) + HEIGHT) */ -} + return search(_nums); /* Time O(N * N * N) | Space O((N * N) + HEIGHT) */ +}; -var search = (nums, left = 1 , right = (nums.length - 2), memo = initMemo(nums)) => { - const isBaseCase = (right - left < 0); +var search = ( + nums, + left = 1, + right = nums.length - 2, + memo = initMemo(nums), +) => { + const isBaseCase = right - left < 0; if (isBaseCase) return 0; - const hasSeen = (memo[left][right] !== -1); + const hasSeen = memo[left][right] !== -1; if (hasSeen) return memo[left][right]; - return dfs(nums, left, right, memo);/* Time O(N * N * N) | Space O((N * N) + HEIGHT) */ -} + return dfs( + nums, + left, + right, + memo, + ); /* Time O(N * N * N) | Space O((N * N) + HEIGHT) */ +}; -var initMemo = (nums) => new Array(nums.length).fill()/* Time O(N) | Space O(N) */ - .map(() => new Array(nums.length).fill(-1)); /* Time O(N) | Space O(N) */ +var initMemo = (nums) => + new Array(nums.length) + .fill() /* Time O(N) | Space O(N) */ + .map(() => + new Array(nums.length).fill(-1), + ); /* Time O(N) | Space O(N) */ var dfs = (nums, left, right, memo, result = 0) => { - for (let i = left; (i <= right); i++) {/* Time O(N) */ - const gain = ((nums[left - 1] * nums[i]) * nums[right + 1]); - const _left = search(nums, left, (i - 1), memo); /* Time O(N * N) | Space O(HEIGHT) */ - const _right = search(nums, (i + 1), right, memo);/* Time O(N * N) | Space O(HEIGHT) */ - const remaining = (_left + _right); + for (let i = left; i <= right; i++) { + /* Time O(N) */ + const gain = nums[left - 1] * nums[i] * nums[right + 1]; + const _left = search( + nums, + left, + i - 1, + memo, + ); /* Time O(N * N) | Space O(HEIGHT) */ + const _right = search( + nums, + i + 1, + right, + memo, + ); /* Time O(N * N) | Space O(HEIGHT) */ + const remaining = _left + _right; result = Math.max(result, remaining + gain); } - memo[left][right] = result; /* | Space O(N * N) */ + memo[left][right] = + result; /* | Space O(N * N) */ return result; -} +}; /** * DP - Bottom Up @@ -47,29 +73,36 @@ var dfs = (nums, left, right, memo, result = 0) => { * @param {number[]} nums * @return {number} */ - var maxCoins = (nums) => { - const tabu = initTabu(nums);/* Time O(N * N) | Space O(N * N) */ +var maxCoins = (nums) => { + const tabu = initTabu(nums); /* Time O(N * N) | Space O(N * N) */ - search(nums, tabu); /* Time O(N * N * N) | Space O(N * N) */ + search(nums, tabu); /* Time O(N * N * N) | Space O(N * N) */ - return tabu[1][(nums.length)]; -} + return tabu[1][nums.length]; +}; -var initTabu = (nums) => new Array(nums.length + 2).fill()/* Time O(N) | Space O(N) */ - .map(() => new Array(nums.length + 2).fill(0)) /* Time O(N) | Space O(N) */ +var initTabu = (nums) => + new Array(nums.length + 2) + .fill() /* Time O(N) | Space O(N) */ + .map(() => + new Array(nums.length + 2).fill(0), + ); /* Time O(N) | Space O(N) */ var search = (nums, tabu) => { - const _nums = [ 1, ...nums, 1 ]; /* Time O(N) | Space O(N) */ - - for (let left = nums.length; (1 <= left); left--) { /* Time O(N) */ - for (let right = left; (right <= nums.length); right++) {/* Time O(N) */ - for (let i = left; (i <= right); i++) { - const gain = ((_nums[left - 1] * _nums[i]) * _nums[right + 1]); - const remaining = (tabu[left][i - 1] + tabu[i + 1][right]); + const _nums = [1, ...nums, 1]; /* Time O(N) | Space O(N) */ - tabu[left][right] = /* | Space O(N * N) */ + for (let left = nums.length; 1 <= left; left--) { + /* Time O(N) */ + for (let right = left; right <= nums.length; right++) { + /* Time O(N) */ + for (let i = left; i <= right; i++) { + const gain = _nums[left - 1] * _nums[i] * _nums[right + 1]; + const remaining = tabu[left][i - 1] + tabu[i + 1][right]; + + tabu[left][right] = + /* | Space O(N * N) */ Math.max(remaining + gain, tabu[left][right]); } } } -} \ No newline at end of file +}; diff --git a/javascript/0322-coin-change.js b/javascript/0322-coin-change.js index 3e8d8a05a..2708e6a6a 100644 --- a/javascript/0322-coin-change.js +++ b/javascript/0322-coin-change.js @@ -6,38 +6,41 @@ * @param {number} amount * @return {number} */ - var coinChange = (coins, amount, coin = 0) => { +var coinChange = (coins, amount, coin = 0) => { const isBaseCase1 = amount === 0; if (isBaseCase1) return 0; - const isBaseCase2 = !((coin < coins.length) && (0 < amount)); + const isBaseCase2 = !(coin < coins.length && 0 < amount); if (isBaseCase2) return -1; - return dfs(coins, amount, coin);/* Time O(S^N) | Space O(N) */ -} + return dfs(coins, amount, coin); /* Time O(S^N) | Space O(N) */ +}; var dfs = (coins, amount, coin) => { - let [ max, minCost ] = [ (amount / coins[coin]), Infinity ]; + let [max, minCost] = [amount / coins[coin], Infinity]; - for (let num = 0; num <= max; num++) {/* Time O(N) */ - const caUpdate = ((num * coins[coin]) <= amount); + for (let num = 0; num <= max; num++) { + /* Time O(N) */ + const caUpdate = num * coins[coin] <= amount; if (!caUpdate) continue; - const product = (num * coins[coin]); + const product = num * coins[coin]; const difference = amount - product; - const min = coinChange(coins, difference, (coin + 1));/* Time O(S^N) | Space O(N) */ - const cost = (min + num); - - const isSentinel = (min === -1); + const min = coinChange( + coins, + difference, + coin + 1, + ); /* Time O(S^N) | Space O(N) */ + const cost = min + num; + + const isSentinel = min === -1; if (isSentinel) continue; minCost = Math.min(minCost, cost); } - return (minCost !== Infinity) - ? minCost - : -1; -} + return minCost !== Infinity ? minCost : -1; +}; /** * DP - Top Down @@ -48,37 +51,40 @@ var dfs = (coins, amount, coin) => { * @param {number} amount * @return {number} */ - var coinChange = (coins, amount, memo = initMemo(amount)) => { - const isBaseCase1 = (amount < 0); +var coinChange = (coins, amount, memo = initMemo(amount)) => { + const isBaseCase1 = amount < 0; if (isBaseCase1) return -1; - const isBaseCase2 = (amount < 1); + const isBaseCase2 = amount < 1; if (isBaseCase2) return 0; - const isBaseCase3 = (memo[amount - 1] !== 0); + const isBaseCase3 = memo[amount - 1] !== 0; if (isBaseCase3) return memo[amount - 1]; - return dfs(coins, amount, memo);/* Time O(N) | Space O(N) */ -} + return dfs(coins, amount, memo); /* Time O(N) | Space O(N) */ +}; const initMemo = (amount) => Array(amount).fill(0); var dfs = (coins, amount, memo, min = Infinity) => { - for (const coin of coins) { /* Time O(N) */ - const cost = coinChange(coins, (amount - coin), memo);/* Time O(N) | Space O(N) */ - - const canUpdate = ((0 <= cost) && (cost < min)); + for (const coin of coins) { + /* Time O(N) */ + const cost = coinChange( + coins, + amount - coin, + memo, + ); /* Time O(N) | Space O(N) */ + + const canUpdate = 0 <= cost && cost < min; if (!canUpdate) continue; - min = (cost + 1); + min = cost + 1; } - memo[amount - 1] = (min !== Infinity) - ? min - : -1; + memo[amount - 1] = min !== Infinity ? min : -1; return memo[amount - 1]; -} +}; /** * DP - Bottom Up @@ -92,27 +98,27 @@ var dfs = (coins, amount, memo, min = Infinity) => { var coinChange = (coins, amount) => { const tabu = initTabu(amount); - for (let _amount = 1; _amount <= amount; _amount++) {/* Time O(N) */ - for (let coin = 0; coin < coins.length; coin++) { /* Time O(N) */ - const canUpdate = (coins[coin] <= _amount); + for (let _amount = 1; _amount <= amount; _amount++) { + /* Time O(N) */ + for (let coin = 0; coin < coins.length; coin++) { + /* Time O(N) */ + const canUpdate = coins[coin] <= _amount; if (!canUpdate) continue; - const difference = (_amount - coins[coin]); - const min = (tabu[difference] + 1); + const difference = _amount - coins[coin]; + const min = tabu[difference] + 1; - tabu[_amount] = Math.min(tabu[_amount], min); /* Space O(N) */ + tabu[_amount] = Math.min(tabu[_amount], min); /* Space O(N) */ } } - return (tabu[amount] <= amount) - ? tabu[amount] - : -1; -} + return tabu[amount] <= amount ? tabu[amount] : -1; +}; const initTabu = (amount) => { - const tabu = Array((amount + 1)).fill((amount + 1)); + const tabu = Array(amount + 1).fill(amount + 1); tabu[0] = 0; return tabu; -} \ No newline at end of file +}; diff --git a/javascript/0323-number-of-connected-components-in-an-undirected-graph.js b/javascript/0323-number-of-connected-components-in-an-undirected-graph.js index d578f548f..f0dc6bbd0 100644 --- a/javascript/0323-number-of-connected-components-in-an-undirected-graph.js +++ b/javascript/0323-number-of-connected-components-in-an-undirected-graph.js @@ -21,15 +21,15 @@ const initGraph = (n) => ({ }); const buildGraph = (n, edges) => { - const { graph, visited } = initGraph(n) + const { graph, visited } = initGraph(n); - for (const [ src, dst ] of edges) { + for (const [src, dst] of edges) { graph[src].push(dst); graph[dst].push(src); } return { graph, visited }; -} +}; const hasPath = (graph, current, visited) => { if (visited[current]) return false; @@ -40,7 +40,7 @@ const hasPath = (graph, current, visited) => { } return true; -} +}; /** * https://leetcode.com/problems/number-of-connected-components-in-an-undirected-graph/ @@ -49,63 +49,62 @@ const hasPath = (graph, current, visited) => { * @param {number[][]} edges * @return {number} */ - var countComponents = function(n, edges) { - return new UnionFind(n, edges) - .connectedComponents; +var countComponents = function (n, edges) { + return new UnionFind(n, edges).connectedComponents; }; class UnionFind { - constructor (n, edges) { - this.parent = new Array(n).fill().map((_, index) => index), - this.rank = new Array(n).fill(1) + constructor(n, edges) { + ((this.parent = new Array(n).fill().map((_, index) => index)), + (this.rank = new Array(n).fill(1))); this.connectedComponents = n; this.search(edges); } - search (edges) { - for (const [ src, dst ] of edges) { - this.union(src, dst) + search(edges) { + for (const [src, dst] of edges) { + this.union(src, dst); } } - find (head, tail = head, { parent } = this) { - const isEqual = () => head === parent[head] + find(head, tail = head, { parent } = this) { + const isEqual = () => head === parent[head]; while (!isEqual()) { head = parent[head]; } this.compress(tail, head); - return head + return head; } - compress (tail, head, { parent } = this) { + compress(tail, head, { parent } = this) { parent[tail] = head; } - - increaseRank (head, tail, { rank } = this) { + + increaseRank(head, tail, { rank } = this) { rank[head] += rank[tail]; } - union (src, dst, { rank } = this) { - const [ rootSrc, rootDst ] = [ this.find(src), this.find(dst) ] + union(src, dst, { rank } = this) { + const [rootSrc, rootDst] = [this.find(src), this.find(dst)]; - const hasCycle = rootSrc === rootDst - if (hasCycle) return + const hasCycle = rootSrc === rootDst; + if (hasCycle) return; this.connectedComponents--; - const isGreater = rank[rootSrc] < rank[rootDst] + const isGreater = rank[rootSrc] < rank[rootDst]; if (isGreater) { - this.increaseRank(rootDst, rootSrc) - this.compress(rootSrc, rootDst) + this.increaseRank(rootDst, rootSrc); + this.compress(rootSrc, rootDst); } - const isLess = rank[rootDst] <= rank[rootSrc] + const isLess = rank[rootDst] <= rank[rootSrc]; if (isLess) { - this.increaseRank(rootSrc, rootDst) - this.compress(rootDst, rootSrc) + this.increaseRank(rootSrc, rootDst); + this.compress(rootDst, rootSrc); } } } diff --git a/javascript/0329-longest-increasing-path-in-a-matrix.js b/javascript/0329-longest-increasing-path-in-a-matrix.js index f59d674ea..df04f6840 100644 --- a/javascript/0329-longest-increasing-path-in-a-matrix.js +++ b/javascript/0329-longest-increasing-path-in-a-matrix.js @@ -5,34 +5,58 @@ * @param {number[][]} matrix * @return {number} */ - var longestIncreasingPath = (matrix, maxPath = 0) => { - const [ rows, cols ] = [ matrix.length, matrix[0].length ]; - - for (let row = 0; (row < rows); row++) {/* Time O(N) */ - for (let col = 0; (col < cols); col++) {/* Time O(M) */ - const path = dfs(matrix, row, rows, col, cols);/* Time O(2^(N + M)) | Space O(HEIGHT) */ +var longestIncreasingPath = (matrix, maxPath = 0) => { + const [rows, cols] = [matrix.length, matrix[0].length]; + + for (let row = 0; row < rows; row++) { + /* Time O(N) */ + for (let col = 0; col < cols; col++) { + /* Time O(M) */ + const path = dfs( + matrix, + row, + rows, + col, + cols, + ); /* Time O(2^(N + M)) | Space O(HEIGHT) */ maxPath = Math.max(maxPath, path); } } return maxPath; -} +}; var dfs = (matrix, row, rows, col, cols, ans = 0) => { - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) {/* Time O(4) */ - const path = dfs(matrix, _row, rows, _col, cols); /* Time O(2^(N + M)) | Space O(HEIGHT) */ + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { + /* Time O(4) */ + const path = dfs( + matrix, + _row, + rows, + _col, + cols, + ); /* Time O(2^(N + M)) | Space O(HEIGHT) */ ans = Math.max(ans, path); } ans += 1; return ans; -} +}; -var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ] - .map(([ _row, _col ]) => [ (row + _row), (col + _col) ]) - .filter(([ _row, _col ]) => (0 <= _row) && (_row < rows) && (0 <= _col) && (_col < cols)); +var getNeighbors = (row, rows, col, cols) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + .map(([_row, _col]) => [row + _row, col + _col]) + .filter( + ([_row, _col]) => + 0 <= _row && _row < rows && 0 <= _col && _col < cols, + ); /** * DP - Top Down @@ -42,12 +66,15 @@ var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ * @param {number[][]} matrix * @return {number} */ - var longestIncreasingPath = (matrix, maxPath = 0, memo = initMemo(matrix)) => { - const [ rows, cols ] = [ matrix.length, matrix[0].length ]; - - for (let row = 0; row < rows; row++) {/* Time O(N) */ - for (let col = 0; col < cols; col++) {/* Time O(M) */ - const path = /* Time O(N * M) | Space O((N * M) + HEIGHT) */ +var longestIncreasingPath = (matrix, maxPath = 0, memo = initMemo(matrix)) => { + const [rows, cols] = [matrix.length, matrix[0].length]; + + for (let row = 0; row < rows; row++) { + /* Time O(N) */ + for (let col = 0; col < cols; col++) { + /* Time O(M) */ + const path = + /* Time O(N * M) | Space O((N * M) + HEIGHT) */ search(matrix, row, rows, col, cols, memo); maxPath = Math.max(maxPath, path); @@ -57,35 +84,63 @@ var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ return maxPath; }; -var initMemo = (matrix) => new Array(matrix.length).fill()/* Time O(N) | Space O(N)*/ - .map(() => new Array(matrix[0].length).fill(0)); /* Time O(M) | Space O(M)*/ +var initMemo = (matrix) => + new Array(matrix.length) + .fill() /* Time O(N) | Space O(N)*/ + .map(() => + new Array(matrix[0].length).fill(0), + ); /* Time O(M) | Space O(M)*/ const search = (matrix, row, rows, col, cols, memo) => { - const hasSeen = (memo[row][col] !== 0) + const hasSeen = memo[row][col] !== 0; if (hasSeen) return memo[row][col]; - return dfs(matrix, row, rows, col, cols, memo);/* Time O(N * M) | Space O((N * M) + HEIGHT) */ -} + return dfs( + matrix, + row, + rows, + col, + cols, + memo, + ); /* Time O(N * M) | Space O((N * M) + HEIGHT) */ +}; var dfs = (matrix, row, rows, col, cols, memo) => { - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) {/* Time O(4) */ - const [ parent, node ] = [ matrix[row][col], matrix[_row][_col] ]; + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { + /* Time O(4) */ + const [parent, node] = [matrix[row][col], matrix[_row][_col]]; - const isLess = (node <= parent); + const isLess = node <= parent; if (isLess) continue; - const path = search(matrix, _row, rows, _col, cols, memo); /* Time O(N * M) | Space O(HEIGHT) */ + const path = search( + matrix, + _row, + rows, + _col, + cols, + memo, + ); /* Time O(N * M) | Space O(HEIGHT) */ memo[row][col] = Math.max(memo[row][col], path); } - memo[row][col] += 1; /* | Space O(N * M) */ + memo[row][col] += 1; /* | Space O(N * M) */ return memo[row][col]; -} +}; -var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ] - .map(([ _row, _col ]) => [ (row + _row), (col + _col) ]) - .filter(([ _row, _col ]) => (0 <= _row) && (_row < rows) && (0 <= _col) && (_col < cols)); +var getNeighbors = (row, rows, col, cols) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + .map(([_row, _col]) => [row + _row, col + _col]) + .filter( + ([_row, _col]) => + 0 <= _row && _row < rows && 0 <= _col && _col < cols, + ); /** * Topological Sort @@ -98,79 +153,109 @@ var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ * @return {number} */ var longestIncreasingPath = (matrix) => { - const { graph, indegree, sources } = /* Time O(N * M) | Space O(N * M) */ + const { graph, indegree, sources } = + /* Time O(N * M) | Space O(N * M) */ buildGraph(matrix); - findSources(graph, indegree, sources);/* Time O(N * M) | Space O(N * M) */ + findSources(graph, indegree, sources); /* Time O(N * M) | Space O(N * M) */ - return bfs(graph, indegree, sources); /* Time O((N * M) + WIDTH) | Space O((N * M) + WIDTH) */ -} + return bfs( + graph, + indegree, + sources, + ); /* Time O((N * M) + WIDTH) | Space O((N * M) + WIDTH) */ +}; const initGraph = (rows, cols) => ({ - graph: new Array((rows + 2)).fill() /* Time O(N) | Space O(N) */ - .map(() => new Array((cols + 2)).fill(0)),/* Time O(M) | Space O(M) */ - indegree: new Array((rows + 2)).fill() /* Time O(N) | Space O(N) */ - .map(() => new Array((cols + 2)).fill(0)),/* Time O(M) | Space O(M) */ - sources: new Queue() -}) + graph: new Array(rows + 2) + .fill() /* Time O(N) | Space O(N) */ + .map(() => new Array(cols + 2).fill(0)) /* Time O(M) | Space O(M) */, + indegree: new Array(rows + 2) + .fill() /* Time O(N) | Space O(N) */ + .map(() => new Array(cols + 2).fill(0)) /* Time O(M) | Space O(M) */, + sources: new Queue(), +}); var buildGraph = (matrix) => { - const [ rows, cols ] = [ matrix.length, matrix[0].length ]; - const { graph, indegree, sources } = /* Time O(N * M) | Space O(N * M) */ + const [rows, cols] = [matrix.length, matrix[0].length]; + const { graph, indegree, sources } = + /* Time O(N * M) | Space O(N * M) */ initGraph(rows, cols); - for (let row = 1; (row < (rows + 1)); row++) {/* Time O(N) */ - graph[row] = [ 0, ...matrix[row - 1], 0 ]; /* | Space O(N * M) */ + for (let row = 1; row < rows + 1; row++) { + /* Time O(N) */ + graph[row] = [ + 0, + ...matrix[row - 1], + 0, + ]; /* | Space O(N * M) */ } - for (let row = 1; (row <= rows); row++) { /* Time O(N) */ - for (let col = 1; (col <= cols); col++) { /* Time O(M) */ - for (const [ _row, _col ] of getNeighbors(row, col)) {/* Time O(4) */ - const isSink = (graph[row][col] < graph[_row][_col]); - if (isSink) indegree[row][col] += 1; /* | Space O(N * M) */ + for (let row = 1; row <= rows; row++) { + /* Time O(N) */ + for (let col = 1; col <= cols; col++) { + /* Time O(M) */ + for (const [_row, _col] of getNeighbors(row, col)) { + /* Time O(4) */ + const isSink = graph[row][col] < graph[_row][_col]; + if (isSink) + indegree[row][col] += 1; /* | Space O(N * M) */ } } } return { graph, indegree, sources }; -} +}; -var getNeighbors = (row, col) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ] - .map(([ _row, _col ]) => [ (row + _row), (col + _col) ]); +var getNeighbors = (row, col) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ].map(([_row, _col]) => [row + _row, col + _col]); var findSources = (graph, indegree, sources) => { - const [ rows, cols ] = [ graph.length, graph[0].length ]; - - for (let row = 1; (row < (rows - 1)); ++row) {/* Time O(N) */ - for (let col = 1; (col < (cols - 1)); ++col) {/* Time O(M) */ - const isSource = (indegree[row][col] === 0); - if (isSource) sources.enqueue([ row, col ]); /* Space O(N * M) */ + const [rows, cols] = [graph.length, graph[0].length]; + + for (let row = 1; row < rows - 1; ++row) { + /* Time O(N) */ + for (let col = 1; col < cols - 1; ++col) { + /* Time O(M) */ + const isSource = indegree[row][col] === 0; + if (isSource) sources.enqueue([row, col]); /* Space O(N * M) */ } } -} +}; const bfs = (graph, indegree, sources, path = 0) => { - while (!sources.isEmpty()) { /* Time(N * M) */ - for (let level = (sources.size() - 1); 0 <= level; level--) {/* Time(WIDTH) */ - checkNeighbors(graph, indegree, sources) /* Space((N * M) + WIDTH) */ + while (!sources.isEmpty()) { + /* Time(N * M) */ + for (let level = sources.size() - 1; 0 <= level; level--) { + /* Time(WIDTH) */ + checkNeighbors( + graph, + indegree, + sources, + ); /* Space((N * M) + WIDTH) */ } path += 1; } return path; -} +}; const checkNeighbors = (graph, indegree, sources) => { - const [ row, col ] = sources.dequeue(); + const [row, col] = sources.dequeue(); - for (const [ _row, _col ] of getNeighbors(row, col)) { - const canDisconnect = (graph[_row][_col] < graph[row][col]); + for (const [_row, _col] of getNeighbors(row, col)) { + const canDisconnect = graph[_row][_col] < graph[row][col]; if (!canDisconnect) continue; - indegree[_row][_col] -= 1; /* Space O(N * M) */ + indegree[_row][_col] -= 1; /* Space O(N * M) */ - const isSource = (indegree[_row][_col] === 0); - if (isSource) sources.enqueue([ _row, _col ]);/* Space O(WIDTH) */ + const isSource = indegree[_row][_col] === 0; + if (isSource) sources.enqueue([_row, _col]); /* Space O(WIDTH) */ } -} \ No newline at end of file +}; diff --git a/javascript/0332-reconstruct-itinerary.js b/javascript/0332-reconstruct-itinerary.js index f198f3af6..1de40c8d7 100644 --- a/javascript/0332-reconstruct-itinerary.js +++ b/javascript/0332-reconstruct-itinerary.js @@ -12,12 +12,12 @@ var findItinerary = (tickets) => { }; const dfs = (tickets, graph, city = 'JFK', path = ['JFK']) => { - const isBaseCase = (path.length === (tickets.length + 1)); + const isBaseCase = path.length === tickets.length + 1; if (isBaseCase) return true; - const queue = (graph.get(city) || []); + const queue = graph.get(city) || []; - const isEmpty = (queue.length === 0); + const isEmpty = queue.length === 0; if (isEmpty) return false; for (const nextCity of queue.slice()) { @@ -33,14 +33,13 @@ const dfs = (tickets, graph, city = 'JFK', path = ['JFK']) => { return false; }; - const buildGraph = (tickets, graph = new Map()) => { - for (const [ src, dst ] of tickets) { - const edges = (graph.get(src) || []); + for (const [src, dst] of tickets) { + const edges = graph.get(src) || []; edges.push(dst); graph.set(src, edges); } return graph; -} +}; diff --git a/javascript/0337-house-robber-iii.js b/javascript/0337-house-robber-iii.js index 34f19eada..2f1a776f3 100644 --- a/javascript/0337-house-robber-iii.js +++ b/javascript/0337-house-robber-iii.js @@ -12,19 +12,19 @@ * @param {TreeNode} root * @return {number} */ -var rob = function(root) { - +var rob = function (root) { function dfs(root) { - if(!root) return [0, 0]; + if (!root) return [0, 0]; const leftSubTree = dfs(root.left); const rightSubTree = dfs(root.right); - const withoutRoot = Math.max(...leftSubTree) + Math.max(...rightSubTree); + const withoutRoot = + Math.max(...leftSubTree) + Math.max(...rightSubTree); const withRoot = root.val + leftSubTree[0] + rightSubTree[0]; - return [withoutRoot, withRoot]; + return [withoutRoot, withRoot]; } - return Math.max(...dfs(root)); + return Math.max(...dfs(root)); }; diff --git a/javascript/0338-counting-bits.js b/javascript/0338-counting-bits.js index 045d823a9..912c80059 100644 --- a/javascript/0338-counting-bits.js +++ b/javascript/0338-counting-bits.js @@ -4,10 +4,10 @@ * @param {number} n * @return {number[]} */ -var countBits = function (n, dp = [ 0 ]) { - for (let i = 1; i < (n + 1); i++) { - const [ mid, bit ] = [ (i >> 1), (i & 1) ] - const bits = (dp[mid] + bit) +var countBits = function (n, dp = [0]) { + for (let i = 1; i < n + 1; i++) { + const [mid, bit] = [i >> 1, i & 1]; + const bits = dp[mid] + bit; dp.push(bits); } diff --git a/javascript/0344-reverse-string.js b/javascript/0344-reverse-string.js index df84a10ed..1b6fd5ebb 100644 --- a/javascript/0344-reverse-string.js +++ b/javascript/0344-reverse-string.js @@ -2,14 +2,16 @@ * @param {character[]} s * @return {void} Do not return anything, modify s in-place instead. */ - var reverseString = function(s) { - let i = 0, j = s.length-1; - - while(i <= j) { - let leftval = s[i], rightval = s[j]; +var reverseString = function (s) { + let i = 0, + j = s.length - 1; + + while (i <= j) { + let leftval = s[i], + rightval = s[j]; s[i] = rightval; s[j] = leftval; - + i++; j--; } diff --git a/javascript/0347-top-k-frequent-elements.js b/javascript/0347-top-k-frequent-elements.js index 9813bb81b..e2137c4c4 100644 --- a/javascript/0347-top-k-frequent-elements.js +++ b/javascript/0347-top-k-frequent-elements.js @@ -6,19 +6,22 @@ * @param {number} k * @return {number[]} */ -var topKFrequent = function(nums, k) { - let frequency = {} - for( let i = 0; i < nums.length; i++){ - if(frequency.hasOwnProperty(nums[i])) frequency[nums[i]] += 1; +var topKFrequent = function (nums, k) { + let frequency = {}; + for (let i = 0; i < nums.length; i++) { + if (frequency.hasOwnProperty(nums[i])) frequency[nums[i]] += 1; else frequency[nums[i]] = 1; } - let result = Object.keys(frequency).map((key) => [Number(key), frequency[key]]); - let sortedResult = result.sort((a,b) => { - return b[1]-a[1] - }) - let output = [] - for ( let i = 0; i < k; i++){ - output.push(sortedResult[i][0]) + let result = Object.keys(frequency).map((key) => [ + Number(key), + frequency[key], + ]); + let sortedResult = result.sort((a, b) => { + return b[1] - a[1]; + }); + let output = []; + for (let i = 0; i < k; i++) { + output.push(sortedResult[i][0]); } return output; }; @@ -32,23 +35,22 @@ var topKFrequent = function(nums, k) { * @return {number[]} */ -var topKFrequent = function(nums, k) { +var topKFrequent = function (nums, k) { const mp = new Map(); const arr = new Array(nums.length + 1).fill(0); const ans = []; - nums.forEach(el => { + nums.forEach((el) => { const val = mp.get(el) || 0; mp.set(el, val + 1); }); - for ( let [key, value] of mp ) { + for (let [key, value] of mp) { const prev = arr[value] || []; prev.push(key); arr[value] = prev; } - arr.reverse(); for (let el of arr) { if (k < 1) break; diff --git a/javascript/0352-data-stream-as-disjoint-intervals.js b/javascript/0352-data-stream-as-disjoint-intervals.js index 3cd7f7717..088b5265c 100644 --- a/javascript/0352-data-stream-as-disjoint-intervals.js +++ b/javascript/0352-data-stream-as-disjoint-intervals.js @@ -1,31 +1,31 @@ class SummaryRanges { - constructor() { - this.numSet = new Set(); - } + constructor() { + this.numSet = new Set(); + } + + addNum(value) { + this.numSet.add(value); + } - addNum(value) { - this.numSet.add(value); - } + getIntervals() { + let nums = Array.from(this.numSet.keys()); + nums.sort((a, b) => a - b); - getIntervals() { - let nums = Array.from(this.numSet.keys()); - nums.sort((a, b) => a - b); + let res = []; - let res = []; + let i = 0; - let i = 0; + while (i < nums.length) { + let start = nums[i]; - while (i < nums.length) { - let start = nums[i]; + while (i + 1 < nums.length && nums[i] + 1 == nums[i + 1]) { + i++; + } - while (i + 1 < nums.length && nums[i] + 1 == nums[i + 1]) { - i++; - } + res.push([start, nums[i]]); + i++; + } - res.push([start, nums[i]]); - i++; + return res; } - - return res; - } } diff --git a/javascript/0355-design-twitter.js b/javascript/0355-design-twitter.js index d2fb3bad9..181d5f2e2 100644 --- a/javascript/0355-design-twitter.js +++ b/javascript/0355-design-twitter.js @@ -1,42 +1,43 @@ -/** - * https://leetcode.com/problems/design-twitter/ - * Your Twitter object will be instantiated and called as such: - * var obj = new Twitter() - * obj.postTweet(userId,tweetId) - * var param_2 = obj.getNewsFeed(userId) - * obj.follow(followerId,followeeId) - * obj.unfollow(followerId,followeeId) - */ - class Twitter { - constructor () { - this.tweets = []; - this.following = new Map(); - } - - postTweet (userId, tweetId, { tweets } = this) { - tweets.push({ authorId: userId, id: tweetId }); - } - - getNewsFeed (userId, newsIDs = [], { tweets, following } = this) { - for (let i = (tweets.length - 1); ((0 <= i) && (newsIDs.length < 10)); i--) { - const tweet = tweets[i]; - - const isAuthor = tweet.authorId === userId - const isFollowing = following?.get(userId)?.has(tweet.authorId); - const canAddTweet = isAuthor || isFollowing - if (canAddTweet) newsIDs.push(tweet.id); - } - - return newsIDs; - } - - follow (followerId, followeeId, { following } = this) { - if (!following.has(followerId)) following.set(followerId, new Set()); - - following.get(followerId).add(followeeId); - } - - unfollow (followerId, followeeId, { following } = this) { - if (following.has(followerId)) following.get(followerId).delete(followeeId); - } -} +/** + * https://leetcode.com/problems/design-twitter/ + * Your Twitter object will be instantiated and called as such: + * var obj = new Twitter() + * obj.postTweet(userId,tweetId) + * var param_2 = obj.getNewsFeed(userId) + * obj.follow(followerId,followeeId) + * obj.unfollow(followerId,followeeId) + */ +class Twitter { + constructor() { + this.tweets = []; + this.following = new Map(); + } + + postTweet(userId, tweetId, { tweets } = this) { + tweets.push({ authorId: userId, id: tweetId }); + } + + getNewsFeed(userId, newsIDs = [], { tweets, following } = this) { + for (let i = tweets.length - 1; 0 <= i && newsIDs.length < 10; i--) { + const tweet = tweets[i]; + + const isAuthor = tweet.authorId === userId; + const isFollowing = following?.get(userId)?.has(tweet.authorId); + const canAddTweet = isAuthor || isFollowing; + if (canAddTweet) newsIDs.push(tweet.id); + } + + return newsIDs; + } + + follow(followerId, followeeId, { following } = this) { + if (!following.has(followerId)) following.set(followerId, new Set()); + + following.get(followerId).add(followeeId); + } + + unfollow(followerId, followeeId, { following } = this) { + if (following.has(followerId)) + following.get(followerId).delete(followeeId); + } +} diff --git a/javascript/0367-valid-perfect-square.js b/javascript/0367-valid-perfect-square.js index a46a49c12..c15951b30 100644 --- a/javascript/0367-valid-perfect-square.js +++ b/javascript/0367-valid-perfect-square.js @@ -2,16 +2,17 @@ * @param {number} num * @return {boolean} */ - var isPerfectSquare = function(num) { - let left = 1, right = num; - - while(left <= right) { +var isPerfectSquare = function (num) { + let left = 1, + right = num; + + while (left <= right) { let mid = Math.floor((left + right) / 2); - - if(mid*mid === num) return true; - else if(mid*mid > num) right = mid -1; + + if (mid * mid === num) return true; + else if (mid * mid > num) right = mid - 1; else left = mid + 1; } - + return false; }; diff --git a/javascript/0371-sum-of-two-integers.js b/javascript/0371-sum-of-two-integers.js index 1fb652a62..582241546 100644 --- a/javascript/0371-sum-of-two-integers.js +++ b/javascript/0371-sum-of-two-integers.js @@ -5,13 +5,13 @@ * @param {number} b * @return {number} */ - var getSum = function(a, b) { +var getSum = function (a, b) { while (b !== 0) { - const [ xor, carry ] = [ (a ^ b), ((a & b) << 1) ]; + const [xor, carry] = [a ^ b, (a & b) << 1]; a = xor; b = carry; } - - return a -}; \ No newline at end of file + + return a; +}; diff --git a/javascript/0374-guess-number-higher-or-lower.js b/javascript/0374-guess-number-higher-or-lower.js index 416b61b5e..f3042911b 100644 --- a/javascript/0374-guess-number-higher-or-lower.js +++ b/javascript/0374-guess-number-higher-or-lower.js @@ -1,15 +1,12 @@ -var guessNumber = function(n) { +var guessNumber = function (n) { let low = 1; let high = n; - - while(true) { - let mid = low + Math.floor((high - low)/2); + + while (true) { + let mid = low + Math.floor((high - low) / 2); let myGuess = guess(mid); - if(myGuess == 1) - low = mid + 1; - else if(myGuess == -1) - high = mid - 1; - else - return mid; + if (myGuess == 1) low = mid + 1; + else if (myGuess == -1) high = mid - 1; + else return mid; } }; diff --git a/javascript/0392-is-subsequence.js b/javascript/0392-is-subsequence.js index 6f8fee951..ae40a1739 100644 --- a/javascript/0392-is-subsequence.js +++ b/javascript/0392-is-subsequence.js @@ -4,19 +4,18 @@ * @param {string} t * @return {boolean} */ -var isSubsequence = function(s, t) { - - if(!s.length || (s === t)) return true; - if(s.length > t.length) return false; - +var isSubsequence = function (s, t) { + if (!s.length || s === t) return true; + if (s.length > t.length) return false; + let j = 0; - - for(let i = 0; i < t.length && j < s.length; i++) { - if(s[j] === t[i]) { + + for (let i = 0; i < t.length && j < s.length; i++) { + if (s[j] === t[i]) { j++; } } - + return j === s.length; }; @@ -26,13 +25,13 @@ var isSubsequence = function(s, t) { * @param {string} t * @return {boolean} */ -var isSubsequence = function(s, t) { +var isSubsequence = function (s, t) { for (let char of s) { let indexChar = t.indexOf(char); if (indexChar === -1) { return false; } - t = t.slice(indexChar+1); + t = t.slice(indexChar + 1); } - return true + return true; }; diff --git a/javascript/0410-split-array-largest-sum.js b/javascript/0410-split-array-largest-sum.js index 32a30f03a..7d99ba5a8 100644 --- a/javascript/0410-split-array-largest-sum.js +++ b/javascript/0410-split-array-largest-sum.js @@ -1,20 +1,19 @@ /** * https://leetcode.com/problems/split-array-largest-sum/ - * + * * Binary Search * Time O(log(s)*n) (s = difference between the least and max possible value) | Space O(1) * @param {number[]} nums * @param {number} k * @return {number} */ -var splitArray = function(nums, k) { - +var splitArray = function (nums, k) { let left = Math.max(...nums); let right = nums.reduce((acc, num) => acc + num, 0); let result = right; - while(left <= right) { + while (left <= right) { const mid = (left + right) >> 1; - if(canSplit(mid)) { + if (canSplit(mid)) { result = mid; right = mid - 1; } else { @@ -26,9 +25,9 @@ var splitArray = function(nums, k) { let splitCount = 0; let currSum = 0; - for(let i = 0; i < nums.length; i++) { + for (let i = 0; i < nums.length; i++) { currSum += nums[i]; - if(currSum > largest) { + if (currSum > largest) { currSum = nums[i]; splitCount++; } diff --git a/javascript/0416-partition-equal-subset-sum.js b/javascript/0416-partition-equal-subset-sum.js index 0206b8c31..ec0dbc06e 100644 --- a/javascript/0416-partition-equal-subset-sum.js +++ b/javascript/0416-partition-equal-subset-sum.js @@ -5,38 +5,38 @@ * @param {number[]} nums * @return {boolean} */ - var canPartition = (nums) => { - const sum = getSum(nums);/* Time O(N) */ - const subSetSum = (sum / 2); +var canPartition = (nums) => { + const sum = getSum(nums); /* Time O(N) */ + const subSetSum = sum / 2; - const isEven = ((sum % 2) === 0); + const isEven = sum % 2 === 0; if (!isEven) return false; - const index = (nums.length - 1); + const index = nums.length - 1; return dfs(nums, index, subSetSum); -} +}; var getSum = (nums, sum = 0) => { - for (const num of nums) (sum += num);/* Time O(N) */ + for (const num of nums) sum += num; /* Time O(N) */ return sum; -} +}; var dfs = (nums, index, subSetSum) => { const isBaseCase1 = subSetSum === 0; if (isBaseCase1) return true; - const isBaseCase2 = (index === 0) || (subSetSum < 0); + const isBaseCase2 = index === 0 || subSetSum < 0; if (isBaseCase2) return false; - const difference = (subSetSum - nums[(index - 1)]); + const difference = subSetSum - nums[index - 1]; - const left = dfs(nums, (index - 1), difference); - const right = dfs(nums, (index - 1), subSetSum); + const left = dfs(nums, index - 1, difference); + const right = dfs(nums, index - 1, subSetSum); - return (left || right); -} + return left || right; +}; /** * DP - Top Down @@ -46,43 +46,50 @@ var dfs = (nums, index, subSetSum) => { * @param {number[]} nums * @return {boolean} */ - var canPartition = (nums) => { +var canPartition = (nums) => { const isEmpty = nums.length === 0; if (isEmpty) return false; - const sum = getSum(nums); /* Time O(N) */ + const sum = getSum(nums); /* Time O(N) */ - const isEven = ((sum % 2) === 0); + const isEven = sum % 2 === 0; if (!isEven) return false; - const subSetSum = (sum >> 1); - const memo = initMemo(nums, subSetSum); /* | Space O(N * M) */ - const index = (nums.length - 1); + const subSetSum = sum >> 1; + const memo = initMemo(nums, subSetSum); /* | Space O(N * M) */ + const index = nums.length - 1; - return dfs(nums, index, subSetSum, memo);/* Time O(N * M) | Space O(N * M) */ -} + return dfs( + nums, + index, + subSetSum, + memo, + ); /* Time O(N * M) | Space O(N * M) */ +}; -var initMemo = (nums, subSetSum) => new Array((nums.length + 1)).fill()/* Space O(N) */ - .map(() => new Array((subSetSum + 1)).fill(null)); /* Space O(M) */ +var initMemo = (nums, subSetSum) => + new Array(nums.length + 1) + .fill() /* Space O(N) */ + .map(() => new Array(subSetSum + 1).fill(null)); /* Space O(M) */ var dfs = (nums, index, subSetSum, memo) => { - const isBaseCase1 = (subSetSum === 0); + const isBaseCase1 = subSetSum === 0; if (isBaseCase1) return true; - const isBaseCase2 = ((index === 0) || (subSetSum < 0)); + const isBaseCase2 = index === 0 || subSetSum < 0; if (isBaseCase2) return false; - const hasSeen = (memo[index][subSetSum] !== null); + const hasSeen = memo[index][subSetSum] !== null; if (hasSeen) return memo[index][subSetSum]; - const difference = (subSetSum - nums[(index - 1)]); + const difference = subSetSum - nums[index - 1]; - const left = dfs(nums, (index - 1), difference, memo); - const right = dfs(nums, (index - 1), subSetSum, memo); + const left = dfs(nums, index - 1, difference, memo); + const right = dfs(nums, index - 1, subSetSum, memo); - memo[index][subSetSum] = (left || right); + memo[index][subSetSum] = left || right; return memo[index][subSetSum]; -} +}; /** * DP - Bottom Up @@ -96,52 +103,62 @@ var canPartition = (nums) => { const isEmpty = nums.length === 0; if (isEmpty) return false; - const sum = getSum(nums); /* Time O(N) */ + const sum = getSum(nums); /* Time O(N) */ - const isEven = ((sum % 2) === 0); + const isEven = sum % 2 === 0; if (!isEven) return false; - const subSetSum = (sum >> 1); - const tabu = initTabu(nums, subSetSum);/* | Space O(N * M) */ + const subSetSum = sum >> 1; + const tabu = initTabu(nums, subSetSum); /* | Space O(N * M) */ search(nums, subSetSum, tabu); return tabu[nums.length][subSetSum]; -} +}; var getSum = (nums, sum = 0) => { - for (const num of nums) { sum += num };/* Time O(N) */ + for (const num of nums) { + sum += num; + } /* Time O(N) */ return sum; -} +}; var initTabu = (nums, subSetSum) => { - const tabu = new Array((nums.length + 1)).fill()/* Space O(N) */ - .map(() => new Array((subSetSum + 1)).fill(false));/* Space O(M) */ + const tabu = new Array(nums.length + 1) + .fill() /* Space O(N) */ + .map(() => new Array(subSetSum + 1).fill(false)); /* Space O(M) */ - tabu[0][0] = true; /* Space O(N * M) */ + tabu[0][0] = true; /* Space O(N * M) */ return tabu; -} +}; var search = (nums, subSetSum, tabu) => { - for (let numIndex = 1; (numIndex <= nums.length); numIndex++) {/* Time O(N) */ - update(nums, numIndex, subSetSum, tabu); /* Time O(N) | Space O(N * M) */ + for (let numIndex = 1; numIndex <= nums.length; numIndex++) { + /* Time O(N) */ + update( + nums, + numIndex, + subSetSum, + tabu, + ); /* Time O(N) | Space O(N * M) */ } -} +}; var update = (nums, numIndex, subSetSum, tabu) => { - const num = (numIndex - 1); + const num = numIndex - 1; const prevNum = nums[num]; - for (let subSet = 0; subSet <= subSetSum; subSet++) {/* Time O(M) */ - const isNumGreater = (subSet < prevNum); + for (let subSet = 0; subSet <= subSetSum; subSet++) { + /* Time O(M) */ + const isNumGreater = subSet < prevNum; - tabu[numIndex][subSet] = isNumGreater /* Space O(N * M) */ - ? (tabu[num][subSet]) - : ((tabu[num][subSet]) || (tabu[num][subSet - prevNum])); + tabu[numIndex][subSet] = isNumGreater /* Space O(N * M) */ + ? tabu[num][subSet] + : tabu[num][subSet] || tabu[num][subSet - prevNum]; } -} +}; /** * DP - Bottom Up @@ -155,43 +172,47 @@ var canPartition = (nums) => { const isEmpty = nums.length === 0; if (isEmpty) return false; - const sum = getSum(nums); /* Time O(N) */ + const sum = getSum(nums); /* Time O(N) */ - const isEven = ((sum % 2) === 0); + const isEven = sum % 2 === 0; if (!isEven) return false; - const subSetSum = (sum >> 1); - const tabu = initTabu(subSetSum);/* | Space O(M) */ + const subSetSum = sum >> 1; + const tabu = initTabu(subSetSum); /* | Space O(M) */ - search(nums, subSetSum, tabu); /* Time O(N * M) | Space O(M) */ + search(nums, subSetSum, tabu); /* Time O(N * M) | Space O(M) */ return tabu[subSetSum]; }; var getSum = (nums, sum = 0) => { - for (const num of nums) { sum += num };/* Time O(N) */ + for (const num of nums) { + sum += num; + } /* Time O(N) */ return sum; -} +}; var initTabu = (subSetSum) => { - const tabu = new Array((subSetSum + 1)).fill(false);/* Space O(M) */ + const tabu = new Array(subSetSum + 1).fill(false); /* Space O(M) */ - tabu[0] = true; /* Space O(M) */ + tabu[0] = true; /* Space O(M) */ return tabu; -} +}; var search = (nums, subSetSum, tabu) => { - for (const num of nums) {/* Time O(N) */ - update(num, subSetSum, tabu);/* Time O(M) | Space O(M) */ + for (const num of nums) { + /* Time O(N) */ + update(num, subSetSum, tabu); /* Time O(M) | Space O(M) */ } -} +}; var update = (num, subSetSum, tabu) => { - for (let subSet = subSetSum; (num <= subSet); subSet--) {/* Time O(M) */ - const difference = (subSet - num); + for (let subSet = subSetSum; num <= subSet; subSet--) { + /* Time O(M) */ + const difference = subSet - num; - tabu[subSet] |= tabu[difference]; /* Space O(M) */ + tabu[subSet] |= tabu[difference]; /* Space O(M) */ } -} +}; diff --git a/javascript/0417-pacific-atlantic-water-flow.js b/javascript/0417-pacific-atlantic-water-flow.js index 39f5c685b..cd13feba8 100644 --- a/javascript/0417-pacific-atlantic-water-flow.js +++ b/javascript/0417-pacific-atlantic-water-flow.js @@ -4,75 +4,138 @@ * @param {number[][]} heights * @return {number[][]} */ -var pacificAtlantic = function(heights) { - const [ pacificReachable, atlanticReachable ] = search(heights); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ - - return searchGrid(heights, pacificReachable, atlanticReachable);/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ +var pacificAtlantic = function (heights) { + const [pacificReachable, atlanticReachable] = + search(heights); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ + + return searchGrid( + heights, + pacificReachable, + atlanticReachable, + ); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ }; var search = (heights) => { - const [ rows, cols ] = [ heights.length, heights[0].length ]; - const [ pacificReachable, atlanticReachable ] = [ getMatrix(rows, cols), getMatrix(rows, cols) ];/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ + const [rows, cols] = [heights.length, heights[0].length]; + const [pacificReachable, atlanticReachable] = [ + getMatrix(rows, cols), + getMatrix(rows, cols), + ]; /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ searchRows(heights, rows, cols, pacificReachable, atlanticReachable); searchCols(heights, rows, cols, pacificReachable, atlanticReachable); - return [ pacificReachable, atlanticReachable ]; -} + return [pacificReachable, atlanticReachable]; +}; -var getMatrix = (rows, cols) => new Array(rows).fill()/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ - .map(() => new Array(cols).fill(false)); +var getMatrix = (rows, cols) => + new Array(rows) + .fill() /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ + .map(() => new Array(cols).fill(false)); var searchRows = (heights, rows, cols, pacificReachable, atlanticReachable) => { - for (let row = 0; row < rows; row++) {/* Time O(ROWS) */ - const [ pacificStart, atlanticStart ] = [ 0, (cols - 1) ]; - - dfs(row, pacificStart, rows, cols, pacificReachable, heights); /* Space O(ROWS * COLS) */ - dfs(row, atlanticStart, rows, cols, atlanticReachable, heights); /* Space O(ROWS * COLS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + const [pacificStart, atlanticStart] = [0, cols - 1]; + + dfs( + row, + pacificStart, + rows, + cols, + pacificReachable, + heights, + ); /* Space O(ROWS * COLS) */ + dfs( + row, + atlanticStart, + rows, + cols, + atlanticReachable, + heights, + ); /* Space O(ROWS * COLS) */ } -} +}; var searchCols = (heights, rows, cols, pacificReachable, atlanticReachable) => { - for (let col = 0; col < cols; col++) {/* Time O(COLS) */ - const [ pacificStart, atlanticStart ] = [ 0, (rows - 1) ]; - - dfs(pacificStart, col, rows, cols, pacificReachable, heights); /* Space O(ROWS * COLS) */ - dfs(atlanticStart, col, rows, cols, atlanticReachable, heights); /* Space O(ROWS * COLS) */ + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ + const [pacificStart, atlanticStart] = [0, rows - 1]; + + dfs( + pacificStart, + col, + rows, + cols, + pacificReachable, + heights, + ); /* Space O(ROWS * COLS) */ + dfs( + atlanticStart, + col, + rows, + cols, + atlanticReachable, + heights, + ); /* Space O(ROWS * COLS) */ } -} +}; const dfs = (row, col, rows, cols, isReachable, heights) => { isReachable[row][col] = true; - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) { + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { if (isReachable[_row][_col]) continue; const isLower = heights[_row][_col] < heights[row][col]; if (isLower) continue; - - dfs(_row, _col, rows, cols, isReachable, heights); /* Space O(ROWS * COLS) */ + dfs( + _row, + _col, + rows, + cols, + isReachable, + heights, + ); /* Space O(ROWS * COLS) */ } -} - -var searchGrid = (heights, pacificReachable, atlanticReachable, intersection = []) => { - const [ rows, cols ] = [ heights.length, heights[0].length ]; +}; - for (let row = 0; row < rows; row++) {/* Time O(ROWS) */ - for (let col = 0; col < cols; col++) {/* Time O(COLS) */ - const isReachable = pacificReachable[row][col] && atlanticReachable[row][col] - if (!isReachable) continue +var searchGrid = ( + heights, + pacificReachable, + atlanticReachable, + intersection = [], +) => { + const [rows, cols] = [heights.length, heights[0].length]; + + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ + const isReachable = + pacificReachable[row][col] && atlanticReachable[row][col]; + if (!isReachable) continue; - intersection.push([ row, col ]); /* Space O(ROWS * COLS) */ + intersection.push([row, col]); /* Space O(ROWS * COLS) */ } } return intersection; -} +}; -var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ] - .map(([ _row, _col ]) => [ (row + _row), (col + _col)]) - .filter(([ _row, _col ]) => (0 <= _row) && (_row < rows) && (0 <= _col) && (_col < cols)) +var getNeighbors = (row, rows, col, cols) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + .map(([_row, _col]) => [row + _row, col + _col]) + .filter( + ([_row, _col]) => + 0 <= _row && _row < rows && 0 <= _col && _col < cols, + ); /** * https://leetcode.com/problems/pacific-atlantic-water-flow/ @@ -80,84 +143,121 @@ var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ * @param {number[][]} heights * @return {number[][]} */ - var pacificAtlantic = function(heights) { - const [ pacificQueue, atlanticQueue ] = search(heights); /* Time O(ROWS + COLS) | Space O(ROWS + COLS) */ - const [ pacificReachable, atlanticReachable ] = [ bfs(heights, pacificQueue), bfs(heights, atlanticQueue) ];/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ - - return getIntersection(heights, pacificReachable, atlanticReachable); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ -} +var pacificAtlantic = function (heights) { + const [pacificQueue, atlanticQueue] = + search(heights); /* Time O(ROWS + COLS) | Space O(ROWS + COLS) */ + const [pacificReachable, atlanticReachable] = [ + bfs(heights, pacificQueue), + bfs(heights, atlanticQueue), + ]; /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ + + return getIntersection( + heights, + pacificReachable, + atlanticReachable, + ); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ +}; -var search = (heights, pacificQueue = new Queue([]), atlanticQueue = new Queue([])) => { +var search = ( + heights, + pacificQueue = new Queue([]), + atlanticQueue = new Queue([]), +) => { searchRows(heights, pacificQueue, atlanticQueue); searchCols(heights, pacificQueue, atlanticQueue); - return [ pacificQueue, atlanticQueue ] -} + return [pacificQueue, atlanticQueue]; +}; var searchRows = (heights, pacificQueue, atlanticQueue) => { - const [ rows, cols ] = [ heights.length, heights[0].length ]; + const [rows, cols] = [heights.length, heights[0].length]; - for (let row = 0; row < rows; row++) {/* Time O(ROWS) */ - pacificQueue.enqueue([ row, 0 ]); /* Space O(ROWS) */ - atlanticQueue.enqueue([ row, (cols - 1) ]);/* Space O(ROWS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + pacificQueue.enqueue([row, 0]); /* Space O(ROWS) */ + atlanticQueue.enqueue([row, cols - 1]); /* Space O(ROWS) */ } -} +}; var searchCols = (heights, pacificQueue, atlanticQueue) => { - const [ rows, cols ] = [ heights.length, heights[0].length ]; + const [rows, cols] = [heights.length, heights[0].length]; - for (let col = 0; col < cols; col++) {/* Time O(COLS) */ - pacificQueue.enqueue([ 0, col ]); /* Space O(COLS) */ - atlanticQueue.enqueue([ (rows - 1), col ]);/* Space O(COLS) */ + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ + pacificQueue.enqueue([0, col]); /* Space O(COLS) */ + atlanticQueue.enqueue([rows - 1, col]); /* Space O(COLS) */ } -} +}; const bfs = (heights, queue) => { - const [ rows, cols ] = [ heights.length, heights[0].length ]; - const isReachable = getMatrix(rows, cols); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ + const [rows, cols] = [heights.length, heights[0].length]; + const isReachable = getMatrix( + rows, + cols, + ); /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ while (!queue.isEmpty()) { - for (let i = (queue.size() - 1); 0 <= i; i--) {/* | Space O(WIDTH) */ - const [ row, col ] = queue.dequeue(); + for (let i = queue.size() - 1; 0 <= i; i--) { + /* | Space O(WIDTH) */ + const [row, col] = queue.dequeue(); checkNeighbor(heights, row, rows, col, cols, isReachable, queue); } } return isReachable; -} +}; -var getMatrix = (rows, cols) => new Array(rows).fill()/* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ - .map(() => new Array(cols).fill(false)); +var getMatrix = (rows, cols) => + new Array(rows) + .fill() /* Time O(ROWS * COLS) | Space O(ROWS * COLS) */ + .map(() => new Array(cols).fill(false)); var checkNeighbor = (heights, row, rows, col, cols, isReachable, queue) => { isReachable[row][col] = true; - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) { + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { if (isReachable[_row][_col]) continue; const isLower = heights[_row][_col] < heights[row][col]; if (isLower) continue; - queue.enqueue([ _row, _col ]); + queue.enqueue([_row, _col]); } -} - -var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ] - .map(([ _row, _col ]) => [ (row + _row), (col + _col)]) - .filter(([ _row, _col ]) => (0 <= _row) && (_row < rows) && (0 <= _col) && (_col < cols)) - -const getIntersection = (heights, pacificReachable, atlanticReachable, intersection = []) => { - const [ rows, cols ] = [ heights.length, heights[0].length ]; +}; - for (let row = 0; row < rows; row++) {/* Time O(ROWS) */ - for (let col = 0; col < cols; col++) {/* Time O(COLS) */ - const isReachable = pacificReachable[row][col] && atlanticReachable[row][col]; +var getNeighbors = (row, rows, col, cols) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + .map(([_row, _col]) => [row + _row, col + _col]) + .filter( + ([_row, _col]) => + 0 <= _row && _row < rows && 0 <= _col && _col < cols, + ); + +const getIntersection = ( + heights, + pacificReachable, + atlanticReachable, + intersection = [], +) => { + const [rows, cols] = [heights.length, heights[0].length]; + + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ + const isReachable = + pacificReachable[row][col] && atlanticReachable[row][col]; if (!isReachable) continue; - intersection.push([ row, col ]); /* Space O(ROWS * COLS) */ + intersection.push([row, col]); /* Space O(ROWS * COLS) */ } } return intersection; -} \ No newline at end of file +}; diff --git a/javascript/0424-longest-repeating-character-replacement.js b/javascript/0424-longest-repeating-character-replacement.js index c886fb30e..aa597b992 100644 --- a/javascript/0424-longest-repeating-character-replacement.js +++ b/javascript/0424-longest-repeating-character-replacement.js @@ -5,21 +5,21 @@ * @param {number} k * @return {number} */ -var characterReplacement = function(s, k) { +var characterReplacement = function (s, k) { let res = 0; let count = new Map(); let l = 0; for (let r = 0; r < s.length; r++) { - let len = r - l + 1 - count.set(s[r], 1 + (count.get(s[r]) || 0)) + let len = r - l + 1; + count.set(s[r], 1 + (count.get(s[r]) || 0)); - if ((len - Math.max(...count.values())) > k) { - count.set(s[l], count.get(s[l]) - 1) + if (len - Math.max(...count.values()) > k) { + count.set(s[l], count.get(s[l]) - 1); l++; } len = r - l + 1; - res = Math.max(res, len) + res = Math.max(res, len); } return res; diff --git a/javascript/0435-non-overlapping-intervals.js b/javascript/0435-non-overlapping-intervals.js index 21331dfd2..34b9eaef6 100644 --- a/javascript/0435-non-overlapping-intervals.js +++ b/javascript/0435-non-overlapping-intervals.js @@ -6,7 +6,7 @@ */ var eraseOverlapIntervals = function (intervals) { intervals.sort(([aStart, aEnd], [bStart, bEnd]) => - aEnd !== bEnd ? aEnd - bEnd : aStart - bStart + aEnd !== bEnd ? aEnd - bEnd : aStart - bStart, ); return getGaps(intervals); diff --git a/javascript/0441-arranging-coins.js b/javascript/0441-arranging-coins.js index 67875334a..82187a10a 100644 --- a/javascript/0441-arranging-coins.js +++ b/javascript/0441-arranging-coins.js @@ -5,12 +5,11 @@ * @param {number} n * @return {number} */ -var arrangeCoins = function(n) { - +var arrangeCoins = function (n) { let steps = 1; let canBuild = 0; - while(n >= steps) { + while (n >= steps) { n = n - steps; canBuild++; steps++; @@ -25,39 +24,37 @@ var arrangeCoins = function(n) { * @param {number} n * @return {number} */ -var arrangeCoins = function(n) { - +var arrangeCoins = function (n) { let left = 1; let right = n; let result = 0; - - while(left <= right) { - - const mid = Math.floor((right+left)/2); - const total = (1 + mid) * (mid/2); - if(n < total) { - right = mid -1; + + while (left <= right) { + const mid = Math.floor((right + left) / 2); + const total = (1 + mid) * (mid / 2); + if (n < total) { + right = mid - 1; } else { - left = mid+1; + left = mid + 1; result = Math.max(result, mid); } } - + return result; - }; - -/** - * Math +}; + +/** + * Math * Time O(1) | Space O(1) * @param {number} n * @return {number} */ -var arrangeCoins = function(n) { - let discriminant = 1 + 8 * n; - let sqrtDiscriminant = Math.sqrt(discriminant); +var arrangeCoins = function (n) { + let discriminant = 1 + 8 * n; + let sqrtDiscriminant = Math.sqrt(discriminant); - let result1 = Math.floor((-1 + sqrtDiscriminant) / 2); - let result2 = Math.floor((-1 - sqrtDiscriminant) / 2); + let result1 = Math.floor((-1 + sqrtDiscriminant) / 2); + let result2 = Math.floor((-1 - sqrtDiscriminant) / 2); - return Math.max(result1, result2); + return Math.max(result1, result2); }; diff --git a/javascript/0448-find-all-numbers-disappeared-in-an-array.js b/javascript/0448-find-all-numbers-disappeared-in-an-array.js index 83739d63c..0a9a3c9dd 100644 --- a/javascript/0448-find-all-numbers-disappeared-in-an-array.js +++ b/javascript/0448-find-all-numbers-disappeared-in-an-array.js @@ -1,16 +1,15 @@ // problem link https://leetcode.com/problems/find-all-numbers-disappeared-in-an-array // time complexity O(n) -var findDisappearedNumbers = function(nums) { - +var findDisappearedNumbers = function (nums) { const numberSet = new Set(); - for(let i = 1; i < nums.length + 1; i++) { + for (let i = 1; i < nums.length + 1; i++) { numberSet.add(i); } nums.forEach((element) => { - if(numberSet.has(element)) { + if (numberSet.has(element)) { numberSet.delete(element); } }); @@ -22,21 +21,21 @@ var findDisappearedNumbers = function(nums) { //time complexity O(n) , space complexity O(1) -var findDisappearedNumbers = function(nums) { - for(let i = 0; i < nums.length; i++) { - let curr = Math.abs(nums[i]) - let idx = curr - 1 - if(nums[idx] > 0) { - nums[idx] = nums[idx] * (-1) +var findDisappearedNumbers = function (nums) { + for (let i = 0; i < nums.length; i++) { + let curr = Math.abs(nums[i]); + let idx = curr - 1; + if (nums[idx] > 0) { + nums[idx] = nums[idx] * -1; } } - let res = [] - for(let i = 0; i < nums.length; i++) { - if(nums[i] > 0) { - res.push(i + 1) + let res = []; + for (let i = 0; i < nums.length; i++) { + if (nums[i] > 0) { + res.push(i + 1); } } - return res + return res; }; // For each value in the array mark its presence by making the number negative at that place in array diff --git a/javascript/0450-delete-node-in-a-bst.js b/javascript/0450-delete-node-in-a-bst.js index 8e2d7bb85..1d0a487c0 100644 --- a/javascript/0450-delete-node-in-a-bst.js +++ b/javascript/0450-delete-node-in-a-bst.js @@ -14,7 +14,7 @@ * @param {number} key * @return {TreeNode} */ -var deleteNode = function(root, key) { +var deleteNode = function (root, key) { if (!root) return root; if (key === root.val) { @@ -32,7 +32,7 @@ var deleteNode = function(root, key) { root.right = deleteNode(root.right, root.val); return root; - } + } if (key < root.val) { root.left = deleteNode(root.left, key); return root; diff --git a/javascript/0460-lfu-cache.js b/javascript/0460-lfu-cache.js index 9219ce187..ab0817c10 100644 --- a/javascript/0460-lfu-cache.js +++ b/javascript/0460-lfu-cache.js @@ -1,121 +1,124 @@ // https://leetcode.com/problems/lfu-cache/ class ListNode { - constructor(val, next, prev) { - this.val = (val===undefined ? 0 : val) - this.next = (next===undefined ? null : next) - this.prev = (next===undefined ? null : prev) - } + constructor(val, next, prev) { + this.val = val === undefined ? 0 : val; + this.next = next === undefined ? null : next; + this.prev = next === undefined ? null : prev; + } } class LinkedList { - constructor() { - this.map = new Map() - this.Right = new ListNode(null) - this.Left = new ListNode(null, this.Right) - this.Right.prev = this.Left - } + constructor() { + this.map = new Map(); + this.Right = new ListNode(null); + this.Left = new ListNode(null, this.Right); + this.Right.prev = this.Left; + } - len() { - return this.map.size - } + len() { + return this.map.size; + } - pop(val) { - if (this.map.has(val)) { - let node = this.map.get(val) + pop(val) { + if (this.map.has(val)) { + let node = this.map.get(val); - // save - let prevNode = node.prev - // delete - prevNode.next = node.next - prevNode.next.prev = prevNode - this.map.delete(val) + // save + let prevNode = node.prev; + // delete + prevNode.next = node.next; + prevNode.next.prev = prevNode; + this.map.delete(val); + } } - } - popleft() { - let data = this.Left.next.val - this.Left.next = this.Left.next.next - this.Left.next.prev = this.Left - this.map.delete(data) - return data - } + popleft() { + let data = this.Left.next.val; + this.Left.next = this.Left.next.next; + this.Left.next.prev = this.Left; + this.map.delete(data); + return data; + } - pushRight(val) { - let newNode = new ListNode(val, this.Right) - newNode.prev = this.Right.prev - newNode.prev.next = newNode - this.Right.prev = newNode - this.map.set(val, newNode) - } + pushRight(val) { + let newNode = new ListNode(val, this.Right); + newNode.prev = this.Right.prev; + newNode.prev.next = newNode; + this.Right.prev = newNode; + this.map.set(val, newNode); + } - update(val) { - this.pop(val) - this.pushRight(val) - } + update(val) { + this.pop(val); + this.pushRight(val); + } } /** * @param {number} capacity */ -var LFUCache = function(capacity) { - this.capacity = capacity - this.valueMap = new Map() - this.countMap = new Map() - this.lftCount = 1 - this.lists = [] - this.counter = (key) => { - let count = this.countMap.get(key) || 0 - if (this.lists[count]) { - this.lists[count].pop(key) - } - if (!this.lists[count + 1]) { - this.lists[count + 1] = new LinkedList() - } - this.lists[count + 1].pushRight(key) - this.countMap.set(key, count + 1) - // console.log(this.lftCount == count, count, this.lists[count].len()) - if (this.lftCount == count && this.lists[count] && this.lists[count].len() === 0) { - this.lftCount++ - } - } +var LFUCache = function (capacity) { + this.capacity = capacity; + this.valueMap = new Map(); + this.countMap = new Map(); + this.lftCount = 1; + this.lists = []; + this.counter = (key) => { + let count = this.countMap.get(key) || 0; + if (this.lists[count]) { + this.lists[count].pop(key); + } + if (!this.lists[count + 1]) { + this.lists[count + 1] = new LinkedList(); + } + this.lists[count + 1].pushRight(key); + this.countMap.set(key, count + 1); + // console.log(this.lftCount == count, count, this.lists[count].len()) + if ( + this.lftCount == count && + this.lists[count] && + this.lists[count].len() === 0 + ) { + this.lftCount++; + } + }; }; -/** +/** * @param {number} key * @return {number} */ -LFUCache.prototype.get = function(key) { - if (!this.valueMap.has(key)) { - return -1 - } - - this.counter(key) - return this.valueMap.get(key) +LFUCache.prototype.get = function (key) { + if (!this.valueMap.has(key)) { + return -1; + } + + this.counter(key); + return this.valueMap.get(key); }; -/** - * @param {number} key +/** + * @param {number} key * @param {number} value * @return {void} */ -LFUCache.prototype.put = function(key, value) { - - if (!this.valueMap.has(key) && this.valueMap.size == this.capacity) { - // we need to evict - // console.log(this.lists[this.lftCount]) - let evictedKey = this.lists[this.lftCount].popleft() - this.valueMap.delete(evictedKey) - this.countMap.delete(evictedKey) - } +LFUCache.prototype.put = function (key, value) { + if (!this.valueMap.has(key) && this.valueMap.size == this.capacity) { + // we need to evict + // console.log(this.lists[this.lftCount]) + let evictedKey = this.lists[this.lftCount].popleft(); + this.valueMap.delete(evictedKey); + this.countMap.delete(evictedKey); + } - this.valueMap.set(key, value) - this.counter(key) - this.lftCount = Math.min(this.countMap.get(key), this.lftCount) + this.valueMap.set(key, value); + this.counter(key); + this.lftCount = Math.min(this.countMap.get(key), this.lftCount); }; -/** +/** * Your LFUCache object will be instantiated and called as such: * var obj = new LFUCache(capacity) * var param_1 = obj.get(key) * obj.put(key,value) - */ \ No newline at end of file + */ diff --git a/javascript/0463-island-perimeter.js b/javascript/0463-island-perimeter.js index 55ddb839e..85d85fd98 100644 --- a/javascript/0463-island-perimeter.js +++ b/javascript/0463-island-perimeter.js @@ -1,13 +1,18 @@ -var islandPerimeter = function(grid) { +var islandPerimeter = function (grid) { const visit = new Set(); - - const dfs = function(i, j) { - if(i >= grid.length || j >= grid[0].length || i < 0 || j < 0 || grid[i][j] == 0) + + const dfs = function (i, j) { + if ( + i >= grid.length || + j >= grid[0].length || + i < 0 || + j < 0 || + grid[i][j] == 0 + ) return 1; - let flatCoord = i*grid[0].length + j; - if(visit.has(flatCoord)) - return 0; - + let flatCoord = i * grid[0].length + j; + if (visit.has(flatCoord)) return 0; + visit.add(flatCoord); let perim = dfs(i, j + 1); perim += dfs(i + 1, j); @@ -15,9 +20,8 @@ var islandPerimeter = function(grid) { perim += dfs(i - 1, j); return perim; }; - - for(let i = 0; i < grid.length; i++) - for(let j = 0; j < grid[0].length; j++) - if(grid[i][j]) - return dfs(i, j); + + for (let i = 0; i < grid.length; i++) + for (let j = 0; j < grid[0].length; j++) + if (grid[i][j]) return dfs(i, j); }; diff --git a/javascript/0494-target-sum.js b/javascript/0494-target-sum.js index 7df390be9..cccde095b 100644 --- a/javascript/0494-target-sum.js +++ b/javascript/0494-target-sum.js @@ -6,24 +6,34 @@ * @param {number} target * @return {number} */ - var findTargetSumWays = (nums, target, index = 0, sum = 0) => { - const isBaseCase = (index === nums.length); +var findTargetSumWays = (nums, target, index = 0, sum = 0) => { + const isBaseCase = index === nums.length; if (isBaseCase) { - const isTarget = (sum === target); + const isTarget = sum === target; if (isTarget) return 1; return 0; } - return dfs(nums, target, index, sum);/* Time O(2^N) | Space O(HEIGHT) */ -} + return dfs(nums, target, index, sum); /* Time O(2^N) | Space O(HEIGHT) */ +}; var dfs = (nums, target, index, sum) => { - const left = findTargetSumWays(nums, target, (index + 1), (sum + nums[index])); /* Time O(2^N) | Space O(HEIGHT) */ - const right = findTargetSumWays(nums, target, (index + 1), (sum - nums[index]));/* Time O(2^N) | Space O(HEIGHT) */ - - return (left + right); -} + const left = findTargetSumWays( + nums, + target, + index + 1, + sum + nums[index], + ); /* Time O(2^N) | Space O(HEIGHT) */ + const right = findTargetSumWays( + nums, + target, + index + 1, + sum - nums[index], + ); /* Time O(2^N) | Space O(HEIGHT) */ + + return left + right; +}; /** * DP - Top Down @@ -35,36 +45,73 @@ var dfs = (nums, target, index, sum) => { * @return {number} */ var findTargetSumWays = (nums, target) => { - const total = nums.reduce((sum, num) => (sum + num), 0);/* Time O(N) */ - - return calculate(nums, target, total); /* Time O(N * M) | Space O((N * M) + HEIGHT) */ -} + const total = nums.reduce((sum, num) => sum + num, 0); /* Time O(N) */ -var initMemo = (nums, total) => new Array(nums.length).fill()/* Time O(N) | Space O(N) */ - .map(() => new Array(((total + 1) << 1)).fill(null)); /* Time O(M) | Space O(M) */ + return calculate( + nums, + target, + total, + ); /* Time O(N * M) | Space O((N * M) + HEIGHT) */ +}; -const calculate = (nums, target, total, index = 0, sum = 0, memo = initMemo(nums, total)) => { - const isBaseCase = (index === nums.length); +var initMemo = (nums, total) => + new Array(nums.length) + .fill() /* Time O(N) | Space O(N) */ + .map(() => + new Array((total + 1) << 1).fill(null), + ); /* Time O(M) | Space O(M) */ + +const calculate = ( + nums, + target, + total, + index = 0, + sum = 0, + memo = initMemo(nums, total), +) => { + const isBaseCase = index === nums.length; if (isBaseCase) { - const isTarget = (sum === target); + const isTarget = sum === target; if (isTarget) return 1; return 0; } - const hasSeen = (memo[index][(sum + total)] != null); - if (hasSeen) return memo[index][(sum + total)]; - - return dfs(nums, target, total, index, sum, memo);/* Time O(N * M) | Space O((N * M) + HEIGHT) */ -} + const hasSeen = memo[index][sum + total] != null; + if (hasSeen) return memo[index][sum + total]; + + return dfs( + nums, + target, + total, + index, + sum, + memo, + ); /* Time O(N * M) | Space O((N * M) + HEIGHT) */ +}; var dfs = (nums, target, total, index, sum, memo) => { - const left = calculate(nums, target, total, (index + 1), (sum + nums[index]), memo); /* Time O(N * M) | Space O(HEIGHT) */ - const right = calculate(nums, target, total, (index + 1), (sum - nums[index]), memo);/* Time O(N * M) | Space O(HEIGHT) */ - - memo[index][(sum + total)] = (left + right); /* | Space O(N * M) */ - return memo[index][(sum + total)]; -} + const left = calculate( + nums, + target, + total, + index + 1, + sum + nums[index], + memo, + ); /* Time O(N * M) | Space O(HEIGHT) */ + const right = calculate( + nums, + target, + total, + index + 1, + sum - nums[index], + memo, + ); /* Time O(N * M) | Space O(HEIGHT) */ + + memo[index][sum + total] = + left + right; /* | Space O(N * M) */ + return memo[index][sum + total]; +}; /** * DP - Bottom Up @@ -76,42 +123,47 @@ var dfs = (nums, target, total, index, sum, memo) => { * @return {number} */ var findTargetSumWays = (nums, target) => { - const total = nums.reduce((sum, num) => (sum + num), 0);/* Time O(N) */ - const tabu = initTabu(nums, total); /* Time O(N * M) | Space O(N * M) */ + const total = nums.reduce((sum, num) => sum + num, 0); /* Time O(N) */ + const tabu = initTabu(nums, total); /* Time O(N * M) | Space O(N * M) */ - search(nums, total, tabu); /* Time O(N * M) | Space O(N * M) */ + search(nums, total, tabu); /* Time O(N * M) | Space O(N * M) */ - return (Math.abs(target) <= total) - ? tabu[(nums.length - 1)][(target + total)] + return Math.abs(target) <= total + ? tabu[nums.length - 1][target + total] : 0; }; var initTabu = (nums, total) => { - const tabu = new Array(nums.length).fill() /* Time O(N) | Space O(N) */ - .map(() => new Array(((total + 1) << 1)).fill(0));/* Time O(M) | Space O(M) */ - const [ left, right ] = [ (total + nums[0]), (total - nums[0]) ]; + const tabu = new Array(nums.length) + .fill() /* Time O(N) | Space O(N) */ + .map(() => + new Array((total + 1) << 1).fill(0), + ); /* Time O(M) | Space O(M) */ + const [left, right] = [total + nums[0], total - nums[0]]; - tabu[0][left] = 1; /* | Space O(N * M) */ - tabu[0][right] += 1; /* | Space O(N * M) */ + tabu[0][left] = 1; /* | Space O(N * M) */ + tabu[0][right] += 1; /* | Space O(N * M) */ return tabu; -} +}; var search = (nums, total, tabu) => { - for (let i = 1; (i < nums.length); i++) {/* Time O(N) */ - for (let sum = (-total); (sum <= total); sum++) {/* Time O(M) */ - const isInvalid = (tabu[(i - 1)][(sum + total)] <= 0); + for (let i = 1; i < nums.length; i++) { + /* Time O(N) */ + for (let sum = -total; sum <= total; sum++) { + /* Time O(M) */ + const isInvalid = tabu[i - 1][sum + total] <= 0; if (isInvalid) continue; - const dpSum = tabu[(i - 1)][sum + total]; - const left = ((sum + nums[i]) + total); - const right = ((sum - nums[i]) + total); + const dpSum = tabu[i - 1][sum + total]; + const left = sum + nums[i] + total; + const right = sum - nums[i] + total; - tabu[i][left] += dpSum; /* Space O(N * M) */ - tabu[i][right] += dpSum; /* Space O(N * M) */ + tabu[i][left] += dpSum; /* Space O(N * M) */ + tabu[i][right] += dpSum; /* Space O(N * M) */ } } -} +}; /** * DP - Top Down @@ -123,51 +175,52 @@ var search = (nums, total, tabu) => { * @return {number} */ var findTargetSumWays = (nums, target) => { - const total = nums.reduce((sum, num) => (sum + num), 0);/* Time O(N) */ - let tabu = getTabu(nums, total); /* Time O(M) | Space O(M) */ + const total = nums.reduce((sum, num) => sum + num, 0); /* Time O(N) */ + let tabu = getTabu(nums, total); /* Time O(M) | Space O(M) */ - tabu = search(nums, total, tabu); /* Time O(N * M) | Space O(M) */ + tabu = search(nums, total, tabu); /* Time O(N * M) | Space O(M) */ - return (Math.abs(target) <= total) - ? tabu[(target + total)] - : 0 -} + return Math.abs(target) <= total ? tabu[target + total] : 0; +}; -var initTabu = (total) => new Array((total + 1) << 1).fill(0);/* Time O(M) | Space O(M) */ +var initTabu = (total) => + new Array((total + 1) << 1).fill(0); /* Time O(M) | Space O(M) */ var getTabu = (nums, total) => { - const tabu = initTabu(total);/* Time O(M) | Space O(M) */ - const [ left, right ] = [ (total + nums[0]), (total - nums[0]) ]; + const tabu = initTabu(total); /* Time O(M) | Space O(M) */ + const [left, right] = [total + nums[0], total - nums[0]]; - tabu[left] = 1; /* | Space O(M) */ - tabu[right] += 1; /* | Space O(M) */ + tabu[left] = 1; /* | Space O(M) */ + tabu[right] += 1; /* | Space O(M) */ return tabu; -} +}; var search = (nums, total, tabu) => { - for (let i = 1; (i < nums.length); i++) { /* Time O(N) */ + for (let i = 1; i < nums.length; i++) { + /* Time O(N) */ const num = nums[i]; - const temp = initTabu(total); /* Time O(M) | Space O(M) */ + const temp = initTabu(total); /* Time O(M) | Space O(M) */ - tabu = update(num, total, tabu, temp); /* Time O(M) | Space O(M) */ + tabu = update(num, total, tabu, temp); /* Time O(M) | Space O(M) */ } return tabu; -} +}; var update = (num, total, tabu, temp) => { - for (let sum = (-total); (sum <= total); sum++) {/* Time O(M) */ - const isInvalid = (tabu[sum + total] <= 0); + for (let sum = -total; sum <= total; sum++) { + /* Time O(M) */ + const isInvalid = tabu[sum + total] <= 0; if (isInvalid) continue; const dpSum = tabu[sum + total]; - const left = ((sum + num) + total); - const right = ((sum - num) + total); + const left = sum + num + total; + const right = sum - num + total; - temp[left] += dpSum; /* Space O(M) */ - temp[right] += dpSum; /* Space O(M) */ + temp[left] += dpSum; /* Space O(M) */ + temp[right] += dpSum; /* Space O(M) */ } return temp; -} \ No newline at end of file +}; diff --git a/javascript/0496-next-greater-element-i.js b/javascript/0496-next-greater-element-i.js index 7e973b6f8..036889d83 100644 --- a/javascript/0496-next-greater-element-i.js +++ b/javascript/0496-next-greater-element-i.js @@ -8,20 +8,20 @@ */ var nextGreaterElement = function (nums1, nums2) { - const subsetMap = new Map(nums1.map((val, i) => [val, i])); - const res = new Array(nums1.length).fill(-1); + const subsetMap = new Map(nums1.map((val, i) => [val, i])); + const res = new Array(nums1.length).fill(-1); - let stack = []; + let stack = []; - for (let num of nums2) { - while (stack.length && num > stack.at(-1)) { - const val = stack.pop(); - const idx = subsetMap.get(val); - res[idx] = num; - } + for (let num of nums2) { + while (stack.length && num > stack.at(-1)) { + const val = stack.pop(); + const idx = subsetMap.get(val); + res[idx] = num; + } - if (subsetMap.has(num)) stack.push(num); - } + if (subsetMap.has(num)) stack.push(num); + } - return res; + return res; }; diff --git a/javascript/0502-ipo.js b/javascript/0502-ipo.js index ce1bec72d..bcb1651c9 100644 --- a/javascript/0502-ipo.js +++ b/javascript/0502-ipo.js @@ -1,5 +1,5 @@ /** - * MaxPriorityQueue | Sorting + * MaxPriorityQueue | Sorting * Time O(n*log(n)) | Space O(n) * https://leetcode.com/problems/ipo/description/ * @param {number} k @@ -8,44 +8,41 @@ * @param {number[]} capital * @return {number} */ -var findMaximizedCapital = function(k, w, profits, capital) { - - const maxQueue = new MaxPriorityQueue({ - compare: (a, b) => { - return b[0] - a[0]; +var findMaximizedCapital = function (k, w, profits, capital) { + const maxQueue = new MaxPriorityQueue({ + compare: (a, b) => { + return b[0] - a[0]; + }, + }); + + const minQueue = new MinPriorityQueue({ + compare: (a, b) => { + return a[0] - b[0]; + }, + }); + + const pc = profits.map((profit, idx) => { + return [profit, capital[idx]]; + }); + + for (let i = 0; i < pc.length; i++) { + minQueue.enqueue([pc[i][1], pc[i][0]]); } - }); - const minQueue = new MinPriorityQueue({ - compare: (a, b) => { - return a[0] - b[0]; - } - }); - - const pc = profits.map((profit, idx) => { - return [profit, capital[idx]]; - }); + let cc = w; + while (k && (!maxQueue.isEmpty() || !minQueue.isEmpty())) { + // add all the project that we can take to maxQ + while (!minQueue.isEmpty() && cc >= minQueue.front()[0]) { + const curr = minQueue.dequeue(); + maxQueue.enqueue([curr[1], curr[0]]); + } - for (let i = 0; i < pc.length; i++) { - minQueue.enqueue([pc[i][1], pc[i][0]]); - } + if (!maxQueue.isEmpty()) { + cc += maxQueue.dequeue()[0]; + } - let cc = w; - while (k && (!maxQueue.isEmpty() || !minQueue.isEmpty())) { - - // add all the project that we can take to maxQ - while (!minQueue.isEmpty() && cc >= minQueue.front()[0]) { - const curr = minQueue.dequeue(); - maxQueue.enqueue([curr[1], curr[0]]); + k--; } - if (!maxQueue.isEmpty()) { - cc += maxQueue.dequeue()[0]; - } - - k--; - } - - return cc; + return cc; }; - diff --git a/javascript/0513-find-bottom-left-tree-value.js b/javascript/0513-find-bottom-left-tree-value.js index ec69d129c..55c01c295 100644 --- a/javascript/0513-find-bottom-left-tree-value.js +++ b/javascript/0513-find-bottom-left-tree-value.js @@ -13,23 +13,22 @@ * @param {TreeNode} root * @return {number} */ -var findBottomLeftValue = function(root) { - +var findBottomLeftValue = function (root) { let leftVal = 0; let deepestLevel = -Infinity; - const dfs = (node, level) => { - if(!node.left && !node.right) { - if(level > deepestLevel) { + const dfs = (node, level) => { + if (!node.left && !node.right) { + if (level > deepestLevel) { leftVal = node.val; deepestLevel = level; - } + } return; } - node.left && dfs(node.left, level + 1); + node.left && dfs(node.left, level + 1); node.right && dfs(node.right, level + 1); - } + }; dfs(root, 0); return leftVal; diff --git a/javascript/0515-find-largest-value-in-each-tree-row.js b/javascript/0515-find-largest-value-in-each-tree-row.js index 36ba63755..bf5360fc9 100644 --- a/javascript/0515-find-largest-value-in-each-tree-row.js +++ b/javascript/0515-find-largest-value-in-each-tree-row.js @@ -8,13 +8,12 @@ */ /** * BFS | Level order traversal - * Time O(n) | Space O(n) + * Time O(n) | Space O(n) * https://leetcode.com/problems/find-largest-value-in-each-tree-row/ * @param {TreeNode} root * @return {number[]} */ -var largestValues = function(root) { - +var largestValues = function (root) { if (!root) return []; const result = []; @@ -34,7 +33,7 @@ var largestValues = function(root) { } result.push(max); } - } + }; bfs(root); return result; diff --git a/javascript/0518-coin-change-ii.js b/javascript/0518-coin-change-ii.js index 3945176da..a30e9ee78 100644 --- a/javascript/0518-coin-change-ii.js +++ b/javascript/0518-coin-change-ii.js @@ -5,25 +5,30 @@ * @param {number[]} coins * @return {number} */ - var change = (amount, coins, n = (coins.length)) => { - const isBaseCase1 = (amount === 0); +var change = (amount, coins, n = coins.length) => { + const isBaseCase1 = amount === 0; if (isBaseCase1) return 1; - const isBaseCase2 = (n === 0); + const isBaseCase2 = n === 0; if (isBaseCase2) return 0; - return dfs(amount, coins, n);/* Time O(2^N) | Space O(N) */ -} + return dfs(amount, coins, n); /* Time O(2^N) | Space O(N) */ +}; var dfs = (amount, coins, n) => { - const isLess = (amount < coins[(n - 1)]); - if (isLess) return change(amount, coins, (n - 1)); /* Time O(2^N) | Space O(N) */ - - const left = change((amount - coins[(n - 1)]), coins, n);/* Time O(2^N) | Space O(N) */ - const right = change(amount, coins, (n - 1)); /* Time O(2^N) | Space O(N) */ - - return (left + right); -} + const isLess = amount < coins[n - 1]; + if (isLess) + return change(amount, coins, n - 1); /* Time O(2^N) | Space O(N) */ + + const left = change( + amount - coins[n - 1], + coins, + n, + ); /* Time O(2^N) | Space O(N) */ + const right = change(amount, coins, n - 1); /* Time O(2^N) | Space O(N) */ + + return left + right; +}; /** * DP - Top Down @@ -34,35 +39,63 @@ var dfs = (amount, coins, n) => { * @param {number[]} coins * @return {number} */ -var change = (amount, coins, n = (coins.length), memo = initMemo(coins, amount)) => { - const isBaseCase1 = (n === 0); +var change = ( + amount, + coins, + n = coins.length, + memo = initMemo(coins, amount), +) => { + const isBaseCase1 = n === 0; if (isBaseCase1) return 0; - const isBaseCase2 = (amount === 0); + const isBaseCase2 = amount === 0; if (isBaseCase2) return 1; - const hasSeen = (memo[n][amount] !== null); + const hasSeen = memo[n][amount] !== null; if (hasSeen) return memo[n][amount]; - return dfs(amount, coins, n, memo);/* Time O(N * AMOUNT) | Space O((N * AMOUNT) + HEIGHT) */ -} + return dfs( + amount, + coins, + n, + memo, + ); /* Time O(N * AMOUNT) | Space O((N * AMOUNT) + HEIGHT) */ +}; -var initMemo = (coins, amount) => new Array(coins.length + 2).fill() - .map(() => new Array(amount + 2).fill(null)); +var initMemo = (coins, amount) => + new Array(coins.length + 2) + .fill() + .map(() => new Array(amount + 2).fill(null)); var dfs = (amount, coins, n, memo) => { - const isLess = (amount < coins[(n - 1)]); + const isLess = amount < coins[n - 1]; if (isLess) { - memo[n][amount] = change(amount, coins, (n - 1), memo); /* Time O(N * AMOUNT) | Space O(HEIGHT) */ + memo[n][amount] = change( + amount, + coins, + n - 1, + memo, + ); /* Time O(N * AMOUNT) | Space O(HEIGHT) */ return memo[n][amount]; } - const left = change((amount - coins[(n - 1)]), coins, n, memo);/* Time O(N * AMOUNT) | Space O(HEIGHT) */ - const right = change(amount, coins, (n - 1), memo); /* Time O(N * AMOUNT) | Space O(HEIGHT) */ - - memo[n][amount] = (left + right); /* | Space O(N * AMOUNT) */ + const left = change( + amount - coins[n - 1], + coins, + n, + memo, + ); /* Time O(N * AMOUNT) | Space O(HEIGHT) */ + const right = change( + amount, + coins, + n - 1, + memo, + ); /* Time O(N * AMOUNT) | Space O(HEIGHT) */ + + memo[n][amount] = + left + right; /* | Space O(N * AMOUNT) */ return memo[n][amount]; -} +}; /** * DP - Bottom Up @@ -70,38 +103,46 @@ var dfs = (amount, coins, n, memo) => { * Time O(N * AMOUNT) | Space O(N * AMOUNT) * https://leetcode.com/problems/coin-change-ii/ */ - var change = (amount, coins) => { - const tabu = initTabu(amount, coins);/* Time O(N * AMOUNT) | Space O(N * AMOUNT) */ +var change = (amount, coins) => { + const tabu = initTabu( + amount, + coins, + ); /* Time O(N * AMOUNT) | Space O(N * AMOUNT) */ - search(amount, coins, tabu); /* Time O(N * AMOUNT) | Space O(N * AMOUNT) */ + search(amount, coins, tabu); /* Time O(N * AMOUNT) | Space O(N * AMOUNT) */ return tabu[coins.length][amount]; -} +}; var initTabu = (amount, coins) => { - const tabu = new Array((coins.length + 1)).fill()/* Time O(N) | Space O(N) */ - .map(() => new Array((amount + 1)).fill(0)); /* Time O(AMOUNT) | Space O(AMOUNT) */ + const tabu = new Array(coins.length + 1) + .fill() /* Time O(N) | Space O(N) */ + .map(() => + new Array(amount + 1).fill(0), + ); /* Time O(AMOUNT) | Space O(AMOUNT) */ - tabu[0][0] = 1; /* | Space O(N * AMOUNT) */ + tabu[0][0] = 1; /* | Space O(N * AMOUNT) */ return tabu; -} +}; var search = (amount, coins, tabu) => { - for (let coin = 1; coin <= coins.length; coin++) { /* Time O(N)*/ - tabu[coin][0] = 1; /* Space O(N * AMOUNT) */ + for (let coin = 1; coin <= coins.length; coin++) { + /* Time O(N)*/ + tabu[coin][0] = 1; /* Space O(N * AMOUNT) */ - for (let _amount = 1; _amount <= amount; _amount++) {/* Time O(AMOUNT) */ + for (let _amount = 1; _amount <= amount; _amount++) { + /* Time O(AMOUNT) */ tabu[coin][_amount] = tabu[coin - 1][_amount]; - const canUpdate = (0 <= (_amount - coins[(coin - 1)])); + const canUpdate = 0 <= _amount - coins[coin - 1]; if (!canUpdate) continue; - const val = tabu[coin][(_amount - coins[(coin - 1)])]; - tabu[coin][_amount] += val /* Space O(N * AMOUNT) */ + const val = tabu[coin][_amount - coins[coin - 1]]; + tabu[coin][_amount] += val; /* Space O(N * AMOUNT) */ } } -} +}; /** * DP - Bottom Up @@ -121,20 +162,20 @@ var change = (amount, coins) => { }; var initTabu = (amount) => { - var tabu = new Array((amount + 1)).fill(0); + var tabu = new Array(amount + 1).fill(0); tabu[0] = 1; return tabu; -} +}; var search = (amount, coins, tabu) => { for (const coin of coins) { - for (let _amount = 0; (_amount < (amount + 1)); _amount++) { - const canUpdate = (coin <= _amount); + for (let _amount = 0; _amount < amount + 1; _amount++) { + const canUpdate = coin <= _amount; if (!canUpdate) continue; - tabu[_amount] += tabu[(_amount - coin)]; + tabu[_amount] += tabu[_amount - coin]; } } -} +}; diff --git a/javascript/0523-continuous-subarray-sum.js b/javascript/0523-continuous-subarray-sum.js index 107151223..39f078fe4 100644 --- a/javascript/0523-continuous-subarray-sum.js +++ b/javascript/0523-continuous-subarray-sum.js @@ -6,19 +6,19 @@ * @param {number} k * @return {boolean} */ -var checkSubarraySum = function(arr, k) { +var checkSubarraySum = function (arr, k) { let sum = 0; - const remainderMap = new Map([ [0, -1] ]); - - for(let i = 0; i < arr.length; i++) { + const remainderMap = new Map([[0, -1]]); + + for (let i = 0; i < arr.length; i++) { sum += arr[i]; - if(remainderMap.has(sum%k) && i - remainderMap.get(sum%k) > 1) { + if (remainderMap.has(sum % k) && i - remainderMap.get(sum % k) > 1) { return true; - } - if(!remainderMap.has(sum%k)) { - remainderMap.set(sum%k,i); - } + } + if (!remainderMap.has(sum % k)) { + remainderMap.set(sum % k, i); + } } - + return false; - }; +}; diff --git a/javascript/0535-encode-and-decode-tinyurl.js b/javascript/0535-encode-and-decode-tinyurl.js index e08802891..ee166968f 100644 --- a/javascript/0535-encode-and-decode-tinyurl.js +++ b/javascript/0535-encode-and-decode-tinyurl.js @@ -5,16 +5,16 @@ const encodeMap = new Map(); const decodeMap = new Map(); const base = 'http://tinyurl.com/'; -var encode = function(longUrl) { - let shortUrl = '' - if(!encodeMap.has(longUrl)) { - shortUrl = base + encodeMap.size + 1 - encodeMap.set(longUrl, shortUrl); - decodeMap.set(shortUrl, longUrl); - } - return shortUrl || encodeMap.get(longUrl); +var encode = function (longUrl) { + let shortUrl = ''; + if (!encodeMap.has(longUrl)) { + shortUrl = base + encodeMap.size + 1; + encodeMap.set(longUrl, shortUrl); + decodeMap.set(shortUrl, longUrl); + } + return shortUrl || encodeMap.get(longUrl); }; -var decode = function(shortUrl) { +var decode = function (shortUrl) { return decodeMap.get(shortUrl); }; diff --git a/javascript/0538-convert-bst-to-greater-tree.js b/javascript/0538-convert-bst-to-greater-tree.js index e74e2e528..60eb1167d 100644 --- a/javascript/0538-convert-bst-to-greater-tree.js +++ b/javascript/0538-convert-bst-to-greater-tree.js @@ -7,21 +7,20 @@ * } */ /** - * Tree | reverse pre-order-traversal + * Tree | reverse pre-order-traversal * Time O(n) | Space O(n) * @param {TreeNode} root * @return {TreeNode} */ -var convertBST = function(root) { - - const dfs = (node, max) => { - if(!node) return max; +var convertBST = function (root) { + const dfs = (node, max) => { + if (!node) return max; const result = dfs(node.right, max); node.val = result + node.val; const result1 = dfs(node.left, node.val); return result1; - } + }; dfs(root, 0); return root; diff --git a/javascript/0543-diameter-of-binary-tree.js b/javascript/0543-diameter-of-binary-tree.js index 092d52b01..2e3c6859b 100644 --- a/javascript/0543-diameter-of-binary-tree.js +++ b/javascript/0543-diameter-of-binary-tree.js @@ -4,7 +4,7 @@ * @param {TreeNode} root * @return {number} */ -var diameterOfBinaryTree = function(root, max = [0]) { +var diameterOfBinaryTree = function (root, max = [0]) { diameterOfTree(root, max); return max[0]; @@ -15,7 +15,7 @@ const diameterOfTree = (root, max) => { if (isBaseCase) return 0; return dfs(root, max); -} +}; const dfs = (root, max) => { const left = diameterOfTree(root.left, max); @@ -27,4 +27,4 @@ const dfs = (root, max) => { const height = Math.max(left, right); return height + 1; -} \ No newline at end of file +}; diff --git a/javascript/0554-brick-wall.js b/javascript/0554-brick-wall.js index 8e2276252..8d0a495b2 100644 --- a/javascript/0554-brick-wall.js +++ b/javascript/0554-brick-wall.js @@ -2,29 +2,30 @@ // time coplexity O(n^2) or the number of bricks we have in our input. // space complexity: whatever the length of the rows happend to be. -var leastBricks = function(wall) { - - const myHash = new Map(); +var leastBricks = function (wall) { + const myHash = new Map(); - const width = wall[0].reduce((pre, brick) => { - return brick + pre; - }, 0); + const width = wall[0].reduce((pre, brick) => { + return brick + pre; + }, 0); - for(let i = 0; i < wall.length; i++) { - let currentWidth = 0; - for(let j = 0; j < wall[i].length; j++) { - currentWidth += wall[i][j]; - myHash.has(currentWidth) ? myHash.set(currentWidth,myHash.get(currentWidth)+1) : myHash.set(currentWidth, 1); - } - } + for (let i = 0; i < wall.length; i++) { + let currentWidth = 0; + for (let j = 0; j < wall[i].length; j++) { + currentWidth += wall[i][j]; + myHash.has(currentWidth) + ? myHash.set(currentWidth, myHash.get(currentWidth) + 1) + : myHash.set(currentWidth, 1); + } + } -// deleteing total width as this will be the rightmost gap which will always give us false positive. -myHash.delete(width); + // deleteing total width as this will be the rightmost gap which will always give us false positive. + myHash.delete(width); -maxGap = 0; - for([key, value] of myHash) { - maxGap = Math.max(maxGap, value); - } + maxGap = 0; + for ([key, value] of myHash) { + maxGap = Math.max(maxGap, value); + } - return wall.length - maxGap; + return wall.length - maxGap; }; diff --git a/javascript/0572-subtree-of-another-tree.js b/javascript/0572-subtree-of-another-tree.js index 3bb99eb13..1461279be 100644 --- a/javascript/0572-subtree-of-another-tree.js +++ b/javascript/0572-subtree-of-another-tree.js @@ -5,93 +5,93 @@ * @return {boolean} */ var isSubtree = function (root, subRoot) { - if (!root) return false + if (!root) return false; - if (isSame(root, subRoot)) return true + if (isSame(root, subRoot)) return true; - const hasLeftTree = isSubtree(root.left, subRoot) - const hasRightTree = isSubtree(root.right, subRoot) + const hasLeftTree = isSubtree(root.left, subRoot); + const hasRightTree = isSubtree(root.right, subRoot); - return hasLeftTree || hasRightTree + return hasLeftTree || hasRightTree; }; const isSame = (root, subRoot) => { - const hasReachedEnd = !(root && subRoot) - if (hasReachedEnd) return root === subRoot + const hasReachedEnd = !(root && subRoot); + if (hasReachedEnd) return root === subRoot; const isMismatch = root.val !== subRoot.val; - if (isMismatch) return false + if (isMismatch) return false; - const isLeftSame = isSame(root.left, subRoot.left) - const isRightSame = isSame(root.right, subRoot.right) + const isLeftSame = isSame(root.left, subRoot.left); + const isRightSame = isSame(root.right, subRoot.right); - return isLeftSame && isRightSame -} + return isLeftSame && isRightSame; +}; const hash = (val) => - require('crypto').createHash('md5').update(val).digest('hex') + require('crypto').createHash('md5').update(val).digest('hex'); const merkle = (root) => { - if (!root) return '#' + if (!root) return '#'; - const { left, val, right } = root + const { left, val, right } = root; - const leftMerkle = merkle(left) - const rightMerkle = merkle(right) + const leftMerkle = merkle(left); + const rightMerkle = merkle(right); - const merkleVal = [leftMerkle, val, rightMerkle].join('') - const merkleHash = hash(merkleVal) + const merkleVal = [leftMerkle, val, rightMerkle].join(''); + const merkleHash = hash(merkleVal); - root.merkle = merkleHash + root.merkle = merkleHash; - return root.merkle -} + return root.merkle; +}; const search = (root, subRoot) => { - if (!root) return false + if (!root) return false; - const hasSamePath = root.merkle === subRoot.merkle - if (hasSamePath) return true + const hasSamePath = root.merkle === subRoot.merkle; + if (hasSamePath) return true; - const left = search(root.left, subRoot) - const right = search(root.right, subRoot) + const left = search(root.left, subRoot); + const right = search(root.right, subRoot); - return left || right -} + return left || right; +}; var isSubtree = function (root, subRoot) { - [root, subRoot].forEach(merkle) + [root, subRoot].forEach(merkle); - return search(root, subRoot) -} + return search(root, subRoot); +}; const hashify = (root, hash, postOrderKey) => { - if (!root) return '#' + if (!root) return '#'; - const left = hashify(root.left, hash, postOrderKey) - const right = hashify(root.right, hash, postOrderKey) + const left = hashify(root.left, hash, postOrderKey); + const right = hashify(root.right, hash, postOrderKey); - const key = [left, root.val, right].join('') + const key = [left, root.val, right].join(''); if (!hash.has(key)) { - hash.set(key, postOrderKey[0]) - postOrderKey[0]++ + hash.set(key, postOrderKey[0]); + postOrderKey[0]++; } - return hash.get(key) -} + return hash.get(key); +}; var isSubtree = function (root, subRoot, hash = new Map(), postOrderKey = [0]) { - hashify(root, hash, postOrderKey) + hashify(root, hash, postOrderKey); const hashKey = [ hashify(subRoot.left, hash, postOrderKey), subRoot.val, hashify(subRoot.right, hash, postOrderKey), - ].join('') + ].join(''); - return hash.has(hashKey) -} + return hash.has(hashKey); +}; /** * Definition for a binary tree node. @@ -109,30 +109,30 @@ var isSubtree = function (root, subRoot, hash = new Map(), postOrderKey = [0]) { */ var isSubtree = function (root, subRoot) { if (!subRoot) { - return true + return true; } else if (!root) { - return false + return false; } else if (isSameTree(root, subRoot)) { - return true + return true; } - const leftResult = isSubtree(root.left, subRoot) - const rightResult = isSubtree(root.right, subRoot) + const leftResult = isSubtree(root.left, subRoot); + const rightResult = isSubtree(root.right, subRoot); - return leftResult || rightResult -} + return leftResult || rightResult; +}; function isSameTree(root, subRoot) { if (!root && !subRoot) { - return true + return true; } else if (!root || !subRoot) { - return false + return false; } else if (root.val !== subRoot.val) { - return false + return false; } - const leftRes = isSameTree(root.left, subRoot.left) - const rightRes = isSameTree(root.right, subRoot.right) + const leftRes = isSameTree(root.left, subRoot.left); + const rightRes = isSameTree(root.right, subRoot.right); - return leftRes && rightRes + return leftRes && rightRes; } diff --git a/javascript/0605-can-place-flowers.js b/javascript/0605-can-place-flowers.js index e37490755..651dfb42e 100644 --- a/javascript/0605-can-place-flowers.js +++ b/javascript/0605-can-place-flowers.js @@ -8,16 +8,16 @@ */ var canPlaceFlowers = function (fb, n) { - if (n === 0) return true; + if (n === 0) return true; - for (let i = 0; i < fb.length; i++) { - if (fb[i] === 0) { - fb[i - 1] !== 1 && fb[i + 1] !== 1 && n-- && i++; - } else { - i++; - } - if (n === 0) return true; - } + for (let i = 0; i < fb.length; i++) { + if (fb[i] === 0) { + fb[i - 1] !== 1 && fb[i + 1] !== 1 && n-- && i++; + } else { + i++; + } + if (n === 0) return true; + } - return false; + return false; }; diff --git a/javascript/0606-construct-string-from-binary-tree.js b/javascript/0606-construct-string-from-binary-tree.js index ebee0cfd0..7978f80b3 100644 --- a/javascript/0606-construct-string-from-binary-tree.js +++ b/javascript/0606-construct-string-from-binary-tree.js @@ -1,5 +1,5 @@ /** - * InOrder Traversal + * InOrder Traversal * Time O(n) | Space O(n) * https://leetcode.com/problems/construct-string-from-binary-tree/ * Definition for a binary tree node. @@ -13,8 +13,8 @@ * @param {TreeNode} root * @return {string} */ -var tree2str = function(root) { - return dfs(root, []).join(""); +var tree2str = function (root) { + return dfs(root, []).join(''); }; const dfs = (node, strArr) => { @@ -22,14 +22,14 @@ const dfs = (node, strArr) => { strArr.push(node.val); - if (node.right || node.left) strArr.push("("); + if (node.right || node.left) strArr.push('('); dfs(node.left, strArr); - if (node.right || node.left) strArr.push(")"); + if (node.right || node.left) strArr.push(')'); // right tree - if (node.right) strArr.push("("); + if (node.right) strArr.push('('); dfs(node.right, strArr); - if (node.right) strArr.push(")"); + if (node.right) strArr.push(')'); return strArr; -} +}; diff --git a/javascript/0617-merge-two-binary-trees.js b/javascript/0617-merge-two-binary-trees.js index fc400d116..76d3709b0 100644 --- a/javascript/0617-merge-two-binary-trees.js +++ b/javascript/0617-merge-two-binary-trees.js @@ -2,19 +2,25 @@ * @param {TreeNode} root1 * @param {TreeNode} root2 * @return {TreeNode} - * Time complexity = O(n+m) + * Time complexity = O(n+m) */ - var mergeTrees = function(root1, root2) { +var mergeTrees = function (root1, root2) { // Base case to return null as result of having both root1, root2 null - if(!root1 && !root2) { + if (!root1 && !root2) { return null; } const val1 = root1 ? root1.val : 0; const val2 = root2 ? root2.val : 0; - - const root = new TreeNode(val1+val2); - root.left = mergeTrees(root1 ? root1.left : null, root2 ? root2.left: null); - root.right = mergeTrees(root1 ? root1.right : null , root2 ? root2.right: null); + + const root = new TreeNode(val1 + val2); + root.left = mergeTrees( + root1 ? root1.left : null, + root2 ? root2.left : null, + ); + root.right = mergeTrees( + root1 ? root1.right : null, + root2 ? root2.right : null, + ); return root; -}; \ No newline at end of file +}; diff --git a/javascript/0621-task-scheduler.js b/javascript/0621-task-scheduler.js index 4957acf26..f86ed2a6c 100644 --- a/javascript/0621-task-scheduler.js +++ b/javascript/0621-task-scheduler.js @@ -1,107 +1,121 @@ -/** - * https://leetcode.com/problems/task-scheduler/ - * Time O(N * log(N)) | Space O(N) - * @param {character[]} tasks - * @param {number} n - * @return {number} - */ -var leastInterval = function(tasks, n) { - const frequencyMap = getFrequencyMap(tasks) - const maxHeap = getMaxHeap(frequencyMap) - - return getMinimumCpuIntervals(maxHeap, n) -} - -var getFrequencyMap = (tasks, frequencyMap = new Array(26).fill(0)) => { - for (const task of tasks) { - const index = task.charCodeAt(0) - 'A'.charCodeAt(0); - - frequencyMap[index]++; - } - - return frequencyMap; -} - -const getMaxHeap = (frequencyMap, maxHeap = new MaxPriorityQueue()) => { - for (const frequency of frequencyMap) { - const hasFrequency = 0 < frequency; - if (hasFrequency) maxHeap.enqueue(frequency) - } - - return maxHeap -} - -const getMinimumCpuIntervals = (maxHeap, n, cpuIntervals = [ 0 ]) => { - while (!maxHeap.isEmpty()) { - const { iterations, coolingPeriodQueue } = execute(n, maxHeap, cpuIntervals) - - reQueueCoolingPeriod(coolingPeriodQueue, maxHeap) - - if (!maxHeap.isEmpty()) cpuIntervals[0] += iterations - } - - return cpuIntervals[0] -} - -const execute = (n, maxHeap, cpuIntervals, iterations = (n + 1), coolingPeriodQueue = new Queue()) => { - while ((0 < iterations) && !maxHeap.isEmpty()) { - const frequency = maxHeap.dequeue().element; - - const hasFrequency = 0 < (frequency - 1); - if (hasFrequency) coolingPeriodQueue.enqueue(frequency - 1); - - cpuIntervals[0]++; - iterations--; - } - - return { iterations, coolingPeriodQueue }; -} - -const reQueueCoolingPeriod = (coolingPeriodQueue, maxHeap) => { - while (!coolingPeriodQueue.isEmpty()) { - maxHeap.enqueue(coolingPeriodQueue.dequeue()) - } -} - -/** - * https://leetcode.com/problems/task-scheduler/ - * Time O(N) | Space O(1) - * @param {character[]} tasks - * @param {number} n - * @return {number} - */ - var leastInterval = function(tasks, n) { - const frequencyMap = getFrequencyMap(tasks); - const maxFrequency = getMaxFrequency(frequencyMap); - const mostFrequentTask = getMostFrequentTask(frequencyMap, maxFrequency); - const interval = ((maxFrequency - 1) * (n + 1)) + mostFrequentTask; - - return Math.max(tasks.length, interval); -} - -var getFrequencyMap = (tasks, frequencyMap = new Array(26).fill(0)) => { - for (const task of tasks) { - const index = task.charCodeAt(0) - 'A'.charCodeAt(0); - - frequencyMap[index]++; - } - - return frequencyMap; -} - -const getMaxFrequency = (frequencyMap, maxFrequency = 0) => { - for (const frequency of frequencyMap) { - maxFrequency = Math.max(maxFrequency, frequency); - } - - return maxFrequency; -} - -const getMostFrequentTask = (frequencyMap, maxFrequency, mostFrequentTask = 0) => { - for (const frequency of frequencyMap) { - const isSame = frequency === maxFrequency; - if (isSame) mostFrequentTask++; - } - - return mostFrequentTask; -} +/** + * https://leetcode.com/problems/task-scheduler/ + * Time O(N * log(N)) | Space O(N) + * @param {character[]} tasks + * @param {number} n + * @return {number} + */ +var leastInterval = function (tasks, n) { + const frequencyMap = getFrequencyMap(tasks); + const maxHeap = getMaxHeap(frequencyMap); + + return getMinimumCpuIntervals(maxHeap, n); +}; + +var getFrequencyMap = (tasks, frequencyMap = new Array(26).fill(0)) => { + for (const task of tasks) { + const index = task.charCodeAt(0) - 'A'.charCodeAt(0); + + frequencyMap[index]++; + } + + return frequencyMap; +}; + +const getMaxHeap = (frequencyMap, maxHeap = new MaxPriorityQueue()) => { + for (const frequency of frequencyMap) { + const hasFrequency = 0 < frequency; + if (hasFrequency) maxHeap.enqueue(frequency); + } + + return maxHeap; +}; + +const getMinimumCpuIntervals = (maxHeap, n, cpuIntervals = [0]) => { + while (!maxHeap.isEmpty()) { + const { iterations, coolingPeriodQueue } = execute( + n, + maxHeap, + cpuIntervals, + ); + + reQueueCoolingPeriod(coolingPeriodQueue, maxHeap); + + if (!maxHeap.isEmpty()) cpuIntervals[0] += iterations; + } + + return cpuIntervals[0]; +}; + +const execute = ( + n, + maxHeap, + cpuIntervals, + iterations = n + 1, + coolingPeriodQueue = new Queue(), +) => { + while (0 < iterations && !maxHeap.isEmpty()) { + const frequency = maxHeap.dequeue().element; + + const hasFrequency = 0 < frequency - 1; + if (hasFrequency) coolingPeriodQueue.enqueue(frequency - 1); + + cpuIntervals[0]++; + iterations--; + } + + return { iterations, coolingPeriodQueue }; +}; + +const reQueueCoolingPeriod = (coolingPeriodQueue, maxHeap) => { + while (!coolingPeriodQueue.isEmpty()) { + maxHeap.enqueue(coolingPeriodQueue.dequeue()); + } +}; + +/** + * https://leetcode.com/problems/task-scheduler/ + * Time O(N) | Space O(1) + * @param {character[]} tasks + * @param {number} n + * @return {number} + */ +var leastInterval = function (tasks, n) { + const frequencyMap = getFrequencyMap(tasks); + const maxFrequency = getMaxFrequency(frequencyMap); + const mostFrequentTask = getMostFrequentTask(frequencyMap, maxFrequency); + const interval = (maxFrequency - 1) * (n + 1) + mostFrequentTask; + + return Math.max(tasks.length, interval); +}; + +var getFrequencyMap = (tasks, frequencyMap = new Array(26).fill(0)) => { + for (const task of tasks) { + const index = task.charCodeAt(0) - 'A'.charCodeAt(0); + + frequencyMap[index]++; + } + + return frequencyMap; +}; + +const getMaxFrequency = (frequencyMap, maxFrequency = 0) => { + for (const frequency of frequencyMap) { + maxFrequency = Math.max(maxFrequency, frequency); + } + + return maxFrequency; +}; + +const getMostFrequentTask = ( + frequencyMap, + maxFrequency, + mostFrequentTask = 0, +) => { + for (const frequency of frequencyMap) { + const isSame = frequency === maxFrequency; + if (isSame) mostFrequentTask++; + } + + return mostFrequentTask; +}; diff --git a/javascript/0647-palindromic-substrings.js b/javascript/0647-palindromic-substrings.js index 87a3b220c..7c279454c 100644 --- a/javascript/0647-palindromic-substrings.js +++ b/javascript/0647-palindromic-substrings.js @@ -6,25 +6,29 @@ * @return {number} */ var countSubstrings = (s, count = 0) => { - for (let left = 0; (left < s.length); left++) { /* Time O(N) */ - for (let right = left; (right < s.length); right++) {/* Time O(N) */ - count += Number(isPalindrome(s, left, right)); /* Time O(N) */ + for (let left = 0; left < s.length; left++) { + /* Time O(N) */ + for (let right = left; right < s.length; right++) { + /* Time O(N) */ + count += Number(isPalindrome(s, left, right)); /* Time O(N) */ } } return count; -} +}; const isPalindrome = (s, left, right) => { - while (left < right) {/* Time O(N) */ - const isEqual = (s[left] === s[right]); + while (left < right) { + /* Time O(N) */ + const isEqual = s[left] === s[right]; if (!isEqual) return false; - left++; right--; + left++; + right--; } return true; -} +}; /** * DP - Bottom Up @@ -36,63 +40,70 @@ const isPalindrome = (s, left, right) => { * @return {number} */ var countSubstrings = (s, count = 0) => { - const tabu = initTabu(s); /* Time O(N * N) | Space O(N * N) */ + const tabu = initTabu(s); /* Time O(N * N) | Space O(N * N) */ - count += singleLetters(s, tabu);/* Time O(N) | Space O(N * N) */ - count += doubleLetters(s, tabu);/* Time O(N) | Space O(N * N) */ + count += singleLetters(s, tabu); /* Time O(N) | Space O(N * N) */ + count += doubleLetters(s, tabu); /* Time O(N) | Space O(N * N) */ count += multiLetters(s, tabu); /* Time O(N * N) | Space O(N * N) */ return count; }; -const initTabu = (s) => new Array(s.length).fill()/* Space O(N) */ - .map(() => new Array(s.length).fill(false)); /* Space O(N) */ +const initTabu = (s) => + new Array(s.length) + .fill() /* Space O(N) */ + .map(() => new Array(s.length).fill(false)); /* Space O(N) */ const singleLetters = (s, tabu, count = 0) => { - for (let index = 0; (index < s.length); index++) {/* Time O(N) */ - tabu[index][index] = true; /* Space O(N * N) */ + for (let index = 0; index < s.length; index++) { + /* Time O(N) */ + tabu[index][index] = true; /* Space O(N * N) */ count += Number(tabu[index][index]); } return count; -} +}; const doubleLetters = (s, tabu, count = 0) => { - for (let curr = 0; curr < (s.length - 1); curr++) {/* Time O(N) */ - const next = (curr + 1); - const isEqual = (s[curr] === s[next]); + for (let curr = 0; curr < s.length - 1; curr++) { + /* Time O(N) */ + const next = curr + 1; + const isEqual = s[curr] === s[next]; - tabu[curr][next] = isEqual; /* Space O(N * N) */ + tabu[curr][next] = isEqual; /* Space O(N * N) */ count += Number(tabu[curr][next]); } return count; -} +}; const multiLetters = (s, tabu, count = 0) => { - for (let window = 3; (window <= s.length); window++) {/* Time O(N) */ - count += slideWindow(s, tabu, window); /* Time O(N) | Space O(N * N) */ + for (let window = 3; window <= s.length; window++) { + /* Time O(N) */ + count += slideWindow(s, tabu, window); /* Time O(N) | Space O(N * N) */ } return count; -} +}; const slideWindow = (s, tabu, window, count = 0) => { - let [ left, right ] = [ 0, (window - 1) ]; + let [left, right] = [0, window - 1]; - while (right < s.length) {/* Time O(N) */ - const isTrue = tabu[(left + 1)][(right - 1)]; - const isEqual = (s[left] === s[right]); + while (right < s.length) { + /* Time O(N) */ + const isTrue = tabu[left + 1][right - 1]; + const isEqual = s[left] === s[right]; - tabu[left][right] = (isTrue && isEqual);/* Space O(N * N) */ + tabu[left][right] = isTrue && isEqual; /* Space O(N * N) */ count += Number(tabu[left][right]); - left++; right++; + left++; + right++; } return count; -} +}; /** * 2 Pointer - Expand Around Center @@ -102,27 +113,30 @@ const slideWindow = (s, tabu, window, count = 0) => { * @return {number} */ var countSubstrings = (s, count = 0) => { - for (let i = 0; (i < s.length); i++) {/* Time O(N) */ - const [ odd, even ] = [ i, (i + 1) ]; + for (let i = 0; i < s.length; i++) { + /* Time O(N) */ + const [odd, even] = [i, i + 1]; /* odd-length: single character center */ count += isPalindromeFromCenter(s, i, odd); /* Time O(N) */ /* even-length: consecutive characters center */ - count += isPalindromeFromCenter(s, i, even);/* Time O(N) */ + count += isPalindromeFromCenter(s, i, even); /* Time O(N) */ } return count; -} +}; const isPalindromeFromCenter = (s, left, right, count = 0) => { - const isInBounds = () => ((0 <= left) && (right < s.length)); - while (isInBounds()) {/* Time O(N) */ - const isEqual = (s[left] === s[right]); + const isInBounds = () => 0 <= left && right < s.length; + while (isInBounds()) { + /* Time O(N) */ + const isEqual = s[left] === s[right]; if (!isEqual) break; count++; - left--; right++; + left--; + right++; } return count; -} \ No newline at end of file +}; diff --git a/javascript/0652-find-duplicate-subtrees.js b/javascript/0652-find-duplicate-subtrees.js index cb0dc0597..bb964366c 100644 --- a/javascript/0652-find-duplicate-subtrees.js +++ b/javascript/0652-find-duplicate-subtrees.js @@ -7,45 +7,44 @@ * } */ /** - * Hashing + * Hashing * Time O(n^2) | Space O(n^2) * https://leetcode.com/problems/find-duplicate-subtrees/ * @param {TreeNode} root * @return {TreeNode[]} */ -var findDuplicateSubtrees = function(root) { - +var findDuplicateSubtrees = function (root) { const stringHash = {}; const makePreOrderStr = (node, str) => { - if(!node) return str + "-" + "null"; - - const str1 = makePreOrderStr(node.left, str + "-" + node.val); + if (!node) return str + '-' + 'null'; + + const str1 = makePreOrderStr(node.left, str + '-' + node.val); const str2 = makePreOrderStr(node.right, str1); return str2; - } + }; const duplicates = []; const dfs = (node) => { - if(!node) return; - const str = makePreOrderStr(node, ""); + if (!node) return; + const str = makePreOrderStr(node, ''); - if(!stringHash[str]) { + if (!stringHash[str]) { stringHash[str] = []; } - + stringHash[str].push(node); dfs(node.left); dfs(node.right); - } + }; dfs(root); - + for (let key in stringHash) { - if(stringHash[key].length > 1) duplicates.push(stringHash[key][0]); + if (stringHash[key].length > 1) duplicates.push(stringHash[key][0]); } return duplicates; diff --git a/javascript/0669-trim-a-binary-search-tree.js b/javascript/0669-trim-a-binary-search-tree.js index ef6973c19..e8bc7567b 100644 --- a/javascript/0669-trim-a-binary-search-tree.js +++ b/javascript/0669-trim-a-binary-search-tree.js @@ -1,33 +1,32 @@ -/** - * Definition for a binary tree node. - * function TreeNode(val, left, right) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } - */ -/** - * @param {TreeNode} root - * @param {number} low - * @param {number} high - * @return {TreeNode} - */ -var trimBST = function (root, low, high) { - - if (!root) { - return null; - } - - if (root.val < low) { - return trimBST(root.right, low, high); - } - - if (root.val > high) { - return trimBST(root.left, low, high); - } - - root.left = trimBST(root.left, low, high); - root.right = trimBST(root.right, low, high); - - return root; -}; \ No newline at end of file +/** + * Definition for a binary tree node. + * function TreeNode(val, left, right) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + */ +/** + * @param {TreeNode} root + * @param {number} low + * @param {number} high + * @return {TreeNode} + */ +var trimBST = function (root, low, high) { + if (!root) { + return null; + } + + if (root.val < low) { + return trimBST(root.right, low, high); + } + + if (root.val > high) { + return trimBST(root.left, low, high); + } + + root.left = trimBST(root.left, low, high); + root.right = trimBST(root.right, low, high); + + return root; +}; diff --git a/javascript/0678-valid-parenthesis-string.js b/javascript/0678-valid-parenthesis-string.js index c7cb6a3b0..f569c4ea7 100644 --- a/javascript/0678-valid-parenthesis-string.js +++ b/javascript/0678-valid-parenthesis-string.js @@ -36,77 +36,83 @@ var checkValidString = function (s) { * @param {string} s * @return {boolean} */ - var checkValidString = function(s) { +var checkValidString = function (s) { const isBaseCase = s.length === 0; if (isBaseCase) return true; - const dp = new Array(s.length).fill() + const dp = new Array(s.length) + .fill() .map(() => new Array(s.length).fill(false)); - for (let i = 0; i < s.length; i++) {/* Time O(N) */ + for (let i = 0; i < s.length; i++) { + /* Time O(N) */ if (isStar(s[i])) dp[i][i] = true; - - const isInBound = i < (s.length - 1) - const isOpenedOrStar = isOpened(s[i]) || isStar(s[i]) - const isClosedOrStar = isClosed(s[i + 1]) || isStar(s[i + 1]) - - const isValid = isInBound && isOpenedOrStar && isClosedOrStar - if (isValid) dp[i][i + 1] = true;/* Space O(N^2) */ + + const isInBound = i < s.length - 1; + const isOpenedOrStar = isOpened(s[i]) || isStar(s[i]); + const isClosedOrStar = isClosed(s[i + 1]) || isStar(s[i + 1]); + + const isValid = isInBound && isOpenedOrStar && isClosedOrStar; + if (isValid) dp[i][i + 1] = true; /* Space O(N^2) */ } - for (let size = 2; size < s.length; size++) {/* Time O() */ - for (let i = 0; i + size < s.length; i++) {/* Time O(N) */ - const isStarOrDP = isStar(s[i]) && isDP(dp, (i + 1), (i + size)) - if (isStarOrDP) { dp[i][i + size] = true; continue; } - - const isOpenedOrStar = isOpened(s[i]) || isStar(s[i]) + for (let size = 2; size < s.length; size++) { + /* Time O() */ + for (let i = 0; i + size < s.length; i++) { + /* Time O(N) */ + const isStarOrDP = isStar(s[i]) && isDP(dp, i + 1, i + size); + if (isStarOrDP) { + dp[i][i + size] = true; + continue; + } + + const isOpenedOrStar = isOpened(s[i]) || isStar(s[i]); if (isOpenedOrStar) check(dp, size, i); /* Time O(N) */ } } - + return dp[0][s.length - 1]; -} +}; -const check = (dp, size, i) => { - for (let k = (i + 1); k <= (i + size); k++) {/* Time O(N) */ - const isClosedOrStar = isClosed(s[k]) || isStar(s[k]) - const isKOrDP = isKEqual(k, i, 1) || isDP(dp, (i + 1), (k - 1)) - const isKOrDPSize = isKEqual(k, i, size) || isDP(dp, (k + 1), (i + size)) +const check = (dp, size, i) => { + for (let k = i + 1; k <= i + size; k++) { + /* Time O(N) */ + const isClosedOrStar = isClosed(s[k]) || isStar(s[k]); + const isKOrDP = isKEqual(k, i, 1) || isDP(dp, i + 1, k - 1); + const isKOrDPSize = isKEqual(k, i, size) || isDP(dp, k + 1, i + size); - const isValid = isClosedOrStar && isKOrDP && isKOrDPSize - if (isValid) dp[i][i + size] = true;/* Space O(N^2) */ + const isValid = isClosedOrStar && isKOrDP && isKOrDPSize; + if (isValid) dp[i][i + size] = true; /* Space O(N^2) */ } -} - -var isStar = (char) => char === '*' -var isOpened = (char) => char === '(' -var isClosed = (char) => char === ')' -const isKEqual = (k, i, size) => k === (i + size) -const isDP = (dp, i, k) => dp[i][k] +}; +var isStar = (char) => char === '*'; +var isOpened = (char) => char === '('; +var isClosed = (char) => char === ')'; +const isKEqual = (k, i, size) => k === i + size; +const isDP = (dp, i, k) => dp[i][k]; /** * Time O(N) | Space O(1) * @param {string} s * @return {boolean} */ -var checkValidString = function(s) { - let [ left, right ] = [ 0, 0 ]; +var checkValidString = function (s) { + let [left, right] = [0, 0]; - for (const char of s) {/* Time O(N) */ - left += isOpened(char) ? 1 : -1; - right += !isClosed(char) ? 1 : -1; - - const isNegative = right < 0; - if (isNegative) break; + for (const char of s) { + /* Time O(N) */ + left += isOpened(char) ? 1 : -1; + right += !isClosed(char) ? 1 : -1; - left = Math.max(left, 0); - } - - return left === 0; -} + const isNegative = right < 0; + if (isNegative) break; -var isOpened = (char) => char === '(' -var isClosed = (char) => char === ')' + left = Math.max(left, 0); + } + return left === 0; +}; +var isOpened = (char) => char === '('; +var isClosed = (char) => char === ')'; diff --git a/javascript/0684-redundant-connection.js b/javascript/0684-redundant-connection.js index 61771b9b0..4c0ab4c7b 100644 --- a/javascript/0684-redundant-connection.js +++ b/javascript/0684-redundant-connection.js @@ -5,26 +5,27 @@ * @return {number[]} */ var findRedundantConnection = function (edges) { - const graph = new Array((1000 + 1)).fill().map(() => []); + const graph = new Array(1000 + 1).fill().map(() => []); - for (const [ src, dst ] of edges) { - const hasNodes = (src in graph) && (dst in graph) - if (hasNodes && hasRedundantConnection(graph, src, dst)) return [ src, dst ]; + for (const [src, dst] of edges) { + const hasNodes = src in graph && dst in graph; + if (hasNodes && hasRedundantConnection(graph, src, dst)) + return [src, dst]; graph[src].push(dst); graph[dst].push(src); } -} +}; const hasRedundantConnection = (graph, source, target, seen = new Set()) => { - if (seen.has(source)) return false + if (seen.has(source)) return false; seen.add(source); - const isEqual = source === target + const isEqual = source === target; if (isEqual) return true; return dfs(graph, source, target, seen); -} +}; const dfs = (graph, source, target, seen) => { for (const neighbor of graph[source]) { @@ -32,7 +33,7 @@ const dfs = (graph, source, target, seen) => { } return false; -} +}; /** * https://leetcode.com/problems/redundant-connection/ @@ -41,27 +42,28 @@ const dfs = (graph, source, target, seen) => { * @return {number[]} */ var findRedundantConnection = function (edges) { - return new UnionFind(edges) - .redundantConnection; + return new UnionFind(edges).redundantConnection; }; class UnionFind { - constructor (edges) { - this.parent = new Array(edges.length + 1).fill().map((_, index) => index); + constructor(edges) { + this.parent = new Array(edges.length + 1) + .fill() + .map((_, index) => index); this.rank = new Array(edges.length + 1).fill(1); - this.redundantConnection = [ -1, -1 ]; + this.redundantConnection = [-1, -1]; this.search(edges); } - search (edges) { - for (let [ src, dst ] of edges) { + search(edges) { + for (let [src, dst] of edges) { const hasConnection = this.union(src, dst); - if (!hasConnection) return (this.redundantConnection = [ src, dst ]); + if (!hasConnection) return (this.redundantConnection = [src, dst]); } } - find (node, { parent } = this) { + find(node, { parent } = this) { let head = parent[node]; const isEqual = () => head === parent[head]; @@ -75,30 +77,30 @@ class UnionFind { return head; } - compress (tail, head, { parent } = this) { + compress(tail, head, { parent } = this) { parent[tail] = head; } - - increaseRank (head, tail, { rank } = this) { + + increaseRank(head, tail, { rank } = this) { rank[head] += rank[tail]; } - union (src, dst, { rank } = this) { - const [ rootSrc, rootDst ] = [ this.find(src), this.find(dst) ]; + union(src, dst, { rank } = this) { + const [rootSrc, rootDst] = [this.find(src), this.find(dst)]; const hasCycle = rootSrc === rootDst; if (hasCycle) return false; const isSrcGreater = rank[rootDst] < rank[rootSrc]; if (isSrcGreater) { - this.increaseRank(rootDst, rootSrc) - this.compress(rootSrc, rootDst) + this.increaseRank(rootDst, rootSrc); + this.compress(rootSrc, rootDst); } const isDstGreater = rank[rootSrc] <= rank[rootDst]; if (isDstGreater) { - this.increaseRank(rootSrc, rootDst) - this.compress(rootDst, rootSrc) + this.increaseRank(rootSrc, rootDst); + this.compress(rootDst, rootSrc); } return true; diff --git a/javascript/0695-max-area-of-island.js b/javascript/0695-max-area-of-island.js index 56d3aab38..feb7f10cf 100644 --- a/javascript/0695-max-area-of-island.js +++ b/javascript/0695-max-area-of-island.js @@ -4,13 +4,22 @@ * @param {number[][]} grid * @return {number} */ - var maxAreaOfIsland = function(grid, maxArea = 0) { - const [ rows, cols ] = [ grid.length, grid[0].length ]; +var maxAreaOfIsland = function (grid, maxArea = 0) { + const [rows, cols] = [grid.length, grid[0].length]; const seen = new Array(rows).fill().map(() => new Array(cols)); - for (let row = 0; row < rows; row++) {/* Time O(ROWS) */ - for (let col = 0; col < cols; col++) {/* Time O(COLS) */ - const area = getArea(grid, row, rows, col, cols, seen);/* Space O(ROWS * COLS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ + const area = getArea( + grid, + row, + rows, + col, + cols, + seen, + ); /* Space O(ROWS * COLS) */ maxArea = Math.max(maxArea, area); } @@ -24,65 +33,81 @@ var getArea = (grid, row, rows, col, cols, seen) => { if (isBaseCase) return 0; if (seen[row][col]) return 0; - seen[row][col] = true; /* Space O(ROWS * COLS) */ + seen[row][col] = true; /* Space O(ROWS * COLS) */ - return dfs(grid, row, rows, col, cols, seen) + 1; /* Space O(ROWS * COLS) */ -} + return dfs(grid, row, rows, col, cols, seen) + 1; /* Space O(ROWS * COLS) */ +}; const dfs = (grid, row, rows, col, cols, seen, area = 0) => { - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) { + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { area += getArea(grid, _row, rows, _col, cols, seen); } - return area -} + return area; +}; -var getNeighbors = (row, rows, col, cols) => [[ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ -1, 0 ]] - .map(([ _row, _col]) => [ (row + _row), (col + _col) ]) - .filter(([ _row, _col ]) => (0 <= _row) && (_row < rows) && (0 <= _col) && (_col < cols)) +var getNeighbors = (row, rows, col, cols) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + .map(([_row, _col]) => [row + _row, col + _col]) + .filter( + ([_row, _col]) => + 0 <= _row && _row < rows && 0 <= _col && _col < cols, + ); - /** +/** * https://leetcode.com/problems/number-of-islands/ * Time O(ROWS * COLS) | Space O(ROWS * COLS) * @param {character[][]} grid * @return {number} */ var maxAreaOfIsland = (grid, maxArea = 0) => { - const [ rows, cols ] = [ grid.length, grid[0].length ] + const [rows, cols] = [grid.length, grid[0].length]; const seen = new Array(rows).fill().map(() => new Array(cols)); - for (let row = 0; row < rows; row++) {/* Time O(ROWS) */ - for (let col = 0; col < cols; col++) {/* Time O(COLS) */ - const isBaseCase = grid[row][col] === 0 + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ + const isBaseCase = grid[row][col] === 0; if (isBaseCase) continue; if (seen[row][col]) continue; - seen[row][col] = true; /* Space O(ROWS * COLS) */ + seen[row][col] = true; /* Space O(ROWS * COLS) */ - const area = getArea(new Queue([[ row, col ]]), grid, seen);/* Space O(ROWS * COLS) */ + const area = getArea( + new Queue([[row, col]]), + grid, + seen, + ); /* Space O(ROWS * COLS) */ maxArea = Math.max(maxArea, area); } } - return maxArea -} + return maxArea; +}; var getArea = (queue, grid, seen, area = 0) => { - const [ rows, cols ] = [ grid.length, grid[0].length ]; + const [rows, cols] = [grid.length, grid[0].length]; while (!queue.isEmpty()) { - for (let i = (queue.size() - 1); 0 <= i; i--) {/* Time O(WIDTH) */ - const [ row, col ] = queue.dequeue(); + for (let i = queue.size() - 1; 0 <= i; i--) { + /* Time O(WIDTH) */ + const [row, col] = queue.dequeue(); - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) { + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { const isBaseCase = grid[_row][_col] === 0; if (isBaseCase) continue; if (seen[_row][_col]) continue; - seen[_row][_col] = true; /* Space O(ROWS * COLS) */ - - queue.enqueue([ _row, _col ]); /* Space O(HEIGHT) */ + seen[_row][_col] = true; /* Space O(ROWS * COLS) */ + + queue.enqueue([_row, _col]); /* Space O(HEIGHT) */ } area++; @@ -90,8 +115,17 @@ var getArea = (queue, grid, seen, area = 0) => { } return area; -} +}; -var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ], [ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ] - .map(([ _row, _col]) => [ (row + _row), (col + _col) ]) - .filter(([ _row, _col ]) => (0 <= _row) && (_row < rows) && (0 <= _col) && (_col < cols)) \ No newline at end of file +var getNeighbors = (row, rows, col, cols) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + .map(([_row, _col]) => [row + _row, col + _col]) + .filter( + ([_row, _col]) => + 0 <= _row && _row < rows && 0 <= _col && _col < cols, + ); diff --git a/javascript/0701-insert-into-a-binary-search-tree.js b/javascript/0701-insert-into-a-binary-search-tree.js index 0ab181e89..f10454079 100644 --- a/javascript/0701-insert-into-a-binary-search-tree.js +++ b/javascript/0701-insert-into-a-binary-search-tree.js @@ -13,7 +13,7 @@ * @param {number} val * @return {TreeNode} */ -var insertIntoBST = function(root, val) { +var insertIntoBST = function (root, val) { return dfs(root, val); }; @@ -27,4 +27,4 @@ const dfs = (root, val) => { } root.left = dfs(root.left, val); return root; -} +}; diff --git a/javascript/0703-kth-largest-element-in-a-stream.js b/javascript/0703-kth-largest-element-in-a-stream.js index 2a500dcce..bf6d59a32 100644 --- a/javascript/0703-kth-largest-element-in-a-stream.js +++ b/javascript/0703-kth-largest-element-in-a-stream.js @@ -1,21 +1,21 @@ -/** +/** * https://leetcode.com/problems/kth-largest-element-in-a-stream/ * Time O(N * (K * log(K))) | Space O(K) * Your KthLargest object will be instantiated and called as such: * var obj = new KthLargest(k, nums) * var param_1 = obj.add(val) */ - class KthLargest { +class KthLargest { /** * @param {number} k * @param {number[]} nums * @constructor */ constructor(k, nums) { - this.k = k + this.k = k; this.minHeap = new MinPriorityQueue(); - nums.forEach((num) => this.add(num)) + nums.forEach((num) => this.add(num)); } /** @@ -26,21 +26,20 @@ const isUnderCapacity = minHeap.size() < this.k; if (isUnderCapacity) { minHeap.enqueue(val); - + return this.top(); } const isLarger = this.top() < val; if (isLarger) { - minHeap.dequeue() + minHeap.dequeue(); minHeap.enqueue(val); } - + return this.top(); } - top ({ minHeap } = this) { - return minHeap.front()?.element || 0 + top({ minHeap } = this) { + return minHeap.front()?.element || 0; } } - diff --git a/javascript/0705-design-hashset.js b/javascript/0705-design-hashset.js index 275b5d59f..43f6e42d1 100644 --- a/javascript/0705-design-hashset.js +++ b/javascript/0705-design-hashset.js @@ -4,7 +4,7 @@ class MyHashSet { this.set = []; } - /** + /** * Time O(1) | Space O(1) * @param {number} key * @return {void} @@ -13,7 +13,7 @@ class MyHashSet { this.set[key] = key; } - /** + /** * Time O(1) | Space O(1) * @param {number} key * @return {void} @@ -22,7 +22,7 @@ class MyHashSet { this.set[key] = undefined; } - /** + /** * Time O(1) | Space O(1) * @param {number} key * @return {boolean} @@ -32,7 +32,7 @@ class MyHashSet { } } -/** +/** * Your MyHashSet object will be instantiated and called as such: * var obj = new MyHashSet() * obj.add(key) diff --git a/javascript/0739-daily-temperatures.js b/javascript/0739-daily-temperatures.js index f89955b56..3134da9d5 100644 --- a/javascript/0739-daily-temperatures.js +++ b/javascript/0739-daily-temperatures.js @@ -4,18 +4,18 @@ * @param {number[]} temperatures * @return {number[]} */ -var dailyTemperatures = function(temp) { - let res = new Array(temp.length).fill(0) - let stack = [] +var dailyTemperatures = function (temp) { + let res = new Array(temp.length).fill(0); + let stack = []; - for (let i = 0; i < temp.length; i++){ - while (stack.length && temp[i] > temp[stack[stack.length - 1]]){ - let idx = stack.pop() - res[idx] = i - idx + for (let i = 0; i < temp.length; i++) { + while (stack.length && temp[i] > temp[stack[stack.length - 1]]) { + let idx = stack.pop(); + res[idx] = i - idx; } - stack.push(i) + stack.push(i); } - return res + return res; }; /** @@ -24,18 +24,20 @@ var dailyTemperatures = function(temp) { * @param {number[]} temperatures * @return {number[]} */ -var dailyTemperatures = function(temperatures, stack = []) { +var dailyTemperatures = function (temperatures, stack = []) { const days = Array(temperatures.length).fill(0); - for (let day = 0; day < temperatures.length; day++) {/* Time O(N + N) */ - while (canShrink(stack, temperatures, day)) { /* Time O(N + N) */ + for (let day = 0; day < temperatures.length; day++) { + /* Time O(N + N) */ + while (canShrink(stack, temperatures, day)) { + /* Time O(N + N) */ const prevColdDay = stack.pop(); - const daysToWait = (day - prevColdDay); + const daysToWait = day - prevColdDay; - days[prevColdDay] = daysToWait; /* Ignore Space O(N) */ + days[prevColdDay] = daysToWait; /* Ignore Space O(N) */ } - stack.push(day); /* Space O(N) */ + stack.push(day); /* Space O(N) */ } return days; @@ -43,11 +45,14 @@ var dailyTemperatures = function(temperatures, stack = []) { const canShrink = (stack, temperatures, day) => { const previousDay = stack[stack.length - 1]; - const [ prevTemperature, currTemperature ] = [ temperatures[previousDay], temperatures[day] ]; + const [prevTemperature, currTemperature] = [ + temperatures[previousDay], + temperatures[day], + ]; const isWarmer = prevTemperature < currTemperature; return stack.length && isWarmer; -} +}; /** * https://leetcode.com/problems/daily-temperatures @@ -55,27 +60,33 @@ const canShrink = (stack, temperatures, day) => { * @param {number[]} temperatures * @return {number[]} */ -var dailyTemperatures = function(temperatures, hottest = 0) { +var dailyTemperatures = function (temperatures, hottest = 0) { const days = new Array(temperatures.length).fill(0); - for (let day = (temperatures.length - 1); (0 <= day); day--) {/* Time O(N + N) */ + for (let day = temperatures.length - 1; 0 <= day; day--) { + /* Time O(N + N) */ const temperature = temperatures[day]; - const isHotter = hottest <= temperature + const isHotter = hottest <= temperature; if (isHotter) { hottest = temperature; - continue; /* Time O(N + N) */ + continue; /* Time O(N + N) */ } - search(temperatures, day, temperature, days); /* Time O(N + N) | Ignore Space O(N) */ + search( + temperatures, + day, + temperature, + days, + ); /* Time O(N + N) | Ignore Space O(N) */ } return days; -} +}; const search = (temperatures, day, temperature, days, dayCount = 1) => { const isHotter = () => temperatures[day + dayCount] <= temperature; - while (isHotter()) dayCount += days[day + dayCount]; /* Time O(N + N) */ + while (isHotter()) dayCount += days[day + dayCount]; /* Time O(N + N) */ - days[day] = dayCount; /* Ignore Space O(N) */ -} + days[day] = dayCount; /* Ignore Space O(N) */ +}; diff --git a/javascript/0743-network-delay-time.js b/javascript/0743-network-delay-time.js index 90be1ea0d..2c8bc6c6e 100644 --- a/javascript/0743-network-delay-time.js +++ b/javascript/0743-network-delay-time.js @@ -8,7 +8,7 @@ * @param {number} k * @return {number} */ - var networkDelayTime = (times, n, k) => { +var networkDelayTime = (times, n, k) => { const { graph, maxTime, queue } = buildGraph(times, n, k); bfs(queue, graph, maxTime, k); @@ -17,51 +17,51 @@ }; var initGraph = (n, k) => ({ - graph: Array.from({ length: n + 1}).fill().map(() => []), - maxTime: Array.from({ length: n + 1}).fill(Infinity), - queue: new Queue([[ k, 0 ]]) -}) + graph: Array.from({ length: n + 1 }) + .fill() + .map(() => []), + maxTime: Array.from({ length: n + 1 }).fill(Infinity), + queue: new Queue([[k, 0]]), +}); var buildGraph = (times, n, k) => { const { graph, maxTime, queue } = initGraph(n, k); - for (const [ src, dst, weight ] of times ) { - graph[src].push([ dst, weight ]); - }; + for (const [src, dst, weight] of times) { + graph[src].push([dst, weight]); + } maxTime[0] = 0; return { graph, maxTime, queue }; -} +}; var bfs = (queue, graph, maxTime) => { while (!queue.isEmpty()) { - for (let level = (queue.size() -1); (0 <= level); level-- ) { + for (let level = queue.size() - 1; 0 <= level; level--) { checkNeighbors(queue, graph, maxTime); } } -} +}; var checkNeighbors = (queue, graph, maxTime) => { - const [ node, time ] = queue.dequeue(); + const [node, time] = queue.dequeue(); - const canUpdate = (time < maxTime[node]); + const canUpdate = time < maxTime[node]; if (!canUpdate) return; maxTime[node] = time; - for (const [ dst, weight ] of graph[node]) { - queue.enqueue([ dst, (weight + time) ]); + for (const [dst, weight] of graph[node]) { + queue.enqueue([dst, weight + time]); } -} +}; var checkAns = (maxTime) => { const max = Math.max(...maxTime); - return (max < Infinity) - ? max - : (-1); -} + return max < Infinity ? max : -1; +}; /** * https://leetcode.com/problems/network-delay-time/ @@ -70,36 +70,36 @@ var checkAns = (maxTime) => { * @param {number} k * @return {number} */ - var networkDelayTime = (times, n, k) => { - const { graph, seen, minHeap } = buildGraph(times, n, k) +var networkDelayTime = (times, n, k) => { + const { graph, seen, minHeap } = buildGraph(times, n, k); const maxTime = getTime(graph, seen, minHeap); - return (seen.size === n) - ? maxTime - : -1; + return seen.size === n ? maxTime : -1; }; var initGraph = (n, k) => ({ - graph: Array.from({ length: n + 1}).fill().map(() => []), + graph: Array.from({ length: n + 1 }) + .fill() + .map(() => []), seen: new Set(), - minHeap: new MinPriorityQueue() -}) + minHeap: new MinPriorityQueue(), +}); var buildGraph = (times, n, k) => { const { graph, seen, minHeap } = initGraph(n, k); - for (const [ src, dst, weight ] of times ) { - graph[src].push([ dst, weight ]); - }; + for (const [src, dst, weight] of times) { + graph[src].push([dst, weight]); + } minHeap.enqueue([k, 0], 0); return { graph, seen, minHeap }; -} +}; const getTime = (graph, seen, minHeap, maxTime = 0) => { while (!minHeap.isEmpty()) { - const [ node, cost ] = minHeap.dequeue().element; + const [node, cost] = minHeap.dequeue().element; if (seen.has(node)) continue; seen.add(node); @@ -109,15 +109,15 @@ const getTime = (graph, seen, minHeap, maxTime = 0) => { } return maxTime; -} +}; var checkNeighbors = (graph, src, srcCost, seen, minHeap) => { - for (const [ dst, dstCost ] of graph[src]) { + for (const [dst, dstCost] of graph[src]) { if (seen.has(dst)) continue; - const cost = (dstCost + srcCost) - const node = [ dst, cost]; + const cost = dstCost + srcCost; + const node = [dst, cost]; minHeap.enqueue(node, cost); } -} \ No newline at end of file +}; diff --git a/javascript/0746-min-cost-climbing-stairs.js b/javascript/0746-min-cost-climbing-stairs.js index 5e67b88a3..a49acdeb3 100644 --- a/javascript/0746-min-cost-climbing-stairs.js +++ b/javascript/0746-min-cost-climbing-stairs.js @@ -10,16 +10,20 @@ var minCostClimbingStairs = (cost, i = cost.length, memo = new Map()) => { const isBaseCase = i <= 1; if (isBaseCase) return 0; - if (memo.has(i)) return memo.get(i);; + if (memo.has(i)) return memo.get(i); - const [ prev, prevPrev ] = [ (i - 1), (i - 2) ]; - const downOne = minCostClimbingStairs(cost, prev, memo) + cost[prev]; /* Time O(N) | Space O(N) */ - const downTwo = minCostClimbingStairs(cost, prevPrev, memo) + cost[prevPrev];/* Time O(N) | Space O(N) */ + const [prev, prevPrev] = [i - 1, i - 2]; + const downOne = + minCostClimbingStairs(cost, prev, memo) + + cost[prev]; /* Time O(N) | Space O(N) */ + const downTwo = + minCostClimbingStairs(cost, prevPrev, memo) + + cost[prevPrev]; /* Time O(N) | Space O(N) */ memo.set(i, Math.min(downOne, downTwo)); return memo.get(i); -} +}; /** * DP - Bottom Up @@ -29,11 +33,11 @@ var minCostClimbingStairs = (cost, i = cost.length, memo = new Map()) => { * @param {number[]} cost * @return {number} */ - var minCostClimbingStairs = (cost) => { +var minCostClimbingStairs = (cost) => { const tabu = new Array(cost.length + 1).fill(0); for (let i = 2; i < tabu.length; i++) { - const [ prev, prevPrev ] = [ (i - 1), (i - 2) ]; + const [prev, prevPrev] = [i - 1, i - 2]; const downOne = tabu[prev] + cost[prev]; const downTwo = tabu[prevPrev] + cost[prevPrev]; @@ -41,7 +45,7 @@ var minCostClimbingStairs = (cost, i = cost.length, memo = new Map()) => { } return tabu[tabu.length - 1]; -} +}; /** * DP - Bottom Up @@ -51,12 +55,13 @@ var minCostClimbingStairs = (cost, i = cost.length, memo = new Map()) => { * @return {number} */ var minCostClimbingStairs = (cost) => { - let [ downOne, downTwo ] = [ 0, 0 ]; + let [downOne, downTwo] = [0, 0]; - for (let i = 2; i < cost.length + 1; i++) {/* Time O(N) */ + for (let i = 2; i < cost.length + 1; i++) { + /* Time O(N) */ const temp = downOne; - const [ _prev, _prevPrev ] = [ (i - 1), (i - 2) ]; + const [_prev, _prevPrev] = [i - 1, i - 2]; const prev = downOne + cost[_prev]; const prevPrev = downTwo + cost[_prevPrev]; @@ -65,4 +70,4 @@ var minCostClimbingStairs = (cost) => { } return downOne; -} \ No newline at end of file +}; diff --git a/javascript/0752-open-the-lock.js b/javascript/0752-open-the-lock.js index 524470ff5..2b97a4f1a 100644 --- a/javascript/0752-open-the-lock.js +++ b/javascript/0752-open-the-lock.js @@ -3,18 +3,17 @@ * @param {string} target * @return {number} */ -var openLock = function(deadends, target) { - +var openLock = function (deadends, target) { // General approach: // Start at the end, mark that spot to be 0 away from target // Find all the valid neighbors through bfs, mark those as 1 // Find all _their_ valid neighbors, mark those as ++ etc // Until we find 0000. Whatever we mark that as is the number. BFS will guarantee it's the shortest path - + let q = [target]; // our BFS Queue - let mem = {}; // to keep track what we already have visited - mem[target] = 0; // starting distance of the end - + let mem = {}; // to keep track what we already have visited + mem[target] = 0; // starting distance of the end + // Helper function that given a position, will generate all the numbers we // can create in 1 move; let getNextPositions = function (pos) { @@ -23,7 +22,7 @@ var openLock = function(deadends, target) { let arr = pos.split(''); let positions = []; let i, j; - + for (j = 0; j < 2; j++) { let next = ''; // for each number in the position @@ -38,27 +37,27 @@ var openLock = function(deadends, target) { } } return positions; - } - + }; + while (q.length) { // dequeue a position to check out let pos = q.shift(); - + // if it's 0000 we're done. BFS guarantees it's the shortest possible if (pos === '0000') { return mem[pos]; } else { let next = getNextPositions(pos); - next.forEach(function(n) { + next.forEach(function (n) { // if we haven't seen n before, and it's not a dead end, if (mem[n] === undefined && !deadends.includes(n)) { - // mark the distance and enqueue to check out next - mem[n] = mem[pos] + 1; - q.push(n); + // mark the distance and enqueue to check out next + mem[n] = mem[pos] + 1; + q.push(n); } - }) - } + }); + } } // if we end up here, we couldn't find it return -1; -}; \ No newline at end of file +}; diff --git a/javascript/0763-partition-labels.js b/javascript/0763-partition-labels.js index b46b17d5c..5ce5b274b 100644 --- a/javascript/0763-partition-labels.js +++ b/javascript/0763-partition-labels.js @@ -31,39 +31,41 @@ var partitionLabels = function (s) { * @param {string} S * @return {number[]} */ - var partitionLabels = function(S) { +var partitionLabels = function (S) { const lastSeen = getLast(S); return getAns(S, lastSeen); }; const getLast = (S, lastSeen = []) => { - for (const index in S) {/* Time O(N) */ + for (const index in S) { + /* Time O(N) */ const code = getCode(S[Number(index)]); - - lastSeen[code] = Number(index);/* Space O(1) */ + + lastSeen[code] = Number(index); /* Space O(1) */ } return lastSeen; }; -const getCode = (char ) => char.charCodeAt(0) - 'a'.charCodeAt(0); +const getCode = (char) => char.charCodeAt(0) - 'a'.charCodeAt(0); const getAns = (S, lastSeen, left = 0, right = 0, labels = []) => { - for (const index in S) {/* Time O(N) */ + for (const index in S) { + /* Time O(N) */ const code = getCode(S[Number(index)]); const lastSeenAt = lastSeen[code]; - + right = Math.max(right, lastSeenAt); - + const isEqual = Number(index) === right; if (!isEqual) continue; - - const placement = (Number(index) - left) + 1; - + + const placement = Number(index) - left + 1; + labels.push(placement); - left = Number(index) + 1; - }; - + left = Number(index) + 1; + } + return labels; -} +}; diff --git a/javascript/0767-reorganize-string.js b/javascript/0767-reorganize-string.js index c4798c81d..91293418b 100644 --- a/javascript/0767-reorganize-string.js +++ b/javascript/0767-reorganize-string.js @@ -5,38 +5,35 @@ * @param {string} s * @return {string} */ -var reorganizeString = function(s) { - +var reorganizeString = function (s) { const maxQ = new MaxPriorityQueue({ compare: (a, b) => { - return b[0] - a[0]; - } + return b[0] - a[0]; + }, }); const freq = {}; for (let i = 0; i < s.length; i++) { const char = s[i]; - freq[char] = (freq[char] && freq[char] + 1 || 1); + freq[char] = (freq[char] && freq[char] + 1) || 1; } for (const key in freq) { const val = freq[key]; maxQ.enqueue([val, key]); } - let orgStr = ""; + let orgStr = ''; while (!maxQ.isEmpty()) { - const [occurance, char] = maxQ.dequeue(); if (orgStr[orgStr.length - 1] === char) { + if (maxQ.isEmpty()) return ''; - if (maxQ.isEmpty()) return ""; - - const [occurance1, char1] = maxQ.dequeue(); + const [occurance1, char1] = maxQ.dequeue(); orgStr += char1; if (occurance1 - 1) { maxQ.enqueue([occurance1 - 1, char1]); - } + } maxQ.enqueue([occurance, char]); } else { orgStr += char; diff --git a/javascript/0778-swim-in-rising-water.js b/javascript/0778-swim-in-rising-water.js index 1611766e6..c65cfbdcd 100644 --- a/javascript/0778-swim-in-rising-water.js +++ b/javascript/0778-swim-in-rising-water.js @@ -3,45 +3,53 @@ * @param {number[][]} grid * @return {number} */ - var swimInWater = (grid) => { +var swimInWater = (grid) => { const seen = new Set(); const minHeap = getHeap(grid); return getTime(grid, seen, minHeap); }; - const getHeap = (grid, minHeap = new MinPriorityQueue()) => { - minHeap.enqueue([ 0, 0 ], grid[0][0]); + minHeap.enqueue([0, 0], grid[0][0]); - return minHeap; -} + return minHeap; +}; var getTime = (grid, seen, minHeap, maxTime = 0) => { - const [ rows, cols ] = [ (grid.length - 1), (grid[0].length - 1) ]; + const [rows, cols] = [grid.length - 1, grid[0].length - 1]; while (!minHeap.isEmpty()) { const { element, priority: cost } = minHeap.dequeue(); - const [ row, col ] = element; + const [row, col] = element; seen.add(grid[row][col]); maxTime = Math.max(maxTime, cost); - const isEnd = (row === rows) && (col === cols); + const isEnd = row === rows && col === cols; if (isEnd) return maxTime; checkNeighbors(grid, row, rows, col, cols, seen, minHeap); } -} +}; var checkNeighbors = (grid, row, rows, col, cols, seen, minHeap) => { - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) { + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { if (seen.has(grid[_row][_col])) continue; - minHeap.enqueue([ _row, _col ], grid[_row][_col]); + minHeap.enqueue([_row, _col], grid[_row][_col]); } -} +}; -const getNeighbors = (row, rows, col, cols) => [ [1, 0], [-1, 0], [0, 1], [0, -1] ] - .map(([ _row, _col ]) => [ (row + _row), (col + _col) ]) - .filter(([ _row, _col ]) => ((0 <= _row) && (_row <= rows) && (0 <= _col) && (_col <= cols))) +const getNeighbors = (row, rows, col, cols) => + [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ] + .map(([_row, _col]) => [row + _row, col + _col]) + .filter( + ([_row, _col]) => + 0 <= _row && _row <= rows && 0 <= _col && _col <= cols, + ); diff --git a/javascript/0783-minimum-distance-between-bst-nodes.js b/javascript/0783-minimum-distance-between-bst-nodes.js index 87704f1c5..4e9fca04f 100644 --- a/javascript/0783-minimum-distance-between-bst-nodes.js +++ b/javascript/0783-minimum-distance-between-bst-nodes.js @@ -13,10 +13,10 @@ * @param {TreeNode} root * @return {number} */ -var minDiffInBST = function(root) { +var minDiffInBST = function (root) { // levelOrderTraversal const sortedArr = dfs(root, []); - + let min = Infinity; for (let i = 1; i < sortedArr.length; i++) { min = Math.min(min, sortedArr[i] - sortedArr[i - 1]); @@ -28,8 +28,8 @@ const dfs = (node, sortedArr) => { if (!node) return; dfs(node.left, sortedArr); - sortedArr.push(node.val) + sortedArr.push(node.val); dfs(node.right, sortedArr); return sortedArr; -} +}; diff --git a/javascript/0787-cheapest-flights-within-k-stops.js b/javascript/0787-cheapest-flights-within-k-stops.js index 79562829f..e63fc62ca 100644 --- a/javascript/0787-cheapest-flights-within-k-stops.js +++ b/javascript/0787-cheapest-flights-within-k-stops.js @@ -6,7 +6,7 @@ * @param {number} k * @return {number} */ - var findCheapestPrice = function (n, flights, src, dst, K) { +var findCheapestPrice = function (n, flights, src, dst, K) { const { graph, seen, minHeap } = buildGraph(n, flights, src, dst, K); return search(graph, src, dst, seen, minHeap); @@ -16,49 +16,49 @@ var initGraph = (n) => ({ graph: new Array(n).fill().map(() => []), seen: new Map(), minHeap: new MinPriorityQueue(), -}) +}); var buildGraph = (n, flights, src, dst, K) => { const { graph, seen, minHeap } = initGraph(n); - for (const [ src, dst, cost ] of flights) { - graph[src].push([ dst, cost ]); + for (const [src, dst, cost] of flights) { + graph[src].push([dst, cost]); } const priority = 0; - const node = [ priority, src, (K + 1) ]; + const node = [priority, src, K + 1]; minHeap.enqueue(node, priority); return { graph, seen, minHeap }; -} +}; const search = (graph, src, dst, seen, minHeap) => { while (!minHeap.isEmpty()) { - const [ cost, city, stops ] = minHeap.dequeue().element; + const [cost, city, stops] = minHeap.dequeue().element; seen.set(city, stops); - const isTarget = (city === dst); + const isTarget = city === dst; if (isTarget) return cost; - const canSkip = (stops <= 0); + const canSkip = stops <= 0; if (canSkip) continue; checkNeighbors(graph, cost, city, stops, seen, minHeap); } return -1; -} +}; var checkNeighbors = (graph, cost, city, stops, seen, minHeap) => { - for (let [ nextCity, nextCost ] of graph[city]) { - const hasSeen = (seen.has(nextCity) && ((stops - 1) <= seen.get(nextCity))); + for (let [nextCity, nextCost] of graph[city]) { + const hasSeen = seen.has(nextCity) && stops - 1 <= seen.get(nextCity); if (hasSeen) continue; - const priority = (cost + nextCost) - const node = [ priority, nextCity, (stops - 1)]; + const priority = cost + nextCost; + const node = [priority, nextCity, stops - 1]; minHeap.enqueue(node, priority); } -} \ No newline at end of file +}; diff --git a/javascript/0837-new-21-game.js b/javascript/0837-new-21-game.js index 375d086a4..52279bf67 100644 --- a/javascript/0837-new-21-game.js +++ b/javascript/0837-new-21-game.js @@ -5,30 +5,30 @@ * @param {number} maxPts * @return {number} */ -var new21Game = function(n, k, maxPts) { - if (k == 0) { - return 1 - } +var new21Game = function (n, k, maxPts) { + if (k == 0) { + return 1; + } - let windowSum = 0 - for (let i = k; i < k + maxPts; i++) { - if (i <= n) { - windowSum += 1 + let windowSum = 0; + for (let i = k; i < k + maxPts; i++) { + if (i <= n) { + windowSum += 1; + } } - } - let dp = {} - for (let i = k - 1; i >= 0; i--) { - dp[i] = windowSum / maxPts + let dp = {}; + for (let i = k - 1; i >= 0; i--) { + dp[i] = windowSum / maxPts; - let remove = 0 - if (i + maxPts <= n) { - remove = dp[i + maxPts] || 1 - } + let remove = 0; + if (i + maxPts <= n) { + remove = dp[i + maxPts] || 1; + } - windowSum += dp[i] - windowSum -= remove - } + windowSum += dp[i]; + windowSum -= remove; + } - return dp[0] -}; \ No newline at end of file + return dp[0]; +}; diff --git a/javascript/0846-hand-of-straights.js b/javascript/0846-hand-of-straights.js index 9b7b4da05..e08caa280 100644 --- a/javascript/0846-hand-of-straights.js +++ b/javascript/0846-hand-of-straights.js @@ -5,46 +5,53 @@ * @param {number} groupSize * @return {boolean} */ - var isNStraightHand = function (hand, groupSize, count = new Map()) { - const map = getFrequencyMap(hand);/* Time O(N) | Space O(N) */ - const sortUniqHand = getUniqueHand(hand);/* Time O(N * Log(N)) | Space O(N) */ +var isNStraightHand = function (hand, groupSize, count = new Map()) { + const map = getFrequencyMap(hand); /* Time O(N) | Space O(N) */ + const sortUniqHand = + getUniqueHand(hand); /* Time O(N * Log(N)) | Space O(N) */ - return search(groupSize, map, sortUniqHand);/* Time O(N * K) */ + return search(groupSize, map, sortUniqHand); /* Time O(N * K) */ }; const getFrequencyMap = (hand, map = new Map()) => { - for (const _hand of hand) {/* Time O(N) */ + for (const _hand of hand) { + /* Time O(N) */ const val = (map.get(_hand) || 0) + 1; - map.set(_hand, val);/* Space O(N) */ + map.set(_hand, val); /* Space O(N) */ } - + return map; -} +}; -const getUniqueHand = (hand) => [ ...new Set(hand) ]/* Time O(N) | Space O(N) */ - .sort((a, b) => b - a);/* Time O(N * Log(N)) | Space HeapSort O(1) | Space QuickSort O(log(N)) */ +const getUniqueHand = (hand) => + [...new Set(hand)] /* Time O(N) | Space O(N) */ + .sort( + (a, b) => b - a, + ); /* Time O(N * Log(N)) | Space HeapSort O(1) | Space QuickSort O(log(N)) */ const search = (groupSize, map, sortUniqHand) => { - while (sortUniqHand.length) {/* Time O(N) */ + while (sortUniqHand.length) { + /* Time O(N) */ const smallest = sortUniqHand[sortUniqHand.length - 1]; - - for (let i = smallest; i < smallest + groupSize; i++) {/* Time O(K) */ + + for (let i = smallest; i < smallest + groupSize; i++) { + /* Time O(K) */ if (!map.has(i)) return false; const val = map.get(i) - 1; - + map.set(i, val); - + let isEqual = map.get(i) === 0; if (!isEqual) continue; - + isEqual = i === sortUniqHand[sortUniqHand.length - 1]; if (!isEqual) return false; sortUniqHand.pop(); } } - + return true; -} \ No newline at end of file +}; diff --git a/javascript/0853-car-fleet.js b/javascript/0853-car-fleet.js index 5d1df6710..e186bdb5f 100644 --- a/javascript/0853-car-fleet.js +++ b/javascript/0853-car-fleet.js @@ -1,63 +1,89 @@ -/** - * https://leetcode.com/problems/car-fleet - * Time O(N * log(N)) | Space O(N) - * @param {number} target - * @param {number[]} position - * @param {number[]} speed - * @return {number} - */ -var carFleet = function(target, position, speed) { - const coordinates = getCoordinates(target, position, speed); /* Time O(N * log(N)) | Space O(N) */ - - return searchAscending(coordinates); /* Time O(N) | Space O(N) */ -}; - -var getCoordinates = (target, position, speed) => position - .map((_position, index) => [ _position, speed[index] ]) /* Time O(N) | Space O(N) */ - .sort(([ aPosition ], [ bPosition ]) => aPosition - bPosition) /* Time O(N * log(N)) | HeapSort Space 0(1) | QuickSort Space O(log(N)) */ - .map(([ _position, _speed ]) => (target - _position) / _speed); /* Time O(N) | Space O(N) */ - -var searchAscending = (coordinates, stack = []) => { - for (const coordinate of coordinates) { /* Time O(N + N) */ - shrink(coordinate, stack); /* Time O(N + N) */ - stack.push(coordinate); /* Space O(N) */ - } - - return stack.length; -} - -const shrink = (coordinate, stack) => { - const isPreviousLess = () => stack[stack.length - 1] <= coordinate; - while (stack.length && isPreviousLess()) stack.pop(); /* Time O(N + N) */ -} - -/** - * https://leetcode.com/problems/car-fleet - * Time O(N * log(N)) | Space O(N) - * @param {number} target - * @param {number[]} position - * @param {number[]} speed - * @return {number} - */ - var carFleet = function(target, position, speed) { - const coordinates = getCoordinates(target, position, speed); /* Time O(N * log(N)) | Space O(N) */ - - return searchDescending(coordinates); /* Time O(N) */ -}; - -var getCoordinates = (target, position, speed) => position - .map((_position, index) => [ _position, speed[index] ]) /* Time O(N) | Space O(N) */ - .sort(([ aPosition ], [ bPosition ]) => bPosition - aPosition) /* Time O(N * log(N)) | HeapSort Space 0(1) | QuickSort Space O(log(N)) */ - .map(([ _position, _speed ]) => (target - _position) / _speed);/* Time O(N) | Space O(N) */ - -var searchDescending = (coordinates, previous = 0, fleets = 0) => { - for (const coordinate of coordinates) { /* Time O(N) */ - const isPreviousLess = previous < coordinate - if (!isPreviousLess) continue - - previous = coordinate - fleets++ - } - - return fleets; -} \ No newline at end of file +/** + * https://leetcode.com/problems/car-fleet + * Time O(N * log(N)) | Space O(N) + * @param {number} target + * @param {number[]} position + * @param {number[]} speed + * @return {number} + */ +var carFleet = function (target, position, speed) { + const coordinates = getCoordinates( + target, + position, + speed, + ); /* Time O(N * log(N)) | Space O(N) */ + + return searchAscending(coordinates); /* Time O(N) | Space O(N) */ +}; + +var getCoordinates = (target, position, speed) => + position + .map((_position, index) => [ + _position, + speed[index], + ]) /* Time O(N) | Space O(N) */ + .sort( + ([aPosition], [bPosition]) => aPosition - bPosition, + ) /* Time O(N * log(N)) | HeapSort Space 0(1) | QuickSort Space O(log(N)) */ + .map( + ([_position, _speed]) => (target - _position) / _speed, + ); /* Time O(N) | Space O(N) */ + +var searchAscending = (coordinates, stack = []) => { + for (const coordinate of coordinates) { + /* Time O(N + N) */ + shrink(coordinate, stack); /* Time O(N + N) */ + stack.push(coordinate); /* Space O(N) */ + } + + return stack.length; +}; + +const shrink = (coordinate, stack) => { + const isPreviousLess = () => stack[stack.length - 1] <= coordinate; + while (stack.length && isPreviousLess()) stack.pop(); /* Time O(N + N) */ +}; + +/** + * https://leetcode.com/problems/car-fleet + * Time O(N * log(N)) | Space O(N) + * @param {number} target + * @param {number[]} position + * @param {number[]} speed + * @return {number} + */ +var carFleet = function (target, position, speed) { + const coordinates = getCoordinates( + target, + position, + speed, + ); /* Time O(N * log(N)) | Space O(N) */ + + return searchDescending(coordinates); /* Time O(N) */ +}; + +var getCoordinates = (target, position, speed) => + position + .map((_position, index) => [ + _position, + speed[index], + ]) /* Time O(N) | Space O(N) */ + .sort( + ([aPosition], [bPosition]) => bPosition - aPosition, + ) /* Time O(N * log(N)) | HeapSort Space 0(1) | QuickSort Space O(log(N)) */ + .map( + ([_position, _speed]) => (target - _position) / _speed, + ); /* Time O(N) | Space O(N) */ + +var searchDescending = (coordinates, previous = 0, fleets = 0) => { + for (const coordinate of coordinates) { + /* Time O(N) */ + const isPreviousLess = previous < coordinate; + if (!isPreviousLess) continue; + + previous = coordinate; + fleets++; + } + + return fleets; +}; diff --git a/javascript/0861-score-after-flipping-matrix.js b/javascript/0861-score-after-flipping-matrix.js index f2d9e9e40..d6c549091 100644 --- a/javascript/0861-score-after-flipping-matrix.js +++ b/javascript/0861-score-after-flipping-matrix.js @@ -5,13 +5,11 @@ * @param {number[][]} grid * @return {number} */ -var matrixScore = function(grid) { - +var matrixScore = function (grid) { const ROW = grid[0].length; const COL = grid.length; const countZeros = (col) => { - let start = 0; let count = 0; while (start < COL) { @@ -20,7 +18,7 @@ var matrixScore = function(grid) { } return count; - } + }; const flip = (i, isRow) => { let start = 0; @@ -40,12 +38,12 @@ var matrixScore = function(grid) { } return; } - } + }; for (let i = 0; i < COL; i++) { if (!grid[i][0]) flip(i, true); - for (let j = (grid[i][0] && 1); j < ROW; j++) { + for (let j = grid[i][0] && 1; j < ROW; j++) { const numberOfZeros = countZeros(j); if (numberOfZeros > COL - numberOfZeros) { flip(j, false); @@ -55,7 +53,7 @@ var matrixScore = function(grid) { let total = 0; for (let i = 0; i < COL; i++) { - total += parseInt(grid[i].join(""), 2); + total += parseInt(grid[i].join(''), 2); } return total; diff --git a/javascript/0872-leaf-similar-trees.js b/javascript/0872-leaf-similar-trees.js index b600b3351..5e5a93e88 100644 --- a/javascript/0872-leaf-similar-trees.js +++ b/javascript/0872-leaf-similar-trees.js @@ -14,8 +14,7 @@ * @param {TreeNode} root2 * @return {boolean} */ -var leafSimilar = function(root1, root2) { - +var leafSimilar = function (root1, root2) { const dfs = (node, arr) => { if (!node.left && !node.right) { arr.push(node.val); @@ -25,7 +24,7 @@ var leafSimilar = function(root1, root2) { if (node.right) dfs(node.right, arr); return arr; - } + }; const arr1 = dfs(root1, []); const arr2 = dfs(root2, []); diff --git a/javascript/0894-all-possible-full-binary-trees.js b/javascript/0894-all-possible-full-binary-trees.js index 76b52ae33..750c60e7a 100644 --- a/javascript/0894-all-possible-full-binary-trees.js +++ b/javascript/0894-all-possible-full-binary-trees.js @@ -13,25 +13,23 @@ * @param {number} n * @return {TreeNode[]} */ -var allPossibleFBT = function(n) { - +var allPossibleFBT = function (n) { // even number of nodes can't make a full binary tree. - if(!(n % 2)) return []; + if (!(n % 2)) return []; const dfs = (n) => { - if(n === 1) return [new TreeNode(0)]; + if (n === 1) return [new TreeNode(0)]; const allPossibleTrees = []; - for(let i = 1; i < n; i += 2) { - + for (let i = 1; i < n; i += 2) { const leftNumOfNodes = i; const rightNumOfNodes = n - i - 1; const leftTrees = dfs(leftNumOfNodes); const rightTrees = dfs(rightNumOfNodes); - for(let i = 0; i < leftTrees.length; i++) { - for(let j = 0; j < rightTrees.length; j++) { + for (let i = 0; i < leftTrees.length; i++) { + for (let j = 0; j < rightTrees.length; j++) { const root = new TreeNode(0, leftTrees[i], rightTrees[j]); allPossibleTrees.push(root); } @@ -39,7 +37,7 @@ var allPossibleFBT = function(n) { } return allPossibleTrees; - } + }; return dfs(n); }; diff --git a/javascript/0901-online-stock-span.js b/javascript/0901-online-stock-span.js index 7b23c590d..ef446b34f 100644 --- a/javascript/0901-online-stock-span.js +++ b/javascript/0901-online-stock-span.js @@ -1,36 +1,36 @@ //https://leetcode.com/problems/online-stock-span/ class StockSpanner { constructor() { - this.stack = []; + this.stack = []; } - + // Time O(1) | Space O(1) isEmpty() { - return this.stack.length === 0; + return this.stack.length === 0; } - + // Time O(1) | Space O(1) peek() { - return this.isEmpty() ? null : this.stack[this.stack.length - 1]; + return this.isEmpty() ? null : this.stack[this.stack.length - 1]; } - + // Time O(1) | Space O(1) push(val) { - return this.stack.push(val); + return this.stack.push(val); } - + // Time O(1) | Space O(1) pop() { - return this.stack.pop(); + return this.stack.pop(); } - + // Time O(n) | Space O(1) next(price) { - let currunt = 1; - while (this.peek() && this.peek()[0] <= price) { - currunt += this.pop()[1]; - } - this.push([price, currunt]); - return this.peek()[1]; + let currunt = 1; + while (this.peek() && this.peek()[0] <= price) { + currunt += this.pop()[1]; + } + this.push([price, currunt]); + return this.peek()[1]; } - } +} diff --git a/javascript/0909-snakes-and-ladders.js b/javascript/0909-snakes-and-ladders.js index b00e525cf..d1386c404 100644 --- a/javascript/0909-snakes-and-ladders.js +++ b/javascript/0909-snakes-and-ladders.js @@ -2,29 +2,29 @@ * @param {number[][]} board * @return {number} */ -var snakesAndLadders = function(board) { +var snakesAndLadders = function (board) { let n = board.length; let set = new Set(); let getPos = (pos) => { - let row = Math.floor((pos - 1) / n) - let col = (pos - 1) % n + let row = Math.floor((pos - 1) / n); + let col = (pos - 1) % n; col = row % 2 == 1 ? n - 1 - col : col; row = n - 1 - row; - return [row, col] - } - let q = [[1, 0]] - while (q.length > 0){ + return [row, col]; + }; + let q = [[1, 0]]; + while (q.length > 0) { [pos, moves] = q.shift(); - for (let i = 1; i < 7; i++){ + for (let i = 1; i < 7; i++) { let newPos = i + pos; let [r, c] = getPos(newPos); - if (board[r][c] != -1 ) newPos = board[r][c] + if (board[r][c] != -1) newPos = board[r][c]; if (newPos == n * n) return moves + 1; if (!set.has(newPos)) { - set.add(newPos) - q.push([newPos, moves + 1]) + set.add(newPos); + q.push([newPos, moves + 1]); } } } - return -1 + return -1; }; diff --git a/javascript/0912-sort-an-array.js b/javascript/0912-sort-an-array.js index 2a9fc4274..399a27881 100644 --- a/javascript/0912-sort-an-array.js +++ b/javascript/0912-sort-an-array.js @@ -5,30 +5,29 @@ * @param {number[]} nums * @return {number[]} */ -const sortArray = function(nums) { - return mergeSort(0, nums.length - 1, nums); -}; +const sortArray = function (nums) { + return mergeSort(0, nums.length - 1, nums); +}; const mergeSort = (left, right, nums) => { + if (left === right) return nums; - if(left === right) return nums; - - const mid = Math.floor((left+right)/2); + const mid = Math.floor((left + right) / 2); mergeSort(left, mid, nums); - mergeSort(mid+1, right, nums); + mergeSort(mid + 1, right, nums); return merge(left, right, mid, nums); -} +}; const merge = (left, right, mid, nums) => { - const arr1 = nums.slice(left, mid+1); - const arr2 = nums.slice(mid+1, right + 1); - - let p1 = 0; + const arr1 = nums.slice(left, mid + 1); + const arr2 = nums.slice(mid + 1, right + 1); + + let p1 = 0; let p2 = 0; let gp = left; - while(p1 < arr1.length && p2 < arr2.length) { - if(arr1[p1] < arr2[p2]) { + while (p1 < arr1.length && p2 < arr2.length) { + if (arr1[p1] < arr2[p2]) { nums[gp] = arr1[p1]; p1++; } else { @@ -38,16 +37,16 @@ const merge = (left, right, mid, nums) => { gp++; } - while(p1 < arr1.length) { + while (p1 < arr1.length) { nums[gp] = arr1[p1]; p1++; gp++; } - while(p2 < arr2.length) { + while (p2 < arr2.length) { nums[gp] = arr2[p2]; p2++; gp++; } return nums; -} +}; diff --git a/javascript/0929-unique-email-addresses.js b/javascript/0929-unique-email-addresses.js index bd9b09a09..3c21d81be 100644 --- a/javascript/0929-unique-email-addresses.js +++ b/javascript/0929-unique-email-addresses.js @@ -7,14 +7,12 @@ * @return {number} */ var numUniqueEmails = function (emails) { - const valid = emails.map(email => { - const [local, domain] = email.split("@"); - return ( - local.split("+").shift().split(".").join("") + "@" + domain - ); - }); + const valid = emails.map((email) => { + const [local, domain] = email.split('@'); + return local.split('+').shift().split('.').join('') + '@' + domain; + }); - return new Set(valid).size; + return new Set(valid).size; }; /** @@ -26,25 +24,25 @@ var numUniqueEmails = function (emails) { * @return {number} */ var numUniqueEmails = function (emails) { - const uniqEmails = new Set(); + const uniqEmails = new Set(); - for (let email of emails) { - let cleanEmail = ""; - for (let i = 0; i < email.length; i++) { - if (email[i] === "@") { - cleanEmail += email.slice(i); - break; - } else if (email[i] === "+") { - while (email[i] !== "@") i++; - cleanEmail += email.slice(i); - break; - } else if (email[i] !== ".") { - cleanEmail += email[i]; - } - } + for (let email of emails) { + let cleanEmail = ''; + for (let i = 0; i < email.length; i++) { + if (email[i] === '@') { + cleanEmail += email.slice(i); + break; + } else if (email[i] === '+') { + while (email[i] !== '@') i++; + cleanEmail += email.slice(i); + break; + } else if (email[i] !== '.') { + cleanEmail += email[i]; + } + } - uniqEmails.add(cleanEmail); - } + uniqEmails.add(cleanEmail); + } - return uniqEmails.size; + return uniqEmails.size; }; diff --git a/javascript/0934-shortest-bridge.js b/javascript/0934-shortest-bridge.js index f2452d428..df3440eaf 100644 --- a/javascript/0934-shortest-bridge.js +++ b/javascript/0934-shortest-bridge.js @@ -1,70 +1,81 @@ -const DIRECTIONS = [[-1, 0], [1, 0], [0, -1], [0, 1]]; +const DIRECTIONS = [ + [-1, 0], + [1, 0], + [0, -1], + [0, 1], +]; const shortestBridge = (grid) => { - const rows = grid.length; - const cols = grid[0].length; + const rows = grid.length; + const cols = grid[0].length; - let queue = []; + let queue = []; - const exploreIslandDFS = (row, col) => { - if (row < 0 || row >= rows || col < 0 || col >= cols || grid[row][col] !== 1) { - return false; - } + const exploreIslandDFS = (row, col) => { + if ( + row < 0 || + row >= rows || + col < 0 || + col >= cols || + grid[row][col] !== 1 + ) { + return false; + } + + queue.push([row, col]); + grid[row][col] = 2; - queue.push([row, col]); - grid[row][col] = 2; + exploreIslandDFS(row - 1, col); + exploreIslandDFS(row + 1, col); + exploreIslandDFS(row, col - 1); + exploreIslandDFS(row, col + 1); - exploreIslandDFS(row - 1, col); - exploreIslandDFS(row + 1, col); - exploreIslandDFS(row, col - 1); - exploreIslandDFS(row, col + 1); + return true; + }; - return true; - }; + const buildBridgeBFS = () => { + let distance = -1; + let currentQueue = []; - const buildBridgeBFS = () => { - let distance = -1; - let currentQueue = []; + while (queue.length) { + currentQueue = queue; + queue = []; - while (queue.length) { - currentQueue = queue; - queue = []; + for (let [row, col] of currentQueue) { + for (let [dx, dy] of DIRECTIONS) { + const nextRow = row + dx; + const nextCol = col + dy; - for (let [row, col] of currentQueue) { - for (let [dx, dy] of DIRECTIONS) { - const nextRow = row + dx; - const nextCol = col + dy; + if ( + nextRow >= 0 && + nextRow < rows && + nextCol >= 0 && + nextCol < cols && + grid[nextRow][nextCol] !== 2 + ) { + if (grid[nextRow][nextCol] === 1) { + return distance + 1; + } - if ( - nextRow >= 0 && - nextRow < rows && - nextCol >= 0 && - nextCol < cols && - grid[nextRow][nextCol] !== 2 - ) { - if (grid[nextRow][nextCol] === 1) { - return distance + 1; + queue.push([nextRow, nextCol]); + grid[nextRow][nextCol] = 2; + } + } } - queue.push([nextRow, nextCol]); - grid[nextRow][nextCol] = 2; - } + distance++; } - } - distance++; - } + return -1; + }; - return -1; - }; - - for (let i = 0; i < rows; i++) { - for (let j = 0; j < cols; j++) { - if (exploreIslandDFS(i, j)) { - return buildBridgeBFS(); - } + for (let i = 0; i < rows; i++) { + for (let j = 0; j < cols; j++) { + if (exploreIslandDFS(i, j)) { + return buildBridgeBFS(); + } + } } - } - return -1; -}; \ No newline at end of file + return -1; +}; diff --git a/javascript/0937-k-closest-points-to-origin.js b/javascript/0937-k-closest-points-to-origin.js index 03d1b738e..abe2b8350 100644 --- a/javascript/0937-k-closest-points-to-origin.js +++ b/javascript/0937-k-closest-points-to-origin.js @@ -5,8 +5,8 @@ * @param {number} k * @return {number[][]} */ - var kClosest = function(points, K) { - const distance = ([x, y]) => (x * x) + (y * y); +var kClosest = function (points, K) { + const distance = ([x, y]) => x * x + y * y; points.sort((a, b) => distance(a) - distance(b)); @@ -20,38 +20,42 @@ * @param {number} k * @return {number[][]} */ -var kClosest = function(points, K) { - const [ left, right ] = [ 0, (points.length - 1) ]; +var kClosest = function (points, K) { + const [left, right] = [0, points.length - 1]; quickSelect(points, K, left, right); - return points.slice(0, K) + return points.slice(0, K); }; const quickSelect = (points, target, left, right) => { const mid = getMid(points, left, right); - const isTarget = mid === (target - 1); + const isTarget = mid === target - 1; if (isTarget) return; - - const isTargetGreater = mid < (target - 1); - if (isTargetGreater) quickSelect(points, target, (mid + 1), right); - - const isTargetLess = (target - 1) < mid; - if (isTargetLess) quickSelect(points, target, left, (mid - 1)); -} -const swap = (points, left, right) => [ points[left], points[right] ] = [ points[right], points[left] ]; + const isTargetGreater = mid < target - 1; + if (isTargetGreater) quickSelect(points, target, mid + 1, right); + + const isTargetLess = target - 1 < mid; + if (isTargetLess) quickSelect(points, target, left, mid - 1); +}; + +const swap = (points, left, right) => + ([points[left], points[right]] = [points[right], points[left]]); -const squareRoot = ([ x, y ]) => ((x * x) + (y * y)); +const squareRoot = ([x, y]) => x * x + y * y; const getMid = (points, left, right) => { let mid = left; while (left < right) { - const [ leftDistance, rightDistance ] = [ squareRoot(points[left]), squareRoot(points[right]) ]; + const [leftDistance, rightDistance] = [ + squareRoot(points[left]), + squareRoot(points[right]), + ]; - const canSwapMid = leftDistance <= rightDistance + const canSwapMid = leftDistance <= rightDistance; if (canSwapMid) { swap(points, left, mid); mid++; @@ -63,7 +67,7 @@ const getMid = (points, left, right) => { swap(points, mid, right); return mid; -} +}; /** * https://leetcode.com/problems/k-closest-points-to-origin/ @@ -72,8 +76,10 @@ const getMid = (points, left, right) => { * @param {number} k * @return {number[][]} */ -var kClosest = function(points, k) { - const maxHeap = new MaxPriorityQueue({ priority: (point) => distance(point) }) +var kClosest = function (points, k) { + const maxHeap = new MaxPriorityQueue({ + priority: (point) => distance(point), + }); for (const point of points) { const isUnderCapacity = maxHeap.size() < k; @@ -89,9 +95,7 @@ var kClosest = function(points, k) { } } - return maxHeap - .toArray() - .map(({ element }) => element); -} + return maxHeap.toArray().map(({ element }) => element); +}; -const distance = ([ x, y ]) => (x * x) + (y * y); \ No newline at end of file +const distance = ([x, y]) => x * x + y * y; diff --git a/javascript/0938-range-sum-of-bst.js b/javascript/0938-range-sum-of-bst.js index 7fa56e034..c8e7ae8ba 100644 --- a/javascript/0938-range-sum-of-bst.js +++ b/javascript/0938-range-sum-of-bst.js @@ -10,14 +10,13 @@ * DFS | Recursion * Time O(n) | Space O(n) * https://leetcode.com/problems/range-sum-of-bst - * + * * @param {TreeNode} root * @param {number} low * @param {number} high * @return {number} */ -var rangeSumBST = function(root, low, high) { - +var rangeSumBST = function (root, low, high) { let total = 0; const dfs = (node) => { @@ -25,7 +24,7 @@ var rangeSumBST = function(root, low, high) { if (node.val >= low && node.val <= high) total += node.val; dfs(node.left); dfs(node.right); - } + }; dfs(root); return total; }; diff --git a/javascript/0951-flip-equivalent-binary-trees.js b/javascript/0951-flip-equivalent-binary-trees.js index d9f061112..b75b28754 100644 --- a/javascript/0951-flip-equivalent-binary-trees.js +++ b/javascript/0951-flip-equivalent-binary-trees.js @@ -14,13 +14,12 @@ * @param {TreeNode} root2 * @return {boolean} */ -var flipEquiv = function(root1, root2) { - +var flipEquiv = function (root1, root2) { const dfs = (node1, node2) => { if (!node1 && !node2) return true; if (!node1) return false; if (!node2) return false; - + if (node1.val !== node2.val) return false; if ((node1.left && node1.left.val) !== (node2.left && node2.left.val)) { @@ -28,7 +27,7 @@ var flipEquiv = function(root1, root2) { } return dfs(node1.left, node2.left) && dfs(node1.right, node2.right); - } + }; return dfs(root1, root2); }; diff --git a/javascript/0953-verifying-an-alien-dictionary.js b/javascript/0953-verifying-an-alien-dictionary.js index 511086dc1..c93c87dc0 100644 --- a/javascript/0953-verifying-an-alien-dictionary.js +++ b/javascript/0953-verifying-an-alien-dictionary.js @@ -1,24 +1,23 @@ -var isAlienSorted = function(words, order) { +var isAlienSorted = function (words, order) { // first differing char // if word A is prefix of word B, word B must be AFTER word A - orderInd = new Map(); { + orderInd = new Map(); + { let ind = 0; - for(const c of order) - orderInd.set(c, ind++); + for (const c of order) orderInd.set(c, ind++); } - - for(let i = 0; i < words.length - 1; i++) { - let w1 = words[i], w2 = words[i + 1]; - - for(let j = 0; j < w1.length; j++) { - if(j == w2.length) - return false; - - if(w1.charAt(j) != w2.charAt(j)) - if(orderInd.get(w2.charAt(j)) < orderInd.get(w1.charAt(j))) + + for (let i = 0; i < words.length - 1; i++) { + let w1 = words[i], + w2 = words[i + 1]; + + for (let j = 0; j < w1.length; j++) { + if (j == w2.length) return false; + + if (w1.charAt(j) != w2.charAt(j)) + if (orderInd.get(w2.charAt(j)) < orderInd.get(w1.charAt(j))) return false; - else - break; + else break; } } return true; diff --git a/javascript/0958-check-completeness-of-a-binary-tree.js b/javascript/0958-check-completeness-of-a-binary-tree.js index 51b8b68e3..e3e4191df 100644 --- a/javascript/0958-check-completeness-of-a-binary-tree.js +++ b/javascript/0958-check-completeness-of-a-binary-tree.js @@ -13,16 +13,15 @@ * @param {TreeNode} root * @return {boolean} */ -var isCompleteTree = function(root) { - +var isCompleteTree = function (root) { // get the depth of the tree // bfs until n-1 level of depth const getDepth = (node) => { if (!node) return 0; return 1 + Math.max(getDepth(node.left), getDepth(node.right)); - } - + }; + const depth = getDepth(root) - 1; const q = new Queue(); @@ -38,14 +37,13 @@ var isCompleteTree = function(root) { } return true; - } + }; let i = 0; while (i < depth) { - let size = q.size(); - if (size !== 2**i) return false; + if (size !== 2 ** i) return false; while (size) { const node = q.dequeue(); @@ -56,7 +54,6 @@ var isCompleteTree = function(root) { q.enqueue(node.left); q.enqueue(node.right); } else { - if (!node.left) { q.enqueue(null); } else { @@ -68,14 +65,13 @@ var isCompleteTree = function(root) { } else { q.enqueue(node.right); } - } - + size--; } i++; } - + return checkLastLevel(q.toArray()); }; diff --git a/javascript/0978-longest-turbulent-subarray.js b/javascript/0978-longest-turbulent-subarray.js index ff06ee4ca..422468015 100644 --- a/javascript/0978-longest-turbulent-subarray.js +++ b/javascript/0978-longest-turbulent-subarray.js @@ -5,10 +5,8 @@ * @param {number[]} arr * @return {number} */ -var maxTurbulenceSize = function(arr) { - +var maxTurbulenceSize = function (arr) { const higherAndLower = (start) => { - let i = start; let shouldBeLow = true; @@ -21,12 +19,9 @@ var maxTurbulenceSize = function(arr) { } return i; - - } + }; const lowerAndHigher = (start) => { - - let i = start; let shouldBeHigh = true; @@ -39,15 +34,13 @@ var maxTurbulenceSize = function(arr) { } return i; - } - + }; let left = 0; let right = 1; let max = 1; while (right < arr.length) { - if (arr[left] > arr[right]) { right = higherAndLower(left); max = Math.max(right - left + 1, max); @@ -68,7 +61,6 @@ var maxTurbulenceSize = function(arr) { left++; right++; } - } return max; diff --git a/javascript/0988-smallest-string-starting-from-leaf.js b/javascript/0988-smallest-string-starting-from-leaf.js index 4d2c57a0e..7eb0ace35 100644 --- a/javascript/0988-smallest-string-starting-from-leaf.js +++ b/javascript/0988-smallest-string-starting-from-leaf.js @@ -13,25 +13,22 @@ * @param {TreeNode} root * @return {string} */ -var smallestFromLeaf = function(root) { - - let biggestStr = new Array(8500).fill("z"); - biggestStr = biggestStr.join(""); +var smallestFromLeaf = function (root) { + let biggestStr = new Array(8500).fill('z'); + biggestStr = biggestStr.join(''); let smallest = biggestStr; const dfs = (node, str) => { - - const char = String.fromCharCode(node.val+97); + const char = String.fromCharCode(node.val + 97); if (!node.left && !node.right) { str.push(char); - const str1 = str.slice(0).reverse().join(""); + const str1 = str.slice(0).reverse().join(''); if (str1 < smallest) { smallest = str1; } str.pop(); return; - } if (node.left) { @@ -44,10 +41,10 @@ var smallestFromLeaf = function(root) { str.push(char); dfs(node.right, str); str.pop(); - } - } + } + }; - dfs(root,[]); + dfs(root, []); return smallest; }; diff --git a/javascript/0994-rotting-oranges.js b/javascript/0994-rotting-oranges.js index abeea84e9..40d110b25 100644 --- a/javascript/0994-rotting-oranges.js +++ b/javascript/0994-rotting-oranges.js @@ -4,37 +4,38 @@ * @param {number[][]} grid * @return {number} */ -var orangesRotting = function(grid) { - const { queue, orangeCount } = searchGrid(grid); /* Time O(ROWS * COLS) */ +var orangesRotting = function (grid) { + const { queue, orangeCount } = searchGrid(grid); /* Time O(ROWS * COLS) */ const { rottenCount, minutes } = bfs(grid, queue); const isEqual = orangeCount === rottenCount; - return isEqual - ? minutes - : -1; + return isEqual ? minutes : -1; }; const searchGrid = (grid, orangeCount = 0, queue = new Queue([])) => { - const [ rows, cols ] = [ grid.length, grid[0].length ]; + const [rows, cols] = [grid.length, grid[0].length]; - for (let row = 0; row < rows; row++){/* Time O(ROWS) */ - for (let col = 0; col < cols; col++) {/* Time O(COLS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ const isEmpty = grid[row][col] === 0; if (!isEmpty) orangeCount++; const isRotten = grid[row][col] === 2; - if (isRotten) queue.enqueue([ row, col ]);/* Space O(ROWS * COLS) */ + if (isRotten) queue.enqueue([row, col]); /* Space O(ROWS * COLS) */ } } - return { queue, orangeCount } -} + return { queue, orangeCount }; +}; const bfs = (grid, queue, rottenCount = 0, minutes = 0) => { while (!queue.isEmpty()) { rottenCount += queue.size(); - for (let i = (queue.size() - 1); 0 <= i; i--) {/* Time O(WIDTH) */ + for (let i = queue.size() - 1; 0 <= i; i--) { + /* Time O(WIDTH) */ expireFresh(grid, queue); } @@ -42,24 +43,33 @@ const bfs = (grid, queue, rottenCount = 0, minutes = 0) => { } return { rottenCount, minutes }; -} +}; var expireFresh = (grid, queue) => { - const [ rows, cols ] = [ grid.length, grid[0].length ]; - const [ row, col ] = queue.dequeue(); + const [rows, cols] = [grid.length, grid[0].length]; + const [row, col] = queue.dequeue(); - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) { + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { const isFresh = grid[_row][_col] === 1; if (!isFresh) continue; grid[_row][_col] = 2; - queue.enqueue([ _row, _col ]);/* Space O(ROWS * COLS) */ + queue.enqueue([_row, _col]); /* Space O(ROWS * COLS) */ } -} +}; -var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ],[ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ] - .map(([ _row, _col ]) => [ (row + _row), (col + _col) ]) - .filter(([ _row, _col ]) => (0 <= _row) && (_row < rows) && (0 <= _col) && (_col < cols)); +var getNeighbors = (row, rows, col, cols) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + .map(([_row, _col]) => [row + _row, col + _col]) + .filter( + ([_row, _col]) => + 0 <= _row && _row < rows && 0 <= _col && _col < cols, + ); /** * https://leetcode.com/problems/rotting-oranges/ @@ -67,46 +77,57 @@ var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ],[ 0, -1 ], [ 1, 0 ], [ - * @param {number[][]} grid * @return {number} */ -var orangesRotting = function(grid, minutes = 2) { - while (expireFresh(grid, minutes)) minutes++;/* Time O((ROWS * COLS)^2) */ +var orangesRotting = function (grid, minutes = 2) { + while (expireFresh(grid, minutes)) minutes++; /* Time O((ROWS * COLS)^2) */ - return !hasFresh(grid) /* Time O(ROWS * COLS) */ - ? (minutes - 2) - : -1; -} + return !hasFresh(grid) /* Time O(ROWS * COLS) */ ? minutes - 2 : -1; +}; var expireFresh = (grid, minutes, toBeContinued = false) => { - const [ rows, cols ] = [ grid.length, grid[0].length ]; + const [rows, cols] = [grid.length, grid[0].length]; - for (let row = 0; row < rows; row++) {/* Time O(ROWS) */ - for (let col = 0; col < cols; col++) {/* Time O(COLS) */ + for (let row = 0; row < rows; row++) { + /* Time O(ROWS) */ + for (let col = 0; col < cols; col++) { + /* Time O(COLS) */ const isEqual = grid[row][col] === minutes; if (!isEqual) continue; - for (const [ _row, _col ] of getNeighbors(row, rows, col, cols)) { + for (const [_row, _col] of getNeighbors(row, rows, col, cols)) { const isFresh = grid[_row][_col] === 1; if (!isFresh) continue; - grid[_row][_col] = (minutes + 1); + grid[_row][_col] = minutes + 1; toBeContinued = true; } } } return toBeContinued; -} +}; -var getNeighbors = (row, rows, col, cols) => [ [ 0, 1 ],[ 0, -1 ], [ 1, 0 ], [ -1, 0 ] ] - .map(([ _row, _col ]) => [ (row + _row), (col + _col) ]) - .filter(([ _row, _col ]) => (0 <= _row) && (_row < rows) && (0 <= _col) && (_col < cols)); +var getNeighbors = (row, rows, col, cols) => + [ + [0, 1], + [0, -1], + [1, 0], + [-1, 0], + ] + .map(([_row, _col]) => [row + _row, col + _col]) + .filter( + ([_row, _col]) => + 0 <= _row && _row < rows && 0 <= _col && _col < cols, + ); const hasFresh = (grid) => { - for (const row of grid) {/* Time O(ROWS) */ - for (const cell of row) {/* Time O(COLS) */ + for (const row of grid) { + /* Time O(ROWS) */ + for (const cell of row) { + /* Time O(COLS) */ const isFresh = cell === 1; if (isFresh) return true; } } return false; -} \ No newline at end of file +}; diff --git a/javascript/1071-greatest-common-divisor-of-strings.js b/javascript/1071-greatest-common-divisor-of-strings.js index afc7af93c..e9d9b8fb4 100644 --- a/javascript/1071-greatest-common-divisor-of-strings.js +++ b/javascript/1071-greatest-common-divisor-of-strings.js @@ -4,25 +4,26 @@ * @return {string} */ var gcdOfStrings = function (str1, str2) { - let [len1, len2] = [str1.length, str2.length]; + let [len1, len2] = [str1.length, str2.length]; - function isDivisor(l) { - if (len1 % l || len2 % l) { - return false; - } + function isDivisor(l) { + if (len1 % l || len2 % l) { + return false; + } - let [f1, f2] = [Math.floor(len1 / l), Math.floor(len2 / l)]; + let [f1, f2] = [Math.floor(len1 / l), Math.floor(len2 / l)]; - return ( - str1.slice(0, l).repeat(f1) == str1 && str1.slice(0, l).repeat(f2) == str2 - ); - } + return ( + str1.slice(0, l).repeat(f1) == str1 && + str1.slice(0, l).repeat(f2) == str2 + ); + } - for (let l = Math.min(len1, len2); l > 0; l--) { - if (isDivisor(l)) { - return str1.slice(0, l); + for (let l = Math.min(len1, len2); l > 0; l--) { + if (isDivisor(l)) { + return str1.slice(0, l); + } } - } - return ""; + return ''; }; diff --git a/javascript/1094-car-pooling.js b/javascript/1094-car-pooling.js index da6dfc6fe..cbb123682 100644 --- a/javascript/1094-car-pooling.js +++ b/javascript/1094-car-pooling.js @@ -6,12 +6,11 @@ * @param {number} capacity * @return {boolean} */ -var carPooling = function(trips, capacity) { - +var carPooling = function (trips, capacity) { const minQ = new MinPriorityQueue({ compare: (e1, e2) => { return e1[0] - e2[0]; - } + }, }); trips.sort((a, b) => a[1] - b[1]); @@ -19,7 +18,7 @@ var carPooling = function(trips, capacity) { for (let i = 0; i < trips.length; i++) { while (!minQ.isEmpty() && minQ.front()[0] <= trips[i][1]) { capacity += minQ.dequeue()[1]; - }; + } capacity -= trips[i][0]; if (capacity < 0) return false; diff --git a/javascript/1189-maximum-number-of-balloons.js b/javascript/1189-maximum-number-of-balloons.js index 9985f763c..22f094b34 100644 --- a/javascript/1189-maximum-number-of-balloons.js +++ b/javascript/1189-maximum-number-of-balloons.js @@ -2,24 +2,24 @@ // time complexity O(n) // space complexity O(n) -var maxNumberOfBalloons = function(text) { - - const balloonCach = {}; +var maxNumberOfBalloons = function (text) { + const balloonCach = {}; const ballonSet = new Set(text.split('')); - + for (const char of text) { - if (!ballonSet.has(char)) continue; + if (!ballonSet.has(char)) continue; - const count = ((balloonCach[char] ?? 0) + 1) + const count = (balloonCach[char] ?? 0) + 1; balloonCach[char] = count; } - let min = Math.min(balloonCach['b'], - balloonCach['a'], - balloonCach['n'], - Math.floor(balloonCach['l']/2), - Math.floor(balloonCach['o']/2)); - + let min = Math.min( + balloonCach['b'], + balloonCach['a'], + balloonCach['n'], + Math.floor(balloonCach['l'] / 2), + Math.floor(balloonCach['o'] / 2), + ); + return min ? min : 0; }; - diff --git a/javascript/1260-shift-2d-grid.js b/javascript/1260-shift-2d-grid.js index 8491c15ea..1866f41b4 100644 --- a/javascript/1260-shift-2d-grid.js +++ b/javascript/1260-shift-2d-grid.js @@ -1,16 +1,14 @@ -var shiftGrid = function(grid, k) { - const M = grid.length, N = grid[0].length; - - let posToVal = (r, c) => - r * N + c; - let valToPos = (v) => - [Math.floor(v / N), v % N]; - +var shiftGrid = function (grid, k) { + const M = grid.length, + N = grid[0].length; + + let posToVal = (r, c) => r * N + c; + let valToPos = (v) => [Math.floor(v / N), v % N]; + res = []; - for(let i = 0; i < M; i++) - res.push([]); - for(let r = 0; r < M; r++) - for(let c = 0; c < N; c++) { + for (let i = 0; i < M; i++) res.push([]); + for (let r = 0; r < M; r++) + for (let c = 0; c < N; c++) { let newVal = (posToVal(r, c) + k) % (M * N); let newRC = valToPos(newVal); res[newRC[0]][newRC[1]] = grid[r][c]; diff --git a/javascript/1268-search-suggestions-system.js b/javascript/1268-search-suggestions-system.js index 513b3844d..56ad706f8 100644 --- a/javascript/1268-search-suggestions-system.js +++ b/javascript/1268-search-suggestions-system.js @@ -1,22 +1,21 @@ /** * Binary Search - * + * * Time O(n*log(n) + m*n) | Space O(m) * https://leetcode.com/problems/search-suggestions-system/description/ * @param {string[]} products * @param {string} searchWord * @return {string[][]} */ -var suggestedProducts = function(products, searchWord) { - +var suggestedProducts = function (products, searchWord) { products.sort((product1, product2) => { - if(product1 < product2) { + if (product1 < product2) { return -1; } - if(product2 < product1) { + if (product2 < product1) { return 1; } - if(product1 === product2) { + if (product1 === product2) { return 0; } }); @@ -24,20 +23,26 @@ var suggestedProducts = function(products, searchWord) { const result = []; let left = 0; let right = products.length - 1; - for(let i = 0; i < searchWord.length; i++) { + for (let i = 0; i < searchWord.length; i++) { let char = searchWord[i]; - - while(left <= right && (products[left].length - 1 < i || products[left][i] !== char)) { + + while ( + left <= right && + (products[left].length - 1 < i || products[left][i] !== char) + ) { left++; } - while(left <= right && (products[right].length - 1 < i || products[right][i] !== char)) { + while ( + left <= right && + (products[right].length - 1 < i || products[right][i] !== char) + ) { right--; } const subResult = []; const len = Math.min(right - left + 1, 3); - for(let j = 0; j < len; j++) { - subResult.push(products[left+j]); + for (let j = 0; j < len; j++) { + subResult.push(products[left + j]); } result.push(subResult); } @@ -53,34 +58,33 @@ var suggestedProducts = function(products, searchWord) { * @param {string} searchWord * @return {string[][]} */ -var suggestedProducts1 = (products, searchWord) => new Trie() - .buildTrie(products) - .searchWord(searchWord); +var suggestedProducts1 = (products, searchWord) => + new Trie().buildTrie(products).searchWord(searchWord); class Node { - constructor () { + constructor() { this.children = new Map(); this.isWord = false; } -}; +} class Trie { - constructor () { + constructor() { this.root = new Node(); } - buildTrie (products) { + buildTrie(products) { for (const word of products) { this.insert(word); } return this; } - - insert (word, { root: node } = this) { + + insert(word, { root: node } = this) { for (const char of word.split('')) { - const child = (node.children.get(char) ?? new Node()); - + const child = node.children.get(char) ?? new Node(); + node.children.set(char, child); node = child; @@ -88,38 +92,38 @@ class Trie { node.isWord = true; } - - searchWord (searchWord, buffer = [], suggestions = []) { + + searchWord(searchWord, buffer = [], suggestions = []) { for (const char of searchWord.split('')) { const prefix = this.getPrefix(buffer, char); const words = this.getSuggestions(prefix); suggestions.push(words); } - + return suggestions; } - getPrefix (buffer, char) { + getPrefix(buffer, char) { buffer.push(char); return buffer.join(''); } - - getSuggestions (prefix, words = []) { + + getSuggestions(prefix, words = []) { const node = this.getPrefixNode(prefix); - const isInvalidPrefix = (node === null); - if (isInvalidPrefix) return words - + const isInvalidPrefix = node === null; + if (isInvalidPrefix) return words; + return this.search(node, prefix, words); } - getPrefixNode (prefix, { root: node } = this) { + getPrefixNode(prefix, { root: node } = this) { for (const char of prefix.split('')) { - const child = (node.children.get(char) ?? null); + const child = node.children.get(char) ?? null; - const isLeafNode = (child === null); + const isLeafNode = child === null; if (isLeafNode) return null; node = child; @@ -128,8 +132,8 @@ class Trie { return node; } - search (node, word, words) { - const isBaseCase = (words.length === 3); + search(node, word, words) { + const isBaseCase = words.length === 3; if (isBaseCase) return words; if (node.isWord) words.push(word); @@ -137,21 +141,22 @@ class Trie { return this.dfs(node, word, words); } - dfs (node, word, words) { + dfs(node, word, words) { for (const char of this.getChars()) { - const child = (node.children.get(char) ?? null); + const child = node.children.get(char) ?? null; - const isLeafNode = (child === null); + const isLeafNode = child === null; if (isLeafNode) continue; - - this.search(child, (word + char), words); + + this.search(child, word + char, words); } return words; } - getChars () { - return new Array(26).fill() - .map((_, index) => String.fromCharCode((index + 97))); + getChars() { + return new Array(26) + .fill() + .map((_, index) => String.fromCharCode(index + 97)); } -}; +} diff --git a/javascript/1290-convert-binary-number-in-a-linked-list-to-integer.js b/javascript/1290-convert-binary-number-in-a-linked-list-to-integer.js index a3a377217..24ec6a03b 100644 --- a/javascript/1290-convert-binary-number-in-a-linked-list-to-integer.js +++ b/javascript/1290-convert-binary-number-in-a-linked-list-to-integer.js @@ -11,10 +11,11 @@ */ var getDecimalValue = function (head) { let value = 0; // initialize value to zero - while (head) { // while loop will run till head becomes null + while (head) { + // while loop will run till head becomes null value = (value << 1) | head.val; // used left shift operator (<<) and bitwise OR (|) operator returns a number from binary head = head.next; // next value of head } return value; // return the value -}; \ No newline at end of file +}; diff --git a/javascript/1323-maximum-69-number.js b/javascript/1323-maximum-69-number.js index 11dc25fe5..b1d2e1699 100644 --- a/javascript/1323-maximum-69-number.js +++ b/javascript/1323-maximum-69-number.js @@ -7,10 +7,12 @@ var maximum69Number = function (num) { let numArr = num.toString().split(''); // initialize numArr as array of num - for (let i = 0; i < numArr.length; i++) { // loop through the every element of array numArr + for (let i = 0; i < numArr.length; i++) { + // loop through the every element of array numArr - if (numArr[i] == 6) { // if current element of numArr is 6 - let arr = [...numArr] // copy numArr into arr + if (numArr[i] == 6) { + // if current element of numArr is 6 + let arr = [...numArr]; // copy numArr into arr arr.splice(i, 1, 9); // make current element arr to 9 maxArr.push(arr.join('')); // convert arr to string and push into maxArr and break the loop break; @@ -18,4 +20,4 @@ var maximum69Number = function (num) { } return Math.max(...maxArr); // return max value from maxArr -}; \ No newline at end of file +}; diff --git a/javascript/1325-delete-leaves-with-a-given-value.js b/javascript/1325-delete-leaves-with-a-given-value.js index 5b0ea13c7..1e1cd2c45 100644 --- a/javascript/1325-delete-leaves-with-a-given-value.js +++ b/javascript/1325-delete-leaves-with-a-given-value.js @@ -14,8 +14,7 @@ * @param {number} target * @return {TreeNode} */ -var removeLeafNodes = function(root, target) { - +var removeLeafNodes = function (root, target) { const dfs = (node) => { if (!node) return null; node.left = dfs(node.left); @@ -24,7 +23,7 @@ var removeLeafNodes = function(root, target) { if (node.val === target) return null; } return node; - } + }; return dfs(root); }; diff --git a/javascript/1342-number-of-steps-to-reduce-a-number-to-zero.js b/javascript/1342-number-of-steps-to-reduce-a-number-to-zero.js index c1ae9000f..848984709 100644 --- a/javascript/1342-number-of-steps-to-reduce-a-number-to-zero.js +++ b/javascript/1342-number-of-steps-to-reduce-a-number-to-zero.js @@ -5,17 +5,21 @@ var numberOfSteps = function (num) { let count = 0; // initialize count to zero let ans = num; // initialize ans to num - while (ans >= 0) { // loop the ans if anwer is greater than or equal to zero - if (ans === 0) { // if ans is zero then break while loop + while (ans >= 0) { + // loop the ans if anwer is greater than or equal to zero + if (ans === 0) { + // if ans is zero then break while loop break; } - if (ans % 2 === 0) { // if ans is even then divide it by 2 and increment count + if (ans % 2 === 0) { + // if ans is even then divide it by 2 and increment count ans /= 2; count++; - } else { // if ans is odd then decrement ans by -1 and increment count + } else { + // if ans is odd then decrement ans by -1 and increment count ans -= 1; count++; } } return count; // return the count -}; \ No newline at end of file +}; diff --git a/javascript/1343-number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold.js b/javascript/1343-number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold.js index 721595879..9278b7b71 100644 --- a/javascript/1343-number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold.js +++ b/javascript/1343-number-of-sub-arrays-of-size-k-and-average-greater-than-or-equal-to-threshold.js @@ -5,18 +5,17 @@ * @return {number} */ var numOfSubarrays = function (arr, k, threshold) { - if (arr.length < k) return 0; - let count = 0; - let sum = 0; - let L = 0; - for (let R = 0; R < arr.length; R++) { - sum += arr[R]; - if (R - L + 1 === k) { - if (sum / k >= threshold) - count += 1; - sum -= arr[L]; - L += 1; + if (arr.length < k) return 0; + let count = 0; + let sum = 0; + let L = 0; + for (let R = 0; R < arr.length; R++) { + sum += arr[R]; + if (R - L + 1 === k) { + if (sum / k >= threshold) count += 1; + sum -= arr[L]; + L += 1; + } } - } - return count; + return count; }; diff --git a/javascript/1361-validate-binary-tree-nodes.js b/javascript/1361-validate-binary-tree-nodes.js index 4a613fd39..71962efe5 100644 --- a/javascript/1361-validate-binary-tree-nodes.js +++ b/javascript/1361-validate-binary-tree-nodes.js @@ -2,41 +2,38 @@ * DFS * Time O(n) | Space O(n) * https://leetcode.com/problems/validate-binary-tree-nodes/ - * + * * @param {number} n * @param {number[]} leftChild * @param {number[]} rightChild * @return {boolean} */ -var validateBinaryTreeNodes = function(n, leftChild, rightChild) { - +var validateBinaryTreeNodes = function (n, leftChild, rightChild) { const visited = new Set(); const findRoot = () => { - - const childrenSet = new Set(); - for (let i = 0; i < n; i++) { - childrenSet.add(i); - } - - for (let i = 0; i < n; i++) { - childrenSet.delete(leftChild[i]); - childrenSet.delete(rightChild[i]); - } + const childrenSet = new Set(); + for (let i = 0; i < n; i++) { + childrenSet.add(i); + } - return [...childrenSet][0]; - } + for (let i = 0; i < n; i++) { + childrenSet.delete(leftChild[i]); + childrenSet.delete(rightChild[i]); + } - const dfs = (i) => { + return [...childrenSet][0]; + }; - if (i === -1) return true; - if (visited.has(i)) return false; + const dfs = (i) => { + if (i === -1) return true; + if (visited.has(i)) return false; - const left = leftChild[i]; - const right = rightChild[i]; - visited.add(i); - return dfs(left) && dfs(right); - } + const left = leftChild[i]; + const right = rightChild[i]; + visited.add(i); + return dfs(left) && dfs(right); + }; const root = findRoot(); return dfs(root) && visited.size === n; diff --git a/javascript/1376-time-needed-to-inform-all-employees.js b/javascript/1376-time-needed-to-inform-all-employees.js index aec42b207..5e4d6e3f9 100644 --- a/javascript/1376-time-needed-to-inform-all-employees.js +++ b/javascript/1376-time-needed-to-inform-all-employees.js @@ -1,5 +1,5 @@ /** - * DFS | Tree + * DFS | Tree * Time O(n) | Space O(n) * https://leetcode.com/problems/time-needed-to-inform-all-employees/ * @param {number} n @@ -8,11 +8,9 @@ * @param {number[]} informTime * @return {number} */ -var numOfMinutes = function(n, headID, manager, informTime) { - +var numOfMinutes = function (n, headID, manager, informTime) { const tree = {}; for (let i = 0; i < manager.length; i++) { - if (manager[i] === -1) continue; const senior = manager[i]; @@ -25,7 +23,6 @@ var numOfMinutes = function(n, headID, manager, informTime) { tree[senior].push(junior); } - let time = 0; const dfs = (node, totalTime) => { if (tree[node] === undefined) { @@ -35,11 +32,11 @@ var numOfMinutes = function(n, headID, manager, informTime) { const subordinates = tree[node]; - for (let i = 0; i < subordinates.length; i++) { + for (let i = 0; i < subordinates.length; i++) { const subordinate = subordinates[i]; dfs(subordinate, totalTime + informTime[node]); } - } + }; dfs(headID, 0); diff --git a/javascript/1383-maximum-performance-of-a-team.js b/javascript/1383-maximum-performance-of-a-team.js index 0e10a8263..364b5a2a3 100644 --- a/javascript/1383-maximum-performance-of-a-team.js +++ b/javascript/1383-maximum-performance-of-a-team.js @@ -8,13 +8,13 @@ * @param {number} k * @return {number}` */ -var maxPerformance = function(n, speed, efficiency, k) { - const mod = 10**9 + 7; +var maxPerformance = function (n, speed, efficiency, k) { + const mod = 10 ** 9 + 7; const minSpeedHeap = new MinPriorityQueue({ compare: (a, b) => { return a - b; - } + }, }); efficiency = efficiency.map((eff, idx) => { @@ -22,7 +22,7 @@ var maxPerformance = function(n, speed, efficiency, k) { }); efficiency.sort((a, b) => b[0] - a[0]); - + let speedSoFar = 0; let max = 0; @@ -36,7 +36,7 @@ var maxPerformance = function(n, speed, efficiency, k) { speedSoFar += efficiency[i][1]; const minEfficiency = efficiency[i][0]; - max = Math.max(max, (speedSoFar * minEfficiency)); + max = Math.max(max, speedSoFar * minEfficiency); minSpeedHeap.enqueue(efficiency[i][1]); } diff --git a/javascript/1396-design-underground-system.js b/javascript/1396-design-underground-system.js index 849731125..71435676f 100644 --- a/javascript/1396-design-underground-system.js +++ b/javascript/1396-design-underground-system.js @@ -1,54 +1,55 @@ // https://leetcode.com/problems/design-underground-system/ class UndergroundSystem { - constructor() { - this.stationSystem = {}; - this.averageTime = {}; - } + constructor() { + this.stationSystem = {}; + this.averageTime = {}; + } - /** - * Time O(1) | Space O(1) - * Records the check-in time and station for a user. - * @param {number} id - User ID - * @param {string} stationName - Check-in station name - * @param {number} t - Check-in time - * @return {void} - */ - checkIn(id, stationName, t) { - this.stationSystem[id] = [stationName, '', t, '']; - } + /** + * Time O(1) | Space O(1) + * Records the check-in time and station for a user. + * @param {number} id - User ID + * @param {string} stationName - Check-in station name + * @param {number} t - Check-in time + * @return {void} + */ + checkIn(id, stationName, t) { + this.stationSystem[id] = [stationName, '', t, '']; + } - /** - * Time O(1) | Space O(1) - * Records the check-out time and station for a user, and calculates the average time. - * @param {number} id - User ID - * @param {string} stationName - Check-out station name - * @param {number} t - Check-out time - * @return {void} - */ - checkOut(id, stationName, t) { - const user = this.stationSystem[id]; - user[1] = stationName; - user[3] = t; - const stationHash = `${user[0]}-${user[1]}`; - if (this.averageTime[stationHash]) { - this.averageTime[stationHash][0] += 1; - this.averageTime[stationHash][1] += user[3] - user[2]; - } else { - this.averageTime[stationHash] = []; - this.averageTime[stationHash][0] = 1; - this.averageTime[stationHash][1] = user[3] - user[2]; + /** + * Time O(1) | Space O(1) + * Records the check-out time and station for a user, and calculates the average time. + * @param {number} id - User ID + * @param {string} stationName - Check-out station name + * @param {number} t - Check-out time + * @return {void} + */ + checkOut(id, stationName, t) { + const user = this.stationSystem[id]; + user[1] = stationName; + user[3] = t; + const stationHash = `${user[0]}-${user[1]}`; + if (this.averageTime[stationHash]) { + this.averageTime[stationHash][0] += 1; + this.averageTime[stationHash][1] += user[3] - user[2]; + } else { + this.averageTime[stationHash] = []; + this.averageTime[stationHash][0] = 1; + this.averageTime[stationHash][1] = user[3] - user[2]; + } } - } - /** - * Time O(1) | Space O(1) - * Returns the average time taken to travel between two stations. - * @param {string} startStation - Start station name - * @param {string} endStation - End station name - * @return {number} - Average time in hours - */ - getAverageTime(startStation, endStation) { - const [rounds, totalHours] = this.averageTime[`${startStation}-${endStation}`]; - return totalHours / rounds; - } + /** + * Time O(1) | Space O(1) + * Returns the average time taken to travel between two stations. + * @param {string} startStation - Start station name + * @param {string} endStation - End station name + * @return {number} - Average time in hours + */ + getAverageTime(startStation, endStation) { + const [rounds, totalHours] = + this.averageTime[`${startStation}-${endStation}`]; + return totalHours / rounds; + } } diff --git a/javascript/1405-longest-happy-string.js b/javascript/1405-longest-happy-string.js index eab01f090..fbd4a67bd 100644 --- a/javascript/1405-longest-happy-string.js +++ b/javascript/1405-longest-happy-string.js @@ -7,28 +7,27 @@ * @param {number} c * @return {string} */ -var longestDiverseString = function(a, b, c) { - +var longestDiverseString = function (a, b, c) { const maxQ = new MaxPriorityQueue({ - compare: (a,b) => { - return b[0]-a[0]; - } + compare: (a, b) => { + return b[0] - a[0]; + }, }); - a && maxQ.enqueue([a, "a"]); - b && maxQ.enqueue([b, "b"]); - c && maxQ.enqueue([c, "c"]); + a && maxQ.enqueue([a, 'a']); + b && maxQ.enqueue([b, 'b']); + c && maxQ.enqueue([c, 'c']); - let happyStr = ""; - - while(!maxQ.isEmpty()) { + let happyStr = ''; - let [count, char] = maxQ.dequeue(); + while (!maxQ.isEmpty()) { + let [count, char] = maxQ.dequeue(); - if(happyStr[happyStr.length - 1] === char && - happyStr[happyStr.length - 2] === char) { - - if(!maxQ.isEmpty()) { + if ( + happyStr[happyStr.length - 1] === char && + happyStr[happyStr.length - 2] === char + ) { + if (!maxQ.isEmpty()) { let [count1, char1] = maxQ.dequeue(); happyStr += char1; @@ -36,10 +35,9 @@ var longestDiverseString = function(a, b, c) { count1 && maxQ.enqueue([count1, char1]); maxQ.enqueue([count, char]); - } + } } else { - - if(count >= 2) { + if (count >= 2) { happyStr += char.repeat(2); count -= 2; } else { diff --git a/javascript/1423-maximum-points-you-can-obtain-from-cards.js b/javascript/1423-maximum-points-you-can-obtain-from-cards.js index 805c9a5b2..3186fc7f2 100644 --- a/javascript/1423-maximum-points-you-can-obtain-from-cards.js +++ b/javascript/1423-maximum-points-you-can-obtain-from-cards.js @@ -1,17 +1,18 @@ /** - * Greedy | Sliding Window | PrefixSum + * Greedy | Sliding Window | PrefixSum * Time O(n) | Space O(1) * https://leetcode.com/problems/maximum-points-you-can-obtain-from-cards/ * @param {number[]} cardPoints * @param {number} k * @return {number} */ -var maxScore = function(cardPoints, k) { - +var maxScore = function (cardPoints, k) { const total = cardPoints.reduce((acc, curr) => acc + curr, 0); - let currTotal = cardPoints.slice(0, cardPoints.length - k).reduce((acc, curr) => acc + curr, 0); + let currTotal = cardPoints + .slice(0, cardPoints.length - k) + .reduce((acc, curr) => acc + curr, 0); let max = total - currTotal; - + let left = 0; let right = cardPoints.length - k - 1; // -1 because the array is 0 indexed. diff --git a/javascript/1443-minimum-time-to-collect-all-apples-in-a-tree.js b/javascript/1443-minimum-time-to-collect-all-apples-in-a-tree.js index 1230778ef..7f1aaa36e 100644 --- a/javascript/1443-minimum-time-to-collect-all-apples-in-a-tree.js +++ b/javascript/1443-minimum-time-to-collect-all-apples-in-a-tree.js @@ -1,5 +1,5 @@ /** - * Graph | DFS + * Graph | DFS * Time O(n) | Space O(n) * https://leetcode.com/problems/minimum-time-to-collect-all-apples-in-a-tree/ * @param {number} n @@ -7,7 +7,7 @@ * @param {boolean[]} hasApple * @return {number} */ -var minTime = function(n, edges, hasApple) { +var minTime = function (n, edges, hasApple) { if (n === 1) return 0; const result = dfs(0, -1, makeGraph(edges), hasApple) - 2; return (result > 0 && result) || 0; @@ -18,17 +18,16 @@ const dfs = (curr, pre, graph, hasApple) => { for (const nextNode of graph[curr]) { if (nextNode === pre) continue; pathLen += dfs(nextNode, curr, graph, hasApple); - } + } if (pathLen > 0 || hasApple[curr]) return pathLen + 2; return 0; -} +}; const makeGraph = (edges) => { const graph = {}; for (let i = 0; i < edges.length; i++) { - const from = edges[i][0]; const to = edges[i][1]; @@ -38,11 +37,11 @@ const makeGraph = (edges) => { if (!graph[to]) { graph[to] = []; - }; + } graph[to].push(from); graph[from].push(to); } return graph; -} +}; diff --git a/javascript/1461-check-if-a-string-contains-all-binary-codes-of-size-k.js b/javascript/1461-check-if-a-string-contains-all-binary-codes-of-size-k.js index f95ef230c..2d10a0d5b 100644 --- a/javascript/1461-check-if-a-string-contains-all-binary-codes-of-size-k.js +++ b/javascript/1461-check-if-a-string-contains-all-binary-codes-of-size-k.js @@ -1,22 +1,20 @@ /** * https://leetcode.com/problems/check-if-a-string-contains-all-binary-codes-of-size-k/ - * + * * Hashing * Time O(n*k) | Space O(2^k) (it can't get any bigger than 2^k in the worst case) * @param {string} s * @param {number} k * @return {boolean} */ -var hasAllCodes = function(s, k) { - +var hasAllCodes = function (s, k) { const bitSet = new Set(); - for(let i = 0; i < s.length; i++) { - if(s.substring(i,i+k).length === k) { - bitSet.add(s.substring(i,i + k)); + for (let i = 0; i < s.length; i++) { + if (s.substring(i, i + k).length === k) { + bitSet.add(s.substring(i, i + k)); } } - return bitSet.size === 1< a[1] - b[1]); frequenciesArr.reverse(); - + while (k) { const lastEl = frequenciesArr[frequenciesArr.length - 1]; while (lastEl[1]) { diff --git a/javascript/1486-xor-operation-in-an-array.js b/javascript/1486-xor-operation-in-an-array.js index ea3342f3b..4e8eb63c7 100644 --- a/javascript/1486-xor-operation-in-an-array.js +++ b/javascript/1486-xor-operation-in-an-array.js @@ -1,14 +1,15 @@ -/** - * @param {number} n - * @param {number} start - * @return {number} - */ -var xorOperation = function(n, start) { - let nums = new Array(n).fill(0); // initialize a nums which is the length of n elements with 0 value of Array using Array() nad fill() - - for(let i=0; i a^b); // return the bitwise XOR of all elements of nums using reduce() -}; +/** + * @param {number} n + * @param {number} start + * @return {number} + */ +var xorOperation = function (n, start) { + let nums = new Array(n).fill(0); // initialize a nums which is the length of n elements with 0 value of Array using Array() nad fill() + + for (let i = 0; i < n; i++) { + // loop through the 0 to n + nums[i] = start + 2 * i; // current element of nums is equal to sum of start and twice the i + } + + return nums.reduce((a, b) => a ^ b); // return the bitwise XOR of all elements of nums using reduce() +}; diff --git a/javascript/1512-number-of-good-pairs.js b/javascript/1512-number-of-good-pairs.js index e0cb98100..c2aa6bb45 100644 --- a/javascript/1512-number-of-good-pairs.js +++ b/javascript/1512-number-of-good-pairs.js @@ -12,4 +12,4 @@ var numIdenticalPairs = function (nums) { } } return result; -}; \ No newline at end of file +}; diff --git a/javascript/1514-path-with-maximum-probability.js b/javascript/1514-path-with-maximum-probability.js index 900b39bb0..863dc980c 100644 --- a/javascript/1514-path-with-maximum-probability.js +++ b/javascript/1514-path-with-maximum-probability.js @@ -6,7 +6,7 @@ * @param {number} end * @return {number} */ -var maxProbability = function(n, edges, succProb, start, end) { +var maxProbability = function (n, edges, succProb, start, end) { const genAdjList = () => { /*** { @@ -16,35 +16,35 @@ var maxProbability = function(n, edges, succProb, start, end) { } ***/ let list = {}; - for(let i = 0; i < n; i++) { + for (let i = 0; i < n; i++) { list[i] = []; } - for(let i = 0; i < edges.length; i++) { + for (let i = 0; i < edges.length; i++) { const [v1, v2] = edges[i]; const p = succProb[i]; list[v1].push([v2, p]); list[v2].push([v1, p]); } - + return list; - } + }; const graph = genAdjList(); const queue = new MaxPriorityQueue(); const visited = new Set(); - + queue.enqueue([start, 1], 1); - - while(!queue.isEmpty()) { + + while (!queue.isEmpty()) { const [n1, p1] = queue.dequeue().element; - if(visited.has(n1)) continue; + if (visited.has(n1)) continue; visited.add(n1); - if(n1 === end) return p1; - - for(const [n2, p2] of graph[n1]) { - if(visited.has(n2)) continue; + if (n1 === end) return p1; + + for (const [n2, p2] of graph[n1]) { + if (visited.has(n2)) continue; const val = p1 * p2; queue.enqueue([n2, val], val); } } - if(visited.size !== n) return 0; + if (visited.size !== n) return 0; }; diff --git a/javascript/1572-matrix-diagonal-sum.js b/javascript/1572-matrix-diagonal-sum.js index e857c5601..60fbae98f 100644 --- a/javascript/1572-matrix-diagonal-sum.js +++ b/javascript/1572-matrix-diagonal-sum.js @@ -5,11 +5,13 @@ var diagonalSum = function (mat) { let sum = 0; // initialize sum to zero let n = mat.length - 1; // initialize n to mat length - 1 - for (let i = 0; i <= n; i++) { // loop through to 0 to n + for (let i = 0; i <= n; i++) { + // loop through to 0 to n sum += mat[i][i]; // add mat[i][i] to sum - if (i !== (n - i)) { // if i not equal to n - i then add mat[i][n - i] to sum + if (i !== n - i) { + // if i not equal to n - i then add mat[i][n - i] to sum sum += mat[i][n - i]; } } return sum; // return sum; -}; \ No newline at end of file +}; diff --git a/javascript/1588-sum-of-all-odd-length-subarrays.js b/javascript/1588-sum-of-all-odd-length-subarrays.js index 6c47dd70b..e06f21172 100644 --- a/javascript/1588-sum-of-all-odd-length-subarrays.js +++ b/javascript/1588-sum-of-all-odd-length-subarrays.js @@ -3,10 +3,11 @@ * @return {number} */ var sumOddLengthSubarrays = function (arr) { - let sum = 0, len = arr.length; + let sum = 0, + len = arr.length; for (let i = 0; i < arr.length; i++) { let total = i * (len - i) + (len - i); sum += Math.ceil(total / 2) * arr[i]; } return sum; -}; \ No newline at end of file +}; diff --git a/javascript/1603-design-parking-system.js b/javascript/1603-design-parking-system.js index 8a17d286f..0750e41b9 100644 --- a/javascript/1603-design-parking-system.js +++ b/javascript/1603-design-parking-system.js @@ -6,39 +6,39 @@ * @param {number} small */ class ParkingSystem { - constructor(big, medium, small) { - this.isBigRemaining = big; - this.isMediumRemaining = medium; - this.isSmallRemaining = small; - } - - /** - * Time O(1) | Space O(1) - * @param {number} carType - * @return {boolean} - */ - addCar(carType) { - const isBigCarAvailable = (carType === 1 && this.isBigRemaining > 0); - if(isBigCarAvailable) { - this.isBigRemaining -= 1; - return true; - } - const isMediumCarAvailable = (carType === 2 && this.isMediumRemaining > 0); - if(isMediumCarAvailable) { - this.isMediumRemaining -= 1; - return true; + constructor(big, medium, small) { + this.isBigRemaining = big; + this.isMediumRemaining = medium; + this.isSmallRemaining = small; } - const isSmallCarAvailable = (carType === 3 && this.isSmallRemaining > 0); - if(isSmallCarAvailable) { - this.isSmallRemaining -= 1; - return true; + + /** + * Time O(1) | Space O(1) + * @param {number} carType + * @return {boolean} + */ + addCar(carType) { + const isBigCarAvailable = carType === 1 && this.isBigRemaining > 0; + if (isBigCarAvailable) { + this.isBigRemaining -= 1; + return true; + } + const isMediumCarAvailable = + carType === 2 && this.isMediumRemaining > 0; + if (isMediumCarAvailable) { + this.isMediumRemaining -= 1; + return true; + } + const isSmallCarAvailable = carType === 3 && this.isSmallRemaining > 0; + if (isSmallCarAvailable) { + this.isSmallRemaining -= 1; + return true; + } + return false; } - return false; - } } - -/** +/** * Your ParkingSystem object will be instantiated and called as such: * var obj = new ParkingSystem(big, medium, small) * var param_1 = obj.addCar(carType) diff --git a/javascript/1609-even-odd-tree.js b/javascript/1609-even-odd-tree.js index 9acd11f83..0261de1a5 100644 --- a/javascript/1609-even-odd-tree.js +++ b/javascript/1609-even-odd-tree.js @@ -14,31 +14,32 @@ * @param {TreeNode} root * @return {boolean} */ -var isEvenOddTree = function(root) { - +var isEvenOddTree = function (root) { // helper function const isStricklyIncreasingAndOdd = (arr) => { - for (let i = 0; i < arr.length; i++) { const currElement = arr[i]; - const nextElement = (arr[i + 1] !== undefined && arr[i + 1]) || Infinity; - if (currElement >= nextElement || currElement % 2 === 0) return false; + const nextElement = + (arr[i + 1] !== undefined && arr[i + 1]) || Infinity; + if (currElement >= nextElement || currElement % 2 === 0) + return false; } return true; - } - + }; + // helper function const isStricklyDecreasingAndEven = (arr) => { - for (let i = 0; i < arr.length; i++) { const currElement = arr[i]; - const nextElement = (arr[i + 1] !== undefined && arr[i + 1]) || -Infinity; - if (currElement <= nextElement || currElement % 2 === 1) return false; + const nextElement = + (arr[i + 1] !== undefined && arr[i + 1]) || -Infinity; + if (currElement <= nextElement || currElement % 2 === 1) + return false; } return true; - } + }; const q = new Queue(); q.enqueue([root, 0]); @@ -50,7 +51,6 @@ var isEvenOddTree = function(root) { const level = q.front()[1]; for (let i = 0; i < size; i++) { - const element = q.dequeue(); const node = element[0]; levelArr.push(node.val); @@ -59,8 +59,10 @@ var isEvenOddTree = function(root) { node.right && q.enqueue([node.right, level + 1]); } - if (level % 2 === 0 && !isStricklyIncreasingAndOdd(levelArr)) return false; - if (level % 2 === 1 && !isStricklyDecreasingAndEven(levelArr)) return false; + if (level % 2 === 0 && !isStricklyIncreasingAndOdd(levelArr)) + return false; + if (level % 2 === 1 && !isStricklyDecreasingAndEven(levelArr)) + return false; } return true; diff --git a/javascript/1614-maximum-nesting-depth-of-the-parentheses.js b/javascript/1614-maximum-nesting-depth-of-the-parentheses.js index 126c5840b..b7ce34d5a 100644 --- a/javascript/1614-maximum-nesting-depth-of-the-parentheses.js +++ b/javascript/1614-maximum-nesting-depth-of-the-parentheses.js @@ -1,17 +1,17 @@ /** - * Stack + * Stack * Time O(n) | Space O(1) * https://leetcode.com/problems/maximum-nesting-depth-of-the-parentheses * @param {string} s * @return {number} */ -var maxDepth = function(s) { +var maxDepth = function (s) { let currDepth = 0; let maxDepth = 0; for (let i = 0; i < s.length; i++) { - if (s[i] === "(") currDepth++; + if (s[i] === '(') currDepth++; maxDepth = Math.max(currDepth, maxDepth); - if (s[i] === ")") currDepth--; + if (s[i] === ')') currDepth--; } return maxDepth; }; diff --git a/javascript/1642-furthest-building-you-can-reach.js b/javascript/1642-furthest-building-you-can-reach.js index c48314f9b..f95889cb3 100644 --- a/javascript/1642-furthest-building-you-can-reach.js +++ b/javascript/1642-furthest-building-you-can-reach.js @@ -1,5 +1,5 @@ /** - * MaxPriorityQueue + * MaxPriorityQueue * Time O(n*log(n)) | Space O(n) * https://leetcode.com/problems/furthest-building-you-can-reach/ * @param {number[]} heights @@ -7,12 +7,11 @@ * @param {number} ladders * @return {number} */ -var furthestBuilding = function(heights, bricks, ladders) { - +var furthestBuilding = function (heights, bricks, ladders) { const maxPriorityQueue = new MaxPriorityQueue({ compare: (a, b) => { return b - a; - } + }, }); let i = 0; diff --git a/javascript/1647-minimum-deletions-to-make-character-frequencies-unique.js b/javascript/1647-minimum-deletions-to-make-character-frequencies-unique.js index aa1b61f57..27506c03c 100644 --- a/javascript/1647-minimum-deletions-to-make-character-frequencies-unique.js +++ b/javascript/1647-minimum-deletions-to-make-character-frequencies-unique.js @@ -5,12 +5,11 @@ * @param {string} s * @return {number} */ -var minDeletions = function(s) { - +var minDeletions = function (s) { // hash frequency let i = 0; const charHash = new Map(); - while (i < s.length) { + while (i < s.length) { const frequency = charHash.get(s[i]) || 0; charHash.set(s[i], frequency + 1); i++; @@ -25,8 +24,8 @@ var minDeletions = function(s) { for (const [key, val] of frequencyHash) { let frequency = key; let frequencyOfFrequency = val; - while(frequencyOfFrequency > 1) { - while(frequencyHash.has(frequency)) { + while (frequencyOfFrequency > 1) { + while (frequencyHash.has(frequency)) { frequency -= 1; min += 1; } diff --git a/javascript/1688-count-of-matches-in-tournament.js b/javascript/1688-count-of-matches-in-tournament.js index d0104aeb6..ee233ebfa 100644 --- a/javascript/1688-count-of-matches-in-tournament.js +++ b/javascript/1688-count-of-matches-in-tournament.js @@ -5,15 +5,20 @@ var numberOfMatches = function (n) { let matches = 0; // initialize matches to zero let num = n; // initialize num equal to n - for (let i = 0; i < n; i++) { // loop through the number n - if (num == 1) { // if num is equal to 1 then break the for loop + for (let i = 0; i < n; i++) { + // loop through the number n + if (num == 1) { + // if num is equal to 1 then break the for loop break; - } else { // else - if (num % 2 == 0) { // if num is even + } else { + // else + if (num % 2 == 0) { + // if num is even let divide = num / 2; // divide num by 2 matches += divide; // add divide to matches num -= divide; // subtract divide to num - } else { // else + } else { + // else let divide = (num - 1) / 2; // subtract num by 1 and then divide it by 2 matches += divide; // add divide to matches num -= divide; // subtract divide to num @@ -21,4 +26,4 @@ var numberOfMatches = function (n) { } } return matches; // return number matches -}; \ No newline at end of file +}; diff --git a/javascript/1700-number-of-students-unable-to-eat-lunch.js b/javascript/1700-number-of-students-unable-to-eat-lunch.js index 3ef2bdf2d..54193ae71 100644 --- a/javascript/1700-number-of-students-unable-to-eat-lunch.js +++ b/javascript/1700-number-of-students-unable-to-eat-lunch.js @@ -6,20 +6,24 @@ var countStudents = function (students, sandwiches) { let movement = 0; // initialize movement to be zero - while (sandwiches.length > 0) { // while length of sandwiches is greater than zero - if (students[0] == sandwiches[0]) { // if first element of students and sandwiches both are same + while (sandwiches.length > 0) { + // while length of sandwiches is greater than zero + if (students[0] == sandwiches[0]) { + // if first element of students and sandwiches both are same students.shift(); // reomve first element of students using shift() sandwiches.shift(); // remove first element of sandwiches using shift() movement = 0; // make movement to be zero - } else { // else + } else { + // else let add = students.shift(); // initialize add to be first element of students students.push(add); // push add to array students movement++; // increment movement - if (movement == students.length) { // if movement is equal to length of students then break the loop + if (movement == students.length) { + // if movement is equal to length of students then break the loop break; } } } return students.length; // return length of array students -}; \ No newline at end of file +}; diff --git a/javascript/1834-single-threaded-cpu.js b/javascript/1834-single-threaded-cpu.js index 6d636203e..1544d8d32 100644 --- a/javascript/1834-single-threaded-cpu.js +++ b/javascript/1834-single-threaded-cpu.js @@ -2,28 +2,28 @@ * @param {number[][]} tasks * @return {number[]} */ -var getOrder = function(tasks) { - for(let i = 0; i < tasks.length; i++) tasks[i].push(i); +var getOrder = function (tasks) { + for (let i = 0; i < tasks.length; i++) tasks[i].push(i); tasks.sort((a, b) => a[0] - b[0]); const pq = new MinPriorityQueue({ compare: (e1, e2) => { - if(e1[1] === e2[1]) return e1[2] - e2[2]; + if (e1[1] === e2[1]) return e1[2] - e2[2]; return e1[1] - e2[1]; - } + }, }); const a = []; - let t = tasks[0][0], i = 0; - while(pq.size() || i < tasks.length){ - while(i < tasks.length && t >= tasks[i][0]){ + let t = tasks[0][0], + i = 0; + while (pq.size() || i < tasks.length) { + while (i < tasks.length && t >= tasks[i][0]) { pq.enqueue(tasks[i]); i++; } - if(pq.size()){ + if (pq.size()) { let e = pq.dequeue(); a.push(e[2]); t += e[1]; - } - else t = tasks[i][0]; + } else t = tasks[i][0]; } return a; -}; \ No newline at end of file +}; diff --git a/javascript/1845-seat-reservation-manager.js b/javascript/1845-seat-reservation-manager.js index 9fb1c1d3b..2f17d9f7f 100644 --- a/javascript/1845-seat-reservation-manager.js +++ b/javascript/1845-seat-reservation-manager.js @@ -1,14 +1,13 @@ - class SeatManager { /** - * MinHeap - * Time O(n*log(n)) | Space O(n) - * https://leetcode.com/problems/seat-reservation-manager/ - * @param {number} n - */ + * MinHeap + * Time O(n*log(n)) | Space O(n) + * https://leetcode.com/problems/seat-reservation-manager/ + * @param {number} n + */ constructor(n) { this.unreserved = new MinPriorityQueue({ - compare: (a, b) => a - b + compare: (a, b) => a - b, }); for (let i = 1; i < n + 1; i++) { @@ -25,7 +24,7 @@ class SeatManager { return minAvailableSeat; } - /** + /** * Time O(log(n)) | Space O(1) * @param {number} seatNumber * @return {void} diff --git a/javascript/1846-maximum-element-after-decreasing-and-rearranging.js b/javascript/1846-maximum-element-after-decreasing-and-rearranging.js index 0a9e4631c..9ee5c5a13 100644 --- a/javascript/1846-maximum-element-after-decreasing-and-rearranging.js +++ b/javascript/1846-maximum-element-after-decreasing-and-rearranging.js @@ -1,4 +1,3 @@ - /** * Sorting * Time O(n*log(n)) | Space O(n) @@ -6,14 +5,12 @@ * @param {number[]} arr * @return {number} */ -var maximumElementAfterDecrementingAndRearranging = function(arr) { - +var maximumElementAfterDecrementingAndRearranging = function (arr) { arr.sort((a, b) => a - b); let index = 1; arr[0] = 1; - + while (index < arr.length) { - const pre = arr[index - 1]; const curr = arr[index]; if (Math.abs(curr - pre) > 1 && pre + 1 < curr) { @@ -21,6 +18,6 @@ var maximumElementAfterDecrementingAndRearranging = function(arr) { } index++; } - + return Math.max(...arr); }; diff --git a/javascript/1851-minimum-interval-to-include-each-query.js b/javascript/1851-minimum-interval-to-include-each-query.js index f35523608..29263c7fa 100644 --- a/javascript/1851-minimum-interval-to-include-each-query.js +++ b/javascript/1851-minimum-interval-to-include-each-query.js @@ -3,28 +3,28 @@ * @param {number[]} queries * @return {number[]} */ -var minInterval = function(intervals, queries) { - intervals.sort((a, b) => a[0] - b[0]); - const queriesSorted = [ ...queries ].sort((a, b) => a - b); - const minHeap = new MinPriorityQueue(); - const output = {}; - let i = 0; +var minInterval = function (intervals, queries) { + intervals.sort((a, b) => a[0] - b[0]); + const queriesSorted = [...queries].sort((a, b) => a - b); + const minHeap = new MinPriorityQueue(); + const output = {}; + let i = 0; - for (const query of queriesSorted) { - while (i < intervals.length && intervals[i][0] <= query) { - const [ start, end ] = intervals[i]; - const length = end - start + 1; - // Use length as the priority in the heap. - minHeap.enqueue([ length, end ], length); - i++; - } + for (const query of queriesSorted) { + while (i < intervals.length && intervals[i][0] <= query) { + const [start, end] = intervals[i]; + const length = end - start + 1; + // Use length as the priority in the heap. + minHeap.enqueue([length, end], length); + i++; + } - while (!minHeap.isEmpty() && minHeap.front().element[1] < query) { - minHeap.dequeue(); - } + while (!minHeap.isEmpty() && minHeap.front().element[1] < query) { + minHeap.dequeue(); + } - output[query] = (!minHeap.isEmpty()) ? minHeap.front().element[0] : -1; - } + output[query] = !minHeap.isEmpty() ? minHeap.front().element[0] : -1; + } - return queries.map((query) => output[query]); + return queries.map((query) => output[query]); }; diff --git a/javascript/1863-sum-of-all-subset-xor-totals.js b/javascript/1863-sum-of-all-subset-xor-totals.js index cc2977bb5..91c6ab976 100644 --- a/javascript/1863-sum-of-all-subset-xor-totals.js +++ b/javascript/1863-sum-of-all-subset-xor-totals.js @@ -7,5 +7,5 @@ var subsetXORSum = function (nums) { for (let i = 0; i < nums.length; ++i) { bitOR |= nums[i]; } - return (bitOR * Math.pow(2, nums.length - 1)); -}; \ No newline at end of file + return bitOR * Math.pow(2, nums.length - 1); +}; diff --git a/javascript/1882-process-tasks-using-servers.js b/javascript/1882-process-tasks-using-servers.js index bf3ac6f2b..9ac6db271 100644 --- a/javascript/1882-process-tasks-using-servers.js +++ b/javascript/1882-process-tasks-using-servers.js @@ -6,20 +6,19 @@ * @param {number[]} tasks * @return {number[]} */ -var assignTasks = function(servers, tasks) { - +var assignTasks = function (servers, tasks) { const toBeCompleted = new MinPriorityQueue({ compare: (a, b) => { if (a[0] === b[0]) return a[1] - b[1]; return a[0] - b[0]; - } + }, }); const freeServers = new MinPriorityQueue({ compare: (a, b) => { if (a[0] === b[0]) return a[1] - b[1]; return a[0] - b[0]; - } + }, }); for (let i = 0; i < servers.length; i++) { @@ -34,13 +33,12 @@ var assignTasks = function(servers, tasks) { for (let i = 0; i < tasks.length; i++) { sec = Math.max(i, sec); - // if the we don't have server available then jump to the next imidiate + // if the we don't have server available then jump to the next imidiate // time when the server will be available. if (freeServers.isEmpty()) { sec = toBeCompleted.front()[0]; } - while (!toBeCompleted.isEmpty() && - toBeCompleted.front()[0] <= sec) { + while (!toBeCompleted.isEmpty() && toBeCompleted.front()[0] <= sec) { const [endTime, serverIdx] = toBeCompleted.dequeue(); const weight = servers[serverIdx]; freeServers.enqueue([weight, serverIdx]); @@ -49,7 +47,7 @@ var assignTasks = function(servers, tasks) { const [weight, serverIdx] = freeServers.dequeue(); const timeToBeTaken = tasks[i]; result.push(serverIdx); - toBeCompleted.enqueue([sec+timeToBeTaken, serverIdx]); + toBeCompleted.enqueue([sec + timeToBeTaken, serverIdx]); } return result; diff --git a/javascript/1898-maximum-number-of-removable-characters.js b/javascript/1898-maximum-number-of-removable-characters.js index 3ae59a871..aa6b3ccf4 100644 --- a/javascript/1898-maximum-number-of-removable-characters.js +++ b/javascript/1898-maximum-number-of-removable-characters.js @@ -1,6 +1,6 @@ /** * https://leetcode.com/problems/maximum-number-of-removable-characters/ - * + * * Brute force * Time O(removable.length * s.length) | Space O(n) * @param {string} s @@ -8,45 +8,44 @@ * @param {number[]} removable * @return {number} */ -var maximumRemovals1 = function(s, p, removable) { - let k = 0; - // removable.reverse(); - s = s.split(''); - p = p.split(''); +var maximumRemovals1 = function (s, p, removable) { + let k = 0; + // removable.reverse(); + s = s.split(''); + p = p.split(''); + + for (let i = 0; i < removable.length; i++) { + s[removable[i]] = -1; + if (isSubSet1(s, p)) { + k++; + continue; + } + return k; + } - for (let i = 0; i < removable.length; i++) { - s[removable[i]] = -1; - if (isSubSet1(s, p)) { - k++; - continue; - } return k; - } - - return k; }; // helper function. function isSubSet1(s, p) { - let i = 0; - let j = 0; - - while (i < s.length && j < p.length) { - if (s[i] === p[j]) { - i++; - j++; - } else { - i++; + let i = 0; + let j = 0; + + while (i < s.length && j < p.length) { + if (s[i] === p[j]) { + i++; + j++; + } else { + i++; + } } - } - return j === p.length; + return j === p.length; } - /** - * - * Binary Search + * + * Binary Search * n = length of string, k = length of removable * Time O(log(k)*n) | Space O(1) * @param {string} s @@ -54,42 +53,41 @@ function isSubSet1(s, p) { * @param {number[]} removable * @return {number} */ -var maximumRemovals = function(s, p, removable) { - - let left = 0; - let right = removable.length - 1; - let k = 0; - - while (left <= right) { - const mid = (left + right) >> 1; - const hash = new Set(removable.slice(0, mid + 1)); - - if (isSubSet(hash, s, p)) { - k = Math.max(k, mid + 1); - left = mid + 1; - continue; +var maximumRemovals = function (s, p, removable) { + let left = 0; + let right = removable.length - 1; + let k = 0; + + while (left <= right) { + const mid = (left + right) >> 1; + const hash = new Set(removable.slice(0, mid + 1)); + + if (isSubSet(hash, s, p)) { + k = Math.max(k, mid + 1); + left = mid + 1; + continue; + } + + right = mid - 1; } - right = mid - 1; - } - - return k; + return k; }; // helper function. function isSubSet(hash, s, p) { - let i = 0; - let j = 0; + let i = 0; + let j = 0; - while (i < s.length && j < p.length) { - if (s[i] === p[j] && !hash.has(i)) { - i++; - j++; - continue; - } + while (i < s.length && j < p.length) { + if (s[i] === p[j] && !hash.has(i)) { + i++; + j++; + continue; + } - i++; - } + i++; + } - return j === p.length; + return j === p.length; } diff --git a/javascript/1899-merge-triplets-to-form-target-triplet.js b/javascript/1899-merge-triplets-to-form-target-triplet.js index ba55f3ef8..acedf53ff 100644 --- a/javascript/1899-merge-triplets-to-form-target-triplet.js +++ b/javascript/1899-merge-triplets-to-form-target-triplet.js @@ -33,18 +33,19 @@ var mergeTriplets = function (triplets, target) { * @param {number[]} target * @return {boolean} */ - var mergeTriplets = function(triplets, target, res = new Array(3).fill(0)) { - for (const [ a, b, c ] of triplets) { /* Time O(N) */ - const [ _a, _b, _c ] = target; +var mergeTriplets = function (triplets, target, res = new Array(3).fill(0)) { + for (const [a, b, c] of triplets) { + /* Time O(N) */ + const [_a, _b, _c] = target; - const isTargetGreater = (a <= _a) && (b <= _b) && (c <= _c); + const isTargetGreater = a <= _a && b <= _b && c <= _c; if (!isTargetGreater) continue; - const [ __a, __b, __c ] = res; - res = [ Math.max(__a, a), Math.max(__b, b), Math.max(__c, c) ]; + const [__a, __b, __c] = res; + res = [Math.max(__a, a), Math.max(__b, b), Math.max(__c, c)]; } - - return res.every((val, i) => val === target[i])/* Time O(N) */ + + return res.every((val, i) => val === target[i]); /* Time O(N) */ }; /** @@ -54,17 +55,22 @@ var mergeTriplets = function (triplets, target) { * @param {number[]} target * @return {boolean} */ -var mergeTriplets = function(triplets, target, res = new Array(3).fill(false)) { - for (const [ a, b, c ] of triplets) {/* Time O(N) */ - const [ _a, _b, _c ] = target; - - const isTargetGreater = (a <= _a) && (b <= _b) && (c <= _c); +var mergeTriplets = function ( + triplets, + target, + res = new Array(3).fill(false), +) { + for (const [a, b, c] of triplets) { + /* Time O(N) */ + const [_a, _b, _c] = target; + + const isTargetGreater = a <= _a && b <= _b && c <= _c; if (!isTargetGreater) continue; - - res[0] |= (a === _a); - res[1] |= (b === _b); - res[2] |= (c === _c); + + res[0] |= a === _a; + res[1] |= b === _b; + res[2] |= c === _c; } - + return res[0] && res[1] && res[2]; -} +}; diff --git a/javascript/1905-count-sub-islands.js b/javascript/1905-count-sub-islands.js index 5cebc1269..ce2d2b188 100644 --- a/javascript/1905-count-sub-islands.js +++ b/javascript/1905-count-sub-islands.js @@ -1,35 +1,35 @@ -var countSubIslands = function(grid1, grid2) { - let ROWS = grid1.length, COLS = grid1[0].length; +var countSubIslands = function (grid1, grid2) { + let ROWS = grid1.length, + COLS = grid1[0].length; let visit = new Set(); - - const dfs = function(r, c) { - let flatCoord = r*COLS + c; + + const dfs = function (r, c) { + let flatCoord = r * COLS + c; if ( - r < 0 - || c < 0 - || r == ROWS - || c == COLS - || grid2[r][c] == 0 - || visit.has(flatCoord) + r < 0 || + c < 0 || + r == ROWS || + c == COLS || + grid2[r][c] == 0 || + visit.has(flatCoord) ) return true; - + visit.add(flatCoord); let res = true; - if(grid1[r][c] == 0) - res = false; - + if (grid1[r][c] == 0) res = false; + res = dfs(r - 1, c) && res; res = dfs(r + 1, c) && res; res = dfs(r, c - 1) && res; res = dfs(r, c + 1) && res; return res; }; - + let count = 0; - for(let r = 0; r < ROWS; r++) - for(let c = 0; c < COLS; c++) - if(grid2[r][c] && !visit.has(r*COLS + c) && dfs(r, c)) + for (let r = 0; r < ROWS; r++) + for (let c = 0; c < COLS; c++) + if (grid2[r][c] && !visit.has(r * COLS + c) && dfs(r, c)) count += 1; return count; }; diff --git a/javascript/1921-eliminate-maximum-number-of-monsters.js b/javascript/1921-eliminate-maximum-number-of-monsters.js index e0ca5a87d..e0bd3f3e6 100644 --- a/javascript/1921-eliminate-maximum-number-of-monsters.js +++ b/javascript/1921-eliminate-maximum-number-of-monsters.js @@ -5,8 +5,7 @@ * @param {number[]} speed * @return {number} */ -var eliminateMaximum = function(dist, speed) { - +var eliminateMaximum = function (dist, speed) { const time = dist.map((d, i) => { return d / speed[i]; }); diff --git a/javascript/1929-concatenation-of-array.js b/javascript/1929-concatenation-of-array.js index a7007d22f..deebc6820 100644 --- a/javascript/1929-concatenation-of-array.js +++ b/javascript/1929-concatenation-of-array.js @@ -5,9 +5,9 @@ * @return {number[]} */ var getConcatenation = function (nums) { - let res = []; - for (let i = 0; i < nums.length * 2; i++) { - res.push(nums[i % nums.length]); - } - return res; + let res = []; + for (let i = 0; i < nums.length * 2; i++) { + res.push(nums[i % nums.length]); + } + return res; }; diff --git a/javascript/1930-unique-length-3-palindromic-subsequences.js b/javascript/1930-unique-length-3-palindromic-subsequences.js index 817c69a2d..28f8e3e5e 100644 --- a/javascript/1930-unique-length-3-palindromic-subsequences.js +++ b/javascript/1930-unique-length-3-palindromic-subsequences.js @@ -5,8 +5,9 @@ var countPalindromicSubsequence = function (s) { let count = 0; let chars = new Set(s); - for(const char of chars){ - let first = s.indexOf(char),last = s.lastIndexOf(char); + for (const char of chars) { + let first = s.indexOf(char), + last = s.lastIndexOf(char); count += new Set(s.slice(first + 1, last)).size; } return count; diff --git a/javascript/1958-check-if-move-is-legal.js b/javascript/1958-check-if-move-is-legal.js index 78ce9ecf4..19f95a6f2 100644 --- a/javascript/1958-check-if-move-is-legal.js +++ b/javascript/1958-check-if-move-is-legal.js @@ -1,27 +1,35 @@ -var checkMove = function(board, rMove, cMove, color) { - const ROWS = board.length, COLS = board[0].length; - let direction = [[1, 0], [-1, 0], [0, 1], [0, -1], - [1, 1], [-1, -1], [1, -1], [-1, 1]]; +var checkMove = function (board, rMove, cMove, color) { + const ROWS = board.length, + COLS = board[0].length; + let direction = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + [1, 1], + [-1, -1], + [1, -1], + [-1, 1], + ]; board[rMove][cMove] = color; - - let legal = function(row, col, color, direc) { - let dr = direc[0], dc = direc[1]; + + let legal = function (row, col, color, direc) { + let dr = direc[0], + dc = direc[1]; row = row + dr; col = col + dc; let length = 1; - - while(0 <= row && row < ROWS && 0 <= col && col < COLS) { + + while (0 <= row && row < ROWS && 0 <= col && col < COLS) { length += 1; - if(board[row][col] == '.') return false; - if(board[row][col] == color) - return length >= 3; + if (board[row][col] == '.') return false; + if (board[row][col] == color) return length >= 3; row = row + dr; col = col + dc; } return false; - } - - for(const d of direction) - if(legal(rMove, cMove, color, d)) return true; + }; + + for (const d of direction) if (legal(rMove, cMove, color, d)) return true; return false; }; diff --git a/javascript/1963-minimum-number-of-swaps-to-make-the-string-balanced.js b/javascript/1963-minimum-number-of-swaps-to-make-the-string-balanced.js index 3da70d70e..7e530e159 100644 --- a/javascript/1963-minimum-number-of-swaps-to-make-the-string-balanced.js +++ b/javascript/1963-minimum-number-of-swaps-to-make-the-string-balanced.js @@ -2,14 +2,13 @@ // time complexity O(n) // space complexity O(1) -var minSwaps = function(s) { - +var minSwaps = function (s) { let extraClosing = 0; let maxClosing = 0; - for(let i = 0; i < s.length; i++) { + for (let i = 0; i < s.length; i++) { s[i] === ']' ? extraClosing++ : extraClosing--; maxClosing = Math.max(maxClosing, extraClosing); } - return Math.ceil(maxClosing/2); + return Math.ceil(maxClosing / 2); }; diff --git a/javascript/1968-array-with-elements-not-equal-to-average-of-neighbors.js b/javascript/1968-array-with-elements-not-equal-to-average-of-neighbors.js index dc1975f4d..977e038f7 100644 --- a/javascript/1968-array-with-elements-not-equal-to-average-of-neighbors.js +++ b/javascript/1968-array-with-elements-not-equal-to-average-of-neighbors.js @@ -1,25 +1,25 @@ /** * Two Pointers * https://leetcode.com/problems/array-with-elements-not-equal-to-average-of-neighbors/ - * + * * Time O(n*log(n)) | Space O(n) * @param {number[]} nums * @return {number[]} */ - var rearrangeArray = function(nums) { - nums.sort((a,b) => a-b); - +var rearrangeArray = function (nums) { + nums.sort((a, b) => a - b); + let midPointer = Math.ceil(nums.length / 2); let beginingPointer = 1; - - while(midPointer < nums.length) { + + while (midPointer < nums.length) { swap(midPointer, beginingPointer, nums); midPointer++; - beginingPointer += 2 + beginingPointer += 2; } return nums; - }; - -var swap = function(i,j,nums) { +}; + +var swap = function (i, j, nums) { [nums[i], nums[j]] = [nums[j], nums[i]]; -} +}; diff --git a/javascript/1985-find-the-kth-largest-integer-in-the-array.js b/javascript/1985-find-the-kth-largest-integer-in-the-array.js index e10ad39f5..3384a5284 100644 --- a/javascript/1985-find-the-kth-largest-integer-in-the-array.js +++ b/javascript/1985-find-the-kth-largest-integer-in-the-array.js @@ -6,8 +6,7 @@ * @param {number} k * @return {string} */ -var kthLargestNumber = function(nums, k) { - +var kthLargestNumber = function (nums, k) { // sort it string wise. nums.sort((a, b) => { if (a.length !== b.length) return b.length - a.length; diff --git a/javascript/1993-operations-on-tree.js b/javascript/1993-operations-on-tree.js index c32b4625c..ba11291a1 100644 --- a/javascript/1993-operations-on-tree.js +++ b/javascript/1993-operations-on-tree.js @@ -6,8 +6,8 @@ class LockingTree { this.parent = parent; this.childHash = {}; this.treeHash = {}; - for(let i = 0; i < parent.length; i++) { - if(this.childHash[parent[i]]) { + for (let i = 0; i < parent.length; i++) { + if (this.childHash[parent[i]]) { this.childHash[parent[i]].push(i); } else { this.childHash[parent[i]] = [i]; @@ -15,38 +15,38 @@ class LockingTree { } } - /** + /** * Time O(1) | Space O(1) - * @param {number} num + * @param {number} num * @param {number} user * @return {boolean} */ lock(num, user) { // it will just lock a node for a given user if it's not already locked THAT'S IT! - if(this.treeHash[num]) return false; + if (this.treeHash[num]) return false; this.treeHash[num] = user; return true; } - /** + /** * Time O(1) | Space O(1) - * @param {number} num + * @param {number} num * @param {number} user * @return {boolean} */ unlock(num, user) { - // only unlock the node if it's locked by the same user - if(this.treeHash[num] === user) { + // only unlock the node if it's locked by the same user + if (this.treeHash[num] === user) { delete this.treeHash[num]; return true; } return false; } - /** - * + /** + * * Time O(n) | Space O(n) - * @param {number} num + * @param {number} num * @param {number} user * @return {boolean} */ @@ -54,10 +54,10 @@ class LockingTree { // lock the node for a given user and unlock all of its descendants no matter who locked it. // 1. the given node should be unlocked // 2. the given node should have at least one locked node descendant by anyone - // 3. the given node shouldn't have any locked ancestors - if(this.treeHash[num]) return false; - if(!this.checkDescendants(num)) return false; - if(!this.checkAncestors(num)) return false; + // 3. the given node shouldn't have any locked ancestors + if (this.treeHash[num]) return false; + if (!this.checkDescendants(num)) return false; + if (!this.checkAncestors(num)) return false; // locking the given node this.treeHash[num] = user; @@ -73,10 +73,10 @@ class LockingTree { unlockDescendants(index) { const stack = []; stack.push(index); - while(stack.length) { + while (stack.length) { const node = stack.pop(); const children = this.childHash[node]; - for(let i = 0; i < (children && children.length); i++) { + for (let i = 0; i < (children && children.length); i++) { delete this.treeHash[children[i]]; stack.push(children[i]); } @@ -91,8 +91,8 @@ class LockingTree { */ checkAncestors(index) { let node = this.parent[index]; - while(node !== -1) { - if(this.treeHash[node]) return false; + while (node !== -1) { + if (this.treeHash[node]) return false; node = this.parent[node]; } return true; @@ -107,11 +107,11 @@ class LockingTree { checkDescendants(index) { const stack = []; stack.push(index); - while(stack.length) { + while (stack.length) { const node = stack.pop(); const children = this.childHash[node]; - for(let i = 0; i < (children && children.length); i++) { - if(this.treeHash[children[i]]) return true; + for (let i = 0; i < (children && children.length); i++) { + if (this.treeHash[children[i]]) return true; stack.push(children[i]); } } diff --git a/javascript/2001-number-of-pairs-of-interchangeable-rectangles.js b/javascript/2001-number-of-pairs-of-interchangeable-rectangles.js index 00b46d9a0..b76aeb3e8 100644 --- a/javascript/2001-number-of-pairs-of-interchangeable-rectangles.js +++ b/javascript/2001-number-of-pairs-of-interchangeable-rectangles.js @@ -6,11 +6,13 @@ * @return {number} */ var interchangeableRectangles = (rectangles) => { - let totalPair = 0; for (let i = 0; i < rectangles.length; i++) { for (let j = i + 1; j < rectangles.length; j++) { - if (rectangles[i][1] / rectangles[i][0] === rectangles[j][1] / rectangles[j][0]) { + if ( + rectangles[i][1] / rectangles[i][0] === + rectangles[j][1] / rectangles[j][0] + ) { totalPair++; } } @@ -18,13 +20,12 @@ var interchangeableRectangles = (rectangles) => { return totalPair; }; /** - * Linear + * Linear * Time O(N) | Space O(n) * @param {number[][]} rectangles * @return {number} */ var interchangeableRectangles = (rectangles) => { - const ratioFrequency = {}; for (let i = 0; i < rectangles.length; i++) { diff --git a/javascript/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.js b/javascript/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.js index a498c0528..a41d6b8c5 100644 --- a/javascript/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.js +++ b/javascript/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.js @@ -29,7 +29,7 @@ var maxProduct = function (s) { return Math.max( dp(m - lb), dp(m - fb), - dp(m - lb - fb) + (s[l] == s[f]) * 2 + dp(m - lb - fb) + (s[l] == s[f]) * 2, ); }); let ans = 0; diff --git a/javascript/2017-grid-game.js b/javascript/2017-grid-game.js index 443af1762..04c8f39a9 100644 --- a/javascript/2017-grid-game.js +++ b/javascript/2017-grid-game.js @@ -1,5 +1,5 @@ /** - * Submission Details: + * Submission Details: * https://leetcode.com/problems/grid-game/ * Time O(n), Space O(1) * Runtime: 89ms (beats 79.31%) || 53.5mb (beats 89.66%) @@ -10,14 +10,14 @@ * @return {number} */ -var gridGame = function(grid) { - let one = grid[0].reduce((a,b)=>a+b) - grid[0][0]; +var gridGame = function (grid) { + let one = grid[0].reduce((a, b) => a + b) - grid[0][0]; let two = 0; let res = one; - for(let i = 1; i < grid[0].length; i++){ - one-=grid[0][i]; - two+=grid[1][i-1]; - res = Math.min(res, Math.max(one,two)); + for (let i = 1; i < grid[0].length; i++) { + one -= grid[0][i]; + two += grid[1][i - 1]; + res = Math.min(res, Math.max(one, two)); } return res; -}; \ No newline at end of file +}; diff --git a/javascript/2038-remove-colored-pieces-if-both-neighbors-are-the-same-color.js b/javascript/2038-remove-colored-pieces-if-both-neighbors-are-the-same-color.js index ae64637e6..98a121ece 100644 --- a/javascript/2038-remove-colored-pieces-if-both-neighbors-are-the-same-color.js +++ b/javascript/2038-remove-colored-pieces-if-both-neighbors-are-the-same-color.js @@ -5,16 +5,19 @@ * @param {string} colors * @return {boolean} */ -var winnerOfGame = function(colors) { - +var winnerOfGame = function (colors) { let aScore = 0; let bScore = 0; - + const canRemove = (index) => { - if (colors[index] === colors[index - 1] && colors[index] === colors[index + 1]) return colors[index]; + if ( + colors[index] === colors[index - 1] && + colors[index] === colors[index + 1] + ) + return colors[index]; return false; - } - + }; + for (let i = 1; i < colors.length; i++) { if (canRemove(i) === 'A') aScore++; if (canRemove(i) === 'B') bScore++; diff --git a/javascript/2125-number-of-laser-beams-in-a-bank.js b/javascript/2125-number-of-laser-beams-in-a-bank.js index 3afac319a..335e84e5d 100644 --- a/javascript/2125-number-of-laser-beams-in-a-bank.js +++ b/javascript/2125-number-of-laser-beams-in-a-bank.js @@ -5,21 +5,20 @@ * @param {string[]} bank * @return {number} */ -var numberOfBeams = function(bank) { - +var numberOfBeams = function (bank) { let totalBeams = 0; let left = 0; let right = left + 1; const countBeam = (beam) => { - return beam.split("").filter((b) => b === "1").length; - } + return beam.split('').filter((b) => b === '1').length; + }; while (right < bank.length) { while (right < bank.length && !countBeam(bank[right])) { right++; - } + } if (right < bank.length) { totalBeams += countBeam(bank[left]) * countBeam(bank[right]); diff --git a/javascript/2130-maximum-twin-sum-of-a-linked-list.js b/javascript/2130-maximum-twin-sum-of-a-linked-list.js index 1b5d435ef..a387329a3 100644 --- a/javascript/2130-maximum-twin-sum-of-a-linked-list.js +++ b/javascript/2130-maximum-twin-sum-of-a-linked-list.js @@ -7,56 +7,56 @@ */ /** - * Linear Time + * Linear Time * Time O(n) | Space O(1) * @param {ListNode} head * @return {number} */ var pairSum = function (head) { - const mid = llLength(head) / 2; - const rightPointer = getRightPointer(head, mid); - const leftPointer = reverseLL(head, mid); - - return getMax(leftPointer, rightPointer); + const mid = llLength(head) / 2; + const rightPointer = getRightPointer(head, mid); + const leftPointer = reverseLL(head, mid); + + return getMax(leftPointer, rightPointer); }; var getMax = (leftPointer, rightPointer) => { let max = 0; while (leftPointer && rightPointer) { - max = Math.max(leftPointer.val + rightPointer.val, max); - leftPointer = leftPointer.next; - rightPointer = rightPointer.next; + max = Math.max(leftPointer.val + rightPointer.val, max); + leftPointer = leftPointer.next; + rightPointer = rightPointer.next; } return max; -} +}; var getRightPointer = (head, mid) => { let count = 0; let rightPointer = head; while (count < mid) { - rightPointer = rightPointer.next; - count++; + rightPointer = rightPointer.next; + count++; } return rightPointer; -} +}; var llLength = (head) => { - let count = 0; - while (head) { - head = head.next; - count++; - } - return count; + let count = 0; + while (head) { + head = head.next; + count++; + } + return count; }; var reverseLL = (head, len) => { - let count = 0; - let temp = null; - while (count < len) { - const next = head.next; - head.next = temp; - temp = head; - head = next; - count++; - } - return temp; + let count = 0; + let temp = null; + while (count < len) { + const next = head.next; + head.next = temp; + temp = head; + head = next; + count++; + } + return temp; }; diff --git a/javascript/2160-minimum-sum-of-four-digit-number-after-splitting-digits.js b/javascript/2160-minimum-sum-of-four-digit-number-after-splitting-digits.js index acbc88fd0..49524e5ee 100644 --- a/javascript/2160-minimum-sum-of-four-digit-number-after-splitting-digits.js +++ b/javascript/2160-minimum-sum-of-four-digit-number-after-splitting-digits.js @@ -3,6 +3,6 @@ * @return {number} */ var minimumSum = function (num) { - let str = String(num).split("").sort(); // intialize str and split the num using String(), split() and sort() - return parseInt(str[0] + str[2]) + parseInt(str[1] + str[3]); // return sum of 1st, 3rd and 2nd, 4th string digit and convert into num using parseInt -}; \ No newline at end of file + let str = String(num).split('').sort(); // intialize str and split the num using String(), split() and sort() + return parseInt(str[0] + str[2]) + parseInt(str[1] + str[3]); // return sum of 1st, 3rd and 2nd, 4th string digit and convert into num using parseInt +}; diff --git a/javascript/2235-add-two-integers.js b/javascript/2235-add-two-integers.js index 0ab61fe5a..9d871c93d 100644 --- a/javascript/2235-add-two-integers.js +++ b/javascript/2235-add-two-integers.js @@ -5,4 +5,4 @@ */ var sum = function (num1, num2) { return num1 + num2; // add num1 and num2 and return it -}; \ No newline at end of file +}; diff --git a/javascript/2306-naming-a-company.js b/javascript/2306-naming-a-company.js index 652daa7a2..991e792c5 100644 --- a/javascript/2306-naming-a-company.js +++ b/javascript/2306-naming-a-company.js @@ -2,7 +2,7 @@ * @param {string[]} ideas * @return {number} */ -var distinctNames = function(ideas) { +var distinctNames = function (ideas) { let sets = []; for (let i = 0; i < 26; i++) { sets[i] = new Set(); @@ -26,9 +26,9 @@ var distinctNames = function(ideas) { let res = 0; for (let i = 0; i < 26; i++) { for (let j = i + 1; j < 26; j++) { - res += (sets[i].size - same[i][j]) * (sets[j].size - same[i][j]) * 2; + res += + (sets[i].size - same[i][j]) * (sets[j].size - same[i][j]) * 2; } } return res; - -}; \ No newline at end of file +}; diff --git a/javascript/2331-evaluate-boolean-binary-tree.js b/javascript/2331-evaluate-boolean-binary-tree.js index 8f9018b57..1a09a90e4 100644 --- a/javascript/2331-evaluate-boolean-binary-tree.js +++ b/javascript/2331-evaluate-boolean-binary-tree.js @@ -13,19 +13,17 @@ * @param {TreeNode} root * @return {boolean} */ -var evaluateTree = function(root) { +var evaluateTree = function (root) { return dfs(root); }; const dfs = (node) => { - if (!node.left && !node.right && node.val) return true; if (!node.left && !node.right && !node.val) return false; - - const is2 = (node.val === 2); + + const is2 = node.val === 2; if (is2) return dfs(node.left) || dfs(node.right); - - const is3 = (node.val === 3); - if (is3) return dfs(node.left) && dfs(node.right); -} + const is3 = node.val === 3; + if (is3) return dfs(node.left) && dfs(node.right); +}; diff --git a/javascript/2348-number-of-zero-filled-subarrays.js b/javascript/2348-number-of-zero-filled-subarrays.js index 7d445f219..3b61a5cd9 100644 --- a/javascript/2348-number-of-zero-filled-subarrays.js +++ b/javascript/2348-number-of-zero-filled-subarrays.js @@ -32,4 +32,4 @@ let zeroFilledSubarray = function (nums) { } return result; -}; \ No newline at end of file +}; diff --git a/javascript/2390-removing-stars-from-a-string.js b/javascript/2390-removing-stars-from-a-string.js index d23be4497..5e519a343 100644 --- a/javascript/2390-removing-stars-from-a-string.js +++ b/javascript/2390-removing-stars-from-a-string.js @@ -1,13 +1,13 @@ -var removeStars = function(s) { - if(!s.length) return ''; +var removeStars = function (s) { + if (!s.length) return ''; const result = []; - for(let char of s){ - if(char == '*') result.pop() - else result.push(char) + for (let char of s) { + if (char == '*') result.pop(); + else result.push(char); } - return result.join('') + return result.join(''); }; // Time Complexity: O(n) // Space Complexity: O(n) diff --git a/javascript/2427-number-of-common-factors.js b/javascript/2427-number-of-common-factors.js index e6ebe8d5e..08f79f771 100644 --- a/javascript/2427-number-of-common-factors.js +++ b/javascript/2427-number-of-common-factors.js @@ -9,7 +9,6 @@ var commonFactors = function (a, b) { // loop thorugh every number from 1 to min for (let i = 1; i <= min; i++) { - // if a anf b both divisable by i then push i into array arr if (a % i == 0 && b % i == 0) { arr.push(i); @@ -18,4 +17,4 @@ var commonFactors = function (a, b) { // return length of array arr return arr.length; -}; \ No newline at end of file +}; diff --git a/javascript/2439-minimize-maximum-of-array.js b/javascript/2439-minimize-maximum-of-array.js index 5e106276d..3a9baf316 100644 --- a/javascript/2439-minimize-maximum-of-array.js +++ b/javascript/2439-minimize-maximum-of-array.js @@ -3,8 +3,7 @@ * @param {number[]} nums * @return {number} */ -var minimizeArrayValue = function(nums) { - +var minimizeArrayValue = function (nums) { let currTotal = nums[0]; let max = nums[0]; diff --git a/javascript/2469-convert-the-temperature.js b/javascript/2469-convert-the-temperature.js index 36e4359b7..308e45a3a 100644 --- a/javascript/2469-convert-the-temperature.js +++ b/javascript/2469-convert-the-temperature.js @@ -2,8 +2,8 @@ * @param {number} celsius * @return {number[]} */ -var convertTemperature = function(celsius) { +var convertTemperature = function (celsius) { let kelvin = celsius + 273.15; // initialize kelvin and add 273.15 to celsius - let fahrenheit = (celsius * 1.80) + 32; // initialize fahrenheit and multiply 1.80 to celsius and add 32 + let fahrenheit = celsius * 1.8 + 32; // initialize fahrenheit and multiply 1.80 to celsius and add 32 return [kelvin, fahrenheit]; // return kelvin and fahrenheit as an array -}; \ No newline at end of file +}; diff --git a/javascript/2485-find-the-pivot-integer.js b/javascript/2485-find-the-pivot-integer.js index 563788033..c81149ed1 100644 --- a/javascript/2485-find-the-pivot-integer.js +++ b/javascript/2485-find-the-pivot-integer.js @@ -3,13 +3,12 @@ * @return {number} */ var pivotInteger = function (n) { - // calculate the total sum fo n - const totalSum = n * (n + 1) / 2; + const totalSum = (n * (n + 1)) / 2; // find the square root of totalSum using Math.sqrt() const sqrtVal = Math.sqrt(totalSum); // if sqrtVal is equal to round down value of sqrtVal then return round down value of sqrtVal otherwise -1 return Math.floor(sqrtVal) === sqrtVal ? Math.floor(sqrtVal) : -1; -}; \ No newline at end of file +}; diff --git a/javascript/2542-maximum-subsequence-score.js b/javascript/2542-maximum-subsequence-score.js index 7e3d45ee7..c75831076 100644 --- a/javascript/2542-maximum-subsequence-score.js +++ b/javascript/2542-maximum-subsequence-score.js @@ -7,12 +7,11 @@ * @param {number} k * @return {number} */ -var maxScore = function(nums1, nums2, k) { - +var maxScore = function (nums1, nums2, k) { const minQ = new MinPriorityQueue({ - compare: (a,b) => { + compare: (a, b) => { return a - b; - } + }, }); let maxScore = 0; @@ -23,21 +22,21 @@ var maxScore = function(nums1, nums2, k) { return [num, nums2[idx]]; }); - nums12.sort((a,b) => { + nums12.sort((a, b) => { return b[1] - a[1]; }); - - for(let i = 0; i < nums12.length; i++) { + + for (let i = 0; i < nums12.length; i++) { const n1 = nums12[i][0]; const n2 = nums12[i][1]; runningTotal += n1; minQ.enqueue(n1); - if(minQ.size() === k) { + if (minQ.size() === k) { maxScore = Math.max(maxScore, runningTotal * n2); } - if(minQ.size() > k) { + if (minQ.size() > k) { runningTotal -= minQ.dequeue(); maxScore = Math.max(maxScore, runningTotal * n2); } diff --git a/javascript/2621-sleep.js b/javascript/2621-sleep.js index 3e79979bf..5b8d6dff6 100644 --- a/javascript/2621-sleep.js +++ b/javascript/2621-sleep.js @@ -3,10 +3,12 @@ * @return {Promise} */ async function sleep(millis) { - return new Promise(resolve => setTimeout(() => resolve("Completed!"), millis)); + return new Promise((resolve) => + setTimeout(() => resolve('Completed!'), millis), + ); } -/** +/** * let t = Date.now() * sleep(100).then(() => console.log(Date.now() - t)) // 100 */ diff --git a/javascript/2623-memoize.js b/javascript/2623-memoize.js index 9fd662e49..787320ec4 100644 --- a/javascript/2623-memoize.js +++ b/javascript/2623-memoize.js @@ -6,13 +6,12 @@ function memoize(fn) { let memo = {}; return function (...args) { let argsjson = JSON.stringify(args); - if (memo.hasOwnProperty(argsjson)) - return memo[argsjson]; - return memo[argsjson] = fn(...args); - } + if (memo.hasOwnProperty(argsjson)) return memo[argsjson]; + return (memo[argsjson] = fn(...args)); + }; } -/** +/** * let callCount = 0; * const memoizedFn = memoize(function (a, b) { * callCount += 1; @@ -20,5 +19,5 @@ function memoize(fn) { * }) * memoizedFn(2, 3) // 5 * memoizedFn(2, 3) // 5 - * console.log(callCount) // 1 + * console.log(callCount) // 1 */ diff --git a/javascript/2626-array-reduce-transformation.js b/javascript/2626-array-reduce-transformation.js index f695fe046..0fc48cee8 100644 --- a/javascript/2626-array-reduce-transformation.js +++ b/javascript/2626-array-reduce-transformation.js @@ -6,7 +6,6 @@ */ var reduce = function (nums, fn, init) { ans = init; - for (let n of nums) - ans = fn(ans, n); + for (let n of nums) ans = fn(ans, n); return ans; }; diff --git a/javascript/2627-debounce.js b/javascript/2627-debounce.js index 55c83420d..a41b1c987 100644 --- a/javascript/2627-debounce.js +++ b/javascript/2627-debounce.js @@ -8,7 +8,7 @@ var debounce = function (fn, t) { return function (...args) { clearTimeout(timeoutHandle); timeoutHandle = setTimeout(() => fn(...args), t); - } + }; }; /** diff --git a/javascript/2628-json-deep-equal.js b/javascript/2628-json-deep-equal.js index 908a392a2..188112033 100644 --- a/javascript/2628-json-deep-equal.js +++ b/javascript/2628-json-deep-equal.js @@ -3,18 +3,20 @@ * @param {any} o2 * @return {boolean} */ -var areDeeplyEqual = function(o1, o2) { +var areDeeplyEqual = function (o1, o2) { if (o1 === null || o2 === null) { return o1 === o2; } - if (typeof o1 !== typeof o2) { + if (typeof o1 !== typeof o2) { return false; } - if (typeof o1 !== 'object') { // primitives + if (typeof o1 !== 'object') { + // primitives return o1 === o2; } - if (Array.isArray(o1) && Array.isArray(o2)) { // Arrays + if (Array.isArray(o1) && Array.isArray(o2)) { + // Arrays if (o1.length !== o2.length) { return false; } @@ -23,7 +25,8 @@ var areDeeplyEqual = function(o1, o2) { return false; } } - } else if (!Array.isArray(o1) && !Array.isArray(o2)) { // Objects + } else if (!Array.isArray(o1) && !Array.isArray(o2)) { + // Objects if (Object.keys(o1).length !== Object.keys(o2).length) { return false; } diff --git a/javascript/2629-function-composition.js b/javascript/2629-function-composition.js index 6899a5d4e..c8ec62f79 100644 --- a/javascript/2629-function-composition.js +++ b/javascript/2629-function-composition.js @@ -5,10 +5,9 @@ var compose = function (functions) { return function (x) { let ans = x; - for (fn of functions.reverse()) - ans = fn(ans); + for (fn of functions.reverse()) ans = fn(ans); return ans; - } + }; }; /** diff --git a/javascript/2632-curry.js b/javascript/2632-curry.js index ed6ee86bb..160078d70 100644 --- a/javascript/2632-curry.js +++ b/javascript/2632-curry.js @@ -5,12 +5,10 @@ var curry = function (fn) { let accum = []; return function curried(...args) { - for (let arg of args) - accum.push(arg); - if (accum.length === fn.length) - return fn(...accum); + for (let arg of args) accum.push(arg); + if (accum.length === fn.length) return fn(...accum); return curried; - } + }; }; /** diff --git a/javascript/2634-filter-elements-from-array.js b/javascript/2634-filter-elements-from-array.js index 57ff4277c..f8e0ba8cb 100644 --- a/javascript/2634-filter-elements-from-array.js +++ b/javascript/2634-filter-elements-from-array.js @@ -5,8 +5,6 @@ */ var filter = function (arr, fn) { ans = []; - for (let i = 0; i < arr.length; i++) - if (fn(arr[i], i)) - ans.push(arr[i]); + for (let i = 0; i < arr.length; i++) if (fn(arr[i], i)) ans.push(arr[i]); return ans; }; diff --git a/javascript/2635-apply-transform-over-each-element-in-array.js b/javascript/2635-apply-transform-over-each-element-in-array.js index 419dd3ef2..e1624be1e 100644 --- a/javascript/2635-apply-transform-over-each-element-in-array.js +++ b/javascript/2635-apply-transform-over-each-element-in-array.js @@ -9,4 +9,4 @@ const map = (arr, fn) => { result.push(fn(arr[i], i)); } return result; -} \ No newline at end of file +}; diff --git a/javascript/2651-calculate-delayed-arrival-time.js b/javascript/2651-calculate-delayed-arrival-time.js index cc3c00c49..cbef451f4 100644 --- a/javascript/2651-calculate-delayed-arrival-time.js +++ b/javascript/2651-calculate-delayed-arrival-time.js @@ -6,11 +6,14 @@ var findDelayedArrivalTime = function (arrivalTime, delayedTime) { let totalTime = arrivalTime + delayedTime; // initialize totalTime is the sum of arrivalTime and delayedTime - if (totalTime == 24) { // if totalTime is equal to 24 then return 0 + if (totalTime == 24) { + // if totalTime is equal to 24 then return 0 return 0; - } else if (totalTime < 24) { // if totalTime is less than 24 then return totalTime + } else if (totalTime < 24) { + // if totalTime is less than 24 then return totalTime return totalTime; - } else { // else return subtraction of totalTime to 24 + } else { + // else return subtraction of totalTime to 24 return totalTime - 24; } -}; \ No newline at end of file +}; diff --git a/javascript/2652-sum-multiples.js b/javascript/2652-sum-multiples.js index 7cf8b0b48..8c93ca82b 100644 --- a/javascript/2652-sum-multiples.js +++ b/javascript/2652-sum-multiples.js @@ -4,11 +4,13 @@ */ var sumOfMultiples = function (n) { let arr = []; // initilialize an empty array - for (let i = 1; i <= n; i++) { // loop through the 1 to n - if ((i % 3 === 0) || (i % 5 === 0) || (i % 7 === 0)) { // if i is divisible by 3 or 5 or 7 then push i into arr + for (let i = 1; i <= n; i++) { + // loop through the 1 to n + if (i % 3 === 0 || i % 5 === 0 || i % 7 === 0) { + // if i is divisible by 3 or 5 or 7 then push i into arr arr.push(i); } } let result = arr.reduce((a, b) => a + b, 0); // find sum of all element of arr and store into result return result; // return the result -}; \ No newline at end of file +}; diff --git a/javascript/2665-counter-ii.js b/javascript/2665-counter-ii.js index 9c2d9b451..c2eb054a2 100644 --- a/javascript/2665-counter-ii.js +++ b/javascript/2665-counter-ii.js @@ -2,7 +2,7 @@ * @param {integer} init * @return { increment: Function, decrement: Function, reset: Function } */ -var createCounter = function(init) { +var createCounter = function (init) { let count = init; increment = () => ++count; @@ -10,15 +10,15 @@ var createCounter = function(init) { decrement = () => --count; reset = () => { - count = init; - return count; - } + count = init; + return count; + }; return { - increment, - decrement, - reset - } + increment, + decrement, + reset, + }; }; /** diff --git a/javascript/2666-allow-one-function-call.js b/javascript/2666-allow-one-function-call.js index 34afa8fba..a0f9bec40 100644 --- a/javascript/2666-allow-one-function-call.js +++ b/javascript/2666-allow-one-function-call.js @@ -9,7 +9,7 @@ var once = function (fn) { called = true; return fn(...args); } - } + }; }; /** diff --git a/javascript/2667-create-hello-world-function.js b/javascript/2667-create-hello-world-function.js index 034fe6c50..afe59a567 100644 --- a/javascript/2667-create-hello-world-function.js +++ b/javascript/2667-create-hello-world-function.js @@ -1,10 +1,10 @@ /** * @return {Function} */ -var createHelloWorld = function() { - return function(...args) { - return "Hello World" - } +var createHelloWorld = function () { + return function (...args) { + return 'Hello World'; + }; }; /** diff --git a/javascript/2704-to-be-or-not-to-be.js b/javascript/2704-to-be-or-not-to-be.js index 4231b276c..cea06d689 100644 --- a/javascript/2704-to-be-or-not-to-be.js +++ b/javascript/2704-to-be-or-not-to-be.js @@ -1,16 +1,18 @@ /** * Creates an expectation object for testing values. - * + * * @param {any} val - The value to be tested. * @returns {Object} An object with two methods: * - toBe(expected): Returns true if val === expected, otherwise throws an error "Not Equal". * - notToBe(expected): Returns true if val !== expected, otherwise throws an error "Equal". */ const expect = (val) => { - const throwError = (message) => { throw new Error(message); }; + const throwError = (message) => { + throw new Error(message); + }; return { - toBe: (expected) => val === expected || throwError("Not Equal"), - notToBe: (expected) => val !== expected || throwError("Equal") + toBe: (expected) => val === expected || throwError('Not Equal'), + notToBe: (expected) => val !== expected || throwError('Equal'), }; }; @@ -18,4 +20,4 @@ const expect = (val) => { // expect(5).toBe(5); // returns true // expect(5).notToBe(3); // returns true // expect(5).toBe(3); // throws "Not Equal" -// expect(5).notToBe(5); // throws "Equal" \ No newline at end of file +// expect(5).notToBe(5); // throws "Equal" diff --git a/javascript/2706-buy-two-chocolates.js b/javascript/2706-buy-two-chocolates.js index b3ec36584..17f091284 100644 --- a/javascript/2706-buy-two-chocolates.js +++ b/javascript/2706-buy-two-chocolates.js @@ -6,10 +6,15 @@ * @param {number} money * @return {number} */ -var buyChoco = function(prices, money) { - - const [cheapestChocolate] = prices.splice(prices.indexOf(Math.min(...prices)), 1); - const [secondCheapestChocolate] = prices.splice(prices.indexOf(Math.min(...prices)), 1); +var buyChoco = function (prices, money) { + const [cheapestChocolate] = prices.splice( + prices.indexOf(Math.min(...prices)), + 1, + ); + const [secondCheapestChocolate] = prices.splice( + prices.indexOf(Math.min(...prices)), + 1, + ); const leftOverMoney = money - (cheapestChocolate + secondCheapestChocolate); - return leftOverMoney > -1 ? leftOverMoney : money; + return leftOverMoney > -1 ? leftOverMoney : money; }; diff --git a/javascript/2710-remove-trailing-zeros-from-a-string.js b/javascript/2710-remove-trailing-zeros-from-a-string.js index 3a212df02..a7213f37d 100644 --- a/javascript/2710-remove-trailing-zeros-from-a-string.js +++ b/javascript/2710-remove-trailing-zeros-from-a-string.js @@ -3,10 +3,11 @@ * @return {string} */ var removeTrailingZeros = function (num) { - - for (let i = num.length - 1; i >= 0; i--) { // loop through the every element of string num from end - if (num[i] != 0) { // if every character of num is not equal to zero + for (let i = num.length - 1; i >= 0; i--) { + // loop through the every element of string num from end + if (num[i] != 0) { + // if every character of num is not equal to zero return num.slice(0, i + 1); // return the character of num upto ith character } } -}; \ No newline at end of file +}; diff --git a/javascript/2769-find-the-maximum-achievable-number.js b/javascript/2769-find-the-maximum-achievable-number.js index 7b4c3c11c..fe007e53b 100644 --- a/javascript/2769-find-the-maximum-achievable-number.js +++ b/javascript/2769-find-the-maximum-achievable-number.js @@ -4,5 +4,5 @@ * @return {number} */ var theMaximumAchievableX = function (num, t) { - return num + (t * 2) // return sum of value of num and twice the value of t -}; \ No newline at end of file + return num + t * 2; // return sum of value of num and twice the value of t +}; diff --git a/javascript/2810-faulty-keyboard.js b/javascript/2810-faulty-keyboard.js index 0db8aa2f2..362fe8426 100644 --- a/javascript/2810-faulty-keyboard.js +++ b/javascript/2810-faulty-keyboard.js @@ -4,11 +4,10 @@ */ var finalString = function (s) { // initialize empty string str - let str = ""; + let str = ''; // loop thorugh the every character of string s for (let i = 0; i < s.length; i++) { - // if every character of string is i then reverse the previous string character and store in string str if (s[i] == 'i') { str = [...str].reverse().join(''); @@ -20,4 +19,4 @@ var finalString = function (s) { // return string str return str; -}; \ No newline at end of file +}; diff --git a/javascript/2864-maximum-odd-binary-number.js b/javascript/2864-maximum-odd-binary-number.js index c44db142a..f59e75489 100644 --- a/javascript/2864-maximum-odd-binary-number.js +++ b/javascript/2864-maximum-odd-binary-number.js @@ -4,18 +4,17 @@ * @param {string} s * @return {string} */ -var maximumOddBinaryNumber = function(s) { - - let numberOf1s = s.split("").filter((bit) => bit === "1").length; - s = s.split("").map((bit) => "0"); +var maximumOddBinaryNumber = function (s) { + let numberOf1s = s.split('').filter((bit) => bit === '1').length; + s = s.split('').map((bit) => '0'); let i = 0; while (numberOf1s > 1) { - s[i] = "1"; + s[i] = '1'; i++; numberOf1s--; } s[s.length - 1] = 1; - return s.join(""); + return s.join(''); }; diff --git a/kotlin/1143-longest-common-subsequence.kt b/kotlin/1143-longest-common-subsequence.kt index 55dc1f154..ea744645e 100644 --- a/kotlin/1143-longest-common-subsequence.kt +++ b/kotlin/1143-longest-common-subsequence.kt @@ -20,79 +20,4 @@ class Solution { } return dp[M][N] } -} - -/* - * Different solutions - */ - - // Recursion + Memoization, Time Complexity of O(n * m) and space complexity of O(n * m) -class Solution { - fun longestCommonSubsequence(t1: String, t2: String): Int { - val n = t1.length - val m = t2.length - val dp = Array (n) { IntArray (m) { -1 } } - - fun dfs(i: Int, j: Int): Int { - if (i == n || j == m) return 0 - if (dp[i][j] != -1) return dp[i][j] - - if (t1[i] == t2[j]) - dp[i][j] = 1 + dfs(i + 1, j + 1) - else - dp[i][j] = maxOf(dfs(i + 1, j), dfs(i, j + 1)) - - return dp[i][j] - } - - return dfs(0, 0) - } -} - -// Top down DP, Time Complexity of O(n * m) and space complexity of O(n * m) -class Solution { - fun longestCommonSubsequence(t1: String, t2: String): Int { - val n = t1.length - val m = t2.length - val dp = Array (n + 1) { IntArray (m + 1) } - - for (i in n - 1 downTo 0) { - for (j in m - 1 downTo 0) { - if (t1[i] == t2[j]) - dp[i][j] = 1 + dp[i + 1][j + 1] - else - dp[i][j] = maxOf(dp[i + 1][j], dp[i][j + 1]) - } - } - - return dp[0][0] - } -} - -// Optimized DP (Works both for both Top-down and Bottom-up, but here we use bottom-up approach) -// Time Complexity of O(n * m) and space complexity of O(maxOf(n, m)) -class Solution { - fun longestCommonSubsequence(t1: String, t2: String): Int { - val m = t1.length - val n = t2.length - if (m < n) return longestCommonSubsequence(t2, t1) - - var dp = IntArray (n + 1) - - for (i in m downTo 0) { - var newDp = IntArray (n + 1) - for (j in n downTo 0) { - if (i == m || j == n) { - newDp[j] = 0 - } else if (t1[i] == t2[j]) { - newDp[j] = 1 + dp[j + 1] - } else { - newDp[j] = maxOf(dp[j], newDp[j + 1]) - } - } - dp = newDp - } - - return dp[0] - } -} +} \ No newline at end of file diff --git a/package-lock.json b/package-lock.json new file mode 100644 index 000000000..77b33b37e --- /dev/null +++ b/package-lock.json @@ -0,0 +1,27 @@ +{ + "name": "leetcode", + "lockfileVersion": 3, + "requires": true, + "packages": { + "": { + "dependencies": { + "prettier": "^3.6.2" + } + }, + "node_modules/prettier": { + "version": "3.6.2", + "resolved": "https://registry.npmjs.org/prettier/-/prettier-3.6.2.tgz", + "integrity": "sha512-I7AIg5boAr5R0FFtJ6rCfD+LFsWHp81dolrFD8S79U9tb8Az2nGrJncnMSnys+bpQJfRUzqs9hnA81OAA3hCuQ==", + "license": "MIT", + "bin": { + "prettier": "bin/prettier.cjs" + }, + "engines": { + "node": ">=14" + }, + "funding": { + "url": "https://github.com/prettier/prettier?sponsor=1" + } + } + } +} diff --git a/package.json b/package.json new file mode 100644 index 000000000..f8de3da1e --- /dev/null +++ b/package.json @@ -0,0 +1,8 @@ +{ + "scripts": { + "format": "prettier --write \"**/**/*.{js,ts,md,json}\"" + }, + "dependencies": { + "prettier": "^3.6.2" + } +} diff --git a/python/0020-valid-parentheses.py b/python/0020-valid-parentheses.py index 4d0ae3424..ce3bf39cd 100644 --- a/python/0020-valid-parentheses.py +++ b/python/0020-valid-parentheses.py @@ -1,13 +1,13 @@ class Solution: def isValid(self, s: str) -> bool: - Map = {")": "(", "]": "[", "}": "{"} + bracketMap = {")": "(", "]": "[", "}": "{"} stack = [] for c in s: - if c not in Map: + if c not in bracketMap: stack.append(c) continue - if not stack or stack[-1] != Map[c]: + if not stack or stack[-1] != bracketMap[c]: return False stack.pop() diff --git a/typescript/0002-add-two-numbers.ts b/typescript/0002-add-two-numbers.ts index 94e91f412..469606fbb 100644 --- a/typescript/0002-add-two-numbers.ts +++ b/typescript/0002-add-two-numbers.ts @@ -12,7 +12,7 @@ function addTwoNumbers( l1: ListNode | null, - l2: ListNode | null + l2: ListNode | null, ): ListNode | null { let dummyNode: ListNode = new ListNode(); let currentNode: ListNode = dummyNode; diff --git a/typescript/0014-longest-common-prefix.ts b/typescript/0014-longest-common-prefix.ts index ca4e44848..0c12d85a7 100644 --- a/typescript/0014-longest-common-prefix.ts +++ b/typescript/0014-longest-common-prefix.ts @@ -1,14 +1,14 @@ function longestCommonPrefix(strs: string[]): string { - let res = ""; - + let res = ''; + for (let i = 0; i < strs[0].length; i++) { for (const s of strs) { if (i == s.length || s[i] !== strs[0][i]) { return res; } } - res += strs[0][i] + res += strs[0][i]; } - + return res; -}; \ No newline at end of file +} diff --git a/typescript/0018-4sum.ts b/typescript/0018-4sum.ts index dfe86108f..de17b4be3 100644 --- a/typescript/0018-4sum.ts +++ b/typescript/0018-4sum.ts @@ -25,7 +25,7 @@ function fourSum(nums: number[], target: number): number[][] { right--; } else { res.push( - quad.concat([sortedNums[left], sortedNums[right]]) + quad.concat([sortedNums[left], sortedNums[right]]), ); left++; while ( diff --git a/typescript/0021-merge-two-sorted-lists.ts b/typescript/0021-merge-two-sorted-lists.ts index 83dbbef75..6ecf9c179 100644 --- a/typescript/0021-merge-two-sorted-lists.ts +++ b/typescript/0021-merge-two-sorted-lists.ts @@ -12,7 +12,7 @@ function mergeTwoLists( list1: ListNode | null, - list2: ListNode | null + list2: ListNode | null, ): ListNode | null { let dummyList: ListNode = new ListNode(0); let currentNode: ListNode = dummyList; diff --git a/typescript/0023-merge-k-sorted-lists.ts b/typescript/0023-merge-k-sorted-lists.ts index 51a0c4bdf..50c3f21ca 100644 --- a/typescript/0023-merge-k-sorted-lists.ts +++ b/typescript/0023-merge-k-sorted-lists.ts @@ -31,7 +31,7 @@ function mergeKLists(lists: Array): ListNode | null { function mergeList( list1: ListNode | null, - list2: ListNode | null + list2: ListNode | null, ): ListNode | null { let dummyNode: ListNode | null = new ListNode(); let tail = dummyNode; diff --git a/typescript/0047-permutations-ii.ts b/typescript/0047-permutations-ii.ts index 259c0652e..447e41054 100644 --- a/typescript/0047-permutations-ii.ts +++ b/typescript/0047-permutations-ii.ts @@ -24,4 +24,4 @@ function permuteUnique(nums: number[]): number[][] { traverse(); return results; -}; +} diff --git a/typescript/0056-merge-intervals.ts b/typescript/0056-merge-intervals.ts index 0835cb77f..2785e9ea5 100644 --- a/typescript/0056-merge-intervals.ts +++ b/typescript/0056-merge-intervals.ts @@ -1,25 +1,27 @@ function merge(intervals: number[][]): number[][] { - intervals.sort(([aStart, aEnd], [bStart, bEnd]) => aStart !== bStart ? aStart - bStart : aEnd - bEnd); - + intervals.sort(([aStart, aEnd], [bStart, bEnd]) => + aStart !== bStart ? aStart - bStart : aEnd - bEnd, + ); + return mergeInterval(intervals); -}; +} function mergeInterval(intervals: number[][]): number[][] { let merged = []; let prev = intervals.shift(); - + for (const curr of intervals) { const [prevStart, prevEnd] = prev; const [currStart, currEnd] = curr; - + // Overlap occurs if (currStart <= prevEnd) { prev[1] = Math.max(prev[1], curr[1]); continue; } - + merged.push(prev); prev = curr; } return [...merged, prev]; -} \ No newline at end of file +} diff --git a/typescript/0057-insert-interval.ts b/typescript/0057-insert-interval.ts index 9b63bae71..22a587172 100644 --- a/typescript/0057-insert-interval.ts +++ b/typescript/0057-insert-interval.ts @@ -3,12 +3,13 @@ function insert(intervals: number[][], newInterval: number[]): number[][] { const afterIndex = mergeIntervals(intervals, newInterval, beforeIndex); const after = intervals.slice(afterIndex); - return [...before, newInterval, ...after]; -}; + return [...before, newInterval, ...after]; +} const getBefore = (intervals, newInterval, index = 0, before = []) => { - const hasGap = ([prevStart, prevEnd], [currStart, currEnd]) => prevEnd < currStart; - + const hasGap = ([prevStart, prevEnd], [currStart, currEnd]) => + prevEnd < currStart; + while (index < intervals.length && hasGap(intervals[index], newInterval)) { const current = intervals[index]; before.push(current); @@ -18,13 +19,17 @@ const getBefore = (intervals, newInterval, index = 0, before = []) => { }; const mergeIntervals = (intervals, newInterval, index) => { - const hasOverlap = ([prevStart, prevEnd], [currStart, currEnd]) => currStart <= prevEnd; + const hasOverlap = ([prevStart, prevEnd], [currStart, currEnd]) => + currStart <= prevEnd; - while (index < intervals.length && hasOverlap(newInterval, intervals[index])) { + while ( + index < intervals.length && + hasOverlap(newInterval, intervals[index]) + ) { const current = intervals[index]; newInterval[0] = Math.min(newInterval[0], current[0]); newInterval[1] = Math.max(newInterval[1], current[1]); index++; } return index; -}; \ No newline at end of file +}; diff --git a/typescript/0067-add-binary.ts b/typescript/0067-add-binary.ts index f77af8e62..7e61d5d50 100644 --- a/typescript/0067-add-binary.ts +++ b/typescript/0067-add-binary.ts @@ -1,11 +1,11 @@ function addBinary(a: string, b: string): string { - let res = "" - let carry = 0 + let res = ''; + let carry = 0; - a = a.split('').reverse().join('') - b = b.split('').reverse().join('') + a = a.split('').reverse().join(''); + b = b.split('').reverse().join(''); - for (let i = 0; i < (Math.max(a.length, b.length)); i++) { + for (let i = 0; i < Math.max(a.length, b.length); i++) { let digitA: number = i < a.length ? +a[i] : 0; let digitB: number = i < b.length ? +b[i] : 0; @@ -15,7 +15,7 @@ function addBinary(a: string, b: string): string { carry = Math.floor(total / 2); } if (carry) { - res = "1" + res; + res = '1' + res; } return res; -}; +} diff --git a/typescript/0072-edit-distance.ts b/typescript/0072-edit-distance.ts index 625810d41..ffca16ba4 100644 --- a/typescript/0072-edit-distance.ts +++ b/typescript/0072-edit-distance.ts @@ -1,5 +1,8 @@ function minDistance(word1: string, word2: string): number { - let dp = Array.from({ length: word2.length + 1 }, (_, i) => word2.length - i); + let dp = Array.from( + { length: word2.length + 1 }, + (_, i) => word2.length - i, + ); for (let i = word1.length - 1; i >= 0; i--) { const current = new Array(word2.length + 1); @@ -9,11 +12,7 @@ function minDistance(word1: string, word2: string): number { if (word1[i] === word2[j]) { current[j] = dp[j + 1]; } else { - current[j] = 1 + Math.min( - dp[j], - current[j + 1], - dp[j + 1], - ); + current[j] = 1 + Math.min(dp[j], current[j + 1], dp[j + 1]); } } @@ -21,4 +20,4 @@ function minDistance(word1: string, word2: string): number { } return dp[0]; -}; +} diff --git a/typescript/0073-set-matrix-zeroes.ts b/typescript/0073-set-matrix-zeroes.ts index 073c85ed0..7bc85a7e0 100644 --- a/typescript/0073-set-matrix-zeroes.ts +++ b/typescript/0073-set-matrix-zeroes.ts @@ -21,4 +21,4 @@ function setZeroes(matrix: number[][]): void { } } } -}; \ No newline at end of file +} diff --git a/typescript/0079-word-search.ts b/typescript/0079-word-search.ts index cbddab40a..7e4edc59d 100644 --- a/typescript/0079-word-search.ts +++ b/typescript/0079-word-search.ts @@ -1,46 +1,47 @@ function exist(board: string[][], word: string): boolean { - const rowsLength = board.length; - const colsLength = board[0].length; + const rowsLength = board.length; + const colsLength = board[0].length; - function outOfBounds(r: number, c: number) { - return r < 0 || c < 0 || r >= rowsLength || c >= colsLength; - } - - // idx: the index of the current character in the word we're looking for - function dfs(row: number, col: number, idx: number): boolean { - if (idx === word.length) { - return true; + function outOfBounds(r: number, c: number) { + return r < 0 || c < 0 || r >= rowsLength || c >= colsLength; } - if (outOfBounds(row, col) || word[idx] !== board[row][col]) { - return false; + + // idx: the index of the current character in the word we're looking for + function dfs(row: number, col: number, idx: number): boolean { + if (idx === word.length) { + return true; + } + if (outOfBounds(row, col) || word[idx] !== board[row][col]) { + return false; + } + + // Mark the current cell as visited + let currentCell = board[row][col]; + board[row][col] = '*'; + + // Pass idx + 1 because we're looking for + // the next character in the word now + let result = + dfs(row + 1, col, idx + 1) || // down + dfs(row - 1, col, idx + 1) || // up + dfs(row, col + 1, idx + 1) || // right + dfs(row, col - 1, idx + 1); // left + + // Reset the current cell to its original value + // because we're done visiting it + board[row][col] = currentCell; + + return result; } - // Mark the current cell as visited - let currentCell = board[row][col]; - board[row][col] = '*'; - - // Pass idx + 1 because we're looking for - // the next character in the word now - let result = dfs(row + 1, col, idx + 1) || // down - dfs(row - 1, col, idx + 1) || // up - dfs(row, col + 1, idx + 1) || // right - dfs(row, col - 1, idx + 1); // left - - // Reset the current cell to its original value - // because we're done visiting it - board[row][col] = currentCell; - - return result; - } - - // For each cell, do a depth-first search - for (let i = 0; i < rowsLength; i++) { - for (let j = 0; j < colsLength; j++) { - if (dfs(i, j, 0)) { - return true; - } + // For each cell, do a depth-first search + for (let i = 0; i < rowsLength; i++) { + for (let j = 0; j < colsLength; j++) { + if (dfs(i, j, 0)) { + return true; + } + } } - } - return false; + return false; } diff --git a/typescript/0094-binary-tree-inorder-traversal.ts b/typescript/0094-binary-tree-inorder-traversal.ts index 36aca4064..6f8ec1e72 100644 --- a/typescript/0094-binary-tree-inorder-traversal.ts +++ b/typescript/0094-binary-tree-inorder-traversal.ts @@ -1,23 +1,25 @@ -/** - * Definition for a binary tree node. - * class TreeNode { - * val: number - * left: TreeNode | null - * right: TreeNode | null - * constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } - * } - */ - function inorderTraversal(root: TreeNode | null, list: Array = [] ): number[] { - - if (!root) return []; - - inorderTraversal(root.left, list); - list.push(root.val) - inorderTraversal(root.right, list); - - return list -}; \ No newline at end of file +/** + * Definition for a binary tree node. + * class TreeNode { + * val: number + * left: TreeNode | null + * right: TreeNode | null + * constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + * } + */ +function inorderTraversal( + root: TreeNode | null, + list: Array = [], +): number[] { + if (!root) return []; + + inorderTraversal(root.left, list); + list.push(root.val); + inorderTraversal(root.right, list); + + return list; +} diff --git a/typescript/0098-validate-binary-search-tree.ts b/typescript/0098-validate-binary-search-tree.ts index d0971ef2a..ab05b42c7 100644 --- a/typescript/0098-validate-binary-search-tree.ts +++ b/typescript/0098-validate-binary-search-tree.ts @@ -19,7 +19,7 @@ function isValidBST(root: TreeNode | null): boolean { function validate( root: TreeNode | null, max: number | null, - min: number | null + min: number | null, ): boolean { if (!root) { return true; diff --git a/typescript/0127-word-ladder.ts b/typescript/0127-word-ladder.ts index 523206043..7b49fd924 100644 --- a/typescript/0127-word-ladder.ts +++ b/typescript/0127-word-ladder.ts @@ -1,7 +1,7 @@ function ladderLength( beginWord: string, endWord: string, - wordList: string[] + wordList: string[], ): number { if (!wordList.includes(endWord)) { return 0; diff --git a/typescript/0130-surrounded-regions.ts b/typescript/0130-surrounded-regions.ts index 1dfcc3740..426cb5b02 100644 --- a/typescript/0130-surrounded-regions.ts +++ b/typescript/0130-surrounded-regions.ts @@ -29,7 +29,7 @@ function solve(board: string[][]): void { } } -function markSeen(r: number, c: number): void { + function markSeen(r: number, c: number): void { if (!inBounds(r, c) || board[r][c] !== 'O') { return; } @@ -40,9 +40,9 @@ function markSeen(r: number, c: number): void { markSeen(r + 1, c); markSeen(r, c - 1); markSeen(r, c + 1); -} + } -function inBounds(r: number, c: number): boolean { + function inBounds(r: number, c: number): boolean { return r >= 0 && c >= 0 && r < rowLen && c < colLen; + } } -}; \ No newline at end of file diff --git a/typescript/0146-lru-cache.ts b/typescript/0146-lru-cache.ts index b9b92f77e..123efa88c 100644 --- a/typescript/0146-lru-cache.ts +++ b/typescript/0146-lru-cache.ts @@ -6,10 +6,10 @@ */ type CacheNode = { - value: number, - key: number | null, - next: CacheNode | null, - prev: CacheNode | null, + value: number; + key: number | null; + next: CacheNode | null; + prev: CacheNode | null; }; class LRUCache { @@ -44,20 +44,20 @@ class LRUCache { this.head.next.prev = node; this.head.next = node; - + return node.value; } put(key: number, value: number): void { let node = this.data.get(key); if (!node) { - this.size++; - node = { value, key } as CacheNode; - this.data.set(key, node); + this.size++; + node = { value, key } as CacheNode; + this.data.set(key, node); } else { - node.value = value; - node.prev.next = node.next; - node.next.prev = node.prev; + node.value = value; + node.prev.next = node.next; + node.next.prev = node.prev; } node.next = this.head.next; @@ -67,7 +67,7 @@ class LRUCache { this.head.next = node; if (this.size > this.capacity) { - this.evict(); + this.evict(); } } diff --git a/typescript/0203-remove-linked-list-elements.ts b/typescript/0203-remove-linked-list-elements.ts index 19522876a..c2ae88785 100644 --- a/typescript/0203-remove-linked-list-elements.ts +++ b/typescript/0203-remove-linked-list-elements.ts @@ -1,33 +1,31 @@ -/** - * Definition for singly-linked list. - * class ListNode { - * val: number - * next: ListNode | null - * constructor(val?: number, next?: ListNode | null) { - * this.val = (val===undefined ? 0 : val) - * this.next = (next===undefined ? null : next) - * } - * } - */ - -function removeElements(head: ListNode | null, val: number): ListNode | null { - - let sentinel_node : ListNode = new ListNode(0, head); - let slow_pointer : ListNode | null = sentinel_node; - let fast_pointer : ListNode | null = null; - - while (slow_pointer) { - - // get next legible node - fast_pointer = slow_pointer.next; - while (fast_pointer && fast_pointer.val === val) { - fast_pointer = fast_pointer.next; - } - - // Set next node to the legible node - slow_pointer.next = fast_pointer; - slow_pointer = slow_pointer.next; - } - - return sentinel_node.next; -}; \ No newline at end of file +/** + * Definition for singly-linked list. + * class ListNode { + * val: number + * next: ListNode | null + * constructor(val?: number, next?: ListNode | null) { + * this.val = (val===undefined ? 0 : val) + * this.next = (next===undefined ? null : next) + * } + * } + */ + +function removeElements(head: ListNode | null, val: number): ListNode | null { + let sentinel_node: ListNode = new ListNode(0, head); + let slow_pointer: ListNode | null = sentinel_node; + let fast_pointer: ListNode | null = null; + + while (slow_pointer) { + // get next legible node + fast_pointer = slow_pointer.next; + while (fast_pointer && fast_pointer.val === val) { + fast_pointer = fast_pointer.next; + } + + // Set next node to the legible node + slow_pointer.next = fast_pointer; + slow_pointer = slow_pointer.next; + } + + return sentinel_node.next; +} diff --git a/typescript/0211-design-add-and-search-words-data-structure.ts b/typescript/0211-design-add-and-search-words-data-structure.ts index 2bbcdd69a..2bdf84d47 100644 --- a/typescript/0211-design-add-and-search-words-data-structure.ts +++ b/typescript/0211-design-add-and-search-words-data-structure.ts @@ -37,7 +37,7 @@ class WordDictionary { if ( Object.prototype.hasOwnProperty.call( cur.children, - key + key, ) ) { const child = cur.children[key]; diff --git a/typescript/0212-word-search-ii.ts b/typescript/0212-word-search-ii.ts index bd23c5cc8..f766edf0d 100644 --- a/typescript/0212-word-search-ii.ts +++ b/typescript/0212-word-search-ii.ts @@ -35,7 +35,7 @@ function findWords(board: string[][], words: string[]): string[] { const currentChar = board[r][c]; const currentNode = node.children[currentChar]; if (!currentNode) return; - + const currentWord = word + currentChar; if (currentNode.word) { resultSet.add(currentWord); @@ -62,4 +62,4 @@ function findWords(board: string[][], words: string[]): string[] { } return [...resultSet]; -}; +} diff --git a/typescript/0213-house-robber-ii.ts b/typescript/0213-house-robber-ii.ts index b8cbfe6f8..1e08c1de3 100644 --- a/typescript/0213-house-robber-ii.ts +++ b/typescript/0213-house-robber-ii.ts @@ -15,6 +15,6 @@ function rob(nums: number[]): number { return Math.max( nums[0], helper(nums.slice(0, nums.length - 1)), - helper(nums.slice(1)) + helper(nums.slice(1)), ); } diff --git a/typescript/0219-contains-duplicate-ii.ts b/typescript/0219-contains-duplicate-ii.ts index 6e0443338..562957e78 100644 --- a/typescript/0219-contains-duplicate-ii.ts +++ b/typescript/0219-contains-duplicate-ii.ts @@ -1,15 +1,15 @@ function containsNearbyDuplicate(nums: number[], k: number): boolean { - let map = new Map() - for(let i = 0; i < nums.length; i++){ - if(!map.has(nums[i])){ - map.set(nums[i], i) - }else{ - if(i - map.get(nums[i]) <= k){ - return true - }else{ - map.set(nums[i], i) + let map = new Map(); + for (let i = 0; i < nums.length; i++) { + if (!map.has(nums[i])) { + map.set(nums[i], i); + } else { + if (i - map.get(nums[i]) <= k) { + return true; + } else { + map.set(nums[i], i); } } } - return false -}; + return false; +} diff --git a/typescript/0235-lowest-common-ancestor-of-a-binary-search-tree.ts b/typescript/0235-lowest-common-ancestor-of-a-binary-search-tree.ts index 6d4db5b9b..9b8383a4e 100644 --- a/typescript/0235-lowest-common-ancestor-of-a-binary-search-tree.ts +++ b/typescript/0235-lowest-common-ancestor-of-a-binary-search-tree.ts @@ -15,7 +15,7 @@ function lowestCommonAncestor( root: TreeNode | null, p: TreeNode | null, - q: TreeNode | null + q: TreeNode | null, ): TreeNode | null { let cur = root; diff --git a/typescript/0256-paint-house.ts b/typescript/0256-paint-house.ts index 91039e223..046ba77ef 100644 --- a/typescript/0256-paint-house.ts +++ b/typescript/0256-paint-house.ts @@ -1,11 +1,11 @@ // Dynamic Programming, Time Complexity: O(n), Space Complexity: O(1) function minCost(costs: number[][]): number { let dp: number[] = [0, 0, 0]; - for ( const cost of costs ) { + for (const cost of costs) { let currMin0: number = cost[0] + Math.min(dp[1], dp[2]); let currMin1: number = cost[1] + Math.min(dp[0], dp[2]); let currMin2: number = cost[2] + Math.min(dp[0], dp[1]); dp = [currMin0, currMin1, currMin2]; } return Math.min(...dp); -}; +} diff --git a/typescript/0261-graph-valid-tree.ts b/typescript/0261-graph-valid-tree.ts index 99d286cd9..444e2a29d 100644 --- a/typescript/0261-graph-valid-tree.ts +++ b/typescript/0261-graph-valid-tree.ts @@ -28,7 +28,7 @@ function dfs( node: number, prevNode: number, visited: Visited, - adjacent: Obj + adjacent: Obj, ): boolean { if (visited[node]) return false; visited[node] = true; diff --git a/typescript/0295-find-median-from-data-stream.ts b/typescript/0295-find-median-from-data-stream.ts index 4feaac219..41a0771bd 100644 --- a/typescript/0295-find-median-from-data-stream.ts +++ b/typescript/0295-find-median-from-data-stream.ts @@ -1,7 +1,7 @@ /* - * Time Complexity: O(logn) - * Space Complexity: O(n) -*/ + * Time Complexity: O(logn) + * Space Complexity: O(n) + */ class MedianFinder { public minHeap; @@ -19,7 +19,10 @@ class MedianFinder { findMedian(): number { if (this.minHeap.size() === this.maxHeap.size()) { - return (this.minHeap.front().element + this.maxHeap.front().element) / 2; + return ( + (this.minHeap.front().element + this.maxHeap.front().element) / + 2 + ); } return this.maxHeap.front().element; diff --git a/typescript/0297-serialize-and-deserialize-binary-tree.ts b/typescript/0297-serialize-and-deserialize-binary-tree.ts index c60a3cc68..de85e9a56 100644 --- a/typescript/0297-serialize-and-deserialize-binary-tree.ts +++ b/typescript/0297-serialize-and-deserialize-binary-tree.ts @@ -27,7 +27,7 @@ function serialize(root: TreeNode | null): string { cereal(root); return box.join(','); -}; +} /* * Decodes your encoded data to tree. @@ -45,10 +45,9 @@ function deserialize(data: string): TreeNode | null { } return decereal(); -}; - +} /** * Your functions will be called as such: * deserialize(serialize(root)); - */ \ No newline at end of file + */ diff --git a/typescript/0303-range-sum-query-immutable.ts b/typescript/0303-range-sum-query-immutable.ts index 757a620a6..263b2e2e1 100644 --- a/typescript/0303-range-sum-query-immutable.ts +++ b/typescript/0303-range-sum-query-immutable.ts @@ -1,17 +1,16 @@ class NumArray { - prefixSums: number[] = []; constructor(nums: number[]) { this.prefixSums.push(nums[0]); - for(let i=1; i> 1; if (leftIndex > mid) { return this.right.queryRange(leftIndex, rightIndex); - } else if (rightIndex <= mid){ + } else if (rightIndex <= mid) { return this.left.queryRange(leftIndex, rightIndex); } - return this.left.queryRange(leftIndex, mid) + this.right.queryRange(mid + 1, rightIndex); + return ( + this.left.queryRange(leftIndex, mid) + + this.right.queryRange(mid + 1, rightIndex) + ); } } diff --git a/typescript/0309-best-time-to-buy-and-sell-stock-with-cooldown.ts b/typescript/0309-best-time-to-buy-and-sell-stock-with-cooldown.ts index 4b595a789..1cf3ed6f6 100644 --- a/typescript/0309-best-time-to-buy-and-sell-stock-with-cooldown.ts +++ b/typescript/0309-best-time-to-buy-and-sell-stock-with-cooldown.ts @@ -1,5 +1,5 @@ function maxProfit(prices: number[]): number { - let [ sold, hold, rest ] = [ 0, Number.MIN_SAFE_INTEGER, 0]; + let [sold, hold, rest] = [0, Number.MIN_SAFE_INTEGER, 0]; for (let i = 0; i < prices.length; i++) { let prevSold = sold; @@ -8,4 +8,4 @@ function maxProfit(prices: number[]): number { rest = Math.max(rest, prevSold); } return Math.max(sold, rest); -}; \ No newline at end of file +} diff --git a/typescript/0312-burst-balloons.ts b/typescript/0312-burst-balloons.ts index 510cf5982..5c29e0b6b 100644 --- a/typescript/0312-burst-balloons.ts +++ b/typescript/0312-burst-balloons.ts @@ -11,7 +11,7 @@ function maxCoins(nums: number[]): number { dp[i][j], dp[i][k - 1] + vals[i - 1] * vals[k] * vals[j + 1] + - dp[k + 1][j] + dp[k + 1][j], ); } } diff --git a/typescript/0347-top-k-frequent-elements.ts b/typescript/0347-top-k-frequent-elements.ts index 0baa7d127..241cb4400 100644 --- a/typescript/0347-top-k-frequent-elements.ts +++ b/typescript/0347-top-k-frequent-elements.ts @@ -4,7 +4,7 @@ function topKFrequent(nums: number[], k: number): number[] | undefined { } = {}; const freq: number[][] = Array.apply(null, Array(nums.length + 1)).map( - () => [] + () => [], ); nums.forEach((item) => { @@ -44,7 +44,7 @@ function topKFrequentNLogN(nums: number[], k: number): number[] { return Object.entries(map) .sort( - ([, countA], [, countB]) => (countB as number) - (countA as number) + ([, countA], [, countB]) => (countB as number) - (countA as number), ) .slice(0, k) .map(([num]) => +num); diff --git a/typescript/0417-pacific-atlantic-water-flow.ts b/typescript/0417-pacific-atlantic-water-flow.ts index 6dcbfb892..8ea2d35e7 100644 --- a/typescript/0417-pacific-atlantic-water-flow.ts +++ b/typescript/0417-pacific-atlantic-water-flow.ts @@ -1,32 +1,44 @@ /** * Breath First Search implementation - * @param matrix - * @param queue - * @param visited + * @param matrix + * @param queue + * @param visited */ -const bfs = (matrix: number[][], queue: number[][], visited: boolean[][]): void => { - let m = matrix.length, n = matrix[0].length; - let directions = [[1, 0], [-1, 0], [0, 1], [0, -1]]; +const bfs = ( + matrix: number[][], + queue: number[][], + visited: boolean[][], +): void => { + let m = matrix.length, + n = matrix[0].length; + let directions = [ + [1, 0], + [-1, 0], + [0, 1], + [0, -1], + ]; while (queue.length > 0) { const [qCordx, qCordy] = queue.shift()!; for (let dir of directions) { - const x = qCordx + dir[0], y = qCordy + dir[1]; - if (!( - x < 0 || - y < 0 || - x >= m || - y >= n || - visited[x][y] || - matrix[x][y] < matrix[qCordx][qCordy]) + const x = qCordx + dir[0], + y = qCordy + dir[1]; + if ( + !( + x < 0 || + y < 0 || + x >= m || + y >= n || + visited[x][y] || + matrix[x][y] < matrix[qCordx][qCordy] + ) ) { visited[x][y] = true; queue.push([x, y]); } - } } -} +}; /** * Creates a Matrix NXM with false values @@ -34,9 +46,9 @@ const bfs = (matrix: number[][], queue: number[][], visited: boolean[][]): void const createMatrix = (n: number, m: number): boolean[][] => Array.from({ length: n }, () => Array.from({ length: m }, () => false)); - function pacificAtlantic(heights: number[][]): number[][] { - const ROWS = heights.length, COLS = heights[0].length; + const ROWS = heights.length, + COLS = heights[0].length; let pacific: boolean[][] = createMatrix(ROWS, COLS); let atlantic: boolean[][] = createMatrix(ROWS, COLS); let pacQueue: number[][] = []; @@ -70,4 +82,4 @@ function pacificAtlantic(heights: number[][]): number[][] { } return results; -}; +} diff --git a/typescript/0435-non-overlapping-intervals.ts b/typescript/0435-non-overlapping-intervals.ts index f20df9d2b..8807ba711 100644 --- a/typescript/0435-non-overlapping-intervals.ts +++ b/typescript/0435-non-overlapping-intervals.ts @@ -1,24 +1,26 @@ function eraseOverlapIntervals(intervals: number[][]): number { - intervals.sort(([aStart, aEnd], [bStart, bEnd]) => aEnd !== bEnd ? aEnd - bEnd : aStart - bStart); - + intervals.sort(([aStart, aEnd], [bStart, bEnd]) => + aEnd !== bEnd ? aEnd - bEnd : aStart - bStart, + ); + return getGaps(intervals); -}; +} function getGaps(intervals: number[][]): number { let gaps = 0; const prev = intervals.shift(); - + for (const curr of intervals) { const [prevStart, prevEnd] = prev; const [currStart, currEnd] = curr; - + const hasGap = prevEnd <= currStart; if (!hasGap) { continue; } - + prev[1] = curr[1]; gaps++; } return intervals.length - gaps; -} \ No newline at end of file +} diff --git a/typescript/0438-find-all-anagrams-in-a-string.ts b/typescript/0438-find-all-anagrams-in-a-string.ts index 7b138b84b..3dbf81829 100644 --- a/typescript/0438-find-all-anagrams-in-a-string.ts +++ b/typescript/0438-find-all-anagrams-in-a-string.ts @@ -1,33 +1,34 @@ //Time Complexity -> O(n) //Space Complexity -> O(n) function findAnagrams(s: string, p: string): number[] { - if (p.length > s.length) return []; + if (p.length > s.length) return []; - const anagramIndexes: number[] = []; - const pCount = new Map(); - const sCount = new Map(); - for (const char of p) pCount.set(char, (pCount.get(char) || 0) + 1); - for (let i = 0; i < p.length; i++) sCount.set(s[i], (sCount.get(s[i]) || 0) + 1); + const anagramIndexes: number[] = []; + const pCount = new Map(); + const sCount = new Map(); + for (const char of p) pCount.set(char, (pCount.get(char) || 0) + 1); + for (let i = 0; i < p.length; i++) + sCount.set(s[i], (sCount.get(s[i]) || 0) + 1); - let l = 0; - let r = p.length - 1; - while (r < s.length) { - let isAnagram = true; - for (const [char, count] of pCount) { - if (!sCount.has(char) || sCount.get(char) !== count) { - isAnagram = false; - break; - } - } - if (isAnagram) anagramIndexes.push(l); + let l = 0; + let r = p.length - 1; + while (r < s.length) { + let isAnagram = true; + for (const [char, count] of pCount) { + if (!sCount.has(char) || sCount.get(char) !== count) { + isAnagram = false; + break; + } + } + if (isAnagram) anagramIndexes.push(l); - sCount.set(s[l], (sCount.get(s[l]) || 1) - 1); - if (sCount.get(s[l]) === 0) sCount.delete(s[l]); - l++; + sCount.set(s[l], (sCount.get(s[l]) || 1) - 1); + if (sCount.get(s[l]) === 0) sCount.delete(s[l]); + l++; - r++; - sCount.set(s[r], (sCount.get(s[r]) || 0) + 1); - } + r++; + sCount.set(s[r], (sCount.get(s[r]) || 0) + 1); + } - return anagramIndexes; + return anagramIndexes; } diff --git a/typescript/0474-ones-and-zeroes.ts b/typescript/0474-ones-and-zeroes.ts index 387c8765f..d4fdfd752 100644 --- a/typescript/0474-ones-and-zeroes.ts +++ b/typescript/0474-ones-and-zeroes.ts @@ -1,15 +1,17 @@ function findMaxForm(strs: string[], m: number, n: number): number { - const data = strs.reduce((accum, str) => { - let zeroes = 0; - for (let c of str) { - if (c === '0') zeroes++; - } - accum.push([zeroes, str.length - zeroes]); - return accum; - }, [] as [number, number][]); + const data = strs.reduce( + (accum, str) => { + let zeroes = 0; + for (let c of str) { + if (c === '0') zeroes++; + } + accum.push([zeroes, str.length - zeroes]); + return accum; + }, + [] as [number, number][], + ); - const dp = Array - .from({ length: m + 1 }, () => new Array(n + 1)); + const dp = Array.from({ length: m + 1 }, () => new Array(n + 1)); for (let i = 0; i < data.length; i++) { const [zeroes, ones] = data[i]; @@ -29,4 +31,4 @@ function findMaxForm(strs: string[], m: number, n: number): number { } return dp[m][n]; -}; +} diff --git a/typescript/0494-target-sum.ts b/typescript/0494-target-sum.ts index 7ce6bab2f..784d7c448 100644 --- a/typescript/0494-target-sum.ts +++ b/typescript/0494-target-sum.ts @@ -21,7 +21,7 @@ function findTargetSumWays(nums: number[], target: number): number { // DP: we memoize number of ways of each pair index, sum cache.set( `${i},${sum}`, - backTrack(i + 1, sum + nums[i]) + backTrack(i + 1, sum - nums[i]) + backTrack(i + 1, sum + nums[i]) + backTrack(i + 1, sum - nums[i]), ); return cache.get(`${i},${sum}`); @@ -30,7 +30,6 @@ function findTargetSumWays(nums: number[], target: number): number { return backTrack(0, 0); } - /** * DP - Bottom Up * Time O(N * M) | Space O(M) @@ -59,4 +58,4 @@ function findTargetSumWays(nums: number[], target: number): number { } return dp[total + target] ?? 0; -}; +} diff --git a/typescript/0502-ipo.ts b/typescript/0502-ipo.ts index 35c2f3ed2..e7bb0fc6d 100644 --- a/typescript/0502-ipo.ts +++ b/typescript/0502-ipo.ts @@ -1,4 +1,9 @@ -function findMaximizedCapital(k: number, w: number, profits: number[], capital: number[]): number { +function findMaximizedCapital( + k: number, + w: number, + profits: number[], + capital: number[], +): number { const minCapital = new PriorityQueue({ compare: (a, b) => a[1] - b[1] }); const maxProfit = new MaxPriorityQueue(); for (let i = 0; i < profits.length; i++) { @@ -18,4 +23,4 @@ function findMaximizedCapital(k: number, w: number, profits: number[], capital: } return profit; -}; +} diff --git a/typescript/0669-trim-a-binary-search-tree.ts b/typescript/0669-trim-a-binary-search-tree.ts index 30ef4f224..f136a9fe2 100644 --- a/typescript/0669-trim-a-binary-search-tree.ts +++ b/typescript/0669-trim-a-binary-search-tree.ts @@ -1,33 +1,36 @@ -/** - * Definition for a binary tree node. - * class TreeNode { - * val: number - * left: TreeNode | null - * right: TreeNode | null - * constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { - * this.val = (val===undefined ? 0 : val) - * this.left = (left===undefined ? null : left) - * this.right = (right===undefined ? null : right) - * } - * } - */ - -function trimBST(root: TreeNode | null, low: number, high: number): TreeNode | null { - - if (!root) { - return null; - } - - if (root.val < low) { - return trimBST(root.right, low, high); - } - - if (root.val > high) { - return trimBST(root.left, low, high); - } - - root.left = trimBST(root.left, low, high); - root.right = trimBST(root.right, low, high); - - return root; -}; \ No newline at end of file +/** + * Definition for a binary tree node. + * class TreeNode { + * val: number + * left: TreeNode | null + * right: TreeNode | null + * constructor(val?: number, left?: TreeNode | null, right?: TreeNode | null) { + * this.val = (val===undefined ? 0 : val) + * this.left = (left===undefined ? null : left) + * this.right = (right===undefined ? null : right) + * } + * } + */ + +function trimBST( + root: TreeNode | null, + low: number, + high: number, +): TreeNode | null { + if (!root) { + return null; + } + + if (root.val < low) { + return trimBST(root.right, low, high); + } + + if (root.val > high) { + return trimBST(root.left, low, high); + } + + root.left = trimBST(root.left, low, high); + root.right = trimBST(root.right, low, high); + + return root; +} diff --git a/typescript/0703-kth-largest-element-in-a-stream.ts b/typescript/0703-kth-largest-element-in-a-stream.ts index a196e11ca..95964aed5 100644 --- a/typescript/0703-kth-largest-element-in-a-stream.ts +++ b/typescript/0703-kth-largest-element-in-a-stream.ts @@ -5,11 +5,11 @@ class KthLargest { constructor(k: number, nums: number[]) { this.backingArray = []; this.size = k; - for(const num of nums) this.add(num) + for (const num of nums) this.add(num); } add(val: number): number { - const newLength = this.backingArray.push(val) + const newLength = this.backingArray.push(val); this.shiftUp(newLength - 1); if (newLength > this.size) this.pop(); @@ -18,20 +18,30 @@ class KthLargest { } private pop() { - this.swap(0, this.backingArray.length - 1) + this.swap(0, this.backingArray.length - 1); this.backingArray.length -= 1; - this.shiftDown(0) + this.shiftDown(0); } private shiftDown(elementIndex: number) { let leftChildIndex = elementIndex * 2 + 1; let rightChildIndex = elementIndex * 2 + 2; - while ((leftChildIndex < this.backingArray.length && this.backingArray[leftChildIndex] < this.backingArray[elementIndex]) - || (rightChildIndex < this.backingArray.length && this.backingArray[rightChildIndex] < this.backingArray[elementIndex])) { + while ( + (leftChildIndex < this.backingArray.length && + this.backingArray[leftChildIndex] < + this.backingArray[elementIndex]) || + (rightChildIndex < this.backingArray.length && + this.backingArray[rightChildIndex] < + this.backingArray[elementIndex]) + ) { let smallestIndex = leftChildIndex; - if (rightChildIndex < this.backingArray.length && this.backingArray[rightChildIndex] < this.backingArray[smallestIndex]) { - smallestIndex = rightChildIndex + if ( + rightChildIndex < this.backingArray.length && + this.backingArray[rightChildIndex] < + this.backingArray[smallestIndex] + ) { + smallestIndex = rightChildIndex; } this.swap(elementIndex, smallestIndex); @@ -46,7 +56,9 @@ class KthLargest { if (elementIndex === 0) return; let parentIndex = Math.floor((elementIndex - 1) / 2); - while (this.backingArray[parentIndex] > this.backingArray[elementIndex]) { + while ( + this.backingArray[parentIndex] > this.backingArray[elementIndex] + ) { this.swap(elementIndex, parentIndex); elementIndex = parentIndex; parentIndex = Math.floor((elementIndex - 1) / 2); diff --git a/typescript/0705-design-hashset.ts b/typescript/0705-design-hashset.ts index b1f3816cc..788aac8d8 100644 --- a/typescript/0705-design-hashset.ts +++ b/typescript/0705-design-hashset.ts @@ -1,4 +1,5 @@ -class _ListNode { // ListNode has a confict +class _ListNode { + // ListNode has a confict key: number; next: _ListNode | undefined; @@ -18,10 +19,9 @@ class MyHashSet { add(key: number): void { let cur = this.set[key % this.set.length]; - + while (cur.next) { - if (cur.next.key === key) - return; + if (cur.next.key === key) return; cur = cur.next; } @@ -31,7 +31,7 @@ class MyHashSet { remove(key: number): void { let cur = this.set[key % this.set.length]; - + while (cur.next) { if (cur.next.key === key) { cur.next = cur.next.next; @@ -44,10 +44,9 @@ class MyHashSet { contains(key: number): boolean { let cur = this.set[key % this.set.length]; - + while (cur.next) { - if (cur.next.key === key) - return true; + if (cur.next.key === key) return true; cur = cur.next; } diff --git a/typescript/0743-network-delay-time.ts b/typescript/0743-network-delay-time.ts index 11817ea92..8adc7433e 100644 --- a/typescript/0743-network-delay-time.ts +++ b/typescript/0743-network-delay-time.ts @@ -1,5 +1,7 @@ function networkDelayTime(times: number[][], n: number, k: number): number { - const adjList = new Map(Array.from({ length: n + 1 }, (_, i) => [i, []])); + const adjList = new Map( + Array.from({ length: n + 1 }, (_, i) => [i, []]), + ); for (let [origin, destination, weight] of times) { adjList.get(origin).push([destination, weight]); } @@ -10,17 +12,18 @@ function networkDelayTime(times: number[][], n: number, k: number): number { } table[k] = 0; const heap = new MinPriorityQueue({ priority: (a) => a[1] }); - for (let [destination, weight] of (adjList.get(k) || [])) { + for (let [destination, weight] of adjList.get(k) || []) { heap.enqueue([destination, weight]); } while (!heap.isEmpty()) { const { element: minEdge } = heap.dequeue(); - if (table[minEdge[0]] !== -1 && minEdge[1] >= table[minEdge[0]]) continue; + if (table[minEdge[0]] !== -1 && minEdge[1] >= table[minEdge[0]]) + continue; table[minEdge[0]] = minEdge[1]; - for (let edge of (adjList.get(minEdge[0]) || [])) { + for (let edge of adjList.get(minEdge[0]) || []) { heap.enqueue([edge[0], minEdge[1] + edge[1]]); } } @@ -32,4 +35,4 @@ function networkDelayTime(times: number[][], n: number, k: number): number { } return max; -}; +} diff --git a/typescript/0778-swim-in-rising-water.ts b/typescript/0778-swim-in-rising-water.ts index 9f8cf29e0..95edf5ba7 100644 --- a/typescript/0778-swim-in-rising-water.ts +++ b/typescript/0778-swim-in-rising-water.ts @@ -3,11 +3,15 @@ function swimInWater(grid: number[][]): number { const n = grid[0].length; const heap = new MinPriorityQueue({ priority: (a) => a[0] }); - const visited = Array.from({ length: m }, () => Array.from({ length: n }, () => false)); + const visited = Array.from({ length: m }, () => + Array.from({ length: n }, () => false), + ); heap.enqueue([grid[0][0], 0, 0]); - + while (!heap.isEmpty()) { - const { element: [weight, r, c ] } = heap.dequeue(); + const { + element: [weight, r, c], + } = heap.dequeue(); if (r === m - 1 && c === n - 1) return weight; @@ -28,4 +32,4 @@ function swimInWater(grid: number[][]): number { } return 0; -}; +} diff --git a/typescript/0787-cheapest-flights-within-k-stops.ts b/typescript/0787-cheapest-flights-within-k-stops.ts index f86e7bec8..f798ec37c 100644 --- a/typescript/0787-cheapest-flights-within-k-stops.ts +++ b/typescript/0787-cheapest-flights-within-k-stops.ts @@ -3,7 +3,7 @@ function findCheapestPrice( flights: number[][], src: number, dst: number, - k: number + k: number, ): number { const adjacencyList = new Map(); diff --git a/typescript/0983-minimum-cost-for-tickets.ts b/typescript/0983-minimum-cost-for-tickets.ts index 74a97b993..b920bbca5 100644 --- a/typescript/0983-minimum-cost-for-tickets.ts +++ b/typescript/0983-minimum-cost-for-tickets.ts @@ -20,4 +20,4 @@ function mincostTickets(days: number[], costs: number[]): number { } return dp[0]; -}; +} diff --git a/typescript/1049-last-stone-weight-ii.ts b/typescript/1049-last-stone-weight-ii.ts index 006b45efa..b2ce04137 100644 --- a/typescript/1049-last-stone-weight-ii.ts +++ b/typescript/1049-last-stone-weight-ii.ts @@ -12,10 +12,7 @@ function lastStoneWeightII(stones: number[]): number { if (j >= target) { current[j] = Math.abs(j - (sum - j)); } else { - current[j] = Math.min( - dp[j], - dp[j + stones[i]], - ); + current[j] = Math.min(dp[j], dp[j + stones[i]]); } } @@ -23,4 +20,4 @@ function lastStoneWeightII(stones: number[]): number { } return dp[0]; -}; +} diff --git a/typescript/1462-course-schedule-iv.ts b/typescript/1462-course-schedule-iv.ts index f6d3cf910..3f1136537 100644 --- a/typescript/1462-course-schedule-iv.ts +++ b/typescript/1462-course-schedule-iv.ts @@ -1,4 +1,8 @@ -function checkIfPrerequisite(numCourses: number, prerequisites: number[][], queries: number[][]): boolean[] { +function checkIfPrerequisite( + numCourses: number, + prerequisites: number[][], + queries: number[][], +): boolean[] { const adjList = new Map( Array.from({ length: numCourses }, (_, i) => [i, []]), ); @@ -28,4 +32,4 @@ function checkIfPrerequisite(numCourses: number, prerequisites: number[][], quer } return queries.map(([a, b]) => cache.get(b).has(a)); -}; +} diff --git a/typescript/1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree.ts b/typescript/1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree.ts index 657e0218a..b89e9154b 100644 --- a/typescript/1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree.ts +++ b/typescript/1489-find-critical-and-pseudo-critical-edges-in-minimum-spanning-tree.ts @@ -37,7 +37,11 @@ class UnionFind { } } -function findMST(n: number, edges: Edge[], heap: typeof MinPriorityQueue): { edges: Edge[], sum: number } { +function findMST( + n: number, + edges: Edge[], + heap: typeof MinPriorityQueue, +): { edges: Edge[]; sum: number } { const unionFind = new UnionFind(n); const resultingEdges = []; let sum = 0; @@ -67,15 +71,20 @@ function findMST(n: number, edges: Edge[], heap: typeof MinPriorityQueue): { edg } function buildHeap() { - return new MinPriorityQueue({ priority: edge => edge[2] }); + return new MinPriorityQueue({ priority: (edge) => edge[2] }); } -function findCriticalAndPseudoCriticalEdges(n: number, edges: Edge[]): number[][] { +function findCriticalAndPseudoCriticalEdges( + n: number, + edges: Edge[], +): number[][] { const generalMST = findMST(n, edges, buildHeap()); const criticalEdges = []; for (let edgeToExclude of generalMST.edges) { - const newEdges = edges.filter(edge => edge.join(',') !== edgeToExclude.join(',')); + const newEdges = edges.filter( + (edge) => edge.join(',') !== edgeToExclude.join(','), + ); const mst = findMST(n, newEdges, buildHeap()); if (mst.sum > generalMST.sum) { @@ -85,8 +94,11 @@ function findCriticalAndPseudoCriticalEdges(n: number, edges: Edge[]): number[][ const pseudoCriticalEdges = []; for (let edge of edges) { - if (criticalEdges.map(e => e.join(',')).includes(edge.join(','))) continue; - const newEdges = edges.filter(possibleEdge => possibleEdge.join(',') !== edge.join(',')); + if (criticalEdges.map((e) => e.join(',')).includes(edge.join(','))) + continue; + const newEdges = edges.filter( + (possibleEdge) => possibleEdge.join(',') !== edge.join(','), + ); const heap = buildHeap(); heap.enqueue(edge); @@ -98,7 +110,15 @@ function findCriticalAndPseudoCriticalEdges(n: number, edges: Edge[]): number[][ } return [ - criticalEdges.map(criticalEdge => edges.findIndex(edge => edge.join(',') === criticalEdge.join(','))), - pseudoCriticalEdges.map(pCriticalEdge => edges.findIndex(edge => edge.join(',') === pCriticalEdge.join(','))), + criticalEdges.map((criticalEdge) => + edges.findIndex( + (edge) => edge.join(',') === criticalEdge.join(','), + ), + ), + pseudoCriticalEdges.map((pCriticalEdge) => + edges.findIndex( + (edge) => edge.join(',') === pCriticalEdge.join(','), + ), + ), ]; -}; +} diff --git a/typescript/1514-path-with-maximum-probability.ts b/typescript/1514-path-with-maximum-probability.ts index 94b00afcc..01c5d9421 100644 --- a/typescript/1514-path-with-maximum-probability.ts +++ b/typescript/1514-path-with-maximum-probability.ts @@ -1,7 +1,11 @@ -function maxProbability(n: number, edges: number[][], succProb: number[], startNode: number, endNode: number): number { - const adjList = new Map( - Array.from({ length: n }, (_, i) => [i, []]) - ); +function maxProbability( + n: number, + edges: number[][], + succProb: number[], + startNode: number, + endNode: number, +): number { + const adjList = new Map(Array.from({ length: n }, (_, i) => [i, []])); for (let i = 0; i < edges.length; i++) { const [origin, target] = edges[i]; @@ -20,7 +24,7 @@ function maxProbability(n: number, edges: number[][], succProb: number[], startN } while (!heap.isEmpty()) { - const { element: maxEdge } = heap.dequeue(); + const { element: maxEdge } = heap.dequeue(); if (table[maxEdge[0]] >= maxEdge[1]) continue; table[maxEdge[0]] = maxEdge[1]; @@ -30,4 +34,4 @@ function maxProbability(n: number, edges: number[][], succProb: number[], startN } return table[endNode]; -}; +} diff --git a/typescript/1584-min-cost-to-connect-all-points.ts b/typescript/1584-min-cost-to-connect-all-points.ts index a21dd0848..619fc39d5 100644 --- a/typescript/1584-min-cost-to-connect-all-points.ts +++ b/typescript/1584-min-cost-to-connect-all-points.ts @@ -10,7 +10,7 @@ function minCostConnectPoints(points: number[][]): number { visited.add(points[0].join(',')); for (let point of points) { if (visited.has(point.join(','))) continue; - + minHeap.enqueue([points[0], point, getDistance(points[0], point)]); } @@ -24,9 +24,13 @@ function minCostConnectPoints(points: number[][]): number { for (let point of points) { if (visited.has(point.join(','))) continue; - minHeap.enqueue([minEdge[1], point, getDistance(minEdge[1], point)]); + minHeap.enqueue([ + minEdge[1], + point, + getDistance(minEdge[1], point), + ]); } } return result; -}; +} diff --git a/typescript/1838-frequency-of-the-most-frequent-element.ts b/typescript/1838-frequency-of-the-most-frequent-element.ts index 61d74f35a..50fc4785f 100644 --- a/typescript/1838-frequency-of-the-most-frequent-element.ts +++ b/typescript/1838-frequency-of-the-most-frequent-element.ts @@ -5,7 +5,11 @@ function maxFrequency(nums: number[], k: number): number { let currentSum: number = 0; let leftWindow: number = 0; - for (let rightWindow: number = 0; rightWindow < sortedNums.length; rightWindow++) { + for ( + let rightWindow: number = 0; + rightWindow < sortedNums.length; + rightWindow++ + ) { const currentLength: number = rightWindow - leftWindow + 1; const rightNum: number = sortedNums[rightWindow]; currentSum += rightNum; @@ -19,4 +23,4 @@ function maxFrequency(nums: number[], k: number): number { } } return maxLength; -}; \ No newline at end of file +} diff --git a/typescript/1929-concatenation-of-array.ts b/typescript/1929-concatenation-of-array.ts index 19350bb6c..d049c2483 100644 --- a/typescript/1929-concatenation-of-array.ts +++ b/typescript/1929-concatenation-of-array.ts @@ -1,9 +1,9 @@ function getConcatenation(nums: number[]): number[] { - let result: number[] = []; + let result: number[] = []; - for(let i = 0; i < 2; i++) { - nums.forEach(num => result.push(num)); - }; + for (let i = 0; i < 2; i++) { + nums.forEach((num) => result.push(num)); + } - return result; -}; + return result; +} diff --git a/typescript/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.ts b/typescript/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.ts index 9fb2b6e41..863ab9a3a 100644 --- a/typescript/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.ts +++ b/typescript/2002-maximum-product-of-the-length-of-two-palindromic-subsequences.ts @@ -20,12 +20,14 @@ function maxProduct(s: string): number { if ((m & (m - 1)) === 0) { return m != 0; } - const l = last[m], f = first[m]; - const lb = 1 << l, fb = 1 << f; + const l = last[m], + f = first[m]; + const lb = 1 << l, + fb = 1 << f; return Math.max( dp(m - lb), dp(m - fb), - dp(m - lb - fb) + Number(s[l] === s[f]) * 2 + dp(m - lb - fb) + Number(s[l] === s[f]) * 2, ); }); let ans = 0; @@ -33,15 +35,15 @@ function maxProduct(s: string): number { ans = Math.max(ans, dp(m) * dp((1 << N) - 1 - m)); } return ans; -}; +} -function cache(func:Function){ +function cache(func: Function) { const map = new Map(); - var wrapper = (m:number) => { + var wrapper = (m: number) => { if (!map.get(m)) { map.set(m, func(m)); } return map.get(m); }; return wrapper; -}; +} diff --git a/typescript/2215-find-the-difference-of-two-arrays.ts b/typescript/2215-find-the-difference-of-two-arrays.ts index e7d331a4d..c6bd0e048 100644 --- a/typescript/2215-find-the-difference-of-two-arrays.ts +++ b/typescript/2215-find-the-difference-of-two-arrays.ts @@ -6,10 +6,10 @@ function findDifference(nums1: number[], nums2: number[]): number[][] { const nums2Set: Set = new Set(nums2); const lst1: number[] = Array.from(nums1Set).filter( - (num: number) => !nums2Set.has(num) + (num: number) => !nums2Set.has(num), ); const lst2: number[] = Array.from(nums2Set).filter( - (num: number) => !nums1Set.has(num) + (num: number) => !nums1Set.has(num), ); return [lst1, lst2]; diff --git a/typescript/2390-removing-stars-from-a-string.ts b/typescript/2390-removing-stars-from-a-string.ts index 9b5cf7edf..862940ca5 100644 --- a/typescript/2390-removing-stars-from-a-string.ts +++ b/typescript/2390-removing-stars-from-a-string.ts @@ -1,14 +1,14 @@ function removeStars(s: string): string { - if(!s.length) return ''; + if (!s.length) return ''; const result = []; - for(let char of s){ - if(char == '*') result.pop() - else result.push(char) + for (let char of s) { + if (char == '*') result.pop(); + else result.push(char); } - return result.join('') -}; + return result.join(''); +} // Time Complexity: O(n) // Space Complexity: O(n) diff --git a/typescript/2421-number-of-good-paths.ts b/typescript/2421-number-of-good-paths.ts index 15d381581..fdbced80c 100644 --- a/typescript/2421-number-of-good-paths.ts +++ b/typescript/2421-number-of-good-paths.ts @@ -63,7 +63,6 @@ function getValToIndex(vals: number[]): Map { return valToIndex; } - function numberOfGoodPaths(vals: number[], edges: number[][]): number { let adj = getAdjList(edges); let valToIndex = getValToIndex(vals); diff --git a/typescript/2469-convert-the-temperature.ts b/typescript/2469-convert-the-temperature.ts index 59d54b405..4f5902529 100644 --- a/typescript/2469-convert-the-temperature.ts +++ b/typescript/2469-convert-the-temperature.ts @@ -1,5 +1,5 @@ function convertTemperature(celsius: number): number[] { const kelvin = celsius + 273.15; - const fahrenheit = celsius * 1.80 + 32.00; + const fahrenheit = celsius * 1.8 + 32.0; return [kelvin, fahrenheit]; -}; +} diff --git a/typescript/2620-counter.ts b/typescript/2620-counter.ts index 898864eac..c3b85034e 100644 --- a/typescript/2620-counter.ts +++ b/typescript/2620-counter.ts @@ -1,11 +1,10 @@ function createCounter(n: number): () => number { - return function() { - return n++; - } + return function () { + return n++; + }; } - -/** +/** * const counter = createCounter(10) * counter() // 10 * counter() // 11 diff --git a/typescript/2667-create-hello-world-function.ts b/typescript/2667-create-hello-world-function.ts index 01320e958..ea6c206e9 100644 --- a/typescript/2667-create-hello-world-function.ts +++ b/typescript/2667-create-hello-world-function.ts @@ -1,8 +1,8 @@ function createHelloWorld() { - return function(...args): string { - return "Hello World"; + return function (...args): string { + return 'Hello World'; }; -}; +} /** * const f = createHelloWorld(); diff --git a/updateCompletionTable.js b/updateCompletionTable.js index 83b1a537e..e3da204a3 100644 --- a/updateCompletionTable.js +++ b/updateCompletionTable.js @@ -23,18 +23,24 @@ const PREPEND_PATH = process.argv[2] || './'; const TEMPLATE_PATH = process.argv[3] || './README_template.md'; const WRITE_PATH = process.argv[3] || './README.md'; -const PROBLEM_SITE_DATA = JSON.parse(fs.readFileSync('./.problemSiteData.json', 'utf8')); +const PROBLEM_SITE_DATA = JSON.parse( + fs.readFileSync('./.problemSiteData.json', 'utf8'), +); function createProblemsObj(PROBLEM_SITE_DATA) { - let PROBLEMS_OBJ = {} - for (const {problem, pattern, link, code} of PROBLEM_SITE_DATA) { - if (!(pattern in PROBLEMS_OBJ)) PROBLEMS_OBJ[pattern] = [] - PROBLEMS_OBJ[pattern].push([problem, "https://leetcode.com/problems/" + link, code.slice(0, 4)]) - } - return PROBLEMS_OBJ + let PROBLEMS_OBJ = {}; + for (const { problem, pattern, link, code } of PROBLEM_SITE_DATA) { + if (!(pattern in PROBLEMS_OBJ)) PROBLEMS_OBJ[pattern] = []; + PROBLEMS_OBJ[pattern].push([ + problem, + 'https://leetcode.com/problems/' + link, + code.slice(0, 4), + ]); + } + return PROBLEMS_OBJ; } -const PROBLEMS_OBJ = createProblemsObj(PROBLEM_SITE_DATA) +const PROBLEMS_OBJ = createProblemsObj(PROBLEM_SITE_DATA); const getDirectories = (source) => readdirSync(source, { withFileTypes: true }) @@ -61,7 +67,7 @@ function nestedFiles(dir) { } const directories = getDirectories(PREPEND_PATH).filter( - (dir) => !IGNORE_DIRS.includes(dir) + (dir) => !IGNORE_DIRS.includes(dir), ); const nestedFilesInDir = directories.reduce((acc, dir) => { acc[dir] = nestedFiles(dir); @@ -96,15 +102,13 @@ for (const problemCategory in PROBLEMS_OBJ) { ]; for (const dir of directories) { let filePath = nestedFilesInDir[dir].find((file) => - file - .match(/[\w-]+\..+/)?.[0] - ?.startsWith(problemNumber) + file.match(/[\w-]+\..+/)?.[0]?.startsWith(problemNumber), ); if (filePath) { problemRow.push( `
[✔️](${encodeURIComponent( - filePath - )})
` + filePath, + )})`, ); } else { problemRow.push("
"); diff --git a/updateSiteData.js b/updateSiteData.js index 78691d31c..dd8757948 100644 --- a/updateSiteData.js +++ b/updateSiteData.js @@ -2,80 +2,82 @@ const fs = require('fs'); -const PROBLEMS_SITE_DATA = JSON.parse(fs.readFileSync('./.problemSiteData.json', 'utf8')); +const PROBLEMS_SITE_DATA = JSON.parse( + fs.readFileSync('./.problemSiteData.json', 'utf8'), +); const languages = [ { name: 'C', directory: 'c', - extension: 'c' + extension: 'c', }, { name: 'C++', directory: 'cpp', - extension: 'cpp' + extension: 'cpp', }, { name: 'C#', directory: 'csharp', - extension: 'cs' + extension: 'cs', }, { name: 'Java', directory: 'java', - extension: 'java' + extension: 'java', }, - { + { name: 'Python', directory: 'python', - extension: 'py' + extension: 'py', }, { name: 'JavaScript', directory: 'javascript', - extension: 'js' + extension: 'js', }, { name: 'TypeScript', directory: 'typescript', - extension: 'ts' + extension: 'ts', }, { name: 'Go', directory: 'go', - extension: 'go' + extension: 'go', }, { name: 'Ruby', directory: 'ruby', - extension: 'rb' + extension: 'rb', }, { name: 'Swift', directory: 'swift', - extension: 'swift' + extension: 'swift', }, { name: 'Kotlin', directory: 'kotlin', - extension: 'kt' + extension: 'kt', }, { name: 'Rust', directory: 'rust', - extension: 'rs' + extension: 'rs', }, { name: 'Scala', directory: 'scala', - extension: 'scala' + extension: 'scala', }, { name: 'Dart', directory: 'dart', - extension: 'dart' + extension: 'dart', }, -] +]; // Rename files to match leetcode url path, and normalize problem number to four digits. for (const lang of languages) { @@ -92,8 +94,10 @@ for (const lang of languages) { // Use problem number to find code file const problemNumber = problem['code'].split('-')[0]; - const foundFile = files.find(file => file.name.startsWith(`${problemNumber.toString()}-`)); - + const foundFile = files.find((file) => + file.name.startsWith(`${problemNumber.toString()}-`), + ); + if (foundFile && foundFile.isFile()) { // rename file to match leetcode url path const oldFile = `${langDir}/${foundFile.name}`; @@ -105,11 +109,17 @@ for (const lang of languages) { problem[langDir] = true; // add language to problemSiteData } } - console.log(`Renamed ${counter} files in ${langDir}, which had ${files.length} total files.`); + console.log( + `Renamed ${counter} files in ${langDir}, which had ${files.length} total files.`, + ); } // Write updated problemSiteData to file -fs.writeFile('./.problemSiteData.json', JSON.stringify(PROBLEMS_SITE_DATA), function (err) { - if (err) throw err; - console.log('Saved!'); -}); +fs.writeFile( + './.problemSiteData.json', + JSON.stringify(PROBLEMS_SITE_DATA), + function (err) { + if (err) throw err; + console.log('Saved!'); + }, +); diff --git a/verifySiteData.js b/verifySiteData.js index f360d2332..5178e49d3 100644 --- a/verifySiteData.js +++ b/verifySiteData.js @@ -3,78 +3,80 @@ const fs = require('fs'); const https = require('/opt/homebrew/lib/node_modules/sync-request'); -const PROBLEMS_SITE_DATA = JSON.parse(fs.readFileSync('./.problemSiteData.json', 'utf8')); +const PROBLEMS_SITE_DATA = JSON.parse( + fs.readFileSync('./.problemSiteData.json', 'utf8'), +); const languageMap = { c: { name: 'C', directory: 'c', - extension: 'c' + extension: 'c', }, cpp: { name: 'C++', directory: 'cpp', - extension: 'cpp' + extension: 'cpp', }, csharp: { name: 'C#', directory: 'csharp', - extension: 'cs' + extension: 'cs', }, java: { name: 'Java', directory: 'java', - extension: 'java' + extension: 'java', }, - python: { + python: { name: 'Python', directory: 'python', - extension: 'py' + extension: 'py', }, javascript: { name: 'JavaScript', directory: 'javascript', - extension: 'js' + extension: 'js', }, typescript: { name: 'TypeScript', directory: 'typescript', - extension: 'ts' + extension: 'ts', }, go: { name: 'Go', directory: 'go', - extension: 'go' + extension: 'go', }, ruby: { name: 'Ruby', directory: 'ruby', - extension: 'rb' + extension: 'rb', }, swift: { name: 'Swift', directory: 'swift', - extension: 'swift' + extension: 'swift', }, kotlin: { name: 'Kotlin', directory: 'kotlin', - extension: 'kt' + extension: 'kt', }, rust: { name: 'Rust', directory: 'rust', - extension: 'rs' + extension: 'rs', }, scala: { name: 'Scala', directory: 'scala', - extension: 'scala' + extension: 'scala', }, dart: { name: 'Dart', directory: 'dart', - extension: 'dart' + extension: 'dart', }, }; @@ -89,8 +91,8 @@ for (const problem of PROBLEMS_SITE_DATA) { const res = https('GET', codeUrl).statusCode; if (res !== 200) { - console.log(codeUrl) - console.log(res) + console.log(codeUrl); + console.log(res); } } } pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy