例题集 数组

  1. 删除重复出现元素
  2. 合并两个有序数组
  3. 整体移动数组
  4. 查找主要元素
  5. 三数之和
  6. 最大子序和
  7. 最长连续序列
  8. 加1
  9. 数组全排列

1.删除重复出现元素

题目:
给你一个有序数组 nums ,请你 原地 删除重复出现的元素,使每个元素 只出现一次 ,返回删除后数组的新长度。
要求:
不要使用额外的数组空间,你必须在 原地 修改输入数组 并在使用 O(1) 额外空间的条件下完成。

思路:
双指针法
当前指针指向第一个位置
比较指针指向第二个位置
如果arr[cur] == arr[compare]->compare下移
如果arr[cur]!= arr[compare]->arr[compare]与arr[cur]下一位置作交换
    public static int removeDuplicates(int[] nums) {
        //判空
        if (nums == null) {
            return 0;
        }
        //当前指针
        int cur = 0;
        //比对指针
        int compare = 1;
        //记录数组长度
        int length = 1;


        while (compare < nums.length){
            if (nums[cur] == nums[compare]){
                //如果两个数相等   ->  compare指针下移
                compare++;
            }else{
                //如果两个数不相等   -> nums[cur + 1] 与 nums[compare]交换
                swap(nums,++cur,compare++);
                length++;
            }
        }

        return length;
    }

    public static void swap(int[]nums,int x,int y){
        int tmp = nums[x];
        nums[x] = nums[y];
        nums[y] = tmp;
    }

2.合并两个有序数组

题目:
你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 中,使 nums1 成为一个有序数组。
要求:
初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。
你可以假设 nums1 的空间大小等于 m + n,这样它就有足够的空间保存来自 nums2 的元素。

思路1:
类似于merge排序外排方法
用额外的help[]数组帮助完成
    public void merge(int[] nums1, int m, int[] nums2, int n) {
        if (nums2 == null){
            return;
        }

        int[] help = new int[m + n];
        int cur1 = 0;
        int cur2 = 0;
        int index = 0;

        while (cur1 < m && cur2 < nums2.length){
            help[index++] = nums1[cur1] < nums2[cur2] ? nums1[cur1++] : nums2[cur2++];
        }

        while (cur1 < m){
            help[index++] = nums1[cur1++];
        }

        while (cur2 < nums2.length){
            help[index++] = nums2[cur2++];
        }

        System.arraycopy(help, 0, nums1, 0, nums1.length);
    }
思路2:
外排+三指针
两个指针分别指向两个数组最后一个元素的位置
一个指针指向arr1的最后一个位置
从arr1最后一个位置开始存放数据
从两个数组末尾元素开始比较存到数组中
    public void merge(int[] nums1, int m, int[] nums2, int n) {
       if (nums2 == null){
           return;
       }

       int cur1 = m - 1;
       int cur2 = n - 1;
       int index = m + n - 1;

       while (cur1 != -1 && cur2 != -1){
           nums1[index--] = nums1[cur1] < nums2[cur2] ? nums2[cur2--] : nums1[cur1--];
       }

       while (cur1 != -1){
           nums1[index--] = nums1[cur1--];
       }

        while (cur2 != -1){
            nums1[index--] = nums2[cur2--];
        }
    }

3.整体移动数组
题目:
给定一个数组,将数组中的元素向右移动 k 个位置,其中 k 是非负数。

思路1
k%length = 真实位移长度(k有可能大于数组长度)
(i+k)%length = 移动后所在的位置
    public static void rotate(int[] nums, int k) {
        if (nums == null){
            return;
        }

        int length = nums.length;
        int[] help = new int[length];

        // k % length = 真实移动长度
        //因为mod的是数组长度   ->  (0..n)%n
        //(i + k)%length =  真实数据

        for (int i =0;i < length;i++){
            help[(i + k)%length] = nums[i];
        }

        System.arraycopy(help, 0, nums, 0, length);
    }
思路2
翻转数组
k%length = 真实位移长度
1.先将数组对称翻转
2.再将 0 ~ k-1 的位置翻转
3.再将 k ~ length - 1 的位置翻转
    public static void rotate(int[] nums, int k) {
        //真实位移长度
        k = k % nums.length;

        reverse(nums, 0, nums.length - 1);
        reverse(nums, 0, k - 1);
        reverse(nums, k, nums.length - 1);
    }

    public static void reverse(int[] nums, int start, int end) {
        //数组一一翻转用while

        //双指针
        while (start < end) {
            int temp = nums[start];
            nums[start] = nums[end];
            nums[end] = temp;
            start += 1;
            end -= 1;
        }
    }

4.查找主要元素
题目:
数组中占比超过一半的元素称之为主要元素。给你一个 整数 数组,找出其中的主要元素。若没有,返回 -1 。
要求:
请设计时间复杂度为 O(N) 、空间复杂度为 O(1) 的解决方案。

思路:
Boyer-Moore 投票算法
从第一个元素开始遍历并计数
遇到相同数字则+1
遇到不同数字则-1
当数字减到0时则改变计数数字
    public static int  majorityElement(int[] nums){
        if (nums == null){
            return 0;
        }

        int curNumber = Integer.MIN_VALUE;
        int count = 0;

        for (int i = 0;i < nums.length;i++){
            if (count == 0){
                curNumber = nums[i];
            }

            if (curNumber == nums[i]){
                count++;
            }else {
                count--;
            }
        }

        count = 0;
        for (int i = 0;i < nums.length;i++){
            if (nums[i] == curNumber){
                count++;
            }
        }

        return count < (nums.length / 2) + 1 ? -1 : curNumber;
    }

5.三数之和
题目:
给你一个包含 n 个整数的数组 nums,判断 nums 中是否存在三个元素 a,b,c ,使得 a + b + c = 0 ?请你找出所有和为 0 且不重复的三元组。
要求:
答案中不可以包含重复的三元组

思路:
三指针(双指针+单指针)
1.先将数组排序
2.从头遍历结点
3.判断当前结点>0?,若>0.则说明后面的数之和肯定大于0
4.判断当前数与前一个数是否相同,相同直接跳下一个循环
5.两个指针分别指向当前数的下一个数 和 数组最后一个数
如果相加=0	->	则存起来
如果两指针跳的下一个数跟当前数相同	->	两指针直接下移
    public static List<List<Integer>> threeSum(int[] nums) {

        List<List<Integer>> listList = new ArrayList<>();

        Arrays.sort(nums);

        for (int i = 0;i < nums.length;i++){

            if (nums[i] > 0){
                return listList;
            }

            if (i > 0 && nums[i] == nums[i - 1]){
                continue;
            }

            int L = i + 1;
            int R = nums.length - 1;

            while (L < R){
                if (nums[i] + nums[L] + nums[R] == 0) {
                    List<Integer> list = new ArrayList<>();
                    list.add(nums[i]);
                    list.add(nums[L]);
                    list.add(nums[R]);
                    listList.add(list);

                    while (L < R && nums[L] == nums[L + 1]){
                        L++;
                    }
                    while (L < R && nums[R] == nums[R - 1]){
                        R--;
                    }
                    L++;
                    R--;
                }else if (nums[i] + nums[L] + nums[R] < 0){
                    L++;
                }else {
                    R--;
                }

            }
        }

        return listList;
    }

6.最大子序和

7.最长连续序列
题目:
给定一个未排序的整数数组 nums ,找出数字连续的最长序列(不要求序列元素在原数组中连续)的长度。

    //时间 96.77
    //空间 95.04
    public int longestConsecutive_1(int[] nums) {

        if (nums == null || nums.length == 0){
            return 0;
        }

        Arrays.sort(nums);
        //记录当前最大长度
        int curRes = 1;
        //记录返回值最大长度
        int res = 1;
        //记录数组长度
        int length = nums.length;
        for (int i = 1; i < length; i++) {
            //相同的不需要判断
            if (nums[i] == nums[i - 1]){
                continue;
            } else if (nums[i] == nums[i - 1] + 1){
                curRes++;
            }else {
                curRes = 1;
            }
            res = Math.max(res,curRes);
        }
        return res;
    }
    //时间 31
    //空间 45.89
    public int longestConsecutive_2(int[] nums) {

        if (nums == null || nums.length == 0){
            return 0;
        }

        HashSet<Integer> set = new HashSet<>();
        for (int i:
             nums) {
            set.add(i);
        }

        int res = 0;
        for (int i:
             nums) {
            if (set.contains(i - 1)){
                continue;
            }
            //记录当前数的值 和 当前长度
            int cur = i;
            while (set.contains(cur + 1)){
                cur++;
            }
            //cur - i + 1 为区间长度
            res = Math.max(res,cur - i + 1);
        }
        return res;
    }

8.加1
题目:
给定两个字符串形式的非负整数 num1 和num2 ,计算它们的和并同样以字符串形式返回。
你不能使用任何內建的用于处理大整数的库(比如 BigInteger), 也不能直接将输入的字符串转换为整数形式。

    //时间 95.45%
    //空间 96.55%
    public String addStrings(String num1, String num2) {
        //记录两个指针 和 判断是否有进位
        int i = num1.length() - 1, j = num2.length() - 1, add = 0;
        StringBuffer ans = new StringBuffer();

        while (i >= 0 || j >= 0 || add != 0) {
            //当位数不足时,补零
            int x = i >= 0 ? num1.charAt(i) - '0' : 0;
            int y = j >= 0 ? num2.charAt(j) - '0' : 0;
            int result = x + y + add;
            //result模10即为位数上的数
            ans.append(result % 10);
            //add/10即为进位数
            add = result / 10;
            i--;
            j--;
        }
        // 计算完以后的答案需要翻转过来
        ans.reverse();
        return ans.toString();
    }

9.数组全排列

    //时间 20.78
    //空间 66.76
    public List<List<Integer>> permute(int[] nums) {
        List<List<Integer>> res = new LinkedList<>();
        if (nums == null || nums.length == 0){
            return res;
        }

        allPermute(nums,0,res);
        return res;
    }

    public void allPermute(int[] nums, int curIndex, List<List<Integer>> res) {
        if(curIndex == nums.length - 1) {
            List<Integer> list = new ArrayList<>();
            for (int num:
                 nums) {
                list.add(num);
            }
            res.add(list);          // 添加排列方案
            return;
        }
        //Set判断是否有重复字符
        HashSet<Integer> set = new HashSet<>();

        int length = nums.length;
        for(int i = curIndex; i <= length - 1; i++) {
            if(set.contains(nums[i])) continue;    // 重复,因此剪枝
            set.add(nums[i]);

            //先固定第i为
            swap(nums,i, curIndex);                   // 交换,将 c[i] 固定在第 x 位
            allPermute(nums, curIndex+ 1,res);          // 开启固定第 x + 1 位字符
            swap(nums,i, curIndex);                   // 恢复交换
        }

    }

    public void swap(int[] arr,int a, int b) {
        int tmp = arr[a];
        arr[a] = arr[b];
        arr[b] = tmp;
    }
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值