字节跳动LeetCode题库

404. 给定整数 n 和 k,找到 1 到 n 中字典序第 k 小的数字。

/**
 * @param {number} n
 * @param {number} k
 * @return {number}
 */
function findKthNumber(n, k) {
	// 定义当前探索点,从1开始,构建十叉树,字典序就是树的先序遍历
	let result = 1
	// 定义剩余探索步数,当这个值为0,说明已经到了我们需要的数上了
	let lastingSteps = k - 1
	while (lastingSteps > 0 ) {
		// 数一下,先序遍历的话,从当前节点到兄弟节点,中间经过几个子结点
		/**定义最多能经过的子结点数,尝试扩大这个数,跳过尽量多的子结点**/
		let numOfSubNode = 0
		/**向下展开当前节点,得到子树中左下角的节点**/
		let expandChildrenStart = result
		/**当前节点的下一个兄弟节点**/
		let expandChildrenEnd = result + 1
		// 向下展开后,只要最左下角的数字没有超过n,就尽量往下展开
		while (expandChildrenStart <= n) {
			// 如果当前探索点的子结点形成完全十叉树,Math.min会取expandChildrenEnd,说明子树中就是有这么多个节点
			// Math.min若取到n + 1,说明形成完全十叉树所需的节点比n还大,子树是不完全的十叉树
			numOfSubNode += Math.min(expandChildrenEnd, n + 1) - expandChildrenStart
			// 计算十叉树再展开一层子结点之后,子结点的数量
			// 如果这次展开之后,下一次expandChildrenEnd大于n+1,就说明有一层节点数量不够形成完全十叉树
			expandChildrenStart *= 10
			expandChildrenEnd *= 10
		}
		// 如果发现展开后,当前位置的子节点数量巨多,大于剩余探索步数
		if (numOfSubNode > lastingSteps) {
			// 就把当前探索点result在十叉树中向下移一层
			result *= 10
			// 指针下移一层,相当于先序走了一步,剩余探索步数减一
			lastingSteps --
		} else {
			// 如果子节点数小于剩余步数,指针向右移动,跳过整棵子树
			result ++
			// 跳过子树相当于跳过多个子节点
			lastingSteps -= numOfSubNode
		}
	}
	return result
}

351. 安卓3 x 3手势解锁的界面,给定两个整数,分别为 ​​m 和 n,其中 1 ≤ m ≤ n ≤ 9,统计有多少种解锁手势,是至少需要经过 m 个点,但是最多经过不超过 n 个点的。每一个解锁手势必须至少经过 m 个点、最多经过 n 个点。解锁手势里不能设置经过重复的点。假如手势中有两个点是顺序经过的,那么这两个点的手势轨迹之间是绝对不能跨过任何未被经过的点。经过点的顺序不同则表示为不同的解锁手势。

 

 

你可能感兴趣的:(LeetCode刷题)