数组是存放在连续内存空间上的相同类型数据的集合。
/**
* 二分查找 leetcode704
*/
public int search(int[] nums, int target) {
if(target < nums[0] || target > nums[nums.length-1]){
return -1;
}
int left = 0;
int right = nums.length-1;
int middle = 0;
while (left <= right){
middle = (left + right)/2;
if(target == nums[middle]){
return middle;
}else if(target < nums[middle]){
right = middle-1;
}else {
left = middle+1;
}
}
return -1;
}
public int searchInsert(int[] nums, int target) {
if(target < nums[0] ){
return 0;
}
if(target > nums[nums.length-1]){
return nums.length;
}
int left = 0;
int right = nums.length-1;
int middle = 0;
while (left <= right){
middle = (left + right)/2;
if(target == nums[middle]){
return middle;
}else if(target < nums[middle]){
right = middle-1;
}else {
left = middle+1;
}
}
/* for (int i = 0; i < nums.length; i++) {
if(target > nums[i] && target < nums[i+1]){
return i+1;
}
}
return -1;*/
return left; //这里可以用奇数或者偶数个序列试一下,可以发现查找不到的时候就是返回left
}
由于是非递减的顺序,可以考虑二分法。
在第一次找到target时,向左右探测。
在左边和右边分别执行二分法找到target后返回下标。
public int[] searchRange(int[] nums, int target) {
int[] arr = {-1, -1};
arr[0] = search2(nums, target, 0); //左边
arr[1] = search2(nums, target, 1); //右边
return arr;
}
public int search2(int[] nums, int target, int flag) {
if (nums.length == 0 || target < nums[0] || target > nums[nums.length - 1]) {
return -1;
}
int left = 0;
int right = nums.length - 1;
int middle = 0;
int ret = -1;
while (left <= right) {
middle = (left + right) / 2;
if (target == nums[middle]) {
ret = middle;
if (flag == 1) { //探测左边
right = middle - 1;
} else { //探测右边
left = middle + 1;
}
} else if (target < nums[middle]) {
right = middle - 1;
} else {
left = middle + 1;
}
}
return ret;
}
/**
* 69题 求平方根
*
* @param x
* @return
*/
public int mySqrt(int x) {
if (x == 0) {
return 0;
}
if (x == 1) {
return 1;
}
int l = 0;
int r = x;
int middle = 0;
while (l <= r) {
middle = (l + r) / 2;
if (x / middle < middle) { //用乘法会溢出
r = middle-1;
} else if(x / middle > middle){
l = middle+1;
}else{
return middle;
}
}
return r; //跳出循环后 l>r 将值小的返回
}
public boolean isPerfectSquare(int num) {
if (num == 0 || num == 1) {
return true;
}
int l = 0;
int r = num;
while (l <= r) {
int m = (l + r) / 2;
long square = (long) m *m;
if (square == num) {
return true;
} else if (square <num) {
l = m + 1;
} else {
r = m - 1;
}
}
return false;
}
/**
* leetcode 27题
* @param nums
* @param val
* @return
*/
public int removeElement(int[] nums, int val) {
// int j = 0;
// for (int i = 0; i < nums.length; i++) {
// if(nums[i] == val){
// j++;
// }else{
// nums[i-j] = nums[i];
// }
// }
// return nums.length-j;
int j = 0;
for (int i = 0; i < nums.length; i++) {
if(nums[i] != val){
nums[j++] = nums[i];
}
}
return j;
}
/**
* leetcode-26.删除排序数组中的重复项
* @param nums
* @return
*/
public int removeDuplicates(int[] nums) {
int j = 0;
int len = nums.length;
for (int i = 0; i < len+-1; i++) {
if(nums[i] == nums[i+1]){
j++;
}else{
nums[i+1-j] = nums[i+1];
}
}
// for (int i = 0; i < nums.length; i++) {
// System.out.printf("%d",nums[i]);
// }
return len-j;
}
/**
* leetcode-283 移动零
* @param nums
*/
public void moveZeroes(int[] nums) {
int j = 0;
for (int i = 0; i < nums.length; i++) {
if(nums[i] != 0){
//非零元素与零元素交换
int temp = nums[j];
nums[j++] = nums[i];
nums[i] = temp;
}
}
for (int n : nums) {
System.out.println(n);
}
}
⭐️
/**
* 844. 比较含退格的字符串
*
* @param s
* @param t
* @return
*/
public boolean backspaceCompare(String s, String t) {
return convert(s).equals(convert(t));
}
public String convert(String s) {
int skip = 0;
StringBuilder sb = new StringBuilder();
char[] arrayStr = s.toCharArray();
for (int i = arrayStr.length-1; i >= 0; i--) { //倒序遍历
if(arrayStr[i] == '#'){
skip++;
}else if(skip==0){
sb.append(arrayStr[i]);
}else{
skip--;
}
}
return sb.toString();
}
/**
* leetcode-977
* @param nums
* @return
*/
public int[] sortedSquares(int[] nums) {
int len = nums.length;
int negative = 0; //负数的最后一个下标
for (int i = 0; i < len; i++) {
if(nums[i] < 0){
negative = i;
}else {
break;
}
}
int[] ans = new int[len];
int i= negative;int j=negative+1;
int index = 0;
//负数平方后会变成一个递减序列 而正数是递增序列 将这两个序列用归并排序的方法放入ans
while (i >=0 && j< len){
if(nums[i]*nums[i] <= nums[j]*nums[j]){
ans[index++] = nums[i]*nums[i];
i--;
}else {
ans[index++] = nums[j]*nums[j];
j++;
}
}
while (i >= 0){
ans[index++] = nums[i]*nums[i];
i--;
}
while (j < len){
ans[index++] = nums[j]*nums[j];
j++;
}
return ans;
}
用滑动窗口的方式解决。
在找到一个满足大于等于target的集合后,起始位置往后移动(即缩小窗口大小),减去缩小部分的值,若依然满足条件则继续往后移动,否则跳出循环,终止位置往后移动。
/**
* 长度最小的子数组 leetcode-209
* @param target
* @param nums
* @return
*/
public int minSubArrayLen(int target, int[] nums) {
int j = 0;
int sum = 0;
int minLen = Integer.MAX_VALUE;
//快指针走到数组末尾后就可以停止 因为找的是最小
for (int i = 0; i < nums.length; i++) {
sum+=nums[i];
while (sum >= target){
minLen = Math.min(minLen,i-j+1);
sum-=nums[j++]; //起始位置往后移
}
}
return minLen == Integer.MAX_VALUE ? 0 : minLen;
}
方法2:
public String minWindow3(String s, String t) {
if (s == null || s.length() == 0 || t == null || t.length() == 0) {
return "";
}
int minLen = Integer.MAX_VALUE;
int begin = 0; //保存起始位置
int left = 0, right = 0, valid = 0;
int[] needs = new int[26];
int[] window = new int[26];
for (char c : t.toCharArray()) {
needs[c - 'a']++;
}
int count = 0; //needs数组中非零值的个数 例如t="aa",则needs实际大小为1
for (int i = 0; i < needs.length; i++) {
if (needs[i] != 0) count++;
}
while (right < s.length()) {
char c = s.charAt(right);
right++;
if (needs[c - 'a'] != 0) {//窗口中只统计t中的字母
window[c - 'a']++;
if (window[c - 'a'] == needs[c - 'a'])
valid++;
}
while (valid == count) {
if (right - left < minLen) {
minLen = right - left;
begin = left; //记录起始位置和最小长度
}
//缩小窗口,优化
char d = s.charAt(left);
left++;
if (needs[d - 'a'] != 0) {
if (window[d - 'a'] == needs[d - 'a']) {
valid--;
}
window[d - 'a']--;
}
}
}
return minLen == Integer.MAX_VALUE ? "" : s.substring(begin, begin + minLen);
}
/**
* 904. 水果成篮
*
* @param fruits
* @return
*/
public int totalFruit(int[] fruits) {
Map<Integer, Integer> map = new HashMap<>();
int ans = 0;
for (int i = 0, j = 0; i < fruits.length; i++) {
int x = fruits[i];
map.put(x, map.getOrDefault(x, 0) + 1); //获取key为x的value值,若存在则加1
// 否则将新元素初始为1
while (map.size() > 2) {
int y = fruits[j++];
map.put(y, map.get(y) - 1);
if (map.get(y) == 0) {
map.remove(y);
}
}
ans = Math.max(ans, i - j + 1);
}
return ans;
}
也可以这样写:https://leetcode.cn/problems/fruit-into-baskets/solutions/1897490/by-ac_oier-skgk/
public int totalFruit(int[] fs) {
int n = fs.length, ans = 0;
int[] cnts = new int[n + 10];
for (int i = 0, j = 0, tot = 0; i < n; i++) {
if (++cnts[fs[i]] == 1) tot++;
while (tot > 2) {
if (--cnts[fs[j++]] == 0) tot--;
}
ans = Math.max(ans, i - j + 1);
}
return ans;
}
public String minWindow(String s, String t) {
if (s == null || s.length() == 0 || t == null || t.length() == 0){
return "";
}
//先找到一个满足条件的序列
int min = Integer.MAX_VALUE;
int[] freqT = new int[128]; //统计t中各字符的数量
int cnt = t.length(); //t序列的字符数量
int begin = 0; //起始位置
for (char c : t.toCharArray()) {
freqT[c]++;
}
int l = 0, len = s.length(),r=0;
while (r < len){
char cR = s.charAt(r);
if(freqT[cR] > 0){ //需要字符cR
cnt--;
}
freqT[cR]--;
//已找到满足条件的序列 缩小序列长度 找到最优
if(cnt == 0){
while (freqT[s.charAt(l)] < 0){
freqT[s.charAt(l)]++;
l++;
}
if(r-l+1 < min){ //找到窗口最小值 记录下起始位置
min = r-l+1;
begin = l;
}
//l再增加一个位置,寻找下一个能满足条件的位置
freqT[s.charAt(l)]++; //左边界右移之前需要释放s.charAt(l)
l++;
cnt++;
}
r++;
}
return min == Integer.MAX_VALUE ? "" : s.substring(begin,begin+min);
}
//稍简化
public String minWindow(String s, String t) {
int len = s.length();
int lenT = t.length();
if (len == 0 || lenT == 0) {
return "";
}
int[] needMap = new int[128]; //映射,大小写都有 大小定义为128
for (int i = 0; i < lenT; i++) {
needMap[t.charAt(i)]++;
}
int minLen = len + 1; //最小的长度设置为一个不可能到达的大的数
int left = 0, right = 0; //滑动窗口的左右边界
int count = lenT; //真正需求的字符个数
int startIdx = -1;
while (right < len) { //减去表示进入窗口 加上表示离开窗口
char c = s.charAt(right);
if (needMap[c] > 0) { //证明该字符是t中需要的
count--;
}
needMap[c]--;//加入窗口
if (count == 0) { //找到一个可行解
//优化可行解 找到更短的 例如 AABC 中优化为 ABC
while (needMap[s.charAt(left)] < 0) { //排除多余元素
needMap[s.charAt(left)]++;
left++; //窗口缩小 此时left应该停留在第二个A的位置
}
if (right - left + 1 < minLen) { //找到了更短的长度
minLen = right - left + 1;
startIdx = left; //记录下取得最短时的起始下标 返回结果时用到
}
//让left再增加一个位置,开始寻找下一个满足条件的滑动窗口,空间要放出来
needMap[s.charAt(left)]++;
left++;
count++;
}
right++;
}
return minLen == len + 1 ? "" : s.substring(startIdx, startIdx + minLen);
}
/**
* 螺旋矩阵 II leetcode-59
* @param n
* @return
*/
public int[][] generateMatrix(int n) {
int start = 0,end = n-1;
int cnt = 1;
int[][] ans = new int[n][n];
int loop = n / 2;
while (loop > 0){
//从左至右
for (int i = start; i <= end; i++) {
ans[start][i] = cnt++;
}
//从上至下
for (int i = start+1; i <= end ; i++) {
ans[i][end] = cnt++;
}
//从右至左
for (int i = end-1; i >= start ; i--) {
ans[end][i] = cnt++;
}
//从下至上
for (int i = end-1; i >= start+1 ; i--) {
ans[i][start] = cnt++;
}
start++;end--;
loop--;
}
if(n%2 != 0){
ans[n/2][n/2] = cnt;
}
return ans;
}
/**
* 螺旋矩阵 leetcode-54
* @param matrix
* @return
*/
public List<Integer> spiralOrder(int[][] matrix) {
List<Integer> ans = new ArrayList<>();
int column = matrix[0].length; //列数
int row = matrix.length; //行数
int loop = column*row;
int start = 0,endY = column-1,endX = row-1;
while (loop > 0){
//从左至右
for (int i = start; i <= endY; i++) {
ans.add(matrix[start][i]);
loop--;
}
if(loop == 0) break;
//从上至下
for (int i = start+1; i <= endX ; i++) {
ans.add(matrix[i][endY]);
loop--;
}
if(loop == 0) break;
//从右至左
for (int i = endY-1; i >= start ; i--) {
ans.add(matrix[endX][i]);
loop--;
}
if(loop == 0) break;
//从下至上
for (int i = endX-1; i >=start+1 ; i--) {
ans.add(matrix[i][start]);
loop--;
}
if(loop == 0) break;
start++;
endX--;endY--;
}
return ans;
}