京东笔试AC 大小写切换 && 合唱队

1. 大小写切换,DP,O(n)
def countPress(s):
    n = len(s)
    # dp[0] lower case
    # dp[1] upper case
    dp = [[n-i for i in range(n)] for _ in range(2)]
    if s[-1].isupper():
        dp[0][-1] += 1
    else:
        dp[1][-1] += 1

    for i in range(2, n+1):
        ch = s[-i]

        if ch.isupper():
            dp[0][-i] = min(dp[0][-i+1] + 2, dp[1][-i+1] + 2)
            dp[1][-i] = min(dp[0][-i+1] + 2, dp[1][-i+1] + 1)
        else:
            dp[0][-i] = min(dp[0][-i+1] + 1, dp[1][-i+1] + 2)
            dp[1][-i] = min(dp[0][-i+1] + 2, dp[1][-i+1] + 2)

    return dp[0][0]
稍微解释一下

典型的DP,重点在于如何划分状态:
  1. dp[state][i]表示当前大小写状态为state情况下,完成字符串s[i:n)输入所需的最小按键次数。定义state=0表示当前为小写状态,state=1表示当前为大写状态。
  2. 边界条件:dp[0][n-1]以及dp[1][n-1],与最后一个字符的大小写有关。
  3. 状态转移:backward pass。从dp[state][i+1]到dp[state][i]的转移表示,在保持大小写状态state不变的情况下(不按CAPLOCK键),多输入一个s[i]字符所需要增加的按键次数(结合字符的大小写、当前状态考虑需不需要按shift);类似地,从dp[state][i+1]到dp[~state][i]则表示按下CAPLOCK键,并正确输入s[i]所需增加的按键次数。
  4. 要求的答案即dp[0][0]
时间空间复杂度都是O(n),如有其他思路欢迎讨论👏

2. 合唱队分组,排序,贪心分组,O(nlogn)
from collections import defaultdict

def divideGroups(heights):
    sorted_h = sorted(heights)

    count = 0
    m = defaultdict(lambda:0)

    for h, t in zip(heights, sorted_h):
        m[h] += 1
        m[t] -= 1

        if m[h] == 0:
            del m[h]
        if m[t] == 0:
            del m[t]

        if len(m) == 0:
            count += 1

    return count

感觉这题比较trick,观察后可以发现,要满足条件,那么每个分组的队员只需要组内交换,就可以到达各自在全组有序序列中的位置。题目给的n范围不大 105,因此可以考虑对比排序后与初始情况的差别。
  1. 初始数组排序,O(nlogn)
  2. 每个人都需要分组,简单起见可以直接从前向后考虑,每次贪心地划分规模最小的分组。
  3. 举个例子,初始 [2,1,3,2],最终顺序应该是 [1,2,2,3]。我们可以同时在两个数组加一个滑动的窗口考虑,当窗口覆盖到的两数组元素种类、数量相同时,可以划为一个分组。比如各自的前两个元素:[2,1]和[1,2],只需要组内交换,一定能达到最终应有的顺序。
  4. 确定可以划分为一个分组时,清空窗口继续向后寻找;否则窗口左端点不动,右端向后移动即可。
  5. 技术上来说,可以维护一个map,表示窗口下两个数组元素各种类数量差。如果所有种类数量差均为0,则表示完全相同。这样维护map的时间开销是O(1)。
时间复杂度主要是排序步骤的O(nlogn),空间复杂度是O(n),如有其他思路欢迎讨论👏

#京东##笔试题目##题解#
全部评论
厉害
点赞 回复 分享
发布于 2019-08-24 21:02
大……大佬
点赞 回复 分享
发布于 2019-08-24 21:10
第二题看到其他大佬用前后缀最值可以O(n)
点赞 回复 分享
发布于 2019-08-24 22:36
top1的也太顶了吧
点赞 回复 分享
发布于 2019-08-24 22:36
第一题o(n)的做法不错,我差一点点就超时了,跑了2899ms,虽说是两题都a了但是时间效率都不大好
点赞 回复 分享
发布于 2019-08-25 01:36
刚刚哪位回复的第一题贪心算法(咋删掉了orz 思路是对的,最后细节差一点,需要判断最后一位和最后大小写状态是否相同,不同则需要再加1。其他都没问题,我本地测了一下,100个case都过了。 认领一下这是谁的代码😂我刚刚复制下来测试了: def get_min_click(text):     n = len(text)     state = False  #caps state initial is False      caps = 0     shifts = 0     for i in range(n-1):           char = text[i]         char_next = text[i+1]         if char.isupper() is not state and char_next.isupper() is char.isupper():             state = not state  #state update             caps += 1  #record 1 time caps click         elif char.isupper() is not state and char_next.isupper() is not char.isupper():             shifts += 1 #record 1 time shift click              return n+caps+shifts+(text[-1].isupper() != state)
点赞 回复 分享
发布于 2019-08-25 10:06
大佬,请教一下大小写切换里面,dp的更新为什么是从后向前,可不可以从前向后啊😂😂😂,还有为什么最后返回结果不考虑dp[1][0]呢
点赞 回复 分享
发布于 2019-08-25 16:09
struct Data { int num; int index; }; bool cmp(const Data &a,const Data &b) { if (a.num == b.num) return a.index < b.index; return a.num < b.num; } int main() { int n = 0; cin >> n; vector<Data> array(n); for (int i = 0; i < n; ++i) { cin >> array[i].num;; array[i].index = i; } sort(array.begin(), array.end(), cmp); int ans = 1; int temp = array[0].index; for (int i = 1; i < n; ++i) { if (array[i].index >= temp){ ++ans; temp = array[i].index; } } cout << ans << endl; } 合唱团这样写也可行吧
点赞 回复 分享
发布于 2019-08-27 23:03

相关推荐

jack_miller:我给我们导员说我不在这里转正,可能没三方签了。导员说没事学校催的时候帮我想办法应付一下
点赞 评论 收藏
分享
评论
10
58
分享
牛客网
牛客企业服务