diff --git a/README.md b/README.md index 2f7a620..3d7f2fb 100644 --- a/README.md +++ b/README.md @@ -15,6 +15,7 @@ | 9 | [Maximum Product of Three Numbers](https://leetcode.com/problems/maximum-product-of-three-numbers/) | [TypeScript](https://github.com/sandrig/leetcode/blob/master/typescript/src/maximumProductofThreeNumbers/README.md) | _O(nlogn)_ | _O(1)_ | Array, Math, Sorting | | 10 | [Maximum Average Subarray I](https://leetcode.com/problems/maximum-average-subarray-i/) | [TypeScript](https://github.com/sandrig/leetcode/blob/master/typescript/src/maximumAverageSubarrayI/README.md) | _O(n)_ | _O(1)_ | Array, Sliding Window | | 11 | [Intersection of Two Arrays II](https://leetcode.com/problems/intersection-of-two-arrays-ii/) | [TypeScript](https://github.com/sandrig/leetcode/blob/master/typescript/src/intersectionOfTwoArraysII/README.md) | _O(n + m)_ | _O(min(n, m))_ | Array, Hash Table, Two Pointers, Binary Search, Sorting | +| 12 | [Valid Palindrome II](https://leetcode.com/problems/valid-palindrome-ii/) | [TypeScript](https://github.com/sandrig/leetcode/blob/master/typescript/src/validPalindromeII/README.md) | _O(n)_ | _O(1)_ | Two Pointers, String Greedy | ## Medium diff --git a/typescript/src/validPalindromeII/README.md b/typescript/src/validPalindromeII/README.md new file mode 100644 index 0000000..befae6e --- /dev/null +++ b/typescript/src/validPalindromeII/README.md @@ -0,0 +1,65 @@ +# [Valid Palindrome II](https://leetcode.com/problems/valid-palindrome-ii/) + +## Description + +Given a string **s**, return **true** if the **s** can be palindrome after deleting at most one character from it. + +**Example 1:** + +``` +Input: s = "aba" +Output: true +``` + +**Example 2:** + +``` +Input: s = "abca" +Output: true +Explanation: You could delete the character 'c'. +``` + +**Example 3:** + +``` +Input: s = "abc" +Output: false +``` + +## Solution + +```typescript +function validPalindrome(s: string): boolean { + function isPalindromeRange(start: number, end: number): boolean { + while (start < end) { + if (s[start] !== s[end]) { + return false; + } + start++; + end--; + } + return true; + } + + let left = 0; + let right = s.length - 1; + + while (left < right) { + if (s[left] !== s[right]) { + // Try skipping the left character or the right character + return ( + isPalindromeRange(left + 1, right) || isPalindromeRange(left, right - 1) + ); + } + left++; + right--; + } + + return true; +} +``` + +## Complexity Analysis + +- Time complexity: _O(n)_ +- Space complexity: _O(1)_ diff --git a/typescript/src/validPalindromeII/validPalindrome.test.ts b/typescript/src/validPalindromeII/validPalindrome.test.ts new file mode 100644 index 0000000..8265ac1 --- /dev/null +++ b/typescript/src/validPalindromeII/validPalindrome.test.ts @@ -0,0 +1,24 @@ +import { validPalindrome } from "./validPalindrome"; + +describe("Valid Palindrome II", () => { + it("should return true for a valid palindrome", () => { + expect(validPalindrome("aba")).toBe(true); + expect(validPalindrome("abccba")).toBe(true); + expect(validPalindrome("racecar")).toBe(true); + expect(validPalindrome("deified")).toBe(true); + }); + + it("should return true for a valid palindrome when one character is removed", () => { + expect(validPalindrome("abca")).toBe(true); + expect(validPalindrome("abcba")).toBe(true); + expect(validPalindrome("abccbad")).toBe(true); + expect(validPalindrome("radarz")).toBe(true); + }); + + it("should return false when more than one character is removed", () => { + expect(validPalindrome("abcde")).toBe(false); + expect(validPalindrome("levellee")).toBe(false); + expect(validPalindrome("radarza")).toBe(false); + expect(validPalindrome("racecarara")).toBe(false); + }); +}); diff --git a/typescript/src/validPalindromeII/validPalindrome.ts b/typescript/src/validPalindromeII/validPalindrome.ts new file mode 100644 index 0000000..42489cd --- /dev/null +++ b/typescript/src/validPalindromeII/validPalindrome.ts @@ -0,0 +1,28 @@ +export function validPalindrome(s: string): boolean { + function isPalindromeRange(start: number, end: number): boolean { + while (start < end) { + if (s[start] !== s[end]) { + return false; + } + start++; + end--; + } + return true; + } + + let left = 0; + let right = s.length - 1; + + while (left < right) { + if (s[left] !== s[right]) { + // Try skipping the left character or the right character + return ( + isPalindromeRange(left + 1, right) || isPalindromeRange(left, right - 1) + ); + } + left++; + right--; + } + + return true; +}