数据结构之字符串

一.规则的判断

is用来判断是否是同一个对象,is相等代表两个对象的id相同

==用来判断两个对象的值是否相等

1.1判断字符串是否符合整数规则

#判断是否为整数
def isNum(str1):
    try:
        num=int(str1)
        print(num)
        return isinstance(num,int)
    except:
        return False

1.2判断字符串是否符合浮点数规则

#判断是否为浮点数
def isfloat(str1):
    try:
        num=float(str1)
        print(num)
        return isinstance(num,float)
    except:
        return False

1.3判断字符串是否符合回文字符串规则

def isPalindrome(str1):
    str2=str1[::-1]#这是一个反转对象,那就不要用reversed了
    return str2==str1
print(isPalindrome('121'))

1.4判断是否为素数

#判断是为素数
def isPrime(str):
    num=int(str)
    for i in range(2,num//2):
        if num%i==0:
            return False
    return True

二.数字运算

2.1大数运算借助数组

2.2使用字符串进行大整数相关运算

#! /usr/bin/python
# -*- coding: utf-8 -*-
import sys
 
def get_10(c):
	return ord(c)-ord('0')
 
def add_one_bit(n1,n2,n3=0):
	a = get_10(n1)
	b = get_10(n2)
	
	sum = a+b+n3
	
	yu = sum%10
	shang = (sum-yu)/10
	
	return str(yu),shang
 
def add(n1,n2):
	
	l1=len(n1)
	l2=len(n2)
	
	s1 = n1
	s2 = n2
	if l1>l2:
		s1 = n2
		s2 = n1
	
	l1 = len(s1)
	l2 = len(s2)
	
	sum = []	
	shang = 0
	for i in range(l1):
		c,shang = add_one_bit(s1[l1-1-i],s2[l2-1-i],shang)
		sum.append(c)
 
	for i in range(l1,l2):
		c,shang = add_one_bit('0',s2[l2-1-i],shang)
		sum.append(c)
	if shang > 0:
		sum.append(str(shang))
		
	for i in range(len(sum)/2):
		tmp = sum[i]
		sum[i]=sum[len(sum)-1-i]
		sum[len(sum)-1-i] = tmp
	return sum	
 
def mul(n1,n2):
	l = len(n1)
	sum=[]
	for i in range(l):
		v = get_10(n1[i])
		if v>0:
			sum_tmp = n2
			for j in range(l-1-i):
				sum_tmp += "0"
			add_v = sum_tmp
			for j in range(1,v):
				sum_tmp = add(sum_tmp,add_v)
			if i==0:
				sum = sum_tmp
			else:
				sum = add(sum,sum_tmp)
	return sum
 
def sub_one_bit(n1,n2,n3):
	a = get_10(n1)
	b = get_10(n2)
	
	sub = a-b-n3
	
	jie=0
	while sub<0:
		jie += 1
		sub += 10
	return str(sub),jie
 
def large(n1,n2):
	if len(n1)>len(n2):
		return True
	elif len(n1)<len(n2):
		return False
	else:
		for i in range(len(n1)):
			if ord(n1[i])>=ord(n2[i]):
				return True
		return False
		
def sub(n1,n2):
	
	s1 = n1
	s2 = n2
	flag=False
	if not large(n1,n2):
		s1 = n2 
		s2 = n1
		flag = True
 
	l1 = len(s1)
	l2 = len(s2)
	
	sub = []	
	jie = 0
	for i in range(l2):
 
			c,jie = sub_one_bit(s1[l1-1-i],s2[l2-1-i],jie)
			sub.append(c)
			
	has_jie = 0		
	if jie>0:
		c,jie = sub_one_bit(n1[l2-1-l1],str(jie),0)
		sub.append(c)
		has_jie=1
	
	while has_jie<l1-l2:
		sub.append(s1[l1-l2-1-has_jie])
		has_jie += 1
		
	if flag:
		sub.append('-')
		
	for i in range(len(sub)/2):
		tmp = sub[i]
		sub[i]=sub[len(sub)-1-i]
		sub[len(sub)-1-i] = tmp
	return sub	
 
def div(n1,n2):
	return "Todo..."
	
def calc(n1,op,n2):
	if op == '+':
		return add(n1,n2)
	elif op == '-':
		return sub(n1,n2)
	elif op == '*':
		return mul(n1,n2)
	elif op == '/':
		return div(n1,n2)
	else:
		return "unsupported operation"
	
if __name__ == '__main__':
	if len(sys.argv)<4:
		print "Usage: bigdata_calc.py  num1 {+,-,*,/} num2"
	else:
		res = calc(sys.argv[1],sys.argv[2],sys.argv[3])
		
		print "%50s\n%s\n%50s\n=\n%50s" %(sys.argv[1],sys.argv[2],sys.argv[3],"".join(res))
		
		

三.字符的统计

3.1使用hash来统计字符,其实还有很多变形

可以使用set把相同的元素去除然后遍历统计set里面的元素

#1使用map进行统计
def count_char(str1):
    count={}
    for i in str1:
        count[i]=str1.count(i)
    return count

#2不使用count方法的话

def count_char1(str1):
    count={}
    for i in str1:
        if i not in count:
            count[i]=1
        else:
            count[i]+=1
    return count
#

四.括号匹配问题

在这里需要使用栈来解决这个问题,首先我们把各种括号的开始端和闭合端分开,作为出入栈的判定依据,然后将相应的括号对应起来以便判断。接下来我们对没一行进行括号的出入栈检验,只有满足条件的最后才能被判定为所有括号都闭合。

# 存储左括号和又括号
open_brackets = '([{<'
close_brackets = ')]}>'
# 映射左右括号便于出栈判断
brackets_map = {')': '(', ']': '[', '}': '{', '>': '<'}

# 对于没一行数据,进行如下判定若括号为左括号,加入栈,若括号为右括号,判断是否跟栈尾括号对应,若对应,弹出栈尾元素,若所有括号均正确闭合,则最后栈为空。
for row in rows:
    stack = []
    label = True
    for char in row:
        if char in open_brackets:
            stack.append(char)
        elif char in close_brackets:
            if len(stack) < 1:
                label = False
                break
            elif brackets_map[char] == stack[-1]:
                stack.pop()
            else:
                label = False
                break
        else:
            continue
    if stack != []:
        label = False
    print label,

五.动态规划问题

5.1最长公共子串LCS(The longest Common Substring)  两个字符串

LCS问题就是求两个字符串最长公共子串的问题。解法就是用一个矩阵来记录两个字符串中所有位置的两个字符之间的匹配情况,若是匹配则为1,否则为0。然后求出对角线最长的1的序列,其对应的位置就是最长匹配子串的位置。

def find_lcsubstr(s1, s2): 
	m=[[0 for i in range(len(s2)+1)]  for j in range(len(s1)+1)]  #生成0矩阵,为方便后续计算,比字符串长度多了一列
	mmax=0   #最长匹配的长度
	p=0  #最长匹配对应在s1中的最后一位
	for i in range(len(s1)):
		for j in range(len(s2)):
			if s1[i]==s2[j]:
				m[i+1][j+1]=m[i][j]+1
				if m[i+1][j+1]>mmax:
					mmax=m[i+1][j+1]
					p=i+1
	return s1[p-mmax:p],mmax   #返回最长子串及其长度
 
print find_lcsubstr('abcdfg','abdfg')

5.2最长公共子序列LCS(The Longest Common Subsequence)   两个字符串

def lengthOfLCS(s1,s2):
    n1=len(s1)
    n2=len(s2)
    dp=[[0 for _ in range(len(s2)+1)]for _ in range(len(s1)+1)]
    for i in range(1,n1+1):
        for j in range(1,n2+1):
            if(s1[i-1]==s2[j-1]):
                dp[i][j]=dp[i-1][j-1]+1
            else:
                dp[i][j]=max(dp[i-1][j],dp[i][j-1])
    return dp[n1][n2]


print(lengthOfLCS('abcdef','abcef'))

 子串要求字符必须是连续的,但是子序列就不是这样。最长公共子序列是一个十分实用的问题,它可以描述两段文字之间的“相似度”,即它们的雷同程度,从而能够用来辨别抄袭。对一段文字进行修改之后,计算改动前后文字的最长公共子序列,将除此子序列外的部分提取出来,这种方法判断修改的部分,往往十分准确。
        解法就是用动态回归的思想,一个矩阵记录两个字符串中匹配情况,若是匹配则为左上方的值加1,否则为左方和上方的最大值。一个矩阵记录转移方向,然后根据转移方向,回溯找到最长子序列。

import numpy

def find_lcseque(s1, s2): 
	 # 生成字符串长度加1的0矩阵,m用来保存对应位置匹配的结果
	m = [ [ 0 for x in range(len(s2)+1) ] for y in range(len(s1)+1) ] 
	# d用来记录转移方向
	d = [ [ None for x in range(len(s2)+1) ] for y in range(len(s1)+1) ] 
 
	for p1 in range(len(s1)): 
		for p2 in range(len(s2)): 
			if s1[p1] == s2[p2]:            #字符匹配成功,则该位置的值为左上方的值加1
				m[p1+1][p2+1] = m[p1][p2]+1
				d[p1+1][p2+1] = 'ok'          
			elif m[p1+1][p2] > m[p1][p2+1]:  #左值大于上值,则该位置的值为左值,并标记回溯时的方向
				m[p1+1][p2+1] = m[p1+1][p2] 
				d[p1+1][p2+1] = 'left'          
			else:                           #上值大于左值,则该位置的值为上值,并标记方向up
				m[p1+1][p2+1] = m[p1][p2+1]   
				d[p1+1][p2+1] = 'up'         
	(p1, p2) = (len(s1), len(s2)) 
	print numpy.array(d)
	s = [] 
	while m[p1][p2]:    #不为None时
		c = d[p1][p2]
		if c == 'ok':   #匹配成功,插入该字符,并向左上角找下一个
			s.append(s1[p1-1])
			p1-=1
			p2-=1 
		if c =='left':  #根据标记,向左找下一个
			p2 -= 1
		if c == 'up':   #根据标记,向上找下一个
			p1 -= 1
	s.reverse() 
	return ''.join(s) 
 
print find_lcseque('abdfg','abcdfg')

5.3最长回文子串 LPS(Longest Palindromic Substring)

可以参考一下这个博客这篇文章

对于字符串问题,常用的一种思路是动态规划的方式。主要思路来源于对于思路一的优化。在思路一中,是将所有的字符串进行了组合,再判断。一种可以想到的简化思路时,在组合字符串的过程中,动态处理,只保留可以组成回文字符串的,而不必将每种组合都进行处理。从而节省时间,也节省了最后判断是否为回文子串的过程。
引入DP[i][j],表示第i个字符至第j个字符组成的子串是否为回文子串。
 

class Solution:
    def longestPalindrome(self, s):
        """
        :type s: str
        :rtype: str
        """
        if not s:
            return ""
        n = len(s)
        # 动态规划算法
        dp = [[1 for _ in range(n)] for _ in range(n)]
        sta = 0
        end = 0
        max_l = 1
        for i in range(n - 1, -1 , -1):
            dp[i][i] = 1
            for j in range(i + 1, n):
                dp[i][j] = (s[i] == s[j]) & dp[i + 1][j - 1]
                # 保留最大值,基于上述遍历规则,此处保留的为最右端的最长子串;如果求最左端的,将下述的<变为<=即可
                if dp[i][j] and max_l < j - i + 1:
                    max_l = j - i + 1
                    sta = i                

        return s[sta:max_l + sta]

5.4最长回文子序列LPS(Longest Palindromic Subsequence)

class Solution:
    def longestPalindromeSubseq(self, s):
        # write your code here
        if s == s[::-1]:
            return len(s)
        dp = [[1 for i in range(len(s))] for j in range(len(s))]
        for j in (range(len(s))):
            for i in range(j - 1, -1, -1):
                if s[i] == s[j]:
                    dp[i][j] = 2 + dp[i + 1][j - 1] if i + 1 <= j - 1 else 2
                else:
                    dp[i][j] = max(dp[i + 1][j], dp[i][j - 1])
        return dp[0][len(s) - 1]
s=Solution()
print(s.longestPalindromeSubseq('abca'))#aba

六.搜索问题

宽度优先搜索

深度优先搜索

比如:给定两个被打乱的字符串A和B,每次只能交换一次字符,如何把A变成B,打印这种变换轨迹

七.排列问题

7.1全排列

思路分析
可以采用递归的形式

从集合中依次选出每一个元素,作为排列的第一个元素,然后对剩余的元素进行全排列,如此递归处理,
从而得到所有元素的全排列。以对字符串abc进行全排列为例,我们可以这么做:以abc为例:
固定a,求后面bc的排列:abc,acb,求好后,a和b交换,得到bac
固定b,求后面ac的排列:bac,bca,求好后,c放到第一位置,得到cba
固定c,求后面ba的排列:cba,cab

把s[0]固定在位置0上,[1,n-1]位置的数字全排(递归) 
把s[1]固定在位置0上(把s[1]和s[0]交换),[1,n-1]位置的数字全排(递归) 
…… 
如果第i个数字在前面出现过,则跳过 
…… 
把s[n-1]固定在位置0上(把s[n-1]和s[0]交换),[1,n-1]位置的数字全排(递归)

def perm(s=''):#有点像完全背包问题,即元素的迭代放在最里面
    # 这里是递归函数的出口,为什么呢,因为这里表示:一个长度为1的字符串,它的排列组合就是它自己。
    if len(s)<=1:
        return [s]
    sl=[] #保存字符串的所有可能排列组合
    for i in range(len(s)):  #这个循环,对应 解题思路1)确定字符串的第一个字母是谁,有n种可能(n为字符串s的长度
        for j in perm(s[0:i]+s[i+1:]): #这个循环,对应 解题思路2)进入递归,s[0:i]+s[i+1:]的意思就是把s中的s[i]给去掉
            sl.append(s[i]+j) # 对应 解题思路2)问题就从“返回字符串中的字母排列组合” **变成了** “返回 第一个字母+除去第一个字母外的字符串的排列组合”
    return sl
 
def main():
    perm_nums=perm('abc') # 有可能存在字母相同的情况
    no_repeat_nums = list(set(perm_nums)) # 去重,挺牛的,这个代码
    print('perm_nums', len(perm_nums), perm_nums)
    print('no_repeat_nums', len(no_repeat_nums), no_repeat_nums)
    pass
 
if __name__ == '__main__':
    main()

7.2全组合

基本思路:求全组合,则假设原有元素n个,则最终组合结果是2^n个。如果有重复的元素用set去重就行。

原因是: 用位操作方法:假设元素原本有:a,b,c三个,则1表示取该元素,0表示不取。故去a则是001,取ab则是011.所以一共三位,每个位上有两个选择0,1.所以是2^{n}个结果。

这些结果的位图值都是0,1,2…2n。所以可以类似全真表一样,从值0到值2^{n}依次输出结果:即:

000,001,010,011,100,101,110,111

对应输出组合结果为:

空,a, b ,ab,c,ac,bc,abc.

这个输出顺序刚好跟数字0~2^{n}结果递增顺序一样,取法的二进制数其实就是从0到2^{n-1}的十进制数

def combination_k(s,k):#['ab', 'ac', 'bc']   abc
    if k==0:#元素的迭代也在最里面的循环中
        return ['']
    subletters=[]
    for i in range(len(s)):
        for letter in combination_k(s[i+1:],k-1):
            subletters+=[s[i]+letter]
    return subletters
def combination(s):
    com_list=[]
    for i in range(1,len(s)+1):
        com_list+=combination_k(s,i)
    return com_list

print(combination('abc'))

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值