字符串虽然不是一种数据结构,在确是被经常使用的,与之相关的算法诸如字符串转换,计数、反转、压缩等问题是非常常见的
leetcode709
利用大小写字母Ascii码相差32对底层字符数组进行加减实现字符串转换
public String toLowerCase(String s) {
int n = s.length();
char[] chars = s.toCharArray();
for (int i = 0; i < n; i++) {
if (chars[i]>='A'&&chars[i]<='Z'){
chars[i] += 32;
}
}
String str = new String(chars);
return str;
}
leetcode8
按照题目要求,去掉空白字符,设置符号位,转换时,取数字,对原结果✖️10➕当前数字,注意溢出判断
public int myAtoi(String s) {
int n = s.length();
char[] chars = s.toCharArray();
int sign = 1;
int res = 0;
int index = 0;
while (index < n && chars[index] == ' ') {
index++;
}
if (index == n) {
return res;
}
if (chars[index] == '+') {
index++;
}else if (chars[index] == '-') {
sign = -1;
index++;
}
while (index < n) {
if (chars[index] >= '0' && chars[index] <= '9') {
if (res > Integer.MAX_VALUE / 10 || (res == Integer.MAX_VALUE / 10 && (chars[index]-'0') > Integer.MAX_VALUE % 10)) {
return Integer.MAX_VALUE;
}
if (res < Integer.MIN_VALUE / 10 || (res == Integer.MIN_VALUE / 10 && (chars[index]-'0') > -(Integer.MIN_VALUE % 10))) {
return Integer.MIN_VALUE;
}
res = res * 10 + sign * (chars[index] - '0');
index++;
} else {
return res;
}
}
return res;
}
leetcode344
使用双指针,对底层字符数组反转实现字符串的反转
public void reverseString(char[] s) {
int left = 0;
int right = s.length - 1;
while (left < right){
char c = s[left];
s[left] = s[right];
s[right] = c;
left++;
right--;
}
}
leetcode541
与原地反转字符串基本相同,差别在于每次对2*k长度的子串进行操作,反转前K个,注意下标
public String reverseStr(String s, int k) {
char[] chars = s.toCharArray();
int length = s.length();
for (int i = 0; i <= length; i+=2*k) {
int left = i;
int right = left + k-1;
right = Math.min(right,length-1);
swap(chars,left,right);
}
return new String(chars);
}
public void swap(char[] chars,int left,int right){
while (left < right) {
char c = chars[left];
chars[left] = chars[right];
chars[right] = c;
left++;
right--;
}
}
leetcode917
使用双指针,分别从左到右和从右到左寻找英文字母,找到后进行交换,直至两指针重合
public String reverseOnlyLetters(String s) {
int left = 0;
int right = s.length()-1;
char[] chars = s.toCharArray();
while (left < right) {
while (left < right&&!isEnglishChar(chars[left])){
left++;
}
while (left < right&&!isEnglishChar(chars[right])){
right--;
}
if (left < right){
char c = chars[left];
chars[left] = chars[right];
chars[right] = c;
left++;
right--;
}
}
return new String(chars);
}
public boolean isEnglishChar(char c){
if((c>='a'&&c<='z')||(c>='A'&&c<='Z')){
return true;
}else {
return false;
}
}
leetcode151
首先对字符串进行反转,然后去掉字符串首尾多余空格,最后去掉单词之间的空格并反转单词
public String reverseWords(String s) {
char[] chars = s.toCharArray();
int len = s.length();
reverse(chars, 0, len - 1);
StringBuilder sb = new StringBuilder();
int start = 0;
while (start < len && chars[start] == ' ') {
start++;
}
int end = len - 1;
while (end > 0 && chars[end] == ' ') {
end--;
}
int index = start;
while (index <= end) {
if (chars[index] != ' ') {
sb.append(chars[index]);
} else if (chars[index] == ' ' && chars[index - 1] != ' ') {
sb.append(chars[index]);
}
index++;
}
s = sb.toString();
chars = s.toCharArray();
start = 0;
index = 0;
while (index < chars.length) {
if (chars[index] != ' ') {
index++;
} else {
reverse(chars, start, index - 1);
index++;
start = index;
}
}
reverse(chars,start,index-1);
return new String(chars);
}
public void reverse(char[] chars, int left, int right) {
while (left < right) {
char c = chars[left];
chars[left] = chars[right];
chars[right] = c;
left++;
right--;
}
}
leetcode125
首先将大写字符转换为小写字符,然后使用双指针进行判断
public boolean isPalindrome(String s) {
StringBuilder sb = new StringBuilder();
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length; i++) {
if (chars[i] >= 'A' && chars[i] <= 'Z') {
chars[i] += 32;
sb.append(chars[i]);
} else if (chars[i] >= 'a' && chars[i] <= 'z') {
sb.append(chars[i]);
} else if (chars[i] >= '0' && chars[i] <= '9') {
sb.append(chars[i]);
}
}
s = sb.toString();
chars = s.toCharArray();
int left = 0;
int right = chars.length - 1;
while (left < right) {
if (chars[left]!=chars[right]){
return false;
}
left++;
right--;
}
return true;
}
leetcode387
使用HashMap存储每个字符出现的次数,之后遍历字符数组,寻找第一个唯一字符
public int firstUniqChar(String s) {
Map<Character,Integer> map = new HashMap<>();
char[] chars = s.toCharArray();
for (int i = 0; i < chars.length;i++){
if (!map.containsKey(chars[i])){
map.put(chars[i],1);
}else {
map.put(chars[i],map.get(chars[i])+1);
}
}
for (int i = 0; i < chars.length;i++){
if (map.get(chars[i])==1){
return i;
}
}
return -1;
}
leetcode242
设置一个长度为26的数组用来计数字符串中26个字符出现的次数,遍历第一个字符串时,对遍历到的每一字符对应的下标加一,遍历第二个字符串时,对遍历到的每一字符对应的下标减一,最后判断整个数组是否全为0
public boolean isAnagram(String s, String t) {
if(s.length()!=t.length()){
return false;
}
int[] res = new int[26];
char[] chars = s.toCharArray();
for (char c : chars){
res[c-'a']++;
}
chars = t.toCharArray();
for (char c : chars){
res[c-'a']--;
}
for (int i=0;i<res.length;i++){
if(res[i]!=0){
return false;
}
}
return true;
}
leetcode14
直观上来看,有竖直和水平两种方式,竖直方式是指我们依次比较所有字符串的第一个字符,如果相同,继续比较所有字符串的下一个字符,直至不相同或者有一个字符串遍历结束。水平方式是指可以先比较前两个字符的最长公共前缀,然后在比较前两个字符的最长公共前缀,与第三个字符的公共前缀,以此类推。同时,采用水平方式时,我们可以使用归并的方式,两两一组找最长公共前缀,然后再进行归并。
public String longestCommonPrefix(String[] strs) {
StringBuilder sb = new StringBuilder();
int len = strs.length;
int n = strs[0].length();
for (int i = 0; i < n; i++) {
char c = strs[0].charAt(i);
for (int j = 1; j < len; j++) {
if (i >= strs[j].length() || strs[j].charAt(i) != c){
return sb.toString();
}
}
sb.append(c);
}
return sb.toString();
}
public String longestCommonPrefix(String[] strs) {
int len = strs.length;
if (len == 1) {
return strs[0];
}
String prefix = longestCommonPrefix(strs[0], strs[1]);
for (int i = 2; i < len; i++) {
prefix = longestCommonPrefix(prefix, strs[i]);
}
return prefix;
}
public String longestCommonPrefix(String str1, String str2) {
StringBuilder sb = new StringBuilder();
int i = 0;
int j = 0;
while (i < str1.length() && j < str2.length()) {
if(str1.charAt(i) == str2.charAt(j)){
sb.append(str1.charAt(i));
i++;
j++;
}else {
return sb.toString();
}
}
return sb.toString();
}
leetcode443
可以设置两个指针,用于寻找重复字符的起始和结束位置,同时在设置一个指针,用于设置写入位置,遍历字符数组,但个字符直接追加,重复字符,写入当前字符和出现次数,对于两位以上的出现次数,可以先逆序写入,然后再反转
public int compress(char[] chars) {
int left = 0;
int right = 0;
int write = 0;
while (right < chars.length) {
while (right < chars.length && chars[right] == chars[left]) {
right++;
}
if (right - left == 1) {
chars[write++] = chars[left];
left = right;
} else {
int count = right - left;
chars[write++] = chars[left];
int start = write;
while (count != 0) {
int num = count % 10;
chars[write++] = (char) ('0' + num);
count/=10;
}
reverse(chars, start, write - 1);
left = right;
}
}
return write;
}
public void reverse(char[] chars, int left, int right) {
while (left < right) {
char temp = chars[left];
chars[left] = chars[right];
chars[right] = temp;
left++;
right--;
}
}