精品推荐:
《征服数据结构》专栏:50多种数据结构彻底征服
《经典图论算法》专栏:50多种经典图论算法全部掌握
本周三小米举办2024届小米应届生迎新典礼,小米CEO雷军出席典礼并发表演讲。据雷军介绍,2024年小米一共招募了4000名应届生,明年至少还会招募4000-5000名。
小米“应届生计划”的目标就是10年时间让其中的佼佼者成为技术专家,或者成为总经理。
--------------下面是今天的算法题--------------
来看下今天的算法题,这题是LeetCode的第556题:下一个更大元素 III。
问题描述
来源:LeetCode第556题
难度:中等
给你一个正整数 n ,请你找出符合条件的最小整数,其由重新排列 n 中存在的每位数字组成,并且其值大于 n 。如果不存在这样的正整数,则返回 -1 。
注意 ,返回的整数应当是一个 32 位整数 ,如果存在满足题意的答案,但不是 32 位整数 ,同样返回 -1 。
示例1:
输入:n = 12
输出:21
示例2:
输入:n = 21
输出:-1
1 <= n <= 2^31 - 1
问题分析
这题和前面讲的《下一个排列》基本完全一样,都是求下一个更大的值,只不过他们给的参数不一样,前面那道题直接给了一个数组,而这题是给了一个数字。但不影响,我们可以先把数字中的每一位都提取出来,构成一个数组,那么这题就和前面那道题完全一样了。具体实现原理可以参考前面的《下一个排列》,这里就不在重复介绍。
JAVA:
public int nextGreaterElement(int n) {
String str = String.valueOf(n);
int[] nums = new int[str.length()];
// 把数字 n 的每一位转成数组
for (int i = 0; i < str.length(); i++)
nums[i] = str.charAt(i) - '0';
// 如果不存在下一个,返回 -1 。
if (!nextPermutation(nums))
return -1;
// 把数组转化为数字
long ans = 0;
for (int num : nums) {
ans = ans * 10 + num;
if (ans > Integer.MAX_VALUE)
return -1;
}
return (int) ans;
}
public boolean nextPermutation(int[] nums) {
int left = nums.length - 2;
// 两两比较,从后面往前找第一个降序的
while (left >= 0 && nums[left] >= nums[left + 1])
left--;
// 如果都是逆序的,也就是没有下一个更大的元素。
if (left < 0)
return false;
int right = nums.length - 1;
// 从后面查找第一个比nums[left]大的值
while (nums[right] <= nums[left])
right--;
swap(nums, left, right);
// 反转后面升序的数字
reverse(nums, left + 1, nums.length - 1);
return true;
}
// 反转子数组[left,right]中的元素
private void reverse(int[] nums, int left, int right) {
while (left < right)
swap(nums, left++, right--);
}
// 交换数组中的两个数字
private void swap(int[] nums, int left, int right) {
int tmp = nums[left];
nums[left] = nums[right];
nums[right] = tmp;
}
C++:
public:
int nextGreaterElement(int n) {
vector<int> nums;
while (n != 0) {
nums.push_back(n % 10);
n /= 10;
}
reverse(nums.begin(), nums.end());
// 如果不存在下一个,返回 -1 。
if (!nextPermutation(nums))
return -1;
// 把数组转化为数字
long ans = 0;
for (int num: nums) {
ans = ans * 10 + num;
if (ans > INT_MAX)
return -1;
}
return (int) ans;
}
bool nextPermutation(vector<int> &nums) {
int left = nums.size() - 2;
// 两两比较,从后面往前找第一个降序的
while (left >= 0 && nums[left] >= nums[left + 1])
left--;
// 如果都是逆序的,也就是没有下一个更大的元素。
if (left < 0)
return false;
int right = nums.size() - 1;
// 从后面查找第一个比nums[left]大的值
while (nums[right] <= nums[left])
right--;
swap(nums[left], nums[right]);
// 反转后面升序的数字
reverse(nums.begin() + left + 1, nums.end());
return true;
}
Python:
def nextGreaterElement(self, n: int) -> int:
nums = []
while n != 0:
nums.append(n % 10)
n //= 10
nums.reverse() # 反转列表,使其从高位到低位
# 如果不存在下一个更大的排列,返回 -1
if not self.next_permutation(nums):
return -1
# 把列表转化为数字,同时检查是否超出int的范围
ans = 0
INT_MAX = 2 ** 31 - 1 # 模拟C++的INT_MAX
for num in nums:
ans = ans * 10 + num
if ans > INT_MAX:
return -1
return ans
def next_permutation(self, nums: list[int]) -> bool:
left = len(nums) - 2
# 从后往前找第一个降序的位置
while left >= 0 and nums[left] >= nums[left + 1]:
left -= 1
# 如果整个列表都是降序的,则没有下一个更大的排列
if left < 0:
return False
right = len(nums) - 1
# 从后往前找第一个比nums[left]大的数
while nums[right] <= nums[left]:
right -= 1
# 交换nums[left]和nums[right]
nums[left], nums[right] = nums[right], nums[left]
# 反转left+1及其之后的部分
nums[left + 1:] = reversed(nums[left + 1:])
return True
笔者简介
博哥,真名:王一博,毕业十多年,《算法秘籍》作者,专注于数据结构和算法的讲解,在全球30多个算法网站中累计做题2000多道,在公众号中写算法题解800多题,对算法题有自己独特的解题思路和解题技巧,喜欢的可以给个关注,也可以下载我整理的1000多页的PDF算法文档。
数组,稀疏表(Sparse Table),单向链表,双向链表,块状链表,跳表,队列和循环队列,双端队列,单调队列,栈,单调栈,双端栈,散列表,堆,字典树(Trie树),ArrayMap,SparseArray,二叉树,二叉搜索树(BST),笛卡尔树,AVL树,树堆(Treap),FHQ-Treap
……
图的介绍,图的表示方式,邻接矩阵转换,广度优先搜索(BFS),深度优先搜索(DFS),A*搜索算法,迭代深化深度优先搜索(IDDFS),IDA*算法,双向广度优先搜索,迪杰斯特拉算法(Dijkstra),贝尔曼-福特算法(Bellman-Ford),SPFA算法,弗洛伊德算法(Floyd)
……