CS3K.com 九章算法基础班

Remove Substrings

题目

思路:很容易想到贪心,能尽量削减原串就削减原串,但是贪心是错误的,反例:"abcabd", ["ab","abcd"]

   用DFS,对于dict中的每一个子串,在原串中找到匹配的该串的索引,并截取原字符串,更新结果,将截取后的字符串加入到队列中(增加一个set来避免相同的串重复加入到队列)以便下一次循环,然后从该索引后面的一个位置开始再找与该子串匹配的索引,重复上述过程。

View Code

Permutation Index

题目

思路:

对于某一个给定的位数A[i],需要判断在它后面有几个小于它的数,记下这个数字和A[i]所在的位置。

比如对于一个四位数,5316  , 第一位后面有2小于它的数,如果这两个数排在第一位,那么(1和3)各有3!的排列组合数小于(5316).

同理,对于第二位,其后有1个小于它的数,如果它放在第二位,那么有2!种排列。

因此判断一个给定数位于排列组合的第几位,则可以按照以下公式进行

count1*(A.length-1)!+count2*(A.length-2)!+......+countn*(0)!

View Code

Permutation Index II

题目

思路:

这道题和Permutation IndexI思想一样,计算每一位上数字是该位上第几个排列,再将每一位结果加和即可。只是这道题有重复元素,有无重复元素最大的区别在于原来的1!, 2!, 3!...等需要除以重复元素个数的阶乘。按照数字从低位到高位进行计算。每遇到一个重复的数字就更新重复元素个数的阶乘的值。

  1. 从后往前遍历数组,用一个hashmap来记录重复元素个数。若新来的数不是重复元素,则加入hashmap,否则将重复元素个数+1,同时更新重复元素个数的阶乘。

  2. 比较当前位和其后面位的数,计算当前位是第几大的数count

  3. 当前位的index为:2的结果count * 其后面位数的阶乘/重复数个数的阶乘。将当前位计入阶乘,重复1-3计算前一位。

  4. 注意:1.题目说index从1开始算。2.要用long来保存result,factor和repeatFactor,用int有可能超过范围
View Code

Maximum Subarray

题目

思路:sum记录到当前索引的子数组的和,minSum记录该索引之前的子数组(从索引0开始)的和的最小值。sum - minSum表示以当前索引结尾的最大子数组的和,遍历一遍后取sum - minSum的最大值即可。

View Code

Maximum Subarray II

题目

思路:求两个不重叠的子数组的和最大。因为两个subarray 一定不重叠,所以必定存在一条分割线,分开这两个 subarrays。枚举分割线的位置,left[] 和 right[] 里分别存的是,某个位置往左的 maximum subarray 和往右的 maximum subarray。

View Code

Maximum Subarray Difference

题目

思路:求两个不重叠的子数组的差的绝对值最大。与Maximum Subarray II的区别在于,需要求出left_max、left_min、right_max、right_min这四个数组,分别表示某个位置往左的最大子数组、某个位置往左的最小子数组、某个位置往右的最大子数组、某个位置往右的最小子数组。然后枚举分割线的位置,对于某一位置的分割线,结果是左边最大值与右边最小值的差的绝对值或者左边最小值与右边最大值的差的绝对值。

View Code

Maximum Subarray III

题目

思路:

local[i][k]表示前i个元素取k个子数组并且必须包含第i个元素的最大和。

global[i][k]表示前i个元素取k个子数组不一定包含第i个元素的最大和。

local[i][k]的状态函数:

max(global[i-1][k-1], local[i-1][k]) + nums[i-1]

有两种情况,第一种是第i个元素自己组成一个子数组,则要在前i-1个元素中找k-1个子数组,第二种情况是第i个元素属于前一个元素的子数组,因此要在i-1个元素中找k个子数组(并且必须包含第i-1个元素,这样第i个元素才能合并到最后一个子数组中),取两种情况里面大的那个。

global[i][k]的状态函数:

max(global[i-1][k],local[i][k])

有两种情况,第一种是不包含第i个元素,所以要在前i-1个元素中找k个子数组,第二种情况为包含第i个元素,在i个元素中找k个子数组且必须包含第i个元素,取两种情况里面大的那个。

注意这一题中DP的方向是先从上往下,再从左往右,而不是通常的先从左往右,再从上往下。这样做是因为localMax[j - 1][j]和globalMax[j - 1][j]置为Integer.MIN_VALUE的次数取决于列循环次数,而不是取决于行循环次数,否则二维数组下标会越界。

View Code

Maximum Subarray IV

题目

思路:同Maximum Subarray,区别在于更新min_pre的时机,不是每次循环都更新,而是i >= 的时候更新,这样才能保证子数组长度大于等于k。

View Code

Maximum Subarray V

题目

思路:使用双端队列Deque,存放i,表示前i个数,第i个数到前index数之间的子数组有可能成为最大和子数组。每次循环,做三个操作:在列首踢掉长度大于k2的子数组的索引,在列尾踢掉子数组的和小于当前长度为k1的子数组的和,此时列首到当前索引的子数组为以当前元素为子数组的最后一个元素的长度在k1 ~ k2之间的最大和子数组,如果这个和比结果大就更新结果。

View Code

LRU Cache

题目

思路:HashMap + DoubleLinkedList  HashMap存储key -> Node,Node节点里的元素:1. key(可不要) 2. value 3. prev和next指针

这一道题的set操作如果set(key, value)的key已经存在的话,不算做最近使用的。

View Code

LFU Cache

题目

思路:双HashMap + DoubleLinkedList。一个valueHash存储:key -> value;另一个nodeHash存储:key -> Node。

Node节点里的元素:1. 频率freq

           2. LinkedHashSet<Integer> keys存储freq相同的key集合,可以保证先使用的Node放前面,最近使用的Node放后面

           3. prev和next指针

事先构造好虚拟的head和tail Node节点。

注意要随时维护好valueHash、nodeHash和DoubleLinkedList中的元素关系。

View Code

猜你喜欢

转载自www.cnblogs.com/jzsf/p/9938486.html