From 1140934f0389809c9ab744d21e1c271379acf299 Mon Sep 17 00:00:00 2001
From: yanglbme <szuyanglb@outlook.com>
Date: Thu, 20 Apr 2023 22:17:54 +0800
Subject: [PATCH] feat: add solutions to lc problem: No.0125

No.0125.Valid Palindrome
---
 .../0100-0199/0125.Valid Palindrome/README.md | 200 +++++++-----------
 .../0125.Valid Palindrome/README_EN.md        | 187 ++++++----------
 .../0125.Valid Palindrome/Solution.cpp        |  16 +-
 .../0125.Valid Palindrome/Solution.cs         |  17 +-
 .../0125.Valid Palindrome/Solution.go         |  34 +--
 .../0125.Valid Palindrome/Solution.java       |   2 +-
 .../0125.Valid Palindrome/Solution.js         |  24 ++-
 .../0125.Valid Palindrome/Solution.py         |  13 ++
 .../0125.Valid Palindrome/Solution.ts         |  22 +-
 9 files changed, 211 insertions(+), 304 deletions(-)
 create mode 100644 solution/0100-0199/0125.Valid Palindrome/Solution.py

diff --git a/solution/0100-0199/0125.Valid Palindrome/README.md b/solution/0100-0199/0125.Valid Palindrome/README.md
index c53645aed491e..c7146421a7ba6 100644
--- a/solution/0100-0199/0125.Valid Palindrome/README.md	
+++ b/solution/0100-0199/0125.Valid Palindrome/README.md	
@@ -52,6 +52,19 @@
 
 <!-- 这里可写通用的实现逻辑 -->
 
+**方法一:双指针**
+
+我们用双指针 $i$ 和 $j$ 分别指向字符串 $s$ 的两端,接下来循环以下过程,直至 $i \geq j$:
+
+1. 如果 $s[i]$ 不是字母或数字,指针 $i$ 右移一位,继续下一次循环;
+1. 如果 $s[j]$ 不是字母或数字,指针 $j$ 左移一位,继续下一次循环;
+1. 如果 $s[i]$ 和 $s[j]$ 的小写形式不相等,返回 `false`;
+1. 否则,指针 $i$ 右移一位,指针 $j$ 左移一位,继续下一次循环。
+
+循环结束,返回 `true`。
+
+时间复杂度 $O(n)$,其中 $n$ 是字符串 $s$ 的长度。空间复杂度 $O(1)$。
+
 <!-- tabs:start -->
 
 ### **Python3**
@@ -70,8 +83,7 @@ class Solution:
             elif s[i].lower() != s[j].lower():
                 return False
             else:
-                i += 1
-                j -= 1
+                i, j = i + 1, j - 1
         return True
 ```
 
@@ -88,7 +100,7 @@ class Solution {
                 ++i;
             } else if (!Character.isLetterOrDigit(s.charAt(j))) {
                 --j;
-            } else if (Character.toUpperCase(s.charAt(i)) != Character.toUpperCase(s.charAt(j))) {
+            } else if (Character.toLowerCase(s.charAt(i)) != Character.toLowerCase(s.charAt(j))) {
                 return false;
             } else {
                 ++i;
@@ -108,43 +120,67 @@ public:
     bool isPalindrome(string s) {
         int i = 0, j = s.size() - 1;
         while (i < j) {
-            if (!isAlphaNum(s[i]))
+            if (!isalnum(s[i])) {
                 ++i;
-            else if (!isAlphaNum(s[j]))
+            } else if (!isalnum(s[j])) {
                 --j;
-            else if ((s[i] + 32 - 'a') % 32 != (s[j] + 32 - 'a') % 32)
+            } else if (tolower(s[i]) != tolower(s[j])) {
                 return false;
-            else {
+            } else {
                 ++i;
                 --j;
             }
         }
         return true;
     }
-
-private:
-    bool isAlphaNum(char& ch) {
-        if (ch >= 'a' && ch <= 'z') return true;
-        if (ch >= 'A' && ch <= 'Z') return true;
-        if (ch >= '0' && ch <= '9') return true;
-        return false;
-    }
 };
 ```
 
+### **Go**
+
+```go
+func isPalindrome(s string) bool {
+	i, j := 0, len(s)-1
+	for i < j {
+		if !isalnum(s[i]) {
+			i++
+		} else if !isalnum(s[j]) {
+			j--
+		} else if tolower(s[i]) != tolower(s[j]) {
+			return false
+		} else {
+			i, j = i+1, j-1
+		}
+	}
+	return true
+}
+
+func isalnum(ch byte) bool {
+	return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
+}
+
+func tolower(ch byte) byte {
+	if ch >= 'A' && ch <= 'Z' {
+		return ch + 32
+	}
+	return ch
+}
+```
+
 ### **C#**
 
 ```cs
-using System.Linq;
-
 public class Solution {
     public bool IsPalindrome(string s) {
-        var chars = s.Where(ch => char.IsLetterOrDigit(ch)).Select(char.ToLower).ToList();
-        var i = 0;
-        var j = chars.Count - 1;
-        for (; i < j; ++i, --j)
-        {
-            if (chars[i] != chars[j]) return false;
+        int i = 0, j = s.Length - 1;
+        while (i < j) {
+            if (!char.IsLetterOrDigit(s[i])) {
+                ++i;
+            } else if (!char.IsLetterOrDigit(s[j])) {
+                --j;
+            } else if (char.ToLower(s[i++]) != char.ToLower(s[j--])) {
+                return false;
+            }
         }
         return true;
     }
@@ -159,57 +195,18 @@ public class Solution {
  * @return {boolean}
  */
 var isPalindrome = function (s) {
-    let arr1 = [],
-        arr2 = [];
-    for (let i = 0; i < s.length; i++) {
-        if (s[i] >= 'A' && s[i] <= 'Z') {
-            arr1.push(s[i].toLowerCase());
-        }
-        if ((s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'z')) {
-            arr1.push(s[i]);
-        }
-    }
-    arr2 = [...arr1];
-    arr2.reverse();
-    return arr1.join('') === arr2.join('');
-};
-```
-
-```js
-/**
- * @param {string} s
- * @return {boolean}
- */
-var isPalindrome = function (s) {
-    function isNumOrAl(a) {
-        if (
-            (a >= 'A' && a <= 'Z') ||
-            (a >= '0' && a <= '9') ||
-            (a >= 'a' && a <= 'z')
-        ) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    if (s.length === 0) {
-        return true;
-    }
-    let i = 0,
-        j = s.length - 1;
+    let i = 0;
+    let j = s.length - 1;
     while (i < j) {
-        while (i < j && !isNumOrAl(s[i])) {
-            i++;
-        }
-        while (i < j && !isNumOrAl(s[j])) {
-            j--;
-        }
-        if (s[i].toLowerCase() !== s[j].toLowerCase()) {
+        if (!/[a-zA-Z0-9]/.test(s[i])) {
+            ++i;
+        } else if (!/[a-zA-Z0-9]/.test(s[j])) {
+            --j;
+        } else if (s[i].toLowerCase() !== s[j].toLowerCase()) {
             return false;
         } else {
-            i++;
-            j--;
+            ++i;
+            --j;
         }
     }
     return true;
@@ -220,36 +217,24 @@ var isPalindrome = function (s) {
 
 ```ts
 function isPalindrome(s: string): boolean {
-    let left: number = 0,
-        right: number = s.length - 1;
-    while (left < right) {
-        let char1: string = s.charAt(left);
-        let char2: string = s.charAt(right);
-        if (!/[a-zA-Z0-9]/.test(char1)) {
-            ++left;
-        } else if (!/[a-zA-Z0-9]/.test(char2)) {
-            --right;
-        } else if (char1.toLocaleLowerCase() != char2.toLocaleLowerCase()) {
+    let i = 0;
+    let j = s.length - 1;
+    while (i < j) {
+        if (!/[a-zA-Z0-9]/.test(s[i])) {
+            ++i;
+        } else if (!/[a-zA-Z0-9]/.test(s[j])) {
+            --j;
+        } else if (s[i].toLowerCase() !== s[j].toLowerCase()) {
             return false;
         } else {
-            ++left;
-            --right;
+            ++i;
+            --j;
         }
     }
     return true;
 }
 ```
 
-```ts
-function isPalindrome(s: string): boolean {
-    const isAlphanumeric = (c: string) => {
-        return (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9');
-    };
-    const cs = s.toLocaleLowerCase().split('').filter(isAlphanumeric);
-    return cs.join('') === cs.reverse().join('');
-}
-```
-
 ### **Rust**
 
 ```rust
@@ -279,35 +264,6 @@ impl Solution {
 }
 ```
 
-### **Go**
-
-```go
-func isPalindrome(s string) bool {
-	s = strings.ToLower(s)
-	left, right := 0, len(s) - 1
-	for left < right {
-		for left < right && !verify(s[left]) {
-			left++
-		}
-		for left < right && !verify(s[right]) {
-			right--
-		}
-		if left < right {
-			if s[left] != s[right] {
-				return false
-			}
-			left++
-			right--
-		}
-	}
-	return true
-}
-
-func verify(ch byte) bool {
-	return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
-}
-```
-
 ### **PHP**
 
 ```php
diff --git a/solution/0100-0199/0125.Valid Palindrome/README_EN.md b/solution/0100-0199/0125.Valid Palindrome/README_EN.md
index 38d356d454fb3..d474fe9e13764 100644
--- a/solution/0100-0199/0125.Valid Palindrome/README_EN.md	
+++ b/solution/0100-0199/0125.Valid Palindrome/README_EN.md	
@@ -60,8 +60,7 @@ class Solution:
             elif s[i].lower() != s[j].lower():
                 return False
             else:
-                i += 1
-                j -= 1
+                i, j = i + 1, j - 1
         return True
 ```
 
@@ -76,7 +75,7 @@ class Solution {
                 ++i;
             } else if (!Character.isLetterOrDigit(s.charAt(j))) {
                 --j;
-            } else if (Character.toUpperCase(s.charAt(i)) != Character.toUpperCase(s.charAt(j))) {
+            } else if (Character.toLowerCase(s.charAt(i)) != Character.toLowerCase(s.charAt(j))) {
                 return false;
             } else {
                 ++i;
@@ -96,43 +95,67 @@ public:
     bool isPalindrome(string s) {
         int i = 0, j = s.size() - 1;
         while (i < j) {
-            if (!isAlphaNum(s[i]))
+            if (!isalnum(s[i])) {
                 ++i;
-            else if (!isAlphaNum(s[j]))
+            } else if (!isalnum(s[j])) {
                 --j;
-            else if ((s[i] + 32 - 'a') % 32 != (s[j] + 32 - 'a') % 32)
+            } else if (tolower(s[i]) != tolower(s[j])) {
                 return false;
-            else {
+            } else {
                 ++i;
                 --j;
             }
         }
         return true;
     }
-
-private:
-    bool isAlphaNum(char& ch) {
-        if (ch >= 'a' && ch <= 'z') return true;
-        if (ch >= 'A' && ch <= 'Z') return true;
-        if (ch >= '0' && ch <= '9') return true;
-        return false;
-    }
 };
 ```
 
+### **Go**
+
+```go
+func isPalindrome(s string) bool {
+	i, j := 0, len(s)-1
+	for i < j {
+		if !isalnum(s[i]) {
+			i++
+		} else if !isalnum(s[j]) {
+			j--
+		} else if tolower(s[i]) != tolower(s[j]) {
+			return false
+		} else {
+			i, j = i+1, j-1
+		}
+	}
+	return true
+}
+
+func isalnum(ch byte) bool {
+	return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
+}
+
+func tolower(ch byte) byte {
+	if ch >= 'A' && ch <= 'Z' {
+		return ch + 32
+	}
+	return ch
+}
+```
+
 ### **C#**
 
 ```cs
-using System.Linq;
-
 public class Solution {
     public bool IsPalindrome(string s) {
-        var chars = s.Where(ch => char.IsLetterOrDigit(ch)).Select(char.ToLower).ToList();
-        var i = 0;
-        var j = chars.Count - 1;
-        for (; i < j; ++i, --j)
-        {
-            if (chars[i] != chars[j]) return false;
+        int i = 0, j = s.Length - 1;
+        while (i < j) {
+            if (!char.IsLetterOrDigit(s[i])) {
+                ++i;
+            } else if (!char.IsLetterOrDigit(s[j])) {
+                --j;
+            } else if (char.ToLower(s[i++]) != char.ToLower(s[j--])) {
+                return false;
+            }
         }
         return true;
     }
@@ -147,57 +170,18 @@ public class Solution {
  * @return {boolean}
  */
 var isPalindrome = function (s) {
-    let arr1 = [],
-        arr2 = [];
-    for (let i = 0; i < s.length; i++) {
-        if (s[i] >= 'A' && s[i] <= 'Z') {
-            arr1.push(s[i].toLowerCase());
-        }
-        if ((s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'z')) {
-            arr1.push(s[i]);
-        }
-    }
-    arr2 = [...arr1];
-    arr2.reverse();
-    return arr1.join('') === arr2.join('');
-};
-```
-
-```js
-/**
- * @param {string} s
- * @return {boolean}
- */
-var isPalindrome = function (s) {
-    function isNumOrAl(a) {
-        if (
-            (a >= 'A' && a <= 'Z') ||
-            (a >= '0' && a <= '9') ||
-            (a >= 'a' && a <= 'z')
-        ) {
-            return true;
-        } else {
-            return false;
-        }
-    }
-
-    if (s.length === 0) {
-        return true;
-    }
-    let i = 0,
-        j = s.length - 1;
+    let i = 0;
+    let j = s.length - 1;
     while (i < j) {
-        while (i < j && !isNumOrAl(s[i])) {
-            i++;
-        }
-        while (i < j && !isNumOrAl(s[j])) {
-            j--;
-        }
-        if (s[i].toLowerCase() !== s[j].toLowerCase()) {
+        if (!/[a-zA-Z0-9]/.test(s[i])) {
+            ++i;
+        } else if (!/[a-zA-Z0-9]/.test(s[j])) {
+            --j;
+        } else if (s[i].toLowerCase() !== s[j].toLowerCase()) {
             return false;
         } else {
-            i++;
-            j--;
+            ++i;
+            --j;
         }
     }
     return true;
@@ -208,36 +192,24 @@ var isPalindrome = function (s) {
 
 ```ts
 function isPalindrome(s: string): boolean {
-    let left: number = 0,
-        right: number = s.length - 1;
-    while (left < right) {
-        let char1: string = s.charAt(left);
-        let char2: string = s.charAt(right);
-        if (!/[a-zA-Z0-9]/.test(char1)) {
-            ++left;
-        } else if (!/[a-zA-Z0-9]/.test(char2)) {
-            --right;
-        } else if (char1.toLocaleLowerCase() != char2.toLocaleLowerCase()) {
+    let i = 0;
+    let j = s.length - 1;
+    while (i < j) {
+        if (!/[a-zA-Z0-9]/.test(s[i])) {
+            ++i;
+        } else if (!/[a-zA-Z0-9]/.test(s[j])) {
+            --j;
+        } else if (s[i].toLowerCase() !== s[j].toLowerCase()) {
             return false;
         } else {
-            ++left;
-            --right;
+            ++i;
+            --j;
         }
     }
     return true;
 }
 ```
 
-```ts
-function isPalindrome(s: string): boolean {
-    const isAlphanumeric = (c: string) => {
-        return (c >= 'a' && c <= 'z') || (c >= '0' && c <= '9');
-    };
-    const cs = s.toLocaleLowerCase().split('').filter(isAlphanumeric);
-    return cs.join('') === cs.reverse().join('');
-}
-```
-
 ### **Rust**
 
 ```rust
@@ -267,35 +239,6 @@ impl Solution {
 }
 ```
 
-### **Go**
-
-```go
-func isPalindrome(s string) bool {
-	s = strings.ToLower(s)
-	left, right := 0, len(s) - 1
-	for left < right {
-		for left < right && !verify(s[left]) {
-			left++
-		}
-		for left < right && !verify(s[right]) {
-			right--
-		}
-		if left < right {
-			if s[left] != s[right] {
-				return false
-			}
-			left++
-			right--
-		}
-	}
-	return true
-}
-
-func verify(ch byte) bool {
-	return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
-}
-```
-
 ### **PHP**
 
 ```php
diff --git a/solution/0100-0199/0125.Valid Palindrome/Solution.cpp b/solution/0100-0199/0125.Valid Palindrome/Solution.cpp
index 242b625b1c58b..bbc2773e14d1e 100644
--- a/solution/0100-0199/0125.Valid Palindrome/Solution.cpp	
+++ b/solution/0100-0199/0125.Valid Palindrome/Solution.cpp	
@@ -3,25 +3,17 @@ class Solution {
     bool isPalindrome(string s) {
         int i = 0, j = s.size() - 1;
         while (i < j) {
-            if (!isAlphaNum(s[i]))
+            if (!isalnum(s[i])) {
                 ++i;
-            else if (!isAlphaNum(s[j]))
+            } else if (!isalnum(s[j])) {
                 --j;
-            else if ((s[i] + 32 - 'a') % 32 != (s[j] + 32 - 'a') % 32)
+            } else if (tolower(s[i]) != tolower(s[j])) {
                 return false;
-            else {
+            } else {
                 ++i;
                 --j;
             }
         }
         return true;
     }
-
-private:
-    bool isAlphaNum(char& ch) {
-        if (ch >= 'a' && ch <= 'z') return true;
-        if (ch >= 'A' && ch <= 'Z') return true;
-        if (ch >= '0' && ch <= '9') return true;
-        return false;
-    }
 };
\ No newline at end of file
diff --git a/solution/0100-0199/0125.Valid Palindrome/Solution.cs b/solution/0100-0199/0125.Valid Palindrome/Solution.cs
index dc2c4e9ad4223..594b7e02f1f13 100644
--- a/solution/0100-0199/0125.Valid Palindrome/Solution.cs	
+++ b/solution/0100-0199/0125.Valid Palindrome/Solution.cs	
@@ -1,13 +1,14 @@
-using System.Linq;
-
 public class Solution {
     public bool IsPalindrome(string s) {
-        var chars = s.Where(ch => char.IsLetterOrDigit(ch)).Select(char.ToLower).ToList();
-        var i = 0;
-        var j = chars.Count - 1;
-        for (; i < j; ++i, --j)
-        {
-            if (chars[i] != chars[j]) return false;
+        int i = 0, j = s.Length - 1;
+        while (i < j) {
+            if (!char.IsLetterOrDigit(s[i])) {
+                ++i;
+            } else if (!char.IsLetterOrDigit(s[j])) {
+                --j;
+            } else if (char.ToLower(s[i++]) != char.ToLower(s[j--])) {
+                return false;
+            }
         }
         return true;
     }
diff --git a/solution/0100-0199/0125.Valid Palindrome/Solution.go b/solution/0100-0199/0125.Valid Palindrome/Solution.go
index 5b3ddec918777..47319af9e8632 100644
--- a/solution/0100-0199/0125.Valid Palindrome/Solution.go	
+++ b/solution/0100-0199/0125.Valid Palindrome/Solution.go	
@@ -1,24 +1,26 @@
 func isPalindrome(s string) bool {
-	s = strings.ToLower(s)
-	left, right := 0, len(s) - 1
-	for left < right {
-		for left < right && !verify(s[left]) {
-			left++
-		}
-		for left < right && !verify(s[right]) {
-			right--
-		}
-		if left < right {
-			if s[left] != s[right] {
-				return false
-			}
-			left++
-			right--
+	i, j := 0, len(s)-1
+	for i < j {
+		if !isalnum(s[i]) {
+			i++
+		} else if !isalnum(s[j]) {
+			j--
+		} else if tolower(s[i]) != tolower(s[j]) {
+			return false
+		} else {
+			i, j = i+1, j-1
 		}
 	}
 	return true
 }
 
-func verify(ch byte) bool {
+func isalnum(ch byte) bool {
 	return (ch >= 'A' && ch <= 'Z') || (ch >= 'a' && ch <= 'z') || (ch >= '0' && ch <= '9')
+}
+
+func tolower(ch byte) byte {
+	if ch >= 'A' && ch <= 'Z' {
+		return ch + 32
+	}
+	return ch
 }
\ No newline at end of file
diff --git a/solution/0100-0199/0125.Valid Palindrome/Solution.java b/solution/0100-0199/0125.Valid Palindrome/Solution.java
index 5df0ee2d50e76..1bf028c1f616c 100644
--- a/solution/0100-0199/0125.Valid Palindrome/Solution.java	
+++ b/solution/0100-0199/0125.Valid Palindrome/Solution.java	
@@ -6,7 +6,7 @@ public boolean isPalindrome(String s) {
                 ++i;
             } else if (!Character.isLetterOrDigit(s.charAt(j))) {
                 --j;
-            } else if (Character.toUpperCase(s.charAt(i)) != Character.toUpperCase(s.charAt(j))) {
+            } else if (Character.toLowerCase(s.charAt(i)) != Character.toLowerCase(s.charAt(j))) {
                 return false;
             } else {
                 ++i;
diff --git a/solution/0100-0199/0125.Valid Palindrome/Solution.js b/solution/0100-0199/0125.Valid Palindrome/Solution.js
index f4d728dd21261..edde5786b0397 100644
--- a/solution/0100-0199/0125.Valid Palindrome/Solution.js	
+++ b/solution/0100-0199/0125.Valid Palindrome/Solution.js	
@@ -3,17 +3,19 @@
  * @return {boolean}
  */
 var isPalindrome = function (s) {
-    let arr1 = [],
-        arr2 = [];
-    for (let i = 0; i < s.length; i++) {
-        if (s[i] >= 'A' && s[i] <= 'Z') {
-            arr1.push(s[i].toLowerCase());
-        }
-        if ((s[i] >= '0' && s[i] <= '9') || (s[i] >= 'a' && s[i] <= 'z')) {
-            arr1.push(s[i]);
+    let i = 0;
+    let j = s.length - 1;
+    while (i < j) {
+        if (!/[a-zA-Z0-9]/.test(s[i])) {
+            ++i;
+        } else if (!/[a-zA-Z0-9]/.test(s[j])) {
+            --j;
+        } else if (s[i].toLowerCase() !== s[j].toLowerCase()) {
+            return false;
+        } else {
+            ++i;
+            --j;
         }
     }
-    arr2 = [...arr1];
-    arr2.reverse();
-    return arr1.join('') === arr2.join('');
+    return true;
 };
diff --git a/solution/0100-0199/0125.Valid Palindrome/Solution.py b/solution/0100-0199/0125.Valid Palindrome/Solution.py
new file mode 100644
index 0000000000000..73fac29a8c02d
--- /dev/null
+++ b/solution/0100-0199/0125.Valid Palindrome/Solution.py	
@@ -0,0 +1,13 @@
+class Solution:
+    def isPalindrome(self, s: str) -> bool:
+        i, j = 0, len(s) - 1
+        while i < j:
+            if not s[i].isalnum():
+                i += 1
+            elif not s[j].isalnum():
+                j -= 1
+            elif s[i].lower() != s[j].lower():
+                return False
+            else:
+                i, j = i + 1, j - 1
+        return True
diff --git a/solution/0100-0199/0125.Valid Palindrome/Solution.ts b/solution/0100-0199/0125.Valid Palindrome/Solution.ts
index 4daab16efc9f7..b06244fa3c279 100644
--- a/solution/0100-0199/0125.Valid Palindrome/Solution.ts	
+++ b/solution/0100-0199/0125.Valid Palindrome/Solution.ts	
@@ -1,18 +1,16 @@
 function isPalindrome(s: string): boolean {
-    let left: number = 0,
-        right: number = s.length - 1;
-    while (left < right) {
-        let char1: string = s.charAt(left);
-        let char2: string = s.charAt(right);
-        if (!/[a-zA-Z0-9]/.test(char1)) {
-            ++left;
-        } else if (!/[a-zA-Z0-9]/.test(char2)) {
-            --right;
-        } else if (char1.toLocaleLowerCase() != char2.toLocaleLowerCase()) {
+    let i = 0;
+    let j = s.length - 1;
+    while (i < j) {
+        if (!/[a-zA-Z0-9]/.test(s[i])) {
+            ++i;
+        } else if (!/[a-zA-Z0-9]/.test(s[j])) {
+            --j;
+        } else if (s[i].toLowerCase() !== s[j].toLowerCase()) {
             return false;
         } else {
-            ++left;
-            --right;
+            ++i;
+            --j;
         }
     }
     return true;