2021.12.31>>第 169 场周赛

123 阅读4分钟

题目

1304. 和为零的N个唯一整数

1305. 两棵二叉搜索树中的所有元素

1306. 跳跃游戏 III

1307. 口算难题

题解1304. 和为零的N个唯一整数

给你一个整数 n,请你返回 任意 一个由 n 个 各不相同 的整数组成的数组,并且这 n 个数相加和为 0 

示例 1:

输入:n = 5
输出:[-7,-1,1,3,4]
解释:这些数组也是正确的 [-5,-1,1,2,3][-3,-1,2,-2,4]

示例 2:

输入:n = 3
输出:[-1,0,1]

示例 3:

输入:n = 1
输出:[0]

只要返回一个对称的正反数组就行了,运用这个公式即可i * 2 - n + 1;

题解1305. 两棵二叉搜索树中的所有元素

给你 root1 和 root2 这两棵二叉搜索树。

请你返回一个列表,其中包含 两棵树 中的所有整数并按 升序 排序。.

示例 1:

输入:root1 = [2,1,4], root2 = [1,0,3]
输出:[0,1,1,2,3,4]

示例 2:

输入:root1 = [0,-10,10], root2 = [5,1,7,0,2]
输出:[-10,0,0,1,2,5,7,10]

示例 3:

输入:root1 = [], root2 = [5,1,7,0,2]
输出:[0,1,2,5,7]

示例 4:

输入:root1 = [0,-10,10], root2 = []
输出:[-10,0,10]

示例 5:

输入:root1 = [1,null,8], root2 = [8,1]
输出:[1,1,8,8]

这个题比较简单,但有需要注意的地方。

首先我们需要的是对两个树进行遍历,得到树中的值,最后就是数组的值排序。

考察树的特点、遍历树以及排序的算法

这是一颗二叉搜索树,它的特点就是:若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值; 若它的右子树不空,则右子树上所有结点的值均大于它的根结点的值

对二叉搜索树进行中序遍历就可以得到树中元素升序排序后的结果,在等到两个单调递增的数组后,我们需要进行排序,这时候就可以使用归并排序

题解1306. 跳跃游戏 III

这里有一个非负整数数组 arr,你最开始位于该数组的起始下标 start 处。当你位于下标 i 处时,你可以跳到 i + arr[i] 或者 i - arr[i]。

请你判断自己是否能够跳到对应元素值为 0 的 任一 下标处。

注意,不管是什么情况下,你都无法跳到数组之外。

示例 1:

输入:arr = [4,2,3,0,3,1,2], start = 5
输出:true
解释:
到达值为 0 的下标 3 有以下可能方案: 
下标 5 -> 下标 4 -> 下标 1 -> 下标 3 
下标 5 -> 下标 6 -> 下标 4 -> 下标 1 -> 下标 3 

示例 2:

输入:arr = [4,2,3,0,3,1,2], start = 0
输出:true 
解释:
到达值为 0 的下标 3 有以下可能方案: 
下标 0 -> 下标 4 -> 下标 1 -> 下标 3

示例 3:

输入:arr = [3,0,2,1,2], start = 2
输出:false
解释:无法到达值为 0 的下标 1 处。 

写这个题的时候有点难受的,没有看出来是广度、深度遍历,自己的想法:首先创建一个路径图,使用递归 ,从start开始走,因为每个点都有两种走法,所以再创建一个Map数据类型,记录每一条路是否走过,十分的麻烦。

广度优先遍历的题解:

const canReach = (arr, start) => {
  const visited = new Set();
  const queue = [start];
  for (let len = 0, max = arr.length; len < queue.length; ++len) {
    const idx = queue[len];
    if (visited.has(idx)) continue;
    if (arr[idx] === 0) return true;
    visited.add(idx);
    idx + arr[idx] < max && queue.push(idx + arr[idx]);
    idx - arr[idx] >= 0 && queue.push(idx - arr[idx]);
  }
  return false;
};

恍然大悟

1、如何记录已经走过的路径

记录的内容:

想法一:记录走过的数,结果:不合理,每一个路有两条路,还有可能重复;

想法二:记录走过的下标,结果:合理,数可能相同,但是下标不会,而且题目条件中,可以跳转的位置也是用下标记录

2、如何遍历、碰到来过的点如何处理

遍历的方式

  想法一:通过递归,结束条件是:碰到来过的点
  
  想法二:通过for循环,用一个数组来记录路径,每循环两次就能遍历完这个点的两个路径
  

深度优先遍历

const canReach = (arr, start) => { 
      const val = arr[start];
      if (val === 0) return true;
      if (val === -1) return false;
      arr[start] = -1;
      return (start - val >= 0 && canReach(arr, start - val)) || (start + val < arr.length && canReach(arr, start + val));
};