Leetcode solution 680: Valid Palindrome II
原文链接
https://blog.baozitraining.org/2019/03/leetcode-solution-680-valid-palindrome.html
Problem Statement
Given a non-empty string s
, you may delete at most one character. Judge whether you can make it a palindrome.
Example 1:
Input: "aba"
Output: True
Example 2:
Input: "abca"
Output: True
Explanation: You could delete the character 'c'.
Note:
- The string will only contain lowercase characters a-z. The maximum length of the string is 50000.
Problem link
Video Tutorial
You can find the detailed video tutorial here
Thought Process
We should all be very familiar with how to determine if a string is a palindrome by keeping two pointers, one from beginning and one from the end of the string. The variation of this problem is to we can at most delete one character. Our thought process is the same to try two pointers. Let's use one example: "abbac", when we start two pointers, the first char 'a' and the last char 'c' are different. We might want to check if the previous of 'c' equals to 'a', we can have a chance OR the next after 'a' is a 'c', we can also have a chance. In this case, we return True since the previous of 'c' indeed is 'a' and the rest is simply a palindrome. However, what happens if we do have two choices? For example, "accac", the first 'a' and last 'c' are different, but we can choose either way, but it will result in different results. (i.e., "ccac" or "acca"), as long as one of the is a palindrome, we return True. Sounds familiar, yes, we can easily use recursion to achieve that. To make it better, we only need to recurse at most once since we are only allowed to delete at most one char.
Solutions
Implementation V1
// A quick implementation, a bit duplicate on checking on the palindrome part
public boolean validPalindromeFirstIteration(String s) {
// It says s is non-empty, the other is covered by normal case, so don't need this check
if (s == null || s.length() <= 2) {
return true;
}
int i = 0;
int j = s.length() - 1;
while (i < j) {
if (s.charAt(i) == s.charAt(j)) {
i++;
j--;
continue;
}
return isPalindromeHelper(s, i, j - 1) || isPalindromeHelper(s, i + 1, j);
}
return true;
}
public boolean isPalindromeHelper(String s, int start, int end) {
while (start < end) {
if (s.charAt(start) == s.charAt(end)) {
start++;
end--;
continue;
}
return false;
}
return true;
}
Implementation V2
// Need an intermediate Result class to return multiple values from a function
public class Result{
public boolean isPalindrome = false;
public int diffStartIndex = 0;
public int diffEndIndex = 0;
public Result(boolean isPalindrome, int diffStartIndex, int diffEndIndex) {
this.isPalindrome = isPalindrome;
this.diffStartIndex = diffStartIndex;
this.diffEndIndex = diffEndIndex;
}
}
public Result isPalindromeGenericHelper(String s, int start, int end) {
while (start < end) {
if (s.charAt(start) == s.charAt(end)) {
start++;
end--;
continue;
}
return new Result(false, start, end);
}
return new Result(true, start, end);
}
public boolean validPalindrome(String s) {
// Just remember to add your VM params with -ea in your run configuration
assert s != null && s.length() > 0 : "Invalid input string s";
Result res = isPalindromeGenericHelper(s, 0, s.length()-1);
if (res.isPalindrome) {
return true;
}
return isPalindromeGenericHelper(s, res.diffStartIndex + 1, res.diffEndIndex).isPalindrome ||
isPalindromeGenericHelper(s, res.diffStartIndex, res.diffEndIndex - 1).isPalindrome;
}
Time Complexity: O(N), N is the string length, worst case we traverse the string twice using recursion , O(N) + O(N) still equals O(N) Space Complexity: No additional space is needed (recursion function stack not included). Even counting function recursion stack, it's still O(1), which means constant space since you are bound to recurse only once
References
- A more clean solution
- Envoy架构概览(7):断路,全局限速和TLS
- Envoy架构概览(9):访问日志,MongoDB,DynamoDB,Redis
- 【前沿】TensorFlow Pytorch Keras代码实现深度学习大神Hinton NIPS2017 Capsule论文
- Linux 部署ASP.NET SQLite 应用 的坎坷之旅 附demo及源码
- 跨平台:使用OWIN 为WebAPI 宿主
- 如何在UWP中统一处理不同设备间的页面回退逻辑
- new and override
- 初识SignalR~仿QQ即时聊天(群发,单发)(Web,WPF等Demo演示)【上】
- 【翻译】A Next-Generation Smart Contract and Decentralized Application Platform
- asp.net回调javascript
- Oracle9i第2版中的UNT_FILE提高了文件输入/输出(I/O)功能。
- Python 工匠:善用变量来改善代码质量
- sql数据库打包部署安装
- 打包并自动安装sql数据库
- JavaScript 教程
- JavaScript 编辑工具
- JavaScript 与HTML
- JavaScript 与Java
- JavaScript 数据结构
- JavaScript 基本数据类型
- JavaScript 特殊数据类型
- JavaScript 运算符
- JavaScript typeof 运算符
- JavaScript 表达式
- JavaScript 类型转换
- JavaScript 基本语法
- JavaScript 注释
- Javascript 基本处理流程
- Javascript 选择结构
- Javascript if 语句
- Javascript if 语句的嵌套
- Javascript switch 语句
- Javascript 循环结构
- Javascript 循环结构实例
- Javascript 跳转语句
- Javascript 控制语句总结
- Javascript 函数介绍
- Javascript 函数的定义
- Javascript 函数调用
- Javascript 几种特殊的函数
- JavaScript 内置函数简介
- Javascript eval() 函数
- Javascript isFinite() 函数
- Javascript isNaN() 函数
- parseInt() 与 parseFloat()
- escape() 与 unescape()
- Javascript 字符串介绍
- Javascript length属性
- javascript 字符串函数
- Javascript 日期对象简介
- Javascript 日期对象用途
- Date 对象属性和方法
- Javascript 数组是什么
- Javascript 创建数组
- Javascript 数组赋值与取值
- Javascript 数组属性和方法
- Redis的使用--(二)与Spring的整合
- Milvus 实战|利用 Milvus 搭建基于图的推荐系统
- k8s基本使用
- 淮师2017校园新闻爬取&&WordCloud年度词云分析
- 13 | Tornado源码分析:BaseIOStream 对象(下)
- 谈谈线程
- springboot整合定时框架-Elastic-job-lite
- hashMap的循环姿势你真的使用对了吗?
- SpringBoot整合常用技术
- SpringBoot整合Quartz实现定时任务(单任务、多任务)
- 你的登录接口,真的安全吗?如何预防黑客攻击
- JWT登录信息加密
- 我画了近百张图来理解红黑树
- SpringBoot之API--Swagger2接口文档管理
- 索引失效原理,终于有人讲明白了