leetcode-滑动窗口/双指针/哈希表

滑动窗口:

左右指针,右指针右移动扩展,满足条件之后,左指针收缩。

// 模板
for () {
    // 将新进来的右边的数据,计算进来
    // 更新数据

    // 判断窗口数据是否不满足要求了
    while (窗口数据不满要求 && left < arrSize) {
        // 移除left数据,更新窗口数据
        left++;    
    }
    // 此时的res是都满足条件的,计算res
    res = right - left + 1
    right++;
}

992 有k个不同整数的子数组 

字典+mostk

[LeetCode] 992. Subarrays with K Different Integers 有K个不同整数的子数组 - Grandyang - 博客园

class Solution(object):
    def mostk(self,nums,k):
        res=0
        left=0
        right=0
        dict={}
        while left<=right and right<len(nums):
            if nums[right] not in dict:
                dict[nums[right]]=1
            else:
                dict[nums[right]]=dict[nums[right]]+1
            #如果dict长度大于k,移动左指针,删掉dict中左指针指向的元素
            while len(dict)>k:
                #如果value为1,直接删除;如果value大于1,减去1
                if dict[nums[left]]==1:
                    del dict[nums[left]]
                else:
                    dict[nums[left]]=dict[nums[left]]-1
                left=left+1
            res+=right-left+1
            right=right+1
        return res

    def subarraysWithKDistinct(self, nums, k):
        """
        :type nums: List[int]
        :type k: int
        :rtype: int
        """
        return self.mostk(nums,k)-self.mostk(nums,k-1)

 

159 最多有2个不同字符的子串

双指针+哈希表

[LeetCode] 159. Longest Substring with At Most Two Distinct Characters 最多有两个不同字符的最长子串 - Grandyang - 博客园

class Solution(object):
    def lengthOfLongestSubstringTwoDistinct(self, s):
        """
        :type s: str
        :rtype: int
        """
#移动右指针,通过字典来判断,是否需要移动左指针
        res=0
        left=0
        right=0
        dict={}
        while left<=right and right<len(s):
            if s[right] not in dict:
                dict[s[right]]=1
            else:
                dict[s[right]]=dict[s[right]]+1
            #如果dict长度大于2,移动左指针,删掉dict中左指针指向的元素
            while len(dict)>2:
                #如果value为1,直接删除;如果value大于1,减去1
                if dict[s[left]]==1:
                    del dict[s[left]]
                else:
                    dict[s[left]]=dict[s[left]]-1
                left=left+1
            cur_res=right-left+1
            if cur_res>res:
                res=cur_res
            right=right+1
        return res

76. 最小覆盖子串

滑动窗口

 

力扣

from collections import defaultdict

class Solution:
    def minWindow(self, s: str, t: str) -> str:
        '''
        如果hs哈希表中包含ht哈希表中的所有字符,并且对应的个数都不小于ht哈希表中各个字符的个数,那么说明当前的窗口是可行的,可行中的长度最短的滑动窗口就是答案。
        '''
        if len(s)<len(t):
            return ""
        hs, ht = defaultdict(int), defaultdict(int)#初始化新加入key的value为0
        for char in t:
            ht[char] += 1
        res = "" 
        left, right = 0, 0 #滑动窗口
        cnt = 0 #当前窗口中满足ht的字符个数
        while right<len(s):
            hs[s[right]] += 1
            if hs[s[right]] <= ht[s[right]]: #必须加入的元素
                cnt += 1 #遇到了一个新的字符先加进了hs,所以相等的情况cnt也+1
            while left<=right and hs[s[left]] > ht[s[left]]:#窗口内元素都符合,开始压缩窗口
                hs[s[left]] -= 1
                left += 1
            if cnt == len(t):
                if not res or right-left+1<len(res): #res为空或者遇到了更短的长度
                    res = s[left:right+1]
            right += 1
        return res

作者:lin-shen-shi-jian-lu-k
链接:https://leetcode-cn.com/problems/minimum-window-substring/solution/leetcode-76-zui-xiao-fu-gai-zi-chuan-cja-lmqz/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution:
    def minWindow(self, s: str, t: str) -> str:
        #哈希表计数
        from collections import Counter
        dic_t=Counter(t)
        dic_s=Counter()
        count=0
        res_size=len(s)+1
        res=''
        #左右指针遍历,右指针的元素加入哈希表
        left=0
        right=0
        while right<len(s):
            dic_s[s[right]]+=1
            #判断是否应该包含在t内
            if dic_s[s[right]]<=dic_t[s[right]]:
                count+=1
             #什么时候移动左指针
            while left<right and dic_s[s[left]]>dic_t[s[left]]:
                dic_s[s[left]]-=1
                left+=1
            #判断是否满足t的长度
            if count==len(t):
                cur_size=right-left+1
                if cur_size<res_size:
                    res_size=cur_size
                    res=s[left:right+1]
            right+=1
        return res

904 水果成篮

超时的滑窗

#双指针:移动右指针,发现不满足条件之后再收缩左指针
#左指针逐位置搜索,通过70/90个case。优化时应该考虑,从maps里判断收缩。
# leetcode submit region begin(Prohibit modification and deletion)
class Solution:
    def totalFruit(self, fruits):
        res=0
        left=0
        right=0
        while left<=right and right<len(fruits):
            maps={}
            maps[fruits[right]]=1
            while right+1<len(fruits):
                right+=1
                if fruits[right] in maps:
                    maps[fruits[right]]+=1
                else:
                    maps[fruits[right]] = 1
                if len(maps)>2:
                    right=right-1
                    break

            cur = right - left + 1
            res = max(res, cur)

            left+=1
            right=left
        return res
fruits = [0,1,2,2]
# fruits = [3,3,3,1,2,1,1,2,3,3,4]
res=Solution().totalFruit(fruits)
print(res)

不超时的滑窗

#右指针始终往右边移动。根据条件判断左指针是否收缩
    def totalFruit2(self, fruits):
        res=0
        left=0
        right=0
        maps={}
        while left<=right and right<len(fruits):
            if fruits[right] not in maps:
                maps[fruits[right]]=1
            else:
                maps[fruits[right]]+=1
            #判断是否已经不满足条件,若不满足条件,收缩left
            while len(maps)>2 :
                maps[fruits[left]]-=1
                if maps[fruits[left]]==0:
                    del maps[fruits[left]]
                left+=1
            #计算
            cur=right-left+1
            res = max(res, cur)
            right+=1
        return res

209. 长度最小的子数组

 滑窗

class Solution:
    def minSubArrayLen(self, target: int, nums: List[int]) -> int:
        #滑窗,当sum大于target时收缩左窗口,当sum等于target时计算一次结果
        #注意是≥ target
        left = 0
        right = 0
        cur_sum = 0
        res = float("inf")
        while right < len(nums):
            cur_sum += nums[right]
            #当cur_sum大于target时收缩左窗口
            while cur_sum >= target:
                cur_res = right - left + 1
                res = min(cur_res,res)
                cur_sum -= nums[left]
                left += 1
            right += 1
        if res == float("inf"):
            return 0
        return res

862. 和至少为 K 的最短子数组

 

 队列中要存index。下面是我第一次写的,bug比较多:

1是没有存index, 而是存的值。

2是没有把队首元素弹出。

3是前缀和写法错误,

presum[j]-presum[i]表示的是nums[j]到nums[i+1],presum[j]-presum[i-1]表示的才是nums[j]到nums[i]
class Solution:
    def shortestSubarray(self, nums: List[int], k: int) -> int:
        #单调递增队列+前缀和
        #前缀和数组
        presum = [0 for _ in range(len(nums)+1)]
        for i in range(1,len(nums)+1):
            presum[i] = presum[i-1] + nums[i-1]
        res = float("inf")
        deq = deque()
        for i in range(len(nums)+1):
            #维护单调递增性
            while deq and deq[-1] > presum[i]:
                deq.pop()
            #都弹出之后
            deq.append(presum[i])
            #计算target
            if deq and deq[-1] - deq[0] >= k:
                cur_res = len(deq)-1
                res = min(res,cur_res)
        if res == float("inf"):
            return -1
        return res

滑窗不行,没有单调性

单调递增队列

class Solution:
    def shortestSubarray(self, nums, k):
        res = float("inf")
        # 1,2,3
        # 1,3,6
        #presum[j]-presum[i]表示的是nums[j]到nums[i+1],presum[j]-presum[i-1]表示的才是nums[j]到nums[i]
        #前缀和
        presum = [0 for _ in range(len(nums)+1)]
        for i in range(1,len(presum)):
            presum[i] = presum[i-1] + nums[i-1]

        #维护一个单调递增队列,队尾-队首>=k,说明找到了一个符合要求的答案
        from collections import deque
        deq = deque()
        for i in range(len(presum)):
            #不满足单调性的话,弹出队尾
            while deq and presum[deq[-1]] > presum[i]:
                deq.pop()
            #满足单调递增性
            deq.append(i)
            #计算一次,注意这里要用while,比如nums = [17,85,93,-45,-21],k = 150,结果是85,93而不是17,85,93
            while presum[deq[-1]] - presum[deq[0]] >= k:
                cur_res = deq[-1] - deq.popleft()
                res = min(cur_res,res)
        if res == float("inf"):
            return -1
        return res

5977. 最少交换次数来组合所有的 1 II

 

class Solution {
public:
    int minSwaps(vector<int>& nums) {
        int n = nums.size();
        int cnt = accumulate(nums.begin(), nums.end(), 0);
        if(cnt == n || cnt == 0 || cnt == 1)
            return 0;
        int ans = 0;
        int temp = 0;
        for(int i = 0; i < cnt; i ++)
            if(nums[i] == 0)
                temp ++;
        ans = temp;
        for(int i = 0; i < n + cnt - 1; i ++)                                    //进行数组拼接
        {
            if(nums[(i + cnt) % n] == 0)                                         //如果新进的元素是0,则交换次数加1
                temp ++;                                                         //如果新出的元素是0,则交换次数减1
            if(nums[i % n] == 0)
                temp --;
            ans = min(ans, temp);
        }
        return ans;
    }
};

作者:Luna_
链接:https://leetcode-cn.com/problems/minimum-swaps-to-group-all-1s-together-ii/solution/hua-dong-chuang-kou-shu-zu-pin-jie-by-lu-bed2/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
class Solution:
    def minSwaps(self, nums: List[int]) -> int:
        n = len(nums)
        a = nums + nums
        
        cnt1 = nums.count(1)
        
        res = float('inf')
        Window_len = cnt1
        
        cur = nums[ :Window_len].count(1)
        res = min(res, cnt1 - cur)
        for r in range(Window_len, n * 2):
            #--进r
            if a[r] == 1:
                cur += 1
            #--弹l
            l = r - Window_len
            if a[l] == 1:
                cur -= 1
            #--更新res
            res = min(res, cnt1 - cur)
    
        return res

作者:Hanxin_Hanxin
链接:https://leetcode-cn.com/problems/minimum-swaps-to-group-all-1s-together-ii/solution/cpython3javago-1hua-dong-chuang-kou-by-h-l4dl/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

环形数组特性

力扣

class Solution:
    def minSwaps(self, nums: List[int]) -> int:
        #窗口长度为1的个数,窗口里最少有几个0
        count1=0
        for i in range(len(nums)):
            if nums[i]==1:
                count1+=1
        count0=0
        for i in range(count1):
            if nums[i]==0:
                count0+=1
        min_count0=count0
        cur_index=count1
        while cur_index<len(nums)*2:
            pre_index=cur_index-count1
            if nums[pre_index%len(nums)]==0:
                count0-=1
            if nums[cur_index%len(nums)]==0:
                count0+=1
            min_count0=min(min_count0,count0)
            cur_index+=1
        return min_count0

1004. 最大连续1的个数 III

class Solution(object):
    def longestOnes(self, A, K):
        N = len(A)
        res = 0
        left, right = 0, 0
        zeros = 0 
        while right < N:
            if A[right] == 0:
                zeros += 1
            while zeros > K:
                if A[left] == 0:
                    zeros -= 1
                left += 1
            res = max(res, right - left + 1)
            right += 1
        return res

作者:fuxuemingzhu
链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/fen-xiang-hua-dong-chuang-kou-mo-ban-mia-f76z/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。
    public int longestOnes(int[] A, int K) {
        int left = 0;//窗口左边的位置
        int maxWindow = 0;//窗口的最大值
        int zeroCount = 0;//窗口中0的个数
        for (int right = 0; right < A.length; right++) {
            if (A[right] == 0) {
                zeroCount++;
            }
            //如果窗口中0的个数超过了K,要缩小窗口的大小,直到0的个数
            //不大于K位置
            while (zeroCount > K) {
                if (A[left++] == 0)
                    zeroCount--;
            }
            //记录最大的窗口
            maxWindow = Math.max(maxWindow, right - left + 1);
        }
        return maxWindow;
    }

作者:sdwwld
链接:https://leetcode-cn.com/problems/max-consecutive-ones-iii/solution/hua-dong-chuang-kou-de-liang-chong-jie-j-8ses/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1493. 删掉一个元素以后全为 1 的最长子数组

class Solution:
    def longestSubarray(self, nums: List[int]) -> int:
        left=0
        right=0
        count0=0
        res=0
        while right<len(nums):
            #当有2个0的时候,收缩左指针
            while count0>1:
                if nums[left]==0:
                    count0-=1
                left+=1
            #right指针右边移动
            if nums[right]==0:
                count0+=1
                cur=right-1-left+1-1
            else:
                cur=right-left+1-1
            res=max(res,cur)
            right+=1
        return res

334 递增的三元子序列

题目要求时间复杂度o(n),空间复杂度o(1)

 两种解法:

1.最长上升子序列问题,leetcode-最大最小问题-v2_MaYingColdPlay的博客-CSDN博客,这个时间复杂度是o(n^2),会超时。

2.双指针解法,满足时间复杂度要求。

# 双指针,一个min_val,一个middle_val,如果第三个比前两个大,返回true
class Solution(object):
    def increasingTriplet(self, nums):
        """
        :type nums: List[int]
        :rtype: bool
        """
        min_val=float("inf")
        middle_val=float("inf")
        for val in nums:
            if val <= min_val:
                min_val = val
            elif val <= middle_val:
                middle_val = val
            else:
                return True
                #说明当前值比min_val和middle_val都大
        return False

时间相关计算

539 最小时间差

class Solution(object):
    # 小时:分钟格式的数据。例如 22:13,22:14
    # 先按照小时排序,再按照分钟排序
    def convert(self,n1,n2):
        #2213,2314
        s1_hour=int(str(n1)[:2])
        s2_hour=int(str(n2)[:2])
        s1_minutes=int(str(n1)[2:])
        s2_minutes =int(str(n2)[2:])
        #如果第二个分钟小于第一个分钟,小时差减去1,分钟差是s2_minutes+60-s1_minutes
        if s2_minutes<s1_minutes:
            hour_diff=(s2_hour-s1_hour-1)*60
            minutes_diff=s2_minutes+60-s1_minutes
            res1 = hour_diff + minutes_diff
        else:
            hour_diff = (s2_hour - s1_hour) * 60
            minutes_diff = s2_minutes - s1_minutes
            res1 = hour_diff + minutes_diff
        return min(res1,1440-res1)
    def getMinutes(self, timePoints):
        timePoints_merge=[]
        for i in range(len(timePoints)):
            cur=timePoints[i]
            hour=cur.split(":")[0]
            minutes=cur.split(":")[1]
            hour_minutes_str=hour+minutes
            # hour_minutes=int(hour_minutes_str)
            timePoints_merge.append(hour_minutes_str)
        timePoints_merge.sort()
        min_diff=self.convert(timePoints_merge[0],timePoints_merge[1])
        for i in range(1,len(timePoints_merge)):
            pre=timePoints_merge[i-1]
            cur=timePoints_merge[i]
            cur_diff=self.convert(pre,cur)
            min_diff=min(cur_diff,min_diff)
        #比较最后一个和第一个
        last_diff=self.convert(timePoints_merge[0],timePoints_merge[-1])
        min_diff = min(last_diff, min_diff)
        return min_diff
# timePoints=["23:59","00:00"]
# timePoints=["01:01","02:01","03:00"]
timePoints=["00:00","04:00","22:00"]
res=Solution().getMinutes(timePoints)
print(res)
def func(timePoints):
    timePoints.sort()
    left = -1
    right = 0
    min_time = 24*60

    n = len(timePoints)
    if n > 1440:
        return 0

    while right < len(timePoints):
        x = timePoints[left].split(":") # 数据
        y = timePoints[right].split(":")

        if int(y[1]) >= int(x[1]):
            time = (int(y[0]) - int(x[0]))*60 + (int(y[1]) - int(x[1]))
        else:
            time = (int(y[0]) - 1 - int(x[0]))*60 + int(y[1]) + 60 - int(x[1])

        if min(abs(time),1440-abs(time)) < min_time:
            min_time = min(abs(time),1440-abs(time))

        left = left + 1
        right = right + 1

    return min_time



作者:lnnnnnnn
链接:https://leetcode-cn.com/problems/minimum-time-difference/solution/python3-pai-xu-by-lnnnnnnn-03qp/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

1185. 一周中的第几天

1911. 最大子序列交替和

记忆化递归,超时。用flag判断奇偶性就不超时。

class Solution:
    def maxAlternatingSum(self, nums: List[int]) -> int:
        cache={}
        #每个元素的下标选或者不选两种选择
        def dfs(index,child_index):
            if (index,child_index) in cache:
                return cache[(index,child_index)]
            if index==len(nums):
                return 0
            a,b,c=0,0,0
            #index不选
            a=dfs(index+1,child_index)
            #index选
            if child_index%2==0:
                b=dfs(index+1,child_index+1)+nums[index]
            else:
                c=dfs(index+1,child_index+1)-nums[index]
            cache[(index,child_index)]=max(a,b,c)
            return max(a,b,c)
        #真实index,在子序列里的index
        return dfs(0,0)
class Solution:
    def maxAlternatingSum(self, nums: List[int]) -> int:
        cache={}
        #每个元素的下标选或者不选两种选择
        def dfs(index,flag):
            if (index,flag) in cache:
                return cache[(index,flag)]
            if index==len(nums):
                return 0
            a,b,c=0,0,0
            #index不选
            a=dfs(index+1,flag)
            #index选
            if flag:
                b=dfs(index+1,False)+nums[index]
            else:
                c=dfs(index+1,True)-nums[index]
            cache[(index,flag)]=max(a,b,c)
            return max(a,b,c)
        #真实index
        #flag代表奇数偶数,flag=True为偶数
        flag=True
        return dfs(0,flag)

1567. 乘积为正数的最长子数组长度

滑窗+脑筋急转弯

 

class Solution:
    def getMaxLen(self, nums: List[int]) -> int:

        cnt, ans, firstMinus, lastMinus, minus = 0, 0, None, None, 0

        for i in range(len(nums) + 1):
            if i == len(nums) or nums[i] == 0:    #遍历完成或者为0时,清空计数,更新ans
                if minus % 2 == 0:   #如果负数为偶数个,就不用管了
                    ans = max(ans, cnt)
                else:   #如果负数为奇数个,就去掉第一个或最后一个负数
                    ans = max(ans, cnt - firstMinus, lastMinus)
                cnt, firstMinus, lastMinus, minus = 0, None, None, 0  #重新计数

            elif nums[i] > 0:  
                cnt += 1
                
            else:
                if firstMinus == None:    #记录下第一个和最后一个(此时最后一个就是第一个)
                    firstMinus = cnt + 1
                    lastMinus = cnt
                elif lastMinus != None:   #出现了第二个负数,此时更新最后一个负数的位置
                    lastMinus = cnt
                minus += 1     #负数的个数
                cnt += 1
                
        return ans

1229 安排会议日程

 遍历,超时

#找到2个人休息时间重合的部分,看是否满足duration要求
#以slots1为基准
def testv2(slots1,slots2,duration):
    slots1.sort()
    slots2.sort()
    for i in range(len(slots1)):
        cur_left=slots1[i][0]
        cur_right=slots1[i][1]
        for j in range(len(slots2)):
                #是否有交集
            if slots2[j][0]<cur_right and slots2[j][1]>cur_left:
                left_new=max(cur_left,slots2[j][0])
                right_new=min(cur_right,slots2[j][1])
                if right_new-left_new>=duration:
                    return [left_new,left_new+duration]
    return []

 双指针,不超时

class Solution:
    def minAvailableDuration(self, slots1: List[List[int]], slots2: List[List[int]], duration: int) -> List[int]:
        #------------双指针
        slots1.sort()
        slots2.sort()
        n1, n2 = len(slots1), len(slots2)
        i = 0
        j = 0 
        while i < n1 and j < n2:
            s1, e1 = slots1[i]
            s2, e2 = slots2[j]
            s = max(s1, s2)
            e = min(e1, e2)
            if e - s >= duration:
                return [s, s + duration]
            if e1 < e2:
                i += 1
            else:
                j += 1
        return []

1001. 网格照明

 

暴力,超时

class Solution:
    def gridIllumination(self, n: int, lamps: List[List[int]], queries: List[List[int]]) -> List[int]:
        # 暴力模拟
        # 暴力模拟
        def light_dark(x, y, label):
            gird[x][y] += label
            # 同一行同一列设置为1,叠加,关灯的时候减去1
            for j in range(n):
                gird[x][j] += label
            gird[x][y] -= label
            for j in range(n):
                gird[j][y] += label
            gird[x][y] -= label
            # 左对角线设置为1,左对角线上部分是(x-1,y-1),下部分是(x+1,y+1)/右对角线设置为1,右对角线上部分是(x-1,y+1),下部分是(x+1,y-1)
            for j in range(1, n):
                if x - j >= 0 and y - j >= 0:
                    gird[x - j][y - j] += label
                if x + j < n and y + j < n:
                    gird[x + j][y + j] += label
                if x - j >= 0 and y + j < n:
                    gird[x - j][y + j] += label
                if x + j < n and y - j >= 0:
                    gird[x + j][y - j] += label

        def check_light(x, y):
            # 先检查上下左右有没有灯/上面一行,下面一行,自己的那行,到y+1
            for j in range(y - 1, y + 2):
                if [x - 1, j] in lamps and [x - 1, j] not in darked:
                    light_dark(x - 1, j, -1)
                    darked.append([x - 1, j])
                if [x, j] in lamps and [x, j] not in darked:
                    light_dark(x, j, -1)
                    darked.append([x, j])
                if [x + 1, j] in lamps and [x + 1, j] not in darked:
                    light_dark(x + 1, j, -1)
                    darked.append([x + 1, j])

        gird = [[0 for _ in range(n)] for _ in range(n)]
        visited = []
        for i in range(len(lamps)):
            if lamps[i] not in visited:
                row, col = lamps[i]
                light_dark(row, col, 1)
                visited.append(lamps[i])
        # 根据queries关灯
        res = []
        darked = []
        for i in range(len(queries)):
            row, col = queries[i]
            cur_ans = gird[row][col]
            # 如果是1,把四周设置为0
            if cur_ans > 0:
                check_light(row, col)
                res.append(1)
            else:
                res.append(cur_ans)
        return res

哈希表+数学

class Solution:
    def gridIllumination(self, n: int, lamps: List[List[int]], queries: List[List[int]]) -> List[int]:
        points = set()
        row, col, diagonal, antiDiagonal = Counter(), Counter(), Counter(), Counter()
        for r, c in lamps:
            if (r, c) in points:
                continue
            points.add((r, c))
            row[r] += 1
            col[c] += 1
            diagonal[r - c] += 1
            antiDiagonal[r + c] += 1

        ans = [0] * len(queries)
        for i, (r, c) in enumerate(queries):
            if row[r] or col[c] or diagonal[r - c] or antiDiagonal[r + c]:
                ans[i] = 1
            for x in range(r - 1, r + 2):
                for y in range(c - 1, c + 2):
                    if x < 0 or y < 0 or x >= n or y >= n or (x, y) not in points:
                        continue
                    points.remove((x, y))
                    row[x] -= 1
                    col[y] -= 1
                    diagonal[x - y] -= 1
                    antiDiagonal[x + y] -= 1
        return ans

作者:LeetCode-Solution
链接:https://leetcode-cn.com/problems/grid-illumination/solution/wang-ge-zhao-ming-by-leetcode-solution-7omu/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

6028. 统计道路上的碰撞次数

直接模拟 超时 

class Solution(object):
    def countCollisions(self, directions):
        """
        :type directions: str
        :rtype: int
        """
         # 遍历,当前是r,碰到l或者s停止,设置一个visited数组防止重复计算
        count = 0
        visited_index = set()
        directions=list(directions)
        left=0
        right=len(directions)
        for i in range(len(directions)):
            if directions[i] == 'R':
                # 往右
                for j in range(i + 1, len(directions)):
                    if (i,j) in visited_index:
                        break
                    if directions[j] == "L" :
                        count += 2
                        visited_index.add((i,j))
                        directions[i] = "S"
                        directions[j] = "S"
                        break
                    if directions[j] == "S" :
                        count += 1
                        visited_index.add((i,j))
                        directions[i] = "S"
                        break

            if directions[i] == 'L':
                # 往左
                for j in range(i - 1, -1, -1):
                    if (j,i) in visited_index:
                        break
                    # if directions[j] == "L":
                    #     break
                    if directions[j] == "R":
                        count += 2
                        visited_index.add((j,i))
                        directions[i] = "S"
                        directions[j] = "S"
                        break
                    if directions[j] == "S":
                        count += 1
                        visited_index.add((j, i))
                        directions[i] = "S"
                        break
        return count

分类讨论2次遍历

class Solution {
    public int countCollisions(String directions) {
        char[] dirs = directions.toCharArray();
        int n = dirs.length, cnt = 0;

        // 统计 L 操作出现的碰撞次数
        boolean leftLimit = false;
        for (int i = 0; i < n; i++) {
            // 左侧有车辆 S 或 R 时,说明左侧有界(L操作肯定会碰撞)
            if (!leftLimit && dirs[i] != 'L') leftLimit = true;

            if (dirs[i] == 'L' && leftLimit) cnt++;
        }

        // 统计 R 操作出现的碰撞次数
        boolean rightLimit = false;
        for (int i = n - 1; i >= 0; i--) {
            // 右侧有车辆 S 或 L 时,说明右侧有界(R操作肯定会碰撞)
            if (!rightLimit && dirs[i] != 'R') rightLimit = true;
            if (dirs[i] == 'R' && rightLimit) cnt++;
        }

        return cnt;
    }
}


作者:smqk
链接:https://leetcode-cn.com/problems/count-collisions-on-a-road/solution/by-smqk-8530/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

954. 二倍数对数组

哈希表

 力扣

class Solution:
    def canReorderDoubled(self, arr: List[int]) -> bool:
        num_map = collections.Counter(arr)
        for num in sorted(num_map, key=abs):
            if num_map[num] > num_map[2 * num]:
                return False
            num_map[2 * num] -= num_map[num]
        return True

作者:Jam007
链接:https://leetcode-cn.com/problems/array-of-doubled-pairs/solution/by-jam007-qk31/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

5302. 加密解密字符串

哈希表

 

 哈希表真牛逼,当时我是用暴力的方法,解密的时候还用了个回溯,结果超时了,最后有2个例子通不过,那个回溯应该也没法剪枝。回溯是这样的

数组[['a', 'c'], ['b'], ['a', 'c'], ['d']],在每个index的子数组里选一个数,找出所有位置的不同组合,结果例如[a,b,c,d],index 1 上取a,index 2上取b,index3上取c,index4上取d

class Encrypter:
    def __init__(self, keys, values, dictionary):
        self.keys = keys
        self.values = values
        self.dictionary = dictionary
    def encrypt(self, word1: str) -> str:
        res = ""
        for char in word1:
            index = self.keys.index(char)
            replace = self.values[index]
            res += replace
        return res
    def decrypt(self, word2: str) -> int:
        # 间隔1
        count = 0
        all = []
        for i in range(0, len(word2), 2):
            cur_repalce=[]
            cur = word2[i:i + 2]
            #找出所有下标
            values_copy = self.values.copy()
            all_index = []
            while cur in values_copy:
                index = values_copy.index(cur)
                all_index.append(index)
                values_copy[index] = "-1"
            for j in range(len(all_index)):
                repalce = self.keys[all_index[j]]
                cur_repalce.append(repalce)
            all.append(cur_repalce)
        print(all)
        #回溯遍历所有组合情况,cur_repalce里可能有多个值
        path=[]
        dfs_res=[]
         def dfs(index):
            if index == len(all):
                dfs_res.append(path[:])
                return
            cur = all[index]
            for j in range(len(cur)):
                path.append(cur[j])
                dfs(index+1)
                path.pop()
        dfs(0)
        print(dfs_res)
        for i in range(len(dfs_res)):
            cur = "".join(dfs_res[i])
            if cur in self.dictionary:
                count += 1
        print(count)
        return count

哈希表解法如下。真的很简洁,万事总归先可以想想能不能用map

class Encrypter {
public:
    unordered_map<char, string> mp;
    unordered_map<string, int> dicts;

    Encrypter(vector<char>& keys, vector<string>& values, vector<string>& dictionary) {
        int n = keys.size();
        for (int i = 0; i < n; i++) { /* 保存映射关系 */
            mp[keys[i]] = values[i];
        }
        for (auto &d : dictionary) { /* 对dict加密, 计数 */
            dicts[encrypt(d)]++;
        }
    }
    
    string encrypt(string word1) { /* 加密 */
        string ans;
        for (auto &ch : word1) {
            ans += mp[ch];
        }
        return ans;
    }
    
    int decrypt(string word2) { /* 解密, 计数 */
        return dicts[word2];
    }
};

作者:liu-xiang-3
链接:https://leetcode-cn.com/problems/encrypt-and-decrypt-strings/solution/c-mapshi-xian-by-liu-xiang-3-0930/
来源:力扣(LeetCode)
著作权归作者所有。商业转载请联系作者获得授权,非商业转载请注明出处。

467. 环绕字符串中唯一的子字符串

  哈希表计数

评论 2
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值