leedcode344. 反转字符串
编写一个函数,其作用是将输入的字符串反转过来。输入字符串以字符数组 s 的形式给出。
不要给另外的数组分配额外的空间,你必须原地修改输入数组、使用 O(1) 的额外空间解决这一问题。
示例 1:
输入:s = [“h”,“e”,“l”,“l”,“o”] 输出:[“o”,“l”,“l”,“e”,“h”]
示例 2:
输入:s = [“H”,“a”,“n”,“n”,“a”,“h”] 输出:[“h”,“a”,“n”,“n”,“a”,“H”]
方法一、双指针
// 第一种方法用temp来交换数值更多人容易理解些
class Solution {
public void reverseString(char[] s) {
int l = 0;
int r = s.length - 1;
while(l < r){
char temp = s[l];
s[l] = s[r];
s[r] = temp;
l++;
r--;
}
}
}
方法二、位运算
class Solution {
public void reverseString(char[] s) {
int l = 0;
int r = s.length - 1;
while (l < r) {
s[l] ^= s[r]; //构造 a ^ b 的结果,并放在 a 中
s[r] ^= s[l]; //将 a ^ b 这一结果再 ^ b ,存入b中,此时 b = a, a = a ^ b
s[l] ^= s[r]; //a ^ b 的结果再 ^ a ,存入 a 中,此时 b = a, a = b 完成交换
l++;
r--;
}
}
}
leedcode541. 反转字符串 II
给定一个字符串 s 和一个整数 k,从字符串开头算起,每计数至 2k 个字符,就反转这 2k 字符中的前 k 个字符。
如果剩余字符少于 k 个,则将剩余字符全部反转。
如果剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符,其余字符保持原样。
示例 1:
输入:s = “abcdefg”, k = 2 输出:“bacdfeg”
示例 2:
输入:s = “abcd”, k = 2 输出:“bacd”
class Solution {
//满足一下条件
//1.从字符串开头算起,每计数至2k个字符,就反转2k个字符中的前k个字符。
//2.如果字符小于2k个但大于等于k个则反转前k个,其余字符串保存不变
//3.如果字符少于k个,则将剩余字符全部反转
//仔细观察第2个条件其实和第一个条件可以同时处理
public String reverseStr(String s, int k) {
char[] ch=s.toCharArray();
for(int i=0;i<ch.length;i=i+2*k){
//完成第1个和第二个条件
if(i+k<=ch.length){ //防止加到后面超出范围,至于是<=可以带个数字进行,例如abc,此时i=0指向a,length是3,k是3,满足条件2需要进行反转
//进行反转
reserve(ch,i,i+k-1);//i+k-1是因为i从0开始然后reserve中i到i+k-1是左闭右闭
continue;//进行下一轮循环
}
//如果剩余字符小于k的话
reserve(ch,i,ch.length-1);//反转全部
}
//将字符数组转成字符串
return new String(ch);
}
//自定义反转函数
public void reserve(char[] s,int left,int right){
while(left<right){
char temp=s[left];
s[left]=s[right];
s[right]=temp;
left++;
right--;
}
}
}
leedcode151. 反转字符串中的单词
给你一个字符串 s ,请你反转字符串中 单词 的顺序。
单词 是由非空格字符组成的字符串。s 中使用至少一个空格将字符串中的 单词 分隔开。
返回 单词 顺序颠倒且 单词 之间用单个空格连接的结果字符串。
注意:输入字符串 s中可能会存在前导空格、尾随空格或者单词间的多个空格。返回的结果字符串中,单词间应当仅用单个空格分隔,且不包含任何额外的空格。
示例 1:
输入:s = “the sky is blue” 输出:“blue is sky the”
示例 2:
输入:s = " hello world " 输出:“world hello”
解释:反转后的字符串中不能存在前导空格和尾随空格。
示例 3:
输入:s = “a good example” 输出:“example good a”
解释:如果两个单词间有多余的空格,反转后的字符串需要将单词间的空格减少到仅有一个。
class Solution {
//原字符串:" hello world "
//删除多余空格:"hello world"
//字符串反转:"dlrow olleh"
//单词反转:"world hello"
public String reverseWords(String s) {
char[] chars=s.toCharArray();
//去除首尾和中间多余的空格
char[] newchar=removeExtraSpaces(chars);
//反转字符串
reserve(newchar,0,newchar.length-1);
//单词反转
reserveWord(newchar);
return new String(newchar);
}
//和数组中移除元素的双指针方法很像
public char[] removeExtraSpaces(char[] chars){
//定义慢指针用于更新元素
int slow=0;
for(int hight=0;hight<chars.length;hight++){
//通过快指针来判断出空格的位置,然后让慢指针来判断是否对其添加空格
if(chars[hight]!=' '){//说明到下一个单词
//因为首个位置不能是空格
if(slow!=0){
chars[slow]=' ';//此时快指针指向的不是空格,慢指针指向的字符增加一个空格
slow++;//同时移动慢指针
}
//因为要hight++所以要判断hight<chars.length,当快指针不执行空格,快慢指针同时移动
while(hight<chars.length&&chars[hight]!=' '){
chars[slow]=chars[hight];
slow++;
hight++;
}
}
}
//复制数组,新建一个数组,将chars[slow]的元素复制过来
char[] newchar= new char[slow];//slow刚好是多移出1位,所以数组长度是slow
/**
第一个参数是要被复制的数组
第二个参数是被复制的数字开始复制的下标
第三个参数是目标数组,也就是要把数据放进来的数组
第四个参数是从目标数据第几个下标开始放入数据
第五个参数表示从被复制的数组中拿几个数值放到目标数组中
*/
System.arraycopy(chars,0,newchar,0,slow);
return newchar;
}
//反转字符串
public void reserve(char[] chars,int left,int right){
if (right >= chars.length) {
System.out.println("set a wrong right");
return;
}
while(right>left){
//方法一
// chars[left]^=chars[right];
// chars[right]^=chars[left];
// chars[left]^=chars[right];
//方法二
char temp=chars[left];
chars[left]=chars[right];
chars[right]=temp;
left++;
right--;
}
}
//反转单词
public void reserveWord(char[] chars){
int start=0;
//end <= s.length() 这里的 = ,是为了让 end 永远指向单词末尾后一个位置,这样我们最后能对start到end-1进行反转
for(int end=0;end<=chars.length;end++){
if(end==chars.length||chars[end]==' '){
end 每次到单词末尾后的空格或最后一个单词的后面,开始反转单词
reserve(chars,start,end-1);
//start位置为end位置加1比如end为空格位置,start就为空格的后一个字符
start=end+1;
}
}
}
}
剑指 Offer 58 - II. 左旋转字符串
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,该函数将返回左旋转两位得到的结果"cdefgab"。
示例 1:
输入: s = “abcdefg”, k = 2 输出: “cdefgab”
示例 2:
输入: s = “lrloseumgh”, k = 6 输出: “umghlrlose”
示例 1:
class Solution {
/**abcdefg k = 2
1.反转区间为前n的子串ba cdefg
2.反转区间为n到末尾的子串ba gfedc
3.反转整个字符串 cdefgab
*/
public String reverseLeftWords(String s, int n) {
char[] chars=s.toCharArray();
reserve(chars,0,n-1);
reserve(chars,n,chars.length-1);
reserve(chars,0,chars.length-1);
return new String(chars);
}
public void reserve(char[] chars,int left,int right){
while(left<right){
chars[left]^=chars[right];
chars[right]^=chars[left];
chars[left]^=chars[right];
left++;
right--;
}
}
}
leedcode459. 重复的子字符串
给定一个非空的字符串 s ,检查是否可以通过由它的一个子串重复多次构成。
示例 1:
输入: s = “abab” 输出: true 解释: 可由子串 “ab” 重复两次构成。
示例 2:
输入: s = “aba” 输出: false
示例 3:
输入: s = “abcabcabcabc” 输出: true 解释: 可由子串 “abc” 重复四次构成。 (或子串 “abcabc”
重复两次构成。)
方法一:移动匹配
class Solution {
//移动匹配
//判断字符串s是否由重复子串组成,只要两个s拼接在一起,里面还出现一个s的话,就说明是由重复子串组成。
public boolean repeatedSubstringPattern(String s) {
String t=s+s;
//字符串截取substring是左闭右开的原则
//我们在判断 s + s 拼接的字符串里是否出现一个s的的时候,要刨除 s + s 的首字符和尾字符,
//这样避免在s+s中搜索出原来的s,我们要搜索的是中间拼接出来的s
if(t.substring(1,t.length()-1).contains(s)){
return true;
}else{
return false;
}
}
}
方法二:KMP
class Solution {
//kmp算法,因为最长相等前后缀的规则,当一个字符串由重复子串组成的,最长相等前后缀不包含的子串就是最小重复子串
public boolean repeatedSubstringPattern(String s) {
if(s.length()==0){
return false;
}
int[] next=new int[s.length()];
//获取next数组,也就是最长相等前后缀
getNext(next,s);
//如果s.length()%(s.length()-next[s.length()-1])==0,则说明数组的长度正好可以被 (数组长度-最长相等前后缀的长度) 整除,说明该字符串有重复的子字符串。
if(next[s.length()-1]!=0&&s.length()%(s.length()-next[s.length()-1])==0){
return true;
}
return false;
}
public void getNext(int[] next,String s){
//初始化
int j=0;
next[0]=0;
for(int i=1;i<s.length();i++){
while(j>0&&s.charAt(i)!=s.charAt(j)){
//回退
j=next[j-1];
}
if(s.charAt(i)==s.charAt(j)){
j++;
}
next[i]=j;
}
}
}
小明的字符串
小明有两个字符串,分别为 S,TS,T。
请你求出 TT 串的前缀在 SS 串中出现的最长长度为多少。
输入描述
输入包含两行,每行包含一个字符串,分别表示 S,T。保证 S,TS,T 只包含小写字母。
输出描述
输出共 11 行,包含一个整数,表示答案。
输入输出样例
示例 1
输入
aabba
abb
输出
3
示例 2
输入
aabba
aba
输出
2
使用KMP算法求得 TT 串的前缀在 SS 串中出现的最长长度
public class KmpTest {
static int sum=0;
static int[] next=new int[1000000];
public static void main(String[] args) {
Scanner scan = new Scanner(System.in);
String s1 = scan.next();
String s2 = scan.next();
getNext(next,s2);
Kmp(s1,s2);
System.out.println(sum);
}
private static void Kmp(String s1, String s2) {
int j=0;
for(int i=0;i<s1.length();i++){
while(j>0&&s1.charAt(i)!=s2.charAt(j)){
j=next[j-1];
}
if(s1.charAt(i)==s2.charAt(j)){
j++;
}
//当j最长也就是 TT 串在 SS 串中出现的最长长度
sum=Math.max(j,sum);
//当j如果完全满足等于s2的长度时要记得返回,不然i下次循环时比较j会越界
if(j==s2.length()){
return;
}
}
}
//求next数组获取最长相等前后缀
private static void getNext(int[] next, String s2) {
int j=0;
next[0]=0;
for(int i=1;i<s2.length();i++){
while(j>0&&s2.charAt(i)!=s2.charAt(j)){
j=next[j-1];
}
if(s2.charAt(i)==s2.charAt(j)){
j++;
}
next[i]=j;
}
}
}