记录一下最近碰到的几个常见编程题

1.字符串的全排列

思路:

以abc为例,取出b,分别在a的前后插入b,可以得到ab,ba,然后再ab的每一个位置插入c,可以得到cab,acb,abc,对ba采取同样的操作。最终可以得到全排列的6种结果。代码如下:

# -*- coding:utf-8 -*-
class Solution:
    def Permutation(self, ss):
        # write code here
        ans=[]
        SrcStr=[ss[0]]
        for i in range(1,len(ss)):
            DstStr = [] #用来保存每次插入单个字符后的字符串list
            for j in range(len(SrcStr)):
                DstStr.extend(self.insertChar(SrcStr[j],ss[i]))  #将生成的全排列好的子串保存,下一次全排列使用
            SrcStr=DstStr
        ans = sorted(list(set(SrcStr)))  # 去掉重复的字符串后按字典序排序
        return ans

    def insertChar(self,string,char):   #将一个字符插入一个字符串中
        ans=[]
        for i in range(len(string)+1):
            ans.append(string[:i]+char+string[i:])
        return ans

2.两链表的公共结点

方法一:将两链表的结点入栈,找第一个不相同的结点,返回该结点的下一个结点即可。代码如下:

#coding:utf-8
def findCommonNode(head1,head2):
    st1=[]  #两个栈用来存放两链表的结点
    st2=[]
    while head1:
        st1.append(head1)
        head1=head1.next
    while head2:
        st2.append(head2)
        head2=head2.next

    while st1 and st2:
        top1=st1.pop()
        top2=st2.pop()
        if top1!=top2:  
            return top1.next

方法二:计算两个链表的长度差diff,让长链表先走diff个结点,然后两链表同时后移,第一个相同的结点即为公共结点。代码如下:

class Solution:
    def FindFirstCommonNode(self, pHead1, pHead2):
        len1,len2=0,0
        head1=pHead1
        head2=pHead2
        while pHead1:
            pHead1=pHead1.next
            len1+=1
        while pHead2:
            pHead2=pHead2.next
            len2+=1
        if len1<len2:
            head1,head2=head2,head1
        diff=abs(len1-len2)
        fast,slow=head1,head2
        while diff:
            fast=fast.next
            diff-=1
        while fast:
            if fast==slow:
                return slow
            fast=fast.next
            slow=slow.next
        return None    #没有公共节点,返回空

3.找到链表环的入口

剑指offer上的思路:

第一步,判断链表是否存在环。利用快慢指针,快指针每次走两个结点,慢指针每次走一个结点。若存在环,则两指针会在环内相遇。

第二步:确定环中结点的数目。由于相遇时快慢指针均在环中,现在让慢指针不动,快指针每次移动一个结点,直到两指针相遇,记录下快指针走过的结点的数目LoopNumber。

第三步:让p1,p2两个指针均指向头节点,p1先走LoopNumber个结点,然后两结点同时移动,当两结点相遇时即为环的入口处。

代码如下:

class Solution:
    def EntryNodeOfLoop(self, pHead):
        # write code here
        slow=fast=pHead
        while fast.next:
            fast=fast.next.next
            slow=slow.next
            if not fast:
                return None
            if fast==slow:
                break
        slow=pHead
        while slow and fast and slow!=fast:
            slow=slow.next
            fast=fast.next
        return fast

4.两个排序数组的中位数

给定两个大小为 m 和 n 的有序数组 nums1 和 nums2 

请找出这两个有序数组的中位数。要求算法的时间复杂度为 O(log (m+n)) 。

示例 1:

nums1 = [1, 3]
nums2 = [2]

中位数是 2.0

示例 2:

nums1 = [1, 2]
nums2 = [3, 4]

中位数是 (2 + 3)/2 = 2.5

利用归并排序的思想,将前一半的数存到新数组中,返回中位数即可。代码如下:

#coding:utf-8
def findMedian(nums1,nums2):
    medianList=[]   #保存中位数及中位数之前的数
    len1,len2=len(nums1),len(nums2)
    ListLength=(len1+len2)//2+1 #新数组的长度
    while ListLength:
        #每次将两数组中值最小的数添加到新数组中
        if nums1 and nums2:
            medianList.append(nums1.pop(0)) if nums1[0]<nums2[0] else medianList.append(nums2.pop(0))
        else:
            if nums1:
                medianList.append(nums1.pop(0))
            elif nums2:
                medianList.append(nums2.pop(0))
        ListLength-=1
    if (len1+len2)%2==1:
        return float(medianList[-1])
    else:
        return (float(medianList[-1])+medianList[-2])/2

5. rand5()生成rand7()

def rand7():
    res=8
    while res>7:
        res=5*(rand5()-1)+rand5()
    return res

改进写法:

def rand7():
    res=22
    while res>21:
        res=5*(rand5()-1)+rand5()
    return res%7+1

6.

给定一个无重复元素的数组 candidates 和一个目标数 target ,找出 candidates 中所有可以使数字和为 target 的组合。

candidates 中的数字可以无限制重复被选取。

说明:

  • 所有数字(包括 target)都是正整数。
  • 解集不能包含重复的组合。 

示例 

输入: candidates = [2,3,6,7], target = 7,所求解集为:[[7],[2,2,3]]
class Solution(object):
    def combinationSum(self, candidates, target):
        self.ans=[]
        candidates.sort()
        self.dfs(candidates,target,[],0)
        return self.ans
        
    def dfs(self,nums,target,sublst,last):
        if target==0:
            self.ans.append(sublst[:])
        if target<nums[0]:
            return
        for n in nums:
            if target<n:
                return
            if n<last:
                continue
            sublst.append(n)
            self.dfs(nums,target-n,sublst,n)
            sublst.pop()

7.KMP

#coding:utf-8 
#朴素匹配
def naive_match(s, p):
    m = len(s); n = len(p)
    for i in range(m-n+1):#起始指针i
        if s[i:i+n] == p:
            return True
    return False

#KMP
def kmp(s, p):
    m = len(s); n = len(p)
    cur = 0#起始指针cur
    table = partial_table(p)
    while cur<=m-n:
        for i in range(n):
            if s[i+cur]!=p[i]:
                cur += max(i - table[i-1], 1)#有了部分匹配表,我们不只是单纯的1位1位往右移,可以一次移动多位
                break
        else:
            return True
    return False
 
#部分匹配表
def partial_table(p):
    prefix=[]   #前缀集合
    postfix=[]  #后缀集合
    res=[0]
    for i in range(1,len(p)):
        prefix.append(p[:i])
        postfix=[p[j:i+1] for j in range(1,i+1)]
        intersection=[v for v in prefix if v in postfix]    #前缀集合和后缀集合的交集不一定只有一个元素
        maxlen=max(map(len,intersection)) if intersection else 0    #保存交集中长度最大的元素的长度
        res.append(maxlen)
    return res



print naive_match("BBC ABCDAB ABCDABCDABDE", "ABCDABD")
print partial_table("ABCDABD")
print kmp("BBC ABCDAB ABCDABCDABDE", "ABCDABD")

 

 

 

 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值