test3. 无重复字符的最长子串
题目如下:
示例1:
输入: s = "abcabcbb"
输出: 3
解释: 因为无重复字符的最长子串是 "abc",所以其长度为 3。
示例2:
输入: s = "bbbbb"
输出: 1
解释: 因为无重复字符的最长子串是 "b",所以其长度为 1。
示例3:
输入: s = "pwwkew"
输出: 3
解释: 因为无重复字符的最长子串是 "wke",所以其长度为 3。
请注意,你的答案必须是 子串 的长度,"pwke" 是一个子序列,不是子串。
解题思路:
这一题的解法说白了就是双指针(官网上有一个好听的名字“滑动窗口”)。
我们使用两个指针i
,j
相当于窗口的左右边界,i
代表着左边界,也就是初始位置,然后判断j
指针对应的值与i
对应的是否一样。
- 如果不一样,我们向右移动
j
指针,不断扩大窗口范围; - 如果一样,我们将已经遍历过的内容长度存入数组,且跳出此轮循环,
i
指针向右移动。
Java代码:
public static int lengthOfLongestSubstring(String s) {
char[] ch = s.toCharArray();
int[] nums = new int[ch.length];
for (int i=0;i<ch.length-1;i++) {
List<Character> list = new ArrayList<>();
list.add(ch[i]);
int j = i+1;
while (ch[i]!=ch[j]) {
if (!list.contains(ch[j])) {
list.add(ch[j]);
if (j< nums.length-1) {
j++;
}
} else {
break;
}
}
nums[i] = list.size();
}
Arrays.sort(nums);
if (nums.length-1<0) {
return 0;
}
if (nums.length-1==0) {
return 1;
}
return nums[nums.length-1];
}
JavaScript代码:
/**
* @param {string} s
* @return {number}
*/
var lengthOfLongestSubstring = function (s) {
let str = s.split("");
let nums = new Array(str.length);
for (let i = 0; i < str.length - 1; i++) {
let strs = [];
strs.push(str[i]);
let j = i + 1;
while (str[i] != str[j]) {
if (!strs.includes(str[j])) {
strs.push(str[j]);
if (j < str.length - 1) {
j++;
}
} else {
break;
}
}
nums[i] = strs.length;
}
nums.sort((a, b) => a - b);
if (nums.length - 1 < 0) {
return 0;
}
if (nums.length - 1 == 0) {
return 1;
}
//注意:JS这里是nums.length - 2,因为前面创建的nums数组我们没用完,没赋值的都是undefined
return nums[nums.length - 2];
};
test5. 最长回文子串
题目如下:
示例1:
输入:s = "babad"
输出:"bab"
解释:"aba" 同样是符合题意的答案。
示例2:
输入:s = "cbbd"
输出:"bb"
解题思路:
尽管我每做一道题都在默念——千万别超时!千万别超时!!千万别超时!!!
但事实就是——我果然还是太年轻了,一看题就有思路,一输出就超时,这种感受谁懂啊喂~
以我目前的水平,只能这么暴力求解。
- 首先,我们先来写个双重for循环“来挑衅一下时间复杂度”;
- 然后在内层for循环里“动手”,截取字符串加if判断,来判断是否是回文子串(此处使用的是双指针来判断是否是回文子串);
- 如果是回文子串,我们用max值来判断该回文子串的长度是否为最长,且将这个子串加入数组中(按照其长度作为下标),最后根据下标输出最长回文子串。
Java代码:
//错误代码——超出时间限制
// public static String longestPalindrome(String s) {
// if (s.length()<2) {
// return s;
// }
// String[] ch = new String[10000];
// int max = 0;
// for (int i=0;i< s.length();i++) {
// for (int j=s.length();j>i;j--) {
// StringBuilder sb1 = new StringBuilder(s.substring(i, j));
// StringBuilder sb2 = new StringBuilder(s.substring(i, j));
// sb1.reverse();
// if (sb1.toString().equals(sb2.toString())) {
// max = max>sb1.length()?max:sb1.length();
// ch[sb1.length()] = sb2.toString();
// }
// }
// }
// return ch[max];
// }
//正确代码——双指针解法
class Solution {
public static String longestPalindrome(String s) {
if (s.length()<2) {
return s;
}
String[] ch = new String[10000];
int max = 0;
for (int i=0;i< s.length();i++) {
for (int j=i;j<s.length();j++) {
//一定要记得加j+1-i>max判断(条件限制——让后面进入panduan里的字符长度大于之前的),可以降低很多时间复杂度,并且一定要写在前面!!!
if(j+1-i>max&&panduan(s.substring(i, j+1))) {
max=Math.max(max,j+1-i);
ch[j+1-i] = s.substring(i, j+1);
}
}
}
return ch[max];
}
//双指针——
private static boolean panduan(String s){
int l=0;
int r =s.length()-1;
while(l<r){
if(s.charAt(l)!=s.charAt(r)){
return false;
}
l++;
r--;
}
return true;
}
}
//正确代码——朋友的解法
public static String longestPalindrome(String s) {
int l = 0;
String result = "";
Map<Character, List<Integer>> map = new HashMap<>();
//Map第一个方字母,第二个放这个字母索引的集合
for (int i = 0; i < s.length(); i++) {
List<Integer> orDefault = map.getOrDefault(s.charAt(i), new ArrayList<>());
orDefault.add(i);
map.put(s.charAt(i), orDefault);
List<Integer> intArr = map.get(s.charAt(i));
for (Integer index : intArr) {
String str = s.substring(index, i + 1);
int tempL = str.length();
if (tempL > l && check(str)) {
l = tempL;
result = str;
}
}
}
return result;
}
JavaScript代码:
/**
* @param {string} s
* @return {string}
*/
var longestPalindrome = function (s) {
let max = 0;
let strs = [];
for (let i = 0; i < s.length; i++) {
for (let j = i; j < s.length; j++) {
if (j + 1 - i > max&& huiwen(s.substring(i, j + 1)) ) {
max = max > j + 1 - i ? max : j + 1 - i;
strs[j + 1 - i] = s.substring(i, j + 1);
}
}
}
return strs[max]
// console.log(strs[max]);
function huiwen(str) {
let l = 0;
let r = str.length - 1
stra = str.split('');
while (l < r) {
if (stra[l] != stra[r]) {
return false;
}
l++;
r--;
}
return true;
}
};
longestPalindrome();
test13. 罗马数字转整数
题目如下:
示例1:
输入: s = "III"
输出: 3
示例2:
输入: s = "IV"
输出: 4
示例3:
输入: s = "IX"
输出: 9
示例4:
输入: s = "LVIII"
输出: 58
解释: L = 50, V= 5, III = 3.
示例5:
输入: s = "MCMXCIV"
输出: 1994
解释: M = 1000, CM = 900, XC = 90, IV = 4.
解题思路:
这个题看起来很长很“恶心”,但是做起来很“简单”,只要懂得如何去存罗马数字对应的字符基本上就解决了一大部分。后半部分就根据题目所示的“步骤”去实现就ok啦!
Java代码:
public static int romanToInt(String s) {
Map<Character,Integer> ch = new HashMap<Character,Integer>() {
{
put('I',1);
put('V',5);
put('X',10);
put('L',50);
put('C',100);
put('D',500);
put('M',1000);
}
};
int n = 0;
for (int i=0;i<s.length();i++) {
int a = ch.get(s.charAt(i));
if (i<s.length()-1&&a<ch.get(s.charAt(i+1))) {
n-=a;
} else {
n+=a;
}
}
return n;
}
JavaScript代码:
/**
* @param {string} s
* @return {number}
*/
var romanToInt = function (s) {
const str = s.split('');
const m1 = new Map([
['I', '1'],
['V', '5'],
['X', '10'],
['L', '50'],
['C', '100'],
['D', '500'],
['M', '1000'],
])
let n = 0;
for (let i = 0; i < str.length; i++) {
let a = m1.get(str[i]) * 1;
if (i < str.length - 1 && a < m1.get(str[i + 1])) {
n -= a;
} else {
n += a;
}
}
return n;
};
test14. 最长公共前缀
题目如下:
示例1:
输入:strs = ["flower","flow","flight"]
输出:"fl"
示例2:
输入:strs = ["dog","racecar","car"]
输出:""
解释:输入不存在公共前缀。
解题思路:
这个题其实有点绕,因为它的两个for循环,有点不符合正常的循环思路。
外循环(i)是用来遍历第一个字符串的所有字符;
内循环(j)是用来遍历所有的字符串;
当我们进入到内循环的时候,对所有的字符串的第i位进行判断,如果都相等,我们进入外循环i
的下一步,否则,就返回结果。
Java代码:
public static String longestCommonPrefix(String[] str) {
String res = "";
if (str.length==0) return "";
for (int i=0;i<str[0].length();i++) {
char c = str[0].charAt(i);
for (String st : str) {
if (i>st.length()-1) return res;
if (st.charAt(i) != c) return res;
}
res += str[0].charAt(i);
}
return res;
}
JavaScript代码:
/**
* @param {string[]} strs
* @return {string}
*/
var longestCommonPrefix = function (strs) {
let res = ""
if (strs.length == 0) return "";
for (let i = 0; i < strs[0].length; i++) {
let s1 = strs[0].split('');
for (let j = 1; j < strs.length; j++) {
let s2 = strs[j].split('');
if (i > strs[j].length - 1) return res;
if (s2[i] != s1[i]) return res;
}
res += s1[i];
}
// console.log(res);
return res;
};
test20. 有效的括号
示例1:
输入:s = "()"
输出:true
示例2:
输入:s = "()[]{}"
输出:true
示例3:
输入:s = "(]"
输出:false
解题思路:
这道题需要用到「栈」
来解决,我们可以来了解一下java中stack
的使用方法——堆栈是一种"后进先出"的数据结构,只能在一端进行插入(称为"压栈")或删除(称为"出栈")数据的操作。
- 存:根据题目的要求,左右括号一对一闭合且按照正确的顺序,意思就是先遇到的左括号要后闭合,后遇到的左括号要先闭合,即
{[()]}
这种闭合方式,因此我们需要将后遇到的左括号放在栈顶(此处我存放的是左括号对应的右括号)。 - 删:当遍历到一个右括号时,我们取出之前放在栈顶的括号来判断是否一样,如果不一样,我们就返回false。
Java代码:
public static boolean isValid(String s) {
//Stack 栈是一个 "先进后出"的原理,本质是一个List,其具备 List 所有方法
Stack<Character> stack = new Stack<Character>();
for (char c: s.toCharArray()){
if (c == '(')stack.push(')');
else if (c == '[')stack.push(']');
else if (c == '{')stack.push('}');
else if (stack.isEmpty()||c!=stack.pop()) return false;
}
//判断Stack是否为空
return stack.isEmpty();
}
JavaScript代码:
/**
* @param {string} s
* @return {boolean}
*/
var isValid = function (s) {
if (s.length == 1) {
return false;
}
const str = [];
for (st of s.split('')) {
if (st === '(') str.push(')');
else if (st == '[') str.push(']');
else if (st == '{') str.push('}');
else if (str.length == 0 || st != str.pop()) return false;
}
if (str.length == 0) {
return true;
} else {
return false;
}
};
test67. 二进制求和
示例1:
输入:a = "11", b = "1"
输出:"100"
示例2:
输入:a = "1010", b = "1011"
输出:"10101"
解题思路:
啥也不说了,我是真的很讨厌进制的题型(好吧,我承认我讨厌的题型多了去了),每次都是在不断地错误输出中找到“路”。要求是以二进制字符串的形式返回它们的和,就在我暗自窃喜直接Integer.parseInt(a,2)+Integer.parseInt(b,2)
输出时,结果就啪啪打脸,它当然不会让你那么愉快地通过了,明确的说报错原因是当字符过长时类型转换出错了。那就没办法,我们另辟蹊径吧!
在旁边一位大佬的指点下,我幡然醒悟,它不是让求和嘛,那我们直接让字符a和b以数字类型先相加,然后逢2进1,就能得到最终结果;想法很简单,但是具体操作起来其实要考虑的地方挺多的,比如当相加之后为222时,还要考虑2进位得3的情况;而且其中很多地方都是靠替换解决的。
Java代码:
import java.math.BigInteger;
class Solution {
public static String addBinary(String a, String b) {
StringBuilder ans = new StringBuilder();
BigInteger c = new BigInteger(b).add(new BigInteger(a));
String str = c.toString();
for (int i = 0;i<str.length();i++) {
ans.append(str.charAt(i));
}
int n=0;
for (int i=str.length()-1;i>=0;i--) {
if (ans.charAt(i)=='2' && i!=0) {
ans.replace(str.length()-1-n,str.length()-n,"0");
if (ans.charAt(i-1)=='1') {
ans.replace(str.length()-2-n,str.length()-1-n,"2");
} else if (ans.charAt(i-1)=='0'){
ans.replace(str.length()-2-n,str.length()-1-n,"1");
} else if (ans.charAt(i-1)=='2') {
ans.replace(str.length()-2-n,str.length()-1-n,"3");
}
}
if (ans.charAt(i)=='3' && i!=0) {
ans.replace(str.length()-1-n,str.length()-n,"1");
if (ans.charAt(i-1)=='1') {
ans.replace(str.length()-2-n,str.length()-1-n,"2");
} else if (ans.charAt(i-1)=='0'){
ans.replace(str.length()-2-n,str.length()-1-n,"1");
} else if (ans.charAt(i-1)=='2') {
ans.replace(str.length()-2-n,str.length()-1-n,"3");
}
}
if (i==0&& ans.charAt(i)=='2') {
ans.replace(0,1,"0");
ans.insert(0,"1");
}
if (i==0&& ans.charAt(i)=='3') {
ans.replace(0,1,"1");
ans.insert(0,"1");
}
n++;
}
return ans.toString();
}
}
上面的代码虽然最终都运行通过了,但仔细看的话,还是不够“优雅”。如果你有更好的解法,请和我分享叭~
如有错误,请指正!