活跃农民
- 积分
- 433
- 大米
- 颗
- 鳄梨
- 个
- 水井
- 尺
- 蓝莓
- 颗
- 萝卜
- 根
- 小米
- 粒
- 学分
- 个
- 注册时间
- 2018-8-4
- 最后登录
- 1970-1-1
|
9.4 做题
621. Task Scheduler. 这个题目使用了Greedy的思路:先放好出现频次最多的那个task,这些频次最多的task的安放原则就是,它们之间均匀排列,每个之间的间隔就都是题目中规定的cooling区间数n;在安置好这个频次最多的task之后,其他的task就依次插入进这些频次最多的task的中间的间隔即可;就比如给定的char array是AABABC,并且n = 2的话,那么A的频次最高是3,因此按上面说的安排A:A ? ? A ? ? A,然后再安排两个B就这样放:A B ? A B ? A,最后是那一个C:A B C A B ? A,这样就可以看出,一共是剩下了一个间隔,那么这个间隔就是idle,因此这个task序列和冷却的结果就应该是7个task加上一个间隔也就是8;总结来说,首先找到出现频次最高的task,然后它的安排相当于划分出了这样的一个部分part = count(A) - 1,也就是两组间隔,而每一组间隔的数量都是给定的n;那么也就是说现在可以放置那些非最高频次的task的间隔数一共就是part * n;而还剩下的非最高频次的task的数量,就相当于是task的总数减去最高频次task的频次;那么idle的数量,其实就是当前一共的间隔数量,减去当前还剩下等待安排的task数量;最后返回的结果就是总共的task数量加上idle的数量;这个题目当然不会这么简单,比如一些情况需要考虑的就是,如果最高频次的task有多个怎么办(比如AABABBCC,出现了3个A和3个B),或者如果最高频次的task太多了怎么办(比如AABBCDCDEEFFG,除了G以外其他所有的task都是最高频次的,最高频次task的数量本身高于了给定的n);这些特殊情况可以在discussion里面看着解决;当然这个题目除了greddy的方法之外还有用PriorityQueue和HashMap的方法,其实也是greedy的思路,先去找频次最大的字符来进行安置
560. Subarray Sum Equals K. 首先这个题目不能用two pointers,因为可能数组中有负数元素存在;这个题目的方法就是,想要找sum为k的subarray,实际上就是要确定在数组中是否存在一个(i, j)的subarray使得sum(i, j)正好等于k;而sum(i, j)正好等于sum(0, j) - sum(0, i - 1),因此这个题目可以用prefix sum的方法;那么具体来说,在遍历数组的时候记录从起始位置到当前位置的sum,如果对于每一个为止的sum,都能立刻检查出sum - k是否在之前的位置的遍历中算出来的话就好了;这是因为,现在的位置j的sum(0, j)是sum,而现在希望看看是不是能够找到有一个从i到j的subarray它的sum(i, j)为k,那么实际上就是,只要能够找到一个i,使得从起始位置到它开始的sum(0, i - 1)正好等于sum - k就可以了,因为如果它存在,那么就意味着k存在;即,sum[i, j] = sum[0, j] - sum[0, i - 1]可以转化为sum[0, i - 1] = sum[0, j] - sum[i, j],sum[0, j]是当前算出来的,sum[i, j]是给定的target,通过算出来sum[0, i - 1]后,能够找到它就可以了;那么怎么找到它呢?用HashMap,用这个map去记录每次遍历到一个位置的时候,从起始位置到当前位置的prefix sum就可以了;如果map中存在它,就说明有subarray是满足target条件的;那么key是prefix sum,value就是频次,因为存在负数的原因,可能一个prefix sum为某个数的subarray会出现很多次,那么也就意味着满足sum为sum[0, i - 1]的subarray其实就会有多个,这样valid的满足sum为sum[i, j]的subarray也会有很多个;所以每次找到prefix sum后,往结果中加入它在map中的value,也就是频次即可
953. Verifying an Alien Dictionary. 这个题目的关键还是,把给定的alien dict规定的字母顺序,和原有的字母都给map起来,就要建立起来一个,26个字母中的每个字符在新的alien dict中都排在第几位的map,比如在给定的"hlabcdefgijkmnopqrstuvwxyz"里面,字母h对应第0位,l对应第1位,a对应第2位这样;因此遍历order字符串,建立一个map;然后对于给定的words数组,从前到后把挨着的两个word进行比较;比较的方法就是两个String一个一个位置的字母进行检查,如果发现对应位置的两个字母不一样,然后就去看看是不是前一个word的当前字符在map中的顺序,比后一个word的当前字符的顺序考前就好了;如果考前就是true,否则就是false
426. Convert Binary Search Tree to Sorted Doubly Linked List. 把一个BST改成sorted的双向练表,其实就是考察BST的inorder和练表的各种操作;BST的inorder是排好顺序的,那么就肯定是在recursion里面,先用recursion function去弄好root.left的,然后对root进行某种操作,接下来再去弄root.right的;那么这个某种操作究竟是什么操作呢?其实就是把当前BST的node改成双向练表的node的转化;对于双向练表的node来说,其实,仍然是有左右指针,只不过不再指向左右子节点,而是指向前后节点;那么具体的转化操作就是,对于当前的node,它的左指针应该指向它的前一个节点,也就是跟他挨着的比他小的节点,而他的右指针就应该指向它的后一个节点,也就是跟他挨着的比他大的节点;因此这里的inorder操作时,recurion去处理left node的话,应该返回一个node,返回的这个node,应该和当前处理的当前node的关系,就应该是当前node的前一个node;也就是说,recursion处理的left子树后,返回的应该是在双向链表中的当前的node前一个node,其实按照sorted顺序也就应该是BST的当前node的左子树的最大的那个,也就是最右子节点;返回了这个pre节点以后,中间的操作就是,把当前节点的left指向pre,然后把pre的right指向当前节点;然后再去recursion处理当前node的右子树,处理完以后返回的节点,其实按照recursion方法的定义,就应该实际上是右子树的最右边节点,也就是当前node为root的tree的最大节点了,这个结果也就可以应用到其他上一层的recursion中;在处理完整个tree以后,还有注意收尾node也应该链接起来,即后一个node的left指向前一个node,前一个node的right指向后一个node
680. Valid Palindrome II. 这个题目就用左右指针相向而行,如果遇到不一样的字符,那么对于一般来说就应该直接返回false了;那么这个题目允许删除一个字符来继续尝试,那么实际上就相当于,对于这两个不一样的字符,要么删除左指针指向的字符以后继续验证,要么删除右指针指向的字符继续验证;如果删除左的,那么继续验证的时候实际上就是验证从left + 1位置一直到right位置的substring是不是一个Palindrome了,验证方法同样也是左右指针相向而行挨个验证是不是相同字符;如果删除右的话,那就验证从left到right - 1的位置进行验证了 |
|