题目一
思路
1、其实基础思路读完题就应该马上想到:
每次得到一个转换中间值x,他所有可能的操作就是,枚举nums中所有数,每个数之于x都有三种操作,+ - ^,所以枚举所有nums数据再操作三次最多得到3000个新的中间结果,然后再循环执行上述操作,这个就是总体解法。
2、在比赛的时候,我直接想到了用DFS,但是仔细分析来,每个节点至多3000个子节点,也就是3000个子函数,暂且不说时间问题,这么多子函数都直接让系统栈溢出了,所以这种稍大数据量一定切记切记!!!!!!!!不能直接莽DFS!
3、一定要加以反思总体思路就是那么做的,那DFS不行,别楞着了,TM除了DFS不是还有BFS吗,只要辅以适当剪枝,BFS在大数据量的时候效果很好,绝壁优于DFS!!!!,所以要思考,不要发呆,你除了DFS不是还学过BFS呢吗!!!!!
BFS
总体思路就如上所言,我们这里介绍一下技巧以及细节注意
1、我要求出转换所用最少次数,所以得维护次数,我还得记录每一个转换中间值,所以二合一,只需要用pair将中间值和他们对应的转换次数对应上就行了
2、对于两个一样的中间结果,因为计算过程一致的原因,所以中间结果一致,放进去继续推一遍,得到的结果,就是一样的,所以没必要重复干活;再加之规定了,只有在0-1000范围内有效,能继续推导,所以状态数都是固定了,就1001个状态,所以记录一下,出现过推完了的没必要再入队,因为再入队相当于重复计算
3、但是我队列存的是一个pair还有推导次数,所以也得论证一下,中间结果一致不入队是否会影响推导次数。我们要求推导次数最少的,如果中间结果一样,推出的结果也都一样,再根据需求,肯定要保留推导次数少的,因为先入队的推导次数肯定少于后入队的,所以我们的策略就是正确的,先入队的能进来,然后标记该中间结果已经出现过了,推导完成了,并且由于是第一次出现,推导次数也是最少的
4、正是由于上述策略,我们只要一找到goal,那么推导次数肯定是最少的
5、超过了1000,不能再次推导,看是不是答案,是的话返回次数,不是的话不用管。
Sum Up:所以总结一下优化策略,因为一样的中间结果求出的结果也一致,所以没必要重复入队,每次进入队列的都是可以造成全新变化的。对于推导次数而言,都是针对首次入队的推导次数,保证了每一步次数都是最少的,所以每次都是次数最少的,所以找到的答案也就一定是最少的。
代码
class Solution {
public:
int minimumOperations(vector<int>& nums, int start, int goal) {
queue<pair<int, int>> item;//队列
item.push(make_pair(start, 0));
bool visit[1005] = {
false };
while (!item.empty()) {
int point = item.front().first;
int cnt = item.front().second;
item.pop();
if (point == goal) {
return cnt;
}
for (int i : nums) {
int new_point[3] = {
point + i,point - i,point^i };
for (int j : new_point) {
if (j > 1000 || j < 0) {
//不可继续推导
if (j == goal) {
return cnt + 1;
}
}
else if (!visit[j]) {
//不能是已出现的点
visit[j] = true;
item.push(make_pair(j, cnt + 1));
}
}
}
}
return -1;
}
};
所有代码均以通过力扣测试
(经过多次测试最短时间为):
题目二
思路
1、先在链表上找临界点,用三指针方法,p1,p2,p3,每次只需要比较p2值是否严格大于/严格小于p1&p3即可,直到p3==nullptr,边走还要为每个节点编号,从一开始
2、因为从前到后走且从前到后编号,所以编号队列一定是严格递增的,所以最大值就是尾元素-首元素,最小差值只需要遍历一边,动态维护就行
代码
class Solution {
public:
vector<int> nodesBetweenCriticalPoints(ListNode* head) {
vector<int> ans(2, -1);
vector<int> item;//存临界点编号
ListNode *p1 = head, *p2 = head->next, *p3 = head->next->next;//三指针
int num = 1;//1开始编号
while (p3 != nullptr) {
if ((p2->val > p1->val&&p2->val > p3->val) || (p2->val < p1->val&&p2->val < p3->val)) {
item.push_back(num);
}
p1 = p1->next;
p2 = p2->next;
p3 = p3->next;
num++;
}
int n = item.size();
if (n < 2) {
return ans;
}
ans[1] = item[n - 1] - item[0];
ans[0] = item[n - 1] - item[n - 2];
for (int i = 0; i < n - 1; i++) {
ans[0] = min(ans[0], item[i + 1] - item[i]);//动态维护
}
return ans;
}
};
题目三
思路
数据量极小,直接暴力模拟
代码
class Solution {
public:
int smallestEqual(vector<int>& nums) {
int n = nums.size();
int ans = -1;
for (int i = 0; i < n; i++) {
if (i % 10 == nums[i]) {
ans = i;
break;
}
}
return ans;
}
};