活跃农民
- 积分
- 427
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2018-8-4
- 最后登录
- 1970-1-1
|
3.14 刷题
315. Count of Smaller Numbers After Self. 这个题目要求给定一个数组,希望对于数组中的每一个元素,都找出它右边所有比它还要小的元素个数,最终存储在一个结果数组里;那么这里的思路就是,对于该给定数组从右往左进行遍历,然后把遍历的结果存储在一个BST当中;对于一个元素,就应该插入到BST当中找到它应该存在的位置,而构建BST的过程就是找寻每一个元素右边更小元素的个数的过程;当遍历到一个元素的时候,就把这个元素放到BST当中,当沿着BST需要在某一个节点往左走的时候,就意味着这个正在遍历的元素比该节点所对应的元素更小,也就是意味着对于该节点所对应的元素来说,它在给定数组的左边出现了一个比它小的元素;这当然不是这一题目需要的结果(题目需要找到每一个元素右边更小的元素个数),但是仍然需要在该节点这里记录下来,也就是说每一个节点都要额外维护一个sum变量,以记录每一个节点的左子树的总节点个数;当沿着BST需要在某一个节点往右走的时候,就以为着这个正在遍历的元素比该节点所对应的元素更大,又因为这是从右往左遍历,也就是说当前正在遍历元素沿着BST经过的节点都代表着在给定数组中比位于该元素右边的节点,因此如果需要往右走的话,就意味着对于该元素来说发现了一个位于它右边且更小的元素;当然,这并不是说“仅仅”发现了一个元素,这是因为对于该节点来说,它自己本身的元素数值比当前正在遍历的元素小,那么它整整一个左子树上的节点所代表的元素,都应该比当前元素小,因此就应该加上这个左子树的总节点个数,也就是之前维护的sum变量,然后继续沿着BST走;另一方面,给定数组可能出现重复的元素,位置不确定,那么在BST中的每一个节点,就需要再额外维护一个dup变量,表示当前从右往左遍历过程中该节点所表示元素的重复次数,起始值为1,每次遇到同样的就加1;那么如果在对于一个元素沿着BST的过程中,遇到一个节点的数值跟它自己完全一样的话,除了dup加1以外,对于当前这个元素它右边更小的元素总个数,就应该是现在从BST根节点往下走的过程中已经加上的元素,再加上BST中当前节点的所有左子树总节点个数,这很好理解,因为当前节点的sum就代表着当前遍历过程中这个节点已经构建好的左子树总节点个数,也就代表着遍历到现在,在出现duplicate之间的这一部分构建到左子树的元素个数,比如24310436567这个,如果当前已经遍历到最左边的那个3的话,但是在BST中数值为3的节点是在遍历到最右边的那个3就构建了,那么这里的sum就代表着这两个3之间所有比3小的元素个数,当然要加起来;因此综上所述,从左往右遍历给定数组,对于某一个元素都去进行构建BST;如果在BST中需要往左走,那么对于当前BST节点的sum要+1,如果在BST中需要往右走,那么在recursion当中prefixSum需要加上当前BST节点的sum和dup;如果在BST中发现可以插入了,那么在最终结果数组中的对应位置上,放上迄今为止已经加好的prefixSum;如果在BST中发现有重复的元素节点,那么就把prefixSum加到结果数组中,还要额外把当前节点的sum也加进去,另外dup也要+1
300. Longest Increasing Subsequence. 这个题目让求给定数组的最长增长子序列,而不是subarray;这里的思路就是,从左到右遍历给定数组,并且在遍历的时候不断对当前遍历到的元素进行binary search,通过binary search去构建一个新的数组,最后新数组的长度就是最长增长子序列的长度;具体来说,对于当前遍历到的元素,把它放到新的dp当中去构建,如果当前dp数组的有效长度(或者已经构建的长度为len),那么这里binary search所要寻找的就是当前这个元素应该放到当前dp数组的哪一个位置;比如如果当前dp数组已经是2 5 8的话,而当前遍历到的元素是7,那么这个7就应该替换掉8使得当前dp变成2 5 7;但如果仍然是这个dp数组2 5 8,但是当前遍历到的元素是12,那么这个12就应该放到dp数组的后面变成2 5 8 12,也就是说dp数组的长度加1;而dp数组总是增长的是sorted的,因此对于每一个遍历到的当前元素,都可以用binary search的方法,寻找在dp数组当中是否有dp[i - 1] <= num < dp[i],如果有的话就把dp[i]替换成num,如果没有的话说明num太大了,那么num就放到dp[i]的后面,因此dp的长度就会增加;总而言之,就是遍历给定数组,对于每一个元素都去dp数组中寻找自己的位置,如果找到了位置就更新,没找到位置就往后增加一位,dp数组的长度也就在这个过程中慢慢增长
354. Russian Doll Envelopes. 这个题目是给一个数组,数组里面都是二元组,表示套娃的宽和高,希望找到一个符合原有顺序套娃序列,可以一个一个套起来套得最多;这个题目的做法就是,首先把这些套娃按照宽升序排序,然后再按照高降序排序,最后利用LIS的那种方法,即从左到右遍历给定数组元素、在用binary search对给定数组元素到dp数组当中寻找合适的位置、找得到就替换找不到就往后放并更新length;这里的binary search是基于所有套娃的高进行search的,而添加进dp数组中当然也是这些套娃的高;这里的原因就是,按照宽生升序就解决了一个纬度的自增序列问题,而高降序则可以break ties,比如[3, 3]和[3, 4]可以变成自增序列而[3, 4]和[3, 3]不行,事实上[3, 3]作为套娃也是放不进[3, 4]的
36. Valid Sudoku. 这个题目就分别按行按列按box各自建立9个hashset,然后对于每一个遍历到的9 * 9的元素都放到对应的三个Set里面,如果有重复就说明不valid;注意box的定位方式是(i / 3) * 3 + j / 3,这个的意思是说,根据行来判断当前处于从编号0开始还是3开始还是6开始的box,而j / 3则是根据列来判断到底要从0或3或6的基础上增加多少个
37. Sudoku Solver. 这个题目就是对于每一个空的位置,都从1到9挨个尝试,如果某一个数字当前是valid,那么就暂时在board当中设置好这个数字,然后对更新后的board进行dfs检查,如果通过就返回true,否则就把当前位置归位空,继续尝试;如果对于这个位置从1到9都没办法,那么就说明无法sudoku,返回false,停止这一分枝的dfs;对于检查valid的helper,要从1到9分别对行、列、box进行检查,对于传入的row和col,找到box的方法就是首先都把(row / 3) * 3和(col / 3) * 3一下,从而定位到这个位置所在的box的左上顶点,然后对于行来说加上i / 3,对于列来说加上i % 3,从而定位到box的具体位置
|
|