【算法面试题汇总】LeetBook列表的算法面试题汇总---数组题目及答案

如果有错的还请各位大佬指出呀
有些是copy的还望不要介意
本人只做学习记录

乘积最大子数组

题目描述:

  给你一个整数数组 nums ,请你找出数组中乘积最大的非空连续子数组(该子数组中至少包含一个数字),并返回该子数组所对应的乘积。

  测试用例的答案是一个 32-位 整数。

  子数组 是数组的连续子序列。

示例:

输入: nums = [2,3,-2,4]
输出: 6
解释: 子数组 [2,3] 有最大乘积 6。
  • 代码实现
class Solution {
    public int maxProduct(int[] nums) {
        int max = Integer.MIN_VALUE,mx = 1,mi = 1;
        for(int i=0;i<nums.length;i++){
            //出现负数时,会导致大的变小,小的变大
            //mx=6 6*(-2)=-12 mi=3 3*(-2)=-6
            //所以先交换mx和mi再进行计算
            //这也是为什么要维护mi的原因
            if(nums[i]<0){
                int temp = mx;
                mx = mi;
                mi = temp;
            }
            mx = Math.max(mx*nums[i],nums[i]);
            mi = Math.min(mi*nums[i],nums[i]);

            max = Math.max(max,mx);
        }
        return max;
    }
}

多数元素

题目描述:

  给定一个大小为 n 的数组 nums ,返回其中的多数元素。多数元素是指在数组中出现次数 大于 ⌊ n/2 ⌋ 的元素。

  你可以假设数组是非空的,并且给定的数组总是存在多数元素。

示例:

输入:nums = [2,2,1,1,1,2,2]
输出:2
  • 排序
class Solution {
    public int majorityElement(int[] nums) {
        Arrays.sort(nums);
        return nums[nums.length/2];
    }
}
  • Boyer-Moore 投票
class Solution {
    public int majorityElement(int[] nums) {
        //先假设第一个数是众数,票数为1
        int num = nums[0],count = 1;
        for(int i=1;i<nums.length;i++){
            //与假设的众数值相同则票数+1
            if(num == nums[i]){
                count++;
            }else{
                //值不同则-1
                count--;
                //若此时票数为0了,则替换众数
                if(count==0){
                    num = nums[i];
                    count = 1;
                }
            }
        }
        //因为存在多数元素,所以每个众数元素与其他元素进行抵消,剩下的便是众数
        return num;
    }
}

旋转数组

题目描述:

  给你一个数组,将数组中的元素向右轮转 `k` 个位置,其中 `k` 是非负数

示例:

输入: nums = [1,2,3,4,5,6,7], k = 3
输出: [5,6,7,1,2,3,4]
解释:
向右轮转 1 步: [7,1,2,3,4,5,6]
向右轮转 2 步: [6,7,1,2,3,4,5]
向右轮转 3 步: [5,6,7,1,2,3,4]
  • 额外的数组
class Solution {
    public void rotate(int[] nums, int k) {
        int n = nums.length;
        //防止原本的数丢失
        int[] newNums = new int[n];
        for(int i = 0;i<n;i++){
            //k可能大过n
            newNums[(i+k)%n] = nums[i];
        } 
        //深拷贝,源数组,原数组起始位置,目标数组,目标数组起始位置,复制的元素数量
        System.arraycopy(newNums,0,nums,0,n);
    }
}

进阶:

尽可能想出更多的解决方案,至少有 **三种** 不同的方法可以解决这个问题。
你可以使用空间复杂度为 `O(1)` 的 **原地** 算法解决这个问题吗?
  • 翻转数组
class Solution {
    public void rotate(int[] nums, int k) {
        //k可能大于n,直接取余可以获取最终位置
        k = k%nums.length;
        //先将整个数组反转
        reverse(nums,0,nums.length-1);
        //以k为切割分别反转
        reverse(nums,0,k-1);
        reverse(nums,k,nums.length-1);
    }
    private void reverse(int[] nums,int i,int j){
        while(i<j){
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
            i++;
            j--;
        }
    }
}

存在重复元素

题目描述:

  给你一个整数数组 `nums` 。如果任一值在数组中出现 **至少两次** ,返回 `true` ;如果数组中每个元素互不相同,返回 `false` 。

示例:

  输入:nums = [1,2,3,1]
  输出:true
  • 排序
    时间O(nlogn)空间O(logn)
class Solution {
    public boolean containsDuplicate(int[] nums) {
        Arrays.sort(nums);
        int n = nums.length;
        for(int i=0;i<n-1;i++){
            //排好序后相邻的相等
            if(nums[i] == nums[i+1]){
                return true;
            }
        }
        return false;
    }
}
  • 哈希表
    时间O(n),空间O(n)
class Solution {
    public boolean containsDuplicate(int[] nums) {
        Set<Integer> set = new HashSet<>();
        for(int i=0;i<nums.length;i++){
            //hashset如果插入已存在的元素则会返回false
            if(!set.add(nums[i])){
                return true;
            }
        }
        return false;
    }
}

移动零

题目描述:

  给定一个数组 `nums`,编写一个函数将所有 `0` 移动到数组的末尾,同时保持非零元素的相对顺序。

请注意 ,必须在不复制数组的情况下原地对数组进行操作。

示例:

输入: nums = [0,1,0,3,12]
输出: [1,3,12,0,0]

进阶: 你能尽量减少完成的操作次数吗?

  • 代码实现

    时间O(n)空间O(1)

class Solution {
    public void moveZeroes(int[] nums) {
        if(nums == null){
            return;
        }
        int i=0,j = 0;
        for(;i<nums.length;i++){
            if(nums[i] != 0){
                int temp = nums[i];
                nums[i] = nums[j];
                nums[j++] = temp;
            }
        }
    }
}

打乱数组

题目描述:

  给你一个整数数组 nums ,设计算法来打乱一个没有重复元素的数组。打乱后,数组的所有排列应该是 等可能 的。

  实现 Solution class:

    Solution(int[] nums) 使用整数数组 nums 初始化对象
	int[] reset() 重设数组到它的初始状态并返回
	int[] shuffle() 返回数组随机打乱后的结果

示例:

输入
["Solution", "shuffle", "reset", "shuffle"]
[[[1, 2, 3]], [], [], []]
输出
[null, [3, 1, 2], [1, 2, 3], [1, 3, 2]]

解释
Solution solution = new Solution([1, 2, 3]);
solution.shuffle();    // 打乱数组 [1,2,3] 并返回结果。任何 [1,2,3]的排列返回的概率应该相同。例如,返回 [3, 1, 2]
solution.reset();      // 重设数组到它的初始状态 [1, 2, 3] 。返回 [1, 2, 3]
solution.shuffle();    // 随机返回数组 [1, 2, 3] 打乱后的结果。例如,返回 [1, 3, 2]
  • 代码实现
class Solution {
    int[] nums;
    int[] tnums;
    
    public Solution(int[] nums) {
        this.nums = nums;
        this.tnums = new int[nums.length];
        //调用java内存模型中本地方法栈区
        System.arraycopy(nums,0,tnums,0,nums.length);
    }
    
    public int[] reset() {
        return tnums;
    }
    
    public int[] shuffle() {
        //洗牌算法
        Random random = new Random();
        int n = nums.length;
        for(int i=0;i<n;i++){
            int j = i+random.nextInt(n - i);
            int temp = nums[i];
            nums[i] = nums[j];
            nums[j] = temp;
        }
        return nums;
    }
}

/**
 * Your Solution object will be instantiated and called as such:
 * Solution obj = new Solution(nums);
 * int[] param_1 = obj.reset();
 * int[] param_2 = obj.shuffle();
 */

两个数组的交集Ⅱ

题目描述:

  给你两个整数数组 nums1 和 nums2 ,请你以数组形式返回两数组的交集。返回结果中每个元素出现的次数,应与元素在两个数组中都出现的次数一致(如果出现次数不一致,则考虑取较小值)。可以不考虑输出结果的顺序。

示例:

输入:nums1 = [1,2,2,1], nums2 = [2,2]
输出:[2,2]
进阶:

  如果给定的数组已经排好序呢?你将如何优化你的算法?
  如果 nums1 的大小比 nums2 小,哪种方法更优?
  如果 nums2 的元素存储在磁盘上,内存是有限的,并且你不能一次加载所有的元素到内存中,你该怎么办?
  • 哈希表

    时间O(m+n)空间O(min(m,n))

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        if(nums1.length > nums2.length){
            intersect(nums2,nums1);
        }

        Map<Integer,Integer> map = new HashMap<>();
        for(int num:nums1){
            int count = map.getOrDefault(num,0) + 1;
            map.put(num,count);
        }

        int[] temp = new int[nums1.length];
        int index = 0;
        for(int num:nums2){
            int count = map.getOrDefault(num,0);
            if(count > 0){
                temp[index++] = num;
                count--;
                if(count > 0){
                    map.put(num,count);
                }else{
                    map.remove(num);
                }
            }
        }
        return Arrays.copyOfRange(temp,0,index);
    }
}
  • 双指针

    时间O(mlogm+nlogn),空间O(min(m,n))

class Solution {
    public int[] intersect(int[] nums1, int[] nums2) {
        Arrays.sort(nums1);
        Arrays.sort(nums2);
        int length1 = nums1.length,length2 = nums2.length;
        int[] temp = new int[Math.min(length1,length2)];
        int i = 0,j = 0,index = 0;
        while(i<length1 && j<length2){
            //两个元素不相等则小的那个指针右移动
            if(nums1[i] < nums2[j]){
                i++;
            }else if(nums1[i] > nums2[j]){
                j++;
            }else if(nums1[i] == nums2[j]){
                //相等则添加,并指针都右移
                temp[index] = nums1[i];
                index++;
                i++;
                j++;
            }
        }
        return Arrays.copyOfRange(temp,0,index);
    }
}

递增的三元子序列

题目描述:

  给你一个整数数组 nums ,判断这个数组中是否存在长度为 3 的递增子序列。

  如果存在这样的三元组下标 (i, j, k) 且满足 i < j < k ,使得 nums[i] < nums[j] < nums[k] ,返回 true ;否则,返回 false 。

示例:

输入:nums = [1,2,3,4,5]
输出:true
解释:任何 i < j < k 的三元组都满足题意

进阶: 你能实现时间复杂度为 O(n) ,空间复杂度为 O(1) 的解决方案吗?

  • 贪心

    时间O(n)空间O(1)

class Solution {
    public boolean increasingTriplet(int[] nums) {
        int f = nums[0],s = Integer.MAX_VALUE;
        int n = nums.length;
        if(n < 3){
            return false;
        }
        //保证第二个值比第一个值大,此时只要找到第三个数便可
        for(int i=1;i<n;i++){
            if(nums[i] > s){
                //如果第三个数比第二个数大则满足
                return true;
            }else if(nums[i] > f){
                //比第二个数小比第一个数大则将该值赋给第二个数,继续找第三个数
                s = nums[i];
            }else{
                //比第一个数小则将该值赋给第一个数,此时新的第一个值就在旧第二个值前面
                f = nums[i];
            }
        }
        return false;
    }
}

搜索二维矩阵Ⅱ

题目描述:

  编写一个高效的算法来搜索 m x n 矩阵 matrix 中的一个目标值 target 。该矩阵具有以下特性:

  每行的元素从左到右升序排列。
  每列的元素从上到下升序排列。

示例:
在这里插入图片描述

输入:matrix = [[1,4,7,11,15],
				[2,5,8,12,19],
				[3,6,9,16,22],
				[10,13,14,17,24],
				[18,21,23,26,30]], target = 5
输出:true
  • 代码实现
class Solution {
    public boolean searchMatrix(int[][] matrix, int target) {
        int row = matrix.length - 1;
        int col = matrix[0].length;
        int temp=0;

        while(row>=0 || temp<=col-1){
            if(matrix[row][temp] == target){
                return true;
            }else if(matrix[row][temp] < target){
                temp++;
                if(temp > col-1) return false;
            }else if(matrix[row][temp] > target){
                row--;
                if(row < 0) return false;
            }
        }
        return false;
    }
}

除自身以外数组的乘积

题目描述:

  给你一个整数数组 nums,返回 数组 answer ,其中 answer[i] 等于 nums 中除 nums[i] 之外其余各元素的乘积 。

  题目数据 保证 数组 nums之中任意元素的全部前缀元素和后缀的乘积都在  32 位 整数范围内。

  请不要使用除法,且在 O(n) 时间复杂度内完成此题

进阶:你可以在 O(1) 的额外空间复杂度内完成这个题目吗?( 出于对空间复杂度分析的目的,输出数组**不被视为额外空间。)

示例:

输入: nums = [1,2,3,4]
输出: [24,12,8,6]
  • 代码实现
class Solution {
    public int[] productExceptSelf(int[] nums) {
        int n = nums.length;
        int[] answer = new int[n];
        int l=1,r = 1;
        for(int i=0;i<n;i++){
            answer[i] = l;
            l *= nums[i];
        }
        for(int i = n-1;i>0;i--){
            r *= nums[i];
            //该位置的值等于左边所有的元素乘积乘以右边所有元素的乘积
            answer[i-1] *= r;
        }
        return answer;
    }
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值