剑指offer:数组,栈,队列(python)

数组:数组给定空间但可以不给定确定的值,元组给定空间和具体的值,列表即可以不给定空间也可以不给定确定的值。
栈:栈在Python中其实也是一个列表,先进后出
队列:先进先出就是队列。

题目:
在一个二维数组中(每个一维数组的长度相同),每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
因为它是一个递增数列所以可以先比较最后那一列判断数字所在的行数,再在该行进行比较,减少算法的时间复杂度。

def Find(self,target,array):
	i=0
	while i < len(array) and j >= 0:
		if array[i][j] == target:
			return True
		elif array[i][j] > target:
			j -= 1
		else:
		i += 1
	return False

题目:
用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。
先要创建两个栈,一个接收一个输出。接受栈输入节点,然后再pop给输出栈

def __init__(self):
	self.acceptStack=[]
	self.outputStack=[]
def push(self,node):
	self.acceptStack.append(node)

def pop(self):
	if self.outputStack ==[]
		while self.acceptStack:
			self.outputStack.append(self,acceptStack.pop())
	if self.outputStack != []:
		return self.outputStack.pop()
	else:
		return None

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

可以用二分查找法来解决
时间复杂度为log(n),因为反过来就是2的n次方。
#101=5 => 10=2
mid=(left+right)>>1(右移就等于向下取整)
因为这是一个翻转数列,只有一部分翻转,一个断崖。所以如果右边的值小于中间的值,则说明最小值一定在右边,因为出现了断崖。右边的值大于中间的值,说明还是顺序递增,最小值在左边。

def minNumberInRotateArray(self,rotateArray):
	if not rotateArray:
		return 0
	
	left = 0
	right = len(rotateArray) - 1
	while left <= right:
		mid=(left + right) >>1
		if rotateArray[mid] < rotateArray[mid-1]:
		return rotateArray[mid]
		elif rotateArray[mid] < rotateArray[right]:
		right=mid-1
		else:
		left=mid + 1
	return 0

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

定义双指针i,j分列数组的左右两端,循环执行,i找偶数,j找奇数,将偶数nums[i]和奇数nums[j]交换位置,这样指针i左边就都是奇数,指针j右边都是偶数。

def exchange(self,nums):
	i=0
	j=len(nums) - 1
	while i < j:
		while i < j and num[i]%2==1:
			i += 1
		while i <j and num[i]%2==0:
			j -= 1
		nums[i],nums[j] = nums[j],nums[i]
	return nums

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

栈中的pop操作是弹出栈顶元素,而栈中的top操作是获得栈顶元素。
生成一个新的列表存放最小的元素。一直存放最小的元素,如果遇到比它大的就不要了,然后把自己最小的元素放进去保证两个列表长度一样。

def __init__(self):
	self.stack = []
	self.minValue = []

def push(self,node):
	self.stack.append(node)
	if self.minValue:
		if self.minValue[-1] > node:
			self.minValue.append(node)
		else:
		self.minValue.append(self.minValue[-1])
	else:
		self.minValue.append(node)
			
def pop(self):
	if self.stack == []:
		return None
	self.minValue.pop()
	return self.stack.pop()

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

def min(self):
	if self.minValue == []:
		return None
	return self.minValue[-1]

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

可以先弹出后再压入元素即中间位置可能先弹出然后再继续压入操作。

#首先需要有一个栈,即列表
#按照pushv的方式压入栈,弹出的时候是需要循环判断是否需要弹出
#判断是否需要弹出的时机,刚刚压入过后就判断
#判断需要弹出的情况调节,压入栈的顶部和弹出栈的顶部数据是否相等
def IsPopOrder(self,pushV,popV):
	if pushV == [] or len(pushV) != len(popV):
		return None
	stack=[]
	index=0
	for item in pushV:
		stack.append(item)
		#可以继续弹出之前压栈进来的元素
		while stack and stack[-1]==popV[index]:
			stack.pop()
			index += 1
	#如果循环完栈为空则成功
	if stack == []:
		return True
	else:
		return False

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

先取第一个数为最大值,然后与后面那个数相加得到tmp,如果tmp比后面加的数大则继续循环下去,如果tmp比后面那个数小则记录上一个加的和为最大值并且从下个数开始为第一个数继续循环,最后比较各个数的大小。(观察数列,当前面相加数的和小于下一个数的时候,则记录前面的和并下一个数为新的起点)

def FindGreatestSumOfSubArray(self,array):
	maxNum = None
	tmpNum = 0
	for i in array:
		if maxNum == None:
			maxNum = i
		if tmpNum + i < i:
			tmpNum = i
		else:
			tmpNum += i
		if maxNum < tmpNum:
			maxNum = tmpNum
	return maxNum

题目:
地上有一个m行和n列的方格。一个机器人从坐标0,0的格子开始移动,每一次只能向左,右,上,下四个方向移动一格,但是不能进入行坐标和列坐标的数位之和大于k的格子。 例如,当k为18时,机器人能够进入方格(35,37),因为3+5+3+7 = 18。但是,它不能进入方格(35,38),因为3+5+3+8 = 19。请问该机器人能够达到多少个格子?
1.判断m,n的个位数之和同K大小的比较。
先创建一个res变量来存储和,然后先除以10取余数,然后再除以10向下取整
2.更新坐标
创建一个数组[(1,0),(-1,0),(0,1),(0.-1)],依次来遍历它们,更新坐标
3.判断更新后坐标有没有越界
更新后的坐标不能小于0,或者大于最大坐标
4.递归终止条件

def movingCount(self,m,n,k):
	if k < 0:
	return 0 
	moves = [(1,0),(-1,0),(0,1),(0,-1)]
	visited = [[0]*n for _ in range(m)]

	def validate_boundary(x,y,xMax,yMax):
		if x < 0 or x >= xMax:
			return False
		if y < 0 or y >=yMax:
			return False
		return True

	def validate_k(x,y,k):
		res = 0
		while x > 0:
			res += x%10
			x = x // 10
		while y > 0:
			res += y%10
			y = y // 10
		return res > k
	
	def dfs(m,n,x,y,k):
		visited[x][y] = 1
		count = 1
		for i in range(len(moves)):
			newX = x + moves[i][0]
			newY = y + moves[i][1]
			if not validate_boundary(newX.newY,m,n):
				continue
			if visited[newX][newY] == 1:
				continue
			if validate_k(newX,newY,k):
				continue
			count += dfs(m,n,newX,newY,k)
		return count
	
	return dfs(m,n,0,0,k)

题目:
给一个没有重复数字的序列,返回其所有可能的全排列。

用递归的方法解决,设定一个和序列长度一样的初始状态。每一次访问下一个节点就让这个状态为1,直到访问到数组长度,输出此时的值。然后回溯上去,让这个状态又变为0.
剑指offer:数组,栈,队列(python)_第1张图片

def permute(self,nums):
	result_all = []
	visited = [0]*len(nums)

	def dfs(n,nums,result):
		if n == len(nums):
			return result_all.append(result[:])
		for i in range(len(nums)):
			if visited[i] == 1:
				continue
			result.append(nums[i])
			visited[i] = 1
			dfs(n+1,nums,result)
			result.pop()
			visited[i] = 0
		
	def(0,nums,[])
	return result_all

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

题目:
给定一个数组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];)(构建乘积数组)

构建的B数组,B[i]的意义是A数组不包括i位置的所有乘积。所以可以构建一个函数去计算A数组不包括i位置的所有乘积。

   def multiply(self, A):
        # write code here
        Alen = len(A)
        B = [1]*Alen
        def Aplus(A,i):
            result = 1
            for j in range(i):
                result *= A[j]
            for p in range(i+1,len(A)):
                result *= A[p]
            return result
        for i in range(Alen):
            B[i] = Aplus(A, i)
        return B

题目:

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

创建一个字典,把字典里没有的元素添加到字典里去,如果发现字典里有的元素则赋值给dulication并返回True

def duplicate(self, numbers, duplication):
        # write code here
        dict = {}
        for i in numbers:
            if i not in dict:
                dict[i] = 0
            else:
                duplication[0] = i 
                return True
        return False

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

先用二分法搜索定位到这个数字,然后以这个数字为中心,前后找与这个数字相同的数字并记录。

    def GetNumberOfK(self, data, k):
        # write code here
        if len(data) < 1:
            return 0
        mid = len(data)//2
        if data[mid] == k:
            begin,end = mid,mid
            for i in range(mid,-1,-1):
                if data[i] == k:
                    begin -= 1
            for j in range(mid+1,len(data)):
                if data[j] == k:
                    end += 1
            return end - begin
        elif data[mid] > k:
            self.GetNumberOfK(data[:mid], k)
        else:
            self.GetNumberOfK(data[mid+1:], k)
        return 0

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

用try和except异常值的方法判断这个字符串是否表示数值。异常时Python对象,表示一个错误。用try/except可以捕捉异常,当开始一个try语句后,python就在当前程序的上下文作标记,try会先执行下面的语句,如果发生异常就执行except中的子句,如果没有发生异常就执行else后面的子句。

    def isNumeric(self, s):
        # write code here
        try:
            value = float(s)
            return True
        except ValueError:
            return False

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

用ord()把字符串转化为ASCII码,然后减48(0是48)就可以得到数字。

    def StrToInt(self, s):
        # write code here
        if not s:
            return 0
        flag = 1
        num = 0
        p = 1
        if s[0] == '-' or s[0] == '+':
            if s[0] == '-':
                flag = -1
            if s == '+' or s == '-':
                return 0
            s = s[1:]
        for i in range(len(s)-1,-1,-1):
            if '9' >= s[i] >= '0':
                num += (ord(s[i])-48) * p 
                p = p*10
                res = num * flag
            else:
                return 0
        return res

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

采用滑动窗口的策略去解决这个问题,采用一个动态窗口,如果窗口里的值等于结果,则添加进数组。如果滑动窗口里的值小于目标值,则大的那个指针加1。如果滑动窗口的值大于目标值,则小的那个指针加1。

def FindContinuousSequence(self, tsum):
        # write code here
        if tsum < 3:
            return []
        res = []
        low_p = 1
        high_p = 2
        while high_p > low_p:
            if tsum == sum(range(low_p,high_p+1)):
                tmp = []
                for i in range(low_p,high_p+1):
                    tmp.append(i)
                res.append(tmp)
                high_p += 1
            elif tsum > sum(range(low_p,high_p+1)):
                high_p += 1
            else:
                low_p += 1
        return res

你可能感兴趣的:(剑指offer,数据结构)