左闭右闭区间:[left,right] —>即可以取到left == right 所以循环写成while(left<=right).
左闭右开区间:[left,right) —>即不可以取到left == right 所以循环写成while(left其实只要把握了能不能取到的问题,写代码时就不会乱了。
为了防止溢出要写成mid = left + (right-left)/2 或则 mid = left + ((right - left) >> 1);
边界的取值完全是由区间来决定的,把握好区间也就把握好了边界取值
给定一个 n 个元素有序的(升序)整型数组 nums 和一个目标值 target ,写一个函数搜索 nums 中的 target,如果目标值存在返回下标,否则返回 -1。
你可以假设 nums 中的所有元素是不重复的。
n 将在 [1, 10000]之间。
nums 的每个元素都将在 [-9999, 9999]之间。
class Solution {
public int search(int[] nums, int target) {
int l = 0;
int r = nums.length-1;
while(l<=r){//左闭右闭
int mid = l+(r-l)/2;
if(target == nums[mid]){
return mid;
}else if(target<nums[mid]){
r = mid-1;
}else{
l =mid+1;
}
}
return -1;
}
}
class Solution {
public int search(int[] nums, int target) {
int l = 0;
int r = nums.length;
while(l<r){//左闭右开
int mid = l+(r-l)/2;
if(target == nums[mid]){
return mid;
}else if(target<nums[mid]){
r = mid;
}else{
l =mid+1;
}
}
return -1;
}
}
给定一个排序数组和一个目标值,在数组中找到目标值,并返回其索引。如果目标值不存在于数组中,返回它将会被按顺序插入的位置。
请必须使用时间复杂度为 O(log n) 的算法。
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums 为无重复元素的升序排列数组
-104 <= target <= 104
class Solution {
public int searchInsert(int[] nums, int target) {
int n = nums.length;
int left = 0, right = n - 1, ans = n;
while (left <= right) {//左闭右闭
int mid = ((right - left) >> 1) + left;
if (target <= nums[mid]) {
ans = mid;
right = mid - 1;
} else {
left = mid + 1;
}
}
return ans;
}
}
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0;
int right = nums.length-1;
while(left<=right){//左闭右闭
int mid = left+(right-left)/2;
if(target<=nums[mid]){//找第一个满足条件的
right = mid-1;
}else{
left = mid+1;
}
}
return left;
}
}
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0;
int right = nums.length;
int ans = nums.length;
while(left<right){//左闭右开
int mid = left+(right-left)/2;
if(target<=nums[mid]){
right = mid;
ans = mid;
}else{
left = mid+1;
}
}
return ans;
}
}
class Solution {
public int searchInsert(int[] nums, int target) {
int left = 0;
int right = nums.length;
while(left<right){//左闭右开
int mid = left+(right-left)/2;
if(target<=nums[mid]){
right = mid;
}else{
left = mid+1;
}
}
return right;
}
}
给定一个按照升序排列的整数数组 nums,和一个目标值 target。找出给定目标值在数组中的开始位置和结束位置。
如果数组中不存在目标值 target,返回 [-1, -1]。
进阶:
你可以设计并实现时间复杂度为 O(log n) 的算法解决此问题吗?
0 <= nums.length <= 105
-109 <= nums[i] <= 109
nums 是一个非递减数组
-109 <= target <= 109
class Solution {
public int[] searchRange(int[] nums, int target) {
int leftIdx = binarySearch(nums, target, true);
int rightIdx = binarySearch(nums, target, false) - 1;
if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) {
return new int[]{leftIdx, rightIdx};
}
return new int[]{-1, -1};
}
public int binarySearch(int[] nums, int target, boolean lower) {
int left = 0, right = nums.length - 1, ans = nums.length;
while (left <= right) {//左闭右闭
int mid = (left + right) / 2;
if (nums[mid] > target || (lower && nums[mid] >= target)) {
right = mid - 1;
ans = mid;
} else {
left = mid + 1;
}
}
return ans;
}
}
class Solution {
public int[] searchRange(int[] nums, int target) {
int leftIdx = binarySearch(nums, target, true);
int rightIdx = binarySearch(nums, target, false) - 1;
if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) {
return new int[]{leftIdx, rightIdx};
}
return new int[]{-1, -1};
}
public int binarySearch(int[] nums, int target, boolean lower) {
int left = 0, right = nums.length - 1;
while (left <= right) {//左闭右闭
int mid = (left + right) / 2;
if (nums[mid] > target || (lower && nums[mid] >= target)) {
right = mid - 1;
} else {
left = mid + 1;
}
}
return left;
}
}
class Solution {
public int[] searchRange(int[] nums, int target) {
int leftIdx = binarySearch(nums, target, true);
int rightIdx = binarySearch(nums, target, false) - 1;
if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) {
return new int[]{leftIdx, rightIdx};
}
return new int[]{-1, -1};
}
public int binarySearch(int[] nums, int target, boolean lower) {
int left = 0, right = nums.length,ans = nums.length;
while (left < right) {//左闭右开
int mid = (left + right) / 2;
if (nums[mid] > target || (lower && nums[mid] >= target)) {
right = mid;
ans = mid;
} else {
left = mid + 1;
}
}
return ans;
}
}
class Solution {
public int[] searchRange(int[] nums, int target) {
int leftIdx = binarySearch(nums, target, true);
int rightIdx = binarySearch(nums, target, false) - 1;
if (leftIdx <= rightIdx && rightIdx < nums.length && nums[leftIdx] == target && nums[rightIdx] == target) {
return new int[]{leftIdx, rightIdx};
}
return new int[]{-1, -1};
}
public int binarySearch(int[] nums, int target, boolean lower) {
int left = 0, right = nums.length;
while (left < right) {//左闭右开
int mid = (left + right) / 2;
if (nums[mid] > target || (lower && nums[mid] >= target)) {
right = mid;
} else {
left = mid + 1;
}
}
return right;
}
}
给你一个非负整数 x ,计算并返回 x 的 算术平方根 。
由于返回类型是整数,结果只保留 整数部分 ,小数部分将被 舍去 。
注意:不允许使用任何内置指数函数和算符,例如 pow(x, 0.5) 或者 x ** 0.5 。
0 <= x <= 231 - 1
class Solution {
public int mySqrt(int x) {
int l=0;
int r=x;
int ans = x;
while(l<=r){
int mid = l+(r-l)/2;
if((long)mid*mid <= x){//找最后一个满足条件的
ans = mid;
l= mid+1;
}else{
r=mid-1;
}
}
return ans;
}
}
class Solution {
public int mySqrt(int x) {
int l=0;
int r=x;
while(l<=r){
int mid = l+(r-l)/2;
if((long)mid*mid <= x){
l= mid+1;
}else{
r=mid-1;
}
}
return r;
}
}
给定一个 正整数 num ,编写一个函数,如果 num 是一个完全平方数,则返回 true ,否则返回 false 。
进阶:不要 使用任何内置的库函数,如 sqrt 。
1 <= num <= 2^31 - 1
class Solution {
public boolean isPerfectSquare(int num) {
long l = 0;
long r = num;
while(l<=r){
long mid = l+(r-l)/2;
if(mid*mid == num){
return true;
}else if(mid*mid > num){
r = mid - 1;
}else{
l = mid + 1;
}
}
return false;
}
}
class Solution {
public boolean isPerfectSquare(int num) {
long l = 0;
long r = num+1;
while(l<r){
long mid = l+(r-l)/2;
if(mid*mid == num){
return true;
}else if(mid*mid > num){
r = mid;
}else{
l = mid + 1;
}
}
return false;
}
}
给你一个数组 nums 和一个值 val,你需要 原地 移除所有数值等于 val 的元素,并返回移除后数组的新长度。
不要使用额外的数组空间,你必须仅使用 O(1) 额外空间并 原地 修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。
0 <= nums.length <= 100
0 <= nums[i] <= 50
0 <= val <= 100
class Solution {
public int removeElement(int[] nums, int val) {
int l = 0;
for(int r =0;r<nums.length;++r){
if(nums[r] != val){
nums[l++] = nums[r];
}
}
return l;
}
}
class Solution {
public int removeElement(int[] nums, int val) {
int l = 0;
int r = 0;
while(r<nums.length){
if(nums[r] != val){
nums[l++] = nums[r];
}
r++;
}
return l;
}
}
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。
0 <= nums.length <= 3 * 104
-104 <= nums[i] <= 104
nums 已按升序排列
class Solution {
public int removeDuplicates(int[] nums) {
if(nums.length == 0){
return 0;
}
int left= 1;
int right = 1;
while(right<nums.length){
if(nums[right]!=nums[right-1]){
nums[left++]=nums[right];
}
right++;
}
return left;
}
}
给定一个数组 nums,编写一个函数将所有 0 移动到数组的末尾,同时保持非零元素的相对顺序。
必须在原数组上操作,不能拷贝额外的数组。
尽量减少操作次数。
class Solution {
public void moveZeroes(int[] nums) {
int n = nums.length, left = 0, right = 0;
while (right < n) {
if (nums[right] != 0) {
swap(nums, left, right);
left++;
}
right++;
}
}
public void swap(int[] nums, int left, int right) {
int temp = nums[left];
nums[left] = nums[right];
nums[right] = temp;
}
}
给定 s 和 t 两个字符串,当它们分别被输入到空白的文本编辑器后,请你判断二者是否相等。# 代表退格字符。
如果相等,返回 true ;否则,返回 false 。
注意:如果对空文本输入退格字符,文本继续为空。
1 <= s.length, t.length <= 200
s 和 t 只含有小写字母以及字符 ‘#’
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;
}
}
给你一个按 非递减顺序 排序的整数数组 nums,返回 每个数字的平方 组成的新数组,要求也按 非递减顺序 排序。
1 <= nums.length <= 104
-104 <= nums[i] <= 104
nums 已按 非递减顺序 排序
class Solution {
public int[] sortedSquares(int[] nums) {
int left = 0;
int right = nums.length-1;
int[] ans = new int[nums.length];
int index = nums.length-1;
while(left<=right){
if(nums[left]*nums[left] <= nums[right]*nums[right]){
ans[index--] = nums[right]*nums[right];
--right;
}else{
ans[index--] = nums[left]*nums[left];
++left;
}
}
return ans;
}
}
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
注意:答案中不可以包含重复的三元组
0 <= nums.length <= 3000
-105 <= nums[i] <= 105
class Solution {
public List<List<Integer>> threeSum(int[] nums) {
int n = nums.length;
Arrays.sort(nums);
List<List<Integer>> ans = new ArrayList<List<Integer>>();
// 枚举 a
for (int first = 0; first < n; ++first) {
// 需要和上一次枚举的数不相同
if (first > 0 && nums[first] == nums[first - 1]) {
continue;
}
// c 对应的指针初始指向数组的最右端
int third = n - 1;
int target = -nums[first];
// 枚举 b
for (int second = first + 1; second < n; ++second) {
// 需要和上一次枚举的数不相同
if (second > first + 1 && nums[second] == nums[second - 1]) {
continue;
}
// 需要保证 b 的指针在 c 的指针的左侧
while (second < third && nums[second] + nums[third] > target) {
--third;
}
// 如果指针重合,随着 b 后续的增加
// 就不会有满足 a+b+c=0 并且 b
if (second == third) {
break;
}
if (nums[second] + nums[third] == target) {
List<Integer> list = new ArrayList<Integer>();
list.add(nums[first]);
list.add(nums[second]);
list.add(nums[third]);
ans.add(list);
}
}
}
return ans;
}
}
给你一个由 n 个整数组成的数组 nums ,和一个目标值 target 。请你找出并返回满足下述全部条件且不重复的四元组 [nums[a], nums[b], nums[c], nums[d]] (若两个四元组元素一一对应,则认为两个四元组重复):
0 <= a, b, c, d < n
a、b、c 和 d 互不相同
nums[a] + nums[b] + nums[c] + nums[d] == target
你可以按 任意顺序 返回答案
1 <= nums.length <= 200
-109 <= nums[i] <= 109
-109 <= target <= 109
class Solution {
public List<List<Integer>> fourSum(int[] nums, int target) {
List<List<Integer>> quadruplets = new ArrayList<List<Integer>>();
if (nums == null || nums.length < 4) {
return quadruplets;
}
Arrays.sort(nums);
int length = nums.length;
for (int i = 0; i < length - 3; i++) {
if (i > 0 && nums[i] == nums[i - 1]) {//去重
continue;
}
if ((long) nums[i] + nums[i + 1] + nums[i + 2] + nums[i + 3] > target) {
break;
}
if ((long) nums[i] + nums[length - 3] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
for (int j = i + 1; j < length - 2; j++) {
if (j > i + 1 && nums[j] == nums[j - 1]) {//去重
continue;
}
if ((long) nums[i] + nums[j] + nums[j + 1] + nums[j + 2] > target) {
break;
}
if ((long) nums[i] + nums[j] + nums[length - 2] + nums[length - 1] < target) {
continue;
}
int left = j + 1, right = length - 1;
while (left < right) {
int sum = nums[i] + nums[j] + nums[left] + nums[right];
if (sum == target) {
quadruplets.add(Arrays.asList(nums[i], nums[j], nums[left], nums[right]));
while (left < right && nums[left] == nums[left + 1]) {//去重
left++;
}
left++;
while (left < right && nums[right] == nums[right - 1]) {//去重
right--;
}
right--;
} else if (sum < target) {
left++;
} else {
right--;
}
}
}
}
return quadruplets;
}
}
窗口内是什么?
如何移动窗口的起始位置?
如何移动窗口的结束位置?
给定一个含有 n 个正整数的数组和一个正整数 target 。
找出该数组中满足其和 ≥ target 的长度最小的 连续子数组 [numsl, numsl+1, …, numsr-1, numsr] ,并返回其长度。如果不存在符合条件的子数组,返回 0 。
1 <= target <= 109
1 <= nums.length <= 105
1 <= nums[i] <= 105
class Solution {
private int count = 0;
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
}
int result = Integer.MAX_VALUE;
int sum = 0;
int left=0;
int windowLength = 0;
for(int right=0;right<n;++right){
sum += nums[right];
while(sum >= target){
windowLength = right-left+1;
result = result <= windowLength ? result : windowLength;
sum -= nums[left++];
}
}
return result == Integer.MAX_VALUE ? 0 : result;
}
}
class Solution {
public int minSubArrayLen(int target, int[] nums) {
int n = nums.length;
if (n == 0) {
return 0;
}
int ans = Integer.MAX_VALUE;
int start = 0, end = 0;
int sum = 0;
while (end < n) {
sum += nums[end];
while (sum >= target) {
ans = Math.min(ans, end - start + 1);
sum -= nums[start++];
}
end++;
}
return ans == Integer.MAX_VALUE ? 0 : ans;
}
}
在一排树中,第 i 棵树产生 tree[i] 型的水果。
你可以从你选择的任何树开始,然后重复执行以下步骤:
把这棵树上的水果放进你的篮子里。如果你做不到,就停下来。
移动到当前树右侧的下一棵树。如果右边没有树,就停下来。
请注意,在选择一颗树后,你没有任何选择:你必须执行步骤 1,然后执行步骤 2,然后返回步骤 1,然后执行步骤 2,依此类推,直至停止。
你有两个篮子,每个篮子可以携带任何数量的水果,但你希望每个篮子只携带一种类型的水果。
用这个程序你能收集的水果树的最大总量是多少?
1 <= tree.length <= 40000
0 <= tree[i] < tree.length
// 这道题可以理解为求只包含两种元素的最长连续子序列
class Solution {
public int totalFruit(int[] tree) {
int ans = 0, i = 0;
Counter count = new Counter();
for (int j = 0; j < tree.length; ++j) {
count.add(tree[j], 1);
while (count.size() >= 3) {
count.add(tree[i], -1);
if (count.get(tree[i]) == 0)
count.remove(tree[i]);
i++;
}
ans = Math.max(ans, j - i + 1);
}
return ans;
}
}
class Counter extends HashMap<Integer, Integer> {
public int get(int k) {
return containsKey(k) ? super.get(k) : 0;
}
public void add(int k, int v) {
put(k, get(k) + v);
}
}
class Solution {
public int totalFruit(int[] tree) {
int ans = 0, i = 0;
Map<Integer,Integer> map = new HashMap<>();
for (int j = 0; j < tree.length; ++j) {
map.put(tree[j],map.getOrDefault(tree[j],0) + 1);
while (map.size() >= 3) {
if (map.containsKey(tree[i])) {
map.put(tree[i],map.getOrDefault(tree[i],0) - 1);
if (map.get(tree[i]) == 0)
map.remove(tree[i]);
}
i++;
}
ans = Math.max(ans, j - i + 1);
}
return ans;
}
}
给你一个字符串 s 、一个字符串 t 。返回 s 中涵盖 t 所有字符的最小子串。如果 s 中不存在涵盖 t 所有字符的子串,则返回空字符串 “” 。
注意:
对于 t 中重复字符,我们寻找的子字符串中该字符数量必须不少于 t 中该字符数量。
如果 s 中存在这样的子串,我们保证它是唯一的答案。
1 <= s.length, t.length <= 105
s 和 t 由英文字母组成
class Solution {
public String minWindow(String s, String t) {
int sLength = s.length();
int tLength = t.length();
if(sLength < tLength){
return "";
}
HashMap<Character,Integer> tMap = new HashMap<>();//记录t字符串各个字符的数量
for(int i=0;i<tLength;++i){
tMap.put(t.charAt(i),tMap.getOrDefault(t.charAt(i),0)+1);
}
int left = 0;//滑动窗口起始位置
int sublength = Integer.MAX_VALUE;//记录子串长度
int valid = 0;//用来记录滑动窗口中有多少字符是与t字符串中的各个字符数量相等
int start = 0;//记录最小子串起始位置
HashMap<Character,Integer> sMap = new HashMap<>();//用来记录滑动窗口中各个字符的数量
for(int right = 0;right<sLength;++right){
char addChar = s.charAt(right);
sMap.put(addChar,sMap.getOrDefault(addChar,0)+1);
//注意:这个地方比较要使用equals 因为是Integer包装类,如果用==比较的是地址
if(tMap.containsKey(addChar) && sMap.get(addChar).equals(tMap.get(addChar))){
valid++;
}
while(valid == tMap.size()){//若相等,说明滑动窗口中已经覆盖了字符串t中的所有字符
if(right-left+1 < sublength){
sublength = right-left+1;
start = left;
}
char removeChar = s.charAt(left++);//滑动窗口起始位置滑动
if(tMap.containsKey(removeChar) && sMap.get(removeChar).equals(tMap.get(removeChar))){
valid--;
}
sMap.put(removeChar,sMap.get(removeChar)-1);
}
}
return sublength == Integer.MAX_VALUE ? "" : s.substring(start,start+sublength);
}
}