想要精通算法和SQL的成长之路 - 下一个更大元素II

想要精通算法和SQL的成长之路 - 下一个更大元素II

前言

想要精通算法和SQL的成长之路 - 系列导航

一. 下一个更大元素 II

原题链接

给定一个循环数组 numsnums[nums.length - 1] 的下一个元素是 nums[0] ),返回 nums 中每个元素的 下一个更大元素 。

数字 x 的 下一个更大的元素 是按数组遍历顺序,这个数字之后的第一个比它更大的数,这意味着你应该循环地搜索它的下一个更大的数。如果不存在,则输出 -1

示例 1:

  • 输入: nums = [1,2,1]
  • 输出: [2,-1,2]
  • 解释: 第一个 1 的下一个更大的数是 2;数字 2 找不到下一个更大的数; 第二个 1 的下一个最大的数需要循环搜索,结果也是 2。

1.1 暴力法

这里的暴力和 下一个更大元素I 很相似。唯一的不同就是:从两个数组变成了一个数组(只不过可以循环)

整体思路:

  • 两层for循环。
  • 由于数组模拟的是循环数组,因此我们在原数组的基础上再拼接一个数组即可。这里可以用Arrays.copyOf进行拷贝。
public int[] nextGreaterElements(int[] nums) {
    int len = nums.length;
    // 因为循环数组的原因,我们用两个循环拼接成一个大数组
    int[] tmp = Arrays.copyOf(nums, 2 * len);
    // 拷贝后半部分数据
    for (int i = len; i < tmp.length; i++) {
        tmp[i] = nums[i - len];
    }
    int[] res = new int[len];
    for (int i = 0; i < nums.length; i++) {
        // 找不到更大值时的默认值是-1
        res[i] = -1;
        // 从当前下标往后遍历,找到第一个值更大的
        for (int j = i + 1; j < tmp.length - 1; j++) {
            if (tmp[j] > nums[i]) {
                res[i] = tmp[j];
                break;
            }
        }
    }
    return res;
}

当然,也可以不需要拷贝数组,通过 下标的一个取模计算 同样能实现循环。

public int[] nextGreaterElements(int[] nums) {
    int len = nums.length;
    int[] res = new int[len];
    for (int i = 0; i < len; i++) {
        // 找不到更大值时的默认值是-1
        res[i] = -1;
        // 从当前下标往后遍历,找到第一个值更大的
        for (int j = i + 1; j < 2 * len - 1; j++) {
            // 对下标进行取模,就不会越界,同时实现了循环的一个下标计算
            int index = j % len;
            if (nums[index] > nums[i]) {
                res[i] = nums[index];
                break;
            }
        }
    }
    return res;
}

1.2 单调栈

思路:

  1. 发现我们要找下一个比当前元素更大的元素。那么我们就使用单调递增栈
  2. 默认值可以提前给数组赋值-1。
  3. 入栈的是数组下标(记得取模处理)。出栈的条件则是:当前元素 > 栈顶元素(栈顶元素最大)。
  4. 这样每个元素最多遍历两遍,最少一次。可以说是O(n)

最终代码如下:

public int[] nextGreaterElements(int[] nums) {
    int len = nums.length;
    int[] res = new int[len];
    // 赋默认值:-1
    Arrays.fill(res, -1);
    // 单调栈
    LinkedList<Integer> stack = new LinkedList<>();
    // 遍历长度:两个数组长度大小
    for (int i = 0; i < len * 2; i++) {
        // 记得对下标进行取模,否则会越界,因为我们取值来源还是原数组
        int index = i % len;
        // 如果发现 当前元素 > 栈顶(单调递增),说明 当前元素 就是 栈顶元素 的下一个更大的值
        while (!stack.isEmpty() && nums[stack.peek()] < nums[index]) {
            // 弹出其下标,赋值当前元素给返回结果
            res[stack.pop()] = nums[index];
        }
        // 下标索引入栈
        stack.push(index);
    }
    return res;
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
作为一个专业的算法工程师,有一些关键的内容是值得学习和掌握的。以下是一些重要的学习内容: 1. 数据结构:深入理解各种数据结构,包括数组、链表、栈、队列、树、图等,以及它们的特性、操作和应用场景。 2. 算法设计与分析:学习常见的算法设计技巧,如贪心算法、动态规划、分治法等,以及算法的时间复杂度和空间复杂度分析。 3. 算法优化与调优:了解常见的算法优化技巧,如剪枝、缓存、并行计算等,以提高算法的效率和性能。 4. 编程语言和工具:精通至少一门编程语言,并了解常用的算法库和工具,如Python、C++、Java等,以实现和优化算法。 5. 计算机体系结构:了解计算机硬件的基本原理和结构,包括内存、CPU、缓存等,以便更好地理解算法在计算机上的执行。 6. 数学基础:具备扎实的数学基础,包括离散数学、概率论、线性代数等,以便理解和分析算法背后的数学原理。 7. 数据库和数据处理:了解数据库系统和数据处理技术,如SQL、NoSQL、数据清洗和转换等,以处理和分析大规模数据。 8. 机器学习和人工智能:熟悉机器学习算法和模型,了解常用的机器学习框架和工具,如TensorFlow、PyTorch等。 9. 算法应用和实践:通过实际项目和实验,将学到的算法应用于实际问题,并进行调试、测试和优化。 10. 持续学习和研究:算法领域不断发展和演进,作为算法工程师,需要保持持续学习的态度,关注最新的研究进展和技术趋势。 以上只是一些基本的内容,算法工程师还可以根据自己的兴趣和领域需求进行更深入的学习和专研。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

Zong_0915

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值