LeetCode算法小抄--田忌赛马问题、游戏随机匹配机制问题

简介: LeetCode算法小抄--田忌赛马问题、游戏随机匹配机制问题

田忌赛马问题

870. 优势洗牌

给定两个大小相等的数组 nums1nums2nums1 相对于 nums2优势可以用满足 nums1[i] > nums2[i] 的索引 i 的数目来描述。

返回 nums1 的任意排列,使其相对于 nums2 的优势最大化。

思路:

给你输入两个长度相等的数组 nums1nums2,请你重新组织 nums1 中元素的位置,使得 nums1 的「优势」最大化。

如果 nums1[i] > nums2[i],就是说 nums1 在索引 i 上对 nums2[i] 有「优势」。优势最大化也就是说让你重新组织 nums1尽可能多的让 nums1[i] > nums2[i]

class Solution {
    public int[] advantageCount(int[] nums1, int[] nums2) {
        int n = nums1.length;
        // 给 nums2 降序排序
        PriorityQueue<int[]> maxpq = new PriorityQueue<>(
            (int[] pair1, int[] pair2)->{
                return pair2[1] - pair1[1];
            }
        );
        for(int i = 0; i< n; i++){
            maxpq.offer(new int[]{i, nums2[i]});
        }
        // 给 nums1 升序排序
        Arrays.sort(nums1);
        // nums1[left] 是最小值,nums1[right] 是最大值
        int left = 0, right = n - 1;
        int[] res = new int[n];
        while (!maxpq.isEmpty()) {
            int[] pair = maxpq.poll();
            // maxval 是 nums2 中的最大值,i 是对应索引
            int i = pair[0], maxval = pair[1];
            if (maxval < nums1[right]) {
                // 如果 nums1[right] 能胜过 maxval,那就自己上
                res[i] = nums1[right];
                right--;
            } else {
                // 否则用最小值混一下,养精蓄锐
                res[i] = nums1[left];
                left++;
            }
        }
        return res;
    }
}

带权重的随机选择算法

算法框架

class Solution {
    // 前缀和数组
    private int[] preSum;
    private Random rand = new Random();
    public Solution(int[] w) {
        int n = w.length;
        // 构建前缀和数组,偏移一位留给 preSum[0]
        preSum = new int[n + 1];
        preSum[0] = 0;
        // preSum[i] = sum(w[0..i-1])
        for (int i = 1; i <= n; i++) {
            preSum[i] = preSum[i - 1] + w[i - 1];
        }
    }
    public int pickIndex() {
        int n = preSum.length;
        // Java 的 nextInt(n) 方法在 [0, n) 中生成一个随机整数
        // 再加一就是在闭区间 [1, preSum[n - 1]] 中随机选择一个数字
        int target = rand.nextInt(preSum[n - 1]) + 1;
        // 获取 target 在前缀和数组 preSum 中的索引
        // 别忘了前缀和数组 preSum 和原始数组 w 有一位索引偏移
        return left_bound(preSum, target) - 1;
    }
    // 搜索左侧边界的二分搜索
    private int left_bound(int[] nums, int target) {
    int left = 0, right = nums.length - 1;
    // 搜索区间为 [left, right]
    while (left <= right) {
        int mid = left + (right - left) / 2;
        if (nums[mid] < target) {
            // 搜索区间变为 [mid+1, right]
            left = mid + 1;
        } else if (nums[mid] > target) {
            // 搜索区间变为 [left, mid-1]
            right = mid - 1;
        } else if (nums[mid] == target) {
            // 收缩右侧边界
            right = mid - 1;
        }
    }
    // 判断 target 是否存在于 nums 中
    // 此时 target 比所有数都大,返回 -1
    if (left == nums.length) return -1;
    // 判断一下 nums[left] 是不是 target
    return nums[left] == target ? left : -1;
  }
}

528. 按权重随机选择[Cisco笔试题]

给你一个 下标从 0 开始 的正整数数组 w ,其中 w[i] 代表第 i 个下标的权重。

请你实现一个函数 pickIndex ,它可以 随机地从范围 [0, w.length - 1] 内(含 0w.length - 1)选出并返回一个下标。选取下标 i概率w[i] / sum(w)

  • 例如,对于 w = [1, 3],挑选下标 0 的概率为 1 / (1 + 3) = 0.25 (即,25%),而选取下标 1 的概率为 3 / (1 + 3) = 0.75(即,75%)。

思路:

1、根据权重数组 w 生成前缀和数组 preSum

2、生成一个取值在 preSum 之内的随机数,用二分搜索算法寻找大于等于这个随机数的最小元素索引。

3、最后对这个索引减一(因为前缀和数组有一位索引偏移),就可以作为权重数组的索引,即最终答案

前缀和数组中 0 本质上是个占位符

class Solution {
    private Random random = new Random();
    private int[] preSum;
    private int n;
    public Solution(int[] w) {
        this.n = w.length;
        // 前缀数组,下标0就是原数组w[0]
        preSum = new int[n];
        // 下标0就是原数组w[0]
        preSum[0] = w[0];
        for (int i = 1; i < n; i++) {
            preSum[i] = preSum[i-1] + w[i];
        }
    }
    public int pickIndex() {
        // 保证取到[1, preSum[n-1]]的闭区间
        int target = random.nextInt(preSum[n-1]) + 1;
        // right可以从n-1开始,也可以从n开始,对结果的正确性没有影响
        int left = 0, right = n;
        while (left < right) {
            int mid = left + (right - left) / 2;
            // 如果找到了,直接去当前的下标
            if (preSum[mid] == target) {
                left =mid;
                break;
            } else if (preSum[mid] > target) {
                // 向左找,因为当前mid的值大于target,可能是"第一个大于target"的值,所以不能丢弃mid
                // 如果mid的值不再需要了(最终不会取到现在的mid),那么就可以right=mid-1;
                right = mid;
            } else {
                // 向右找,因为当前的mid的值比target小,永远不会取到了。所以left=mid+1;
                left = mid + 1;
            }
        }
        // left代表的含义:
        // 当目标元素 target 不存在数组 nums 中时,搜索左侧边界的二分搜索的返回值可以做以下几种解读:
        // 1、返回的这个值是 nums 中大于等于 target 的最小元素索引。
        // 2、返回的这个值是 target 应该插入在 nums 中的索引位置。
        // 3、返回的这个值是 nums 中小于 target 的元素个数。
        return left;
    }
}

下面这道题目和上面👆一模一样

剑指 Offer II 071. 按权重生成随机数

给定一个正整数数组 w ,其中 w[i] 代表下标 i 的权重(下标从 0 开始),请写一个函数 pickIndex ,它可以随机地获取下标 i,选取下标 i 的概率与 w[i] 成正比。

例如,对于 w = [1, 3],挑选下标 0 的概率为 1 / (1 + 3) = 0.25 (即,25%),而选取下标 1 的概率为 3 / (1 + 3) = 0.75(即,75%)。

也就是说,选取下标 i 的概率为 w[i] / sum(w)

class Solution {
    private Random random = new Random();
    private int[] preSum;
    private int n;
    public Solution(int[] w) {
        this.n = w.length;
        // 前缀数组,下标0就是原数组w[0]
        preSum = new int[n];
        // 下标0就是原数组w[0]
        preSum[0] = w[0];
        for (int i = 1; i < n; i++) {
            preSum[i] = preSum[i-1] + w[i];
        }
    }
    public int pickIndex() {
        // 保证取到[1, preSum[n-1]]的闭区间
        int target = random.nextInt(preSum[n-1]) + 1;
        // right可以从n-1开始,也可以从n开始,对结果的正确性没有影响
        int left = 0, right = n;
        while (left < right) {
            int mid = left + (right - left) / 2;
            // 如果找到了,直接去当前的下标
            if (preSum[mid] == target) {
                left =mid;
                break;
            } else if (preSum[mid] > target) {
                // 向左找,因为当前mid的值大于target,可能是"第一个大于target"的值,所以不能丢弃mid
                // 如果mid的值不再需要了(最终不会取到现在的mid),那么就可以right=mid-1;
                right = mid;
            } else {
                // 向右找,因为当前的mid的值比target小,永远不会取到了。所以left=mid+1;
                left = mid + 1;
            }
        }
        // left代表的含义:
        // 当目标元素 target 不存在数组 nums 中时,搜索左侧边界的二分搜索的返回值可以做以下几种解读:
        // 1、返回的这个值是 nums 中大于等于 target 的最小元素索引。
        // 2、返回的这个值是 target 应该插入在 nums 中的索引位置。
        // 3、返回的这个值是 nums 中小于 target 的元素个数。
        return left;
    }
}


相关文章
|
7月前
|
存储 监控 算法
基于 C++ 哈希表算法实现局域网监控电脑屏幕的数据加速机制研究
企业网络安全与办公管理需求日益复杂的学术语境下,局域网监控电脑屏幕作为保障信息安全、规范员工操作的重要手段,已然成为网络安全领域的关键研究对象。其作用类似网络空间中的 “电子眼”,实时捕获每台电脑屏幕上的操作动态。然而,面对海量监控数据,实现高效数据存储与快速检索,已成为提升监控系统性能的核心挑战。本文聚焦于 C++ 语言中的哈希表算法,深入探究其如何成为局域网监控电脑屏幕数据处理的 “加速引擎”,并通过详尽的代码示例,展现其强大功能与应用价值。
167 2
|
2月前
|
存储 人工智能 算法
从零掌握贪心算法Java版:LeetCode 10题实战解析(上)
在算法世界里,有一种思想如同生活中的"见好就收"——每次做出当前看来最优的选择,寄希望于通过局部最优达成全局最优。这种思想就是贪心算法,它以其简洁高效的特点,成为解决最优问题的利器。今天我们就来系统学习贪心算法的核心思想,并通过10道LeetCode经典题目实战演练,带你掌握这种"步步为营"的解题思维。
|
3月前
|
机器学习/深度学习 人工智能 算法
当AI提示词遇见精密算法:TimeGuessr如何用数学魔法打造文化游戏新体验
TimeGuessr融合AI与历史文化,首创时间与空间双维度评分体系,结合分段惩罚、Haversine距离计算与加权算法,辅以连击、速度与完美奖励机制,实现公平且富挑战性的游戏体验。
|
算法
Leetcode 初级算法 --- 数组篇
Leetcode 初级算法 --- 数组篇
146 0
|
9月前
|
存储 监控 算法
基于 PHP 二叉搜索树算法的内网行为管理机制探究
在当今数字化网络环境中,内网行为管理对于企业网络安全及高效运营具有至关重要的意义。它涵盖对企业内部网络中各类行为的监测、分析与管控。在内网行为管理技术体系里,算法与数据结构扮演着核心角色。本文将深入探究 PHP 语言中的二叉搜索树算法于内网行为管理中的应用。
128 4
|
8月前
|
存储 算法 物联网
解析局域网内控制电脑机制:基于 Go 语言链表算法的隐秘通信技术探究
数字化办公与物联网蓬勃发展的时代背景下,局域网内计算机控制已成为提升工作效率、达成设备协同管理的重要途径。无论是企业远程办公时的设备统一调度,还是智能家居系统中多设备间的联动控制,高效的数据传输与管理机制均构成实现局域网内计算机控制功能的核心要素。本文将深入探究 Go 语言中的链表数据结构,剖析其在局域网内计算机控制过程中,如何达成数据的有序存储与高效传输,并通过完整的 Go 语言代码示例展示其应用流程。
145 0
|
10月前
|
存储 监控 算法
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
在数字化办公时代,公司监控上网软件成为企业管理网络资源和保障信息安全的关键工具。本文深入剖析C++中的链表数据结构及其在该软件中的应用。链表通过节点存储网络访问记录,具备高效插入、删除操作及节省内存的优势,助力企业实时追踪员工上网行为,提升运营效率并降低安全风险。示例代码展示了如何用C++实现链表记录上网行为,并模拟发送至服务器。链表为公司监控上网软件提供了灵活高效的数据管理方式,但实际开发还需考虑安全性、隐私保护等多方面因素。
204 0
公司监控上网软件架构:基于 C++ 链表算法的数据关联机制探讨
|
存储 算法 Java
leetcode算法题-有效的括号(简单)
【11月更文挑战第5天】本文介绍了 LeetCode 上“有效的括号”这道题的解法。题目要求判断一个只包含括号字符的字符串是否有效。有效字符串需满足左括号必须用相同类型的右括号闭合,并且左括号必须以正确的顺序闭合。解题思路是使用栈数据结构,遍历字符串时将左括号压入栈中,遇到右括号时检查栈顶元素是否匹配。最后根据栈是否为空来判断字符串中的括号是否有效。示例代码包括 Python 和 Java 版本。
288 4
|
算法
每日一道算法题(Leetcode 20)
每日一道算法题(Leetcode 20)
175 2
|
2月前
|
机器学习/深度学习 算法 机器人
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
【水下图像增强融合算法】基于融合的水下图像与视频增强研究(Matlab代码实现)
223 0

热门文章

最新文章