题目代号: 剑指 Offer 05. 替换空格
题目描述:
请实现一个函数,把字符串 s 中的每个空格替换成"%20"。
测试用例:
示例 1:
输入:s = “We are happy.”
输出:“We%20are%20happy.”
我的分析:
虽然这是一个字符串,但我们是可以一个一个字母的拿出来,当遇到空格的时候就替换,否则就直接加上
代码:
package 剑指offer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @program: day01
* @description:
* @author: Mr.Wang
* @create: 2021-04-14 18:23
**/
public class offer5 {
public static void main(String[] args) throws IOException {
BufferedReader rd = new BufferedReader(new InputStreamReader(System.in));
String str = rd.readLine(); //对一行读入
System.out.println(replaceSpace(str));
}
public static String replaceSpace(String s) {
int length = s.length();
int[] res = new int[3*length];
int idx = 0;
for(int i = 0;i < length;i++){
char yuansu = s.charAt(i);
if(yuansu == ' '){
res[idx++] = '%';
res[idx++] = '2';
res[idx++] = '0';
}else {
res[idx++] = yuansu;
}
}
return new String(res,0,idx);//把索引从0到idx的数组转化成字符串
}
}
题目代号: 剑指 Offer 38. 字符串的排列
题目描述:
输入一个字符串,打印出该字符串中字符的所有排列。
你可以以任意顺序返回这个字符串数组,但里面不能有重复元素。
测试用例:
示例:
输入:s = “abc”
输出:[“abc”,“acb”,“bac”,“bca”,“cab”,“cba”]
我的分析:
对于给定的一个字符串,就从头开始,一个点一个点的来考虑
先固定第一个点,后面的点进行排列(排列过程就是互换过程)
再固定第二个点,后面的点进行排列
再固定第三个点,后面的点进行排列
…
这个互换过程很重要,对于每个点都要互换的
代码:
class Solution {
List<String> res = new ArrayList<>();//创建一个链表,先把结果放进链表中,因为链表好操作一点,直接放进数组反倒不好操作,最后数组再转化为链表
public String[] permutation(String s){
dfs(s.toCharArray(),0);//将字符串转换成字符数组
return res.toArray(new String[res.size()]);//链表转化成字符串数组
}
public void dfs(char[] strArr,int begin){//begin位是个移动位,就在不停的固定它所在位的元素
if(begin == strArr.length-1){
res.add(String.valueOf(strArr));//字符串数组转化成字符串
return;
}
HashSet<Character> set = new HashSet<>();
for(int i = begin;i < strArr.length;i++){
if(set.contains(strArr[i])) continue;//每一次排列都要查重,把重复的跳过
set.add(strArr[i]);
swap(strArr,begin,i);//交换,将strArr[i]固定在第begin位
dfs(strArr,begin+1);//固定第begin+1位
swap(strArr,begin,i);//恢复交换
}
}
public void swap(char[] strArr,int a,int b){
char temp=strArr[a];
strArr[a]=strArr[b];
strArr[b]=temp;
}
}
题目代号: 剑指 Offer 50. 第一个只出现一次的字符
题目描述:
在字符串 s 中找出第一个只出现一次的字符。如果没有,返回一个单空格。 s 只包含小写字母。
测试用例:
s = “abaccdeff”
返回 “b”
s = “”
返回 " "
我的分析:
先遍历,放进hashmap中,然后看里面的哪个键对应的值为1,那就输出这个键
代码:
package 剑指offer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
import java.util.HashMap;
import java.util.Map;
/**
* @program: day01
* @description:
* @author: Mr.Wang
* @create: 2021-04-15 14:10
**/
public class offer50 {
public static void main(String[] args) throws IOException {
BufferedReader rd = new BufferedReader(new InputStreamReader(System.in));
String s = rd.readLine();
System.out.println(firstUniqChar(s));
}
public static char firstUniqChar(String s) {
Map<Character,Integer> map = new HashMap<>();
for(int i = 0;i < s.length();i++){//把字符串遍历一下,放进hashmap中
char c = s.charAt(i);
map.put(c,map.getOrDefault(c,0)+1);
}
for(int i = 0;i < s.length();i++){
char c = s.charAt(i);
if(map.get(c) == 1){
return c;
}
}
return ' ';
}
}
题目代号: 剑指 Offer 58 - II. 左旋转字符串
题目描述:
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
测试用例:
示例 1:
输入: s = “abcdefg”, k = 2
输出: “cdefgab”
示例 2:
输入: s = “lrloseumgh”, k = 6
输出: “umghlrlose”
我的分析:
就先遍历后半部分,再遍历前半部分就好了
代码:
package 剑指offer;
import java.io.BufferedReader;
import java.io.IOException;
import java.io.InputStreamReader;
/**
* @program: day01
* @description:
* @author: Mr.Wang
* @create: 2021-04-15 14:29
**/
public class offer58 {
public static void main(String[] args) throws IOException {
BufferedReader rd = new BufferedReader(new InputStreamReader(System.in));
String s = rd.readLine();
int n = Integer.parseInt(rd.readLine());//字符串转整数
System.out.println(reverseLeftWords(s,n));
}
public static String reverseLeftWords(String s, int n) {
String res = "";
for(int i = n;i < s.length();i++){
res += s.charAt(i);
}
for (int i = 0;i < n;i++){
res += s.charAt(i);
}
return res;
}
//这两种方法均可,只是放的地方不一样而已,思路一样的
// public String reverseLeftWords(String s, int n){
// StringBuilder sb = new StringBuilder();
// for(int i = n;i < s.length();i++){
// sb.append(s.charAt(i));
// }
// for (int i = 0;i < n;i++){
// sb.append(s.charAt(i));
// }
// return sb.toString();
// }
}
题目代号: 剑指 Offer 58 - I. 翻转单词顺序
题目描述:
输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. “,则输出"student. a am I”。
测试用例:
示例 1:
输入: “the sky is blue”
输出: “blue is sky the”
示例 2:
输入: " hello world! "
输出: “world! hello”
解释: 输入字符串可以在前面或者后面包含多余的空格,但是反转后的字符不能包括。
示例 3:
输入: “a good example”
输出: “example good a”
解释: 如果两个单词间有多余的空格,将反转后单词间的空格减少到只含一个。
我的分析:
首先按空格切分开,形成一个字符串数组
字符串数组依次遍历,将结果放进StringBuilder中,但必须将空格全部剔除,然后在放入的时候,自己添加空格
这样的结果会末尾多一个空格,然后删除即可
代码:
class Solution {
public String reverseWords(String s) {
String[] strs = s.split(" "); // 删除首尾空格,分割字符串,放进字符数组中
StringBuilder res = new StringBuilder();
for(int i = strs.length - 1; i >= 0; i--) { // 倒序遍历字符串数组,放进StringBuilder中
if(strs[i].equals("")) continue; // 遇到空单词则跳过
//好奇怪,equals还不能中间有空格
res.append(strs[i] + " "); // 将单词拼接至 StringBuilder
}
return res.toString().trim(); // 转化为字符串,删除尾部空格,并返回
}
}
题目代号: 剑指 Offer 67. 把字符串转换成整数
题目描述:
将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。
输入输出描述:
输入一个字符串,包括字母、数字、符号,可以为空。如果是合法的数值表达则返回该数字,否则返回0。
测试用例:
示例 1:
输入: “42”
输出: 42
示例 2:
输入: " -42"
输出: -42
解释: 第一个非空白字符为 ‘-’, 它是一个负号。
我们尽可能将负号与后面所有连续出现的数字组合起来,最后得到 -42 。
示例 3:
输入: “4193 with words”
输出: 4193
解释: 转换截止于数字 ‘3’ ,因为它的下一个字符不为数字。
示例 4:
输入: “words and 987”
输出: 0
解释: 第一个非空字符是 ‘w’, 但它不是数字或正、负号。
因此无法执行有效的转换。
示例 5:
输入: “-91283472332”
输出: -2147483648
解释: 数字 “-91283472332” 超过 32 位有符号整数范围。
因此返回 INT_MIN (−231) 。
我的分析:
当你读入的时候,你需要考虑的是
第一点:先把空格去掉
第二点:判断下标志位是正负
第三点:一位一位往出拿,当看的数连接起来比较大的时候,就出来最大值或者最小值
*/
代码:
package 剑指offer;
/**
* @program: day01
* @description:
* @author: Mr.Wang
* @create: 2021-04-15 16:10
**/
public class offer67 {
public static void main(String[] args) {
}
/*
当你读入的时候,你需要考虑的是
第一点:先把空格去掉
第二点:判断下标志位是正负
第三点:一位一位往出拿,当看的数连接起来比较大的时候,就出来最大值或者最小值
*/
public int strToInt(String str) {
//第一点:去空格
char[] s = str.trim().toCharArray();
//第二步:定义标志位,正负
int flag = 1;
//第三步:定义索引位置
int i = 0;
if(s.length == 0) return 0;
if(s[i] == '+') i++;
else if(s[i] == '-'){
i++;flag = -1;
}
long res = 0;//储存最后结果
while (i < s.length){
if(s[i] < '0' || s[i] > '9') break;
long zhi = 10*res+flag*(s[i]-'0');
if(zhi > Integer.MAX_VALUE && flag == 1) return Integer.MAX_VALUE;
if(zhi < Integer.MIN_VALUE && flag == -1) return Integer.MIN_VALUE;
res = zhi;
i++;
}
return (int) res;//这里强转不能省略;
}
}
题目代号: 剑指 Offer 19. 正则表达式匹配
题目描述:
请实现一个函数用来匹配包含’. ‘和’‘的正则表达式。模式中的字符’.‘表示任意一个字符,而’'表示它前面的字符可以出现任意次(含0次)。在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"abaca"匹配,但与"aa.a"和"ab*a"均不匹配。
测试用例:
示例 1:
输入:
s = “aa”
p = “a”
输出: false
解释: “a” 无法匹配 “aa” 整个字符串。
示例 2:
输入:
s = “aa”
p = “a*”
输出: true
解释: 因为 ‘*’ 代表可以匹配零个或多个前面的那一个元素, 在这里前面的元素就是 ‘a’。因此,字符串 “aa” 可被视为 ‘a’ 重复了一次。
示例 3:
输入:
s = “ab”
p = “."
输出: true
解释: ".” 表示可匹配零个或多个(’*’)任意字符(’.’)。
示例 4:
输入:
s = “aab”
p = “cab”
输出: true
解释: 因为 ‘*’ 表示零个或多个,这里 ‘c’ 为 0 个, ‘a’ 被重复一次。因此可以匹配字符串 “aab”。
示例 5:
输入:
s = “mississippi”
p = “misisp*.”
输出: false
s 可能为空,且只包含从 a-z 的小写字母。
p 可能为空,且只包含从 a-z 的小写字母以及字符 . 和 ,无连续的 '’。
我的分析:
从第二个字符来分类讨论
代码:
package 剑指offer;
import java.math.BigDecimal;
/**
* @program: day01
* @description:
* @author: Mr.Wang
* @create: 2021-04-15 16:56
**/
public class offer19 {
public static void main(String[] args) {
}
/*
咱们一个一个字符的来看
1、如果是相同的字符,直接下一个
2、如果是.,直接下一个
3、如果字符是*,就要分情况讨论了
3.1 在p中,*号跟它前面的那个值c是捆绑在一起的,如果c*中c与s中的对应元素不同,就把c*一起剔除就好,被忽略掉
如果c*中c与s中的对应元素相同,那就只能s中对应元素出现无数次
*/
public boolean isMatch(String s, String p) {
if(s == null || p == null){
return false;
}
int i = 0;int j = 0;
return match(s,0,p,0);
}
private boolean match(String s, int i,String p,int j){
if(j == p.length() && i == s.length()){
return true;
}
if(i < s.length() && j == p.length()){
return false;
}
if(j+1 < p.length() && p.charAt(j+1) == '*'){//如果第二个字符是*
if((i < s.length() && s.charAt(i) == p.charAt(j)) || (i < s.length() && p.charAt(j) == '.')){//第一个字符相等:有三种情况
//分别代表匹配0个、1个、多个
//例如s = a p = a*
return match(s,i,p,j+2) || match(s,i+1,p,j+2) || match(s,i+1,p,j);
}else {//第一个字符不等
//例如 s = a p = b*a
return match(s,i,p,j+2);
}
}else {//第二个字符不是*
if((i < s.length() && s.charAt(i) == p.charAt(j)) || (i < s.length() && p.charAt(j) == '.')){
return match(s,i+1,p,j+1);
}
}
return false;
}
}
题目代号: 剑指 Offer 20. 表示数值的字符串
题目描述:
测试用例:
我的分析:
这道题就看给出的字符串是否符合规范
1、所以咱们定义四个flag来对应符合规范的四种字符(初始化都为false)
a、是否有数字:hasNum
b、是否有e:hasE
c、是否有正负号:hasSign
d、是否有小数点:hasDot
2、字符串长度为n以及字符串索引index
3、先处理一下开头的空格,index后移
4、然后进入循环,遍历字符串
a、如果字符c是数字:hasNum置为true
b、如果字符c是e或者E:如果e已经出现或者当前e之前没有出现过数字,返回结果false;
否则令hasE = true,并且将其他3个flag全部置为false,因为要开始遍历e后面的新数字了
c、当前字符c是+或-:如果已经出现过+或-或者已经出现过数字或者已经出现过’.’,返回false;否则令hasSign = true
d、如果当前字符c是’.’:如果已经出现过’.‘或者已经出现过’e’或’E’,返回false;否则令hasDot = true
e、如果当前字符c是’ ':结束循环,因为可能是末尾的空格了,但也有可能是字符串中间的空格,在循环外继续处理
如果当前字符c是除了上面5种情况以外的其他字符,直接返回false
5、处理空格,index相应的后移
6、如果当前索引index与字符串长度相等,说明遍历到了末尾,但是还要满足hasNum为true才可以最终返回true,
因为如果字符串里全是符号没有数字的话是不行的,而且e后面没有数字也是不行的,但是没有符号是可以的,
所以4个flag里只要判断一下hasNum就行;所以最后返回的是hasNum && index == n
7、如果字符串中间有空格,按以上思路是无法遍历到末尾的,index不会与n相等,返回的就是false
代码:
public boolean isNumber(String s) {
int n = s.length();
int index = 0;
boolean hasNum = false, hasE = false,hasSign = false, hasDot = false;
while (index < n && s.charAt(index) == ' ') index++;
while (index < n){//现在进入循环了
while (index < n && s.charAt(index) >= '0' && s.charAt(index) <= '9'){//这是个循环,所以不能把char提到之前
index++;
hasNum = true;//说明已经有过数字了
}
if(index == n) break;
char c = s.charAt(index);
//现在正式判断这几种情况
if(c == 'e' || c == 'E'){
if(hasE==true || hasNum == false){//如果已经出来过e E或者数字没出现过
return false;
}
hasE = true;
hasDot = false;hasNum = false;hasSign = false;//一旦在这之后,那就重头开始,这些都相当于没出现过
//之后只能出现数字了,其他的不能出现了
} else if (c == '+' || c == '-') {
if(hasDot || hasNum || hasSign){//任意出现一个都了不得
return false;
}
hasSign = true;
}else if(c == '.'){
if(hasDot || hasE){
return false;//这俩肯定不能出现过
}
hasDot = true;
}else if(c == ' '){//中间不能有空格,所以跳出的时候肯定是结尾了
break;
}else {
return false;
}
index++;//一个一个遍历索引
}
while (index < n && s.charAt(index) == ' ')
index++;//只有最后剩下空格的时候,才会不断的前进
return hasNum && index == n;//最后只看数字和索引是否到最后了
}
题目代号: 剑指 Offer 48. 最长不含重复字符的子字符串
题目描述:
请从字符串中找出一个最长的不包含重复字符的子字符串,计算该最长子字符串的长度。
测试用例:
输入: “abcabcbb”
输出: 3
解释: 因为无重复字符的最长子串是 “abc”,所以其长度为 3。
我的分析:
存到map中去,键放元素,值放元素下标,这个下标其实相当于右子针哦
定义左子针,并不断更新
右子针也不断更新
同时不断更新结果res
代码:
public int lengthOfLongestSubstring(String s) {
int i = -1;//起始值
int res = 0;//结果
Map<Character,Integer> map = new HashMap<>();//键放字母,值放字母对应的下标
for(int j = 0;j < s.length();j++){
if(map.containsKey(s.charAt(j))){
i = Math.max(i,map.get(s.charAt(j)));//更新起始位置
}
map.put(s.charAt(j),j);//更新结尾位置
res = Math.max(res,j-i);//更新最后结果
}
return res;
}