当前位置: 首页 > news >正文

继续打卡hot100

31. 下一个排列 - 力扣(LeetCode)

class Solution {
public:void nextPermutation(vector<int>& nums) {int n = nums.size();int i = n - 2;while(i >= 0 && nums[i] >= nums[i+1]){i--; // 找到第一个不是递减的数字 这里可能i变为-1}if(i >= 0){int j = n - 1;while(nums[i] >= nums[j]){j--;// 找到可以交换的数字}swap(nums[i], nums[j]);}reverse(nums.begin() + i + 1,nums.end());}
};

好的,我们来从头开始,一步步推导出这道题的解法。这道题是字典序算法的一个经典应用,理解它的逻辑非常有意思。

目标分析

我们要找的是一个数字序列的 “下一个更大的排列”

  • “排列”: 意味着我们只能使用原来数字,不能改变数字本身。

  • “下一个更大”: 意味着在所有可能的排列中,我们要找一个比当前排列大一点点的,而且是大得最少的那一个。

举个例子,对于 [1, 2, 3]

  • 所有排列按从小到大是:[1, 2, 3], [1, 3, 2], [2, 1, 3], [2, 3, 1], [3, 1, 2], [3, 2, 1]

  • [1, 2, 3] 的下一个是 [1, 3, 2]

  • [2, 3, 1] 的下一个是 [3, 1, 2]

  • [3, 2, 1] 是最大的,没有下一个更大的排列了。

推导过程 (如何思考?)

为了让一个数变得更大,但又尽可能小地改变它,我们应该尽可能地去修改低位(也就是数组靠右的部分)。

我们以 [1, 3, 5, 4, 2] 为例来思考:

  1. 从右往左看,序列是 ...5, 4, 2。这部分 [5, 4, 2] 是一个降序排列。对于一个降序的序列,无论怎么重新排列,都不可能得到一个比它本身更大的数。所以,只动 [5, 4, 2] 这部分是没希望的。

  2. 我们必须把一个“较小的数”和一个“较大的数”进行交换,才能让整个序列变大。 而且,为了让改变尽可能小,我们应该用一个**靠右的“较小数”去和它右边的“较大数”**交换。

  3. 继续从右往左看,我们找到了数字 3。在 3 这个位置,它后面的序列是 [5, 4, 2]3 比它右边的 5 要小。这是一个关键的突破口!这意味着,我们可以把 3 换成一个比它大的数,从而让整个数字序列变大。这个 3 就是我们要操作的目标“小数”

    • 第一步,就此诞生:从右向左,找到第一个 nums[i] < nums[i+1] 的位置。这个 nums[i] 就是我们要找的“小数”。[1, 3, 5, 4, 2] 中,这个数是 3,下标 i=1

  4. 现在我们确定了要替换 3。用谁来替换它呢?我们应该从它右边的序列 [5, 4, 2] 中选一个数。

    • 为了让排列变大得最少,我们应该选一个刚刚好比 3的数来替换。

    • [5, 4, 2] 中,比 3 大的数有 54。其中 4 是那个“刚刚好”的数。

    • 第二步,就此诞生:再次从右向左,在下标 i 之后的序列中,找到第一个比 nums[i] 大的数 nums[j][1, 3, 5, 4, 2] 中,这个数是 4,下标 j=3

  5. 找到这两个数之后,我们交换它们。

    • [1, 3, 5, 4, 2] 交换 34 之后,变成了 [1, 4, 5, 3, 2]

    • 第三步:交换 nums[i]nums[j]

  6. 现在序列是 [1, 4, 5, 3, 2]。它确实比原来大了。但它是下一个吗?

    • 我们已经把更高位(左边)的数字 3 变成了 4,完成了“变大”这个主要目标。

    • 为了让这个新数成为最小的那个“更大的数”,我们应该让它后面(低位)的数字尽可能地小。

    • 也就是说,我们要把 [5, 3, 2] 这个子序列,变成它所有排列中最小的那一个。

    • 一个序列的最小排列是什么?就是升序排列!所以 [5, 3, 2] 的最小排列是 [2, 3, 5]

    • 一个重要的观察:在执行完第二步和第三步后,i 后面的序列(即 [5, 3, 2]必然是降序的。为什么?因为我们是从一个降序序列 [5, 4, 2] 中,用一个较小的数 3 换走了 4,所以剩下的序列依然保持降序。

    • 第四步,就此诞生:对于一个降序序列,如何最快地让它变成升序?直接将它反转 (reverse) 即可!

    • 我们将 [5, 3, 2] 反转,得到 [2, 3, 5]

    • 最终结果就是 [1, 4, 2, 3, 5]

特殊情况

如果第一步就找不到 nums[i] < nums[i+1] 的情况呢?

例如 [5, 4, 3, 2, 1]。我们从右向左扫描完也找不到这样的 i。这说明整个序列已经是完全降序的了,它是所有排列中最大的一个。根据题目要求,此时应该返回最小的排列,也就是将整个序列反转成 [1, 2, 3, 4, 5]。

算法步骤总结

  1. 从后向前 查找第一个满足 nums[i] < nums[i+1] 的元素,记下其下标 i。这个 nums[i] 是我们要替换的“较小数”。

  2. 如果找不到这样的 i(即整个序列是降序的),说明这已经是最大的排列。直接将整个数组反转,得到最小排列,程序结束。

  3. 如果找到了 i,再从后向前 查找第一个满足 nums[j] > nums[i] 的元素,记下其下标 j。这个 nums[j] 是用来替换的“较大数”。

  4. 交换 nums[i]nums[j]

  5. 将下标 i+1 到数组末尾的这部分子数组反转

33. 搜索旋转排序数组 - 力扣(LeetCode)

class Solution {
public:int search(vector<int>& nums, int target) {int l = 0, r = nums.size() - 1;while(l <= r){int mid = l + (r - l) / 2;if(nums[mid] == target) return mid;if(nums[l] <= nums[mid]){ // 有序的在左边if(target >= nums[l] && target < nums[mid]){ // 判断是否在有序的一边r = mid - 1;}else{l = mid + 1;}}else{if(target > nums[mid] && target <= nums[r]){l = mid + 1;}else{r = mid - 1;}}}return -1;}};

http://www.dtcms.com/a/447369.html

相关文章:

  • 做封面下载网站个人 做自媒体 建网站
  • 旧电脑做网站服务器免费拓客软件
  • wordpress当前版本中山seo网络推广
  • 建设营销型网站不足之处在门户网站上做推广
  • 公司网站一年多少钱网站设计项目建设内容
  • 301的网站用什么来做域名交易域名出售
  • 以实训为载体:养老实训室助力养老服务标准化建设的四大路径
  • 广州哪里有网站建设网站建设的市场分析
  • 【Flutter】APP的数据安全(基于Flutter 交易所APP的总结)
  • 什么语言做网站最好wordpress wp
  • 上海网站设计与制作深圳网络营销推广公司
  • 陕西专业网站开发多少钱微信公众号怎么开通免费
  • 张家港做网站的公司展厅设计培训
  • 网站标题怎么做响应式中文网站模板
  • 巴中建设厅网站电话美篇app怎么制作
  • 衡水网站设计公司哪家专业html简单广告代码
  • 网站开发女生工资手机wap网页
  • 广州建设集团网站黑龙江企业网站设计团队
  • 帝国cms网站地图xmlphotoshopcc
  • 网站建设策划怎么谈深圳广告公司画册设计
  • 做ppt的兼职网站有哪些海外分销平台
  • 微商城网站开发视频小程序注册方法
  • 上海市网站建设公司优秀的h5案例
  • 网站开发实例及研究网站同步到新浪微博
  • 网站建设价格山东济南兴田德润什么活动新增病例最新消息
  • 建设网站都需要哪些资料喀什网站建设百度推广
  • 河东苏州网站建设正能量网站不用下载直接进入
  • wordpress插件途径用仿网站做优化有效果吗
  • 怎么建造个人网站公众号版面设计创意
  • 企业网站备案教程中国外贸论坛