剑指offer刷题0405

本文介绍如何利用位运算解决编程难题,包括不使用算术运算符做加法、字符串转整数、查找数组中重复数字及字符流中首个唯一字符等。通过实例解析,帮助读者掌握位运算的基本原理及其在实际问题中的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

今天刷的并不牢靠。第一题有点纠结太久了

感谢与参考:https://codingcat.cn/article/

不用加减乘除做加法 

把字符串转换成整数

数组中重复的数字

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

 

 

不用加减乘除做加法 

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

注意: 不能用四则运算符,那则只能是用最原始的二进制位运算。数值在计算机中的存储采用的是补码存储,所以一般的位运算都是基于补码进行的 二进制的加法运算,三步走:
第一步:相加各位的值,不算进位,即进行
异或操作
第二步:计算进位值,进行与操作并左移一位
第三步,重复重复上述两步,当进位值为 0,则跳出循环。

具体到此题:
以用三步走的方式计算二进制值相加: 5即101,7即111
第一步:相加各位的值,不算进位,得到010,二进制每位相加就相当于各位做异或操作,即101^111。
第二步:计算进位值,得到1010,相当于各位做与操作(用&表示)得到101,再向左移一位得到1010,即(101&111) << 1。
第三步重复上述两步, 各位相加 010^1010=1000,进位值为100=(010&1010) << 1。 继续重复上述两步:1000^100 = 1100,进位值为0,跳出循环,1100为最终结果。

异或运算(操作)又叫半加运算,其运算法则相当于不带进位的二进制加法。二进制下用1表示真,0表示假,则异或的运算法则为:0⊕0=0,1⊕0=1,0⊕1=1,1⊕1=0(同为0,异为1),这些法则与加法是相同的,只是不带进位,所以异或常被认作不进位加法,用 ^ 表示

## C++ 语言版的
class Solution {
public:
    int Add(int num1, int num2)
        //#思路:二进制的运算。三步,第一步,异或运算,第二步,计算进位,与操作,左移一位。
        //#第三步重复上述,直到进位为0
    {
        while(num2 !=0){
            int temp=num1^num2; //与操作
            num2=(num1&num2)<<1;//计算进位,并赋值给num2
            num1=temp;
        }
        return num1;

    }
};

C语言版本中int是32位的,进入下最后一个循环后,向左移一位后,最高位的1就溢出了,那一位就去了,如果原数后面第31位是0,则新的32位就变成了0. 但是python由于支持大int值,它的整数不是32位,而是某种程度上可以无限扩展,结果左移的1跑到33位,b仍然不是0,实际上永远也不是0,于是就无限循环了......
那么为了修正这个bug,我们必须截断b,让他保持最多32位,修改如下:

def getSum(a,b):
     while b!=0:
         ta = a
         a = a^b #异或操作,
         b = ((ta&b)<<1)&0xffffffff  #与操作,截断b,让b保持最多32位
     hibit = (a&0x80000000)>>31#a与上16进制中的 0x80000001 ,即与上二进制为1000 0000 0000 0000 0000 0000 0000 0000
     #前三十一位都变为0了,再右移31位,记得到了原来数中第32位的值
     if hibit==1:#如果第32为1,则原来的数为 负数了,需要按位取反+1,得到原值。
         return -(((~a)+1)&0xffffffff)
     else:
         return a&0xffffffff
    
s=getSum(2,-5)
print(s)

 

把字符串转换成整数
题目描述
将一个字符串转换成一个整数(实现Integer.valueOf(string)的功能,但是string不符合数字要求时返回0),要求不能使用字符串转换整数的库函数。 数值为0或者字符串不是一个合法的数值则返回0。

注意:‘0’,'9'这样字符,其本质上存储也是用ASCII值存储的,字符‘0’对应48,字符'9'对应57


# -*- coding:utf-8 -*-
class Solution:
    def StrToInt(self, s):
        # write code here
        #要注意考虑的全面性,注意细节的讨论
        #需要回头看
        minus = 1
        number = 0
        if not s:
            return number
        if s[0] == '+':
            if len(s) > 1:
                s = s[1:]
            else:
                return 0
        elif s[0] == '-':
            minus = -1
            if len(s) > 1:
                s = s[1:]
            else:
                return 0
        for i in range(0, len(s)):
            if '0' <= s[i] <= '9':
                number = number * 10 + ord(s[i]) - ord('0')##ord(‘0’)将当个字符‘0’转换为其ASCII的整数值
            else:
                return 0
        return number * minus

 

数组中重复的数字
问题
在一个长度为n的数组里的所有数字都在0到n-1的范围内。 数组中某些数字是重复的,但不知道有几个数字是重复的。也不知道每个数字重复几次。请找出数组中任意一个重复的数字。 例如,如果输入长度为7的数组{2,3,1,0,2,5,3},那么对应的输出是第一个重复的数字2。

此题,需要再回头看看,尝试用字典存储key与频次value
思路 基本的思路就是建一个hash表,读数先判断是否重复,不重复就放进去读下一个,直到找到第一个重复的。 另外可以进行排序,然后判断是否有相邻两个数重复。

但注意题目中条件,所有数字都在0到n-1范围内。因此无需开辟额外空间,可以直接在数组上做标记。读到数字时,将数组中该数字作为下标的位置的数字,减去n,作为标记。下次读到相同数字,去其下标位置,发现数字值小于0,说明已经被标记过,那么这个就是重复数字了。
一些细节:之所以不用加上n的方法来标记,是因为可能会导致数字过大溢出(减去n就不会,因为只要n不溢出, -n-1 就不溢出, -n-1+一个正数 就也不会溢出)。也不能乘以-1来做标记,因为这种方法对0就没法做标记了。

 

# -*- coding:utf-8 -*-
class Solution:
    # 返回值格式:函数返回True/False,找到任意重复的一个值并赋值到duplication[0]
    def duplicate(self, numbers, duplication):
        length = len(numbers)
        for num in numbers:
            if num >= 0:
                # 直接按num为下标去找
                index = num
            else:
                # 如果此处已被标记,则下标要按此处的值 num+length 去找
                index = num + length
            if numbers[index] < 0:
                # 找到重复
                duplication[0] = numbers[index] + length
                return True
            else:
                # 不重复,则做下标记
                numbers[index] -= length
        return False

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

思路1:先扫一遍串,记下每个字符出现的次数,再扫一遍串同时查询每个字符出现的次数,遇到出现次数为1的就是第一个只出现一次的字符了。 思路2:可参考辛的笔记,还有蛮多方法的

# -*- coding:utf-8 -*-
class Solution:
    def __init__(self):
        self.stream = []
        self.counter = {}
    # 返回对应char
    def FirstAppearingOnce(self):
        for c in self.stream:
            if self.counter[c] == 1:
                return c
        return '#'
    def Insert(self, char):
        if char in self.counter:
            self.counter[char] += 1
        else:
            self.counter[char] = 1
        self.stream.append(char)

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值