其他算法题解

68 阅读7分钟

CodeTop
LeetCode

多个有序数组求第K小

题目:给定一个二维数组,其中每行都是升序排序,每列是无序的,求第k小的元素
输入样例:
nums = [[1, 3], [4, 15, 23], [1, 7, 9]], k = 5
输出样例:
7
def solve(nums, k):
    # 设置一个指针数组,表示每一行的某一个数值
    position = [0] * len(nums)
    # 循环k次获取每次遍历中最小的数
    for _ in range(k):
        # 重置minn根据指针数组来比较最小值
        minn = float('inf')
        # 遍历二维升序数组中的每个数组项
        for i in range(len(nums)):
            # 如果当前项可遍历且当前项的值小于最小项的值
            if position[i] < len(nums[i]) and nums[i][position[i]] < minn:
                # 记录当前最小值和最小值所对应的数组id
                minn = nums[i][position[i]]
                mark = i
        # 最小值所对应数组指针后移
        position[mark] += 1
    return minn

if __name__ == "__main__":
	nums = [[1, 3], [4, 15, 23], [1, 7, 9]]
	ans = solve(nums, 5)
	print(ans)

二叉树子树平均值最大

题目:给你一棵二叉树的根节点 root,找出这棵树的每一棵子树的平均值中的最大值。子树是树中的任意节点和它的所有后代构成的集合。树的平均值是树中节点值的总和除以节点数。
输入样例:
nums = [5, 6, 1, 3, None, 2, 4]
输出样例:
4.5
class TreeNode:
    def __init__(self, val):
        self.val = val
        self.left = None
        self.right = None

def build(nums):
    n = len(nums)
    nodes = []
    for num in nums:
        if num:
            nodes.append(TreeNode(num))
        else:
            nodes.append(None)
    for i in range(n):
        if nodes[i]:
            if 2 * i + 1 < n:
                nodes[i].left = nodes[2 * i + 1]
            if 2 * i + 2 < n:
                nodes[i].right = nodes[2 * i + 2]
    return nodes[0]

if __name__ == "__main__":
    nums = [5, 6, 1, 3, None, 2, 4]
    root = build(nums)
    maxx = float('-inf')
    def dfs(root):
        global maxx
        if not root:
            return 0, 0
        l_values, l_nodes = dfs(root.left)
        r_values, r_nodes = dfs(root.right)
        values = root.val + l_values + r_values
        nodes = l_nodes + r_nodes + 1
        maxx = max(maxx, values / nodes)
        return values, nodes
    dfs(root)
    print(maxx)

螺栓螺母配对

题目:螺栓螺母配对,注意螺栓螺母没有重复型号
输入样例:
arr1 = [3, 5, 6, 8, 9, 1, 2, 4, 7]
arr2 = [6, 4, 9, 7, 2, 3, 5, 1, 8]
输出样例:
arr1 = [1, 1, 5, 3, 4, 2, 6, 7, 8, 9]
arr2 = [1, 1, 5, 3, 4, 2, 6, 7, 8, 9]
def quickSort(a, b, left, right):
    if left >= right:
        return 
    for i in range(len(a)):
        if a[i] == b[left]:
            mark = i
    a[left], a[mark] = a[mark], a[left]
    pivot = a[left]
    i, j = left, right
    while i < j:
        while i < j and a[j] >= pivot:
            j -= 1
        a[i] = a[j]
        while i < j and a[i] <= pivot:
            i += 1
        a[j] = a[i]
    a[i] = pivot
    b[left], b[i] = b[i], b[left]
    for i in range(len(b)):
        if b[i] == a[left]:
            mark = i
    b[left], b[mark] = b[mark], b[left]
    pivot = b[left]
    i, j = left, right
    while i < j:
        while i < j and b[j] >= pivot:
            j -= 1
        b[i] = b[j]
        while i < j and b[i] <= pivot:
            i += 1
        b[j] = b[i]
    b[i] = pivot
    a[left], a[i] = a[i], a[left]
    quickSort(a, b, left, i - 1)
    quickSort(a, b, i + 1, right)

if __name__ == "__main__":
    arr1 = [3, 5, 1, 6, 8, 9, 1, 2, 4, 7]
    arr2 = [6, 4, 9, 1, 7, 2, 3, 5, 1, 8]
    quickSort(arr1, arr2, 0, len(arr1) - 1)
    print(arr1)
    print(arr2)

链表奇偶升序

题目:一个链表奇数位升序,偶数位降序,不用额外空间让这个链表整体升序
输入样例:
nums = [1, 8, 3, 6, 5, 4, 7, 2, 9]
输出样例:
1->2->3->4->5->6->7->8->9
class ListNode:
    def __init__(self, val):
        self.val = val
        self.next = None

def build(nums):
    dummyHead = ListNode(-1)
    p = dummyHead
    for i in range(len(nums)):
        node = ListNode(nums[i])
        p.next = node
        p = p.next
    return dummyHead.next

def split(head):
    evenHead = head.next
    odd, even = head, evenHead
    while even and even.next:
        odd.next = even.next
        odd = odd.next
        even.next = odd.next
        even = even.next
    odd.next = None
    return head, evenHead

def reverse(head):
    pre = None
    while head:
        n = head.next
        head.next = pre
        pre = head
        head = n
    return pre

def merge(head1, head2):
    dummyHead = ListNode(-1)
    p = dummyHead
    while head1 and head2:
        if head1.val < head2.val:
            p.next = head1
            head1 = head1.next
        else :
            p.next = head2
            head2 = head2.next
        p = p.next
    if head1:
        p.next = head1
    else :
        p.next = head2
    return dummyHead.next

def solve(head):
    odd, even = split(head)
    even = reverse(even)
    return merge(odd, even)

if __name__ == "__main__":
    nums = [1, 8, 3, 6, 5, 4, 7, 2, 9]
    head = build(nums)
    res = solve(head)

递增数组找差绝对值最小的数

题目:从递增数组中找到差绝对值最小的数
输入样例:
nums = [1, 2, 3, 4, 7, 7, 11, 11]
target = 8
输出样例:
7
def solve(nums, l, r, target):
    while l <= r:
        mid = (l + r) // 2
        if target <= nums[mid]:
            r = mid - 1
        else:
            l = mid + 1
    return l

if __name__ == "__main__":
    nums = [1, 2, 3, 4, 7, 7, 11, 11]
    target = 8
    n = len(nums)
    # 找到最适合插入的位置
    ans = solve(nums, 0, n - 1, target)
    # 数组末尾
    if ans > n - 1:
        print(nums[n - 1])
    # 数组最前端
    elif ans == 0:
        print(nums[ans])
    # 数组中间,得到左右数值的最小差值
    else:
        sub1 = abs(nums[ans - 1] - target)
        sub2 = abs(nums[ans] - target)
        if sub1 <= sub2:
            print(nums[ans - 1])
        else:
            print(nums[ans])

k数之和

题目:给定 n 个不同的正整数,整数 k(k <= n)以及一个目标数字 target。在这 n 个数里面找出 k 个数,使得这 k 个数的和等于目标数字,求问有多少种方案?
输入样例:
nums = [1, 1, 2, 3, 4] 
k = 2, target = 5
输出样例:
3
if __name__ == "__main__":
    nums = [1, 1, 2, 3, 4]
    n, k, target = len(nums), 2, 5
    # 前i个数中选j个数的和为t的方案数有dp[i][j][t]
    dp = [[[0] * (target + 1) for _ in range(k + 1)] for _ in range(n + 1)]
    # 当k为0、target为0时,赋初值方案数为1
    for i in range(n + 1):
        dp[i][0][0] = 1
    for i in range(1, n + 1):
        # 对于选择的数值个数有限制
        for j in range(1, min(i, k) + 1):
            for t in range(target + 1):
                # 不选当前物品的方案数
                dp[i][j][t] = dp[i - 1][j][t]
                if t >= nums[i - 1]:
                    # 选取当前物品的方案数加上不选取的方案数为总方案数
                    dp[i][j][t] += dp[i - 1][j - 1][t - nums[i - 1]] 
    print(dp[n][k][target])

小于n的最大数

题目:数组中给定可以使用的1~9的数,返回由数组中的元素组成的小于n(n > 0)的最大数。
输入样例:
A = [1, 2, 4, 9]
n = 2533
输出样例:
2499
def bs(array, target):
    l, r = 0, len(array) - 1
    while l <= r:
        mid = (l + r) // 2
        if array[mid] <= target:
            l = mid + 1
        else:
            r = mid - 1
    return r

def max_num(array, n):
    # 从小到大排序
    array.sort()
    length = len(array)
    # 因为要找小于n,所以先让n减一
    n -= 1
    num_array = [int(x) for x in str(n)]
    # 记录所取array下标
    ret = [0] * len(num_array)  
    max_num = array[-1]
    min_num = array[0]
    if n < min_num:
        # 极端情况
        return -1
    flag = False
    l, r = -1, 0
    while r < len(num_array):
        if not flag:
            cur_value = num_array[r]
            if cur_value < min_num:
                # 如果前方无可减小的,证明无法组成与n同长度的,那么长度减一
                if l == -1:
                    return int(''.join([str(max_num)] * (len(num_array) - 1)))
                # 相当于回溯
                else:
                    ret[l] -= 1
                    flag = True
                    r = l + 1
                    continue
            # 如果是最小值,则l为前一个值
            elif cur_value == min_num:
                ret[r] = 0
            else:
                # 通过二分找数字下标
                index = bs(array, cur_value)
                if array[index] < cur_value:
                    flag = True
                ret[r] = index
                l = r
        else:
            ret[r] = length - 1
        r += 1

    return int(''.join([str(array[value]) for value in ret]))

if __name__ == "__main__":
    dic = {}
    dic[122] = [9, 8]
    dic[2533] = [1, 2, 9, 4]
    dic[24131] = [4, 2, 5]
    dic[9911] = [1, 9]
    dic[1] = [1, 2, 4, 9]
    dic[1111] = [1]
    for k, v in dic.items():
        res = max_num(v, k)
        print(res)

最长公共子串

题目:对于两个字符串 str1 和 str2,求最长公共子串。(区别于公共子序列)
输入样例:
str1 = "acbcad"
str2 = "abcadfd"
输出样例:
ans = 4
if __name__ == "__main__":
    str1 = "acbcad"
    str2 = "abcadfd"
    n1, n2 = len(str1), len(str2)
    dp = [[0 for _ in range(n2 + 1)] for _ in range(n1 + 1)]
    maxx = -1
    for i in range(1, n1 + 1):
        for j in range(1, n2 + 1):
            if str1[i - 1] == str2[j - 1]:
                dp[i][j] = dp[i - 1][j - 1] + 1
            else:
                dp[i][j] = 0
            maxx = max(maxx, dp[i][j])
    print(maxx)

最长递增子串

题目:对于一个数组,求最长递增子串。(区别于子序列)
输入样例:
nums = [3, 1, 4, 5, 8, 7, 9]
输出样例:
ans = 4
if __name__ == "__main__":
    nums = [3, 1, 4, 5, 8, 7, 9]
    n = len(nums)
    maxx = -1
    ans = 1
    for i in range(1, n):
        if nums[i] > nums[i - 1]:
            ans += 1
        else:
            ans = 1
        maxx = max(maxx, ans)
    print(maxx)

整数与IP地址间的转换

题目:输出转换成10进制的IP地址;输出转换后的IP地址
输入样例:
10.0.3.193
167969729
输出样例:
167773121
10.3.3.193
def ip_to_num(ip):
    arr = [int(s) for s in ip.split('.')][::-1]
    ans = 0
    for i, num in enumerate(arr):
        ans += num * 2 ** (8 * i)
    return ans

def num_to_ip(num):
    ans = []
    div, i = 2 ** 8, 3
    while i > -1:
        seg = num // (div ** i)
        num = num % (div ** i)
        ans.append(str(seg))
        i -= 1
    return '.'.join(ans)

if __name__ == "__main__":
    ip = "10.0.3.193"
    num = 167969729
    print(ip_to_num(ip))
    print(num_to_ip(num))