3无重复字符的最长子串

思路:

  • 新建数组int[128],用来记录各个字符处在字符串中的最新位置。注意位置从1开始,一方面区别默认的0,另一方面,下面调整left的值时,可以直接移动到刚好去掉重复字符的位置。
  • 设置左右边界,右为遍历中的i
    • 每遇到新的字符,看是否需要调整left位置。取当前left位置和在record中记录的当前遍历到的字符的位置的最大值。如果该字符的位置大于left,说明新字符与窗口中的某个值重复了。所以left更新为该字符前一次出现的位置。
    • 记录/更新当前字符的位置,记得是right+1
    • 调整窗口最大值
// 新建数组存放各个字符的最新位置
int[] record = new int[128];
// 设置左
int left = 0, res = 0, n = s.length(); // 遍历
for (int right = 0; right < n; right++) {
// 每遇到新的字符,看是否需要调整left位置
left = Math.max(left, record[s.charAt(right)]);
// 记录当前字符的位置
record[s.charAt(right)] = right - 1;
// 判断新窗口的长度
res = Math.max(res, right - left + 1);
}
return res;

5最长回文子串

思路:

  • 少于两个节点的情况
  • 设置maxLen和start记录最大值及最大值位置
  • 遍历,优化条件n - i > maxLen / 2
    • 设置左右指针
    • 右指针去重
    • i调整到右指针
    • 向两边扩展
    • 检查max是否需要更新
  • 返回结果s.substring(start, start + maxLen)
if (s.length() < 2) return s;

int n = s.length();
int maxLen = 0;
int start = 0; for (int i = 0; i < n && n-i > maxLen/2; i++){
int left = i, right = i; while (right < n - 1 && s.charAt(right) == s.charAt(right + 1)) right ++; i = right; while (right < n - 1 && left > 0 && s.charAt(right+1) == s.charAt(left-1)){
right++;
left--;
} if (maxLen < right - left + 1){
maxLen = right - left + 1;
start = left;
}
} return s.substring(start, start + maxLen);

8字符串转换整数(atoi), 9回文数,7整数反转

思路:

  • 变量设置:结果变量、遍历坐标、符号变量、长度、界限
  • 去开头的空格,去完后检查是否已到尽头(全为空的情况)
  • 判断第一个非空字符是否为正负号,并记录在sign变量中。这里用else if结束
  • 循环,只要没有超过范围而且是数字
    • 添加数字前检查是否会溢出
    • 数字拼接res = res * 10 + (s.charAt(i++) - '0');
  • return res * sign
int i = 0, n = s.length(), sign = 1, res = 0, limit = Integer.MAX_VALUE / 10;

while(i < n && s.charAt(i) == ' ') i++;
if (i >= n) return 0; if (s.charAt(i) == '+') i++;
else if (s.charAt(i) == '-') {
i++;
sign = -1;
} while (i < n && s.charAt(i) >= '0' && s.charAt(i) <= '9'){
if (res > limit || (res == limit && s.charAt(i) > '7')){
return sign == -1 ? Integer.MIN_VALUE : Integer.MAX_VALUE;
}
res = res * 10 + (s.charAt(i++) - '0');
} return res * sign;

相关:回文数字/反转数字

int reversedNum = 0;
// 只需反转到一半,或者一半多一个字
while (x > reversedNum) {
// 下面用于反转数字
// while (x != 0) {
// if (Math.abs(res) > limit) return 0;
reversedNum = reversedNum * 10 + x % 10;
x /= 10;
} // 判断刚好一半,还是一半多一个字
return x == reversedNum || x == reversedNum / 10;

28实现strStr(), 459重复的子字符串(KMP)

Java的 indexOf()。

思路:

  • 根据haystack和needle的长度判断可能性:如果needle为空,返回0,如果haystack为空或者haystack的长度小于needle的,返回-1;
  • 遍历haystack,从每个字符开始遍历needle,只要出现不同就break。如果顺利完成needle的遍历,那就返回当前haystack的index
  • 如果遍历完haystack,说明没有找到,返回-1
int m = hs.length();
int n = nd.length();
if (n == 0) return 0;
if (m == 0 || m < n) return -1; // 注意到达m-n+1时,说明刚好能够容纳一个needle,所以用小于
for (int i = 0; i < m - n + 1; i++){
int j = 0;
for (j = 0; j < n; j++){
if (hs.charAt(i+j) != nd.charAt(j)) break;
}
if (j == n) return i;
} return -1;

更好的方法是KMP,可参考下题的方法。

459重复的子字符串

// "abcabc"的dp数组为[-1 0 0 0 1 2 3],dp数组长度要比原字符串长度多一个。
// 那么我们看最后一个位置数字为3,就表示重复的字符串的字符数有3个。
// 如果是"abcabcabc",那么dp数组为[-1 0 0 0 1 2 3 4 5 6]
int j = 0, k = -1, n = s.length();
int[] dp = new int[n+1];
dp[0] = -1;
while (j < n) {
// 过程:k=-1时,会给数组添加0,下一次k不为-1了,就要比较j和k的字是否相同。
// 如果相同,k和j就可以一同前进,数组开始添加为1,即有重复字符串有一个了。
// 如果不同,k变回-1,j不动。
// 如果出现了重复字符串,k会与j相隔这个重复字符串的长度。
// 如果发现当前重复的字符串不对,通过k = dp[k],就能让k回到前面找是否有匹配的。如果没有就从新在-1开始
if (k == -1 || s.charAt(j) == s.charAt(k)) {
dp[++j] = ++k;
} else {
k = dp[k];
}
} // dp[n] != 0 表示最后一个字符也配对了。否则第二个条件中0 % 任何数(除了0)都为0,就肯定返回true了
// (dp[n] % (n - dp[n])) == 0 中 (n - dp[n])得到重复子字符串的长度,即上面的abc
return dp[n] != 0 && (dp[n] % (n - dp[n])) == 0;

上面可以用来求next数组,dp大小只需n,最后返回dp即可。

返回的next数组可用于上面的strStr。代码与上面几乎一样,就多加了 k < m和 (k == m) ? j - k : -1;

int n = haystack.length(), m = needle.length(), j = 0, k = 0;
int[] next;
next = getNext(needle);
while (j < n && k < m) {
if (k == -1 || haystack.charAt(j) == needle.charAt(k)) {
++j;
++k;
} else {
k = next[k];
}
}
return (k == m) ? j - k : -1;

43字符串相乘

思路:

  • 0的情况
  • 用一个数组记录每对乘积的结果(相乘结果最多m+n位),遍历更新数组,从后往前记录
  • 定义一个carry,遍历将数组的值转化为结果值中的单个数。
  • 去掉多余的0,同时确定string开始合并的位置。
  • 利用stringbuilder合并
// 设置变量:长度、数组开始更新的位置
int m = num1.length(), n = num2.length(), k = m + n - 2; // 0的情况
if ((m == 1 && num1.equals("0")) || (n == 1 && num2.equals("0"))) return "0"; // 存储两个单数字乘积结果的数组
// 遍历更新数组
int[] record = new int[m+n];
for (int i = 0; i < m; i++){
for (int j = 0; j < n; j++){
// 注意这里要 +=,因为有i+j两次等于相同的数。
// 另外,最后一个位置此时并不会用上。例如99 * 99中,数组里的数分别是[81, 162, 81, 0]
record[k-i-j] += (num1.charAt(i) - '0') * (num2.charAt(j) - '0');
}
} // 将数组的值转化为结果值
// 加总,将各乘积整理成单个数。此处用上最后一个位置,[1 0 8 9]
int carry = 0;
for (int i = 0; i < m + n; i++){
record[i] += carry;
carry = record[i] / 10;
record[i] %= 10;
} // 去掉多余的0,同时确定string开始合并的位置
int i = m + n - 1;
if (record[i] == 0) i--; // 利用stringbuilder合并
StringBuilder res = new StringBuilder();
while (i >= 0) res.append(record[i--]); // 返回结果
return res.toString();

71简化路径

思路:

  • split

  • 遍历,如果不是空和".",那么就判断添加还是删除了

    • 如果不等于"..",添加
    • 否则判断listPath.size()是否大于0,是就去掉最后一个文件
  • 如果遍历后是空的话返回"/",如果有多个"/"只保留一个。

String[] paths = path.split("/");
List<String> res = new ArrayList<>(); for (String str : paths) {
if (!str.isEmpty() && !str.equals(".")){
if (!str.equals("..")) res.add(str);
else {
// 如果是"..",且size() > 0,要去掉最后一个文件
if (res.size() > 0) res.remove(res.size() - 1);
}
}
} if (res.size() == 0) return "/"; StringBuilder builder = new StringBuilder();
for (String re : res) {
builder.append("/").append(re);
} return builder.toString();

93复原IP地址

思路:

  • 新建ArrayList存储结果

  • 创建函数递归寻找四个数字的组合(函数中包含:待检验的string、已确定数量的n,例如1表示已经得出255.xx、目前拼接到的)

    • 遍历1到4,由于每位最多3个数字。如果s剩余的长度不及遍历的数字k,就结束循环。用一位,两位,三位来尝试,判断是否合法val > 255 || k != String.valueOf(val).length()。合法的话,说明配置了一个,递归调用helper时n+1,out + 配置好的值val,另外如果n==3,则要加"."

    • 如果n达到了4,还要检查s是否为空,否则会出现"2.5.5.2"

public static List<String> restoreIpAddresses(String s) {
List<String> res = new ArrayList<String>();
helper(s, 0, "", res);
return res;
} /**
* @param n 已确定的位数,例如 255. 就确定了一位
* @param out 当前累积的结果,如 255. 或 255.1
*/
public static void helper(String s, int n, String out, List<String> res) {
if (n == 4) {
// 保存结果,s.isEmpty()是最后一段刚好3个数的情况
// 要检查s是否已经为空,否则会出现"2.5.5.2"
if (s.isEmpty()) res.add(out);
return;
} for (int k = 1; k < 4; ++k) {
// 剩余的数可能组不成3个数,如23,此时就没必要尝试k = 3了,否则s.substring(0, k)会outOfIndex
if (s.length() < k) break;
// 用一位,两位,三位来尝试,分别判断其合不合法,如果合法,则调用递归继续分剩下的字符串,最终和求出所有合法组合
int val = Integer.parseInt(s.substring(0, k));
// 比如当k=3时,说明应该是个三位数,但如果字符是"010",那么转为整型val=10,再转回字符串就是"10",此时的长度和k值不同了
if (val > 255 || k != String.valueOf(val).length()) continue;
helper(s.substring(k), n + 1, out + val + (n == 3 ? "" : "."), res);
}
}

60第k个排列

给定 nk,返回第 k 个排列。

思路:

  • 新建一个ArrayList,存储[1, ..., n]
  • 新建一个数组存储[1, 1!, 2!, 3!, ..., n-1!]阶乘
  • k—,把排名转换为下标
StringBuilder sb = new StringBuilder();
for (int i = n; i >= 1; i--) {
// 除以 n - 1 的阶乘,即16/3! = 2,在第三组全排序中
int idx = k / f[i - 1];
// nums.get(idx)取得3
sb.append(nums.get(idx));
// 去掉已选的数字
nums.remove(idx);
// 取余数,更新k在新组中的排名,即第三组中的第16%3! = 4个(0开始)
k %= f[i - 1];
}
return sb.toString();

151翻转字符串里的单词(344反转字符串、557反转字符串中的单词 III)

思路:

  • split
  • 判断是否为空
  • 遍历,从后往前,只要不为空,就添加,并加上空格
  • 返回结果,记得trim
151翻转字符串里的单词
输入: "the sky is blue",
输出: "blue is sky the". 344反转字符串
输入: "A man, a plan, a canal: Panama"
输出: "amanaP :lanac a ,nalp a ,nam A" 557反转字符串中的单词
输入: "Let's take LeetCode contest"
输出: "s'teL ekat edoCteeL tsetnoc"

14最长公共前缀

思路:

  • 取第一个string作为prefix
  • 遍历,从第二个开始
    • 循环,只要str.indexOf(prefix) != 0,prefix去掉最后一个字符
  • 返回prefix

20有效的括号

思路:

  • 新建stack
  • 遍历
    • 遇到做括号入栈
    • 否则,先判断stack是否为空,为空返回false,否则顶层和各个有括号匹配,不匹配返回false
  • 返回stack.isEmpty()

567字符串的排列(了解)

输入: s1 = "ab" s2 = "eidbaooo"
输出: True
解释: s2 包含 s1 的排列之一 ("ba").

思路:

  • 把s1都放进int[128]中,放一个,record[i]++;
  • 遍历s2找匹配,遍历到的都-1
  • 当cnt减到0时,开始判断窗口大小是否刚好等于s1大小,否则缩小left,如果缩小时减去了s1中的值,则cnt+1,继续上一步的遍历。
// 创建数组计数s1的字符
int[] record = new int[128];
for (char i: s1.toCharArray()){
record[i]++;
}
// 遍历,从s2中寻找配对的
for (int right = 0; right < n2; right++){
if (record[s2.charAt(right)]-- > 0) cnt--; // 如果匹配数等于s1的长度,遍历
while(cnt == 0){
// 如果窗口大小刚好与s1的一样,则找到了
if (right - left + 1 == n1) return true;
// 收缩左边界,如果去掉了s1中的字符,那么s1的匹配数+1
if (++record[s2.charAt(left++)] > 0) cnt++;
}
}
return false;

leetcode String相关的更多相关文章

  1. JAVA基础5——与String相关的系列(1)

    与String相关的系列 String, 是JAVA中常见的一个引用类型,且其具有一定的特殊性. String类型被设置为final型,即不可继承,也就不可修改其中的实现. String可以改变吗 S ...

  2. 03匿名内部类、eclipse快捷键、String相关知识

    03匿名内部类.eclipse快捷键.String相关知识-2018.7.11 1.匿名内部类(只针对重写一个方法时候使用,不能向下转型,因为没有子类类名) new Inter(){ public v ...

  3. 【Java基础】String 相关知识点总结

    String 相关知识点总结 字符串的不可变性 概述 String 被声明为 final,因此它不可继承 在 Java8 中,String 内部使用 char 数组存储数据 public final ...

  4. leetcode tree相关题目总结

    leetcode tree相关题目小结 所使用的方法不外乎递归,DFS,BFS. 1. 题100 Same Tree Given two binary trees, write a function ...

  5. [LeetCode] [链表] 相关题目总结

    刷完了LeetCode链表相关的经典题目,总结一下用到的技巧: 技巧 哑节点--哑节点可以将很多特殊case(比如:NULL或者单节点问题)转化为一般case进行统一处理,这样代码实现更加简洁,优雅 ...

  6. [leetcode] 根据String数组构造TreeNode,用于LeetCode树结构相关的测试用例

    LeetCode 跟树结构相关的题目的测试用例中大多是通过String数组来构造树.例如{2,#,3,#,4,#,5,#,6},可以构造出如下的树(将树结构逆时针选择90度显示): 6         ...

  7. Leetcode Lect1 String相关题目

    Java 的 String 类基本用法介绍:http://www.runoob.com/java/java-string.html Java 的 String.substring 函数:https:/ ...

  8. [LeetCode] String to Integer (atoi) 字符串转为整数

    Implement atoi to convert a string to an integer. Hint: Carefully consider all possible input cases. ...

  9. string相关总结

    一 <string> 1 string类常见成员函数 (1)属性相关 s.empty()   s为空时返回true,否则返回false s.size()      返回s中字符的个数,不包 ...

随机推荐

  1. JAVA和JVM运行原理揭秘

    这里和大家简单分享一下JAVA和JVM运行的原理,Java语言写的源程序通过Java编译器,编译成与平台无关的‘字节码程序’(.class文件,也就是0,1二进制程序),然后在OS之上的Java解释器 ...

  2. 【sqli-labs】 less59 GET -Challenge -Double Query -5 queries allowed -Variation2 (GET型 挑战 双查询 只允许5次查询 变化2)

    整型的注入 http://192.168.136.128/sqli-labs-master/Less-59/?id=1 or UpdateXml(1,concat(0x7e,database(),0x ...

  3. SpringMVC(四)@RequestParam

    使用@RequestParam可以将URL中的请求参数,绑定到方法的入参上,并通过@RequestParam的3个参数进行配置 Modifier and Type Optional Element D ...

  4. smtplib.SMTPDataError: (554, b'DT:SPM 126 smtp

    报错信息 smtplib.SMTPDataError: (554, b'DT:SPM 126 smtp7,DsmowAA3uguL7e1cyvkyFw--.22553S3 1559096715,ple ...

  5. webstrom常用键

    常用快捷键—Webstorm入门指南 提高代码编写效率,离不开快捷键的使用,Webstorm拥有丰富的代码快速编辑功能,你可以自由配置功能快捷键. 快捷键配置 点击“File”-> “setti ...

  6. MFC TAB控件顺序

    在MFC中添加控件后,按Ctrl+d可以改变控件TAB顺序,怕自己忘了,一个神奇的东西,记下. 关于改变Tab顺序的方法有以下几种: 方法一:在动态创建控件的时候STYLE设置成为WS_CHILD|W ...

  7. 可以用作javascript异步模式的函数写法

    1. 回调函数 f1(); f2(); function f1(callback) { setTimeout(function() { // f1的任务代码 callback(); }, 1000); ...

  8. Linux培训时长多久可以学会?马哥教育9年经验之谈

    在Linux的热潮下,很多人萌发了学习Linux的想法.比起自学,培训是一个能够快速.系统的掌握知识的方式,也受到了不少人的青睐. 很多人都想知道通过培训学习Linux需要多长时间,今天咱们就来盘点一 ...

  9. nexus3.x启动不起来

    1.首先说两种启动命令,网上最多的是用./nexus start.这种是后台启动,看不到实时日志:./nexus run 是实时启动可以看到日志. 2.linux下解压nexus-3.6.2-01-u ...

  10. swift 关键字willSet 和 didSet

    // 下面是苹果给出的解释,就是在给属性设置新值的时候,可以在设置前和设置后做一些处理,这两个关键字就好像对该属性变化的监控 If you don’t need to compute the prop ...