参考:
所有offer题目的LeetCode链接及python实现github Target offer题目:统计一个数字在排序数组中出现的次数。例如输入排序数组{1,2,3,3,3,3,4,5}和数字3,由于3在这个数组中出现了4次,因此输出4。
二分查找算法: GetFirstK用于寻找第一个k出现的位置;
每一次将数组中间的位置与k比较如果data[mid]==k,判断data[mid-1]与k的关系,再决定是否进一步查找如果data[mid-1]==k,继续在data[:mid]中二分查找k如果data[mid-1]!=k,则index=mid即为所求。GetLastK用于寻找最后一个k出现的位置;思路与上述类似。 GetFirstK和GetLastK都是用二分查找法在数组中查找一个合乎要求的数字,它们的时间复杂度都是O(logn),因此GetNumberOfK的总的时间复杂度也只有O(logn)。
# -*- coding:utf-8 -*- class Solution: def GetNumberOfK(self, data, k): if data == [] or not k: return 0 length = len(data) first = self.GetFirstK(data, k, 0, length-1) last = self.GetLastK(data, k, 0, length-1) return last-first+1 if first>-1 and last>-1 else 0 def GetFirstK(self, data, k, start, end): if start>end: return -1 mid = int((start + end)/2) if data[mid]<k: start = mid + 1 elif data[mid]==k: if mid>0 and data[mid-1]==k: end = mid - 1 else: return mid else: end = mid - 1 return self.GetFirstK(data, k, start, end) def GetLastK(self, data, k, start, end): if start>end: return -1 mid = int((start + end)/2) if data[mid]<k: start = mid+1 elif data[mid]==k: if mid<end and data[mid+1]==k: start = mid+1 else: return mid else: end = mid - 1 return self.GetLastK(data, k, start, end)题目一:输入一棵二叉树的根结点,求该树的深度。从根结点到叶结点依次经过的结点(含根、叶结点)形成树的一条路径,最长路径的长度为树的深度。
复杂度分析:
时间复杂度:我们每个结点只访问一次,因此时间复杂度为 O(N), 其中 N 是结点的数量。空间复杂度:在最糟糕的情况下,树是完全不平衡的,例如每个结点只剩下左子结点,递归将会被调用 N 次(树的高度),因此保持调用栈的存储将是 O(N)。但在最好的情况下(树是完全平衡的),树的高度将是 log(N)。因此,在这种情况下的空间复杂度将是 O(log(N))。 class Solution(object): def maxDepth(self, root): if root is None: return 0 else: leftD = self.maxDepth(root.left) rightD = self.maxDepth(root.right) return max(leftD, rightD)+1非递归版本: 使用栈存储已遍历节点和其对应的深度。 复杂度分析:
时间复杂度:O(N)。空间复杂度:O(N)。 class Solution(object): def maxDepth(self, root): stack = [] if root is not None: stack.append((1, root)) else: return 0 depth = 0 while stack: # d, node = stack.pop() # depth = max(depth, d) # if node.left: # stack.append((d+1, node.left)) # if node.right: # stack.append((d+1, node.right)) #### 减少了判断条件,更快, current_depth, root = stack.pop() if root is not None: # 当本次弹出的节点非空时,才更新最大深度 depth = max(depth, current_depth) stack.append((current_depth + 1, root.left)) stack.append((current_depth + 1, root.right)) return depth输入一棵二叉树的根结点,判断该树是不是平衡二叉树。如果某二叉树中任意结点的左右子树的深度相差不超过1,那么它就是一棵平衡二叉树。
递归版本的实现:
class Solution(object): def maxDepth(self, root): if root is None: return 0 else: leftD = self.maxDepth(root.left) rightD = self.maxDepth(root.right) return max(leftD, rightD)+1 def isBalanced(self, root): if root is None: return True if abs(self.maxDepth(root.left)-self.maxDepth(root.right))>1: return False else: return self.isBalanced(root.left) and self.isBalanced(root.right)题目:一个整型数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。要求时间复杂度是O(n),空间复杂度是O(1)。
**题目一:**输入一个递增排序的数组和一个数字s,在数组中查找两个数,使得它们的和正好是s。如果有多对数字的和等于s,输出任意一对即可。
题目二:输入一个正数s,打印出所有和为s的连续正数序列(至少含有两个数)。例如输入15,由于1+2+3+4+5=4+5+6=7+8=15,所以结果打印出3个连续序列1~5、4~6和7~8。
定义两个序列指针,small与big,small指向较小数字即序列的开头,big指向较大数字即序列的结尾;
如果当前nums[small:big]求和大于target_sum,则增大small即丢弃较小的值;如果当前nums[small:big]求和小于target_sum,则增大big即增加较大的值; # -*- coding:utf-8 -*- class Solution: def FindContinuousSequence(self, tsum): if tsum <= 2: return [] small, big = 1, 2 cur_sum = small + big ans = [] # 定义中间数字 middle = (tsum + 1) >> 1 # while big < tsum: # 终止条件 while small < middle: if cur_sum == tsum: ans.append(list(range(small,big+1))) cur_sum -= small small += 1 elif cur_sum < tsum: big += 1 cur_sum += big else: cur_sum -= small small += 1 return ans**题目一:**输入一个英文句子,翻转句子中单词的顺序,但单词内字符的顺序不变。为简单起见,标点符号和普通字母一样处理。例如输入字符串"I am a student. “,则输出"student. a am I”。
先使用s.split(' ') 将字符串分成多个单词,再使用 ' '.join(l[::-1]) 将分开的单词列表,按照从后到前的顺序连接起来,即可得到所求。
# 直接利用Python的语句进行字符串的翻转 def ReverseSentence2(self, s): l = s.split(' ') return ' '.join(l[::-1])**题目二:**字符串的左旋转操作是把字符串前面的若干个字符转移到字符串的尾部。请定义一个函数实现字符串左旋转操作的功能。比如输入字符串"abcdefg"和数字2,该函数将返回左旋转2位得到的结果"cdefgab"。
将前半段和后半段分别反转后,交换两段的位置即可。
首先需要写一个reverse函数,把任何输入的字符串完全翻转。然后根据题目中给出的左旋转字符串的个数n,用全字符串长度length减去旋转字符串个数n,求得对于新的字符串应该在哪一位进行旋转,然后分别旋转前[:length-n]子串和[length-n:]子串,重新拼接两个子串即可。 # -*- coding:utf-8 -*- class Solution: def LeftRotateString(self, s, n): if len(s) <= 0 or len(s) < n or n < 0: return '' strList= list(s) # 翻转字符串 self.Reverse(strList) length = len(s) pivot = length - n frontList = self.Reverse(strList[:pivot]) behindList = self.Reverse(strList[pivot:]) resultStr = ''.join(frontList) + ''.join(behindList) return resultStr def Reverse(self, alist): if alist == None or len(alist) <= 0: return '' startIndex = 0 endIndex = len(alist) - 1 # 从数组的两端开始,依次交换数组元素,直到比较的对象位于中间为止 while startIndex < endIndex: alist[startIndex], alist[endIndex] = alist[endIndex], alist[startIndex] startIndex += 1 endIndex -= 1 return alist