面试+算法之数组:多数元素、两数之和、三数之和、股票交易最大利润、连续元素最大求和、未出现的最小正整数、排序数组求某元素的索引位置、不重复的元素

概述

算法是一个程序员的核心竞争力,也是面试最重要的考查环节。本文整理一些与数组相关的基础算法题。

注:题目均搜集自网络,仅做汇总整理备忘录用。

考题

多数元素

给定一个大小为n的数组,找到其中的多数元素和出现次数。多数元素:在数组中出现次数大于 ⌊n/2⌋ 的元素。

假定:数组非空且总是存在多数元素。

要求:时间复杂度为O(n)、空间复杂度为O(1)

public static int getMajority(int[] nums) {
    int count = 0;
    int result = 0;
    for (int item : nums) {
        if (item == result) {
            count += 1;
        } else {
            if (count == 0) {
                result = item;
                count = 1;
            } else {
                count -= 1;
            }
        }
    }
    return result;
}

两数之和

从给定的数组nums里面找到满足条件的两个数,使其和为目标值target。返回满足条件的一组结果即可,返回索引值。

分析:结果存在多种情况,题目要求只返回一种:

public static int[] twoSum(int[] nums, int target) {
    int[] answer = new int[2];
    int n = nums.length;
    for (int i = 0; i < n - 1; i++) {
        int t = target - nums[i];
        answer[0] = i + 1;
        for (int j = i + 1; j < n; j++) {
            if (nums[j] > t) {
                break;
            }
            if (nums[j] == t) {
                answer[1] = j + 1;
                break;
            }
        }
        if (answer[1] != 0) {
            break;
        }
    }
    return answer;
}

如果需要返回全部满足条件的组合呢?

组合总和

给定一个无重复元素的数组nums和目标数 target,找出nums中所有可以使数字和为target的组合。

注:nums中的数字可以无限制重复被选取,组合不能重复。

public static List<List<Integer>> combinationSum(int[] nums, int target) {
    List<List<Integer>> resultList = new ArrayList<>();
    List<Integer> result = new ArrayList<>();
    Arrays.sort(nums);
    dfs(nums, resultList, result, 0, target);
    return resultList;
}

private static void dfs(int[] nums, List<List<Integer>> resultList, List<Integer> result, int start, int target) {
    if (target >= 0) {
        if (target == 0) {
            resultList.add(new ArrayList<>(result));
        } else {
            for (int i = start; i < nums.length; i++) {
                result.add(nums[i]);
                dfs(nums, resultList, result, i, target - nums[i]);
                result.remove(result.size() - 1);
            }
        }
    }
}

三数之和

股票交易的最大利润

给定一个非负整数元素组成的数组,其中的元素值表示股票的每日价格,求能获得的股票交易最大利润。

注:股票交易必须先买入,后卖出;可以多次买入卖出;只有卖出后才能获取到利润。

示例:
输入:[3, 5, 4, 3, 1, 4]
输出:5

public static int maxProfit(int[] prices) {
    int temp = 0;
    // 终止条件为length-1,防止数组越界
    for (int i = 0; i < prices.length - 1; i++) {
        if (prices[i + 1] > prices[i]) {
            temp = temp + prices[i + 1] - prices[i];
        }
    }
    return temp;
}

连续元素的最大和

给定一个包含负数的整数数组,求连续元素的最大求和。

public static int maxSubArray(int[] nums) {
    int maxSum = nums[0];
    int curSum = 0;
    for (int n : nums) {
        curSum += n;
        if (curSum > maxSum) {
            maxSum = curSum;
        }
        if (curSum < 0) {
            curSum = 0;
        }
    }
    return maxSum;
}

未出现的最小正整数

给你一个未排序的整数数组 nums ,找出其中未出现的最小正整数。

public static int firstMissingPositive(int[] nums) {
    int ls = nums.length;
    int index = 0;
    while (index < ls) {
    	// 正数; while循环结束条件;
        if (nums[index] <= 0 || nums[index] > ls || nums[nums[index] - 1] == nums[index]) {
            index += 1;
        } else {
            int pos = nums[index] - 1;
            int tmp = nums[index];
            nums[index] = nums[pos];
            nums[pos] = tmp;
        }
    }
    int res = 0;
    return res + 1;
}

排序数组求某元素的索引位置

给定一个升序排列的整数数组nums,目标值target。找出给定目标值在数组中的开始位置和结束位置;如果数组中不存在目标值 target,返回[-1, -1]

注:元素可能不存在,也可能出现不止2次。

public static int[] searchRange(int[] nums, int target) {
    int[] result = new int[2];
    result[0] = floor(nums, target);
    result[1] = ceil(nums, target);
    return result;
}

private static int floor(int[] nums, int target) {
    int left = -1;
    int right = nums.length - 1;
    while (left < right) {
        int mid = left + (right - left + 1) / 2;
        if (target <= nums[mid]) {
            right = mid - 1;
        } else {
            left = mid;
        }
    }
    if (left + 1 < nums.length && nums[left + 1] == target) {
        return left + 1;
    } else {
        return -1;
    }
}

private static int ceil(int[] nums, int target) {
    int left = 0;
    int right = nums.length;
    while (left < right) {
        int mid = left + (right - left) / 2;
        if (target >= nums[mid]) {
            left = mid + 1;
        } else {
            right = mid;
        }
    }
    if (right - 1 >= 0 && nums[right - 1] == target) {
        return right - 1;
    } else {
        return -1;
    }
}

不重复的元素

给定一个包含若干重复元素的数组,找出第一个未重复的元素。

分析:存在重复2次或以上的情况;存在多个元素未重复的情况。

public static int singleNumber(int[] nums) {
    Arrays.sort(nums);
    int res = 0;
    int i = 0;
    for (int j = 1; j < nums.length; j++) {
        if (nums[j] != nums[i]) {
            if (j - i == 1) {
                res = nums[i];
                break;
            } else {
                i = j;
            }
        }
    }
    if (i == nums.length - 1) {
        res = nums[i];
    }
    return res;
}

搜索并插入有序数组

给定一个有序数组,和目标值target,将target插入到数组中,返回其索引值。

分析:数组可能包括负数,可能存在重复值,目标值也可能与数组元素重复。

public static int searchInsert(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    if (target < nums[left]) {
        return 0;
    }
    if (target > nums[right]) {
        return nums.length;
    }
    while (left <= right) {
        int mid = (right - left) / 2 + left;
        if (target < nums[mid]) {
            right = mid - 1;
        } else if (target > nums[mid]) {
            left = mid + 1;
        } else {
            return mid;
        }
    }
    return left;
}

数组元素可组成的最大数

给定一组非负整数 nums,重新排列每个数的顺序(每个数不可拆分)使之组成一个最大的整数。注:输出结果可能非常大,返回一个字符串。
示例:
输入:[3, 30, 34, 5, 9]
输出:9534330

public static String largest(int[] nums) {
    int n = nums.length;
    for (int i = 0; i < n; i++) {
        for (int j = 0; j < n - i - 1; j++) {
            String tmp1 = String.valueOf(nums[j]);
            String tmp2 = String.valueOf(nums[j + 1]);
            if ((tmp1 + tmp2).compareTo(tmp2 + tmp1) < 0) {
                int tmp = nums[j];
                nums[j] = nums[j + 1];
                nums[j + 1] = tmp;
            }
        }
    }
    StringBuilder re = new StringBuilder();
    for (int item : nums) {
        re.append(item);
    }
    return re.toString();
}

跳跃游戏

给定一个非负整数数组,最初位于数组的第一个位置。数组中的每个元素代表你在该位置可以跳跃的最大长度。

目标:使用最少的跳跃次数到达数组的最后一个位置。

public static int jump(int[] nums) {
    int end = 0;
    int steps = 0;
    int maxPosition = 0;
    // 不能等于length-1
    for (int i = 0; i < nums.length - 1; i++) {
        maxPosition = Math.max(maxPosition, i + nums[i]);
        if (i == end) {
            end = maxPosition;
            steps++;
        }
    }
    return steps;
}

移除元素

给定一个数组nums和目标值target,原地移除所有数值等于target的元素,返回移除后数组的新长度。

注:不能使用额外的数组空间,必须仅使用 O(1) 额外空间并原地修改输入数组。
元素的顺序可以改变。你不需要考虑数组中超出新长度后面的元素。

public static int removeElement(int[] nums, int target) {
    int len = nums.length;
    for (int i = 0; i < len; ) {
        if (nums[i] == target) {
            nums[i] = nums[len - 1];
            len--;
        } else {
            i++;
        }
    }
    log.info(Arrays.toString(Arrays.stream(nums).limit(len).toArray()));
    return len;
}

盛水最多

给定一个数组,数组每个元素值表示其高度值,单位值为1,每两个元素间隔单位值为1。为简化问题,假设水的宽度为单位1。求能盛水的最大体积。

示例:
输入:[1, 8, 6, 2, 5, 4, 8, 3, 7]
输出:49

public static int maxArea(int[] height) {
    int ret = 0;
    int temp;
    int j = height.length - 1;
    for (int i = 0; i < j; ) {
        temp = Math.min(height[i], height[j]) * (j - i);
        ret = Math.max(ret, temp);
        if (height[i] > height[j]) {
            j--;
        } else {
            i++;
        }
    }
    return ret;
}

参考

posted @   johnny233  阅读(44)  评论(0编辑  收藏  举报  
相关博文:
阅读排行:
· Manus重磅发布:全球首款通用AI代理技术深度解析与实战指南
· 被坑几百块钱后,我竟然真的恢复了删除的微信聊天记录!
· 没有Manus邀请码?试试免邀请码的MGX或者开源的OpenManus吧
· 园子的第一款AI主题卫衣上架——"HELLO! HOW CAN I ASSIST YOU TODAY
· 【自荐】一款简洁、开源的在线白板工具 Drawnix
历史上的今天:
2020-02-26 一文总结Java开发各种锁
2019-02-26 Java学习之NoClassDefFoundError、ClassNotFoundException、NoSuchMethodError
点击右上角即可分享
微信分享提示