7月算法训练------第九天(二分查找)解题报告

7月算法训练------第九天(二分查找)解题报告

题目类型:二分查找
题目难度:中等

第一题、

  1. 题目链接:1146. 快照数组
  2. 思路分析:
    我们用一个List sn数组来模仿三维数组;List sn的长度为length,List中存放的时一个ArrayList,ArrayList中存放的时一个二维数组;我们用以下来表示
    ["SnapshotArray","set","snap","set","get"] [[3],[0,5],[],[0,6],[0,0]]
    执行SnapshotArray(3)时,创建长度为3的List数组sn;
    执行set(0,5)时,我们向sn[0]中加入数组{id,val},表示数组下标为0的元素,在第id次时变成过val;这里我们就向sn[0]ArrayList中加入-1次快照时的val5
    当执行snap时我们先加加再返回id值;
    执行get(0,0)时,我们就用二分查找,返回List sn中第indexArrayList的版本值与snap_id对应的数字;
    执行完之后List数组成为如下所示的模样:
位置指向
sn[0]ArrayList1
sn[1]ArrayList2
sn[2]ArrayList3

其中ArrayList1、2、3如下所示:

内容
ArrayList1-15
06

表示版本-1时,我们将ArrayList1改为5,版本0时,我们将ArrayList1改为6
ArrayList2ArrayList3中什么也没有。

  1. 代码:
class SnapshotArray {
    int id = -1;
    List<int[]>[] sn;
    public SnapshotArray(int length) {
        sn = new List[length];
        for(int i = 0; i < length; i++){
            sn[i] = new ArrayList<int[]>();
        }
    }
    
    public void set(int index, int val) {
        sn[index].add(new int[]{id, val});
    }
    
    public int snap() {     
        return ++id;
    }
    
    public int get(int index, int snap_id) {
        List<int[]> snList = sn[index];
        int l = 0, r = snList.size() - 1;
        int mid = 0;
        int ans = 0;
        while(l <= r){
            mid = (l+r) >> 1;
            if(snList.get(mid)[0] < snap_id){
                l = mid + 1;
                ans = snList.get(mid)[1];
            }else{
                r = mid - 1;
            }
        }
        return ans;
    }
}

/**
 * Your SnapshotArray object will be instantiated and called as such:
 * SnapshotArray obj = new SnapshotArray(length);
 * obj.set(index,val);
 * int param_2 = obj.snap();
 * int param_3 = obj.get(index,snap_id);
 */

第二题、1498. 满足条件的子序列数目

  1. 题目链接:1498. 满足条件的子序列数目
  2. 思路分析:
    先对数组进行排序;
    然后枚举某个nums[i],二分查找nums[j],由于排序了,所以nums[i] <= nums[j],如果他们的和小于等于target,那么就在区间[i,j]中任意两个数的和都是满足条件的,所以在这个区间内,每个数可以选,也可以不选就是排列组合,直接用二分快速快速幂计算取模即可。
  3. 代码:
class Solution {
    static final int mod = 1000000007;
    public int numSubseq(int[] nums, int target) {
        Arrays.sort(nums);
        int ret = 0;
        for(int i = 0; i < nums.length; ++i){
            int l = i;
            int r = nums.length - 1;
            int ans = -1;
            while(l <= r){
                int mid = (l+r) >> 1;
                if(nums[i] + nums[mid] <= target){
                    ans = mid;
                    l = mid + 1;
                }else{
                    r = mid - 1;
                }
            }
            if(ans != -1){
                ret += power(2, ans - i, mod);
                ret %= mod;
            }
        }
        return ret;
    }
    private static long power(long a, long b, long c){
        if(b == 0){
            return 1;
        }
        long tmp = power(a*a%c, b>>1, c);
        if((b&1)==1){
            tmp = tmp * a % c;
        }
        return tmp;
    }
}

第三题、1802. 有界数组中指定下标处的最大值

  1. 题目链接:1802. 有界数组中指定下标处的最大值

  2. 思路分析:
    刚开始,我们把数组全都填上1;
    第一轮循环,然后我们在index处+1;
    第二轮循环,我们再index和index左右两边+1;

    直到用完maxSum时,就能找到最大值了。

  3. 代码:

class Solution {
    public int maxValue(int n, int index, int maxSum) {
        int l = index, r = index;
        int rest = maxSum - n;
        int ans = 1;
        while(l > 0 || r < n - 1){
            int m = r - l + 1;
            if(rest - m >= 0){
                rest -= m;
                ans++;
                if(l != 0){
                    l--;
                }
                if(r != n - 1){
                    r++; 
                }
            }else{
                break;
            }
        }
        ans += rest / n;
        return ans;
    }
}

第四题、2040. 两个有序数组的第 K 小乘积

  1. 题目链接:2040. 两个有序数组的第 K 小乘积
  2. 思路分析:
    这一题先占个位,有点难,呜呜(-̩̩̩-̩̩̩-̩̩̩-̩̩̩-̩̩̩___-̩̩̩-̩̩̩-̩̩̩-̩̩̩-̩̩̩)( ´◔ ‸◔`)

先做一下基础题吧!

5月的题:

704. 二分查找

  1. 题目链接:704. 二分查找
  2. 思路分析:
    运用二分查找,将结果找出。
  3. 代码:
class Solution {
    public int search(int[] nums, int target) {
        int l= 0, r = nums.length - 1;
        while(l <= r){
            int mid = (r - l) / 2 + l;
            if(nums[mid] > target){
                r = mid - 1;
            }else if(nums[mid] < target){
                l = mid + 1;
            }else{
                return mid;
            }
        }
        return -1;
    }
}

剑指 Offer 53 - I. 在排序数组中查找数字 I

  1. 题目链接:剑指 Offer 53 - I. 在排序数组中查找数字 I
  2. 思路分析:
    运用二分查找,将结果找出。
  3. 代码:
class Solution {
    public int search(int[] nums, int target) {
        // 搜索右边界 right
        int i = 0, j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] <= target) i = m + 1;
            else j = m - 1;
        }
        int right = i;
        // 若数组中无 target ,则提前返回
        if(j >= 0 && nums[j] != target) return 0;
        // 搜索左边界 right
        i = 0; j = nums.length - 1;
        while(i <= j) {
            int m = (i + j) / 2;
            if(nums[m] < target) i = m + 1;
            else j = m - 1;
        }
        int left = j;
        return right - left - 1;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值