牛客网刷题2--python

链表中环的入口节点

给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。
解法
参考:https://blog.csdn.net/wszll_Alex/article/details/86741909
牛客网刷题2--python_第1张图片

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        if not pHead:
            return None
        fast = slow = pHead
        while fast and fast.next:
            slow = slow.next
            fast = fast.next.next
            
            if fast == slow:
                fast = pHead
                while fast != slow:
                    fast = fast.next
                    slow = slow.next
                return fast
            
        return None

包含min函数的栈

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。
注意:保证测试中不会当栈为空的时候,对栈调用pop()或者min()或者top()方法。

解法
其实就是提前存下一个min值,随时更新它就可以。

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack = []
        self.mi = 100000
        
    def push(self, node):
        # write code here
        self.stack.append(node)
        if node < self.mi:
            self.mi = node
            
    def pop(self):
        # write code here
        t = self.stack[-1]
        self.stack = self.stack[:-1]
        if t == self.mi:
            self.mi = 100000
            for x in self.stack:
                if x < self.mi:
                    self.mi = x
                
        return t
    
    def top(self):
        # write code here
        t = self.stack[-1]
        return t
    
    def min(self):
        # write code here
        return self.mi
        

字符流中第一个不重复的字符

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。
输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。

解法
想到了哈希,用一个列表存储所有进来的字符,随时判断每个字符是否重复,并且随时更新当前指向第一个不重复字符的指针。
但是后来看了解析,发现并不需要这么复杂,可以使用队列的思想,不需要保存下所有字符,只需要保存那些不重复的字符。

  • 入队:获取字符流中的一个字符时,当我们判断它是不重复时,将它加入队列;
  • 输出/出队:注意,因为队列中存储的 “不重复字符” 在一系列的流读取操作后,随时有可能改变状态(变重复),所以,队列中的字符不能直接输出,要先进行一次重复判断,如果发现队头字符已经重复了,就将它移出队列并判断新的队头,否则,输出队头的值;
# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.s = []
        self.dic = {}
        self.idx = -1
    # 返回对应char
    def FirstAppearingOnce(self):
        # write code here
        if self.idx == -1:
            return "#"
        return self.s[self.idx]
    
    def Insert(self, char):
        # write code here
        self.s.append(char)
        if char not in self.dic:
            self.dic[char] = 1
            if self.idx == -1:
                self.idx = len(self.s) - 1
        else:
            self.dic[char] += 1
            
        if self.idx != -1 and self.dic[self.s[self.idx]] > 1:
            flag = 0
            for i in range(self.idx + 1, len(self.s)):
                if self.dic[self.s[i]] == 1:
                    self.idx = i
                    flag = 1
                    break
            if flag == 0:
                self.idx = -1
                    

把二叉树打印出多行

从上到下按层打印二叉树,同一层结点从左至右输出。每一层输出一行。

解法
二叉树的层次遍历用的就是BFS,为了确定当前是哪一行,所以需要在队列中再保存一个当前的层数。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表[[1,2],[4,5]]
    def Print(self, pRoot):
        # write code here
        if not pRoot:
            return []
        res = [[]]
        q = []
        q.append((pRoot, 0))
        
        while q:
            cur, n = q.pop(0)
            if n >= len(res):
                res.append([])
            res[n].append(cur.val)
            if cur.left:
                q.append((cur.left, n + 1))
            if cur.right:
                q.append((cur.right, n + 1))
                
        return res

数字在排序数组中出现的次数

统计一个数字在排序数组中出现的次数。

解法

  • 暴力遍历一遍
  • 二分法:找到当前值的任何一个位置Idx,然后遍历得到上界和下界
  • 二分法:两次二分得到上界和下界
# -*- coding:utf-8 -*-
class Solution:
    def GetNumberOfK(self, data, k):
        # write code here
        if not data:
            return 0
        l, r = 0, len(data) - 1
        idx = -1
        while l <= r:
            mid = (l + r) // 2
            if data[mid] == k:
                idx = mid
                break
            elif data[mid] < k:
                l = mid + 1
            elif data[mid] > k :
                r = mid - 1
            
        if idx == -1:
            return 0
        res = 0
        for i in range(idx, len(data)):
            if data[i] == k:
                res += 1
            elif data[i] > k:
                break
        for i in range(idx - 1, -1, -1):
            if data[i] == k:
                res += 1
            elif data[i] < k:
                break
                
        return res
# -*- coding:utf-8 -*-
class Solution:
    def GetNumberOfK(self, data, k):
        # write code here
        if not data:
            return 0
        l, r = 0, len(data)
        while l < r:
            mid = (l + r) // 2
            if data[mid] < k:
                l = mid + 1
            else:
                r = mid
        lower = l
        
        l, r = 0, len(data)
        while l < r:
            mid = (l + r) // 2
            if data[mid] <= k:
                l = mid + 1
            else:
                r = mid
        upper = l
        
        return upper - lower

圆圈中最后剩下的数

每年六一儿童节,牛客都会准备一些小礼物去看望孤儿院的小朋友,今年亦是如此。HF作为牛客的资深元老,自然也准备了一些小游戏。其中,有个游戏是这样的:首先,让小朋友们围成一个大圈。然后,他随机指定一个数m,让编号为0的小朋友开始报数。每次喊到m-1的那个小朋友要出列唱首歌,然后可以在礼品箱中任意的挑选礼物,并且不再回到圈中,从他的下一个小朋友开始,继续0…m-1报数…这样下去…直到剩下最后一个小朋友,可以不用表演,并且拿到牛客名贵的“名侦探柯南”典藏版(名额有限哦!!_)。请你试着想下,哪个小朋友会得到这份礼品呢?(注:小朋友的编号是从0到n-1)

如果没有小朋友,请返回-1

解法
参考:https://www.nowcoder.com/questionTerminal/f78a359491e64a50bce2d89cff857eb6?answerType=1&f=discussion

  • 模拟法

  • 递归法:假设f(n, m) 表示最终留下元素的序号。
    首先,长度为 n 的序列会先删除第 m % n 个元素,然后剩下一个长度为 n - 1 的序列。那么,我们可以递归地求解 f(n - 1, m),就可以知道对于剩下的 n - 1 个元素,最终会留下第几个元素,我们设答案为 x = f(n - 1, m)。
    由于我们删除了第 m % n 个元素,将序列的长度变为 n - 1。当我们知道了 f(n - 1, m) 对应的答案 x 之后,我们也就可以知道,长度为 n 的序列最后一个删除的元素,应当是从 m % n 开始数的第 x 个元素。因此有 f(n, m) = (m % n + x) % n = (m + x) % n。
    当n等于1时,f(1,m) = 0

  • 迭代法:从递归法延伸过来的,因为递归会超时

# -*- coding:utf-8 -*-
class Solution:
    def LastRemaining_Solution(self, n, m):
        # write code here
        if n < 1:
            return -1
        
        res = 0
        for i in range(2, n + 1):
            res = (res + m) % i
            
        return res

数组中只出现一次的数字

一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。

解法

  • 哈希:用字典存储次数
  • 异或:如果a、b两个值不相同,则异或结果为1。如果a、b两个值相同,异或结果为0。所以,我们可以让数组中的每一个数异或一下,最后会得到一个结果ret,就是两个出现一次的数字的异或结果这个结果肯定是由两个不同数字异或而来,因此我们找ret二进制中为1的位置i,因为1一定是由0,1异或而来,因此要求得两个数中,一定有一个数的二进制中的第i个位置为1, 一个为0.

如何找到位置i?可用i = ret ^ (-ret)
因为计算机用补码存取二进制数,而负数的补码为反码+1,举个例子
假如ret = 1110 , -ret = 0010 , 所以 i = 0010
所以,再异或一遍即可得到答案。

# -*- coding:utf-8 -*-
class Solution:
    # 返回[a,b] 其中ab是出现一次的两个数字
    def FindNumsAppearOnce(self, array):
        # write code here
        tmp = 0
        for x in array:
            tmp ^= x
            
        res = tmp & (-tmp)
        num1, num2 = 0, 0
        for x in array:
            if x & res:
                num1 ^= x
            else:
                num2 ^= x
                
        return [num1, num2]

二叉树的下一个节点

给定一个二叉树和其中的一个结点,请找出中序遍历顺序的下一个结点并且返回。注意,树中的结点不仅包含左右子结点,同时包含指向父结点的指针。

解法
参考:https://www.nowcoder.com/questionTerminal/9023a0c988684a53960365b889ceaf5e?answerType=1&f=discussion

  • 模拟法:根据给出的结点求出整棵树的根节点;根据根节点递归求出树的中序遍历,存下;遍历查找当前结点,则当前结点的下一结点即为所求。
  • 分情况:一种情况是节点有右子树的时候,就是要得到右子树的最左节点;另一种情况就是没有右子树的时候,就是找父节点,但是也要分具体情况。
# -*- coding:utf-8 -*-
# class TreeLinkNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
#         self.next = None
class Solution:
    def GetNext(self, pNode):
        # write code here
        if not pNode:
            return None
        
        cur = pNode
        if cur.right:
            cur = cur.right
            while cur.left:
                cur = cur.left
            return cur
        
        while cur.next:
            tmp = cur.next
            if tmp.left == cur:
                return tmp
            cur = cur.next
            
        return None

栈的压入、弹出序列

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

解法
链接:https://www.nowcoder.com/questionTerminal/d77d11405cc7470d82554cb392585106?answerType=1&f=discussion
来源:牛客网

直接模拟即可。因为弹出之前的值都会先入栈,所以这里用个栈来辅助。

  • 初始化:用指针i指向pushV的第一个位置, 指针j指向popV的第一个位置;
  • 如果pushV[i] != popV[j], 那么应该将pushV[i]放入栈中, ++i
  • 否则,pushV[i]==popV[j], 说明这个元素是放入栈中立马弹出,所以,++i, ++j,然后应该检查popV[j],与栈顶元素是否相等,如果相等,++j, 并且弹出栈顶元素
  • 重复2,3, 如果i==pushV.size(), 说明入栈序列访问完,此时检查栈是否为空,如果为空,说明匹配,斗则不匹配。
# -*- coding:utf-8 -*-
class Solution:
    def IsPopOrder(self, pushV, popV):
        # write code here
        l, r = 0, 0
        stack = []
        while pushV:
            tmp = pushV.pop(0)
            if tmp != popV[0]:
                stack.append(tmp)
            else:
                popV.pop(0)
                if not popV:
                    return True
                while stack[-1] == popV[0]:
                    stack.pop(-1)
                    popV.pop(0)
                    if not popV:
                        return True
        
        return False

和为S的两个数字

输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输出描述:
对应每个测试案例,输出两个数,小的先输出。

解法
开始自己一直陷在递增排序所以用二分法的解法中,然后又不希望遍历,就想找规律,什么样的两个数乘积最小,后来发现无解,于是看了题解。

  • 哈希法:忽略递增这个条件,要求a + b = sum, 如果已知a, 那么b = sum - a,所以可以先遍历一遍将b添加入哈希中,然后遍历一遍数组设为a, 在哈希中寻找是否存在sum-a,顺便更新乘积最小值。
  • 双指针:遇到排序数组既要想到二分法也要想到双指针。一左一右,如果arr[i] + arr[j] == sum , 说明是可能解;否则如果arr[i] + arr[j] > sum, 说明和太大,所以–j ;否则如果arr[i] + arr[j] < sum, 说明和太小,所以++i
# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, array, tsum):
        # write code here
        l, r = 0, len(array) - 1
        mul = 100000
        res = []
        while l < r:
            if array[l] + array[r] == tsum:
                if array[l] * array[r] < mul:
                    res = [array[l], array[r]]
                    mul = array[l] * array[r]
                l += 1
                r -= 1
            elif array[l] + array[r] > tsum:
                r -= 1
            else:
                l += 1
                
        return res

数组中重复的数字

在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

解法

  • 哈希法:忽略第一个条件,正常遍历一遍数组存储到哈希中,然后就可以找到第一个出现的重复的数字。
  • in-place算法:数据的范围是0-n-1条件没有用到。所以我们可以这么做:设置一个指针i指向开头0,对于arr[i]进行判断,如果arr[i] == i, 说明下标为i的数据正确的放在了该位置上,让i++;如果arr[i] != i, 说明没有正确放在位置上,那么我们就把arr[i]放在正确的位置上,也就是交换arr[i] 和arr[arr[i]]。交换之后,如果arr[i] != i, 继续交换。如果交换的过程中,arr[i] == arr[arr[i]],说明遇到了重复值,返回即可。
# -*- coding:utf-8 -*-
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        # write code here
        for i in range(len(numbers)):
            while i != numbers[i]:
                if numbers[i] == numbers[numbers[i]]:
                    duplication[0] = numbers[i]
                    return True
                else:
                    tmp = numbers[i]
                    numbers[i] = numbers[numbers[i]]
                    numbers[tmp] = tmp
                    #numbers[i], numbers[numbers[i]] = numbers[numbers[i]], numbers[i]
                    
        return False

二叉搜索树与双向链表

输入一棵二叉搜索树,将该二叉搜索树转换成一个排序的双向链表。要求不能创建任何新的结点,只能调整树中结点指针的指向。

解法
参考:https://www.nowcoder.com/questionTerminal/947f6eb80d944a84850b0538bf0ec3a5?answerType=1&f=discussion

  • 辅助数组:最容易想到的,是用一个数组来存储中序遍历的节点,然后再从头到尾,建立节点前后的连接关系。
  • 线索化二叉树:因为二叉排序树中序遍历的结果是排好序的,很容易联想到用线索化二叉树的方法去做,用一个全局变量去保存前一个节点,然后再去创建节点之间的关系(这里区别与线索化二叉树的是,线索化二叉树创建节点之间的关系是在节点的左右孩子为空的时候采取创建,这样二叉树还是二叉树。但是这里就不是,只要pre不空,就创建关系,创建后就是链表了。但是要注意,返回的双向链表是降序排列的,那我们有两种解决方法,第一种是再遍历一遍得到的结果,将节点的最后一个结果返回。第二种是设置一个变量来记录。
  • 优化:我们受到惯性思维的约束,每次都是想着中序遍历先遍历左子树,再遍历根节点,再遍历右子树。那既然第二种方法得到的二叉树是降序的,那我先遍历右子树,再遍历根节点,再遍历左子树不就可以了么
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def __init__(self):
        self.pre = None
    def Convert(self, pRootOfTree):
        # write code here
        if pRootOfTree == None:
            return None
        self.Convert(pRootOfTree.right)
        if self.pre != None:
            pRootOfTree.right = self.pre
            self.pre.left = pRootOfTree
            
        self.pre = pRootOfTree
        self.Convert(pRootOfTree.left)
        return self.pre

第一个只出现一次的字符

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)

解法
本来以为会有优雅点的解法,但发现就是直接哈希。第一遍哈希得到字符次数,第二遍找到第一个位置

# -*- coding:utf-8 -*-
class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        dic = {}
        for x in s:
            if x not in dic:
                dic[x] = 0
            dic[x] += 1
            
        for i in range(len(s)):
            if dic[s[i]] == 1:
                return i
            
        return -1

数组中出现次数超过一半的数字

数组中有一个数字出现的次数超过数组长度的一半,请找出这个数字。例如输入一个长度为9的数组{1,2,3,2,2,2,5,4,2}。由于数字2在数组中出现了5次,超过数组长度的一半,因此输出2。如果不存在则输出0。

解法

  • 哈希法:可以先遍历一遍数组,在map中存每个元素出现的次数,然后再遍历一次数组,找出众数。
  • 排序法:可以先将数组排序,然后可能的众数肯定在数组中间,然后判断一下。
  • 投票法:加入数组中存在众数,那么众数一定大于数组的长度的一半。思想就是:如果两个数不相等,就消去这两个数,最坏情况下,每次消去一个众数和一个非众数,那么如果存在众数,最后留下的数肯定是众数。

注意:记得最后要判断一下最后得到的数字是否真的是众数。这几种方法的时间复杂度都是O(n)。

# -*- coding:utf-8 -*-
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        # write code here
        cnt, tmp = 1, numbers[0]
        for x in numbers[1:]:
            if x == tmp:
                cnt += 1
            else:
                cnt -= 1
                if cnt == 0:
                    cnt = 1
                    tmp = x
                    
        cnt = 0
        for x in numbers:
            if x == tmp:
                cnt += 1
        if cnt > len(numbers)/2:
            return tmp
        
        return 0

把数组排成最小的数

输入一个正整数数组,把数组里所有数字拼接起来排成一个数,打印能拼接出的所有数字中最小的一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

解法

  • 冒泡排序:先将数组中每个元素转换成String类型,然后进行排序,如果str(a) + str(b) > str(b) + str(a),说明ab > ba,应该把b排在a前面。
  • 使用sorted函数和匿名函数
def PrintMinNumber(self, numbers):
    # write code here
    n = len(numbers)
    for i in range(n):
        for j in range(i+1, n):
            if int(str(numbers[i]) + str(numbers[j]) > str(numbers[j]) + str(numbers[i])):
                numbers[j], numbers[i] = numbers[i], numbers[j]
    return ''.join([str(i) for i in numbers])
# -*- coding:utf-8 -*-
class Solution:
    def PrintMinNumber(self, numbers):
        # write code here
        lmb = lambda a, b: int(str(a) + str(b)) - int(str(b) + str(a))
        numbers = sorted(numbers, cmp=lmb)
        res = "".join(str(x) for x in numbers)
        return res

和为S的连续正数序列

小明很喜欢数学,有一天他在做数学作业时,要求计算出9~16的和,他马上就写出了正确答案是100。但是他并不满足于此,他在想究竟有多少种连续的正数序列的和为100(至少包括两个数)。没多久,他就得到另一组连续正数和为100的序列:18,19,20,21,22。现在把问题交给你,你能不能也很快的找出所有和为S的连续正数序列? Good Luck!
输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序

解法
参考:https://www.nowcoder.com/questionTerminal/c451a3fd84b64cb19485dad758a55ebe?answerType=1&f=discussion

  • 暴力法:用指针i枚举目标序列的左边界,用指针j枚举目标序列的右边界,用指针k枚举区间[i, j],来计算区间和,看是否等于目标sum。
  • 前缀法:sum[i]表示前i个数的和。比如sum[1] = 1,表示前一个数的和为1,sum[2] = 3, 表示前2个数的和为3.现在我们要求区间[2,4]表示求第2,3,4个数的和,就等于sum[4] - sum[1] = 9,代码中我们用一个变量来模拟这个前缀和。
  • 滑动窗口:初始化,i=1,j=1, 表示窗口大小为0;如果窗口中值的和小于目标值sum, 表示需要扩大窗口,j += 1;否则,如果狂口值和大于目标值sum,表示需要缩小窗口,i += 1;否则,等于目标值,存结果,缩小窗口,继续进行步骤2,3,4。
# -*- coding:utf-8 -*-
class Solution:
    def FindContinuousSequence(self, tsum):
        # write code here
        l, r = 1, 1
        tmp = 0
        res = []
        while l <= tsum/2:
            if tmp < tsum:
                tmp += r 
                r += 1
            elif tmp > tsum:
                tmp -= l
                l += 1
            else:
                ans = [x for x in range(l, r)]
                res.append(ans)
                tmp -= l
                l += 1
                
        return res

合并两个排序链表

输入两个单调递增的链表,输出两个链表合成后的链表,当然我们需要合成后的链表满足单调不减规则。

解法

  • 迭代归并排序:按照归并的方法给cur.next赋值
  • 递归法:注意返回条件和递归过程
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        head = ListNode(-1)
        cur = head
        while pHead1 and pHead2:
            if pHead1.val < pHead2.val:
                cur.next = pHead1
                pHead1 = pHead1.next
            else:
                cur.next = pHead2
                pHead2 = pHead2.next
            cur = cur.next
            
        if pHead1:
            cur.next = pHead1
        if pHead2:
            cur.next = pHead2
            
        return head.next
# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回合并后列表
    def Merge(self, pHead1, pHead2):
        # write code here
        if not pHead1:
            return pHead2
        if not pHead2:
            return pHead1
        if pHead1.val <= pHead2.val:
            pHead1.next = self.Merge(pHead1.next, pHead2)
            return pHead1
        else:
            pHead2.next = self.Merge(pHead1, pHead2.next)
            return pHead2

从上往下打印二叉树

从上往下打印出二叉树的每个节点,同层节点从左至右打印。

解法
不需要记录深度的层次遍历

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回从上到下每个节点值列表,例:[1,2,3]
    def PrintFromTopToBottom(self, root):
        # write code here
        if not root:
            return []
        q = [root]
        res = []
        while q:
            cur = q.pop(0)
            res.append(cur.val)
            if cur.left:
                q.append(cur.left)
            if cur.right:
                q.append(cur.right)
                
        return res
        

调整数组顺序使奇数位于偶数前面

输入一个整数数组,实现一个函数来调整该数组中数字的顺序,使得所有的奇数位于数组的前半部分,所有的偶数位于数组的后半部分,并保证奇数和奇数,偶数和偶数之间的相对位置不变。

解法
参考https://www.nowcoder.com/questionTerminal/beb5aa231adc45b2a5dcc5b62c93f593?answerType=1&f=discussion

  • 辅助数组: 遍历一次数组,遇到奇数直接放入新开的数组中,再遍历一次数组,遇到偶数就继续放入新开的数组。
  • In-place: 初始化操作:记录一个变量i表示已经将奇数放好的下一个位置,显然最开始i=0,表示还没有一个奇数放好。j 表示数组的下标,初始值为0, 表示从下标0开始遍历。如果遇到偶数,j++;如果遇到奇数,假设位置为j,就将此奇数插入到i所指的位置,然后i往后移动一个位置,在插入之前,显然会涉及到数据的移动,也就是将[i,j-1]整体往后移动。直到整个数组遍历完毕,结束。
# -*- coding:utf-8 -*-
class Solution:
    def reOrderArray(self, array):
        # write code here
        i = 0
        for j in range(len(array)):
            if array[j] % 2 == 1:
                tmp = array[j]
                for k in range(j - 1, i - 1, -1):
                    array[k + 1] = array[k]
                array[i] = tmp
                i += 1
        return array

二叉树中和为某一值的路径

输入一颗二叉树的根节点和一个整数,按字典序打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。

解法
显然是使用递归的方法。注意要判断叶子节点。关键是在递归上面加上两个全局变量存储结果。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def __init__(self):
        self.path = []
        self.res = []
        
    def dfs(self, root, expectNumber):
        self.path.append(root.val)
        if root.val == expectNumber and not root.left and not root.right:
            self.res.append(self.path)
        
        if root.left:
            self.dfs(root.left, expectNumber - root.val)
        if root.right:
            self.dfs(root.right, expectNumber - root.val)
        
        self.path = self.path[:-1]
        
    def FindPath(self, root, expectNumber):
        # write code here
        if not root:
            return self.path
        self.dfs(root, expectNumber)
        
        return self.res

扑克牌顺子

LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张_)…他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子…LL不高兴了,他想了想,决定大\小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。

题解
参考: https://www.nowcoder.com/questionTerminal/762836f4d43d43ca9deb273b3de8e1f4?answerType=1&f=discussion
这个题也不难,本来想的是用一堆判断来做,但是发现有更简单的思路。
分两种情况考虑,

  • 如果vector中不包含0的情况:那么如何判断呢?因为需要是顺子,所以首先不能有重复值, 如果没有重复值,那么形如[1 2 3 4 5],[5 6 7 8 9], 会发现最大值与最小值的差值应该小于5.
  • 如果vector中包含0:发现除去0后的值,判断方法和1中是一样的。

所以根据如上两个条件,算法过程如下:

  • 初始化一个set,最大值max_ = 0, 最小值min_ = 14
  • 遍历数组,对于大于0的整数,没有在set中出现,则加入到set中,同时更新max_, min_
  • 如果出现在了set中,直接返回false
  • 数组遍历完,最后再判断一下最大值与最小值的差值是否小于5
# -*- coding:utf-8 -*-
class Solution:
    def IsContinuous(self, numbers):
        # write code here
        if not numbers:
            return False
        mi, ma = 14, 0
        res = set()
        for x in numbers:
            if x in res:
                return False
            if x != 0 and x not in res:
                res.add(x)
                if x < mi:
                    mi = x
                if x > ma:
                    ma = x 
                    
        if ma - mi < 5:
            return True
        return False

滑动窗口的最大值

给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{2,3,4,2,6,2,5,1}及滑动窗口的大小3,那么一共存在6个滑动窗口,他们的最大值分别为{4,4,6,6,6,5}; 针对数组{2,3,4,2,6,2,5,1}的滑动窗口有以下6个: {[2,3,4],2,6,2,5,1}, {2,[3,4,2],6,2,5,1}, {2,3,[4,2,6],2,5,1}, {2,3,4,[2,6,2],5,1}, {2,3,4,2,[6,2,5],1}, {2,3,4,2,6,[2,5,1]}。

解法
之前做过这个题

  • 暴力:枚举每个窗口的左边界 i,根据窗口的左边界i可以对应计算出右边界j,遍历窗口,计算出最大值
  • 单调队列:遍历数组的每一个元素,如果容器为空,则直接将当前元素加入到容器中。如果容器不为空,则让当前元素和容器的最后一个元素比较,如果大于,则将容器的最后一个元素删除,然后继续讲当前元素和容器的最后一个元素比较;如果当前元素小于容器的最后一个元素,则直接将当前元素加入到容器的末尾;如果容器头部的元素已经不属于当前窗口的边界,则应该将头部元素删除
# -*- coding:utf-8 -*-
class Solution:
    def maxInWindows(self, num, size):
        # write code here
        if not num or size < 1 or len(num) < size:
            return []
        res = []
        q = []
        for i, x in enumerate(num):
            while q and num[q[-1]] < x:
                q.pop()
            q.append(i)
            if q[0] <= i - size:
                q.pop(0)
                
            if i >= size - 1:
                res.append(num[q[0]])
                
        return res

二叉搜索树的第k个结点

给定一棵二叉搜索树,请找出其中的第k小的结点。例如, (5,3,7,2,4,6,8) 中,按结点数值大小顺序第三小结点的值为4。

解法
思路比较简单,因为二叉搜索树的性质,中序遍历就可以得到从小到大的顺序,只需要在到达第k个值的时候停下就可以。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回对应节点TreeNode
    def __init__(self):
        self.cnt = 0
        self.res = None
        
    def dfs(self, pRoot, k):
        if not pRoot:
            return
        self.KthNode(pRoot.left, k)
        self.cnt += 1
        if self.cnt == k:
            self.res = pRoot
            return
        if self.cnt > k:
            return
        self.KthNode(pRoot.right, k)
        
    def KthNode(self, pRoot, k):
        # write code here
        self.dfs(pRoot, k)
        return self.res
        

你可能感兴趣的:(牛客网,Python)