Problem A - 值相等的最小索引
题目描述:
给你一个下标从 0 开始的整数数组 nums ,返回 nums 中满足 i mod 10 == nums[i] 的最小下标 i
;如果不存在这样的下标,返回 -1 。 x mod y 表示 x 除以 y 的 余数 。
样例一:
输入:nums = [0,1,2]
输出:0
解释:
i=0: 0 mod 10 = 0 == nums[0].
i=1: 1 mod 10 = 1 == nums[1].
i=2: 2 mod 10 = 2 == nums[2].
所有下标都满足 i mod 10 == nums[i] ,所以返回最小下标 0
数据范围:
1 <= nums.length <= 100 ,0 <= nums[i] <= 9
方法一:遍历
直接遍历一遍,逐个判断
参考代码:(c++)
class Solution {
public:
int smallestEqual(vector<int>& nums) {
for(int i=0;i<nums.size();i++){
if(nums[i]==i%10){
return i;
}
}
return -1;
}
};
Problem B - 找出临界点之间的最小和最大距离
题目描述:
链表中的 临界点 定义为一个 局部极大值点 或 局部极小值点 。
如果当前节点的值 严格大于 前一个节点和后一个节点,那么这个节点就是一个 局部极大值点 。
如果当前节点的值 严格小于 前一个节点和后一个节点,那么这个节点就是一个 局部极小值点 。
注意:节点只有在同时存在前一个节点和后一个节点的情况下,才能成为一个 局部极大值点 / 极小值点 。
给你一个链表 head ,返回一个长度为 2 的数组 [minDistance, maxDistance] ,其中 minDistance
是任意两个不同临界点之间的最小距离,maxDistance 是任意两个不同临界点之间的最大距离。如果临界点少于两个,则返回 [-1,-1]。
样例一:
输入:head = [1,3,2,2,3,2,2,2,7]
输出:[3,3]
解释:存在两个临界点:
[1,3,2,2,3,2,2,2,7]:第二个节点是一个局部极大值点,因为 3 比 1 和 2 大。
[1,3,2,2,3,2,2,2,7]:第五个节点是一个局部极大值点,因为 3 比 2 和 2 大。 最小和最大距离都存在于第二个节点和第五个节点之间。 因此,minDistance 和 maxDistance 是 5 - 2 = 3 。
注意,最后一个节点不算一个局部极大值点,因为它之后就没有节点了。
样例二:
输入:head = [2,3,3,2]
输出:[-1,-1]
解释:链表 [2,3,3,2] 中不存在临界点
数据范围:
链表中节点的数量在范围 [2, 105] 内
1 <= Node.val <= 1 0 5 10^{5} 105
方法一:遍历
由于链表不方便直接获取前一个和后一个节点,所以先把链表的值复制到数组上,然后通过一次遍历获取并保存所有的局部极大值点 和局部极小值点。 任意两个不同临界点之间的最小距离就是所有相邻的局部极值点之间的距离最小值,任意两个不同临界点之间的最大距离就是第一个局部极值点和最后一个局部极值点的距离。
参考代码:(c++)
class Solution {
public:
vector<int> nums;
vector<int> nodesBetweenCriticalPoints(ListNode* head) {
while(head!= nullptr){
nums.push_back(head->val);
head=head->next;
}
vector<int> temp;
for(int i=1;i<nums.size()-1;i++){
if(nums[i]>nums[i-1]&&nums[i]>nums[i+1]){
temp.push_back(i);
}
if(nums[i]<nums[i-1]&&nums[i]<nums[i+1]){
temp.push_back(i);
}
}
vector<int> ans;
if(temp.size()<2){
ans.push_back(-1);
ans.push_back(-1);
}else{
int minAns=0x3f3f3f3f;
int maxAns=0xcfcfcfcf;
for(int i=1;i<temp.size();i++){
minAns=min(minAns,temp[i]-temp[i-1]);
}
maxAns=temp[temp.size()-1]-temp[0];
ans.push_back(minAns);
ans.push_back(maxAns);
}
return ans;
}
};
Problem C -转化数字的最小运算数
题目描述:
给你一个下标从 0 开始的整数数组 nums ,该数组由 互不相同 的数字组成。另给你两个整数 start 和 goal 。
整数 x 的值最开始设为 start ,你打算执行一些运算使 x 转化为 goal 。你可以对数字 x 重复执行下述运算:
如果 0 <= x <= 1000 ,那么,对于数组中的任一下标 i(0 <= i < nums.length),可以将 x
设为下述任一值:
- x + nums[i]
- x - nums[i]
- x ^ nums[i](按位异或 XOR)
注意,你可以按任意顺序使用每个 nums[i]任意次。使 x 越过 0 <= x <= 1000 范围的运算同样可以生效,但该该运算执行后将不能执行其他运算。
返回将 x = start 转化为 goal 的最小操作数;如果无法完成转化,则返回 -1 。
样例一:
输入:nums = [1,3], start = 6, goal = 4
输出:2
解释: 可以按 6 → 7 → 4的转化路径进行,只需执行下述 2 次运算:
- 6 ^ 1 = 7
- 7 ^ 3 = 4
样例二:
输入:nums = [2,8,16], start = 0, goal = 1
输出:-1
解释: 无法将 0 转化为 1
数据范围:
1 <= nums.length <= 1000
- 1 0 9 10^{9} 109 <= nums[i], goal <= 1 0 9 10^{9} 109
0 <= start <= 1000 start != goal
nums 中的所有整数互不相同
方法一:BFS
1.start入队
2.取出队首元素u,然后枚举nums数组,对于nums数组的每个元素nums[i],判断u+nums[i],u-nums[i],u^nums[i]是不是goal,若是直接返回答案为vis[u]+1,若不是则判断是否需要入队(跳过超出范围和重复到达的点)。
3.重复2,直到直接返回答案,或者队列为空,不能转化为goal,返回-1
参考代码:
class Solution {
public:
int vis[1001];// vis[x]=-1表示x的位置没有到达过,vix[x]!=-1表示变换到x的最小操作次数
//用来判断pos是否有必要进入队列
bool judge(int pos,int u,int goal){
/*
只有在pos>=0&&pos<=1000以内才有入队的可能,不在这个范围内的话无法进行操作,没有入队的
必要。
*/
if(pos>=0&&pos<=1000){
/*
vis[pos]==-1表示pos还没到达过,那么有可能可以通过pos到达goal,同时需要更新vis[pos]
如果vis[pos]!=-1,表示pos已经在之前已经到达过了,说明pos已经入过队,没有再次入队的
必要了。
*/
if(vis[pos]==-1){
vis[pos]=vis[u]+1;
return true;
}
}
return false;
}
int minimumOperations(vector<int>& nums, int start, int goal) {
memset(vis,-1,sizeof(vis));
queue<int> que;
que.push(start);
vis[start]=0;
while(!que.empty()){
int u=que.front();
que.pop();
for(int i=0;i<nums.size();i++){
int tempPos=u+nums[i];
//判断u+nums[i]
if(tempPos==goal){
return vis[u]+1;
}
if(judge(tempPos,u,goal)){
que.push(tempPos);
}
tempPos=u-nums[i];
//判断u-nums[i]
if(tempPos==goal){
return vis[u]+1;
}
if(judge(tempPos,u,goal)){
que.push(tempPos);
}
tempPos=u^nums[i];
//判断u+nums[i]
if(tempPos==goal){
return vis[u]+1;
}
if(judge(tempPos,u,goal)){
que.push(tempPos);
}
}
}
return -1;
}
};