题目链接:
思路:维护好循环不变量。另外一个点注意别让加和超出int类型的限制,可以变为加差。
解法一:左闭右闭
public int search(int[] nums, int target) {
int left = 0, right = nums.length - 1, mid = 0;
while (left <= right) {
mid = left + ((right - left) >> 1);
if (target > nums[mid]) {
left = mid + 1;
} else if (target < nums[mid]) {
right = mid - 1;
}else {
return mid;
}
}
return -1;
}
解法二:左闭右开
public int search(int[] nums, int target) {
int left = 0, right = nums.length, mid = 0;
while (left < right) {
mid = left + ((right - left) >> 1);
if (target > nums[mid]) {
left = mid + 1;
} else if (target < nums[mid]) {
right = mid;
}else {
return mid;
}
}
return -1;
}
题目链接:
思路:经典二分查找。
public int searchInsert(int[] nums, int target) {
int left = 0, right = nums.length - 1, mid = 0;
while (left <= right) {
mid = left + ((right - left) >> 1);
if (target > nums[mid]) {
left = mid + 1;
} else if (target < nums[mid]) {
right = mid - 1;
} else {
return mid;
}
}
return left;
}
题目链接
思路:分别用二分查找查左边界和右边界,查找区间的左边界,要在mid小于等于target时一直记录从左边逼近边界,而右边不做记录,同理求右边界也是如此。
class Solution {
public int[] searchRange(int[] nums, int target) {
if (nums.length == 0) {
return new int[]{-1, -1};
}
int left = getLeftBorder(nums, target);
int right = getRightBorder(nums, target);
if (left == -2 || right == -2) {
return new int[]{-1, -1};
}
if (right - left > 1) {
return new int[]{left + 1, right - 1};
}
return new int[]{-1, -1};
}
int getLeftBorder(int[] nums, int target) {
int left = 0, right = nums.length - 1, mid = 0, leftBorder = -2;
while (left <= right) {
mid = left + ((right - left) >> 1);
if (target <= nums[mid]) {
right = mid - 1;
leftBorder = right;
}else {
left = mid + 1;
}
}
return leftBorder;
}
int getRightBorder(int[] nums, int target) {
int left = 0, right = nums.length - 1, mid = 0, rightBorder = -2;
while (left <= right) {
mid = left + ((right - left) >> 1);
if (target >= nums[mid]) {
left = mid + 1;
rightBorder = left;
}else {
right = mid - 1;
}
}
return rightBorder;
}
}
题目链接
思路:求平方根有小数的向下取整,这种情况下只要中值计算小于等于mid就一直搜集结果,和上面求边界的思路类似,当然注意防止溢出,要用long
class Solution {
public int mySqrt(int x) {
int left = 0, right = x, result = 0;
while (left <= right) {
int mid = left + ((right - left) >> 1);
if ((long) mid * mid <= x) {
result = mid;
left = mid + 1;
} else {
right = mid - 1;
}
}
return result;
}
}
题目链接
思路:二分查找搜索即可,但是同样注意乘积使用long。
class Solution {
public boolean isPerfectSquare(int num) {
int left = 0, right = num, mid = 0;
while (left <= right) {
mid = left + ((right - left) >> 1);
long temp = (long) mid * mid;
if (temp == num) {
return true;
} else if (num < temp) {
right = mid - 1;
}else {
left = mid + 1;
}
}
return false;
}
}
题目链接
思路:用一个变量k计数,记录相等元素的个数,不等则向前移动k个位置,最后返回数组长度减去k,因为k是要删除的元素。
class Solution {
public int removeElement(int[] nums, int val) {
int k = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] == val) {
k++;
}else {
nums[i-k] = nums[i];
}
}
return nums.length - k;
}
}
双指针解法:一个快指针,一个慢指针,快指针向前遍历,快指针指向的元素不等于target,就将元素赋值给慢指针,慢指针再前进一步,这个思路和上面有一个变量记录要移动的距离类似,有异曲同工之妙。
class Solution {
public int removeElement(int[] nums, int val) {
int slow = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] != val) {
nums[slow++] = nums[i];
}
}
return slow;
}
}
双向指针法:一个关键点维护好循环不变量,然后从左寻找等于target的值(即要被覆盖的值),从右寻找不等于target的值(即要保留的值),找到之后即覆盖一次。
class Solution {
public int removeElement(int[] nums, int val) {
int left = 0, right = nums.length - 1;
while (left <= right) {
while (left <= right && nums[left] != val) {
left++;
}
while (left <= right && nums[right] == val) {
right--;
}
if (left <= right) {
nums[left++] = nums[right--];
}
}
return left;
}
}
题目链接
思路:因为数组是有序的,所以相同的元素都是紧挨着的,只需要比较相邻元素即可,只要当前元素与上一个元素相等就给元素k加1,当不相等时,就要往前移动k个位置,数组的长度即为删除掉K个元素之后的长度。
class Solution {
public int removeDuplicates(int[] nums) {
if (nums.length == 1) return 1;
int k = 0;
for (int i = 1; i < nums.length; i++) {
if (nums[i] == nums[i-1]) {
k++;
}else {
nums[i-k] = nums[i];
}
}
return nums.length - k;
}
}
题目链接
思路:这个移动零和前面删除元素类似,快慢指针然后交换元素即可。
class Solution {
public void moveZeroes(int[] nums) {
int slow = 0;
for (int i = 0; i < nums.length; i++) {
if (nums[i] != 0) {
int temp = nums[slow];
nums[slow++] = nums[i];
nums[i] = temp;
}
}
}
}
题目链接
思路:从前往后要拼接字符串,从后往前就简单了,有#就记录,没有就跳过#数量,数量没了就比较是否相等,不等就返回false
class Solution {
public boolean backspaceCompare(String s, String t) {
int i = s.length() - 1, j = t.length() - 1;
int skipS = 0, skipT = 0;
while (i >= 0 || j >= 0) {
while (i >= 0) {
if (s.charAt(i) == '#') {
skipS++;
i--;
} else if (skipS > 0) {
skipS--;
i--;
}else {
break;
}
}
while (j >= 0) {
if (t.charAt(j) == '#') {
skipT++;
j--;
} else if (skipT > 0) {
skipT--;
j--;
}else {
break;
}
}
if (i >= 0 && j >= 0) {
if (s.charAt(i) != t.charAt(j)) {
return false;
}
} else {
if (i >= 0 || j >= 0) {
return false;
}
}
i--;
j--;
}
return true;
}
}
题目链接
思路:找到正数负数分界线,然后归并算法
class Solution {
public int[] sortedSquares(int[] nums) {
int n = nums.length;
int negative = -1;
for (int i = 0; i < n; ++i) {
if (nums[i] < 0) {
negative = i;
} else {
break;
}
}
int[] ans = new int[n];
int index = 0, i = negative, j = negative + 1;
while (i >= 0 || j < n) {
if (i < 0) {
ans[index] = nums[j] * nums[j];
++j;
} else if (j == n) {
ans[index] = nums[i] * nums[i];
--i;
} else if (nums[i] * nums[i] < nums[j] * nums[j]) {
ans[index] = nums[i] * nums[i];
--i;
} else {
ans[index] = nums[j] * nums[j];
++j;
}
++index;
}
return ans;
}
}