力扣第265场周赛

第九十二天 --- 力扣第265场周赛

  • 题目一
    • 思路
      • BFS
    • 代码
  • 题目二
    • 思路
    • 代码
  • 题目三
    • 思路
    • 代码

题目一

力扣:5916. 转化数字的最小运算数

力扣第265场周赛_第1张图片

力扣第265场周赛_第2张图片
力扣第265场周赛_第3张图片

思路

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;
	}
}; 


所有代码均以通过力扣测试
(经过多次测试最短时间为):
力扣第265场周赛_第4张图片

题目二

力扣:5915. 找出临界点之间的最小和最大距离

力扣第265场周赛_第5张图片
力扣第265场周赛_第6张图片
力扣第265场周赛_第7张图片

思路

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;
	}
};

力扣第265场周赛_第8张图片

题目三

力扣:5914. 值相等的最小索引
力扣第265场周赛_第9张图片
力扣第265场周赛_第10张图片

思路

数据量极小,直接暴力模拟

代码

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;
	}
};

力扣第265场周赛_第11张图片

你可能感兴趣的:(力扣题解,leetcode,算法,BFS,链表,BFS剪枝优化)