class Solution {
public int search(int[] nums, int target) {
int n = nums.length;
int left = 0;
int right = n-1;
while(left < right){
int mid = left + (right - left) / 2;
if(nums[mid] < target)
left = mid + 1;
else
right = mid;
}
if(nums[left] == target)
return left;
else
return -1;
}
}
class Solution {
public int[] searchRange(int[] nums, int target) {
int n = nums.length;
if(n == 0)
return new int[]{-1,-1};
int[] ans = new int[2];
int left = 0;
int right = n-1;
//查找第一个位置
while(left < right){
int mid = left + (right-left) / 2;
if(nums[mid] < target)
left = mid + 1;
else
right = mid;
}
if(nums[left] != target)
return new int[]{-1,-1};
ans[0] = left;
right = n-1;
//查找最后一个位置
while(left < right){
int mid = left + (right-left+1) / 2;
if(nums[mid] > target)
right = mid - 1;
else
left = mid;
}
ans[1] = left;
return ans;
}
}
class Solution {
public int search(int[] nums, int target) {
int n = nums.length;
if(n == 0)
return 0;
int[] ans = new int[2];
int left = 0;
int right = n-1;
//查找第一个位置
while(left < right){
int mid = left + (right-left) / 2;
if(nums[mid] < target)
left = mid + 1;
else
right = mid;
}
if(nums[left] != target)
return 0;
ans[0] = left;
right = n-1;
//查找最后一个位置
while(left < right){
int mid = left + (right-left+1) / 2;
if(nums[mid] > target)
right = mid - 1;
else
left = mid;
}
ans[1] = left;
return ans[1]-ans[0]+1;
}
}
class Solution {
public int searchInsert(int[] nums, int target) {
int n = nums.length;
int left = 0;
int right = n-1;
while(left < right){
int mid = left + (right-left+1) / 2;
if(nums[mid] > target)
right = mid -1;
else
left = mid;
}
if(nums[left] >= target)
return left;
else
return left + 1;
}
}
解法一
O(m+n)
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length;
int n = matrix[0].length;
int i = 0;
int j = n-1;
while(j >=0 && i < m){
if(matrix[i][j] > target)
j -= 1;
else if(matrix[i][j] < target)
i += 1;
else
return true;
}
return false;
}
}
解法二
o(mlogn)
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length;
int n = matrix[0].length;
for(int i = 0; i < m;i++){
int left = 0;
int right = n-1;
while(left < right){
int mid = left + (right-left) / 2;
if(matrix[i][mid] < target)
left = mid+1;
else
right = mid;
}
if(matrix[i][left] == target)
return true;
}
return false;
}
}
解法一
O(logm+logn)=O(logmn)
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length;
int n = matrix[0].length;
int left = 0;
int right = m-1;
while(left < right){
int mid = left + (right-left+1) / 2;
if(matrix[mid][0] > target)
right = mid-1;
else
left = mid;
}
//System.out.println(matrix[left][0]);
if(matrix[left][0] > target)
return false;
int index = left;
System.out.println(index);
left = 0;
right = n-1;
while(left < right){
int mid = left + (right-left) / 2;
if(matrix[index][mid] < target)
left = mid + 1;
else
right = mid;
}
if(matrix[index][left] == target)
return true;
else
return false;
}
}
解法二
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length;
int n = matrix[0].length;
int left = 0;
int right = m*n-1;
while(left < right){
int mid = left + (right-left+1) / 2;
if(matrix[mid/n][mid%n] > target)
right = mid-1;
else
left = mid;
}
if(matrix[left/n][left%n] == target)
return true;
else
return false;
}
}
解法三
O(m+n)
class Solution {
public boolean searchMatrix(int[][] matrix, int target) {
int m = matrix.length;
int n = matrix[0].length;
int i = 0;
int j = n-1;
while(j >=0 && i < m){
if(matrix[i][j] > target)
j -= 1;
else if(matrix[i][j] < target)
i += 1;
else
return true;
}
return false;
}
}
class Solution {
public int maxEnvelopes(int[][] envelopes) {
int n = envelopes.length;
//nlogn
Arrays.sort(envelopes,new Comparator<int[]>(){
// 按第一维升序排序 如果第一维相同 按第二维降序排序
public int compare(int[] e1,int[] e2){
if(e1[0] != e2[0])
return e1[0] - e2[0];
else
return e2[1] - e1[1];
}
});
int[] dp = new int[n];
dp[0] = envelopes[0][1];
int len = 1;
for(int i = 1; i < n;i++){
int left = 0;
int right = len-1;
while(left < right){
int mid = left + (right-left) / 2;
if(dp[mid] < envelopes[i][1])
left = mid+1;
else
right = mid;
}
if(dp[left] >= envelopes[i][1])
dp[left] = envelopes[i][1];
else{
dp[len] = envelopes[i][1];
len += 1;
}
}
return len;
}
}
二分查找
class Solution {
public int numMatchingSubseq(String s, String[] words) {
int n = words.length;
int m = s.length();
//用map记录s中每个字符出现的位置
//'c':list list记录了字符'c'出现的位置 list递增排序
ArrayList<Integer>[] count = new ArrayList[26];
for(int i = 0; i < m;i++){
char ch = s.charAt(i);
int idx = ch-'a';
if(count[idx] == null){
count[idx] = new ArrayList<>();
}
count[idx].add(i);
}
int ans = 0;
//遍历words 判断每个word 是否是s的子序列
for(int i = 0; i < n; i++){
String word = words[i];
char ch = word.charAt(0);
//第一个字符就不存在
int idx = ch-'a';
if(count[idx] == null)
continue;
int index = count[idx].get(0)+1;
boolean flag = true;
for(int j = 1;j < word.length() && flag;j++){
char chj = word.charAt(j);
idx = chj - 'a';
ArrayList<Integer> al = count[idx];
//有字符不存在
if(al == null){
flag = false;
break;
}
//找出al中>= index 的最小值
int left = 0;
int right = al.size()-1;
while(left < right){
int mid = left + (right-left) / 2;
if(al.get(mid) < index)
left = mid+1;
else
right = mid;
}
if(al.get(left)< index)
flag = false;
else{
index = al.get(left) + 1;
}
}
if(flag == true)
ans += 1;
}
return ans;
}
}
哈希map略慢 但耗内存小
class Solution {
public int numMatchingSubseq(String s, String[] words) {
int n = words.length;
int m = s.length();
//用map记录s中每个字符出现的位置
//'c':list list记录了字符'c'出现的位置 list递增排序
Map<Character,ArrayList<Integer>> count = new HashMap<>();
for(int i = 0; i < m;i++){
char ch = s.charAt(i);
if(count.get(ch) == null)
count.put(ch,new ArrayList<>());
count.get(ch).add(i);
}
int ans = 0;
//遍历words 判断每个word 是否是s的子序列
for(int i = 0; i < n; i++){
String word = words[i];
char ch = word.charAt(0);
//第一个字符就不存在
if(count.get(ch) == null)
continue;
int index = count.get(ch).get(0)+1;
boolean flag = true;
for(int j = 1;j < word.length() && flag;j++){
char chj = word.charAt(j);
ArrayList<Integer> al = count.get(chj);
//有字符不存在
if(al == null){
flag = false;
break;
}
//找出al中>= index 的最小值
int left = 0;
int right = al.size()-1;
while(left < right){
int mid = left + (right-left) / 2;
if(al.get(mid) < index)
left = mid+1;
else
right = mid;
}
if(al.get(left)< index)
flag = false;
else{
index = al.get(left) + 1;
}
}
if(flag == true)
ans += 1;
}
return ans;
}
}
指向下一个字母的指针
class Solution {
public int numMatchingSubseq(String s, String[] words) {
int m = s.length();
int n = words.length;
Map<Character,ArrayList<String>> count = new HashMap<>();
for(int i = 0; i < n;i++){
char ch = words[i].charAt(0);
if(count.get(ch) == null)
count.put(ch,new ArrayList<>());
count.get(ch).add(words[i]);
}
int ans = 0;
for(int i = 0; i < m;i++){
char ch = s.charAt(i);
ArrayList<String> list = count.get(ch);
if(list == null)
continue;
count.remove(ch);
for(int j = 0; j < list.size();j++){
String word = list.get(j);
if(word.length() == 1){
ans += 1;
continue;
}
word = word.substring(1,word.length());
char chj = word.charAt(0);
if(count.get(chj) == null)
count.put(chj,new ArrayList<>());
count.get(chj).add(word);
}
}
return ans;
}
}
class Solution {
public List<Integer> findClosestElements(int[] arr, int k, int x) {
int n = arr.length;
int left = 0;
int right = n-1;
int mid = 0;
//寻找小于等于x的最大数
while(left < right){
mid = left +(right-left+1) / 2;
if(arr[mid] > x)
right = mid-1;
else
left = mid;
}
//如果arr[left] == x 那就以arr[left]为中点 否则以 arr[left] 和 arr[left+1]中与x较近的一个为中点
if(left+1< n && Math.abs(arr[left+1]-x) < Math.abs(arr[left]-x))
mid = left+1;
else
mid = left;
//双指针寻找k个数
if(mid == n-1){//中点在末尾
right = n-1;
left = n-1-k+1;
}else if(mid == 0){//中点在头
left = 0;
right = k-1;
}else{
left = mid-1;
right = mid + 1;
while(left >= 0 && right < n && (right-left-1) < k){
if(Math.abs(arr[right] - x) < Math.abs(arr[left]-x))
right += 1;
else
left -= 1;
}
left = left+1;
right = right-1;
// 没有足够k个数 left >= 0 || right < n 跳出循环
if(right-left+1 < k){
int dif = k-(right-left+1);
if(left == 0){
right += dif;
}else{
left -= dif;
}
}
}
List<Integer> ans = new ArrayList<>();
for(int i = left; i <= right;i++){
ans.add(arr[i]);
}
return ans;
}
}
前置知识
class Solution {
public int trailingZeroes(int n) {
int ans = 0;
while(n>0){
ans += n/5;
n = n/ 5;
}
return ans;
}
}
class Solution {
public int preimageSizeFZF(int k) {
long left = 0L;
long right = 5L * k;
long mid = 0L;
long sum = 0L;
long n = 0L;
while(left < right){
mid = left + (right - left + 1) / 2;
n = mid;
sum = 0L;
while(n > 0){
sum += n / 5;
n = n / 5;
}
if(sum > k)
right = mid -1;
else
left = mid;
}
n = left;
sum = 0L;
while(n > 0){
sum += n / 5;
n = n / 5;
}
if(sum == k)
return 5;
else
return 0;
}
}
class Solution {
public int peakIndexInMountainArray(int[] arr) {
//数组长度
int n = arr.length;
int left = 1;
int right = n-2;
while(left < right){
int mid = left + (right - left + 1) / 2;
if(arr[mid] < arr[mid-1] && arr[mid] > arr[mid+1])
right = mid-1;
else
left = mid;
}
return left;
}
}
class Solution {
public int shipWithinDays(int[] weights, int days) {
//船的最小载重为单个包裹重量的最大值
int left = 1;
// 船的最大载重为所有包裹的总和
int right = 0;
for(int i = 0; i < weights.length;i++){
right += weights[i];
left = Math.max(weights[i],left);
}
while(left < right){
int mid = left + (right - left) / 2;
if(isOK(weights,days,mid))
right = mid;
else
left = mid + 1;
}
return left;
}
public boolean isOK(int[] weights,int days,int capacity){
int cur = 0;
int d = 1;
for(int i = 0; i < weights.length;i++){
//判断能不能装上船呀
//可以装上船
if(cur + weights[i] <= capacity)
cur += weights[i];
//不能装上船
else{
cur = weights[i];
d += 1;
}
}
if(d <= days)
return true;
else
return false;
}
}
class Solution {
public int splitArray(int[] nums, int k) {
//子数组之和的最大值 的 最小值是nums中元素的最大值
int left = 0;
//子数组的之和的最大值 的最大值是nums中所有元素相加
int right = 0;
for(int i = 0; i < nums.length;i++){
right += nums[i];
left = Math.max(nums[i],left);
}
while(left < right){
int mid = left + (right - left) / 2;
int group = splitNum(nums,mid);
//组太多了 说明max_value 设小了
if(group > k)
left = mid + 1;
else
right = mid;
}
return left;
}
public int splitNum(int[] nums,int max_value){
int sum = 0;
int group = 1;
for(int i = 0; i < nums.length; i++){
if(sum + nums[i] <= max_value)
sum += nums[i];
else{
sum = nums[i];
group += 1;
}
}
return group;
}
}
class Solution {
public int minEatingSpeed(int[] piles, int h) {
//速度最小值是1
int left = 1;
//速度最大值是piles中元素最大值
int right = 1;
for(int i = 0; i < piles.length;i++){
right = Math.max(right,piles[i]);
}
while(left < right){
int mid = left + (right - left) / 2;
int hour = getHour(piles,mid);
//速度小了
if(hour > h)
left = mid + 1;
else
right = mid;
}
return left;
}
public int getHour(int[] piles,int speed){
int hour = 0;
for(int i =0 ; i < piles.length;i++){
hour += piles[i] % speed == 0 ? piles[i] / speed : (piles[i] / speed) +1 ;
}
return hour;
}
}
丑数系列
class Solution {
public boolean isUgly(int n) {
if (n <= 0) {
return false;
}
int[] factors = {2, 3, 5};
for (int factor : factors) {
while (n % factor == 0) {
n /= factor;
}
}
return n == 1;
}
}
优先队列 一个丑数 * 2 *3 * 5以后也是丑数
class Solution {
public int nthUglyNumber(int n) {
Set<Long> set = new HashSet<>();
//默认是小顶堆
PriorityQueue<Long> heap = new PriorityQueue<Long>();
long[] factors = {2L,3L,5L};
set.add(1L);
heap.offer(1L);
int sum = 0;
int ans = 0;
while(sum < n){
ans = (int)((long)heap.poll());
sum += 1;
for(int i = 0; i < factors.length;i++){
if(!set.contains(ans * factors[i])){
set.add(ans * factors[i]);
heap.offer(ans * factors[i]);
}
}
}
return ans;
}
}
二分查找 + 容斥定理 + 辗转相除法
class Solution {
public int nthUglyNumber(int n, int a, int b, int c) {
//[1-nums] 之间
long left = 1;
long right = 2000000000;
while(left < right){
long mid = left + (right - left) / 2;
if(getUglyNum(mid,a,b,c) < n)
left = mid + 1;
else
right = mid;
}
return (int)(left);
}
//最小公倍数
private long lcm(long a,long b){
return (a * b) / gcd(a,b);
}
//最大公约数
//两个整数的最大公约数等于其中较小的那个数和两数相除余数的最大公约数
public long gcd(long a,long b){
if(a < b)
return gcd(b,a);
if(b == 0)
return a;
return gcd(b,a % b);
}
public long getUglyNum(long n,long a,long b,long c){
long A = n / a;
long B = n / b;
long C = n / c;
long AB = n / lcm(a,b);
long BC = n / lcm(b,c);
long AC = n / lcm(a,c);
long ABC = n / lcm(lcm(a,b),c);
return A + B + C -AB - BC - AC + ABC;
}
}
class Solution {
public int nthSuperUglyNumber(int n, int[] primes) {
int plen = primes.length;
//存放前n个丑数
long[] dp = new long[n];
dp[0] = 1;
//当前最小丑数是dp[0]
//pointers都指向下标0
int[] pointers = new int[plen];
for(int i = 1; i < n; i++){
dp[i] = Long.MAX_VALUE;
for(int j = 0; j < plen;j++){
dp[i] = Math.min(dp[i],dp[pointers[j]]* (long)(primes[j]));
}
for(int j = 0; j < plen;j++){
if(dp[i] == dp[pointers[j]]* (long)(primes[j]))
pointers[j] += 1;
}
}
return (int)(dp[n-1]);
}
}
class Solution {
public int missingNumber(int[] nums) {
// 重点 找到第一个不满足nums[index] = index的情况 缺失值就是 nums[index] -1
int n = nums.length;
int left = 0;
int right = n-1;
while(left < right){
int mid = left + (right - left) / 2;
if(nums[mid] == mid){
left = mid + 1;
}
else{
right = mid;
}
}
//left 一直向右移发现一直满足 nums[left] = left 缺失值在最末尾
if(nums[left] == left)
return left + 1;
//第一个不满足nums[index] = index 的情况 缺失值就是 nums[index] -1
else
return nums[left] - 1;
}
}