剑指offer(Python实现)

剑指offer(Python实现)

剑指offer(Python实现)

面试题:实现Singleton模式

在这里插入图片描述
**单例模式,**核心结构中只包含一个被称为单例类的特殊类,类的对象只能存在一个

三个要点: 某个类只有一个实例; 必须自行创建这个实例; 必须自行向整个系统提供这个实例

'''
单例模式,核心结构中只包含一个被称为单例类的特殊类,类的对象只能存在一个
三个要点: 某个类只有一个实例; 必须自行创建这个实例; 必须自行向整个系统提供这个实例
'''

"""
方法1:实现__new__方法,然后将类的一个实例绑定到类变量_instance上
如果cls._instance为None,说明该类没有被实例化过,new一个该类的实例,并返回
如果cls._instance不是None,直接返回——instance
"""
class Singleton1(object):
    def __new__(cls,*args,**kwargs):
        if not hasattr(cls,'_instance'):
            orig = super(Singleton1,cls)
            cls._instance = orig.__new__(cls,*args,**kwargs)
        return cls._instance

class Myclass(Singleton1):
    a = 1

one = Myclass()
two = Myclass()

# one和two完全相同,可以用id(),==,is检测
print(id(one))
print(id(two))
print(one == two)   #True
print(one is two)   #True

two.a = 3
print(one.a)    # 3



"""
方法2:共享属性:所谓单例就是所有引用(实例、对象)拥有相同的状态(属性)和行为(方法)
同一个类的所有实例天然有相同的行为(方法)
只需要保证一个类的所有实例具有相同的状态(属性)即可
所有实例共享属性的最简单方法就是__dict__属性指向(引用)同一个字典(dict)
"""
class Borg(object):
    _state = {}
    def __new__(cls, *args, **kwargs):
        ob = super(Borg, self).__new__(cls,*args,**kwargs)
        ob.__dict__ = cls._state
        return ob
class MyClass2(Borg):
    a = 1
one = MyClass2()
two = MyClass2()
two.a = 3
print(one.a)

# one 和 two 是两个不同的对象,id,==,is对比结果可以看出
print(id(one))          # 18410480
print(id(two))          # 18410512
print(one == two)       # False
print(one is two)       # False
# 但是one和two具有相同的(同一个)__dict__属性
print(id(one.__dict__)) # 14194768
print(id(two.__dict__)) # 14194768




"""
方法3:装饰器版本decorator
这是一种更pythonic,更elegant的方法
单例类本身根本不知道自己是单例的,因为他自己的代码不是单例的
"""
def singleton(cls,*args,**kwargs):
    instances = {}
    def getinstance():
        if cls not in instances:
            instances[cls] = cls(*args,**kwargs)
        return instances[cls]
    return getinstance

@singleton
class MyClass3(object):
    a = 1
    def __init__(self,x = 0):
        self.x = x
one = MyClass3()
two = MyClass3()
two.a = 3

print(one.a)            # 3
print(id(one))          # 8842576
print(id(two))          # 8842576
print(one == two)       # True
print(one is two)       # True
one.x = 1
print(one.x)            # 1
print(two.x)            # 1




'''
方法4:import方法
python中的模块module在程序中只被加载一次,本身就是单例的
可以直接写一个模块,将你需要的方法和属性,写在模块中当做函数和模块作用域的全局变量即可,根本不需要写类。
'''
# mysingleton.py
# class My_Singleton(object):
#     def foo(self):
#         pass
# my_singleton = My_Singleton()

# to use
from mysingleton import my_singleton
my_singleton.foo()

面试题:二维数组查找

在这里插入图片描述

#-*- coding:utf-8 -*-
'''
在一个二维数组中,每一行都按照从左到右递增的顺序排序
每一列都按照从上到下递增的顺序排序。
请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
'''

'''
查找方式从右上角开始查找
如果当前元素大于target, 左移一位继续查找
如果当前元素小于target, 下移一位继续查找
进行了简单的修改, 可以判定输入类型为字符的情况
'''

'''
如何出现了array中既有字符串,又有数字,可能需要用到ord()函数,这里就不展开讨论了
'''

class Solution:
    #array 二维列表
    def Find(self,target,array):
        if array == [[]]:
            return False
        rawnum = len(array)
        colnum = len(array[0])

        #判断非法输入
        #可以换成 isinstance(target,(int,float))进行判断
        if type(target) == float and type(array[0][0]) == int:
            if int(target) == target:
                return False
            target = int(target)
        elif type(target) == int and type(array[0][0]) == float:
            target = float(int)
        elif type(target) != type(array[0][0]): # 浮点数的相等判断问题需要特别注意, 一般都是判断两个数的差值是否小于一个特别小的数。这里不展开分析。
            return False

        j = colnum-1
        i = 0
        while i < rawnum and j >= 0:
            if array[i][j] < target:
                i += 1
            elif array[i][j] > target:
                j -= 1
            else:
                return True

        return False

    # 扩展, 输出数组中target的个数
    def searchMatrix(self,matrix,target):
        if matrix == None or len(matrix) == 0:
            return 0
        rows = len(matrix)
        cols = len(matrix[0])
        row,col = 0,cols -1
        count = 0
        while row <= rows-1 and col >= 0:
            if matrix[row][col] > target:
                col -= 1
            elif matrix[row][col] < target:
                row += 1
            else:
                count += 1
                col  -= 1

        return count







if __name__ == "__main__":
    array = [[1, 2, 8, 9],
             [2, 4, 9, 12],
             [4, 7, 10, 13],
             [6, 8, 11, 15]]

    array2 = []
    array3 = [['a', 'b', 'c'],
              ['b', 'c', 'd']]
    array4 = [[62, 63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80],
              [63, 64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81],
              [64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82],
              [65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83],
              [66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84],
              [67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79, 80, 81, 82, 83, 84, 85]]

    solu = Solution()
    print(solu.Find(30,array))

    print(solu.searchMatrix(array4,81))


面试题:替换空格

在这里插入图片描述
在这里插入图片描述

'''
请实现一个函数,将一个字符串中的空格替换成“%20”。
例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。
'''

# -*-coding:utf-8 -*-
class Solution(object):
    # s 源字符串
    # 使用append一次遍历即可替换
    # 由于list的append是o(1) 的时间复杂度,除了扩容所导致的时间损耗,该算法复杂度为o(n)
    def replaceSpaceByAppend(self,s):
        s = list(s)
        stringReplace = []
        for item in s:
            if item == ' ':
                stringReplace.append('%')
                stringReplace.append('2')
                stringReplace.append('0')
            else:
                stringReplace.append(item)


        return "".join(stringReplace)


    #创建新的字符串进行替换
    def replaceSpace1(self,s):
        tempstr = ''
        if type(s) != str:
            return
        for c in s:
            if c == ' ':
                tempstr += '%20'
            else:
                tempstr += c
        return tempstr


    #简单代码替换
    #在Python中str类型是不可变的类型, 使用replace语句会生成一个新的str, 原始的s还是带空格的str变量

    def replaceSpace2(self,s):
        if type(s) != str:
            return
        return s.replace(' ','%20')

    #书中给的思路
    # 判断输入类型的时候,isinstance必须首先判断,因为如果输入为integer的话,没有len,就会直接报错
    def replaceSpace3(self,s):
        if not isinstance(s,str) or len(s) <= 0 or s == None:
            return ""
        spaceNum = 0
        for i in s:
            if  i == " ":
                spaceNum += 1
        newStrLen = len(s) + spaceNum*2
        newStr = newStrLen*[None]
        indexOfOriginal,indexOfNew = len(s) - 1,newStrLen - 1

        while indexOfNew >= 0 and indexOfNew >= indexOfOriginal:
            if s[indexOfOriginal] == ' ':
                newStr[indexOfNew-2:indexOfNew+1] = ['%','2','0']
                indexOfNew -= 3
                indexOfOriginal -= 1

            else:
                newStr[indexOfNew] = s[indexOfOriginal]
                indexOfNew -= 1
                indexOfOriginal -= 1
        return "".join(newStr)

if __name__ == "__main__":
    s = 'we are happy'
    test = Solution()
    print(test.replaceSpace1(s))
    print(test.replaceSpace2(s))
    print(test.replaceSpace3(s))

面试题:反向打印链表

在这里插入图片描述

'''
输入一个链表,从尾到头打印链表每个节点的值。
'''
class ListNode:
    def __init__(self,x=None):
        self.val = x
        self.next = None

class Solution(object):
    def printListFromTailToHead(self,listNode):
        if listNode == None:
            return []
        l = []
        head = listNode
        while head:
            l.insert(0,head.val)
            head = head.next
        return l

if __name__=="__main__":
    node1 = ListNode(10)
    node2 = ListNode(11)
    node3 = ListNode(13)

    node1.next = node2
    node2.next = node3

    singleNode = ListNode(12)

    test = ListNode()

    S = Solution()
    print(S.printListFromTailToHead(node1))

面试题:重建二叉树

在这里插入图片描述

'''
输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。
假设输入的前序遍历和中序遍历的结果中都不含重复的数字。
例如输入前序遍历序列{1,2,4,7,3,5,6,8}和中序遍历序列{4,7,2,1,5,3,8,6},则重建二叉树并返回。
'''
#-*- coding:utf - 8 -*-
class TreeNode:
    def __init__(self,x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    #返回构造的TreeNode跟节点
    def reConstructBinaryTree(self,pre,tin):
        #write code here
        if not pre and not tin:
            return None
        root = TreeNode(pre[0])
        if set(pre) != set(tin):
            return None
        i = tin.index(pre[0])
        
        root.left = self.reConstructBinaryTree(pre[1:i+1],tin[:i])
        root.right = self.reConstructBinaryTree(pre[i+1:],tin[i+1:])
        return root

    # 按层序遍历输出树中某一层的值
    def PrintNodeAtLevel(self,treeNode,level):
        if not treeNode or level < 0:
            return 0
        if level == 0:
            print(treeNode.val)
            return 1

        self.PrintNodeAtLevel(treeNode.left,level-1)
        self.PrintNodeAtLevel(treeNode.right,level-1)

    # 已知树的深度按层遍历输出的值
    def PrintNodeByLevel(self, treeNode, depth):
        for level in range(depth):
            self.PrintNodeAtLevel(treeNode,level)


if __name__ == "__main__":
    pre = [1, 2, 3, 5, 6, 4]
    tin = [5, 3, 6, 2, 4, 1]
    solu = Solution()
    newTree = solu.reConstructBinaryTree(pre,tin)
    #输出一下第level层
    #solu.PrintNodeAtLevel(newTree,1)#level表示第几层的元素

    solu.PrintNodeByLevel(newTree,5)

面试题:用两个栈实现队列

在这里插入图片描述

'''
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
'''
#-*— coding:utf-8 -*-
class Queue(object):
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
    def push(self,node):
        self.stack1.append(node)

    def pop(self):
        if len(self.stack2) == 0 and len(self.stack1) == 0:
            return

        elif len(self.stack2) == 0:
            while len(self.stack1) > 0:
                self.stack2.append(self.stack1.pop())
        return self.stack2.pop()

if __name__ == "__main__":
    Q = Queue()
    Q.push(10)
    Q.push(11)
    Q.push(12)
    print(Q.pop())

    Q.push(13)
    print(Q.pop())
    print(Q.pop())
    print(Q.pop())


# -*- coding:UTF-8 -*-
'''
两个队列实现栈
'''
class Solution:
    def __init__(self):
        self.queue1 = []
        self.queue2 = []
    def push(self, x):
        if self.queue2 == []:
            self.queue1.append(x)
        else:
            self.queue2.append(x)
    def pop(self):
        if not self.queue1 and not self.queue2:
            return
        if self.queue1 != []:
            length = len(self.queue1)
            for i in range(length-1):
                self.queue2.append(self.queue1.pop(0))
            return self.queue1.pop()
        else:
            length = len(self.queue2)
            for i in range(length-1):
                self.queue1.append(self.queue2.pop(0))
            return self.queue2.pop()

P = Solution()
P.push(10)
P.push(11)
P.push(12)
print(P.pop())
P.push(13)
print(P.pop())
print(P.pop())
print(P.pop())
print(P.pop())

面试题:旋转数组的最小数字

在这里插入图片描述

'''
把一个数组最开始的若干个元素搬到数组的末尾,我们称之为数组的旋转。
输入一个递增排序的数组的一个旋转,输出旋转数组的最小元素。
例如数组{3,4,5,1,2}为{1,2,3,4,5}的一个旋转,该数组的最小值为1。
NOTE:给出的所有元素都大于0,若数组大小为0,请返回0。
'''

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        if len(rotateArray) == 0:
            return 0
        front = 0
        rear = len(rotateArray) - 1
        minVal = rotateArray[0]
        if rotateArray[front] < rotateArray[rear]:
            return rotateArray[front]
        else:
            while (rear - front) > 1:
                mid = (rear + front)//2
                if rotateArray[mid] > rotateArray[rear]:
                    front = mid
                elif rotateArray[mid] < rotateArray[front]:
                    rear = mid
                elif rotateArray[mid] == rotateArray[front] and rotateArray[front] == rotateArray[rear]:
                    for i in range(1, len(rotateArray)):
                        if rotateArray[i] < minVal:
                            minVal = rotateArray[i]
                            rear = i
            minVal = rotateArray[rear]
            return minVal
    # 书上方法
    def minNumberInRotateArray2(self, rotateArray):
        if len(rotateArray) == 0:
            return 0
        front, rear = 0, len(rotateArray) - 1
        midIndex = 0
        while rotateArray[front] >= rotateArray[rear]:
            if rear - front == 1:
                midIndex = rear
                break
            midIndex = (front + rear) // 2
            if rotateArray[front] == rotateArray[rear] and rotateArray[front] == rotateArray[midIndex]:
                return self.MinInOrder(rotateArray, front, rear)

            if rotateArray[midIndex] >= rotateArray[front]:
                front = midIndex
            elif rotateArray[midIndex] <= rotateArray[rear]:
                rear = midIndex
        return rotateArray[midIndex]
    def MinInOrder(self, array, front, end):
        result = array[0]
        for i in array[front:end+1]:
            if i < result:
                result = i
        return result

Test = Solution()
print(Test.minNumberInRotateArray([3, 4, 5, 1, 2]))
print(Test.minNumberInRotateArray([1, 2, 3, 4, 5]))
print(Test.minNumberInRotateArray([1, 1, 1, 0, 1]))
print(Test.minNumberInRotateArray([1, 0, 1, 1, 1]))
print(Test.minNumberInRotateArray([]))
print(Test.minNumberInRotateArray([1]))

面试题:斐波那契数列

在这里插入图片描述
递归法:

class Solution1(object):
	def Fibonacci(self,n):
		if n <= 0:
			return 0
		if n == 1:
			return 1
		return self.Fibonacci(n-1)+self.Fibonacci(n-2)

动态规划:

class Solution(object):
	def Fibonacci(self,n):
		if n <= 0:
			return 0
		if n == 1:
			return n
		tempList = [-1]*(n+1)
		tempList[0]=0
		tempList[1]=1

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

面试题:跳台阶

一只青蛙一次可以跳上1级台阶,也可以跳上2级。求该青蛙跳上一个n级的台阶总共有多少种跳法(先后次序不同算不同的结果)。
动态规划:

class Solution(object):
    def jumpFloor(self,number):
        tempList = [-1]*(number+1)
        if number <=1:
            return 1
        tempList[0] = 1
        tempList[1] = 1
        for i in range(2,number+1):
            tempList[i] = tempList[i-1]+tempList[i-2]

        return tempList[number]

面试题:跳台阶II

贪心法:
变态青蛙跳,每次至少跳一个,至多跳n个,一共有f(n)=2n-1种跳法。考察数学建模的能力。

class Solution(object):
    def jumpFloorII(self, number):
        ans = 1
        if number >=2:
            for i in range(number-1):
                ans = ans*2
        return ans

面试题:矩阵覆盖

我们可以用21的小矩形横着或者竖着去覆盖更大的矩形。请问用n个21的小矩形无重叠地覆盖一个2*n的大矩形,总共有多少种方法?

比如n=3时,2*3的矩形块有3种覆盖方法

class Solution(object):
    def rectCover(self,number):
        if number <= 2:
            return number
        else:
            methods = []
            for i in range(number):
                if i <= 1:
                    methods.append(i+1)
                else:
                    methods.append(methods[i-1]+methods[i-2])
            return methods[number-1]

面试题:二进制中1的个数

输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。
在这里插入图片描述

注意到每个非零整数n和n-1进行按位与运算,整数n的二进制数中最右边的1就会变成0,那么二进制数中的1的个数就会减少一个,因此可以利用一个循环,使得 n = n&(n-1) ,计算经过几次运算减少到0,就是有几个1。注意:书中给了另外两种方法,分别是原始n左移一位和右移一位的方法,因为python不会出现整数溢出的情况,这里就不再考虑着两种方法。扩展:判断一个数值是不是2得整数次方,如果是的话,这个数的二进制数中有且只有一个1,那么这个数n会有 n&(n-1) == 0。或者求两个整数m和n需要改变m二进制中的多少位才能得到n,可以先做 m^n 的异或运算,然后求这个数中有多少个1。
方法1:

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        # write code here
        count = 0
        if n < 0:
            n = n & 0xffffffff

        while n :
            count += 1
            n = (n-1)&n

        return count

方法2:

class Solution(object):
    def NumberOf1(self,n):
        if n < 0:
            s = bin(n&0xffffffff)
        else:
            s = bin(n)
        return s.count('1')

面试题:数值的整数次方

在这里插入图片描述
给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。
保证base和exponent不同时为0

class Solution(object):
    def Power(self,base,exponent):
        if exponent == 0:
            return 1
        if exponent == 1:
            return base

        if exponent == -1:
            return 1/base

        result = self.Power(base,exponent >> 1)
        result *= result
        if (exponent & 0x1) == 1:
            result *= base
        return result

面试题:打印1到最大的n位数

在这里插入图片描述

'''
输入数字n, 按顺序打印从1最大的n位十进制数
比如输入3, 则打印出1、2、3、到最大的3位数即999
'''


def Print1ToMaxOfNDigits(n):
    if n <= 0:
        return

    number = ['0'] * n
    while not Increment(number):
        PrintNumber(number)

def Increment(number):
    isOverflow = False
    nTakeOver = 0
    nLength = len(number)

    for i in range(nLength-1, -1, -1):
        nSum = int(number[i]) + nTakeOver
        if i == nLength - 1:
            nSum += 1

        if nSum >= 10:
            if i == 0:
                isOverflow = True
            else:
                nSum -= 10
                nTakeOver = 1
                number[i] = str(nSum)
        else:
            number[i] = str(nSum)
            break

    return isOverflow

def PrintNumber(number):
    isBeginning0 = True
    nLength = len(number)

    for i in range(nLength):
        if isBeginning0 and number[i] != '0':
            isBeginning0 = False
        if not isBeginning0:
            print('%c' % number[i], end='')
    print('')


#方法2
def Print1ToMaxOfNDigits2(n):
    if n <= 0:
        return

    number = ['0'] * n
    for i in range(10):
        number[0] = str(i)
        Print1ToMaxOfNDigitsRecursively(number, n, 0)

def Print1ToMaxOfNDigitsRecursively(number, length, index):
    if index == length - 1:
        PrintNumber(number)
        return
    for i in range(10):
        number[index + 1] = str(i)
        Print1ToMaxOfNDigitsRecursively(number, length, index+1)

面试题:在O(1)时间内删除链表节点

在这里插入图片描述

'''
给定单向链表的头指针和一个结点指针,定义一个函数在O(1)时间删除该结点
'''
class ListNode:
    def __init__(self, x=None):
        self.val = x
        self.next = None
    def __del__(self):
        self.val = None
        self.next = None

class Solution:
    def DeleteNode(self, pListHead, pToBeDeleted):
        if not pListHead or not pToBeDeleted:
            return None

        if pToBeDeleted.next != None:
            pNext = pToBeDeleted.next
            pToBeDeleted.val = pNext.val
            pToBeDeleted.next = pNext.next
            pNext.__del__()


        elif pListHead == pToBeDeleted:
            pToBeDeleted.__del__()
            pListHead.__del__()
        else:
            pNode = pListHead
            while pNode.next != pToBeDeleted:
                pNode = pNode.next
            pNode.next = None
            pToBeDeleted.__del__()


node1 = ListNode(10)
node2 = ListNode(11)
node3 = ListNode(13)
node4 = ListNode(15)
node1.next = node2
node2.next = node3
node3.next = node4

S = Solution()
S.DeleteNode(node1, node3)
print(node3.val)
S.DeleteNode(node1, node3)
print(node3.val)
print(node2.val)
S.DeleteNode(node1, node1)
print(node1.val)
S.DeleteNode(node1, node1)
print(node1.val)

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

在这里插入图片描述
常规方法:

# -*- coding:utf-8 -*-
class Solution:
    def reOrderArray(self, array):
        # write code here
        if len(array) < 1:
            return []
        if len(array) == 1:
            return array
        
        arrayOdd = []
        arrayEven = []
        for num in array:
            if num & 0x1:
                arrayOdd.append(num)
            else:
                arrayEven.append(num)
                
        return arrayOdd+arrayEven
          

Python 的小技巧


class Solution2(object):
    def reOrderArray(self,array):
        left = [x for x in array if x & 1]
        right = [x for x in array if not x & 1]

        return left + right

面试题:链表中倒数第K个节点

在这里插入图片描述

class ListNode(object):
    def __init__(self,x=None):
        self.val = x
        self.next = None

class Solution(object):
    def FindKthToTail(self,head,k):
        if head == None or k <= 0:
            return None

        fast = head
        slow = head

        #快指针向前走k-1步

        #但是移动除去就返回None
        for i in range(k-1):
            if fast.next != None:

                fast = fast.next
            else:
                return None

        while fast.next != None:
            fast = fast.next
            slow = slow.next

        return slow


if __name__ == "__main__":

    node1 = ListNode(10)
    node2 = ListNode(11)
    node3 = ListNode(12)
    node4 = ListNode(13)
    node5 = ListNode(14)
    node1.next = node2
    node2.next = node3
    node3.next = node4
    node4.next = node5




    solu = Solution()
    print(solu.FindKthToTail(node1,3).val)



面试题:反转链表

class ListNode(object):
    def __init__(self,x=None):
        self.val = x
        self.next = None
        
class Solution(object):
    def ReverseList(self,head):
        pReverseHead = None
        
        currNode = head
        preNode = None
        
        while currNode != None:
            nextNode = currNode.next
            if nextNode == None:
                pReverseHead = currNode
            
            currNode.next = preNode
            preNode = currNode
            currNode = nextNode
        return pReverseHead
    
            

递归实现

 def ReverseListRec(self, pHead):
        if not pHead or not pHead.next:
            return pHead
        else:
            pReversedHead = self.ReverseList(pHead.next)
            pHead.next.next = pHead
            pHead.next = None
            return pReversedHead

面试题:合并两个排序链表

在这里插入图片描述

class ListNode(object):
    def __init__(self,x=None):
        self.val = x
        self.next = None


class Solution(object):
    def Merge(self,pHead1,pHead2):
        if pHead1 == None:
            return pHead2
        if pHead2 == None:
            return pHead1

        pMergeHead = None
        if pHead1.val < pHead2.val:
            pMergeHead = pHead1
            pMergeHead.next = self.Merge(pHead1.next,pHead2)
        else:
            pMergeHead = pHead2
            pMergeHead.next = self.Merge(pHead1,pHead2.next)

        return pMergeHead

面试题:树的子结构

在这里插入图片描述

class TreeNode(object):
    def __init__(self,x= None):
        self.val = x
        self.left = None
        self.right = None


class Solution(object):
    def HasSubtree(self,pRoot1,pRoot2):
        result = None
        if pRoot1 != None and pRoot2 != None:
            if pRoot1.val == pRoot2.val:
                result = self.DoesTree1haveTree2(pRoot1,pRoot2)
            if not result:
                result = self.HasSubtree(pRoot1.left,pRoot2)
            if not result:
                result = self.HasSubtree(pRoot1.right,pRoot2)





    # 用于递归判断树的每个节点是否相同
    # 需要注意的地方是: 前两个if语句不可以颠倒顺序
    # 如果颠倒顺序, 会先判断pRoot1是否为None, 其实这个时候pRoot2的结点已经遍历完成确定相等了, 但是返回了False, 判断错误
    def DoesTree1haveTree2(self,pRoot1,pRoot2):
        if pRoot2 == None:
            return True
        if pRoot1 == None:
            return False
        if pRoot1.val != pRoot2.val:
            return False

        return self.DoesTree1haveTree2(pRoot1.left,pRoot2.left) and self.DoesTree1haveTree2(pRoot1.right,pRoot2.right)

面试题:二叉树的镜像

在这里插入图片描述
递归实现

class TreeNode(object):
    def __init__(self,x=None):
        self.val = x
        self.left = None
        self.right = None
        
class Solution(object):
    def Mirror(self,root):
        if root == None:
            return None
        if root.left == None and root.right == None:
            return root
        
        root.left,root.right = root.right,root.left
        
        self.Mirror(root.left)
        self.Mirror(root.right)

非递归实现(超出时间限制)

class TreeNode(object):
    def __init__(self,x= None):
        self.val = x
        self.left = None
        self.right = None
class Solution(object):
    def Mirror(self,root):
        if root == None:
            return None
        nodeQueue = [root]
        while len(nodeQueue) > 0:
            curLevel,count=len(nodeQueue),0
            while count<curLevel:
                count += 1
                pRoot = nodeQueue.pop(0)
                pRoot.left,root.right = root.right,root.left
                if pRoot.left:
                    nodeQueue.append(pRoot.left)
                if pRoot.right:
                    nodeQueue.append(pRoot.right)

面试题:顺时针打印矩阵

在这里插入图片描述

class Solution(object):
    def printMatrix(self,matrix):
        
        printArr = []
        
        if matrix == None:
            return None
        if matrix == []:
            return []
        rows = len(matrix)
        columns = len(matrix[0])
        start = 0 #每次循环时的起点
        
        while rows >start*2 and columns > start*2:
            
            endX = columns - 1 - start
            endY = rows - 1 - start
            
            #从左到右加入到printArr
            for i in range(start,endX+1):
                number = matrix[start][i]
                printArr.append(number)
            #从上到下加入到printArr
            if start < endY:
                for i in range(start+1,endY+1):
                    number = matrix[i][endX]
                    printArr.append(number)
            #从右到左加入到printArr
            if start < endX and start < endY:
                for i in range(endX-1,start-1,-1):
                    number = matrix[endY][i]
                    printArr.append(number)
                    
            #从下到上加入printArr
            if start < endX and start < endY-1:
                for i in range(endY-1,start,-1):
                    number = matrix[i][start]
                    printArr.append(number)
            start += 1
        return printArr

            

面试题:包含min函数的栈

class Solution(object):
    def __init__(self):
        self.stack = []
        self.minStack = []

    def push(self, x):
        self.stack.append(x)
        if self.minStack == [] or x < self.min():
            self.minStack.append(x)
        else:
            self.minStack.append(self.min())



    def pop(self):
        if self.stack == [] or self.minStack == []:
            return None
        self.stack.pop()
        self.minStack.pop()
    def min(self):
        if self.minStack==[]:
            return None
        return self.minStack[-1]

    def top(self):
        return self.stack[-1]

面试题:栈的压入,弹出序列

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

class Solution(object):
    def IsPopOrder(self,pushV,popV):
        if pushV == [] or popV == []:
            return False
        stack = []
        for i in pushV:
            stack.append(i)
            while len(stack) and stack[-1] == popV[0]:
                stack.pop()
                popV.pop(0)
                
        if len(stack) == 0:
            return True
        else:
            return False
  

面试题:从上往下打印二叉树

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

# -*- 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
        
        res = []
        queue = []
        if root == None:
            return []
        queue.append(root)
        while len(queue) > 0:
            currRoot = queue.pop(0)
            res.append(currRoot.val)
            if currRoot.left:
                queue.append(currRoot.left)
            if currRoot.right:
                queue.append(currRoot.right)
                
        return res

面试题:二叉搜索树的后续遍历序列

输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。如果是则输出Yes,否则输出No。假设输入的数组的任意两个数字都互不相同。

'''
输入一个整数数组,判断该数组是不是某二叉搜索树的后序遍历的结果。
如果是则输出Yes,否则输出No。
假设输入的数组的任意两个数字都互不相同。
二叉搜索树对于每一个非叶子节点, 均有结点左子节点<当前节点<结点右子节点
'''
class Solution(object):
    def VerifySquenceOfBST(self,sequence):
        if sequence == []:
            return False
        root = sequence[-1]
        length = len(sequence)
        #仅有左子树或者右子树是返回True
        if min(sequence) > root or max(sequence) < root:
            return True
        index = 0
        #二叉搜索树的左子树节点小于根节点
        '''
        下面这个for循环特别需要主要index=i必须写在if语句外面,
        否则就会发生当root结点前的所有元素小于root的时候, 正确判断应该为True,
        但是因为if语句没有进入, index = 0 ,
        在进入二叉搜索树的右子树结点大于根结点的for循环的时候, 因为sequence的数都小于root, 就会判断出错
        '''
        for i in range(length-1):
            index = i
            if sequence[i] > root:
                break
        # 二叉搜索树的右子树结点大于根结点
        # 这个循环中范围起始点必须是index+1, 不能为index
        # 因为当root结点前的所有元素小于root的时候,index=length-2,
        # 此时sequence[index]<root, 但是按照range(index, length-1), 第一个元素sequence[j]==sequence[index] < root, 返回False, 实际应该返回True才对
        # 而使用index+1, 因为已经默认index>root, 所以从后面一个开始盘算右子树结点是否大于root, 也不会影响结果
        for j in range(index+1,length-1):
            if sequence[j] < root:
                return False
#递归部分:
        left = True
        if index > 0:
            left = self.VerifySquenceOfBST(sequence[:index])

        right = True
        if index < length-1:
            right = self.VerifySquenceOfBST(sequence[index:length-1])

        return left and right

面试题:二叉树中和为某一值的路径

输入一颗二叉树的根节点和一个整数,打印出二叉树中结点值的和为输入整数的所有路径。路径定义为从树的根结点开始往下一直到叶结点所经过的结点形成一条路径。(注意: 在返回值的list中,数组长度大的数组靠前)

递归

class TreeNode(object):
    def __init__(self,x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def FindPath(self,root,expectNumber):
        #返回二维列表,内部每个列表表示找到的路径
        if not root:
            return []
        if root.left == None and root.right == None:
            if root.val == expectNumber:
                return [[root.val]]
            else:
                return []

        stack =[]
        leftStack = self.FindPath(root.left,expectNumber-root.val)
        for i in leftStack:
            i.insert(0,root.val)
            stack.append(i)

        rightStack = self.FindPath(root.right,expectNumber-root.val)
        for i in rightStack:
            i.insert(0,root.val)
            stack.append(i)

        return stack


面试题:复杂链表的复制

输入一个复杂链表(每个节点中有节点值,以及两个指针,一个指向下一个节点,另一个特殊指针指向任意一个节点),返回结果为复制后复杂链表的head。(注意,输出结果中请不要返回参数中的节点引用,否则判题程序会直接返回空)

# -*- coding:utf-8 -*-
class RandomListNode:
    def __init__(self, x):
        self.label = x
        self.next = None
        self.random = None
class Solution:
    # 返回 RandomListNode
    def Clone(self, pHead):
        if pHead == None:
            return None
        self.CloneNodes(pHead)
        self.ConnectRandomNodes(pHead)
        return self.ReconnectNodes(pHead)
    # 复制原始链表的每个结点, 将复制的结点链接在其原始结点的后面
    def CloneNodes(self, pHead):
        pNode = pHead
        while pNode:
            pCloned = RandomListNode(0)
            pCloned.label = pNode.label
            pCloned.next = pNode.next
            # pCloned.random = None         #不需要写这句话, 因为创建新的结点的时候,random自动指向None

            pNode.next = pCloned
            pNode = pCloned.next

    # 将复制后的链表中的复制结点的random指针链接到被复制结点random指针的后一个结点
    def ConnectRandomNodes(self, pHead):
        pNode = pHead
        while pNode:
            pCloned = pNode.next
            if pNode.random != None:
                pCloned.random = pNode.random.next
            pNode = pCloned.next

    # 拆分链表, 将原始链表的结点组成新的链表, 复制结点组成复制后的链表
    def ReconnectNodes(self, pHead):
        pNode = pHead
        pClonedHead = pClonedNode = pNode.next
        pNode.next = pClonedHead.next
        pNode = pNode.next

        while pNode:
            pClonedNode.next = pNode.next
            pClonedNode = pClonedNode.next
            pNode.next = pClonedNode.next
            pNode = pNode.next

        return pClonedHead

面试题:二叉搜索树与双向链表

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

class TreeNode(object):
    def __init__(self,x):
        self.val = x
        self.left = None
        self.right = None
        
class Solution(object):
    def Convert(self,pRootOfTree):
        if pRootOfTree == None:
            return None
        if not pRootOfTree.left and not pRootOfTree.right:
            return pRootOfTree
        #处理左子树
        self.Convert(pRootOfTree.left)
        left = pRootOfTree.left
        
        #连接根与左子树最大结点
        if left:
            while left.right:
                left = left.right
            pRootOfTree.left,left.right = left,pRootOfTree
            
        
        
        #处理右子树
        self.Convert(pRootOfTree.right)
        right = pRootOfTree.right
        
        #连接根与右子树最小结点
        if right:
            while right.left:
                right = right.left
            pRootOfTree.right,right.left=right,pRootOfTree
        
        while pRootOfTree.left:
            pRootOfTree = pRootOfTree.left
        return pRootOfTree

面试题:字符串的排列和组合

输入一个字符串,按字典序打印出该字符串中字符的所有排列。例如输入字符串abc,则打印出由字符a,b,c所能排列出来的所有字符串abc,acb,bac,bca,cab和cba。

class Solution(object):
    def Permutation(self,ss):
        if len(ss) == 0:
            return []
        if len(ss) == 1:
            return  list(ss)

        charList = list(ss)
        charList.sort()
        res = []

        for i in range(len(charList)):
            if i > 0 and charList[i] == charList[i-1]:
                continue
            temp =self.Permutation(''.join(charList[:i])+''.join(charList[i+1:]))
            for j in temp:
                res.append(charList[i]+j)
        return res

扩展习题, 生成字符的所有组合

比如输入abc, 则他们的组合有[‘a’, ‘ab’, ‘abc’, ‘ac’, ‘b’, ‘bc’, ‘c’], ab和ba属于不同的排列, 但属于同一个组合

    def group(self,ss):
        if len(ss) == 0:
            return []
        if len(ss) == 1:
            return list(ss)
        charList = list(ss)
        charList.sort()
        res = []
        
        for i in range(len(charList)):
            res.append(charList[i])
            if i > 0 and charList[i] == charList[i-1]:
                continue
            temp = self.group(''.join(charList[i+1:]))
            for j in temp:
                res.append(charList[i]+j)
            res = list(set(res))
            res.sort()
        return res

面试题:数组中出现次数超过一半的数字

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

第一种思路,出现次数超过一半的数字,不管如何,必然这个数字位于数组中间的位置,因此可以采用类似于快排的划分的方法,找到位于数组中间的位置的数字,然后在顺序检索是否这个数字出现次数超过一半。
有问题

在这里插入代码片

第二种思路根据数组的特点,出现次数超过一半的数,他出现的次数比其他数字出现的总和还要多,因此可以最开始保存两个数值:数组中的一个数字以及它出现的次数,然后遍历,如果下一个数字等于这个数字,那么次数加一,如果不等,次数减一,当次数等于0的时候,在下一个数字的时候重新复制新的数字以及出现的次数置为1,直到进行到最后,然后再验证最后留下的数字是否出现次数超过一半,因为可能前面的次数依次抵消掉,最后一个数字就直接是保留下来的数字,但是出现次数不一定超过一半。

class Solution:
    # 基于Partition函数的O(n)算法
    def MoreThanHalfNum_Solution(self, numbers):
        length = len(numbers)
        if numbers == None or length <= 0:
            return 0
        result = numbers[0]
        times = 1
        for i in range(1, length):
            if times == 0:
                result = numbers[i]
                times = 1
            elif numbers[i] == result:
                times += 1
            else:
                times -= 1
        if not self.CheckMoreThanHalf(numbers, length, result):
            result = 0
        return result
    # 检查查找到中位数的元素出现次数是否超过所有元素数量的一半
    def CheckMoreThanHalf(self, numbers, length, number):
        times = 0
        for i in range(length):
            if numbers[i] == number:
                times += 1
        if times*2 <= length:
            return False
        return True

面试题:最小的k个数

输入n个整数,找出其中最小的K个数。例如输入4,5,1,6,2,7,3,8这8个数字,则最小的4个数字是1,2,3,4,。

第一种方法是基于划分的方法,如果是查找第k个数字,第一次划分之后,划分的位置如果大于k,那么就在前面的子数组中进行继续划分,反之则在后面的子数组继续划分,时间复杂度O(n);

class Solution:
    # O(n)的算法, 只有当我们可以修改输入的数组时可用
    # 基于Partition的方法
    def GetLeastNumbers_Solution(self, tinput, k):
        if tinput == None or len(tinput) < k or len(tinput) <= 0 or k <=0:
            return []
        n = len(tinput)
        start = 0
        end = n - 1
        index = self.Partition(tinput, n, start, end)
        while index != k-1:
            if index > k-1:
                end = index - 1
                index = self.Partition(tinput, n, start, end)
            else:
                start = index + 1
                index = self.Partition(tinput, n, start, end)
        output = tinput[:k]
        output.sort()
        return output

    def Partition(self, numbers, length, start, end):
        if numbers == None or length <= 0 or start < 0 or end >= length:
            return None
        if end == start:
            return end
        pivotvlue = numbers[start]
        leftmark = start + 1
        rightmark = end

        done = False

        while not done:
            while numbers[leftmark] <= pivotvlue and leftmark <= rightmark:
                leftmark += 1
            while numbers[rightmark] >= pivotvlue and rightmark >= leftmark:
                rightmark -= 1

            if leftmark > rightmark:
                done = True
            else:
                numbers[leftmark], numbers[rightmark] = numbers[rightmark], numbers[leftmark]
        numbers[rightmark], numbers[start] = numbers[start], numbers[rightmark]
        return rightmark

第二种方法是可以适用于海量数据的方法,该方法基于二叉树或者堆来实现,首先把数组前k个数字构建一个最大堆,然后从第k+1个数字开始遍历数组,如果遍历到的元素小于堆顶的数字,那么久将换两个数字,重新构造堆,继续遍历,最后剩下的堆就是最小的k个数,时间复杂度O(nlog k)。
有问题

在这里插入代码片

面试题:连续子数组的最大和

HZ偶尔会拿些专业问题来忽悠那些非计算机专业的同学。今天测试组开完会后,他又发话了:在古老的一维模式识别中,常常需要计算连续子向量的最大和,当向量全为正数的时候,问题很好解决。但是,如果向量中包含负数,是否应该包含某个负数,并期望旁边的正数会弥补它呢?例如:{6,-3,-2,7,-15,1,2,2},连续子向量的最大和为8(从第0个开始,到第3个为止)。给一个数组,返回它的最大连续子序列的和,你会不会被他忽悠住?(子向量的长度至少是1)

常规方法

# -*- coding:utf-8 -*-
class Solution:
    def FindGreatestSumOfSubArray(self, array):
        # write code here
        if array == None or len(array)<=0:
            return 0
        
        nCurSum = 0
        nGreatestSum = array[0]
        for i in range(len(array)):
            if nCurSum < 0:
                nCurSum = array[i]
            else:
                nCurSum += array[i]
            if nGreatestSum < nCurSum:
                nGreatestSum = nCurSum
        return nGreatestSum

动态规划

# -*- coding:utf-8 -*-
class Solution:
    def FindGreatestSumOfSubArray(self, array):
        # write code here
        if array == None or len(array)<=0:
            return 0
        aList = [0]*len(array)
        for i in range(len(array)):
            if i == 0 or aList[i-1] <= 0:
                aList[i] = array[i]
            else:
                aList[i] = aList[i-1]+array[i]
        return max(aList)

面试题:整数中1出现的次数(从1到n整数中1出现的次数)

在这里插入图片描述
数学规律:

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code herea
        num_ones = 0
        m = 1
        while m <= n:
            num_ones += (n // m + 8) // 10 * m + (n // m % 10 == 1) * (n % m + 1)
            m *= 10
        return num_ones

数学规律:

    def NumberOf1Between1AndN2(self, n):
        ones, m = 0, 1
        while m <= n:
            if ((n // m) % 10) != 0 and ((n // m) % 10) != 1:
                ones += (n // 10 // m + 1) * m
            elif ((n // m) % 10) == 1:
                ones += (n // m // 10) * m + n % m + 1
            m *= 10
        return ones

面试题:把数组排成最小的数

一个。例如输入数组{3,32,321},则打印出这三个数字能排成的最小数字为321323。

# -*- coding:utf-8 -*-
class Solution:
    def PrintMinNumber(self, numbers):
        # write code here
        if numbers == None or len(numbers) <= 0:
            return ''
        strList=[str(m) for m in numbers]
        for i in range(len(numbers)-1):
            for j in range(i+1,len(numbers)):
                if strList[i]+strList[j] > strList[j]+strList[i]:
                    strList[i],strList[j] = strList[j],strList[i]
        return ''.join(strList)

面试题:丑数

把只包含质因子2、3和5的数称作丑数(Ugly Number)。例如6、8都是丑数,但14不是,因为它包含质因子7。 习惯上我们把1当做是第一个丑数。求按从小到大的顺序的第N个丑数。

解法:
空间换时间。建立一个长度为n的数组,保存这n个丑数。在进行运算的时候,某个位置需要求得丑数一定是前面某个丑数乘以2、3或者5的结果,我们分别记录之前乘以2后能得到的最大丑数M2,乘以3后能得到的最大丑数M3,乘以5后能得到的最大丑数M5,那么下一个丑数一定是M2,M3,M5中的最小的那一个。同时注意到,已有的丑数是按顺序存放在数组中的。对乘以2而言,肯定存在某一个丑数T2,排在他之前的每一个丑数乘以2得到的结果都会小于已有的最大丑数,在他之后的每一个丑数乘以2得到的结果都会太大,我们只需记下这个丑数的位置,每次生成新的丑数的时候,去更新这个T2。对于3和5同理。

# -*- coding:utf-8 -*-
class Solution:
    def GetUglyNumber_Solution(self, index):
        # write code here
        if index == None or len(index)<= 0:
            return 0

        uglyNumbers = [1]*index
        m = 1

        index2= 0
        index3 = 0
        index5 = 0

        while m < index:
            minVal = min(uglyNumbers[index2]*2,uglyNumbers[index3]*3,uglyNumbers[index5]*5)
            uglyNumbers[m] = minVal

            while uglyNumbers[index2]*2 <= uglyNumbers[m]:
                index2 += 1
            while uglyNumbers[index3]*3 <= uglyNumbers[m]:
                index3 += 1
            while uglyNumbers[index5]*5 <= uglyNumbers[m]:
                index5 += 1
            m += 1
        return uglyNumbers[-1]

面试题:第一个只出现一次的字符

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

# -*- coding:utf-8 -*-
class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        if s == None or len(s) <= 0:
            return -1
        dict = {}
        sList = list(s)
        for i in sList:
            if i not in dict:
                dict[i] = 1
            else:
                dict[i] += 1
                
        for i in range(len(sList)):
            if dict[sList[i]] == 1:
                return i
        return -1

面试题:数组中的逆序对

在这里插入图片描述
解题思路:
这道题可以这么想,我们要找到数组中的逆序对,**可以看做对数据进行排序,需要交换数组中的元素的次数,**但是防止相同大小的元素发生交换,因此需要选择一个稳定的排序方法,记录发生交换的次数。那么,基于比较的稳定的排序方法中,最快的方法就是归并了,所以直接按照归并排序的思路,将数组分解、合并、排序即可。但是需要注意的是,在常规归并排序的时候,如果前一个元素大于后一个元素,直接进行交换即可,只进行了一次操作,但是对于这道题来讲,对于每一次的归并段,我们选择从后向前遍历,前面的归并段的某一个数值left[i]如果大于后面的某一个数值right[j],因为在right自己独自排序的过程中,已经保证了right是有序的,所以j位置前面的数字全部小于right[j],所以在这里逆序对的个数就会是 j-start-length,其中start是整个数组的起点,length是left的长度,然后再进行交换。

仅能通过50%测试用例

# -*- coding:utf-8 -*-
class Solution:
    def InversePairs(self, data):
        # write code here
        if len(data) <= 0:
            return 0
        count = 0
        copy=[]
        for i in data:
            copy.append(i)

        copy.sort()
        i = 0
        while i < len(copy):
            count += data.index(copy[i])
            data.remove(copy[i])
            i+=1
        return count

归并排序:

在这里插入代码片

面试题:两个链表的第一个公共结点

首先依次遍历两个链表,记录两个链表的长度m和n,如果 m > n,那么我们就先让长度为m的链表走m-n个结点,然后两个链表同时遍历,当遍历到相同的结点的时候停止即可。对于 m < n,同理。

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        # write code here
        nLength1 = self.GetListLength(pHead1)
        nLength2 = self.GetListLength(pHead2)
        nLengthDiff = abs(nLength1-nLength2)
        
        if nLength1 > nLength2:
            longOne = pHead1
            shortOne = pHead2
        else:
            longOne = pHead2
            shortOne = pHead1
        for i in range(nLengthDiff):
            longOne = longOne.next
        while longOne != None and shortOne != None and longOne != shortOne:
            longOne = longOne.next
            shortOne = shortOne.next
        pFirstCommonNode = longOne
        return pFirstCommonNode
    def GetListLength(self,pHead):
        nLength = 0
        while pHead != None:
            pHead = pHead.next
            nLength+= 1
        return nLength

面试题:数字在排序数组中出现的次数

二分查找的扩展。可以构造两个函数。第一个函数查找目标数字出现的最前面的位置,先使用二分查找找到该数字,如果该数字的index > 0而且该数字前面一个数字等于k的话,那么就令end=middle-1,继续二分查找。对于第二个函数,查找目标数字出现的最后面的位置,反之编写。最后如果数字存在的话,令走后面的index减去最前面的index然后+1即可。在进行有序数组的元素查找,可以先尝试一下二分查找

# -*- coding:utf-8 -*-
class Solution:
    def GetNumberOfK(self, data, k):

        # write code here
        number = 0
        if data != None and len(data)>0:
            length = len(data)
            first = self.GetFirstK(data,length,k,0,length-1)
            last = self.GetLastK(data,length,k,0,length-1)
            if first > -1:
                number = last-first+1
        return number
    
    def GetFirstK(self,data,length,k,start,end):
        if start > end:
            return -1
        mid = (start+end)//2
        midData = data[mid]
        
        if midData == k:
            if mid > 0 and data[mid-1] == k:
                end = mid-1
            else:
                return mid
            
        elif midData > k:
            end = mid-1
        else:
            start = mid +1
        return self.GetFirstK(data,length,k,start,end)
    
    
    def GetLastK(self,data,length,k,start,end):
        if start > end:
            return -1
        mid =(start+end)//2
        midData = data[mid]
        if midData == k:
            if mid < end and data[mid+1] == k:
                start = mid+1
            else:
                return mid
        elif midData > k:
            end = mid-1
        else:
            start = mid+1
        return self.GetLastK(data,length,k,start,end)
            
                



面试题:二叉树的深度

输入一棵二叉树,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。

递归算法

class TreeNode(object):
    def __init__(self,x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def TreeDepth(self,pRoot):
        if pRoot == None:
            return 0
        else:
            return max(self.TreeDepth(pRoot.left),self.TreeDepth(pRoot.right))+1

非递归方法:利用一个栈和一个标志位栈

class TreeNode(object):
    def __init__(self,x):
        self.val = x
        self.left = None
        self.right = None
        
class Solution(object):
    def TreeDepth(self,pRoot):
        if not pRoot:
            return 0
        depth = 0
        stack = []
        tag = []

        pNode = pRoot
        while pNode or stack:
            while pNode:
                stack.append(pNode)
                tag.append(0)
                pNode = pNode.left
            if tag[-1] == 1:
                depth = max(depth,len(stack))
                stack.pop()
                tag.pop()
                pNode = None
                
            else:
                pNode = stack[-1]
                pNode = pNode.right
                tag.pop()
                tag.append(1)
                
        return depth

面试题:判断平衡二叉树

输入一棵二叉树,判断该二叉树是否是平衡二叉树。

class TreeNode(object):
    def __init__(self,x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def IsBalanced_Solution(self,pRoot):
        if pRoot == None:
            return True
        if abs(self.getDepth(pRoot.left)-self.getDepth(pRoot.right)) > 1:
            return False
        return self.IsBalanced_Solution(pRoot.left) and self.IsBalanced_Solution(pRoot.right)
            


    def getDepth(self,pRoot):
        if pRoot == None:
            return 0

        return max(self.getDepth(pRoot.left),self.getDepth(pRoot.right))+1

面试题:数组中只出现一次的数字

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

class Solution:
    # 返回[a,b] 其中ab是出现一次的两个数字
    def FindNumsAppearOnce(self, array):
    # write code here
        res = []
        dict = {}
        for i in array:
            if i not in dict:
                dict[i] = 1
            else:
                dict[i] += 1
        for i in dict.keys():
            if dict[i] == 1:
                res.append(i)
        return res

面试题:和为S的连续正数序列

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

输出描述:
输出所有和为S的连续正数序列。序列内按照从小至大的顺序,序列间按照开始数字从小到大的顺序

滑动窗口解法:

# -*- coding:utf-8 -*-
class Solution:
    def FindContinuousSequence(self, tsum):
        # write code here
        """
        使用滑动窗口的方法来解决,
        设定一个动态的窗口,p_low指向窗口头部,
        p_high指向窗口尾部,窗口之间的值,为目标值。
        如果目标值为tsum,那就是其中一个解。否则移动窗口。
        :param tsum:
        """
        #判断输入要是小于3的话无解
        if tsum < 3:
            return []

        #设定初始的滑动窗口大小
        p_low = 1
        p_high = 2

        ans = []
        while p_low < p_high:
            #计算滑动窗口现在圈中的大小
            cur_sum = sum(range(p_low,p_high+1))
            if cur_sum == tsum:
                #找到一组解
                ans.append(range(p_low,p_high+1))
                #移动滑动窗口并寻找下一组解
                p_high = p_high+1
            elif cur_sum <tsum:
                p_high = p_high+1
            else:
                p_low=p_low+1

        return ans

面试题:和为s的两个数字

输入一个递增排序的数组和一个数字S,在数组中查找两个数,使得他们的和正好是S,如果有多对数字的和等于S,输出两个数的乘积最小的。
输出描述:
对应每个测试案例,输出两个数,小的先输出。
# 从左右一起查找
# 因为当两个数的和一定的时候, 两个数字的间隔越大, 乘积越小
# 所以直接输出查找到的第一对数即可

# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, array, tsum):
        # write code here
        if array == None or len(array) <= 0 or array[-1]+array[-2]<tsum:
            return []
        start = 0
        end = len(array)-1
        while start < end:
            sum =array[start]+array[end]
            
            if sum < tsum:
                start += 1
            elif sum > tsum:
                end -= 1
            else:
                return [array[start],array[end]]
        return []

面试题:左旋转字符串

题目描述
汇编语言中有一种移位指令叫做循环左移(ROL),现在有个简单的任务,就是用字符串模拟这个指令的运算结果。对于一个给定的字符序列S,请你把其循环左移K位后的序列输出。例如,字符序列S=”abcXYZdef”,要求输出循环左移3位后的结果,即“XYZdefabc”。是不是很简单?OK,搞定它!

class Solution(object):
    def LeftRotateString(self,s,n):
        if len(s) <= 0 or n < 0:
            return ''

        if len(s) == n:
            return s
        strList = list(s)


        frontList = strList[:n]
        behindList = strList[n:]

        res = ''.join(behindList)+''.join(frontList)
        return res

面试题:反转单词顺序列

题目描述
牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

class Solution(object):
	def ReverseSentence(self,s):
		l = s.split(" ")
		return ' '.join(l[::-1])

面试题:扑克牌顺子

题目描述
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。

class Solution(object):
    def IsContinuous(self,numbers):
        if numbers == None or len(numbers) <= 0:
            return False
        # 把A,J,Q,K转化一下
        transDict = {'A':1,'J':11,'Q':12,'K':13}
        for i in range(len(numbers)):
            if numbers[i] in transDict.keys():
                numbers[i] = transDict[numbers[i]]


        numbers = sorted(numbers)
        numberOfzero = 0
        numberOfGap = 0
        # 统计0的个数
        i= 0

        # 统计0的个数
        i = 0
        while i <len(numbers) and numbers[i] == 0:
            numberOfzero += 1
            i += 1

        # 统计间隔的数目
        small = numberOfzero
        big = small + 1
        while big < len(numbers):
            #出现对子,不可能是顺子
            if numbers[small] == numbers[big]:
                return False

            numberOfGap += numbers[big] - numbers[small]-1
            small = big
            big += 1
        return False if numberOfGap > numberOfzero else True

面试题:圆圈中最后剩下的数

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

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

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

面试题:求1+2+3+…+n

题目描述
求1+2+3+…+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

# -*- coding:utf-8 -*-
class Solution:
    def Sum_Solution(self, n):
        # write code here
        return n and self.Sum_Solution(n-1)+n

面试题:不用加减乘除做加法

利用异或以及与进位求解
不能一个正数一个负数
可能是python的的整型可以无限大的原因, 导致正数和负数的异或操作不断变成更小的负数而不会溢出
使用Swift尝试了一下, 还是可以求得正数和负数的位操作相加运算的
超时

class Solution(object):
    def Add(self,num1,num2):
        while num2:
           sum = num1^num2
           carry = (num1&num2)<<1
           num1 = sum
           num2 = carry

        return num1

#通过
通过每次对num1进行与操作保证是一个32位的整形
因此我们可以判断符号位是否为1做处理

class Solution(object):
    def Add(self,num1,num2):
        while num2 != 0:
            temp = num1 ^ num2
            num2 = (num1&num2) << 1
            num1 = temp & 0xFFFFFFFF
        return num1 if num1 >> 31 == 0 else num1 - 4294967296

面试题:把字符串转换成整数

题目描述

将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0

输入描述:
输入一个字符串,包括数字字母符号,可以为空

输出描述:
如果是合法的数值表达则返回该数字,否则返回0

class Solution(object):
    def StrToInt(self,s):
        flag = False
        if s == None or len(s) < 1:
            return 0
        numStack = []
        dict = {'0': 0, '1': 1, '2': 2, '3': 3, '4': 4, '5': 5, '6': 6, '7': 7, '8': 8, '9': 9}
        for i in s:
            if i in dict.keys():
                numStack.append(dict[i])

            elif i == '+':
                continue
            elif i == '-':
                continue
            else:
                return 0


        print(numStack)
        ans = 0
        if len(numStack) == 1 and numStack[0] == 0:
            flag = True
            return 0

        for i in numStack:
            ans = ans*10+i
        if s[0] == '-':
            ans = 0 - ans
        return ans

面试题:数组中重复的数字

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

class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        if numbers == None or len(numbers) <= 0:
            return False
        for i in numbers:
            if i < 0 or i > len(numbers) - 1:
                return False
        for i in range(len(numbers)):
            while numbers[i] != i:
                if numbers[i] == numbers[numbers[i]]:
                    duplication[0] = numbers[i]
                    return True
                else:
                    index = numbers[i]
                    numbers[i], numbers[index] = numbers[index], numbers[i]
        return False

面试题:构建乘积矩阵

题目描述
给定一个数组A[0,1,…,n-1],请构建一个数组B[0,1,…,n-1],其中B中的元素B[i]=A[0]A[1]…*A[i-1]A[i+1]…*A[n-1]。不能使用除法。(注意:规定B[0] = A[1] * A[2] * … * A[n-1],B[n-1] = A[0] * A[1] * … * A[n-2];)

class Solution(object):
    def multiply(self,A):
        if A == None or len(A) <= 0:
            return
        length = len(A)
        aList = [1] *length
        for i in range(1,length):
            aList[i] = aList[i-1]*A[i-1]

        temp = 1
        for i in range(length-2,-1,-1):
            temp = temp * A[i+1]
            aList[i] *= temp

        return aList

面试题:正则表达式匹配

面试题:表示数值的字符串

题目描述
请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100",“5e2”,"-123",“3.1416"和”-1E-16"都表示数值。 但是"12e",“1a3.14”,“1.2.3”,"±5"和"12e+4.3"都不是。

class Solution(object):
    #s字符串
    def isNumeric(self,s):
        if s == None or len(s) <= 0:
            return False
        
        aList = [w.lower() for w in s]
        if 'e' in aList:
            indexE = aList.index('e')
            front = aList[:indexE]
            behind = aList[indexE+1:]
            
            if '.' in behind or len(behind) == 0:
                return False
            isFront = self.scanDigit(front)
            isBehind = self.scanDigit(behind)
            return isBehind and isFront
        
        else:
            isNum = self.scanDigit(aList)
            return isNum
        
        
    def scanDigit(self,aList):
        dotNum = 0
        allowVal = ['0','1','2','3','4','5','6','7','8','9','+','-','.','e']
        for i in range(len(aList)):
            if aList[i] not in allowVal:
                return False
            
            if aList[i] == '.':
                dotNum += 1
            
            if aList[i] in '+-' and i != 0:
                return False
            
        if dotNum > 1:
            return False
        return True
       
# Python trick
    def isNumeric2(self, s):
        try:
            float(s)
            if s[0:2] != '-+' and s[0:2] != '+-':
                return True
            else:
                return False
        except:
            return False

面试题:字符流中第一个不重复的字符

题目描述
请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。

输出描述:
如果当前字符流没有存在出现一次的字符,返回#字符。

class Solution(object):
    def __init__(self):
        self.aDict = {}
        self.aList = []

    def FirstAppearingOnce(self):
        while len(self.aList) > 0 and self.aDict[self.aList[0]] == 2:
            self.aList.pop(0)

        if len(self.aList) == 0:
            return '#'

        else:
            return self.aList[0]


    def Insert(self,char):
        if char not in self.aDict.keys():
            self.aDict[char] = 1
            self.aList.append(char)
            
        elif self.aDict[char]:
            self.aDict[char] = 2

面试题:链表中环的入口结点

题目描述
给一个链表,若其中包含环,请找出该链表的环的入口结点,否则,输出null。

寻找链表中环的入口结点主要分成三个步骤:首先是设置两个快慢指针,如果快慢指针相遇,则快慢指针必然都在环中;然后从相遇的地方设置一个指针向后遍历并记录走的步数,当这个指针重新指到开始的位置的时候,当前对应的步数就是环中结点的数量k;然后设置两个指针从链表开始,第一个节点先走k步,然后第二个指针指到链表的开始,两个指针每次都向后走一步,两个指针相遇的位置就是链表的入口。

class ListNode:
	def __init__(self,x):
		self.val = x
		self.next = None
class Solution(object):
	def MeetingNode(self,pHead):
		if pHead == None:
			return None
		pSlow = pHead.next
		if pSlow == None:
			return None
		pFast = pSlow.next

		while pFast:
			if pFast == pSlow:
				return pSlow
			pSlow = pSlow.next
			pFast = pFast.next
			if pFast:
				pFast = pFast.next
	def EntryNodeOfLoop(self,pHead):
		meetingNode = self.MeetingNode(pHead)
		if not meetingNode:
			return None
		NodeLoop = 1
		flagNode = meetingNode
		while flagNode.next != meetingNode:
			NodeLoop += 1
			flagNode = flagNode.next

		pFast = pHead
		for i in range(NodeLoop):
			pFast = pFast.next
		pSlow = pHead
		while pFast != pSlow:
			pFast = pFast.next
			pSlow = pSlow.next
		return pFast

面试题:删除链表中重复的结点

我们需要设置一个指针preNode,preNode最开始为None,然后设置两个指针,pNode指向当前节点,pNext指向pNode下一个结点,⓵如果pNext不为空而且pNext的值等于pNode的值,那么就说明出现了重复数字的结点,就需要删除,然后从pNode开始遍历,如果结点值等于前面那个重复值,继续遍历。当遍历到None或者不同值结点的时候,这时候需要判断preNode结点,如果preNode结点为None,就说明我们刚才的重复结点是从整个链表的头结点开始重复的,就直接把pHead设置为当前结点,pNode也设置为当前结点。反之,如果preNode不为None,直接把preNode的下一个指针指向当前节点,pNode指向preNode即可;⓶如果pNext为空或者pNext的值不等于pNode的值,说明当前的这个pNode和后面的值不重复,直接令preNode = pNode,pNode指向下一个结点即可。

class ListNode(object):
    def __init__(self,x):
        self.val = x
        self.next = None

class Solution(object):
    def deleteDuplication(self,pHead):
        if pHead == None:
            return
        preHead = None
        
        pNode = pHead
        while pNode != None:
            needDelete = False
            nextNode = pNode.next
            if nextNode != None and nextNode.val == pNode.val:
                needDelete = True
            if needDelete == False:
                preHead = pNode
                pNode = pNode.next
            else:
                nodeVal = pNode.val
                pToBeDel = pNode
                while pToBeDel != None and pToBeDel.val == nodeVal:
                    pToBeDel = pToBeDel.next
                if preHead == None:
                    pHead = pToBeDel
                    pNode = pToBeDel
                    continue
                    
                else:
                    preHead.next = pToBeDel
                pNode = preHead
                
        return pHead          

面试题:二叉树的下一个结点

三种情况:当前节点有右子树的话,当前节点的下一个结点是右子树中的最左子节点;当前节点无右子树但是是父节点的左子节点,下一个节点是当前结点的父节点;当前节点无右子树而且是父节点的右子节点,则一直向上遍历,直到找到最靠近的一个祖先节点pNode,pNode是其父节点的左子节点,那么输入节点的下一个结点就是pNode的父节点。

class TreeLinkNode:
	def __init__(self,x):
		self.val = x 
		self.left = None
		self.right = None
		self.next = None
class Solution(object):
	def GetNext(self,pNode):
		if pNode == None:
			return 
		pNext = None
		if pNode.right != None:
			pRight = pNode.right
			while pRight.left != None:
				pRight = pRight.left
			pNext = pRight
		elif pNode != None:
			pCurrent = pNode
			pParent = pCurrenrt
			while pParent != None and pCurrent == pParent.right:
				pCurrent = pParent
				pParent = pCurrent.next
			pNext = pParent
		return pNext

面试题:对称的二叉树

分为递归和非递归的两种方式,思想是一样的。主要就是把叶子节点的None节点也加入到遍历当中。按照前序遍历二叉树,存入一个序列中。然后按照和前序遍历对应的先父节点,然后右子节点,最后左子节点遍历二叉树,存入一个序列。如果前后两个序列相等,那么说明二叉树是对称的。

递归法:

class TreeNode(object):
    def __init__(self,x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def isSymmetrical(self, pRoot):
        return self.selfIsSymmetrical(pRoot,pRoot)


    def selfIsSymmetrical(self,pRoot1,pRoot2):
        if pRoot1 == None and pRoot2 == None:
            return True
        if pRoot1 == None or pRoot2 == None:
            return False
        if pRoot1.val != pRoot2.val:
            return False
        return self.selfIsSymmetrical(pRoot1.left,pRoot2.right) and self.selfIsSymmetrical(pRoot1.right,pRoot2.left)
    

非递归实现判断二叉树是否对称
#利用前序遍历

class Solution2:
    def isSymmetrical(self, pRoot):
        preList = self.preOrder(pRoot)
        mirrorList = self.mirrorPreOrder(pRoot)
        if preList == mirrorList:
            return True
        return False

    def preOrder(self, pRoot):
        if pRoot == None:
            return [None]
        treeStack = []
        output = []
        pNode = pRoot
        while pNode or len(treeStack) > 0:
            while pNode:
                treeStack.append(pNode)
                output.append(pNode.val)
                pNode = pNode.left
                if not pNode:
                    output.append(None)
            if len(treeStack):
                pNode = treeStack.pop()
                pNode = pNode.right
                if not pNode:
                    output.append(None)
        return output

    def mirrorPreOrder(self, pRoot):
        if pRoot == None:
            return [None]
        treeStack = []
        output = []
        pNode = pRoot
        while pNode or len(treeStack) > 0:
            while pNode:
                treeStack.append(pNode)
                output.append(pNode.val)
                pNode = pNode.right
                if not pNode:
                    output.append(None)
            if len(treeStack):
                pNode = treeStack.pop()
                pNode = pNode.left
                if not pNode:
                    output.append(None)
        return output

面试题:把二叉树打印成多行

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

class TreeNode(object):
    def __init__(self,x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def Print(self,pRoot):
        if pRoot == None:
            return []

        nodes,res = [pRoot],[]

        while nodes:
            curStack,nextStack = [],[]
            for node in nodes:
                curStack.append(node.val)
                if node.left:
                    nextStack.append(node.left)

                if node.right:
                    nextStack.append(node.right)

            res.append(curStack)
            nodes = nextStack

        return res

面试题:按之字形顺序打印二叉树

class TreeNode(object):
    def __init__(self,x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def Serialize(self,root):
        serializeStr = ''
        if root == None:
            return '#'
        stack = []
        while root or stack:
            while root:
                serializeStr += str(root.val) + ','
                stack.append(root)
                root = root.left

            serializeStr += '#,'
            root = stack.pop()
            root = root.right

        serializeStr = serializeStr[:-1]
        return serializeStr

    def Deserialize(self, s):
        serialize = s.split(',')
        tree, sp = self.deserialize(serialize, 0)
        return tree

    def deserialize(self, s, sp):
        if sp >= len(s) or s[sp] == '#':
            return None, sp + 1
        node = TreeNode(int(s[sp]))
        sp += 1
        node.left, sp = self.deserialize(s, sp)
        node.right, sp = self.deserialize(s, sp)
        return node, sp

面试题:序列化二叉树

class TreeNode(object):
    def __init__(self,x):
        self.val = x
        self.left = None
        self.right = None

class Solution(object):
    def Serialize(self,root):
        serializeStr = ''
        if root == None:
            return '#'
        stack = []
        while root or stack:
            while root:
                serializeStr += str(root.val) + ','
                stack.append(root)
                root = root.left

            serializeStr += '#,'
            root = stack.pop()
            root = root.right

        serializeStr = serializeStr[:-1]
        return serializeStr

    def Deserialize(self, s):
        serialize = s.split(',')
        tree, sp = self.deserialize(serialize, 0)
        return tree

    def deserialize(self, s, sp):
        if sp >= len(s) or s[sp] == '#':
            return None, sp + 1
        node = TreeNode(int(s[sp]))
        sp += 1
        node.left, sp = self.deserialize(s, sp)
        node.right, sp = self.deserialize(s, sp)
        return node, sp

面试题:二叉搜索树的第k个结点

‘’’
给定一颗二叉搜索树,请找出其中的第k大的结点。例如,
5
/
3 7
/\ /
2 4 6 8 中,
按结点数值大小顺序第三个结点的值为4。
‘’’
中序遍历

class TreeNode:
    def __init__(self,x):
        self.val = x
        self.left = None
        self.right = None


class Solution:
    #返回对应结点TreeNode
    def __init__(self):
        self.treeNode = []
    def inOrder(self,pRoot):
        if len(self.treeNode) < 0:
            return None
        if pRoot.left:
            self.inOrder(pRoot.left)
        self.treeNode.append(pRoot)

        if pRoot.right:
            self.inOrder(pRoot.right)


    def KthNode(self,pRoot,k):
        if k == 0 or pRoot == None:
            return
        self.inOrder(pRoot)
        if len(self.treeNode) < k:
            return None
        return self.treeNode[k-1]

面试题:

题目描述
如何得到一个数据流中的中位数?如果从数据流中读出奇数个数值,那么中位数就是所有数值排序之后位于中间的数值。如果从数据流中读出偶数个数值,那么中位数就是所有数值排序之后中间两个数的平均值。我们使用Insert()方法读取数据流,使用GetMedian()方法获取当前读取数据的中位数。

class Solution(object):
    def __init__(self):
        self.nums = []
        
    def Insert(self,num):
        self.nums.append(num)
        
        
    def GetMedian(self,n=None):
        self.nums.sort()
        if len(self.nums)%2 == 0:
            res = (self.nums[len(self.nums)/2] + self.nums[len(self.nums)/2-1])/2.0
        else:
            res = self.nums[len(self.nums)//2]
            
        return res

面试题:滑动窗口的最大值

题目描述
给定一个数组和滑动窗口的大小,找出所有滑动窗口里数值的最大值。例如,如果输入数组{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]}。

我们把可能成为滑动窗口的最大值的数值下标存入一个两端开口的队列index中。

首先遍历输入数组,在遍历次数小于窗口长度的时候,如果index数组里面含有元素而且元素后面的下标值对应的输入数组的数如果小于当前遍历到的输入数组元素值,那么就把尾部的元素下标值不断pop出来,再压入当前输入元素对应的下标值。然后再从等于滑动窗口大小的位置继续遍历输入数组。首先把index数组的头元素下标值对应输入数组值压入输出数组。同样的,如果index数组里面含有元素而且元素后面的下标值对应的输入数组的数如果小于当前遍历到的输入数组元素值,那么就把尾部的元素下标值不断pop出来,同时,如果index数组内有元素,而且当一个数字的下标与当前处理的数字的下标只差大于或等于滑动窗口的大小时,这个数字已经从窗口中画出,可以从队列中删除了,再压入当前输入元素对应的下标值。最后还需要在输出数组中append一下index手元素下标对应的输入元素值。

class Solution(object):
    def maxInWindows(self,num,size):
        if not num or size <= 0:
            return []
        deque = []
        if len(num) >= size:
            index = []
            for i in range(size):
                while len(index) > 0 and num[i] > num[index[-1]]:
                    index.pop()
                index.append(i)


            for i in range(size,len(num)):
                deque.append(num[index[0]])
                while len(index) > 0 and num[i] >= num[index[-1]]:
                    index.pop()
                if len(index) > 0 and index[0] <= i - size:
                    index.pop(0)
                index.append(i)

            deque.append(num[index[0]])
        return deque

面试题:矩阵中的路径

在这里插入图片描述
回溯法:
任选一个格子作为路径的起点。假设矩阵中某个格子的字符为ch并且这个格子将对应于路径上的第i个字符。如果路径上的第i个字符不是ch,那么这个格子不可能处在路径上的第i个位置。如果路径上的第i个字符正好是ch,那么往相邻的格子寻找路径上的第i+1个字符。除在矩阵边界上的格子外,其他各自都有4个相邻的格子。重复这个过程直到路径上的所有字符都在矩阵中找到相应的位置。

class Solution(object):
	def hasPath(self,matrix,rows,cols,path):
		if matrix == None or rows < 1 or cols < 1 or path == None:
			return False
		visited = [0] * [rows * cols]
		for row in range(rows):
			for col in range(cols):
				self.hasPathCore(matrix,rows,cols,row,col,path,pathLength,visited)
				

面试题:机器人的运动范围

题目描述
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?

class Solution(object):
    def movingCount(self,threshold,rows,cols):
        visited = [False] * (rows * cols)
        count = self.movingCountCore(threshold,rows,cols,0,0,visited)
        return count

    def movingCountCore(self,threshold,rows,cols,row,col,visited):
        count = 0
        if self.check(threshold,rows,cols,row,col,visited):
            visited[row*cols+col] = True
            count = 1 +self.movingCountCore(threshold,rows,cols,row-1,col,visited) + \
                       self.movingCountCore(threshold,rows,cols,row+1,col,visited) + \
                       self.movingCountCore(threshold,rows,cols,row,col-1,visited) + \
                       self.movingCountCore(threshold,rows,cols,row,col+1,visited)
        return count



    def check(self,threshold,rows,cols,row,col,visited):
        if row >= 0 and row < rows and col >= 0 and col < cols and self.getDigitSum(row) + self.getDigitSum(col) <= threshold and not visited[row*cols+col]:
            return True
        return False

    def getDigitSum(self,number):
        sum = 0
        while number > 0:
            sum  += (number % 10)
            number = number// 10
        return sum

面试题:剪绳子

题目描述
给你一根长度为n的绳子,请把绳子剪成整数长的m段(m、n都是整数,n>1并且m>1),每段绳子的长度记为k[0],k[1],…,k[m]。请问k[0]xk[1]x…xk[m]可能的最大乘积是多少?例如,当绳子的长度是8时,我们把它剪成长度分别为2、3、3的三段,此时得到的最大乘积是18。

动态规划

class Solution:
    def cutRope(self, number):
        # write code here

        if number < 2:
            return 0
        if number == 2:
            return 1
        if number == 3:
            return 2

        dp = [-1]*(number+1)
        dp[0] = 0
        dp[1] = 1
        dp[2] = 2
        dp[3] = 3
        for i in range(4,number+1):
            max = 0
            for j in range(1,i//2 + 1):
                temp = dp[j] * dp[i-j]
                if temp > max:
                    max = temp
                    dp[i] = max

        return dp[number]

贪心


class Solution:
    def cutRope(self, number):
        # write code here
        res=1
        if number<=1:
            return 0
        elif number<=2:
            return 1
        elif number<=3:
            return 2
        elif number>3:
            if number%3==0:
                res=3**(number//3)
            elif number%3==1:
                res=3**(number//3-1)*4
            else:
                res=3**(number//3)*(number%3)
        return res
  • 0
    点赞
  • 6
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值