剑指offer(Python版)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_38358305/article/details/85858099

一、线性表

1.数组 

 题3:二维数组中的查找

在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。

思路:

# -*- coding:utf-8 -*-
class Solution:
    # array 二维列表
    def Find(self, target, array):
        # write code here
        i = 0
        j = len(array[0]) - 1
        while i <= len(array)-1 and j >= 0:
            if array[i][j] > target:
                j = j-1
            elif array[i][j] < target:
                i = i+1
            else:
                return True
        return False

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

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

思路:(插入排序)

 i从左到右遍历,遇到奇数停止,j从i-1向左遍历,遇偶数交换,j继续从该位置向左迭代交换偶数。

# -*- coding:utf-8 -*-
class Solution:
    def reOrderArray(self, array):
        # write code here
        temp = 0
        for i in range(len(array)):
            if array[i]%2 == 1:
                for j in range(i-1,-1,-1):#从i到0逆序
                    if array[j]%2 == 0:#将插入排序法中比大小改为比奇偶
                        temp = array[j+1]
                        array[j+1] = array[j]
                        array[j] = temp
        return array

题29:数组中出现超过一半的数字

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

思路:

如果有符合条件的数字,则它出现的次数比其他所有数字出现的次数和还要多。在遍历数组时保存两个值:一是数组中一个数字,一是次数。遍历下一个数字时,若它与之前保存的数字相同,则次数加1,否则次数减1;若次数为0,则保存下一个数字,并将次数置为1。遍历结束后,所保存的数字即为所求。然后再判断它是否符合条件即可。

# -*- coding:utf-8 -*-
class Solution:
    def MoreThanHalfNum_Solution(self, numbers):
        # write code here
        if numbers == None:
            return 0
        list_len = len(numbers)
        count = 0
        for i in range(list_len):
            if count == 0:
                result = numbers[i]
            if result == numbers[i]:
                count = count+1
            else:
                count = count -1
        totle_num =  numbers.count(result)
        if totle_num <= list_len/2:#这步很关键
            return 0
        return result

题30:最小的K个数

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

思路:size为k的最大堆,每次拿堆顶和其他数比较,保留较小的。最后对堆序列排序。

# -*- coding:utf-8 -*-
class Solution:
    def GetLeastNumbers_Solution(self, tinput, k):
        # write code here
        n = len(tinput)
        if k <= 0 or k > n:
            return []
        # 建立大顶堆
        for i in range(int(k / 2) - 1, -1, -1):
            self.build_max_head(tinput,k,i)
        for i in range(k, n):
            if tinput[i] < tinput[0]:
                tinput[0], tinput[i] = tinput[i], tinput[0]
                # 调整前k个数
                self.build_max_head(tinput,k,0)
        res = []
        for i in range(k):
            res.append(tinput[i])
        res.sort()
        return res

    def build_max_head(self,arr,heapsize,root_index):
        #根据给定的根节点计算左右节点的index
        left_index = 2*root_index+1
        right_index = left_index+1
        max_num_index = root_index    
        #如果左节点大于根节点,那么max_num_index=left_index
        if left_index<heapsize and arr[left_index]>arr[max_num_index]:
            max_num_index=left_index    
        #如果右节点大于根节点,那么max_num_index=right_index
        if right_index<heapsize and arr[right_index]>arr[max_num_index]:
            max_num_index=right_index    
        if  max_num_index != root_index:
            arr[root_index],arr[max_num_index] = arr[max_num_index],arr[root_index]        #进行下一个节点的build_max
            self.build_max_head(arr,heapsize,max_num_index)

题33:把数组拍成最小的数

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

思路:将快排中的比大小改为两数拼接的数比大小

# -*- coding:utf-8 -*-
class Solution:
    def quick_sort(self,L,start,end):
        if start < end:
            i,j,mid = start,end,L[start]
            while i<j:
                while i < j and str(L[j])+str(mid) >= str(mid)+str(L[j]):
                    j = j-1
                if i<j :
                    L[i] = L[j]
                while i < j and str(L[i])+str(mid) <= str(mid)+str(L[i]):
                    i = i+1
                if i<j:
                    L[j] = L[i]
            L[i] = mid
            self.quick_sort(L,start,i-1)
            self.quick_sort(L,i+1,end)
        return L
    def PrintMinNumber(self, numbers):
        # write code here
        self.quick_sort(numbers,0,len(numbers)-1)
        res = ''
        for i in range(len(numbers)):
            res = res + str(numbers[i])
        return res

题36:数组中的逆序对 

在数组中的两个数字,如果前面一个数字大于后面的数字,则这两个数字组成一个逆序对。输入一个数组,求出这个数组中的逆序对的总数P。并将P对1000000007取模的结果输出。 即输出P%1000000007

思路:归并排序,两组合并的时候,第二组每合并一个数,逆序对就增加第一组剩下的长度。(直接用基础归并python会超时)

按归并排序,把两个函数合并为一个,降低时间

# -*- coding:utf-8 -*-
class Solution:
    def InversePairs(self, data):
        # write code here
        return self.merge_sort(data[:], 0, len(data)-1, data[:])%1000000007
    def merge_sort(self, temp, start, end, data):
        if end-start <1:
            return 0
        if end - start == 1:
            if data[start]<=data[end]:
                return 0
            else:
                temp[start], temp[end] = data[end], data[start]
                return 1
        mid = (start+end)//2#(int)((start+end)/2)
        left = self.merge_sort(data,start,mid,temp)
        right = self.merge_sort(data,mid+1,end,temp)
        count = 0
        i = start
        j = mid + 1
        index = start
        while i<=mid and j<=end:
            if data[i] <= data[j]:
                temp[index] = data[i]
                i +=1
            else:
                temp[index] = data[j]
                j+=1
                count += mid-i+1
            index += 1
        while i<=mid:
            temp[index] = data[i]
            i += 1
            index +=1
        while j<=end:
            temp[index] = data[j]
            j += 1
            index += 1
        return count+left+right

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

题目描述:统计一个数字在排序数组中出现的次数。

思路:看到有序,用二分查找,找对值为k的第一个和最后一个坐标,相减。

# -*- coding:utf-8 -*-
class Solution:#(0分做法?)
    def GetNumberOfK(self, data, k):
        # write code here
        return data.count(k)
# -*- coding:utf-8 -*-
class Solution:
    def GetNumberOfK(self, data, k):
        # write code here
        left = 0
        right = len(data) - 1
        leftk = self.getleftK(data,k,left,right)
        rightk = self.getrightK(data,k,left,right)
        return rightk-leftk+1
    def getleftK(self,data,k,left,right):
        while left <= right:
            mid = (left+right)//2
            if data[mid]<k:
                left = mid+1
            else:
                right = mid-1
        return left
    def getrightK(self,data,k,left,right):
        while left <= right:
            mid = (left+right)//2
            if data[mid]<=k:
                left = mid+1
            else:
                right = mid-1
        return right

题55 数组中重复的数字

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

思路:(因为有条件:在一个长度为n的数组里的所有数字都在0到n-1的范围内。)从下标0开始,对每个元素,若numbers[i]不等于i,则交换numbers[i]和numbers[numbers[i]],直至i和numbers[i]相等继续循环,或numbers[i]和numbers[numbers[i]]相等即遇到重复元素返回True。(注意两数调换的顺序)

# -*- coding:utf-8 -*-
class Solution:
    # 这里要特别注意~找到任意重复的一个值并赋值到duplication[0]
    # 函数返回True/False
    def duplicate(self, numbers, duplication):
        for i in range(len(numbers)):
            while numbers[i] != i:
                if numbers[i]==numbers[numbers[i]]:
                    duplication[0] = numbers[i]
                    return True
                tmp = numbers[numbers[i]]
                numbers[numbers[i]] = numbers[i]
                numbers[i] = tmp
#                tmp = numbers[i] 
#                numbers[i] = numbers[numbers[i]]
#                numbers[numbers[i]] = tmp#先改变numbers[i]的值会改变numbers[numbers[i]]的位置索引,不行
                #numbers[i],numbers[numbers[i]] = numbers[numbers[i]],numbers[i]
        return False

面试题52:构建乘积数组

题目描述:给定一个数组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]。不能使用除法。

 思路:建立A*A的对角矩阵,对角线为1 每行相乘即为B(动态规划)

# -*- coding:utf-8 -*-
class Solution:
    def multiply(self, A):
        # write code here
        B=[1]*len(A)
        C=[1]*len(A)
        D=[1]*len(A)
        for i in range(1,len(A)):
            C[i]=A[i-1]*C[i-1]
        for j in range(len(A)-2,-1,-1):
            D[j]=A[j+1]*D[j+1]
        for x in range(len(A)):
            B[x]=C[x]*D[x]
        return B

2、链(pHead头节点是实在的,有val!!!!!)

题5:从尾到头打印链表

题目描述

输入一个链表,按链表值从尾到头的顺序返回一个ArrayList。

思路:遍历链表到list,再反转

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None

class Solution:
    # 返回从尾部到头部的列表值序列,例如[1,2,3]
    def printListFromTailToHead(self, listNode):
        # write code here
        res=[]
        node = listNode
        if node == None:
            return []
        if node.next ==None:
            return[listNode.val]
        while node.next !=None:
            res.append(node.val)
            node =node.next
            if node.next ==None:
                res.append(node.val)
        res.reverse()
        return res

题15:链表中倒数第k个结点

题目描述:输入一个链表,输出该链表中倒数第k个结点。

思路:设置两个指针,A指针先走k-1个节点,然后A,B指针一起遍历,到A结束时读B所指节点

class Solution:
    def FindKthToTail(self, head, k):
        # write code here
        a = head
        b = head
        if k==0 or head ==None:
            return None
        if k==1:
            a = b
        if k>1:
            for i in range(k-1):
                a =a.next
                if a==None:
                    return None
        while a.next !=None:
            a =a.next
            b=b.next
        return b

面试题16:反转链表

题目描述:输入一个链表,反转链表后,输出新链表的表头。

思路:直接撸

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    # 返回ListNode
    def ReverseList(self, pHead):
        # write code here
        if pHead == None or pHead.next ==None:
            return pHead
        temp = pHead.next
        pHead.next = None
        node2 = temp
        node1 = pHead
        while node2 !=None:
            temp = node2.next
            node2.next = node1
            node1 = node2
            node2 = temp
        return node1

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

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

思路:递归

# -*- 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 pHead1 is None:
            return pHead2
        elif pHead2 is None:
            return pHead1
        if pHead1.val < pHead2.val:
            node = pHead1
            node.next = self.Merge(pHead1.next,pHead2)
        else:
            node = pHead2
            node.next = self.Merge(pHead1,pHead2.next)
        return node

面试题26:复杂链表的复制

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

思路:先复制每个链表结点,并接在每个原结点后面,再将每个random克隆指针赋给克隆节点,最后将原来和克隆节点分开

# -*- 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):
        # write code here
        self.clone_nodes(pHead)
        self.connect_random_nodes(pHead)
        return self.divide_list(pHead)
    def clone_nodes(self,pHead):
        node = pHead
        while node is not None:
            clone_node = RandomListNode(node.label)
            clone_node.next = node.next
            node.next = clone_node
            node = clone_node.next
    def connect_random_nodes(self,pHead):
        node = pHead
        while node is not None:
            clone_node = node.next
            if node.random is not None:
                clone_node.random = node.random.next
            node = clone_node.next
    def divide_list(self,pHead):
        node = pHead
        clone_list_head = None
        if node is not None:
            clone_list_head = node.next
            clone_node = node.next
            node.next = clone_node.next
            node = node.next
        while node is not None:
            clone_node.next = node.next
            clone_node = clone_node.next
            node.next = clone_node.next
            node = node.next
        return clone_list_head

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

题目描述:输入两个链表,找出它们的第一个公共结点。

思路:暴力遍历

# -*- 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
        a = []
        x1 = pHead1
        x2 = pHead2
        while x1 is not None:
            a.append(x1.val)
            x1 = x1.next
        while x2 is not None:
            if x2.val in a:
                return x2
            else:
                x2 = x2.next
        return None

思路: 

第一种情况:相同长度有交点
两个指针一起走,步长一致,碰到第一个相同的节点 p1 == p1,退出循环,return p1。
第二种情况:相同长度无交点
两个指针一起走,直到走到最后一个节点,p1.next 和 p2.next都为 None,满足 相等的条件,退出循环,return p1。
第三种情况:不同长度有交点
两个指针一起走,当一个指针p1走到终点时,说明p1所在的链表比较短,让p1指向另一个链表的头结点开始走,直到p2走到终点,让p2指向短的链表的头结点,那么,接下来两个指针要走的长度就一样了,变成第一种情况。
第四种情况:不同长度无交点
两个指针一起走,当一个指针p1走到终点时,说明p1所在的链表比较短,让p1指向另一个链表的头结点开始走,直到p2走到终点,让p2指向短的链表的头结点,那么,接下来两个指针要走的长度就一样了,变成第二种情况。

意思是长接短链表和短接长链表, 如果有公共结点,这俩链表后半段相同。

# -*- 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
        if not pHead1 or not pHead2:
            return None
        p1, p2 = pHead1, pHead2
        while p1 != p2:
            p1 = pHead2 if not p1 else p1.next
            p2 = pHead1 if not p2 else p2.next
        return p1

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

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

思路:

第一步,找环中相汇点。分别用p1,p2指向链表头部,p1每次走一步,p2每次走二步,直到p1==p2找到在环中的相汇点。

第二步,找环的入口。接上步,当p1==p2时,p2所经过节点数为2x,p1所经过节点数为x,设环中有n个节点,p2比p1多走一圈有2x=n+x; n=x;可以看出p1实际走了一个环的步数,再让p2指向链表头部,p1位置不变,p1,p2每次走一步直到p1==p2; 此时p1指向环的入口。

# -*- 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 (pHead.next and pHead.next.next) is None:
            return None
        p1 = pHead.next
        p2 = pHead.next.next
        while p1.next and p2.next.next:
            if p1 != p2:
                p1 = p1.next
                p2 = p2.next.next
            else:
                p2 = pHead
                while p1!=p2:
                    p1 = p1.next
                    p2 = p2.next
                return p1
        return None

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

题目描述:在一个排序的链表中,存在重复的结点,请删除该链表中重复的结点,重复的结点不保留,返回链表头指针。 例如,链表1->2->3->3->4->4->5 处理后为 1->2->5

思路:链表前加个新头节点,删节点时要保留前面的节点信息

# -*- coding:utf-8 -*-
# class ListNode:
#     def __init__(self, x):
#         self.val = x
#         self.next = None
class Solution:
    def deleteDuplication(self, pHead):
        # write code here
        first = ListNode(2009)
        last = first
        first.next = pHead
        while first.next and first.next.next:
            if first.next.val == first.next.next.val:
                num = first.next.val
                while first.next and first.next.val == num:
                    first.next = first.next.next
                continue
            first = first.next
        return last.next

面试题4:替换空格

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

# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        s=s.replace(' ','%20')
        return s

面试题28:字符串的排列

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

输入描述:  输入一个字符串,长度不超过9(可能有字符重复),字符只包括大小写字母。
思路:要做字符串的全排列。做法是把对字符串中的每个元素都当做起始位置,把其他元素当做以后的位置,然后再同样的进行操作。这样就会得到全排列。

# -*- coding:utf-8 -*-
class Solution:
    def Permutation(self, ss):
        if not ss:
            return []
        res = []
        self.helper(ss, res, '')
        return sorted(list(set(res)))

    def helper(self, ss, res, path):
        if not ss:
            res.append(path)
        else:
            for i in range(len(ss)):
                self.helper(ss[:i] + ss[i+1:], res, path + ss[i])

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

题目描述:求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

思路:遍历各位

1.当前位为flag十位0,如103,count增加1(high) * 10(flag)

2.当前位为1,如113,count加1(high)*10 + low(3)+1(cur)

3.当前位为2-9,如159,count加(1(high)+1)*flag

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        count = 0
        flag = 1
        while n/flag:
            cur = (n/flag)%10
            low = n-(n/flag)*flag
            high = n/(flag*10)
            if cur == 0:
                count += high*flag
            elif cur ==1:
                count += high*flag+low+1
            else:
                count += (high+1)*flag
            flag *=10
        return count

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

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

# -*- coding:utf-8 -*-
class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        if s =='':
            return -1
        for i in s:
            if s.count(i) == 1:
                return s.index(i)
        return -1

面试题42:反转单词顺序以及左旋转字符串
反转单词顺序:

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

# -*- coding:utf-8 -*-
class Solution:
    def ReverseSentence(self, s):
        # write code here
        a=''
        b=''
        for i in range(len(s)-1,-1,-1):
            if s[i] !=' ':
                a = s[i]+a
            else:
                b = b+a
                b = b+' '
                a = ''
            if i == 0:
                b= b+a
        return b

左旋转字符串:

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

# -*- coding:utf-8 -*-
class Solution:
    def LeftRotateString(self, s, n):
        # write code here
        return s[n:]+s[0:n]

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

题目描述:将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。

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

输出描述:如果是合法的数值表达则返回该数字,否则返回0
思路:a放连续字符的整数,b放各段连续整数,若长度为1则返回。需要判空,判单个‘-’。

# -*- coding:utf-8 -*-
class Solution:
    def StrToInt(self, s):
        # write code here
        if s=='':
            return 0
        a=''
        i=0
        b=[]
        while i<len(s):
            if s[i]=='-' or ord(s[i])>=ord('0')and ord(s[i])<=ord('9'):
                a = a+s[i]
            elif a!='':
                b.append(a)
            i +=1
            if i==len(s) and len(a)>0:
                b.append(a)
        if len(b) ==1 and b[0]!='-':
            return int(b[0])
        else:
            return 0

面试题53:正则表达式匹配

题目描述:请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配

思路:

特殊:

1、两个字符串都为空,返回true

2、当第一个字符串不空,而第二个字符串空了,返回false

而当模式中的第二个字符是“*”时:

如果字符串第一个字符跟模式第一个字符不匹配,则模式后移2个字符,继续匹配。如果字符串第一个字符跟模式第一个字符匹配,可以有3种匹配方式:

1、模式后移2字符,相当于x*被忽略;

2、字符串后移1字符,模式后移2字符;

3、字符串后移1字符,模式不变,即继续匹配字符下一位,因为*可以匹配多位;

当模式中的第二个字符不是“*”时:

1、如果字符串第一个字符和模式中的第一个字符相匹配,那么字符串和模式都后移一个字符,然后匹配剩余的。

2、如果 字符串第一个字符和模式中的第一个字符相不匹配,直接返回false。

# -*- coding:utf-8 -*-
class Solution:
    # s, pattern都是字符串
    def match(self, s, pattern):
        # write code here
        if s=='' and pattern=='':
            return True
        elif s!='' and pattern=='':
            return False
        if len(pattern)>1 and pattern[1] == '*':
            if len(s)>0 and (s[0]==pattern[0] or pattern[0]=='.'):
                return self.match(s,pattern[2:])or self.match(s[1:],pattern[2:]) or self.match(s[1:],pattern)
            else:
                return self.match(s,pattern[2:])
        if len(s) >0 and (pattern[0]=='.' or pattern[0]==s[0]):
            return self.match(s[1:],pattern[1:])
        return False

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

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

# -*- coding:utf-8 -*-
class Solution:
    # s字符串
    def isNumeric(self, s):
        # write code here
        try:
            float(s)
            return True
        except:
            return False
# -*- coding:utf-8 -*-
class Solution:
    # s字符串
    def isNumeric(self, s):
        # write code here
        e_index = -1
        p_index = -1
        if s.count('.')>1 or (s.count('e')+s.count('E'))>1:
            return False
        for i in range(len(s)):
            if (s[i] =='+' or s[i]=='-') and i>(e_index+1):
                return False
            elif s[i] == 'e'or s[i]=='E':
                e_index = i
            elif s[i] == '.':
                p_index = i
            elif (ord(s[i])<ord('0') or ord(s[i])>ord('9')) and(s[i]!='+'and s[i]!='-'):
                return False
            
            if e_index < p_index and e_index!=-1 or e_index==len(s)-1:
                return False
        return True

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

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

# -*- coding:utf-8 -*-
class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        if s =='':
            return -1
        for i in s:
            if s.count(i) == 1:
                return s.index(i)
        return -1

三、栈和队列

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

题目描述:用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack1 = []
        self.stack2 = []
    def push(self, node):
        # write code here
        while len(self.stack2) > 0:
            self.stack1.append(self.stack2.pop())
        self.stack1.append(node)
    def pop(self):
        # return xx
        while len(self.stack1) > 0:
            self.stack2.append(self.stack1.pop())
        return self.stack2.pop()
    #看剑指offer-题7:用两个栈实现队列

面试题21:包含min函数的栈

题目描述:定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

思路:建个min的栈,data栈每压入一个较大的数,min就压入一个栈顶的数。

# -*- coding:utf-8 -*-
class Solution:
    def __init__:
        self.data_stack = []
        self.min_stack = []
    def push(self, node):
        # write code here
        self.data_stack.append(node)
        if len(self.min_stack) == 0 or node < self.min_stack[-1]:
            self.min_stack.append(node)
        else:
            self.min_stack.append(self.min_stack[-1])
    def pop(self):
        # write code here
        if len(self.data_stack) > 0:
            self.data_stack.pop()
            self.min_stack.pop()
    def top(self):
        # write code here
        return self.data_stack[-1]
    def min(self):
        # write code here
        return self.min_stack[-1]

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

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

思路:建个空栈,按pushV顺序压入,当栈顶对倒popV的第一个出栈的数时,stack[-1]和popV[0]同时出栈。

# -*- coding:utf-8 -*-
class Solution:
    def IsPopOrder(self, pushV, popV):
        # write code here
        stack = []
        while popV:
            if stack and stack[-1] == popV[0]:
                stack.pop()
                popV.pop(0)
            elif pushV:
                stack.append(pushV.pop(0))
            else:
                return False
        return True

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

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

# -*- coding:utf-8 -*-
class Solution:
    def maxInWindows(self, num, size):
        # write code here
        if size <= 0:
            return []
        res = []
        for i in range(0, len(num)-size+1):
            res.append(max(num[i:i+size]))
        return res

四、树

面试题6:重建二叉树

题目描述:输入某二叉树的前序遍历和中序遍历的结果,请重建出该二叉树。假设输入的前序遍历和中序遍历的结果中都不含重复的数字。例如输入前序遍历序列{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:
    # 返回构造的TreeNode根节点
    def reConstructBinaryTree(self, pre, tin):
        # write code here
        if len(pre) == 0 :
            return None
        root = TreeNode(pre[0])
        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
#二叉树的前序遍历顺序是:先访问根节点,然后前序遍历左子树,再前序遍历右子树。
#中序遍历顺序是:中序遍历根节点的左子树,然后是访问根节点,最后中序遍历右子树。
#1、二叉树的前序遍历序列一定是该树的根节点
#2、中序遍历序列中根节点前面一定是该树的左子树,后面是该树的右子树
#从上面可知,题目中前序遍历的第一个节点{1}一定是这棵二叉树的根节点,根据中序遍历序列,
#可以发现中序遍历序列中节点{1}之前的{4,7,2}是这棵二叉树的左子树,
#{5,3,8,6}是这棵二叉树的右子树。然后,对于左子树,递归地把前序子序列{2,4,7}和中序子序列{4,7,2}看成新的前序遍历和中序遍历序列。
#此时,对于这两个序列,该子树的根节点是{2},该子树的左子树为{4,7}、右子树为空,如此递归下去(即把当前子树当做树,又根据上述步骤分析)。
#{5,3,8,6}这棵右子树的分析也是这样。

面试题18:树的子结构

题目描述:输入两棵二叉树A,B,判断B是不是A的子结构。(ps:我们约定空树不是任意一个树的子结构)

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def HasSubtree(self, pRoot1, pRoot2):
        # write code here
        result = False
        if pRoot1 !=None and pRoot2!=None:
            if pRoot1.val == pRoot2.val:
                result = self.isSame(pRoot1,pRoot2)
            if not result:
                result = self.HasSubtree(pRoot1.left,pRoot2)
            if not result:
                result = self.HasSubtree(pRoot1.right,pRoot2)
        return result
    def isSame(self,pRoot1,pRoot2):
        if pRoot2 ==None:
            return True
        if pRoot1 == None:
            return False
        if pRoot1.val !=pRoot2.val:
            return False
        return self.isSame(pRoot1.left,pRoot2.left) and self.isSame(pRoot1.right,pRoot2.right)

面试题19:二叉树镜像

题目描述:操作给定的二叉树,将其变换为源二叉树的镜像。

思路:递归,左右互换

输入描述:

二叉树的镜像定义:源二叉树 
    	    8
    	   /  \
    	  6   10
    	 / \  / \
    	5  7 9 11
    	镜像二叉树
    	    8
    	   /  \
    	  10   6
    	 / \  / \
    	11 9 7  5
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回镜像树的根节点
    def Mirror(self, root):
        # write code here
        if root == None:
            return
        elif root.left ==None and root.right == None:
            return
        else:
            temp = root.left
            root.left = root.right
            root.right = temp
            if root.left !=None:
                self.Mirror(root.left)
            if root.right !=None:
                self.Mirror(root.right)

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

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

思路:队列思想,每一层按顺序加入队列,每次加入节点的左右子树后将其弹出,最后一个一个弹出。

# -*- 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
        result = []
        queue = [] #加入了队列思想
        if root != None:
            queue.append(root) #append 不管什么类型都可以插入
        while len(queue) != 0:
            tempNode = queue.pop(0)
            result.append(tempNode.val)
            if tempNode.left != None:
                queue.append(tempNode.left)
            if tempNode.right != None:
                queue.append(tempNode.right)
        return result

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

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

# -*- coding:utf-8 -*-
class Solution:
    def VerifySquenceOfBST(self, sequence):#后续遍历,最后一个为根节点,大于左子树,小于右子树,递归
        # write code here
        if not sequence: #在python中 None, False, 空字符串"", 0, 空列表[], 空字典{}, 空元组()都相当于False 
            return False
        root = sequence[-1]
        left = []
        right = []
        i=0
        while sequence[i] < root:
            left.append(sequence[i])
            i += 1     #python不能用i++
        while sequence[i] > root:
            right.append(sequence[i])
            i += 1
        if sequence[i] != root:
            return False
        if len(left) > 0:
            self.VerifySquenceOfBST(left)    #调用自身要加self
        if len(right) > 0:
            self.VerifySquenceOfBST(right)
        return True

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

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

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回二维列表,内部每个列表表示找到的路径
    def FindPath(self, root, expectNumber):
        if not root:
            return []
        tmp = []
        if  not root.left and not root.right and root.val == expectNumber:
            return [[root.val]]
        else:
            left = self.FindPath(root.left,expectNumber-root.val)
            right = self.FindPath(root.right,expectNumber-root.val)
            for item in left+right:
                tmp.append([root.val]+item)
        return tmp

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

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

 思路:左子树上最右结点 -> root -> 右子树上的最左结点

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def __init__(self):
        self.last_node = None
    def Convert(self, pRootOfTree):
        # write code here
        self.convert_node(pRootOfTree)
        head_node = self.last_node
        while head_node is not None and head_node.left is not None:
            head_node = head_node.left
        return head_node
    def convert_node(self, node):
        if node is None:
            return
        cur_node = node
        if cur_node.left is not None:
            self.convert_node(cur_node.left)
        if self.last_node is not None:
            self.last_node.right = cur_node
            cur_node.left = self.last_node
        self.last_node = cur_node
        if cur_node.right is not None:
            self.convert_node(cur_node.right)

面试题39:二叉树的深度

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

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def __init__(self):
        self.deep = 0
    def TreeDepth(self, pRoot):
        # write code here
        if pRoot:
            n = 1
            self.depth(pRoot,n)
        return self.deep
    def depth(self,pRoot,n):
        if not pRoot.left and not pRoot.right:
            if n>self.deep:
                self.deep = n
        n +=1
        if pRoot.left:
            self.depth(pRoot.left,n)
        if pRoot.right:
            self.depth(pRoot.right,n)
# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def TreeDepth(self, pRoot):
        # write code here
        if pRoot == None:
            return 0
        if pRoot.left == None and pRoot.right==None:
            return 1
        return max(self.TreeDepth(pRoot.left),self.TreeDepth(pRoot.right))+1

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

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

思路:有以下三种情况: 
a. 如果该结点存在右子结点,那么该结点的下一个结点是右子结点树上最左子结点 
b. 如果该结点不存在右子结点,且它是它父结点的左子结点,那么该结点的下一个结点是它的父结点 
c. 如果该结点既不存在右子结点,且也不是它父结点的左子结点,则需要一路向祖先结点搜索,直到找到一个结点,该结点是其父亲结点的左子结点。如果这样的结点存在,那么该结点的父亲结点就是我们要找的下一个结点。

# -*- 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 pNode
        if pNode.right:
            p = pNode.right
            while p.left:
                p = p.left
            return p
        p = pNode.next
        while(p and p.right==pNode):#如果不是左节点就返回
            pNode = p
            p = p.next
        return p

面试题59:对称的二叉树

题目描述:请实现一个函数,用来判断一颗二叉树是不是对称的。注意,如果一个二叉树同此二叉树的镜像是同样的,定义其为对称的。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def isSymmetrical(self, pRoot):
        # write code here
        if not pRoot:
            return True
        return self.same(pRoot.left,pRoot.right)
    def same(self,p,q):
        if not p and not q:
            return True
        if p and q:
            return p.val == q.val and self.same(p.right,q.left)and self.same(p.left,q.right)
        else:
            return False

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

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

# -*- 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 pRoot==None:
            return []
        res = []
        Node = [pRoot]
        while Node:
            temp = []
            temp_N =[]
            for i in Node:
                temp.append(i.val)
                if i.left:
                    temp_N.append(i.left)
                if i.right:
                    temp_N.append(i.right)
            res.append(temp)
            Node = temp_N
        return res

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

题目描述:请实现一个函数按照之字形打印二叉树,即第一行按照从左到右的顺序打印,第二层按照从右至左的顺序打印,第三行按照从左到右的顺序打印,其他行以此类推。

思路:多行打印二叉树,加个偶数判断反转。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Print(self, pRoot):
        # write code here
        if pRoot==None:
            return []
        res = []
        Node = [pRoot]
        n = 1
        while Node:
            temp = []
            temp_N =[]
            for i in Node:
                temp.append(i.val)
                if i.left:
                    temp_N.append(i.left)
                if i.right:
                    temp_N.append(i.right)
            if n%2==0:
                temp.reverse()
            res.append(temp)
            Node = temp_N
            n +=1
        return res

面试题62:序列化二叉树

题目描述:请实现两个函数,分别用来序列化和反序列化二叉树

思路:将二叉树转为字符串,再从字符串转为二叉树

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def Serialize(self, root):
        # write code here
        def doit(node):
            if node:
                vals.append(str(node.val))
                doit(node.left)
                doit(node.right)
            else:
                vals.append('#')
        vals = []
        doit(root)
        return ' '.join(vals)

    def Deserialize(self, s):
        # write code here
        def doit():
            val = next(vals)
            if val == '#':
                return None
            node = TreeNode(int(val))
            node.left = doit()
            node.right = doit()
            return node
        vals = iter(s.split())
        return doit()

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

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

思路:二叉搜索树的中序遍历就是有序序列。

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    # 返回对应节点TreeNode
    def KthNode(self, pRoot, k):
        # write code here
        res = []
        node = pRoot
        while node:
            res.append(node)
            node= node.left
        cnt=0
        while res and cnt<k:
            node = res.pop()
            right = node.right
            while right:
                res.append(right)
                right = right.left
            cnt +=1
        if node and k== cnt:
            return node
        return None

牛客剑指题:平衡二叉树

题目描述:输入一棵二叉树,判断该二叉树是否是平衡二叉树。

思考:BST的定义为|height(lefttree)−height(righttree)|<=1,原问题拆分为计算树高度和判断高度差
 

# -*- coding:utf-8 -*-
# class TreeNode:
#     def __init__(self, x):
#         self.val = x
#         self.left = None
#         self.right = None
class Solution:
    def IsBalanced_Solution(self, pRoot):
        # write code here
        if not pRoot:
            return True
        return abs(self.depth(pRoot.left)-self.depth(pRoot.right))<=1
        
    def depth(self,root):
        if not root:
            return 0
        if not root.left and not root.right:
            return 1
        left = self.depth(root.left)
        right = self.depth(root.right)
        return max(left,right)+1

五、查找和排序

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

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

思想:二分查找(加了)

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        if not rotateArray:
            return 0
        left = 0
        right =len(rotateArray)-1
        while left<right:
            mid= (left+right)/2
            if rotateArray[mid]>rotateArray[right]:
                left = mid+1
            else:
                right = mid
        return rotateArray[right]

加了优化相同值的操作。 

# -*- coding:utf-8 -*-
class Solution:
    def minNumberInRotateArray(self, rotateArray):
        # write code here
        arr = rotateArray
        if len(arr) ==0:
            return 0
        p1 = 0
        p2 = len(arr) - 1
        mid = p1
        while arr[p1] >= arr[p2]:
            while arr[p1] == arr[p2]:
                p2 -= 1
            if (p2 - p1) == 1:
                return arr[p2]
            mid = (p1+p2)/2
            if arr[mid] > arr[p2]:
                p1 = mid
            else:
                p2 = mid
        return arr[p2]

六、动态规划

面试题9:斐波那契数列

思想:动态规划

# -*- coding:utf-8 -*-
class Solution:
    def Fibonacci(self, n):
        # write code here
        if n ==0:
            return 0
        if n==1 or n ==2:
            return 1
        dp = [1,1]
        for i in range(n-2):
            dp.append(dp[-1]+dp[-2])
        return dp[-1]

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

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

动态规划求解:(O(n))

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

面试题34:丑数

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

思路:设置2,3,5三个计数作为list索引,加上递归,(丑数都是丑数自己相乘)

# -*- coding:utf-8 -*-
class Solution:
    def GetUglyNumber_Solution(self, index):
        # write code here
        if (index <= 0):
            return 0
        uglyList = [1]
        indexTwo = 0
        indexThree = 0
        indexFive = 0
        for i in range(index-1):
            newUgly = min(uglyList[indexTwo]*2, uglyList[indexThree]*3, uglyList[indexFive]*5)
            uglyList.append(newUgly)
            if (newUgly % 2 == 0):
                indexTwo += 1
            if (newUgly % 3 == 0):
                indexThree += 1
            if (newUgly % 5 == 0):
                indexFive += 1
        return uglyList[-1]

面试题45:圆圈中最后剩下的数字(约瑟夫环问题)

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

思路:建立0到n-1数组,设立起始点游标。

# -*- coding:utf-8 -*-
class Solution:
    def LastRemaining_Solution(self, n, m):
        # write code here
        if n <1:
            return -1
        end = -1
        beg = 0
        cnt = [i for i in range(n)]
        while cnt:
            k = (beg+m-1)%n
            end = cnt.pop(k)
            n -=1
            beg = k
        return end

七、回朔法

面试题66:矩阵中的路径

题目描述:请设计一个函数,用来判断在一个矩阵中是否存在一条包含某字符串所有字符的路径。路径可以从矩阵中的任意一个格子开始,每一步可以在矩阵中向左,向右,向上,向下移动一个格子。如果一条路径经过了矩阵中的某一个格子,则之后不能再次进入这个格子。 例如 a b c e s f c s a d e e 这样的3 X 4 矩阵中包含一条字符串"bcced"的路径,但是矩阵中不包含"abcb"路径,因为字符串的第一个字符b占据了矩阵中的第一行第二个格子之后,路径不能再次进入该格子。
 

# -*- coding:utf-8 -*-
class Solution:
    def hasPath(self, matrix, rows, cols, path):
        if path =='':
            return True
        foot = [True]*rows*cols
        for r in range(rows):
            for c in range(cols):
                if matrix[r*cols+c] == path[0]:
                    foot[r*cols+c] = False
                    if self.dfs(foot,matrix,rows,cols,r,c,path[1:]):
                        return True
                    foot[r*cols+c]=True
        return False
    def dfs(self,foot,matrix,rows,cols,r,c,path):
        if path=='':
            return True
        dx = [-1,1,0,0]
        dy = [0,0,-1,1]
        for k in range(4):
            x = dx[k]+r
            y = dy[k]+c
            if x>=0and x<rows and y>=0 and y<cols and foot[x*cols+y] and matrix[x*cols+y]==path[0]:
                foot[x*cols+y]=False
                if self.dfs(foot,matrix,rows,cols,x,y,path[1:]):
                    return True
                foot[x*cols+y] = True
        return False
# -*- coding:utf-8 -*-
class Solution:
    def hasPath(self, matrix, rows, cols, path):
        assistMatrix = [True]*rows*cols
        for i in range(rows):
            for j in range(cols):
                if(self.hasPathAtAStartPoint(matrix,rows,cols, i, j, path, assistMatrix)):
                    return True
        return False
    def hasPathAtAStartPoint(self, matrix, rows, cols, i, j, path, assistMatrix):
        if not path:
            return True
        index = i*cols+j
        if i<0 or i>=rows or j<0 or j>=cols or matrix[index]!=path[0] or assistMatrix[index]==False:
            return False
        assistMatrix[index] = False
        if(self.hasPathAtAStartPoint(matrix,rows,cols,i+1,j,path[1:],assistMatrix) or
               self.hasPathAtAStartPoint(matrix,rows,cols,i-1,j,path[1:],assistMatrix) or
               self.hasPathAtAStartPoint(matrix,rows,cols,i,j-1,path[1:],assistMatrix) or
               self.hasPathAtAStartPoint(matrix,rows,cols,i,j+1,path[1:],assistMatrix)):
            return True
        assistMatrix[index] = True
        return False

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

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

# -*- coding:utf-8 -*-
class Solution:
    def movingCount(self, threshold, rows, cols):
        # write code here
        foot = set()
        def dfs(i,j):
            def judge(i,j):
                return sum(map(int,list(str(i))))+sum(map(int,list(str(j))))<=threshold
            if not judge(i,j) or (i,j)in foot:
                return
            foot.add((i,j))
            if i!=rows-1:
                dfs(i+1,j)
            if j!=cols-1:
                dfs(i,j+1)
        dfs(0,0)
        return len(foot)

八、细节实现题

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

题目描述:输入一个整数,输出该数二进制表示中1的个数。其中负数用补码表示。

输入的是二进制数

# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1(self, n):
        # write code here
        sum = 0
        for i in range(0,32):#int长32位
            sum += (n>>i & 1)#每一位与1比,>>为右移
        return sum

面试题11:数值的整数次方

题目描述:给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        # write code here
        result = 1.0
        flag = 0
        if base == 0.0:
            return 0
        if base == 1.0 or exponent == 0:
            return 1
        if exponent < 0:
            flag = 1
        for i in range(abs(exponent)):
            result *= base
        if flag == 1:
            result = 1/result
        return result

面试题20:顺时针打印矩阵

题目描述:输入一个矩阵,按照从外向里以顺时针的顺序依次打印出每一个数字,例如,如果输入如下4 X 4矩阵: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 则依次打印出数字1,2,3,4,8,12,16,15,14,13,9,5,6,7,11,10.

# -*- coding:utf-8 -*-
class Solution:
    # matrix类型为二维列表,需要返回列表
    def printMatrix(self, matrix):
        # write code here
        result=[]
        while matrix:
            result=result+matrix.pop(0)
            if not matrix:
                break
            matrix=self.turn(matrix)
        return result
    def turn(self, matrix):
        r=len(matrix)
        c=len(matrix[0])
        B=[]
        for i in range(c):
            A=[]
            for j in range(r):
                A.append(matrix[j][i])
            B.append(A)
        B.reverse()
        return B

面试题41:和为s的两个数字VS和为s的连续正数序列

和为s的两个数字:

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

输出描述:对应每个测试案例,输出两个数,小的先输出。

# -*- coding:utf-8 -*-
class Solution:
    def FindNumbersWithSum(self, array, tsum):
        # write code here
        if not array:
            return []
        res = []
        mul = 100000
        left = 0
        right = len(array)-1
        while array[left]*2<tsum:
            while array[right]>tsum-array[left]:
                right -=1
            if mul > array[left]*array[right] and array[right]==tsum-array[left]:
                res =[]
                res.append(array[left])
                res.append(array[right])
                mul = array[left]*array[right]
            left +=1
        return res

面试题43:n个骰子的点数

面试题44:扑克牌顺子

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

# -*- coding:utf-8 -*-
class Solution:
    def IsContinuous(self, numbers):
        # write code here
        if len(numbers)<1:
            return False
        new_nums = [i for i in numbers if i>0]
        max_n = max(numbers)
        min_n = min(new_nums)
        d = []
        if max_n -min_n <5:
            for i in numbers:
                if i != 0 and i in d:
                    return False
                else:
                    d.append(i)
        else:
            return False
        return True

面试题46:求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)

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

题目描述:写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

# -*- coding:utf-8 -*-
class Solution:
    def Add(self, num1, num2):
        # write code here
        if not num1:
            return num2
        if not num2:
            return num1
        while num2!=0:
            n1=num1^num2 #异或
            n2=(num1&num2)<<1 #按位与 进位没有
            num1=n1&0xFFFFFFFF
            num2=n2
        return num1 if num1>>31==0 else num1 - 4294967296

面试题64:数据流中的中位数(树)

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

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.data = []
    def Insert(self, num):
        # write code here
        self.data.append(num)
        self.data.sort()
    def GetMedian(self,data):
        # write code here
        length = len(self.data)
        if length%2 ==1:
            return self.data[length//2]
        else:
            return(self.data[length//2-1]+self.data[length//2])/2.0

猜你喜欢

转载自blog.csdn.net/qq_38358305/article/details/85858099