主頁 > 區塊鏈 > 從兩個字串中洗掉一個字符子集后檢查兩個字串是否相等

從兩個字串中洗掉一個字符子集后檢查兩個字串是否相等

2022-03-29 18:15:23 區塊鏈

我最近遇到了這個問題:

您有兩個字串 s1 和 s2,它們完全由小寫字母“a”到“r”組成,需要處理一系列查詢。每個查詢提供從“a”到“r”的小寫英文字母子集。對于每個查詢,確定 s1 和 s2 在僅限于查詢中的字母時是否相等。s1 和 s2 最多可以包含 10^5 個字符,最多可以有 10^5 個查詢。

例如,如果 s1 是“aabcd”而 s2 是“caabd”,并且要求您處理帶有子集“ac”的查詢,那么 s1 變為“aac”,而 s2 變為“caa”。這些不匹配,因此查詢將回傳 false。

通過執行以下操作,我能夠在 O(N^2) 時間內解決此問題: 對于每個查詢,我通過遍歷兩個字串(一次一個字符)檢查 s1 和 s2 是否相等,跳過不相等的字符位于允許字符的子集中,并檢查 s1 和 s2 中的“允許”字符是否匹配。如果在某些時候,字符不匹配,則字串不相等。否則,當僅限于查詢中的字母時,s1 和 s2 相等。每個查詢需要 O(N) 時間來處理,并且有 N 個查詢,總共需要 O(N^2) 時間。

然而,有人告訴我有一種方法可以比 O(N^2) 更快地解決這個問題,使用位運算子和一些聰明的數學。有誰知道如何做到這一點?

uj5u.com熱心網友回復:

第一個明顯的加速是確保你的集合成員測驗是 O(1)。為此,有幾個選項:

  • 將每個字母表示為一個位——現在每個字符都是一個 18 位值,只設定了一個位。允許的字符集現在是這些位 OR 在一起的掩碼,您可以使用按位與來測驗字符的成員資格;
  • 或者,您可以有一個 18 值陣列并按字符對其進行索引(c - 'a'將給出 0 到 17 之間的值)。成員資格測驗基本上是陣列查找的成本(并且您可以通過不進行減法來節省操作 - 而只是使陣列更大并直接按字符索引。

思想實驗

下一個潛在的加速是認識到在兩個字串中出現的次數不完全相同的任何字符將立即成為失敗的匹配。您可以使用可以在 O(N) 時間內完成的直方圖計算兩個字串中的所有字符頻率。這樣,如果這樣的字符出現在查詢中,您可以修剪搜索空間,并且可以在恒定時間內對此進行測驗。

當然,這對真正的壓力測驗沒有幫助,因為它可以保證所有可能的字母在兩個字串中都具有匹配的頻率。那么,你會怎么做呢?

好吧,您通過認識到對于字串 1中字符的任何位置x和字串 2 中該字符的某個位置將是有效匹配來擴展上述前提(相同數量的字符x出現在兩個字串中,直到它們各自的位置) ,那么在這些位置之前的任何其他字符的總數必須相等。對于任何不正確的角色,它不可能與 character 兼容x


概念

讓我們從一種稱為記憶的技術開始考慮這一點,您可以利用預先計算或部分計算的資訊并從中獲得大量資訊。所以考慮兩個這樣的字串:

a  b  a  a  c  d  e   |   e  a  b  a  c  a  d 

你可以在這里做些什么有用的事情?那么,為什么不存盤每個字母的部分計數總和:

          a  b  a  a  c  d  e  |  e  a  b  a  c  a  d
         ----------------------|----------------------
freq(a) = 1  1  2  3  3  3  3  |  0  1  1  2  2  3  3
freq(b) = 0  1  1  1  1  1  1  |  0  0  1  1  1  1  1
freq(c) = 0  0  0  0  1  1  1  |  0  0  0  0  1  1  1
freq(d) = 0  0  0  0  0  1  1  |  0  0  0  0  0  0  1
freq(e) = 0  0  0  0  0  0  1  |  1  1  1  1  1  1  1

這會占用大量記憶體,但別擔心——我們稍后會處理。相反,花時間吸收我們實際在做的事情。

查看上表,我們在這些字串的每個位置都有兩個字串的運行字符總數。

"ab"現在讓我們通過顯示匹配查詢和不匹配查詢的示例來看看我們的匹配規則是如何作業的"acd"

  1. 對于"ab"

               a  b  a  a  c  d  e  |  e  a  b  a  c  a  d
              ----------------------|----------------------
     freq(a) = 1  1  2  3  3  3  3  |  0  1  1  2  2  3  3
     freq(b) = 0  1  1  1  1  1  1  |  0  0  1  1  1  1  1
               ^  ^  ^  ^                 ^  ^  ^     ^
    

    我們掃描頻率陣列,直到我們在查詢中找到我們的一個字母。我在^上面標記的位置。如果您洗掉所有未標記的列,您將看到剩余的列在兩邊都匹配。所以這是一場比賽。

  2. 對于"acd"

               a  b  a  a  c  d  e  |  e  a  b  a  c  a  d
              ----------------------|----------------------
     freq(a) = 1  1  2  3  3  3  3  |  0  1  1  2  2  3  3
     freq(c) = 0  0  0  0  1  1  1  |  0  0  0  0  1  1  1
     freq(d) = 0  0  0  0  0  1  1  |  0  0  0  0  0  0  1
               ^     ^  #  #  ^           ^     ^  #  #  ^
    

    Here, all columns are matching except those marked with #.


Putting it together

All right so you can see how this works, but you may wondering about the runtime, because those examples above seem to be doing even more scanning than you were doing before!

Here's where things get interesting, and where our character frequency counts really kick in.

First, observe what we're actually doing on those marked columns. For any one character that we care about (for example, the 'a'), we're looking for only the positions in both strings where its count matches, and then we're comparing these two columns to see what other values match. This gives us a set of all other characters that are valid when used with 'a'. And of course, 'a' itself is also valid.

And what was our very first optimization? A bitset -- an 18-bit value the represents valid characters. You can now use this. For the two columns in each string, you set a 1 for characters with matching counts and a zero for characters with non-matching counts. If you process every single pair of matching 'a' values in this manner, what you get is a bunch of sets that they work with. And you can keep a running "master" set that represents the intersection of these -- you just intersect it with each intermediate set you calculate, which is a single bitwise-AND.

By the time you reach the end of both strings, you have performed a O(N) search and you examined 18 rows any time you encountered 'a'. And the result was the set of all characters that work with 'a'.

Now repeat for the other characters, one at a time. Every time it's a O(N) scan as above and you wind up with the set of all other characters that work with that the one you're processing.

After processing all these rows you now have an array containing 18 values representing the set of all characters that work with any one character. The operation took O(18N) time and O(18N) storage.


Query

Since you now have an array where for each character you have all possible characters that work with it, you simply look up each character in the query, and you intersect their sets (again, with bitwise-AND). A further intersection is required by using the set of all characters present in the query. That prunes off all characters that are not relevant.

This leaves you with a value which, for all values in the query, represents the set of all values that can result in a matching string. So if this value is then equal to the query then you have a match. Otherwise, you don't.

This is the part that is now fast. It has essentially reduced your query tests to constant time. However, the original indexing did cost us a lot of memory. What can be done about that?


Dynamic Programming

Is it really necessary to allocate all that storage for our frequency arrays?

Well actually, no. It was useful as a visual tool by laying out our counts in tabular form, and to explain the method conceptually but actually a lot of those values are not very useful most of the time and it sure made the method seem a bit complicated.

The good news is we can compute our master sets at the same time as computing character counts, without needing to store any frequency arrays. Remember that when we're computing the counts we use a histogram which is as simple as having one small 18-value array array where you say count[c] = 1 (if c is a character or an index derived from that character). So we could save a ton of memory if we just do the following:

Processing the set (mask) of all compatible characters for character c:

  1. Initialize the mask for character c to all 1s (mask[c] = (1 << 18) - 1) -- this represents all characters are currently compatible. Initialize a character histogram (count) to all zero.

  2. Walk through string 1 until you reach character c. For every character x you encounter along the way, increase its count in the histogram (count[x] ).

  3. Walk through string 2 until you reach character c. For every character x you encounter along the way, decrease its count in the histogram (count[x]--).

  4. Construct a 'good' set where any character that currently has a zero-count has a 1-bit, otherwise 0-bit. Intersect this with the current mask for c (using bitwise-AND): mask[c] &= good

  5. Continue from step 2 until you have reached the end of both strings. If you reach the end of one of the strings prematurely, then the character count does not match and so you set the mask for this character to zero: mask[c] = 0

  6. 對每個字符從 1 開始重復,直到完成所有字符。

上面,我們基本上具有相同的 O(18N) 時間復雜度,除了我們有絕對最小的額外存盤——每個字符只有一個計數陣列和一個掩碼陣列。

結合上述技術來真正快速地解決看似復雜的組合問題通常被稱為動態編程我們將問題簡化為一個真值表,該表表示與任何單個字符一起使用的所有可能字符。時間復雜度相對于字串的長度保持線性,并且僅根據可能的字符數進行縮放。

這是上面用 C 破解的演算法:https ://godbolt.org/z/PxzYvGs8q

uj5u.com熱心網友回復:

令 RESTRICT(s,q) 為字串 s 對集合 q 中字母的限制。

如果 q 包含兩個以上的字母,則可以從所有字串 RESTRICT(s,q ij ) 重構完整的字串 RESTRICT(s,q),其中 q ij是q 中的一對字母。

因此,RESTRICT(s1,q) = RESTRICT(s2,q) 當且僅當 RESTRICT(s1,q ij ) = RESTRICT(s2,q ij ) 對于 q 中的所有對 q ij

由于您被限制為 18 個字母,因此只有 153 個字母對,或者只有 171 個基本的單字母或雙字母查詢。

如果您預先計算這 171 個查詢的結果,那么您可以通過組合它們的結果來回答任何其他更復雜的查詢,而根本不需要檢查字串。

轉載請註明出處,本文鏈接:https://www.uj5u.com/qukuanlian/451712.html

標籤:算法 数学

上一篇:熊貓分組和日志添加

下一篇:如何通過重復最后一位來增加整數?

標籤雲
其他(157675) Python(38076) JavaScript(25376) Java(17977) C(15215) 區塊鏈(8255) C#(7972) AI(7469) 爪哇(7425) MySQL(7132) html(6777) 基礎類(6313) sql(6102) 熊猫(6058) PHP(5869) 数组(5741) R(5409) Linux(5327) 反应(5209) 腳本語言(PerlPython)(5129) 非技術區(4971) Android(4554) 数据框(4311) css(4259) 节点.js(4032) C語言(3288) json(3245) 列表(3129) 扑(3119) C++語言(3117) 安卓(2998) 打字稿(2995) VBA(2789) Java相關(2746) 疑難問題(2699) 细绳(2522) 單片機工控(2479) iOS(2429) ASP.NET(2402) MongoDB(2323) 麻木的(2285) 正则表达式(2254) 字典(2211) 循环(2198) 迅速(2185) 擅长(2169) 镖(2155) 功能(1967) .NET技术(1958) Web開發(1951) python-3.x(1918) HtmlCss(1915) 弹簧靴(1913) C++(1909) xml(1889) PostgreSQL(1872) .NETCore(1853) 谷歌表格(1846) Unity3D(1843) for循环(1842)

熱門瀏覽
  • JAVA使用 web3j 進行token轉賬

    最近新學習了下區塊鏈這方面的知識,所學不多,給大家分享下。 # 1. 關于web3j web3j是一個高度模塊化,反應性,型別安全的Java和Android庫,用于與智能合約配合并與以太坊網路上的客戶端(節點)集成。 # 2. 準備作業 jdk版本1.8 引入maven <dependency> < ......

    uj5u.com 2020-09-10 03:03:06 more
  • 以太坊智能合約開發框架Truffle

    前言 部署智能合約有多種方式,命令列的瀏覽器的渠道都有,但往往跟我們程式員的風格不太相符,因為我們習慣了在IDE里寫了代碼然后打包運行看效果。 雖然現在IDE中已經存在了Solidity插件,可以撰寫智能合約,但是部署智能合約卻要另走他路,沒辦法進行一個快捷的部署與測驗。 如果團隊管理的區塊節點多、 ......

    uj5u.com 2020-09-10 03:03:12 more
  • 谷歌二次驗證碼成為區塊鏈專用安全碼,你怎么看?

    前言 谷歌身份驗證器,前些年大家都比較陌生,但隨著國內互聯網安全的加強,它越來越多地出現在大家的視野中。 比較廣泛接觸的人群是國際3A游戲愛好者,游戲盜號現象嚴重+國外賬號安全應用廣泛,這類游戲一般都會要求用戶系結名為“兩步驗證”、“雙重驗證”等,平臺一般都推薦用谷歌身份驗證器。 后來區塊鏈業務風靡 ......

    uj5u.com 2020-09-10 03:03:17 more
  • 密碼學DAY1

    目錄 ##1.1 密碼學基本概念 密碼在我們的生活中有著重要的作用,那么密碼究竟來自何方,為何會產生呢? 密碼學是網路安全、資訊安全、區塊鏈等產品的基礎,常見的非對稱加密、對稱加密、散列函式等,都屬于密碼學范疇。 密碼學有數千年的歷史,從最開始的替換法到如今的非對稱加密演算法,經歷了古典密碼學,近代密 ......

    uj5u.com 2020-09-10 03:03:50 more
  • 密碼學DAY1_02

    目錄 ##1.1 ASCII編碼 ASCII(American Standard Code for Information Interchange,美國資訊交換標準代碼)是基于拉丁字母的一套電腦編碼系統,主要用于顯示現代英語和其他西歐語言。它是現今最通用的單位元組編碼系統,并等同于國際標準ISO/IE ......

    uj5u.com 2020-09-10 03:04:50 more
  • 密碼學DAY2

    ##1.1 加密模式 加密模式:https://docs.oracle.com/javase/8/docs/api/javax/crypto/Cipher.html ECB ECB : Electronic codebook, 電子密碼本. 需要加密的訊息按照塊密碼的塊大小被分為數個塊,并對每個塊進 ......

    uj5u.com 2020-09-10 03:05:42 more
  • NTP時鐘服務器的特點(京準電子)

    NTP時鐘服務器的特點(京準電子) NTP時鐘服務器的特點(京準電子) 京準電子官V——ahjzsz 首先對時間同步進行了背景介紹,然后討論了不同的時間同步網路技術,最后指出了建立全球或區域時間同步網存在的問題。 一、概 述 在通信領域,“同步”概念是指頻率的同步,即網路各個節點的時鐘頻率和相位同步 ......

    uj5u.com 2020-09-10 03:05:47 more
  • 標準化考場時鐘同步系統推進智能化校園建設

    標準化考場時鐘同步系統推進智能化校園建設 標準化考場時鐘同步系統推進智能化校園建設 安徽京準電子科技官微——ahjzsz 一、背景概述隨著教育事業的快速發展,學校建設如雨后春筍,隨之而來的學校教育、管理、安全方面的問題成了學校管理人員面臨的最大的挑戰,這些問題同時也是學生家長所擔心的。為了讓學生有更 ......

    uj5u.com 2020-09-10 03:05:51 more
  • 位元幣入門

    引言 位元幣基本結構 位元幣基礎知識 1)哈希演算法 2)非對稱加密技術 3)數字簽名 4)MerkleTree 5)哪有位元幣,有的是UTXO 6)位元幣挖礦與共識 7)區塊驗證(共識) 總結 引言 上一篇我們已經知道了什么是區塊鏈,此篇說一下區塊鏈的第一個應用——位元幣。其實先有位元幣,后有的區塊 ......

    uj5u.com 2020-09-10 03:06:15 more
  • 北斗對時服務器(北斗對時設備)電力系統應用

    北斗對時服務器(北斗對時設備)電力系統應用 北斗對時服務器(北斗對時設備)電力系統應用 京準電子科技官微(ahjzsz) 中國北斗衛星導航系統(英文名稱:BeiDou Navigation Satellite System,簡稱BDS),因為是目前世界范圍內唯一可以大面積提供免費定位服務的系統,所以 ......

    uj5u.com 2020-09-10 03:06:20 more
最新发布
  • web3 產品介紹:metamask 錢包 使用最多的瀏覽器插件錢包

    Metamask錢包是一種基于區塊鏈技術的數字貨幣錢包,它允許用戶在安全、便捷的環境下管理自己的加密資產。Metamask錢包是以太坊生態系統中最流行的錢包之一,它具有易于使用、安全性高和功能強大等優點。 本文將詳細介紹Metamask錢包的功能和使用方法。 一、 Metamask錢包的功能 數字資 ......

    uj5u.com 2023-04-20 08:46:47 more
  • Hyperledger Fabric 使用 CouchDB 和復雜智能合約開發

    在上個實驗中,我們已經實作了簡單智能合約實作及客戶端開發,但該實驗中智能合約只有基礎的增刪改查功能,且其中的資料管理功能與傳統 MySQL 比相差甚遠。本文將在前面實驗的基礎上,將 Hyperledger Fabric 的默認資料庫支持 LevelDB 改為 CouchDB 模式,以實作更復雜的資料... ......

    uj5u.com 2023-04-16 07:28:31 more
  • .NET Core 波場鏈離線簽名、廣播交易(發送 TRX和USDT)筆記

    Get Started NuGet You can run the following command to install the Tron.Wallet.Net in your project. PM> Install-Package Tron.Wallet.Net 配置 public reco ......

    uj5u.com 2023-04-14 08:08:00 more
  • DKP 黑客分析——不正確的代幣對比率計算

    概述: 2023 年 2 月 8 日,針對 DKP 協議的閃電貸攻擊導致該協議的用戶損失了 8 萬美元,因為 execute() 函式取決于 USDT-DKP 對中兩種代幣的余額比率。 智能合約黑客概述: 攻擊者的交易:0x0c850f,0x2d31 攻擊者地址:0xF38 利用合同:0xf34ad ......

    uj5u.com 2023-04-07 07:46:09 more
  • Defi開發簡介

    Defi開發簡介 介紹 Defi是去中心化金融的縮寫, 是一項旨在利用區塊鏈技術和智能合約創建更加開放,可訪問和透明的金融體系的運動. 這與傳統金融形成鮮明對比,傳統金融通常由少數大型銀行和金融機構控制 在Defi的世界里,用戶可以直接從他們的電腦或移動設備上訪問廣泛的金融服務,而不需要像銀行或者信 ......

    uj5u.com 2023-04-05 08:01:34 more
  • solidity簡單的ERC20代幣實作

    // SPDX-License-Identifier: GPL-3.0 pragma solidity >=0.7.0 <0.9.0; import "hardhat/console.sol"; //ERC20 同質化代幣,每個代幣的本質或性質都是相同 //ETH 是原生代幣,它不是ERC20代幣, ......

    uj5u.com 2023-03-21 07:56:29 more
  • solidity 參考型別修飾符memory、calldata與storage 常量修飾符C

    在solidity語言中 參考型別修飾符(參考型別為存盤空間不固定的數值型別) memory、calldata與storage,它們只能修飾參考型別變數,比如字串、陣列、位元組等... memory 適用于方法傳參、返參或在方法體內使用,使用完就會清除掉,釋放記憶體 calldata 僅適用于方法傳參 ......

    uj5u.com 2023-03-08 07:57:54 more
  • solidity注解標簽

    在solidity語言中 注釋符為// 注解符為/* 內容*/ 或者 是 ///內容 注解中含有這幾個標簽給予我們使用 @title 一個應該描述合約/介面的標題 contract, library, interface @author 作者的名字 contract, library, interf ......

    uj5u.com 2023-03-08 07:57:49 more
  • 評價指標:相似度、GAS消耗

    【代碼注釋自動生成方法綜述】 這些評測指標主要來自機器翻譯和文本總結等研究領域,可以評估候選文本(即基于代碼注釋自動方法而生成)和參考文本(即基于手工方式而生成)的相似度. BLEU指標^[^?88^^?^]^:其全稱是bilingual evaluation understudy.該指標是最早用于 ......

    uj5u.com 2023-02-23 07:27:39 more
  • 基于NOSTR協議的“公有制”版本的Twitter,去中心化社交軟體Damus

    最近,一個幽靈,Web3的幽靈,在網路游蕩,它叫Damus,這玩意詮釋了什么叫做病毒式營銷,滑稽的是,一個Web3產品卻在Web2的產品鏈上瘋狂傳銷,各方大佬紛紛為其背書,到底發生了什么?Damus的葫蘆里,賣的是什么藥? 注冊和簡單實用 很少有什么產品在用戶注冊環節會有什么噱頭,但Damus確實出 ......

    uj5u.com 2023-02-05 06:48:39 more