经典递归问题:0,1背包问题 kmp 用遗传算法来解背包问题,hash表,位图法搜索,最长公共子序列...

0,1背包问题:我写笔记风格就是想到哪里写哪里,有很多是旧的也没删除,代码内部可能有很多重复的东西,但是保证能运行出最后效果
'''学点高大上的遗传算法'''
'''首先是Np问题的定义:
npc:多项式复杂程度的非确定性问题,
首先是基本的0-1背包问题。 '''
'''给定N个物品和一个背包,物品i的质量是Wi,其价值位Vi,背包的容量为C,问应该
如何选择装入背包的物品,使得转入背包的物品的总价值为最大? 
在选择物品的时候,对每种物品i只有两种选择,即装入背包或不装入背包。不能将
物品i装入多次,也不能只装入物品的一部分。因此,该问题被称为0-1背包问题。'''
'''如果穷举就有2^n个需要测试,很大'''
'''其实,0-1背包是DP的一个经典实例,可以用动态规划求解。

DP求解过程可以这样理解:对于前i件物品,背包剩余容量为j时,所取得的最大价值(此时称为状态3)只依赖于两个状态。

状态1:前i-1件物品,背包剩余容量为j。在该状态下,只要不选第i个物品,就可以转换到状态3。

状态2:前i-1件物品,背包剩余容量为j-w[i]。在该状态下,选第i个物品,也可以转换到状态3。

因为,这里要求最大价值,所以只要从状态1和状态2中选择最大价值较大的一个即可。'''
'''算法复杂度基本是O(N)'''
bag_weight=95800
stone=[]
#stone[i] means (weight, value)
stone.append((100,100))
stone.append((200,105))
stone.append((300.9,400))
stone.append((400.56,900.56))
stone.append((500,1000.598))

stone=sorted(stone) #default sorted by first column of stone ,very convinient
print (stone)
#creat a two-dim list,row i means using the first i stone
#column j means the bag_weight
'''只想到用递归来写,递推还不知道怎么弄'''
#网上说法是不能用递推来写,因为不知道重量的变化,变化太多,不知道要存多少才行.
#下面写出打印的最好的石头组合的index,现在是这个问题比较难!!!!!!!!!!!因为递归问题很难区分这次和上次
#来的index,反复访问很难弄,下面用函数的双返回值来处理这个问题,但是空间开销也是相当大.目测O(N^2)
zuhe=[0]*len(stone)
def value(num,tmpbag_weight):
      if num==1:
            if tmpbag_weight>=stone[0][0]:
                                      
                                      return 100
            else:
                  return 0
      firstcase=0
      if tmpbag_weight>=stone[num-1][0]:
            
          firstcase=0
          firstcase+=stone[num-1][1]
          firstcase+=value(num-1,tmpbag_weight-stone[num-1][0])

      secondcase=value(num-1,tmpbag_weight)
      
      return max(firstcase,secondcase)
print (value(len(stone),bag_weight))
print (zuhe)





###########
print ('妈的我居然写出来了55555555')

def value(num,tmpbag_weight):
      if num==1:
            if tmpbag_weight>=stone[0][0]:
                                      zuhe=[0]
                                      return stone[0][1],zuhe
            else:
                  return 0,[]
      firstcase=0
      if tmpbag_weight>=stone[num-1][0]:
            
          firstcase=0
          firstcase+=stone[num-1][1]
          a,b=value(num-1,tmpbag_weight-stone[num-1][0])
          firstcase+=a
      c,d=value(num-1,tmpbag_weight)
      secondcase=c
      if firstcase>secondcase:
        b.append(num-1)
        return max(firstcase,secondcase),b
      else:
        return max(firstcase,secondcase),d
print (value(len(stone),bag_weight))
View Code

 2.kmp

'''匹配字符串bf算法'''
def search(a,b):#if a in b :return first index else:return None
      for i in range(len(b)):
       #直接b切片就行了,记住几个常用计数长度更方便
       #range[i,i+len(a)] 标示角标从i一直到i+len(a)-1一共len(a)个元素
       #切片也类似b[i:i+len(a)]也表示len(a)个元素
            if i+len(a)-1==len(b):
                  return None
            if b[i:i+len(a)]==a:
                  return i
print (search('ffg','qfgsdfgsdffg'))
'''下面是KMP算法--看毛片算法'''
'''把复杂度从O(mn)下降到O(m+n)'''
#这个写的很详细,KMP还是要从例子的图形里面分析出来.注意next[0]=-1,是一种人为的规定,为了识别,你定义-2也一样.
'''http://www.cnblogs.com/yjiyjige/p/3263858.html'''





'''先学一下c语言里面的++'''
'''首先要说:a++ = a 和 ++a = a + 1 并不是两个合法的语句。这两个式子
是说 a++ 的值就是 a 的值,而 ++a 的值等于 a+1。 注意:我说的是++a和a++的值。

你的这两个表达式不合法!
在C语言中前置和后置自增运算符返回的结果是右值,不能放在等号左侧。
顺便提一下:在C++中,前置自增的结果是左值,可以放在等号左侧。


1.int main() {
  int b=0;
  int a=3;
  ++a=b;
  a+=1;
  return 0;
}   答案a是1

2.int main() {
  int b=0;
  int a=3;
  b=++a;
  a+=1;
  return 0;
}  答案a是5

3.int main() {
  int b=0;
  int a=3;
  a++=b;
  a+=1;
  return 0;
}  第四句话不合法,无法运行'''#c++什么鬼

#要先写获取next数组这个函数
#先用暴力方法实现next数组的求法.

'''理解:
待处理数组,也就是我们要配出的字符串,比如一个长串里面找一个短的串,那么待处理数组就是这个短的设为p
'''
'''p=abcaab  那么我们的next数组就是-1,0,0,0,1,1
next[i]的招法是符合下面条件的最大的index
1.next[i]<i
2.设next[i]=k,有p[:k]=p[i-k:i]'''
'''http://www.cnblogs.com/tangzhengyue/p/4315393.html
这个地址里面有一个长的面试题:说的是给一个字符串求他的next数组,下面我来尝试这个next方法
上面写的对不对.
他给的P:
abcaacbbcbadaabcacbd
答案:-10001100000101123400他给的答案做进一步优化了,不止考虑上面3个条件,
也考虑了当前位置,所以把一些项优化到-1了'''
def next_rough(a):
      shuchu=[]
      shuchu.append(-1)
      for i in range(1,len(a)):
            for j in range(i-1,-1,-1):
                  #这个j循环测试看哪个是k
                  if a[:j]==a[i-j:i]:
                        shuchu.append(j)
                        break
      return shuchu
print (next_rough('abcaacbbcbadaabcacbd'))
#成功得到了上面的next数组
#显然这个方法太慢了,应该是O(N^2)的.当然当N非常小的时候还是很快的.
#正确的方法有点复杂的,利用的是动态规划来处理这个next数组
#先用next数组进行最后的kmp出结果把.
def kmp(a,b):
      i=0
      j=0
      nextshuzu=next_rough(a)
      while 1:
            if j==len(a):
                  return i-len(a) #开始index
            if i>len(b)-1:
                  return None
            if b[i]==a[j]:
                  i+=1
                  j+=1
            else:
                  if nextshuzu[j]==-1:
                        i+=1
                        j=0
                  else:
                        j=nextshuzu[j]
                        
print (kmp('43aa','3ht54543aa43a4a6'))
print (kmp('1','23'))
#效果还不错.

#最后应该用动态规划来写next数组了.
#http://www.cnblogs.com/yjiyjige/p/3263858.html里面写的真的很详细.
#像这种情况,如果你从代码上看应该是这一句:k = next[k];为什么是这样子?你看下面应该就明白了。
#上面这句话在博客里面的说没说完,其实k=next[k]这个吊代码,把2次匹配next给用一个代码写明白了,确实叼.
#下面只需要改成python实现即可.
def next_true(a):
      shuchu=[]
      shuchu.append(-1)
      j=0
      k=-1
      while (j<len(a)-1):
            if (k==-1 or a[j]==a[k]):
                  j+=1
                  k+=1
                  shuchu.append(k)
            else:
                  k=shuchu[k]
      return shuchu
print (next_true('abcaacbbcbadaabcacbd'))
#从结果看完美解决了.
















                  
View Code

 3.遗传算法解背包问题,一写一个晚上没了,干了200行,我理解是这东西就是个类似随机查找的东西,本质很low,但是实用性强,有点像神经网落,普世通用性强.描述性强

缺陷当然是慢!!写写还挺有意思,复习了很多的random函数的使用.这东西不推荐手写大型的,因为有库直接能调用遗传算法.当然现在还有遗传加神经网络的综合体,有点

强.

'''学点高大上的遗传算法'''
import random
print (random.randint(10, 11))#python 的这个随机正数是包含收尾的,这点要注意.很特俗
'''首先是Np问题的定义:
npc:多项式复杂程度的非确定性问题,
首先是基本的0-1背包问题。 '''
'''给定N个物品和一个背包,物品i的质量是Wi,其价值位Vi,背包的容量为C,问应该
如何选择装入背包的物品,使得转入背包的物品的总价值为最大? 
在选择物品的时候,对每种物品i只有两种选择,即装入背包或不装入背包。不能将
物品i装入多次,也不能只装入物品的一部分。因此,该问题被称为0-1背包问题。'''
'''如果穷举就有2^n个需要测试,很大'''
'''其实,0-1背包是DP的一个经典实例,可以用动态规划求解。

DP求解过程可以这样理解:对于前i件物品,背包剩余容量为j时,所取得的最大价值(此时称为状态3)只依赖于两个状态。

状态1:前i-1件物品,背包剩余容量为j。在该状态下,只要不选第i个物品,就可以转换到状态3。

状态2:前i-1件物品,背包剩余容量为j-w[i]。在该状态下,选第i个物品,也可以转换到状态3。

因为,这里要求最大价值,所以只要从状态1和状态2中选择最大价值较大的一个即可。'''
'''算法复杂度基本是O(N)'''
bag_weight=1200
stone=[]
stone.append((100,100))
stone.append((200,105))
stone.append((300,400))
stone.append((400,900))
stone.append((500,1000))



# 举个例子,使用遗传算法解决“0-1背包问题”的思路:0-1背包的解可以编码为一串0-1
#字符串(0:不取,1:取) ;首先,随机产生M个0-1字符串,然后评价这些0-1字
#符串作为0-1背包问题的解的优劣;然后,随机选择一些字符串通过交叉、突变等操作产生下
#一代的M个字符串,而且#较优的解被选中的概率要比较高。这样经过G代的进化后就可能会产生
#出0-1背包问题的一个“近似最优解”。

#遗传算法的问题
'''1.编码:需要将问题的解编码成字符串的形式才能使用遗传算法。最简单的一种编码方式是二进制编码
,即将问题的解编码成二进制位数组的形式。例如,问题的解是整数,
那么可以将其编码成二进制位数组的形式。将0-1字符串作为0-1背包问题的解就属于二进制编码。
2.遗传算法有3个最基本的操作:选择,交叉,变异。
下面处理第一个选择问题:
1.问题:有n个物体,他们被选择的概率是p1,...pn.和为1.
求一个函数每次根据这个概率随机出一个物体.
这个用random(0,1)函数随便写很简单--他们管这个叫轮盘赌算法下面我定义他是rws(Roulette
Wheel Selection )函数.
第二个问题交叉:
http://www.cnblogs.com/heaad/archive/2010/12/23/1914725.html
这里面只写了原理没有实现,最后用一个库包来实现的,我打算还是自己手写一次
根据他里面的思想,手动实现遗传算法.
原理写下来:
交叉(Crossover):2条染色体交换部分基因,来构造下一代的2条新的染色体。例如:
变异(Mutation):在繁殖过程,新产生的染色体中的基因会以一定的概率出错,称为
变异。变异发生的概率记为Pm 。例如:

'''
import random


a=[0.1,0.2,0.3,0.4]#物体被选择的概率,这个概率就是这个物体的效果函数
def rws(a):
      #生成累加概率
      
      b=random.random()
      for i in range(len(a)):
           j=(sum(a[:i+1]))
           if b<j:
            return i #return the index of selection one in a
 #效果还可以
import numpy as np
def crossover_and_mutation(a,b,mutation_rate):#代表一次进化,a,b都是二进制的数
      #我认为把a,b都转化成2进制然后转化为字符串就容易变化多了.所以初始化的时候就弄成2进制的

   #直接字符串操作,很方便.
   #生成2个需要变化的开始index和结尾index
   kaishi=random.randint(0,len(stone))
   jieshu=random.randint(0,len(stone))
   start=min(kaishi,jieshu)
   end=max(kaishi,jieshu)
   #开始交换
   a=a[:start]+b[start:end+1]+a[end+1:]#切片的角标非常贴心,如果角标超了自动返回空list.
   b=b[:start]+a[start:end+1]+b[end+1:]

   #继续开始突变mutation
   #生成一个突变的index,每一次突变基因的个数=mutation_rate*len(stone)
##   np.random.randint(low[, high, size]) 返回随机的整数,位于半开区间 [low, high)。
   #下面这行就是闭区间的随机取一个
   #再加一行,让mutation_rate变动来模拟是否突变:
   mutation_rate=random.random()*mutation_rate
   mutation_index=np.random.random_integers(0,len(stone)-1,int(mutation_rate*len(stone)))
   mutation_index=set(mutation_index)

   #开始突变:
   after_mut_a=''
   
   for i in range(len(a)):
         if i in mutation_index and a[i]=='1':
               after_mut_a+='0'
               continue #这地方要加入continue
         if i in mutation_index and a[i]=='0':
               after_mut_a+='1'
               continue
         else:
                after_mut_a+=a[i]
#b完全类似               
   mutation_index=np.random.random_integers(0,len(stone)-1,int(mutation_rate*len(stone)))
   #开始突变:
   after_mut_b=''
   
   for i in range(len(b)):
         if i in mutation_index and b[i]=='1':
               after_mut_b+='0'
               continue
         if i in mutation_index and b[i]=='0':
               after_mut_b+='1'
               continue
         else:
                after_mut_b+=b[i]
   return after_mut_a,after_mut_b

print (crossover_and_mutation('01001','01101',0.5))
print ('上面是一次进化的结果')




   
c=2**len(stone)-1
print (c)
def init(n):#初始化n这么多个生物
      creature=[]
      for i in range(n):
           t=random.randint(0, c)
           t=bin(t)
           t=t[2:]
           
           q=len(stone)-len(t)
           t='0'*q+t
           creature.append(t)
      return creature





#下面写一个二进制的价值函数,也就是这个二进制是否符合背包的规则,和他的价值
def value_of_pick(a):
      weight=0
      for i in range(len(a)):
            weight+=int(a[i])*stone[i][0]
      value=0
      for i in range(len(a)):
            value+=int(a[i])*stone[i][1]
      if weight>bag_weight:
            value/=4
      return value
def all_value(a_all):
      b=[] 

      for i in range(len(a_all)):
            b.append(value_of_pick(a_all[i]))
      return b

#下面开始跑遗传
a_all=init(10)
all_the_value=all_value(a_all)

he=sum(all_the_value)
for i in range(len(all_the_value)):
     all_the_value[i]/=he
#上步是归一化
#先选2个,然后进化
for i in range(50):#进化50次
  first=rws(all_the_value)
  second=rws(all_the_value)
  #这里假设自己和自己也能繁殖..
  a,b=crossover_and_mutation(a_all[first],a_all[second],0.3)
  a_all.append(a)
  a_all.append(b)
  all_the_value=all_value(a_all)

  he=sum(all_the_value)
  for i in range(len(all_the_value)):
      all_the_value[i]/=he
jieguo=(all_value(a_all))
print (max(jieguo))
#下面我们找到这个答案的具体的pick方法.
index_final=np.argmax(np.array(jieguo))
print (a_all[index_final])
print ('总结取法',end=''),print(a_all[index_final],end=''),print('价值',end=''),print(max(jieguo))
View Code

 4.hash表数据结构的实现

'''Hash表'''
'''核心就是hash函数的设计:
特点:在构造Hash函数时应尽量考虑关键字的分布特点来设计函数
使得Hash地址随机均匀地分布在整个地址空间当中。
1)直接定址法
  取关键字或者关键字的某个线性函数为Hash地址,即address(key)=a*key+b;如
知道学生的学号从2NoneNoneNone开始,最大为4NoneNoneNone,则可以将address(key)=key-2NoneNoneNone作为Hash地址。
2)平方取中法
  对关键字进行平方运算,然后取结果的中间几位作为Hash地址。假如有以下关
键字序列{421,423,436},平方之后的结果为{177241,178929,19NoneNone96},那么可以取{72,89,NoneNone}
作为Hash地址。
3)折叠法
  将关键字拆分成几部分,然后将这几部分组合在一起,以特定的方式进行转化形
成Hash地址。假如知道图书的ISBN号为89None3-241-23,可以将address(key)=89+None3+24+12+3作为Hash地址。
4)除留取余法
  如果知道Hash表的最大长度为m,可以取不大于m的最大质数p,然后对关键字进
行取余运算,address(key)=key%p。
  在这里p的选取非常关键,p选择的好的话,能够最大程度地减少冲突,p一般取不
大于m的最大质数。'''
'''5.Hash表的优缺点

  Hash表存在的优点显而易见,能够在常数级的时间复杂度上进行查找,并且插入数据
和删除数据比较容易。但是它也有某些缺点,比如不支持排序,一般比用线性表存储需要更
多的空间,并且记录的关键字不能重复。'''

a=[1,2,3,4,51,2,3,4,51,2,3,4,551,2,3,4,551,2,3,4,551,2,3,4,551,2,3,4,551,2,3,4,5]
class hashnode():
    def __init__(self,data):
     self.data=data;
     self.next=None

#下面写的是取mod的方法:一般除数取比len(表)小的最大素数。
#获取除数
import math
b=len(a)

if b==1:
    c=1
if b==2:
    c=2
if b==3:
    c=2

if b>3:

 def sushu(b):
  for i in range(b-1,2,-1):
     k=None
     
     for j in range(2,int(math.sqrt(i))+2):
         
         if i%j==None:
             break
             
         if j==int(math.sqrt(i))+1:
          k=1
  
     if k==1:
     
      return i
 c=sushu(b)#除数就是c
 #下面建立hash 表

 hashlist=[None]*c
 print (c)
 for i in range(len(a)):
     hashtmp=a[i]%c
     
     if hashlist[hashtmp]==None:
         hashlist[hashtmp]=hashnode(a[i])
     else:
        head=hashlist[hashtmp]
        while 1:
            
            if  head.next!=None:
                head=head.next
                continue
            else:
                head.next=hashnode(a[i])
                break
print (hashlist[2].next.next.data)
print (66666666)
#然后添加元素。直接复制上面的部分代码即可。都类似的。
def add(one):
 
 hashtmp=one%c
 
 if hashlist[hashtmp]==None:
     hashlist[hashtmp]=hashnode(one)
 else:
    head=hashlist[hashtmp]
    while 1:
        
        if  head.next!=None:
            head=head.next
            continue
        else:
            head.next=hashnode(one)
            break
add(11)
print (hashlist[0])

def delme(two):
 hashtmp=two%c
 
 if hashlist[hashtmp]==None:
     pass
 else:
    head=hashlist[hashtmp]
    while 1:
        
       if head.data==two:
           head.data=None
       if head.next!=None:
           head=head.next
           continue
       if head.next==None:
           break
delme(11)
print (hashlist[0])


#下面写查询,这个写的是全部查询,找到所有等于a的hashlist里面的元素的个数
def search(a):
    hashtmp=a%c
    b=0
    head=hashlist[hashtmp]
    while 1:
        if head.data==a:
            b+=1
        if head.next!=None:
            head=head.next
            continue
        if head.next==None:
            break
    return b
print (search(2))
#曾,删,改,查,建立,都有了
#下面写个修改。这个修改貌似很多数据结构不写这个方法。
def change(two,three):
 hashtmp=two%c
 
 if hashlist[hashtmp]==None:
     pass
 else:
    head=hashlist[hashtmp]
    while 1:
        
       if head.data==two:
           head.data=three
       if head.next!=None:
           head=head.next
           continue
       if head.next==None:
           break
change(2,3)
#因为把所有的2都改成了3所以下面的搜索会变成0
print (search(2))
print (search(3))  #其实这个改有很大问题,因为他没有改变hash的东西,是否需要重新建立改完东西的hash索引,这个
#是需要讨论的,但是本质都不难。这里面写的change只是把原来放2的地方数据都改成了3,。所以你找3还是找不到新修改
#的那8个3,还是最开始的那8个3.ps:出事数据里面是8个2 ,8个3的。
View Code

 5.位图法的实现

##位图大发好神奇

''' 1、给40亿个不重复的unsigned int的整数,没排过序的,然后再给一个数,如何
快速判断这个数是否在那40亿个数当中
  首先,将这40亿个数字存储到bitmap中,然后对于给出的数,判断是否
在bitmap中即可。

位图和位向量
所谓位向量法,其实就是使用一串二进制串来表示一组数字集合的方法。
比如,我们知道一个byte = 8bit,表示成二进制串就是:00000000.这里我们就得到
了八个可用的符号位,假如我们作如下规定
1)符号位为1的,说明存在于我们的数字集合中
2)符号位为0的,说明不在我们的数字集合中
那么,二进制串01010101,表示的数字集合为{1,3,5,7} (注意,计算机通常都是从0
开始计算的)
。。
我们知道位图的数据结构就是一个数组,而位图的操作(算法)基本依赖于下面3个元操作

set_bit(char x, int n); //将x的第n位置1,可以通过x |= (1 << n)来实现

clr_bit(char x, int n); //将x的第n位清0,可以通过x &= ~(1 << n)来实现

get_bit(char x, int n); //取出x的第n位的值,可以通过(x >> n) & 1来实现
'''

#下面用python手动实现。python所有的数本质都是2进制,可以直接用位运算。
#举一个例子,一个集合里面有数字1,3,5 那么我们用二进制010101 来表示。也就是第一个0表示没有数字0,然后1表示
#有数字1,0表示没有2, 1表示有数字3, 下一位0又表示没有数字4,最后一个1表示有数字5.
#这样用一个数字就表示了函数数字1,3,5这个信息了。问题是python的二进制是从右边开始算的。所以我们再反转一下
#用101010来表示1,3,5存在这个信息就行了。
b=[1,3,4,5,19,8]
def init(a):#首先建立第一个数字存在的信息
    return 1<<a
chushihua=init(b[0])

for i in range(len(b)):
    if i>=1:
        chushihua=chushihua |(1<<b[i])
print (bin(chushihua))#效果不错
#下面是查询一个数字是否在chushihua里面
def search(chushihua,a):
    return (chushihua>>a) &1
print (search(chushihua,8))
print (search(chushihua,19))
print (search(chushihua,9))
print (search(chushihua,20))
#成功解决这个问题。
#还有一个删除函数。比如我有一个操作把所有等于8的数从集合中删除。下面来给他写出来
#思路也不难,比如删除8:我就做一个011111111,然后跟chushihua取交就完了。这地方有那么一点点的复杂。trick
def delme(chushihua,a):
    chushihua=(chushihua &(~(1<<a)))
    return chushihua
chushihua=delme(chushihua,8)
#删除8之后找8
print('删除8之后找8')
print (bin(chushihua))
print (search(chushihua,8))

    

#下面没事闲的测试一下,利用random
import numpy as np  #这模块有int32限制。。python 这个东西有问题,太大的数会出现错误。
b=np.random.random_integers(0,1000,100)#先弄10万个大数。
b=[50,3,4,324,32,4,32,4,324,324,32,4,32,4,32,432,4,3,4,3,4,3,4,3,43,4,3,43,4,3,4,3,3,3,3,3,3,3,3,3,3,34,4,4,4,4,4,4,4,5,3,4,324,32,4,32,4,324,324,32,4,32,4,32,432,4,3,4,3,4,3,4,3,43,4,3,43,4,3,4,3,3,3,3,3,3,3,3,3,3,34,4,4,4,4,4,4,4,5,3,4,324,32,4,32,4,324,324,32,4,32,4,32,432,4,3,4,3,4,3,4,3,43,4,3,43,4,3,4,3,3,3,3,3,3,3,3,3,3,34,4,4,4,4,4,4,4,5,3,4,324,32,4,32,4,324,324,32,4,32,4,32,432,4,3,4,3,4,3,4,3,43,4,3,43,4,3,4,3,3,3,3,3,3,3,3,3,3,34,4,4,4,4,4,4,4,5,3,4,324,32,4,32,4,324,324,32,4,32,4,32,432,4,3,4,3,4,3,4,3,43,4,3,43,4,3,4,3,3,3,3,3,3,3,3,3,3,34,4,4,4,4,4,4,4]
b=b*99900
#下面就是上面的代码copy
def init(a):#首先建立第一个数字存在的信息
    return 1<<a
chushihua=init(b[0])

for i in range(len(b)):
    if i>=1:
        chushihua=chushihua |(1<<b[i])
       #      python 这个东西有问题,太大的数会出现错误。!!!!!!!
                                          #这地方不太清楚,会不会是数字个数太多,导致误差,然后random时候会bug
       #后面我改用自己创造的数据然后*99900,发现效果很好,这个bug先放着问问别人。
#下面是查询一个数字是否在chushihua里面

print ('先用自带的in测试一下')
print (15 in b)
print ('再用我的函数测试一下')
print (search(chushihua,15))
print (search(chushihua,19))
print (search(chushihua,9))
print (search(chushihua,20))
#成功解决这个问题。
#还有一个删除函数。比如我有一个操作把所有等于8的数从集合中删除。下面来给他写出来
#思路也不难,比如删除8:我就做一个011111111,然后跟chushihua取交就完了。这地方有那么一点点的复杂。trick
def delme(chushihua,a):
    chushihua=(chushihua &(~(1<<a)))
    return chushihua
chushihua=delme(chushihua,8)
#最后很明显的看出来,我写的search比自带的int快99999999呗哈哈
View Code

 6.最长公共子序列问题

'''最长公共子序列:显然动态规划'''
'''经过画图分析,显然是2阶动态规划问题'''
'''设f(a,b,i,j)表示a从0到i的子串,和b从0到j的子串这2个子串的最长公共序列的长度'''
'''那么f(a,b,i,j)是从f(a,b,i-1,j),f(a,b,i,j-1),f(a,b,i-1,j-1)里面开发出来的'''#具体直接写代码。
def f(a,b,i,j):
      if i==0:
            if a[0] in b:
                  return 1
            else:
                  return 0
      if j==0:
            if b[0] in a:
                  return 1
            else:
                  return 0
      case1=case2=case3=0
      if a[i]==b[j]:
            case1=1+f(a,b,i-1,j-1)
      if a[i]!=b[j]:
            case2=f(a,b,i-1,j)
            case3=f(a,b,i,j-1)
      return max(case1,case2,case3)
a='343242dsfd'
b='dsfds'
print (f(a,b,len(a)-1,len(b)-1))
#上面很简单,3分钟搞定。男的是要把这个解解出来,而不仅仅是输出一个数字。
#这个跟背包问题很像,递归里面开数组。不是太好写。# 下面开始尝试。keyword:多返回值函数




def f(a,b,i,j):
      if i==0:
            if a[0] in b:
                  return 1,a[0]
            else:
                  return 0,''
      if j==0:
            if b[0] in a:
                  return 1,b[0]
            else:
                  return 0,''
      case1=case2=case3=0
      if a[i]==b[j]:
            case1=1+f(a,b,i-1,j-1)[0]
            case1_data=f(a,b,i-1,j-1)[1]+a[i]
      if a[i]!=b[j]:
            case2=f(a,b,i-1,j)[0]
            case2_data=f(a,b,i-1,j)[1]
            case3=f(a,b,i,j-1)[0]
            case3_data=f(a,b,i,j-1)[1]#如果有相同长度的解,应该返回最前面的。那么case2和case3如果相同呢????????
                                                   #我认为这个是一个相当男的bug了,弄点诡异数据来测一测。
                                                  #然而经过我长时间的分析,这个bug其实是没有的,具体很复杂,不容易说明白,
                                                   #结论我先说一下,就是这个代码
      if case1>case2 and case1>case3:
            return case1,case1_data
      if case2>=case1 and case2>=case3:   #这个代码case2》=case3为什么这么写可以,也就是说如果相等,我还是
                                                                 #只需要返回case2即可,舍弃case3.我尝试一下说明白这个取舍问题。
                                                               #道理就是你的这种取舍,考虑的前提就是case2里面最后一个元素被使用到了,然而
                                                             #你如果发生bug那么就必然发生这种情况,下面再让i+1,j+1后,如果用case3里面的情况
                                                           #会添加一个元素得到的长度比case2里面的长。但是这是不可能的,原因就是上一步
                                                        #已经保证了case2里面最后一个元素使用过了。总之很难说清楚的东西。
            return case2,case2_data
      if case3>=case1 and case3>=case2:
            return case3,case3_data
      
a='babax'
b='bbaxy'
print (f(a,b,len(a)-1,len(b)-1))
View Code

 7.最长公共子串

'''最长公共子串'''
'''也是动态规划'''
def com(a,b,i,j): #得到a,b的公共子串并且子串以a[i]和b[j]作为结尾的长度,
                         #然后把他们保存起来用下面的get函数,然后我们再取这个矩阵最大的就行了
    if i==0:
        if b[j]==a[i]:
            return 1
        else:
            return 0
    if j==0:
        if a[i]==b[j]:
            return 1
        else:
            return 0
    if a[i]==b[j]:
        return com(a,b,i-1,j-1)+1
    else:
        return 0
def get(a,b):
    save=[]
    for i in range(len(a)):
        for j in range(len(b)):
             save.append(com(a,b,i,j))
    return max(save)
print (get('aa3232','aaa783232'))
#效果还不错。
#下面还是继续写,把这个最长子串的组合写出来。
    

def com(a,b,i,j): #得到a,b的公共子串并且子串以a[i]和b[j]作为结尾的长度,
                         #然后把他们保存起来用下面的get函数,然后我们再取这个矩阵最大的就行了
    if i==0:
        if b[j]==a[i]:
            return 1,a[i]
        else:
            return 0,''
    if j==0:
        if a[i]==b[j]:
            return 1,a[i]
        else:
            return 0,''
    if a[i]==b[j]:
        return com(a,b,i-1,j-1)[0]+1,com(a,b,i-1,j-1)[1]+a[i]
    else:
        return 0,''
def get(a,b):
    save=[]
    for i in range(len(a)):
        for j in range(len(b)):
             save.append(com(a,b,i,j))
    return max(save)
print (get('aa3232','aaa783232'))
#一样轻松写出。








    
View Code

 8.全域散列法,随机hash的思想

'''全域散列,随机hash技术'''
'''全域散列法在执行的开始时,就从一组精心设计的函数总,随机的选择一个作为散列函数,
随机化保证了没有哪一个输入会导致最坏性能情况的发生.'''
'''构造这个函数族很复杂,也不是非常复杂:
原范围是p,分类后的曹数是m,也就是把p范围内的数都分布到m个曹当中

h(k)_(a,b)=((ak+b)modp)modm
那么因为p,m去定.a跑遍1到p-1,b跑遍1到p就构造了p(p-1)这么多个函数.他的性质是Pr(h(k)_(a,b)=h(k)_(a,b)).







'''
View Code

 9.二叉搜索树:

#coding:utf-8
#首先是二叉搜索树的定义:
'''若它的左子树不空,则左子树上所有结点的值均小于它的根结点的值;
若它的右子树不空,则右子树上所有结点的
值均大于它的根结点的值; 它的左、右子树也分别为二叉排序树。'''
'''二叉搜索树''''''二叉搜索树里面的元素都是不重复的
所以当插入一个元素时候先搜索他是否在树里面,如果在就不插入了,
不果不在就插入'''

class node():
        def __init__(self,data):
            self.left=None
            self.right=None
            self.data=data
#不能把类写在另一个类里面
class ercha():
    
    def __init__(self):
        self.head=node(None)
    def input(self,a):
        old_head=self.head
        while 1:
             
             if self.head.data==None:
                 self.head.data=a
                 self.head=old_head
                 return
             if self.chazhao(a)==None:
                 if a<self.head.data and self.head.left==None:
                      self.head.left=node(a)
                      self.head=old_head
                      return
                 if a<self.head.data and self.head.left!=None:
                            self.head=self.head.left
                            continue
                 if a>self.head.data and self.head.right==None:
                      self.head.right=node(a)
                      self.head=old_head
                      return
                 if a>self.head.data and self.head.right!=None:
                            self.head=self.head.right
                            continue
                      



             
    def chazhao(self,a):
     old_head=self.head
     while 1:
        if self.head==None:
                   self.head=old_head
                   return None
        if a==self.head.data:
            new_head=self.head
            self.head=old_head
            return new_head
        if a>self.head.data:
                   self.head=self.head.right
                   continue
        if a<self.head.data:
                    self.head=self.head.left
    def delet(self,a):
              if self.chazhao(a)==None:
                         print ('错误')
                         return None
              else:
                     if self.chazhao(a).left==None and self.chazhao(a).right==None:
                             t=self.chazhao(a)
                             # t=None这里面写这个不好使.对象不能直接赋值?
                             t.data=None
                     if self.chazhao(a).left==None and self.chazhao(a).right!=None:
                             pass
    def listhua(self,a):#把root=a的子树,中序遍历的结果都转化成list来查询
                                     #这个递归代码不能实际使用,因为速度O(N)了,跟需要logn矛盾.
            b=[]
            if a==None:
                    return b
            if a!=None:
                    if a.left==None and a.right==None:
                            return [a]
                    else:
                                         a1=self.listhua(a.left)
                                         a2=[a]
                                         a3=self.listhua(a.right)
                                         if a1==None:
                                                 a1=[]
                                         if a3==None:
                                                 a3=[]
                                         return a1+a2+a3
#删除还是没写明白
            
shu=ercha()
shu.input(3)

shu.input(2)

shu.input(6)
shu.input(9)
listhuazhihou=shu.listhua(shu.chazhao(3))
print (listhuazhihou[0].data)
View Code
#自己写的不对,还是贴个别人的吧
class TreeNode:
    def __init__(self,val):
        self.val=val;
        self.left=None;
        self.right=None;
def insert(root,val):
    if root is None:
        root=TreeNode(val);
    else:
        if val<root.val:
            root.left=insert(root.left,val);   #递归地插入元素
        elif val>root.val:
            root.right=insert(root.right,val);  
    return root;

def query(root,val):
    if root is None:
        return ;
    if root.val is val:
        return 1;
    if root.val <val:
        return query(root.right,val);  #递归地查询
    else:  
        return query(root.left,val);
def findmin(root):
    if root.left:
        return findmin(root.left);
    else:
        return root;
    
def delnum(root,val):
    if root is None:
        return ;
    if val<root.val:
        return delnum(root.left,val);
    elif val>root.val:
        return delnum(root.right,val);
    else:                                             # 删除要区分左右孩子是否为空的情况
        if(root.left and root.right):
            
            tmp=finmin(root.right);             #找到后继结点
            root.val=tmp.val;
            root.right=delnum(root.right,val);    #实际删除的是这个后继结点
            
        else:
            if root.left is None:
                root=root.right;
            elif root.right is None:
                root=root.left;
    return root;
                
                
#測试代码            
root=TreeNode(3);
root=insert(root,2);
root=insert(root,1);
root=insert(root,4);

#print query(root,3);
print (query(root,1))
root=delnum(root,1)
print (query(root,1))
View Code
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

15122306087

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值