日渐头秃的代码日记 -- 第321场周赛磕磕绊绊了

253 阅读4分钟

一、找出中枢整数

给你一个正整数 n ,找出满足下述条件的 中枢整数 x :

  • 1 和 x 之间的所有元素之和等于 x 和 n 之间所有元素之和。

返回中枢整数 **x 。如果不存在中枢整数,则返回 -1 。题目保证对于给定的输入,至多存在一个中枢整数。

 

示例 1:

输入: n = 8
输出: 6
解释: 6 是中枢整数,因为 1 + 2 + 3 + 4 + 5 + 6 = 6 + 7 + 8 = 21

示例 2:

输入: n = 1
输出: 1
解释: 1 是中枢整数,因为 1 = 1

示例 3:

输入: n = 4
输出: -1
解释: 可以证明不存在满足题目要求的整数。

 

提示:

  • 1 <= n <= 1000

解析

因为n的范围不大,所以可以直接暴力计算,当然也可以用数学的方法,1到x的求和公式等于x到n的求和公式,得出来的结果是x等于根号下n*(n+1)/2,如果开根号之后是整数,就是结果,不是整数,就返回-1

代码

class Solution:
    def pivotInteger(self, n: int) -> int:
        if n == 1:
            return 1
        
        l = [i for i in range(1, n+1)]
        for x in range(len(l)):
            if sum(l[:x+1]) == sum(l[x:]):
                return x+1
        return -1

二、追加字符以获得子序列

给你两个仅由小写英文字母组成的字符串 s 和 t 。

现在需要通过向 s 末尾追加字符的方式使 t 变成 s 的一个 子序列 ,返回需要追加的最少字符数。

子序列是一个可以由其他字符串删除部分(或不删除)字符但不改变剩下字符顺序得到的字符串。

 

示例 1:

输入: s = "coaching", t = "coding"
输出: 4
解释: 向 s 末尾追加字符串 "ding" ,s = "coachingding" 。
现在,t 是 s ("coachingding") 的一个子序列。
可以证明向 s 末尾追加任何 3 个字符都无法使 t 成为 s 的一个子序列。

示例 2:

输入: s = "abcde", t = "a"
输出: 0
解释: t 已经是 s ("abcde") 的一个子序列。

示例 3:

输入: s = "z", t = "abcde"
输出: 5
解释: 向 s 末尾追加字符串 "abcde" ,s = "zabcde" 。
现在,t 是 s ("zabcde") 的一个子序列。 
可以证明向 s 末尾追加任何 4 个字符都无法使 t 成为 s 的一个子序列。

 

提示:

  • 1 <= s.length, t.length <= 10^5
  • s 和 t 仅由小写英文字母组成

解析

题目要求是在s的结尾追加字符,以使得t变成s的一个子序列。遍历t的每一个字符的时候,如果它在s当中出现,并且出现的位置大于上一个字符出现的位置即可,当发现t里的某一个字符没有在s里出现,那么从这个字符开始,后边的所有字符都需要被追加到s后面。

当然也可以反过来,在层遍历s,跟t的一个字符进行比较,当发现相等的时候,下一次比较的目标值就是t的下一个字符,直到s结束,t里还剩下多少个字符,就需要补充多少个

代码

class Solution:
    def appendCharacters(self, s: str, t: str) -> int:
        i = 0
        length = len(t)
        for c in s:
            if i < length and c == t[i]:
                i += 1
        return length - i

三、从链表中移除节点

给你一个链表的头节点 head 。

对于列表中的每个节点 node ,如果其右侧存在一个具有 严格更大 值的节点,则移除 node 。

返回修改后链表的头节点 **head **。

 

示例 1:

输入: head = [5,2,13,3,8]
输出: [13,8]
解释: 需要移除的节点是 5 ,2 和 3 。
- 节点 13 在节点 5 右侧。
- 节点 13 在节点 2 右侧。
- 节点 8 在节点 3 右侧。

示例 2:

输入: head = [1,1,1,1]
输出: [1,1,1,1]
解释: 每个节点的值都是 1 ,所以没有需要移除的节点。

 

提示:

  • 给定列表中的节点数目在范围 [1, 10^5] 内
  • 1 <= Node.val <= 10^5

解析

这题目本身没什么难度,就是找到一个严格降序的链表即可,注意,题目没有要求是在原链表上操作,因此可以简单的把各个节点的值取出来,放到一个数组里,在数组里进行个钟操作即可,复杂程度迅速降低。

代码

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def removeNodes(self, head: Optional[ListNode]) -> Optional[ListNode]:
        vals = []
        while head:
            vals.append(head.val)
            head = head.next
        vals = vals[::-1]
        m = 0
        t = []
        for v in vals:
            if v >= m:
                m = v
                t.append(v)
        t = t[::-1]
        nodes = [ListNode(val=x) for x in t]
        for i in range(1, len(nodes)):
            nodes[i-1].next = nodes[i]
        return nodes[0]

原地操作的版本

# Definition for singly-linked list.
# class ListNode:
#     def __init__(self, val=0, next=None):
#         self.val = val
#         self.next = next
class Solution:
    def reverseNodes(self, head: ListNode) -> ListNode:
        if not head:
            return None
        if not head.next:
            return head
        head.hold = 1
        headNode = self.reverseNodes(head.next)
        headNode.hold = 1
        head.next.next = head
        head.next = None
        head.hold = 1
        return headNode
    
    def reverseBackNodes(self, head: ListNode) -> ListNode:
        if not head:
            return None
        if not head.next:
            return head
        headNode = self.reverseBackNodes(head.next)
        head.next.next = head
        head.next = None
        return headNode
    
    def printNode(self, head):
        while head:
            print("print", head.val, head.hold)
            # if head.hold == 1:
            #     print(head.val)
            head = head.next
            
    def checkNode(self, head):
        if not head:
            return None

        if head.hold:
            return head
        else:
            return head.next
        head.next = self.checkNode(head.next)
        if head.next:
            print("check", head.next.val, head.next.hold)
        return head
    
    def removeNodes(self, head: Optional[ListNode]) -> Optional[ListNode]:
        reverseHead = self.reverseNodes(head)
        # self.printNode(reverseHead)
        current_max = 0
        start = reverseHead
        while start and start.val > 0:
            if start.val >= current_max:
                start.hold = 1
                current_max = start.val
            else:
                start.hold = 0
            # print(start.val, start.hold)
            start = start.next
        reverseBack = self.reverseBackNodes(reverseHead)
        newHead = None
        tmp = reverseBack
        while tmp:
            if tmp.hold == 1:
                newHead = tmp
                break
            else:
                tmp = tmp.next
        print("从newHead开始: %s" % newHead.val)
        stack = []
        # stack.append(newHead)
        tmp = newHead
        while tmp:
            if tmp.hold:
                if not stack:
                    stack.append(tmp)
                else:
                    stack[-1].next = tmp
                    stack.append(tmp)
            tmp = tmp.next
        return stack[0]

四、统计中位数为 K 的子数组

给你一个长度为 n 的数组 nums ,该数组由从 1 到 n 的 不同 整数组成。另给你一个正整数 k 。

统计并返回 num 中的 中位数 等于 k 的非空子数组的数目。

注意:

  • 数组的中位数是按 递增 顺序排列后位于 中间 的那个元素,如果数组长度为偶数,则中位数是位于中间靠  的那个元素。

    • 例如,[2,3,1,4] 的中位数是 2 ,[8,4,3,5,1] 的中位数是 4 。
  • 子数组是数组中的一个连续部分。

 

示例 1:

输入: nums = [3,2,1,4,5], k = 4
输出: 3
解释: 中位数等于 4 的子数组有:[4][4,5][1,4,5]

示例 2:

输入: nums = [2,3,1], k = 3
输出: 1
解释: [3] 是唯一一个中位数等于 3 的子数组。

 

提示:

  • n == nums.length
  • 1 <= n <= 10^5
  • 1 <= nums[i], k <= n
  • nums 中的整数互不相同

解析

这道题难度并不大,有一个细节需要注意,题目要找的是中位数,不是平均数,中位数是一定存在于这个子数组中的,而平均数不一定。在初看此题的时候,这里理解有误,比如1,2,4,5 的中位数应该是2,我给理解成了3,所以在算3,1,2,4,5且k为3的时候,总比答案多一个值。

当考虑到中位数必须存在于子数组之中的时候,题目就变得简单了。

先找到这个k的位置,如果要使得子数组的中位数是k,则整体上,比k大的个数要等于比k小的个数,或者比k大的个数减去比k小的个数,差值为1.

中位数只需要比较大小,不看具体值是多少。

代码

class Solution:
    def countSubarrays(self, nums: List[int], k: int) -> int:
        pos = nums.index(k)
        cnt = defaultdict(int)
        cnt[0] = 1  # i=pos 的时候 c 是 0,直接记到 cnt 中,这样下面不是大于就是小于
        c = 0
        for i in range(pos + 1, len(nums)):
            c += 1 if nums[i] > k else -1
            cnt[c] += 1

        ans = cnt[0] + cnt[1]  # i=pos 的时候 c 是 0,直接加到答案中,这样下面不是大于就是小于
        c = 0
        for i in range(pos - 1, -1, -1):
            c += 1 if nums[i] < k else -1
            ans += cnt[c] + cnt[c + 1]
        return ans