3.数组

 870--优势洗牌

 

public static int[] advantageCount(int[] A, int[] B) {
        int[] sortedA=A.clone();
        Arrays.sort(sortedA);//升序排列
        int[] sortedB=B.clone();
        Arrays.sort(sortedB);
        //Integer存放B的值,后面的队列存放大于B值的A中的值
        HashMap<Integer, Deque<Integer>> map = new HashMap<>();
        for (int i : sortedB) {
            map.put(i,new LinkedList<>());
        }
        //摆烂队列,这里放的都是比拼失败的下等马
        Deque<Integer> remaining=new LinkedList<>();
        int j=0;
        for (int i : sortedA) {
            //如果当前位置的a大于当前位置的b,存放进map里,并且让j++
            if(i>sortedB[j]){
                map.get(sortedB[j++]).add(i);
                //不然就存放进队列中
            }else{
                remaining.add(i);
            }
        }
        int[] ans=new int[B.length];
        for (int i = 0; i < B.length; i++) {
            //正常从map里的deque拿,这里都是a的上等马
            if(map.get(B[i]).size()>0)ans[i]=map.get(B[i]).pop();
            //打不过就摆烂
            else ans[i]=remaining.pop();
        }
        return ans;
    }

704--二分查找

 public int search(int[] nums, int target) {
        int left=0;
        int right=nums.length-1;
        while (left<=right){//搜索区间为空时才应该被制止,所以这里的条件是<=
            int mid=left+(right-left)/2;//防止溢出
            if(nums[mid]==target)return mid;
            else if(nums[mid]<target)left=mid+1;//mid已经搜索过了,所以应该排除
            else if(nums[mid]>target)right=mid-1;
        }
        return -1;
    }

34--排序数组中查找元素的第一个位置和最后一个位置

    public int[] searchRange(int[] nums, int target) {
        int left=0;
        int right=nums.length-1;
        int ans=-1;
        while(left<=right){
            int mid=left+(right-left)/2;
            if(nums[mid]==target){
                ans=mid;
                break;
            }
            else if(nums[mid]>target)right=mid-1;
            else if(nums[mid]<target)left=mid+1;
        }
        if(ans==-1)return new int[]{-1,-1};
        int ansLeft=ans,ansRight=ans;
        //移动指针并且检验是否越界
        while(ansLeft>=0&&nums[ansLeft]==target){
            ansLeft--;
        }
        while(ansRight<=nums.length-1&&nums[ansRight]==target){
            ansRight++;
        }
        return new int[]{ansLeft+1,ansRight-1};
    }

857--爱吃香蕉的人(二分法的妙用)

/**
     * 当吃香蕉的速度为x的时候,需要H个小时才能吃完香蕉,H=f(x),其中H关于x单调递减
     * @param arr 代表香蕉的数组
     * @param speed 吃的速度 根/小时
     * @return 吃完香蕉的时间
     */
    int f(int[] arr,int speed){
        int time=0;
        for (int i = 0; i < arr.length; i++) {
            time+=arr[i]/speed;
            int res=arr[i]%speed;
            if(res>0){
                time++;
            }
        }
        return time;
    }

    /**
     * @param piles 吃香蕉的数组
     * @param h 警卫回来的时间
     * @return 最小的速度
     */
    public int getMinSpeed(int[] piles,int h){
        if(piles==null)return 0;
        int left=1;//最小的速度应该是1
        int right=1000000000;//最大的速度题目中规定为10^9
        while (left<=right){
            int mid=left+(right-left)/2;
            //我们想让返回的值尽量小,所以我们得让left尽量靠左,所以我们让相当的情况和移动右点到左点的情况一致
            if(f(piles,mid)<=h)right=mid-1;
            else left=mid+1;
        }
        return left;
    }

1011-在D天内送达包裹的能力(二分法的妙用)

/**
     * @param arr 数组
     * @param hold 载重量
     * @return 最低天数
     * 载重量越高,天数越短,所以这也是一个单调递减的函数
     */
//方法一,效率比较低,判断条件过于冗杂
    public int f(int[] arr,int hold){
        int days=1;
        int num=0;
        for (int i = 0; i < arr.length; i++) {
            num+=arr[i];
            //等于的时候也需要开了,因为已经装不下了,此时如果还有货物就加一天,没有货物就不加了
            if(num>hold){
                days++;
                num=arr[i];//大于的情况需要把这次的货加上去
            }else if(num==hold&&i!=arr.length-1){
                days++;
                num=0;
            }else if(num==hold&&i==arr.length-1){
                days--;
            }
        }
        return days;
    }
//方法二,效率比一略高
  
    public int f(int[] weights, int x) {
        int days = 0;
        for (int i = 0; i < weights.length; ) {
            // 尽可能多装货物
            int cap = x;
            while (i < weights.length) {
                if (cap < weights[i]) break;
                else cap -= weights[i];
                i++;
            }
            days++;
        }
        return days;
    }


    /**
     * @param weights 物品重量
     * @param days  天数
     * @return 最小运载量,返回值尽量小
     */
    public int shipWithinDays(int[] weights, int days) {
        int left=1;//最低载重量至少为1
        int right=50000;//题目条件
        //最终返回的结果至少要比所有的weight值要大,而rignt值可以让他为所有值的和
        for (int weight : weights) {
            left=Math.max(left,weight);
            right+=weight;
        }
        while(left<=right){
            int mid=left+(right-left)/2;
            if(days>=f(weights,mid)){right=mid-1;}
            else{left=mid+1;}
        }
        return left;
    }

410--分割数组的最大值(二分法的妙用)

    //限定一个最大数组和,返回最少可以分割成几个数组,数字越大,可分割的次数越少,这是一个单调递减的函数
    int f(int[] arr,int max){
        int count=1;
        int sum=0;
        for (int i = 0; i < arr.length; i++) {
            if(max<sum+arr[i]){
                //不可以添加元素了
                sum=arr[i];
                count++;
            }else{
                sum+=arr[i];
            }
        }
        return count;
    }
    //我们要使得分割数组的最大值最小
    public int splitArray(int[] nums, int m) {
        int left=getLeft(nums);
        int right=getRight(nums);
        while (left<=right){
            int mid=left+(right-left)/2;
            if(m>=f(nums,mid))right=mid-1;
            else{left=mid+1;}
        }
        return left;
    }
    //获取数组中的最大值,因为它至少是最大值,才能保证数组被分割
    public int getLeft(int[] arr){
        int res=0;
        for (int i : arr) {
            res=Math.max(res,i);
        }
        return res;
    }
    public int getRight(int[] arr){
        int res=0;
        for (int i = 0; i < arr.length; i++) {
            res+=arr[i];
        }
        return res;
    }

380--常数时间插入,删除和获取随机元素

分析:HashSet,LinikedHashSet的时间复杂度都为O(1)但是只要底层是链表实现的,我们就没有办法在插入的时候实现O(1),所以我们一定要使用底层为数组实现的,并且数组需要是紧凑的,那数据插入,删除的时候怎么保证呢?可以直接在尾部插入,所以在删除的时候我们把它移动到尾部然后再pop掉,每个数对应的索引使用hashmap来存储

public class likou380 {
    private HashMap<Integer,Integer> map;
    private ArrayList<Integer> list;
    Random random = new Random();
    public likou380(){
        map=new HashMap<>();
        list=new ArrayList<>();
    }
    public boolean insert(int val) {
        if(map.containsKey(val))return false;
        //先放到map里面
        map.put(val,list.size());
        list.add(val);//尾插
        return true;
    }
    public boolean remove(int val) {
        if(!map.containsKey(val))return false;
        int index=map.get(val);
        int lastEleValue=list.get(list.size()-1);
        map.put(lastEleValue,index);
        list.set(index,lastEleValue);
        list.remove(list.size()-1);
        map.remove(val);
        return true;
    }
    int getRandom() {
        // 随机获取 nums 中的一个元素
        return list.get(random.nextInt(list.size()));
    }
}

710--黑名单中的随机数

白名单中数的个数为 N - len(B),那么可以直接在 [0, N - len(B)) 中随机生成整数。我们把所有小于 N - len(B) 且在黑名单中数一一映射到大于等于 N - len(B) 且出现在白名单中的数。这样一来,如果随机生成的整数出现在黑名单中,我们就返回它唯一对应的那个出现在白名单中的数即可。

例如当 N = 6,B = [0, 2, 3] 时,我们在 [0, 3) 中随机生成整数,并将 2 映射到 4,3 映射到 5,这样随机生成的整数就是 [0, 1, 4, 5] 中的一个。

public class likou710 {
    Random r;
    int wlen;
    Map<Integer,Integer> m;
    likou710(int n,int[] b){
        m=new HashMap<>();
        r=new Random();
        wlen=n-b.length;
        Set<Integer> w = new HashSet<>();
        //创建[wlen,n)的集合(映射集合也就是比[0,wlen)大的数)
        for (int i = wlen; i < n; i++) {
            w.add(i);
        }
        //排除掉映射集合中黑名单的有元素
        for (int x : b) {
            w.remove(x);
        }
        //剩下的元素加入到集合中
        Iterator<Integer> wi = w.iterator();
        //对于小于wlen长度的元素我们需要映射到我们的白名单元素
        for (int i : b) {
            if(i<wlen)m.put(i,wi.next());
        }

    }
    public int pick(){
        int k=r.nextInt(wlen);
        return m.getOrDefault(k,k);//如果有值那么说明它需要被映射,没有值说明不需要被映射,可以直接返回
    }

    public static void main(String[] args) {
        likou710 likou710 = new likou710(10, new int[]{0, 1, 4,9});
        for (int i = 0; i < 20; i++) {
            System.out.println(likou710.pick());
        }

    }
}

402--移除掉k位有效数字

    public String removeKdigits(String num, int k) {
        Deque<Character> deque = new LinkedList<Character>();
        int length = num.length();
        for (int i = 0; i < length; ++i) {
            char digit = num.charAt(i);
            //只要队列不为空,并且k还没有减到0,并且栈的最近的元素大于当前元素进入下面的循环
            while (!deque.isEmpty() && k > 0 && deque.peekLast() > digit) {
                deque.pollLast();//栈中元素出来
                k--;//k减少
            }
            //入队列
            deque.offerLast(digit);
        }
        //继续弹出k个元素,此时队列里的数字已经是单调不降了,但是还没有达到k=0,所以我们要继续弹出元素
        for (int i = 0; i < k; ++i) {
            deque.pollLast();
        }

        StringBuilder ret = new StringBuilder();
        boolean leadingZero = true;
        while (!deque.isEmpty()) {
            char digit = deque.pollFirst();//从头部取出元素
            if (leadingZero && digit == '0') {//如果是0就跳过
                continue;
            }
            leadingZero = false;
            ret.append(digit);//组装字符串
        }
        //最后长度为0就返回0否则返回拼接的字符串
        return ret.length() == 0 ? "0" : ret.toString();
    }

26--删除有序数组中的重复项

public int removeDuplicates(int[] nums) {
        if(nums==null||nums.length==0)return 0;
        int p=0;
        int q=1;
        while(q<nums.length){
            //如果两个指针的数值不相等
            if(nums[p]!=nums[q]){
                //如果q-p>1的时候才把nums[p+1]重新赋值为nums[q],q=p+1的时候是不需要赋值的
                if(q-p>1){
                    nums[p+1]=nums[q];
                }
                //p指针后移
                p++;
            }
            //两个指针相等q指针后移
            q++;
        }
        return p+1;
    }
 public int removeDuplicates2(int[] nums) {
        int slow=0;
        int fast=0;
        while (fast<nums.length){
            if(nums[slow]==nums[fast]){
                fast++;
                continue;
            }
            slow++;
            nums[slow]=nums[fast];
        }
        return slow+1;
    }

83--和上题相似的一道类似的链表题

public ListNode deleteDuplicates(ListNode head) {
        ListNode cur = head;
        while(cur != null && cur.next != null) {
            if(cur.val == cur.next.val) {
                cur.next = cur.next.next;
            } else {
                cur = cur.next;
            }
        }
        return head;
    }

 public ListNode deleteDuplicates2(ListNode head) {
        if(head==null)return null;
        ListNode slow = head;
        ListNode fast = head;
        while (fast != null) {
            if (slow.val != fast.val) {
                slow.next = fast;
                slow = slow.next;
            }
            fast = fast.next;
        }
        //断开后面重复元素的连接
        slow.next=null;
        return head;
    }

27--移除元素

public int removeElement(int[] nums, int val) {
       int fast=0,slow=0;
       while(fast<nums.length){
           if(nums[fast]!=val){
               //不相等的时候给慢指针赋值为快指针当前的值
               nums[slow]=nums[fast];
               //慢指针赋值完往前走一步,准备下一次赋值
               slow++;
           }
           //相等的时候就让快指针往前走
           fast++;
       }
       return slow;
    }

 283--移动零到数组的结尾

    public void moveZeroes(int[] nums) {
        int i = removeElement(nums, 0);
        for (; i <nums.length ; i++) {
            nums[i]=0;
        }
    }
    public int removeElement(int[] nums, int val) {
        int fast=0,slow=0;
        while(fast<nums.length){
            if(nums[fast]!=val){
                //不相等的时候给慢指针赋值为快指针当前的值
                nums[slow]=nums[fast];
                //慢指针赋值完往前走一步,准备下一次赋值
                slow++;
            }
            //相等的时候就让快指针往前走
            fast++;
        }
        return slow;
    }
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
用户界面: 1. 数组输入:请输入数组的长度:(用户输入长度) 请输入数组的元素:(用户输入元素,以空格分隔) 数组输入成功! 2. 数组排序:请选择排序方式: 1. 升序排序 2. 降序排序 (用户选择排序方式) 排序成功! 3. 元素插入:请输入要插入的元素:(用户输入元素) 请输入要插入的位置:(用户输入位置) 插入成功! 4. 元素查找:请输入要查找的元素:(用户输入元素) 元素查找成功!该元素在数组中的位置为:(输出位置) 5. 元素删除:请输入要删除的元素:(用户输入元素) 元素删除成功! 6. 数组输出:数组元素为:(输出数组元素) 7. 输出指定位置元素:请输入要查询的位置:(用户输入位置) 该位置的元素为:(输出元素) 8. 对指定个数的数组元素求和:请输入要求和的个数:(用户输入个数) 数组元素求和为:(输出求和结果) 9. 实验报告: 本次实验设计了一个整型数组操作库,实现了数组输入、数组排序、元素插入、元素查找、元素删除、数组输出、输出指定位置元素、对指定个数的数组元素求和等功能。 在用户界面中,用户可以输入数组的长度和元素,进行数组的初始化;也可以选择升序或降序排序方式,进行数组排序;可以插入元素,查找元素,删除元素;输出数组元素和指定位置的元素;求和指定个数的数组元素。 实验中,我们使用了冒泡排序算法进行数组排序,使用了数组下标进行元素插入和删除操作。同时,我们对用户的输入进行了合法性判断,保证了程序的稳定性和正确性。 本次实验让我对数组操作有了更深入的理解,也锻炼了我的编程能力和问题解决能力。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值