剑指offer编程题,一周刷完

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

解题思路:从头到尾遍历一次,如果碰到偶数,则从该偶数位置往后查找,查找到第一个奇数,将该奇数值记录下来,pop掉之后,再将该奇数插入到偶数之前的位置;

class Solution:
    def reOrderArray(self, array):
        # write code here
        left = 0
        n = len(array)
        while left < n:
            if array[left]%2!=0:
                left += 1
            else:
                for i in range(left+1,n):
                    if array[i]%2!=0:
                        tmp = array[i]
                        array.insert(left,tmp)
                        array.pop(i+1)
                        break
                left += 1
        return array

2.镜像二叉树:

class Solution:
    # 返回镜像树的根节点
    def Mirror(self, root):
        # write code here
        if not root:
            return root
        node = root.left
        root.left = root.right
        root.right = node
        self.Mirror(root.left)
        self.Mirror(root.right)
        return root

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

解题思路:二叉搜索树有一个性质,根节点的值要大于左子树所有值,小于右子树所有值。因为后序遍历最后一个值为子树的根结点,那么先得到数组最后一个值a,然后再找到第一个比a大的数,在a之前的为左子树,在a之后的为右子树,再观察右子树中是否所有值都大于a,如果不满足则return False。递归

代码:

class Solution:
    def VerifySquenceOfBST(self, sequence):
        # write code here
        s = sequence
        if s == None or len(s) == 0:
            return False
        n = len(s)
        root = s[n-1]
        for i in range(n):
            if s[i] > root:
                break
        for j in range(i,n):
            if s[j] < root:
                return False
        left = True
        if i > 0:
            left = self.VerifySquenceOfBST(s[0:i])
        right = True
        if i < n-1:
            right = self.VerifySquenceOfBST(s[i:n-1])
        return left and right

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

解题思路:递归,回溯,找到所有组合

# -*- coding:utf-8 -*-
class Solution:
    def dfs(self,res,n,ss,temp,book):
        if len(temp) == n and temp not in res:
            res += [temp]
            return 
        for i in range(n):
            if book[i] == 0:
                book[i] = 1
                self.dfs(res,n,ss,temp+ss[i],book)
                book[i] = 0
            
    def Permutation(self, ss):
        # write code here
        res = []
        n = len(ss)
        if n == 0 or n==1:
            return ss
        book = [0]*n
        self.dfs(res,n,ss,'',book)
        return res

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

思路:创建两个指针,一个指向头一个指向尾。res只记录满足两数之和等于tsum的并且乘机和(muti)当前最小的两个数。

class Solution:
    def FindNumbersWithSum(self, array, tsum):
        # write code here
        low = 0
        high = len(array)-1
        res = []
        muti = 10000
        while low

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

思路:创建一个旋转函数(逆序函数),如’abc’→’cba’,然后对字符串按k分成两块,分别调用旋转函数,再对整体调用一次旋转函数。涉及字符串换位旋转的都可以用这种方法。

# -*- coding:utf-8 -*-
class Solution:
    def change(self,s):
	return s[::-1]
	
    def LeftRotateString(self, s, n):
        # write code here
        s1 = self.change(s[0:n])
        s2 = self.change(s[n:])
        res = self.change(s1+s2)
        return res

7.例如,“student. a am I”。这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

思路:与上题类似,对每个单词旋转,再对整体旋转,注意空格

# -*- coding:utf-8 -*-
class Solution:
    def change(self,s):
        return s[::-1]
    def ReverseSentence(self, s):
        # write code here
        s = s.split(' ')
        s_reverse = ''
        for x in s:
            s_reverse += self.change(x) + ' '  #结尾会多个空格
        return self.change(s_reverse)[1:] #结尾的空格反转到了头部,所以从1位置之后打印

8.上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。

思路:排序后,统计0的个数,如果0的个数>=4,则直接返回True,否则,遍历一次剔除0的数组,前后差距如果==1,则continue;如果 != 1 ,那么在该i位置插入numbers[i-1]+1的值,并使num_0-1,如果当num_0等于一的时候还出现前后差距>1的情况,直接返回False。

# -*- coding:utf-8 -*-
class Solution:
    def IsContinuous(self, numbers):
        # write code here
        if not numbers:
            return False
        numbers = sorted(numbers)
        n = len(numbers)
        num_0 = numbers.count(0)
        numbers = numbers[num_0:]
        if num_0 >= 4:
            return True
        for i in range(1,n):
            if numbers[i] - numbers[i-1] != 1 and num_0 == 0:
                return False
            elif numbers[i] - numbers[i-1] != 1 and num_0 != 0:
                numbers.insert(i,numbers[i-1]+1)
                num_0 -= 1
        return True

9.一个整型数组里除了两个数字之外,其他的数字都出现了偶数次。请写程序找出这两个只出现一次的数字。
思路:hash,遍历一遍存入字典,然后对字典value值升序排序,取出前两个。

# -*- coding:utf-8 -*-
class Solution:
    # 返回[a,b] 其中ab是出现一次的两个数字
    def FindNumsAppearOnce(self, array):
        # write code here
#        res = []
#        for x in array:
#            if array.count(x) == 1:
#                res.append(str(x))
#        return res
        dic = {}
        for i in range(len(array)):
            if array[i] not in dic.keys():
                dic[array[i]] = 1 
            else:
                dic[array[i]] += 1
        dic = sorted(dic.items(),key = lambda x:x[1],reverse = False)
        return [dic[0][0],dic[1][0]]

对于一个有序数组arr,再给定一个整数num,请在arr中找到num这个数出现的最左边的位置。

给定一个数组arr及它的大小n,同时给定num。请返回所求位置。若该元素在数组中未出现,请返回-1。
测试样例:

[1,2,3,3,4],5,3

返回:2

# -*- coding:utf-8 -*-

class LeftMostAppearance:
    def findPos(self, arr, n, num):
        # write code here
        res = -1
        left, right = 0, n-1
        while left <= right:
            mid = left+(right-left)/2
            if arr[mid] > num:
                right = mid - 1
                continue
            if arr[mid] < num:
                left = mid + 1
                continue
            if arr[mid] == num:
                res = mid
                right = mid - 1
        return res

对于一个有序循环数组arr,返回arr中的最小值。有序循环数组是指,有序数组左边任意长度的部分放到右边去,右边的部分拿到左边来。比如数组[1,2,3,3,4],是有序循环数组,[4,1,2,3,3]也是。

给定数组arr及它的大小n,请返回最小值。
测试样例:
[4,1,2,3,3],5
返回:1

# -*- coding:utf-8 -*-
class MinValue:
    def getMin(self, arr, n):
        low=0
        high=n-1
        # arr[low] >= arr[high]
        while low<=high:#和寻找元素最左出现的位置”这部分是一样的
            mid=low+(high-low)/2
            if arr[low]>arr[mid]:  #左一半
                high=mid
            elif arr[mid]>arr[high]:  #右一半
                low=mid+1
            else:  #arr[low]==arr[mid]==arr[right] 特殊情况 只能挨个遍历,之前两个if最后到了一个元素的也会到达这里进行最终的判断
                cur=arr[low]
                while low arr[low+1]:
                        cur=arr[low+1]
                    low=low+1
                return cur

12.动态规划割绳子:
给你一根长度为n的绳子,请把绳子剪成m段 (m和n都是整数,n>1并且m>1)每段绳子的长度记为k[0],k[1],…,k[m].请问k[0]k[1]…*k[m]可能的最大乘积是多少?
例如,当绳子的长度为8时,我们把它剪成长度分别为2,3,3的三段,此时得到的最大乘积是18.

def cut(n):
    if n==1:
        return 0
    if n==2:
        return 1
    if n==3:
        return 2
    dp = [0]*(n+1)
    dp[0] = 0
    dp[1] = 1
    dp[2] = 2
    dp[3] = 3
    for i in range(4,n+1):
        max0 = -1
        for j in range(1,i//2+1):
            p = dp[j]*dp[i-j]
            if max0

你可能感兴趣的:(剑指offer)