数组和字符串
数组和字符串 - LeetBook - 力扣(LeetCode)全球极客挚爱的技术成长平台
寻找数组的中心索引
解法1
- 遍历所有下标,对左右元素取和。
- 相等时返回元素下标,否则返回-1。
class Solution {
public int pivotIndex(int[] nums) {
for (int i = 0; i < nums.length; i++) {
int left = 0;
int rigth = 0;
for (int j = 0; j < i; j++) {
left += nums[j];
}
for (int k = i + 1; k < nums.length; k++) {
rigth += nums[k];
}
if (left == rigth) {
return i;
}
}
return -1;
}
}
解法2
- 先对数组求和。
- 遍历所有下标,当左侧求和等于其余元素求和除以2时,返回下标,否则返回-1
class Solution {
public int pivotIndex(int[] nums) {
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
for (int i = 0; i < nums.length; i++) {
if ((sum - nums[i]) % 2 != 0) {
continue;
}
int left = 0;
for (int j = 0; j < i; j++) {
left += nums[j];
}
if (left == (sum - nums[i]) / 2) {
return i;
}
}
return -1;
}
}
解法3
- 先对数组求和sum。
- 遍历数组,sum依次减掉当前元素。
- 判断左侧元素和是否等于sum。
- 左侧元素和加上当前元素,进入下一次循环。
class Solution {
public int pivotIndex(int[] nums) {
int sum = 0;
for (int i = 0; i < nums.length; i++) {
sum += nums[i];
}
int left = 0;
for (int i = 0; i < nums.length; i++) {
sum -= nums[i];
if (left == sum) {
return i;
}
left += nums[i];
}
return -1;
}
}
搜索插入位置
解法1
- 判断如果该数大于数组最后一个数则直接返回数组长度。
- 进行循环,如果该数大于或者等于数组中某个数,返回该数下标
class Solution {
public int searchInsert(int[] nums, int target) {
if (nums[nums.length - 1] < target) {
return nums.length;
}
for (int i = 0; i < nums.length; i++) {
if (nums[i] == target) {
return i;
}
if (nums[i] > target) {
return i;
}
}
return 0;
}
}
合并区间
解法1
- 对intervals里面进行排序(按照第一个数字的大小排序)
- 循环遍历intervals,对于能和后一个区间合并的向后合并,前一个区间置为0
- 再次遍历intervals,将不为0的区间取出,放到一个新数组中
- return新数组即为结果
class Solution {
public int[][] merge(int[][] intervals) {
Arrays.sort(intervals, (a, b) -> a[0] - b[0]);
int count = intervals.length;
for (int i = 0; i < intervals.length - 1; i++) {
if (intervals[i][1] >= intervals[i + 1][0]) {
intervals[i + 1][0] = intervals[i][0];
if (intervals[i][1] > intervals[i+1][1]) {
intervals[i + 1][1] = intervals[i][1];
}
intervals[i][0] = 0;
intervals[i][1] = 0;
count--;
}
}
int[][] result = new int[count][2];
int j = 0;
for (int i = 0; i < intervals.length; i++) {
if (!(intervals[i][0] == 0 && intervals[i][1] == 0)) {
result[j][0] = intervals[i][0];
result[j][1] = intervals[i][1];
j++;
}
}
return result;
}
}
旋转矩阵
解法1
-
如果是顺时针旋转90°
一定是先对角线翻转,再水平翻转
-
如果是逆时针旋转90°
一定是先水平翻转,再对角线翻转
class Solution {
public void rotate(int[][] matrix) {
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix.length - 1 - i; j++) {
int temp = matrix[i][j];
matrix[i][j] = matrix[matrix.length - 1 - j][matrix.length - 1 - i];
matrix[matrix.length - 1 - j][matrix.length - 1 - i] = temp;
}
}
for (int i = 0; i < matrix.length / 2; i++) {
int[] t = matrix[i];
matrix[i] = matrix[matrix.length - 1 - i];
matrix[matrix.length - 1 - i] = t;
}
}
}
零矩阵
解法1
- 遍历矩阵,取出所有0所对应的横坐标和纵坐标。
- 单独遍历取出的横纵坐标数组,对对应的行列置为0
- return
class Solution {
public void setZeroes(int[][] matrix) {
int[] x = new int[matrix.length * matrix[0].length];
int[] y = new int[matrix[0].length * matrix.length];
int count_x = 0;
int count_y = 0;
for (int i = 0; i < matrix.length; i++) {
for (int j = 0; j < matrix[0].length; j++) {
if (matrix[i][j] == 0) {
x[count_x] = i;
y[count_y] = j;
count_y++;
count_x++;
}
}
}
for (int i = 0; i < count_x; i++) {
for (int j = 0; j < matrix[0].length; j++) {
matrix[x[i]][j] = 0;
}
}
for (int i = 0; i < count_y; i++) {
for (int j = 0; j < matrix.length; j++) {
matrix[j][y[i]] = 0;
}
}
}
}
对角线遍历
解法1
-
根据元素坐标横纵坐标和来判断对角线走向
- 如果x+y为偶数:走向为左下到右上
- 如果x+y为奇数:走向为右上到左下
-
根据不同走向分别进行循环
-
左下到右上,行减一,列加一
- 判断越界,y越界行加2,列减1
-
右上到左下,行加一,列减一
- 判断越界,x越界列减1,行加2
-
class Solution {
public int[] findDiagonalOrder(int[][] mat) {
int x = 0;
int y = 0;
int[] result = new int[mat.length * mat[0].length];
int count = 0;
int m = mat.length;
int n = mat[0].length;
for (int i = 0; i < mat.length + mat[0].length - 1; i++) {
if ((x + y) % 2 == 0) {
while (x >= 0 && y < n) {
result[count] = mat[x][y];
count++;
x--;
y++;
}
if (y < n){
x++;
} else {
x++;
x++;
y--;
}
} else {
while (y >= 0 && x < m) {
result[count] = mat[x][y];
count++;
x++;
y--;
}
if (x < m) {
y++;
} else {
y++;
y++;
x--;
}
}
}
return result;
}
}
最长公共前缀
解法1
- 找到字符串最大长度和最小长度
- 将字符串转化为数组
- 遍历数组每一位,当遇到某一位出现不同时跳出
- 返回结果
class Solution {
public String longestCommonPrefix(String[] strs) {
int maxit = 0;
int minit = 999;
for (String ss: strs) {
if (ss.length() > maxit) {
maxit = ss.length();
}
if (ss.length() < minit) {
minit = ss.length();
}
}
char[][] s = new char[strs.length][maxit];
String result = "";
for (int i = 0; i < s.length; i++) {
s[i] = strs[i].toCharArray();
}
boolean flag = true;
for (int i = 0; i < minit; i++) {
for (int j = 0; j < s.length - 1; j++) {
if (s[j][i] != s[j + 1][i]) {
flag = false;
break;
}
}
if (flag == false) {
break;
}
result = result + s[0][i];
}
return result;
}
}
解法2
- 遍历数组,找出长度最小的字符串
- 对找出的字符串进行循环由大到小切割
- 判断切割下来的子串是否为所有字符串的公共前缀
- 若为公共前缀则返回此子串,若循环到最后依然没有匹配,则返回空串
class Solution {
public String longestCommonPrefix(String[] strs) {
String minit = strs[0];
for (int i = 1; i < strs.length; i++) {
if (strs[i].length() < minit.length()) {
minit = strs[i];
}
}
for (int i = 0; i < minit.length(); i++) {
String s = minit.substring(0, minit.length() - i);
int count = 0;
for (int j = 0; j < strs.length; j++) {
if (strs[j].indexOf(s) == 0) {
count++;
}
}
if (count == strs.length) {
return s;
}
}
return "";
}
}
最长回文子串
解法1
- 将字符串转换为数组
- 对数组进行循环,当碰到回文中心时(例如:“bb”,“bab”),以回文中心为基准扩散寻找当前回文中心对应的最大回文序列
- 若寻找到的回文序列比已记录的回文序列长,则记录此回文序列的首尾下标
- 循环结束后返回所记录的首尾下标对应的最长回文序列
class Solution {
public String longestPalindrome(String s) {
char[] str = s.toCharArray();
int startIndex = 0;
int endIndex = 0;
for (int i = 0; i < str.length - 1; i++) {
if (str[i] == (str[i + 1])) {
int start = i;
int end = i + 1;
while (start >= 0 && end < str.length && str[start] == (str[end])) {
start--;
end++;
}
if ((end - start - 2) > (endIndex - startIndex)) {
startIndex = start + 1;
endIndex = end - 1;
}
}
if (i + 2 != str.length && str[i] == (str[i + 2])) {
int start = i;
int end = i + 2;
while (start >= 0 && end < str.length && str[start] == (str[end])) {
start--;
end++;
}
if ((end - start - 2) > (endIndex - startIndex)) {
startIndex = start + 1;
endIndex = end - 1;
}
}
}
String result = "";
for (int i = startIndex; i <= endIndex; i++) {
result = result +str[i];
}
return result;
}
}
解法2
- 优化:
- StringBuilder替换String
class Solution {
public String longestPalindrome(String s) {
char[] ccc = s.toCharArray();
int startIndex = 0;
int endIndex = 0;
for (int i = 0; i < ccc.length - 1; i++) {
if (ccc[i] == ccc[i + 1]) {
int start = i;
int end = i + 1;
while (start >= 0 && end < ccc.length && ccc[start] == ccc[end]) {
start--;
end++;
}
if ((end - start - 2) > (endIndex - startIndex)) {
startIndex = start + 1;
endIndex = end - 1;
}
}
if (i + 2 != ccc.length && ccc[i] == ccc[i + 2]) {
int start = i;
int end = i + 2;
while (start >= 0 && end < ccc.length && ccc[start] == ccc[end]) {
start--;
end++;
}
if ((end - start - 2) > (endIndex - startIndex)) {
startIndex = start + 1;
endIndex = end - 1;
}
}
}
StringBuilder result = new StringBuilder();
for (int i = startIndex; i <= endIndex; i++) {
result.append(ccc[i]);
}
return result.toString();
}
}
翻转字符串里的单词
解法1
- 使用trim去除前后空格
- 使用split分割字符串
- 将不为空的字符串反向组合
- 返回结果
class Solution {
public String reverseWords(String s) {
s = s.trim();
String[] str = s.split(" ");
String result = "";
for (int i = str.length - 1; i >= 0; i--) {
if (!str[i].equals("")){
result = result + str[i] + " ";
}
}
return result.trim();
}
}
解法2
双指针
- 将字符串转换为数组,新建一个新的数组
- 对字符串转换的数组进行逆向循环,当左指针指到空或下标为0,则将单词存到新数组,并存一个空格
- 如果左右指针相同指向空字符,左右指针同时前移
- 如果左右指针均不指向空格,且左指针不指向下标0,则左指针前移
- 用valueOf将数组转字符串,并用trim去除前后空格后返回
class Solution {
public String reverseWords(String s) {
char[] str = s.toCharArray();
char[] news = new char[str.length];
int left = str.length - 1;
int right = str.length - 1;
int count = 0;
for (int i = str.length - 1; i >= 0; i--) {
if (str[i] == ' ') {
if (left == right) {
left--;
right--;
} else {
for (int j = left + 1; j <= right; j++) {
news[count] = str[j];
count++;
}
left--;
right = left;
news[count] = ' ';
count++;
}
} else {
if (i == 0) {
for (int j = left; j <= right; j++) {
news[count] = str[j];
count++;
}
} else {
left--;
}
}
}
return String.valueOf(news).trim();
}
}
实现strStr()
解法1
-
将字符串转化为数组
-
对长数组进行循环,分别于短数组的第一个字母进行比较
-
如果相等,则进行一个长度为短数组长度的循环,比较两个数组的元素是否相等
- 如果循环内没有出现不相等的情况,则return返回下标
- 如果出现不相等则break,进入最外层循环继续进行
-
如果不相等,则继续循环
-
-
如果没循环到的长数组元素个数少于短数组长度,则提前跳出
class Solution {
public int strStr(String haystack, String needle) {
int len1 = haystack.length();
int len2 = needle.length();
char[] s1 = haystack.toCharArray();
char[] s2 = needle.toCharArray();
for (int i = 0; i < len1; i++) {
if (len1 - i < len2) {
break;
}
if (s1[i] == s2[0]) {
boolean flag = true;
for (int j = i; j < i + len2; j++) {
if (s1[j] != s2[j - i]) {
flag = false;
break;
}
}
if (flag) {
return i;
}
}
}
return -1;
}
}
反转字符串
解法1
双指针
- 一个指针指向数组开头,另一个指针指向数组末尾
- 循环交换,当两个指针相遇时结束
class Solution {
public void reverseString(char[] s) {
int i = 0;
int j = s.length - 1;
while ((i !=j ) && (i != j + 1)) {
char temp = s[i];
s[i] = s[j];
s[j] = temp;
i++;
j--;
}
}
}
数组拆分Ⅰ
解法1
- 对数组进行排序
- 去偶数下标的元素求和
class Solution {
public int arrayPairSum(int[] nums) {
Arrays.sort(nums);
int sum = 0;
for (int i = 0; i < nums.length; i++) {
if (i % 2 == 0) {
sum += nums[i];
}
}
return sum;
}
}
两数之和Ⅱ-输入有序数组
解法1
暴力循环
- 遍历整个数组
- 如果两个数相加等于target,返回下标
class Solution {
public int[] twoSum(int[] numbers, int target) {
int[] result = new int[2];
for (int i = 0; i < numbers.length; i++) {
for (int j = i + 1; j < numbers.length; j++) {
if (numbers[i] + numbers[j] == target) {
result[0] = i + 1;
result[1] = j + 1;
return result;
}
}
}
return result;
}
}
解法2
双指针
-
由于数组是从小到大排列的
-
一个指针指向数组头,零一个指针指向数组末尾,进行循环判断,两个指针指向的数的和是否等于target
- 如果相等,则返回下标
- 如果大于target,则后面的指针-1
- 如果小于target,则前面的指针+1
class Solution {
public int[] twoSum(int[] numbers, int target) {
int i = 0;
int j = numbers.length - 1;
int[] result = new int[2];
while (i < j) {
if (numbers[i] + numbers[j] == target) {
result[0] = i + 1;
result[1] = j + 1;
return result;
} else if (numbers[i] + numbers[j] > target) {
j--;
} else {
i++;
}
}
return result;
}
}
移除元素
解法1
双指针(快慢指针)
- 创建两个指针
- 循环为原数组赋值,如果碰到快指针的值等于val,则跳过
- return慢指针的值
class Solution {
public int removeElement(int[] nums, int val) {
int fast;
int slow = 0;
for (fast = 0; fast < nums.length; fast++) {
if (nums[fast] == val) {
continue;
}
nums[slow++] = nums[fast];
}
return slow;
}
}
最大连续1的个数
解法1
暴力循环
- 对数组进行循环,碰到1开启一个新的循环
- 新的循环中碰到0停止,对1的个数计数
- 如果大于目前记录的最大连续1的个属,则替换掉之前的计数
class Solution {
public int findMaxConsecutiveOnes(int[] nums) {
int count = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == 1) {
int number = 0;
while (i + number < nums.length && nums[i + number] == 1) {
number++;
}
if (number > count) {
count = number;
i = i + number;
}
}
}
return count;
}
}
解法2
双指针(快慢指针)
- 快指针对数组进行遍历
- 碰到0或者数组末尾,计算和慢指针之间的距离,如果大于之前记录的最大连续1的个数,则替换,慢指针移到快指针所在位置
class Solution {
public int findMaxConsecutiveOnes(int[] nums) {
int fast;
int slow = 0;
int max = 0;
for (fast = 0; fast < nums.length; fast++) {
if (nums[slow] == 1 && nums[fast] == 0) {
if (fast - slow > max) {
max = fast - slow;
}
slow = fast;
}
if (nums[slow] == 1 && fast == nums.length - 1) {
if (fast - slow + 1 > max) {
max = fast - slow + 1;
}
slow = fast;
}
if (nums[fast] == 1) {
continue;
}
if (nums[fast] == 0 && nums[slow] == 0) {
slow++;
}
}
return max;
}
}
解法3
贪婪算法
-
对数组进行循环
- 如果碰到1,则sum自加
- 如果碰到0,则sum赋值为0
-
每一次循环都判断sum和max的关系,如果sum大于了max,则给max赋值为sum的值
class Solution {
public int findMaxConsecutiveOnes(int[] nums) {
int sum = 0;
int max = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == 1) {
sum++;
} else {
sum = 0;
}
if (sum > max) {
max = sum;
}
}
return max;
}
}
解法4
解法2和解法3综合优化
-
快指针对数组进行循环
- 如果快指针指向1,则自加
- 如果快指针指向0,则判断快慢指针之间距离是否大于记录,如果大于则赋值
-
循环结束后单独判断一次最后的快慢指针距离和记录的关系,如果大于则赋值
class Solution {
public int findMaxConsecutiveOnes(int[] nums) {
int left = 0;
int right = 0;
int result = 0;
while (right < nums.length) {
if (nums[right] == 1) {
right++;
} else {
if (right - left > result) {
result = right - left;
}
right++;
left = right;
}
}
if (right - left > result) {
result = right - left;
}
return result;
}
}
长度最小的子数组
解法1
双指针(快慢指针)
- 快指针遍历数组,sum跟随快指针遍历加每个元素
- 如果sum大于target,则快指针固定,开始向右移动慢指针
- 跟随慢指针的移动sum自减每个元素,当sum小于target时,切换回移动快指针
- 如果快慢指针之间的距离小于min的记录(min初始为一个足够大的数),则更新min
- 最后如果快指针移动到最后,sum也小于target,则跳出循环
- return结果
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int left = 0;
int right;
int min = 9999999;
int sum = 0;
for (right = 0; ;) {
if (right == nums.length && sum < target) {
break;
}
if (sum >= target) {
if (right - left < min) {
min = right - left;
}
sum -= nums[left];
left++;
} else {
sum += nums[right];
right++;
}
}
if (min == 9999999) {
return 0;
}
return min;
}
}
杨辉三角
解法1
- new一个List,每循环一行add一个List
- 单独判断numRows为0、1、2的情况提前返回结果
- 从第三行开始循环(line=2),遇到首尾add(1),其他情况add上一行对应的值和上一行对应的值的前一个值的和
class Solution {
public List<List<Integer>> generate(int numRows) {
List<List<Integer>> result = new ArrayList<>();
if (numRows == 0) {
return result;
}
result.add(new ArrayList<>());
result.get(0).add(1);
if (numRows == 1) {
return result;
}
result.add(new ArrayList<>());
result.get(1).add(1);
result.get(1).add(1);
if (numRows == 2) {
return result;
}
int line = 2;
while (line < numRows) {
result.add(new ArrayList<>());
int count = 0;
while (count <= line) {
if (count == 0 || count == line) {
result.get(line).add(1);
} else {
result.get(line).add(result.get(line - 1).get(count - 1) + result.get(line - 1).get(count));
}
count++;
}
line++;
}
return result;
}
}
杨辉三角Ⅱ
解法1
使用杨辉三角的解法,构建杨辉三角后get出对应行的元素
class Solution {
public List<Integer> getRow(int rowIndex) {
rowIndex++;
List<List<Integer>> result = new ArrayList<>();
result.add(new ArrayList<>());
result.get(0).add(1);
if (rowIndex == 1) {
return result.get(rowIndex - 1);
}
result.add(new ArrayList<>());
result.get(1).add(1);
result.get(1).add(1);
if (rowIndex == 2) {
return result.get(rowIndex - 1);
}
int line = 2;
while (line < rowIndex) {
result.add(new ArrayList<>());
int count = 0;
while (count <= line) {
if (count == 0 || count == line) {
result.get(line).add(1);
} else {
result.get(line).add(result.get(line - 1).get(count - 1) + result.get(line - 1).get(count));
}
count++;
}
line++;
}
return result.get(rowIndex - 1);
}
}
解法2
- 杨辉三角某一行的前半部分每一位的值等于前一位的值乘以行数减去前一位的下标除以当前位下标
- new一个List,单独判断rowIndex=0的情况
- 套用公式添加前半部分的值
- 向前循环取值补齐后半部分的值
- 注意: 使用Integer会有一个例子发生溢出,使用公式时,中间计算转为long进行
class Solution {
public List<Integer> getRow(int rowIndex) {
List<Integer> result = new ArrayList<>();
result.add(1);
if (rowIndex == 0){
return result;
}
for (int i = 1; i <= rowIndex / 2; i++) {
result.add((int)((long)result.get(i - 1) * (long)(rowIndex - (i - 1)) / (long)i));
}
if (rowIndex % 2 == 0) {
for (int i = result.size() - 2; i >= 0; i--) {
result.add(result.get(i));
}
} else {
for (int i = result.size() - 1; i >= 0; i--) {
result.add(result.get(i));
}
}
return result;
}
}
反转字符串中的单词Ⅲ
解法1
和反转字符串中的单词思路基本一致,双指针
- 将字符串转为数组
- 快慢指针,快指针循环数组
- 碰到“ ”空格(或碰到数组末尾),开启一个循环反向取出单词放到一个新数组中,并将慢指针移动到快指针位置
- return新数组
class Solution {
public String reverseWords(String s) {
char[] str = s.toCharArray();
char[] news = new char[str.length];
int left = 0;
int right;
int count = 0;
for (right = 0; right < str.length; ) {
if (str[right] == ' ') {
if (left == right) {
news[count] = ' ';
count++;
left++;
right++;
} else {
for (int j = right - 1; j >= left; j--) {
news[count] = str[j];
count++;
}
left = right;
}
} else {
if (right == str.length - 1) {
for (int j = right; j >= left; j--) {
news[count] = str[j];
count++;
}
right++;
} else {
right++;
}
}
}
return String.valueOf(news);
}
}
寻找旋转排序数组中的最小值
解法1
- 假设数组第一个值为最小值
- 进行一次循环,如果碰到某个值k小于第一个值的,直接返回k
- 否者返回数组第一个值
class Solution {
public int findMin(int[] nums) {
for (int i = 1; i < nums.length; i++) {
if (nums[i] < nums[0]) {
return nums[i];
}
}
return nums[0];
}
}
删除排序数组中的重复项
解法1
双指针(快慢指针)
- 快慢指针初始指向数组第一个元素
- 快指针对数组进行循环
- 如果碰到快慢指针所指向的元素不一致,则慢指针自加1,然后把快指针的值赋给慢指针指向的位置
- 返回慢指针自加1后的整数
class Solution {
public int removeDuplicates(int[] nums) {
int left = 0;
int right;
for (right = 0; right < nums.length; right++) {
if (nums[right] != nums[left]) {
left++;
nums[left] = nums[right];
}
}
return ++left;
}
}
移动零
解法1
双指针(快慢指针)
- 快慢指针初始化均指向0
- 快指针遍历数组
- 如果碰到非0的数则向慢指针所指向的位置赋值,并且慢指针自加
- 遍历完成后,对慢指针指向位置之后的位置赋0
class Solution {
public void moveZeroes(int[] nums) {
int left = 0;
int right;
for (right = 0; right < nums.length; right++) {
if (nums[right] != 0) {
nums[left] = nums[right];
left++;
}
}
for (int i = left; i < nums.length; i++) {
nums[i] = 0;
}
}
}