package java_core.string;
import java.util.HashMap;
import java.util.LinkedList;
import java.util.Queue;
import java.util.Stack;
public class StringTest {
public static void main(String[] args) {
System.out.println(100%0);
// System.out.println("ababab".lastIndexOf("ab"));
// System.out.println("ababab".substring(4));
// System.out.println(isFlipedString("ALLLPP","LLLPPA"));
}
//---------------------------------------------------------------------------------------------------------------
/*680. 验证回文字符串 Ⅱ
给定一个非空字符串 s,最多删除一个字符。判断是否能成为回文字符串。*/
// https://leetcode-cn.com/problems/valid-palindrome-ii/solution/yan-zheng-hui-wen-zi-fu-chuan-ii-by-leetcode-solut/
// ok
private static boolean validPalindrome_680(String s) {
int right = s.length() - 1;
int left = 0;
while (left < right) {
//左指针不等于右指针
if (s.charAt(left) != s.charAt(right)) {
boolean l;
boolean r;
//分别判断删除右边字符或者左边字符后的字符串是不是回文字符串,
// 如果两个都不是,说明不是回文字符串,有一个是,则说明是回文字符串
if (right + 1 > s.length()) {
l = isStr(s.substring(left + 1));
} else {
l = isStr(s.substring(left + 1, right + 1));
}
r = isStr(s.substring(left, right));
return l || r;
} else {
left++;
right--;
}
}
return true;
}
private static boolean isStr(String str) {
int left = 0;
int right = str.length() - 1;
while (left < right) {
if (str.charAt(left++) != str.charAt(right--)) {
return false;
}
}
return true;
}
//ok
private static boolean validPalindrome1_680(String s) {
int low = 0, high = s.length() - 1;
while (low < high) {
char c1 = s.charAt(low), c2 = s.charAt(high);
if (c1 == c2) {
low++;
high--;
} else {
boolean flag1 = true, flag2 = true;
for (int i = low, j = high - 1; i < j; i++, j--) {
char c3 = s.charAt(i), c4 = s.charAt(j);
if (c3 != c4) {
flag1 = false;
break;
}
}
for (int i = low + 1, j = high; i < j; i++, j--) {
char c3 = s.charAt(i), c4 = s.charAt(j);
if (c3 != c4) {
flag2 = false;
break;
}
}
return flag1 || flag2;
}
}
return true;
}
//-----------------------------------------------------------------------------------------------------------------
/**
* 面试题58 - I. 翻转单词顺序 https://leetcode-cn.com/problems/fan-zhuan-dan-ci-shun-xu-lcof/
* 输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。
* 为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. ",
* 则输出"student. a am I"。
*/
// ok
private static String reverseWords_58_I(String s) {
//将多余的空格替换成一个空格
String[] s1 = s.replaceAll(" {2,}", " ").split(" ");
StringBuilder stringBuffer = new StringBuilder();
for (int i = s1.length - 1; i >= 0; i--) {
if (s1[i].equals(" ")) {
continue;
}
stringBuffer.append(s1[i]).append(" ");
}
return stringBuffer.toString().trim();
}
//ok
private String reverseWords2_58_I(String s) {
s = s.trim(); // 删除首尾空格
int j = s.length() - 1, i = j;
StringBuilder res = new StringBuilder();
while (i >= 0) {
while (i >= 0 && s.charAt(i) != ' ') i--; // 搜索首个空格
res.append(s.substring(i + 1, j + 1) + " "); // 添加单词
while (i >= 0 && s.charAt(i) == ' ') i--; // 跳过单词间空格
j = i; // j 指向下个单词的尾字符
}
return res.toString().trim(); // 转化为字符串并返回
}
//ok
private String reverseWords3_58_I(String s) {
String[] strs = s.trim().split(" "); // 删除首尾空格,分割字符串
StringBuilder res = new StringBuilder();
for (int i = strs.length - 1; i >= 0; i--) { // 倒序遍历单词列表
if (strs[i].equals("")) continue; // 遇到空单词则跳过
res.append(strs[i] + " "); // 将单词拼接至 StringBuilder
}
return res.toString().trim(); // 转化为字符串,删除尾部空格,并返回
}
//-----------------------------------------------------------------------------------------------------------------
/*面试题58 - II. 左旋转字符串 https://leetcode-cn.com/problems/zuo-xuan-zhuan-zi-fu-chuan-lcof/
字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。
请定义一个函数实现字符串左旋转操作的功能。比如,输入字符串"abcdefg"和数字2,
该函数将返回左旋转两位得到的结果"cdefgab"。*/
//ok 利用队列,弹出再放入
private static String reverseLeftWords_58_II(String s, int n) {
Queue<Character> characterQueue = new LinkedList<Character>();
for (int i = 0; i < s.length(); i++) {
characterQueue.offer(s.charAt(i));
}
for (int i = 0; i < n; i++) {
Character poll = characterQueue.poll();
characterQueue.offer(poll);
}
StringBuilder stringBuffer = new StringBuilder();
Character c;
while ((c = characterQueue.poll()) != null) {
stringBuffer.append(c);
}
return stringBuffer.toString();
}
//ok
private String reverseLeftWords2_58_II(String s, int n) {
StringBuilder res = new StringBuilder();
for (int i = n; i < s.length(); i++)
res.append(s.charAt(i));
for (int i = 0; i < n; i++)
res.append(s.charAt(i));
return res.toString();
}
//ok
private static String reverseLeftWords3_58_II(String s, int n) {
StringBuilder res = new StringBuilder();
for (int i = n; i < n + s.length(); i++)
res.append(s.charAt(i % s.length()));
return res.toString();
}
//-----------------------------------------------------------------------------------------------------------------
/*20. 有效的括号
给定一个只包括 '(',')','{','}','[',']' 的字符串,判断字符串是否有效。
有效字符串需满足:
左括号必须用相同类型的右括号闭合。
左括号必须以正确的顺序闭合。
注意空字符串可被认为是有效字符串。*/
public boolean isValid_20(String s) {
return false;
}
class Solution {
private HashMap<Character, Character> mappings;
public Solution() {
this.mappings = new HashMap<Character, Character>();
this.mappings.put(')', '(');
this.mappings.put('}', '{');
this.mappings.put(']', '[');
}
public boolean isValid(String s) {
Stack<Character> stack = new Stack<Character>();
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (this.mappings.containsKey(c)) {
char topElement = stack.empty() ? '#' : stack.pop();
if (topElement != this.mappings.get(c)) {
return false;
}
} else {
stack.push(c);
}
}
return stack.isEmpty();
}
}
public boolean isValid2_20(String s) {
char[] charArray = new char[s.length() + 1];
int p = 1;
for (char c : s.toCharArray()) {
if (c == '(' || c == '{' || c == '[') {
charArray[p++] = c;
} else {
p--;
if (c == ')' && charArray[p] != '(') {
return false;
}
if (c == '}' && charArray[p] != '{') {
return false;
}
if (c == ']' && charArray[p] != '[') {
return false;
}
}
}
return p == 1; // 如果左括号还有剩余 括号没有一一对应,属于无效情况
}
//-----------------------------------------------------------------------------------------------------------------
/*125. 验证回文串 https://leetcode-cn.com/problems/valid-palindrome/
给定一个字符串,验证它是否是回文串,只考虑字母和数字字符,可以忽略字母的大小写。
说明:本题中,我们将空字符串定义为有效的回文串。
示例 1:
输入: "A man, a plan, a canal: Panama"
输出: true*/
// ok
private static boolean isPalindrome_125(String s) {
String str = s.toUpperCase();
int left = 0;
int right = str.length() - 1;
while (left < right) {
char cleft = str.charAt(left);
char cright = str.charAt(right);
while (left < right) {
//判断是否是字母或者数字
if (Character.isLetterOrDigit(cleft)) {
break;
} else {
left++;
cleft = str.charAt(left);
}
}
while (left < right) {
//判断是否是字母或者数字
if (Character.isLetterOrDigit(cright)) {
break;
} else {
right--;
cright = str.charAt(right);
}
}
if (!(cleft - cright == 0)) {
return false;
}
right--;
left++;
}
return true;
}
private boolean isPalindrome2_125(String s) {
//为空或长度为1,直接返回true
if ("".equals(s) || s.length() == 1) {
return true;
}
int left = 0;
int right = s.length() - 1;
while (left < right) {
//判断是否是字母或数字
if (!Character.isLetterOrDigit(s.charAt(left))) {
left++;
continue;
}
if (!Character.isLetterOrDigit(s.charAt(right))) {
right--;
continue;
}
//如果相等,直接继续
if (s.charAt(left) == s.charAt(right) ||
//如果不相等,首先判断是否都是字母
//ps:用例中有"0P",当真佩服
Character.isLetter(s.charAt(left)) && Character.isLetter(s.charAt(right)) &&
//ASCII方式判断相等
(s.charAt(left) == s.charAt(right) - 32 || s.charAt(left) - 32 == s.charAt(right))) {
left++;
right--;
} else {
return false;
}
}
return true;
}
private boolean isPalindrome3_125(String s) {
String str = s.toLowerCase();
StringBuilder sb = new StringBuilder();
for (char c : str.toCharArray()) {
if (Character.isLetterOrDigit(c)) sb.append(c);
}
return sb.toString().equals(sb.reverse().toString());
}
//-----------------------------------------------------------------------------------------------------------------
/*551. 学生出勤记录 I
给定一个字符串来代表一个学生的出勤记录,这个记录仅包含以下三个字符:
'A' : Absent,缺勤
'L' : Late,迟到
'P' : Present,到场
如果一个学生的出勤记录中不超过一个'A'(缺勤)并且不超过两个连续的'L'(迟到),那么这个学生会被奖赏。
你需要根据这个学生的出勤记录判断他是否会被奖赏。
示例 1:
输入: "PPALLP"
输出: True*/
//ok
private static boolean checkRecord_551(String s) {
int Acount = 0;
for (int i = 0; i < s.length(); i++) {
if (s.charAt(i) == 'A') {
Acount++;
}
}
return Acount < 2 && !s.contains("LLL");
}
private boolean checkRecord2_551(String s) {
int count = 0;
for (int i = 0; i < s.length(); i++)
if (s.charAt(i) == 'A')
count++;
return count < 2 && s.indexOf("LLL") < 0;
}
private boolean checkRecord3_551(String s) {
int countA = 0;
int countL = 0;
for (int i = 0; i < s.length(); i++) {
char c = s.charAt(i);
if (c == 'P') {
countL = 0;
} else {
if (c == 'A') {
countA++;
if (countA > 1) {
return false;
}
;
countL = 0;
} else if (c == 'L') {
countL++;
if (countL > 2) {
return false;
}
;
}
;
}
;
}
;
return true;
}
//-----------------------------------------------------------------------------------------------------------------
/*面试题 01.03. URL化 https://leetcode-cn.com/problems/string-to-url-lcci/solution/
URL化。编写一种方法,将字符串中的空格全部替换为%20。
假定该字符串尾部有足够的空间存放新增字符,并且知道字符串
的“真实”长度。(注:用Java实现的话,请使用字符数组实现,以便直接在数组上操作。)
示例1:
输入:"Mr John Smith ", 13
输出:"Mr%20John%20Smith"*/
private String replaceSpaces_0103(String S, int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
if (S.charAt(i) == ' ') {
sb.append("%20");
} else {
sb.append(S.charAt(i));
}
}
return sb.toString();
}
private String replaceSpaces2_0103(String S, int length) {
StringBuilder sb = new StringBuilder();
for (int i = 0; i < length; i++) {
if (S.charAt(i) == ' ') {
sb.append("%20");
} else {
sb.append(S.charAt(i));
}
}
return sb.toString();
}
private String replaceSpaces3_0103(String S, int length) {
String s = S.substring(0, length);
return s.replaceAll(" ", "%20");
}
private String replaceSpaces4(String s, int length) {
StringBuilder stringBuilder = new StringBuilder();
for (int i = 0; i < length && i < s.length(); i++) {
;
if (s.charAt(i) == ' ') {
stringBuilder.append("%20");
} else {
stringBuilder.append(s.charAt(i));
}
}
return stringBuilder.toString();
}
//-----------------------------------------------------------------------------------------------------------------
/*面试题 01.09. 字符串轮转 https://leetcode-cn.com/problems/string-rotation-lcci/
字符串轮转。给定两个字符串s1和s2,请编写代码检查s2是否为s1旋转而成(比如,waterbottle是erbottlewat旋转后的字符串)。
示例1:
输入:s1 = "waterbottle", s2 = "erbottlewat"
输出:True*/
//ok 先旋转,再比较
private static boolean isFlipedString_0109(String s1, String s2) {
if (s1.equals(s2)) {
return true;
}
if (s1.length() != s2.length()) {
return false;
}
for (int i = 1; i <= s2.length(); i++) {
if (reverseLeftWords3_58_II(s1, i).equals(s2)) {
return true;
}
}
return false;
}
// 相加再包含!!!
private boolean isFlipedString2_0109(String s1, String s2) {
if (s1.length() != s2.length()) return false;
if (s1.equals(s2)) return true;
s1 += s1;
return s1.contains(s2);
}
private boolean isFlipedString3_0100(String s1, String s2) {
if (s1.length() != s2.length()) return false;
int i = 0;
int j = 0;
int len = 0;
while (i != s1.length() && j != s2.length()) {
if (s1.charAt(i) == s2.charAt(j)) {
i++;
j++;
len++;
} else {
j = 0;
i++;
len = 0;
}
}
if (i == s1.length()) {
int k = 0;
while (j != s2.length()) {
if (s2.charAt(j) == s1.charAt(k)) {
k++;
j++;
len++;
} else {
break;
}
}
return len == s1.length();
}
return false;
}
private boolean isFlipedString4_0109(String s1, String s2) {
return s1.length() == s2.length() && (s1 + s1).contains(s2);
}
}