cstring添加一个字符_剑指Offer整理3 -- 栈和队列 + 数学和字符串

c83228586ca39d2b0893cebf582698c8.png

专题3 栈和队列 + 数学和字符串

专题3-1 栈和队列

1. 栈的压入弹出序列

题目描述

输入两个整数序列,第一个序列表示栈的压入顺序,请判断第二个序列是否可能为该栈的弹出顺序。假设压入栈的所有数字均不相等。例如序列1,2,3,4,5是某栈的压入顺序,序列4,5,3,2,1是该压栈序列对应的一个弹出序列,但4,3,5,1,2就不可能是该压栈序列的弹出序列。(注意:这两个序列的长度是相等的)

Python

2.包含min函数的栈

题目描述

定义栈的数据结构,请在该类型中实现一个能够得到栈中所含最小元素的min函数(时间复杂度应为O(1))。

注意:保证测试中不会当栈为空的时候,对栈调用pop()或者min()或者top()方法。

Python:
# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stack = []
        self.minvalue = []
    def push(self, node):
        # write code here
        self.stack.append(node)
        if self.minvalue:
            if self.minvalue[-1] > node:
                self.minvalue.append(node)
            else:
                self.minvalue.append(self.minvalue[-1])
        else:
            self.minvalue.append(node)
    def pop(self):
        # write code here
        if self.stack == []:
            return None
        self.minvalue.pop()
        return self.stack.pop()
    def top(self):
        # write code here
        if self.stack == []:
            return None
        return self.stack[-1]
    def min(self):
        # write code here
        if self.minvalue == []:
            return None
        return self.minvalue[-1]

3.用两个栈来实现一个队列

题目描述

用两个栈来实现一个队列,完成队列的Push和Pop操作。 队列中的元素为int类型。

42938f07ad2151a16f827333077bd033.png
Python
# -*- coding:utf-8 -*-
##队列是一种特殊的线性表,特殊之处在于它只允许在表的前端(front)进行删除操作,而在表的后端(rear)进行插入操作,和栈一样,队列是一种操作受限制的线性表。进行插入操作的端称为队尾,进行删除操作的端称为队头
#栈(stack)又名堆栈,它是一种运算受限的线性表。其限制是仅允许在表的一端进行插入和删除运算。这一端被称为栈顶,相对地,把另一端称为栈底。向一个栈插入新元素又称作进栈、入栈或压栈,它是把新元素放到栈顶元素的上面,使之成为新的栈顶元素;从一个栈删除元素又称作出栈或退栈,它是把栈顶元素删除掉,使其相邻的元素成为新的栈顶元素

class Solution:
    def init(self):
        #添加数据栈
        self.acceptStack=[]
        #删除数据栈
        self.outputStack = []
    def push(self, node):
        #向添加数据的栈中添加数据
        self.acceptStack.append(node)
    def pop(self):
        #判断删除数据的栈中是否有数据,没有的话,就添加数据,添加数据时,要添加栈1 中删除的数据
        if not self.outputStack:
            while self.acceptStack:
            self.outputStack.append(self.acceptStack.pop())
        #如果有数据的话,就返回
        if self.outputStack:
            return self.outputStack.pop()
        #如果没有数据,说明没有数据添加进去,也就不需要删除数据,所以返回none
        else:
            return None

专题3-2 字符串和数学

1.字符流中第一个不重复的字符

题目描述

请实现一个函数用来找出字符流中第一个只出现一次的字符。例如,当从字符流中只读出前两个字符"go"时,第一个只出现一次的字符是"g"。当从该字符流中读出前六个字符“google"时,第一个只出现一次的字符是"l"。

输出描述:

如果当前字符流没有存在出现一次的字符,返回#字符。

Python:
# -*- coding:utf-8 -*-
class Solution:
    # 返回对应char
    def __init__(self):
        self.s = ""
 
    def FirstAppearingOnce(self):
        # write code here 
        #method1       
        res=list(filter(lambda c:self.s.count(c)==1,self.s))
        return res[0] if res else "#"   

        '''
#method2  python3
        ret = []
        res = {x: self.s.count(x) for x in self.s}
        for key,  value in res.items():     
            if value == 1:
                ret.append(key)
 
        return ret[0] if ret else "#" 
 
        #method3      
for a in self.s:
            if self.s.count(a) == 1:
                return a
                break
        return '#'
        '''
 def Insert(self, char):
        # write code here
        self.s  +=  char

2.表示数值的字符串

题目描述

请实现一个函数用来判断字符串是否表示数值(包括整数和小数)。例如,字符串"+100","5e2","-123","3.1416"和"-1E-16"都表示数值。 但是"12e","1a3.14","1.2.3","+-5"和"12e+4.3"都不是。

Python:
# -*- coding:utf-8 -*-
class Solution:
    # s字符串
    def isNumeric(self, s):
        # write code here
        if len(s) <= 0:
            return False
        # 分别标记是否出现过正负号、小数点、e,因为这几个需要特殊考虑
        has_sign = False
        has_point = False
        has_e = False
        for i in range(len(s)):
            # 对于e的情况
            if s[i] == 'E' or s[i] == 'e':
                # 不同出现两个e
                if has_e:
                    return False
                # e不能出现在最后面,因为e后面要接数字
                else:
                    has_e = True
                    if i == len(s) -1:
                        return False   
            # 对于符号位的情况
            elif s[i] == '+' or s[i] == '-':
                # 如果前面已经出现过了符号位,那么这个符号位,必须是跟在e后面的
                if has_sign:
                    if s[i-1] != 'e' and s[i-1] != 'E':
                        return False
                # 如果这是第一次出现符号位,而且出现的位置不是字符串第一个位置,那么就只能出现在e后面
                else:
                    has_sign = True
                    if i > 0 and s[i-1] != 'e' and s[i-1] != 'E':
                        return False
            # 对于小数点的情况
            elif s[i] == '.':
                # 小数点不能出现两次;而且如果已经出现过e了,那么就不能再出现小数点,因为e后面只能是整数
                if has_point or has_e:
                    return False
                # 如果是第一次出现小数点,如果前面出现过e,那么还是不能出现小数点
                else:
                    has_point = True
                    if i > 0 and (s[i-1] == 'e' or s[i-1] == 'E'):
                        return False
            else:
                # 其他字符必须是‘0’到‘9’之间的
                if s[i] < '0' or s[i] > '9':
                    return False
        return True
 
'''
     ##method2:
        try:
            ss=float(s)
            return True
 
        except:
            return False
   '''

3.正则表达式的匹配

题目描述

请实现一个函数用来匹配包括'.'和'*'的正则表达式。模式中的字符'.'表示任意一个字符,而'*'表示它前面的字符可以出现任意次(包含0次)。 在本题中,匹配是指字符串的所有字符匹配整个模式。例如,字符串"aaa"与模式"a.a"和"ab*ac*a"匹配,但是与"aa.a"和"ab*a"均不匹配

Python:
# -*- coding:utf-8 -*-
class Solution:
    # s, pattern都是字符串
    def match(self, s, pattern):
        # write code here
        if len(s) == 0 and len(pattern) == 0:
            return True
        elif len(s) != 0 and len(pattern) == 0:
            return False
        elif len(s) == 0 and len(pattern) != 0:
            # pattern中的第二个字符为*,则pattern后移两位继续比较
            if len(pattern) > 1 and pattern[1] == '*':
                return self.match(s, pattern[2:])
            else:
                return False
 
       #s与pattern都不为空的情况
        else:
            # pattern的第二个字符为*的情况
            if len(pattern) > 1 and pattern[1] == '*':
                # s与pattern的第一个元素不同,则s不变,pattern后移两位,相当于pattern前两位当成空
                if s[0] != pattern[0] and pattern[0] != '.':
                    return self.match(s, pattern[2:])
                else:
    #如果s[0]与pattern[0]相同,且pattern[1]为*,这个时候有三种情况
    #pattern后移2个,s不变;相当于把pattern前两位当成空,匹配后面的
    # pattern后移2个,s后移1个;相当于pattern前两位与s[0]匹配
    # pattern不变,s后移1个;相当于pattern前两位,与s中的多位进行匹配,因为*可以匹配多位
                    return self.match(s, pattern[2:]) or self.match(s[1:], pattern[2:]) or self.match(s[1:], pattern)
            # pattern第二个字符不为*的情况
            else:
                if s[0] == pattern[0] or pattern[0] == '.':
                    return self.match(s[1:], pattern[1:])
                else:
                    return False
C++
class Solution {
public:
/*  注意,'.'是任意一个非空字符
    解这题需要把题意仔细研究清楚,反正我试了好多次才明白的。
    首先,考虑特殊情况:
         1>两个字符串都为空,返回true
         2>当第一个字符串不空,而第二个字符串空了,返回false(因为这样,就无法匹配成功了,而如果第一个字符串空了,第二个字符串非空,还是可能匹配成功的,比如第二个字符串是“a*a*a*a*”,由于‘*’之前的元素可以出现0次,所以有可能匹配成功),之后就开始匹配第一个字符,这里有两种可能:匹配成功或匹配失败。但考虑到pattern,下一个字符可能是‘*’, 这里我们分两种情况讨论:pattern下一个字符为‘*’或不为‘*’:
          1>pattern下一个字符不为‘*’:这种情况比较简单,直接匹配当前字符。如果匹配成功,继续匹配下一个;如果匹配失败,直接返回false。注意这里的“匹配成功”,除了两个字符相同的情况外,还有一种情况,就是pattern的当前字符为‘.’,同时str的当前字符不为‘0’。
          2>pattern下一个字符为‘*’时,稍微复杂一些,因为‘*’可以代表0个或多个。这里把这些情况都考虑到:
          a>当‘*’匹配0个字符时,str当前字符不变,pattern当前字符后移两位,跳过这个‘*’符号;
          b>当‘*’匹配1个或多个时,str当前字符移向下一个,pattern当前字符不变。(这里匹配1个或多个可以看成一种情况,因为:当匹配一个时,
由于str移到了下一个字符,而pattern字符不变,就回到了上边的情况a;当匹配多于一个字符时,相当于从str的下一个字符继续开始匹配)
    之后再写代码就很简单了。
*/
    bool match(char* str, char* pattern)
    {
        if (*str == '0' && *pattern == '0')
            return true;
        if (*str != '0' && *pattern == '0')
            return false;
        //if the next character in pattern is not '*'
        if (*(pattern+1) != '*')
        {
            if (*str == *pattern || (*str != '0' && *pattern == '.'))
                return match(str+1, pattern+1);
            else
                return false;
        }
        //if the next character is '*'
        else
        {
            if (*str == *pattern || (*str != '0' && *pattern == '.'))
                return match(str, pattern+2) || match(str+1, pattern);
            else
                return match(str, pattern+2);
        }
 
    }
};

4.把字符串转换为整数

题目描述

将一个字符串转换成一个整数,要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0

输入描述:

输入一个字符串,包括数字字母符号,可以为空

输出描述:

如果是合法的数值表达则返回该数字,否则返回0

f556a2099ea3f980c27b07fb0f7d22d2.png
Python:
# -*- coding:utf-8 -*-
class Solution:
    def StrToInt(self, s):
       # write code here
        numlist=['0','1','2','3','4','5','6','7','8','9','+','-']
        sum=0
        label=1#正负数标记
        if s=='':
            return 0
        for string in s:
            if string in numlist:#如果是合法字符
                if string=='+':
                    label=1
                    continue
                if string=='-':
                    label=-1
                    continue
                else:
                    sum=sum*10+numlist.index(string)
            if string not in numlist:#非合法字符
                sum=0
                break#跳出循环
        return sum*label

5.不用加减乘除做加法

题目描述

写一个函数,求两个整数之和,要求在函数体内不得使用+、-、*、/四则运算符号。

b9f4ea1a356f3b478a26d2047a20d614.png
Python:
# -*- coding:utf-8 -*-
class Solution:
    def Add(self, num1, num2):
        # write code here
        xornum = num1 ^ num2
        andnum = (num1 & num2) << 1
 
        while andnum != 0:
            tmp1 = xornum ^ andnum
            tmp2 = (xornum & andnum) << 1
            tmp1 = tmp1 & 0xFFFFFFFF #越界检查 32位
            xornum = tmp1
            andnum = tmp2
            #正数返回,负数的话还原~n = -(n+1)
        return xornum if xornum <= 0x7FFFFFFF else ~(xornum^0xFFFFFFFF)
C++
class Solution {
public:
    int Add(int num1, int num2)
    {
        int xornum = num1 ^ num2;
        int andnum = (num1 & num2) << 1;
        while(andnum != 0)
        {
            int tmp1 = xornum ^ andnum;
            int tmp2 = (xornum & andnum) << 1;
            xornum = tmp1;
            andnum = tmp2;
        }
 
        return xornum;
    }
};

6.求1+2+3+...+n

题目描述

求1+2+3+...+n,要求不能使用乘除法、for、while、if、else、switch、case等关键字及条件判断语句(A?B:C)。

Python:
# -*- coding:utf-8 -*-
class Solution:
    def Sum_Solution(self, n):
        # write code here
        #return sum(list(range(1,n+1)))
        return (pow(n,2) + n) >> 1

7.翻扑克牌子

题目描述

LL今天心情特别好,因为他去买了一副扑克牌,发现里面居然有2个大王,2个小王(一副牌原本是54张^_^)...他随机从中抽出了5张牌,想测测自己的手气,看看能不能抽到顺子,如果抽到的话,他决定去买体育彩票,嘿嘿!!“红心A,黑桃3,小王,大王,方片5”,“Oh My God!”不是顺子.....LL不高兴了,他想了想,决定大小 王可以看成任何数字,并且A看作1,J为11,Q为12,K为13。上面的5张牌就可以变成“1,2,3,4,5”(大小王分别看作2和4),“So Lucky!”。LL决定去买体育彩票啦。 现在,要求你使用这幅牌模拟上面的过程,然后告诉我们LL的运气如何, 如果牌能组成顺子就输出true,否则就输出false。为了方便起见,你可以认为大小王是0。

Python:
# -*- coding:utf-8 -*-
class Solution:
    def IsContinuous(self, numbers):
        # write code here
        #method1
        if len(numbers):
            while min(numbers) == 0:
                numbers.remove(0)
            if max(numbers) - min(numbers) <= 4 and len(numbers) == len(set(numbers)):
                return True
        return False
C++
class Solution {
public:
    bool IsContinuous( vector<int> numbers ) {

        if(numbers.size()!=5) return false;
        sort(numbers.begin(),numbers.end());
        int i=0;
        while(numbers[i]==0) i++;
        if(numbers[4]-numbers[i]>4) return false;
        for(int j=i;j<4;j++){
            if(numbers[j]==numbers[j+1]) return false;
        }
        return true;
    }
};

8.翻转单词序列

题目描述

牛客最近来了一个新员工Fish,每天早晨总是会拿着一本英文杂志,写些句子在本子上。同事Cat对Fish写的内容颇感兴趣,有一天他向Fish借来翻看,但却读不懂它的意思。例如,“student. a am I”。后来才意识到,这家伙原来把句子单词的顺序翻转了,正确的句子应该是“I am a student.”。Cat对一一的翻转这些单词顺序可不在行,你能帮助他么?

Python:
# -*- coding:utf-8 -*-
class Solution:
    def ReverseSentence(self, s):
        # write code here
        if len(s) == 0:
            return s
        s = s.split(" ")
        #print(s[::-1])

        res = " ".join(s[::-1])
        return res

9.左旋转字符串

题目描述

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

Python:
# -*- coding:utf-8 -*-
class Solution:
    def LeftRotateString(self, s, n):
        # write code here     
        l = len(s)
        if l <= 0 or n < 0:
            return s
        n = n % l
        a = s[:n][::-1]
        b = s[n:][::-1]
        c =  b[::-1] + a[::-1]
        return c
 
        '''
        return s[n:] + s[:n]
        '''

10.第一个只出现一次的字符

题目描述

在一个字符串(0<=字符串长度<=10000,全部由字母组成)中找到第一个只出现一次的字符,并返回它的位置, 如果没有则返回 -1(需要区分大小写).(从0开始计数)

Python
# -*- coding:utf-8 -*-
class Solution:
    def FirstNotRepeatingChar(self, s):
        # write code here
        #return [i for i in range(len(s)) if s.count(s[i])==1][0] if s else -1
        '''
        if s:
            a = [i for i in range(len(s)) if s.count(s[i])==1][0]
            return a 
        else:
            return -1
         '''
        #判断输入条件
        if len(s)<=0 or len(s)>10000:
            return -1
        #count用于统计字符串中某个字符的出现]数
        #index为计算字符串中某个字符的位置
        for i in s:
            if s.count(i)==1:
                return s.index(i)
                break

11.数值的整数次方

题目描述

给定一个double类型的浮点数base和int类型的整数exponent。求base的exponent次方。

保证base和exponent不同时为0

Python
# -*- coding:utf-8 -*-
class Solution:
    def Power(self, base, exponent):
        # write code here
        #return base**exponent   
 
        if base == 0:
            return 0
        if exponent == 0:
            return 1
        p = abs(exponent)
 
        res = 1
        while(p > 0):
            #如果最后一位为1,那么给res乘上这一位的结果
            if (p & 1 == 1):
                res =res * base
            p = p >> 1
            base = base * base
        return res if exponent > 0 else 1/res
C++
class Solution {
public:
    double Power(double base, int exponent) 
   { //code
      if(base == 0.0)
            return 0;
      if(exponent == 0.0)
            return 1;

      long long p = abs((long long)exponent);
      double r = 1.0;
        while(p){
            if(p & 1)  r *= base;
            base *= base;
            p >>= 1;
        }
        return exponent < 0 ? 1/ r : r;
    }
};

12.二进制中1的个数

题目描述

输入一个整数,输出该数32位二进制表示中1的个数。其中负数用补码表示

Python:
    def NumberOf1(self, n):
        # write code here
        #flag = 1
        count = 0
        if n < 0: ##必须加
            n = n & 0xffffffff #为了获得负数(十进制表示)的补码,需要手动将其和十六进制数0xfffffffd进行按位与操作
        while n:
            count += 1
            n = (n-1)&n
        return count
C++
class Solution {
public:
     int  NumberOf1(int n) {
        /*
         int count = 0;
         int flag = 1;
         //C语言中 << 是逻辑移位,不是循环移位; 1左移32位后为0
         while(flag)
         {
             if(n&flag)
                 count++;
             flag = flag << 1;
 
         }
         return count;
         */
         int count = 0;
         while(n)
         {
             count ++;
             n = (n-1) & n;//消除n最右边的一个0

         }
         return count;
    }
};

13.替换空格

题目描述

请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

Python
# -*- coding:utf-8 -*-
class Solution:
    # s 源字符串
    def replaceSpace(self, s):
        # write code here
        #s1 = s.replace(' ', '%20')
        #return s1
 
        new_s = ''
        for j in s:
            if j == ' ':
                new_s = new_s + '%20'
            else:
                new_s = new_s + j
        return new_s
C++
class Solution {
public:
	void replaceSpace(char *str,int length) 
    {

        if(str==NULL||length<0)
            return;
        int i=0;
        int oldnumber=0;//记录以前的长度
        int replacenumber=0;//记录空格的数量
        while(str[i]!='0')
            {
               oldnumber++;
               if(str[i]==' ')
                   {
                     replacenumber++;
                   }
                  i++; 
            }
        int newlength=oldnumber+replacenumber*2;//插入后的长度
        if(newlength>length)//如果计算后的长度大于总长度就无法插入
            return;
        int pOldlength=oldnumber; //注意不要减一因为隐藏个‘0’也要算里
        int pNewlength=newlength;
        while(pOldlength>=0&&pNewlength>pOldlength)//放字符
            {
              if(str[pOldlength]==' ') //碰到空格就替换
                  {
                     str[pNewlength--]='0';
                     str[pNewlength--]='2';
                     str[pNewlength--]='%';
 
                  }
               else //不是空格就把pOldlength指向的字符装入pNewlength指向的位置
               {
                    str[pNewlength--]=str[pOldlength];
 
               }
             pOldlength--; //不管是if还是elsr都要把pOldlength前移
 
           }
    }
};

14.整数中出现1的次数(从1到n)******

题目描述

求出1~13的整数中1出现的次数,并算出100~1300的整数中1出现的次数?为此他特别数了一下1~13中包含1的数字有1、10、11、12、13因此共出现6次,但是对于后面问题他就没辙了。ACMer希望你们帮帮他,并把问题更加普遍化,可以很快的求出任意非负整数区间中1出现的次数(从1 到 n 中1出现的次数)。

Python
# -*- coding:utf-8 -*-
class Solution:
    def NumberOf1Between1AndN_Solution(self, n):
        # write code here
        #return ''.join(map(str, range(n+1))).count('1')
        #method 1         
        # 将1-n全部转换为字符串
        # 只需要统计每个字符串中'1'出现的次数并相加即可     
        return ''.join(map(str,range(n+1))).count('1')
C++
class Solution {
public:
    int NumberOf1Between1AndN_Solution(int n)
{
    //方法1:暴力求解
        //int count = 0;
       // for(int i=0; i<=n; i++){
           // int temp = i;
           // while(temp){
              //  if(temp%10 == 1){
               //    count++;
               // }
               // temp /= 10;
          //  }
        //}
        //return count; 
      //方法2
        int count = 0;
        long long m = 1;
        for(m=1; m<=n; m*=10)
        {
            int a = n/m;
            int b = n%m;
            count += (a+8)/10*m + (a%10==1)*(b+1);
 
        }
        return count;
    }
};
//举一反三:如果求2的个数
//count += (a+7)/10*m + (a%10==2)*(b+1); 以此类推

C++方法2举例说明

当n = 3141592时:

57e571d2927688103c711f4aa2acc796.png

当然后面还有m=10000,100000,1000000三种情况,对应着万位,十万位, 百万位为1时的情况

下面说下a+8的意义:

当考虑个位,十位,百位这三位为1的情况时:

个位 2 ,当个位取值1时,前面的六位数字可由0~314159组成,即314160种情况

十位9,当十位取值1时,前面的五位数字可由0~31415组成,十位之后的一位可由0~9组成,组合情况31416*10=314160种情况

百位5,当百位取值为1时,前面的四位数字可由0~3141组成,百位之后的两位可由0~99组成,组合情况为3142*100=314200种情况

注意:当考虑千位1时:

千位1,千位取值即1,前面的三位数字可由0~314组成,但是当前面的值为314时,后面的三位只有0~592种情况(特殊情况),其余的情况即为前面的值为0~313,后面三位有0~999,情况数为3141000,所以总情况数为3141000 + 593=314593种情况

这时可发现和代码中的公式算的情况是吻合的,a+8的巧妙之处在于当a的最后一位(当前分析位)为0或1时,加8不产生进位,这是为需要单独算的特殊情况做准备,而当前分析位为2~9时,不需要考虑特殊情况,所以允许加8产生的进位。(>2或者=0时计算相同,=1时计算附加值)

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值