數據結構:找出字符串中重復的字符(Finding Duplicates in a String)——使用位運算

目錄

預備知識

左移運算(<<)

位運算?

一、從最樸素的方法開始

二、如果只關心“有沒有出現過”,不關心“次數”,還能不能更省?

三、有沒有一種更“緊湊”的方式表示26個開關?

四、用一個整數的每一位表示一個字母是否出現


預備知識

左移運算(<<

x << n

表示:把整數 x 的二進制表示整體向左移動 n 位

舉例說明:

我們來觀察下面的例子(以 int 為例,32 位):

int x = 1;00000000 00000000 00000000 00000001

現在我們做左移操作:

int y = x << 3;

意思是把 1 向左移動 3位,得到的新值是 8

為什么?看圖:

x = 00000000 00000000 00000000 00000001   // 原始值是 1
y = 00000000 00000000 00000000 00001000   // 變成了 8

1 × 2^3 = 8

? 左移 n 位 就相當于 乘以 2?

左移的“位圖”意義

我們現在不把整數當作“數”,而當作一排開關/位

int mask = 1 << i;  // 表示第 i 位是 1,其余是 0
imask(二進制)十進制
000000000 00000000 000000011
100000000 00000000 000000102
200000000 00000000 000001004
300000000 00000000 000010008
2500000010 00000000 0000000033554432
mask = 1 << ('c' - 'a');  // 表示字符 'c' 的那一位

?所以就能精準地表示:字母 'c' 這個字符的“標志位”是否應該置 1


位運算?

ORing(按位或)

把某一位設置為 1(“合并標記”)

💡 場景:

想要記錄:這個字符 已經出現過了

我們通過:

bitmask = bitmask | mask;

示例:

bitmask = 00000000 00000000 00000000 00000101
mask    = 00000000 00000000 00000000 00000100  // 想設置第2位bitmask | mask = 00000000 00000000 00000000 00000101

注意:已經是 1 的位不會被改動;為 0 的位被“點亮”

快寫法(更常見):

bitmask |= mask;

完全等價于 bitmask = bitmask | mask

ANDing(按位與)

檢查某一位是否是 1(“掩碼檢查”)

💡 場景:

想要判斷:這個字符是否 已經出現過

通過:

if ((bitmask & mask) > 0)// 第 i 位是 1,說明已經出現

示例:

bitmask = 00000000 00000000 00000000 00000101  // 第0位和第2位是1
mask    = 00000000 00000000 00000000 00000100  // 想查第2位bitmask & mask = 00000000 00000000 00000000 00000100  // 非0 → 出現過

如果該位是 0,則結果為全 0

技術總結:“一個整數的每一位代表一個狀態,我們用按位或 | 來點亮,用按位與 & 來檢測。”


一、從最樸素的方法開始

問題目標

給定一個小寫字母字符串,比如:"programming"

我們想找出:哪些字母 出現過不止一次(如:r, g, m

我們第一時間想到的,是記錄每個字母出現的次數:

  • 可以用數組 int count[26] 來記錄每個字母是否出現

  • 索引通過 'c' - 'a' 映射到 0~25(參考:數據結構:找出字符串中重復的字符(Finding Duplicates in a String)——使用哈希表 -CSDN博客

這很好用,但我們接著問:

二、如果只關心“有沒有出現過”,不關心“次數”,還能不能更省?

我們回顧需求:

  • 我不在乎你出現了幾次

  • 我只想知道你是不是已經來過一次

  • 如果再次遇到你,我就說你是重復字符

于是我們意識到:

我不需要記錄次數,只需要記錄「有沒有來過」

那我需要 26 個“是否來過”的記錄

想法:

bool seen[26] = {false};
  • 'a' 來了 → seen[0] = true

  • 'g' 來了 → seen[6] = true

  • 再次遇到 'g',發現 seen[6] == true → 它是重復的!

?這已經是一個優化:我們只用 26 個 bit(布爾量),不記錄次數了。

三、有沒有一種更“緊湊”的方式表示26個開關?

我們再想進一步優化空間:

如果我們有一個可以表示「26個狀態」的結構,我們就能把 seen[26] 合并成一個東西。

你也許會聯想到:

  • 一個 bool 變量本質上需要 1 字節(8位)

  • 26 個 bool 實際上占用了 26 字節 ≈ 208 bits,但其實我們只需要 26 個 bit 就夠了!

于是我們問:

? 有沒有什么東西,能存儲多個“是/否”狀態?

想一想數字的二進制!

例子:

int x = 0;  // 二進制:00000000 00000000 00000000 00000000

這不就是 32 個“是/否”開關嗎?每一位只能是 0 或 1!

我們現在重新定義:

一個 int 類型(32位),我們只用前 26 位,每一位表示一個字母是否已經出現過:

  • 變量 int checker = 0;

  • 每當字符 ch 出現時,我們設法標記它的“位置 i”為 1

  • 如果下一次這個位置已是 1 → 它是重復的!

我們用 1 << i 來構造這個“單個字母對應的位置”

字母位位置說明
'a'0bit 0 表示 a 是否出現
'b'1bit 1 表示 b 是否出現
'c'2bit 2 表示 c 是否出現
.........
'z'25bit 25 表示 z 是否出現

所以我們的問題變成了:

  • 有一個整型變量 int bitmask = 0;,代表 26 個字母的狀態

  • 每個小寫字母 'a''z',分別映射到第 0 位到第 25 位

  • 我想對某個字母做兩件事:

    1. 檢測它是否已經出現(對應的位是不是 1)

    2. 標記它出現過(把對應的位設為 1)


四、用一個整數的每一位表示一個字母是否出現

第一步:確定某個字符應該對應哪一位(位置)

我們先要知道:'c' 應該對應 bitmask 的哪一位?

用以下方式:

int pos = ch - 'a';  // 'a' = 0, 'b' = 1, ..., 'z' = 25
字符ASCII'ch' - 'a'位位置
'a'970第 0 位
'c'992第 2 位
'z'12225第 25 位

第二步:構造一個“掩碼”來訪問這一位

我們的問題是:“如何選中第 pos 位?”

我們用左移操作構造:

int mask = 1 << pos;

含義是:

  • 1 << pos 就是一個整數,只有第 pos 位是 1,其他全是 0

posmask(二進制)十進制
000000000 00000000 000000011
200000000 00000000 000001004
500000000 00000000 0010000032

第三步:判斷該字符是否出現過(讀位)

此時我們就可以“檢測”:

if ((bitmask & mask) != 0) {// 字符 ch 已經出現過了
}

解釋:

  • bitmask & mask

    • 如果該位是 1,結果就是 mask 本身(非 0)

    • 如果該位是 0,結果是 0

所以我們通過這個判斷該字符是否出現。

?第四步:標記該字符出現(寫位)

如果該位還沒有被設置,我們就“標記”它出現過:

bitmask = bitmask | mask;
//或者簡寫為:
bitmask |= mask;

這會把原來的 bitmask 中的第 pos 位設為 1,其他位保持不變。?

第五步:代碼實現?
1.?忽略非小寫字母字符:

    if (ch < 'a' || ch > 'z')continue;

2.?把當前字符映射為位索引:

int i = ch - 'a';  // 假設是小寫字母

?3. 構造一個掩碼,代表“我要檢查的位”:

int mask = 1 << i;  // 只把第 i 位設置為 1

4. 檢查是否已經來過:

if ((checker & mask) > 0) {// 說明這位之前已經是 1,重復了
}

5. 否則,設置該位為 1:

checker |= mask;

完整代碼實現(只用于小寫字母)

#include <iostream>
using namespace std;void findDuplicatesUsingBits(const char str[]) {int checker = 0;cout << "重復字符有:";for (int i = 0; str[i] != '\0'; i++) {char ch = str[i];if (ch < 'a' || ch > 'z')continue;  // 忽略非小寫字符int pos = ch - 'a';int mask = 1 << pos;if ((checker & mask) > 0) {cout << ch << " ";} else {checker |= mask;}}cout << endl;
}int main() {const char str[] = "programming";findDuplicatesUsingBits(str);return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/web/90424.shtml
繁體地址,請注明出處:http://hk.pswp.cn/web/90424.shtml
英文地址,請注明出處:http://en.pswp.cn/web/90424.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

DevOps 完整實現指南:從理論到實踐

DevOps 是一種集軟件開發&#xff08;Dev&#xff09;與 IT 運維&#xff08;Ops&#xff09;于一體的文化、實踐和工具鏈&#xff0c;旨在通過自動化流程、持續集成/持續交付&#xff08;CI/CD&#xff09;、基礎設施即代碼&#xff08;IaC&#xff09;和跨團隊協作&#xff0…

使用 5 種安全解決方案將 Android 短信導出為PDF

想要將安卓手機短信導出為 PDF 格式&#xff0c;用于法律用途、情感表達或僅僅為了記錄&#xff1f;總之&#xff0c;您可以保存安卓手機短信并將其轉換為 PDF 格式&#xff0c;確保它們井然有序&#xff0c;方便打印。快來獲取解決方案吧&#xff01;第 1 部分&#xff1a;如何…

再談fpga開發(fpga開發的幾個差異)

【 聲明&#xff1a;版權所有&#xff0c;歡迎轉載&#xff0c;請勿用于商業用途。 聯系信箱&#xff1a;feixiaoxing 163.com】學習嵌入式的同學都知道&#xff0c;嵌入式一般分成這幾種chip&#xff0c;有51&#xff0c;有stm32 mcu&#xff0c;有soc&#xff0c;有dsp&#…

Kafka運維實戰 11 - kafka查看消息的具體內容【實戰】

目錄kafka 消息查看1. 直接查看日志文件內容步驟&#xff1a;2. 使用 Kafka 工具查看日志主要參數說明常用命令&#xff1a;輸出說明&#xff1a;3. 注意事項kafka 消息日志文件詳解我們有時候遇到這樣的需求&#xff0c;需要查看下kafka消息的內容。 kafka 消息查看 查看 Ka…

【自動化測試】JMeter+Jenkins自動化接口與性能測試環境部署指南

環境準備與基礎配置 軟硬件環境要求 工具鏈安裝部署 工具鏈安裝部署涉及JDK、JMeter、Jenkins等核心組件,其在Linux與Windows環境下的安裝流程存在顯著差異,企業級部署需重點關注靜默安裝、權限控制及數據備份配置。以下從組件安裝差異、企業級部署要點及備份配置三方面展開…

三步實現Android系統級集成:預裝Google TTS + 默認引擎設置 + 語音包預緩存方案

在定制Android系統時&#xff0c;預裝Google TTS引擎并實現開箱即用的語音服務能顯著提升用戶體驗。本文將詳解預裝APK→設為默認引擎→語音包預緩存的實現方案&#xff0c;適用于ROM開發者或系統定制場景。分步實現方案 預裝Google TTS APK 預裝APK這里可以采用很多種方式&…

Python基礎學習第三課:數據結構與文件操作

以下是Python基礎學習第三課的完整內容&#xff0c;重點講解數據結構&#xff08;列表、字典、元組、集合&#xff09;和文件操作&#xff0c;通過實例演示如何高效管理和操作數據&#xff1a;Python基礎學習第三課&#xff1a;數據結構與文件操作一、課程目標1. 掌握四種核心數…

【PHP 流程控制完全指南】

PHP 流程控制完全指南&#x1f9e0; 一、什么是流程控制&#xff1f; 在編程中&#xff0c;流程控制是指控制程序執行順序的語句。它決定了代碼是“從上往下執行”&#xff0c;還是“根據條件跳轉”&#xff0c;或者“循環執行某些代碼”。 PHP 中的流程控制語句主要包括&#…

Kafka運維實戰 05 - kafka 消費者組和重平衡(Rebalance)

目錄什么是消費者組&#xff1f;消費者組如何工作&#xff1f;位移&#xff08;Offset&#xff09;消費者組的核心機制&#xff1a;重平衡&#xff08;Rebalance&#xff09;觸發條件重平衡影響在消息隊列&#xff08;如 Kafka&#xff09;的世界里&#xff0c;消費者組是實現高…

Mysql-UDF提權

UDF&#xff08;User Defined Function&#xff09; 是用戶自定義函數&#xff0c;是 MySQL 支持的一種機制&#xff0c;可以通過 C語言寫動態鏈接庫&#xff08;.so / .dll&#xff09;&#xff0c;然后讓 MySQL 調用這些函數&#xff0c;調用方式與一般系統自帶的函數相同&am…

車規級CANFD芯片在汽車車身控制方案中的應用解析

摘要&#xff1a;隨著汽車電子技術的不斷發展&#xff0c;汽車車身控制系統對信息傳輸的效率、可靠性及抗干擾能力等要求日益提高。車規級CANFD芯片作為一種先進的通信芯片&#xff0c;憑借其高速率、高可靠性以及強大的抗干擾能力&#xff0c;成為汽車車身控制系統中的關鍵組件…

docker desktop 訪問 https://registry-1.docker.io/v2/ 報錯問題解決

win11 docker desktop 配置國內鏡像加速器 1、win11管理員運行powershell notepad "$env:APPDATA\Docker\config.json"2、配置以下內容保存 {"registry-mirrors": ["https://hub-mirror.c.163.com","https://docker.mirrors.ustc.edu.cn&qu…

LLaMA-Factory微調教程1:LLaMA-Factory安裝及使用

文章目錄 環境搭建 LLaMA-Factory 安裝教程 模型大小選擇 環境搭建 Windows系統 RTX 4060 Ti(16G顯存) python 3.10 cuda=12.6 cudnn torch== 2.7.1+cu126 torchvision==0.22.1+cu126 torchaudio== 2.7.1+cu126 PS C:\Users\18098> nvidia-smi Tue Jul 22 01:52:19 2025 +…

Oracle數據庫索引性能機制深度解析:從數據結構到企業實踐的系統性知識體系

一、數據檢索的根本問題與索引產生的必然性 1.1、數據檢索的本質挑戰 在理解Oracle索引的性能優勢之前&#xff0c;必須回到數據檢索的根本問題。當面對海量數據時&#xff0c;傳統的線性搜索&#xff08;Sequential Search&#xff09;面臨著不可調和的性能瓶頸。這種瓶頸源于…

c#面向對象程序設計

一、面向對象與面向過程的核心區別&#xff08;概念鋪墊&#xff09;代碼背景開篇對比了兩種編程范式&#xff1a;面向過程&#xff08;PP&#xff09;&#xff1a;按步驟分解問題&#xff08;如 “輸入長→輸入寬→計算面積”&#xff09;&#xff1b;面向對象&#xff08;OOP…

Kylin V10 4070安裝nvidia驅動+CUDA+docker安裝

目錄 1.系統版本信息 2.安裝nvidia驅動 3.CUDA安裝 4.docker離線安裝 1.系統版本信息 查看一下系統版本&#xff0c;命令為&#xff1a; cat /etc/kylin-release2.安裝nvidia驅動 編輯/usr/lib/modprobe.d/dist-blacklist.conf文件 blacklist nvidiafb加#號注釋掉 添加…

首家!數巔AskBI通過中國信通院數據分析智能體專項測試

近日&#xff0c;在中國信息通信研究院組織的數據分析智能體&#xff08;Data Agent&#xff09;專項測試中&#xff0c;數巔生成式分析智能體AskBI順利完成專項測試的全部內容。《數據智能體技術要求》標準及測試簡介中國信通院云計算與大數據研究所依托中國通信標準化協會大數…

一些Avalonia與WPF內容的對應關系和不同用法

UIElement、FrameworkElement和ControlWPFAvaloniaUIElementControlFrameworkElementControlControlTemplatedControl在 WPF 中&#xff0c;通過繼承 Control 類來創建新的模板控件&#xff0c;而在 Avalonia 中&#xff0c;從 TemplatedControl 繼承。在 WPF 中&#xff0c;通…

【REACT18.x】CRA+TS+ANTD5.X封裝自定義的hooks復用業務功能

模擬react中的hooks方法&#xff0c;實現自定義的hooks來封裝我們需要重復使用的組件&#xff0c;來優化代碼。這種hooks也是利用了react的原生hooks來實現我們需要的特定業務&#xff0c;可以返回任何我們需要的值&#xff0c;也可以不返回值&#xff0c;作為一個副作用方法使…

Vue CSR 到 Nuxt 3 SSR 遷移:技術實現與問題解決實錄

1. 遷移動機與技術選型1.1 CSR 架構的局限性 基于 Vue 3 和 Vite 構建的客戶端渲染 (CSR) 單頁應用 (SPA) 提供了良好的開發體驗和用戶交互流暢性。但是其核心局限在于&#xff1a;搜索引擎優化 (SEO)&#xff1a;初始 HTML 響應僅包含一個根 div 元素&#xff0c;實際內容由 J…