সমস্ত অক্ষর অনন্য কিনা তা নির্ধারণের জন্য কিছুটা ভেক্টরের ব্যবহার ব্যাখ্যা করুন


150

বিট ভেক্টর কীভাবে এটি করতে কাজ করবে (বিট ভেক্টরগুলির সাথে খুব বেশি পরিচিত নয়) তা সম্পর্কে আমি বিভ্রান্ত। এখানে দেওয়া কোড। কেউ কি আমাকে এই মাধ্যমে যেতে পারে?

public static boolean isUniqueChars(String str) {
    int checker = 0;
    for (int i = 0; i < str.length(); ++i) {
        int val = str.charAt(i) - 'a';
        if ((checker & (1 << val)) > 0) return false;
        checker |= (1 << val);
    }
    return true;
}

বিশেষত, কি checkerকরছেন?


এটি জাভাতে রয়েছে তবে যদি সি / সি ++ এর মতো কিছু থাকে তবে এটি আমার জন্য আরও সহায়ক more
ব্যবহারকারী 1136342

101
এই কোডটি কোড সাক্ষাত্কার ক্র্যাকিং থেকে নেওয়া হয়েছে
দেজেল

2
তুমি কি এটা পরীক্ষা করেছ? দেখে মনে হচ্ছে এটি 'ক' অক্ষরগুলি ডুপ্লিকেট করতে ব্যর্থ হবে যেহেতু এটি 0 তে সেট করা হয়েছে এবং বাম-স্থানান্তর এটি এখনও 0 এ রাখবে
রিজ

3
দ্রষ্টব্যটি নিম্ন বর্ণের অ্যাজে জন্য ব্যবহৃত হয়, এর অর্থ আমরা এটি 26 টি অক্ষরের অনুলিপি খুঁজে পেতে ব্যবহার করছি। সুতরাং, 32 টি বিট গ্রহণ করা এখানে ব্যবহার করা যেতে পারে। যদি পরিসীমাটি আরও বড় হত তবে সমাধানটি কার্যকর হবে না।
a3.14_Infinity

1
লোকেরা যেখানে ভুল করে তা হ'ল তারা বাম শিফট অপারেটর সিনট্যাক্সের সাথে বিভ্রান্ত হয় - এটি 1 যা x (= str.charAt (i) - 'a') দ্বারা বাম দিকে স্থানান্তরিত করে না x এর বিটটি 1 স্থান বামে স্থানান্তরিত করে।
ন্যানোসফট

উত্তর:


100

int checkerবিটের স্টোরেজ হিসাবে এখানে ব্যবহৃত হয়। পূর্ণসংখ্যার মান প্রতিটি intবিটকে একটি পতাকা হিসাবে বিবেচনা করা যেতে পারে, সুতরাং শেষ পর্যন্ত বিটের একটি অ্যারে (পতাকা)। আপনার কোডের প্রতিটি বিট বিটের সূচকযুক্ত অক্ষরটি স্ট্রিংয়ে পাওয়া গেছে কিনা তা জানিয়েছে। আপনি পরিবর্তে একই কারণে বিট ভেক্টর ব্যবহার করতে পারেন int। তাদের মধ্যে দুটি পার্থক্য রয়েছে:

  • আকারintআকার স্থির থাকে, সাধারণত 4 বাইট যার অর্থ 8 * 4 = 32 বিট (পতাকা)। বিট ভেক্টর সাধারণত বিভিন্ন আকারের হতে পারে বা আপনার কনস্ট্রাক্টরের আকারটি নির্দিষ্ট করা উচিত।

  • এপিআই । বিট ভেক্টরগুলির সাহায্যে আপনার কোড পড়া সহজ হবে, সম্ভবত এটির মতো:

    vector.SetFlag(4, true); // set flag at index 4 as true

    জন্য intআপনি নিম্ন স্তরের বিট যুক্তিবিজ্ঞান কোড আছে হবে:

    checker |= (1 << 5); // set flag at index 5 to true

এছাড়াও সম্ভবত intকিছুটা দ্রুত হতে পারে, কারণ বিটগুলি সহ অপারেশনগুলি খুব নিম্ন স্তরের এবং সিপিইউ দ্বারা যেমনটি হয় তেমন কার্যকর করা যায়। বিটভেক্টর পরিবর্তে কিছুটা কম ক্রিপ্টিক কোড লেখার অনুমতি দেয় এটি আরও বেশি পতাকা সঞ্চয় করতে পারে।

ভবিষ্যতের রেফারেন্সের জন্য: বিট ভেক্টর বিটসেট বা বিটআরে হিসাবেও পরিচিত। বিভিন্ন ভাষা / প্ল্যাটফর্মের জন্য এই ডেটা কাঠামোর কয়েকটি লিঙ্ক এখানে রয়েছে:


জাভাতে কি বিটভেক্টর ক্লাস থাকে? আমি এটিতে কোনও নথি খুঁজে পাইনি!
দেজেল

আকারের স্থির আকার রয়েছে যা 32 বিট। এর অর্থ কি এটি কেবল 32 টি অক্ষরের অনন্য পরীক্ষা করতে পারে? আমার পরীক্ষা আছে যে, এই ফাংশনটি "abcdefgZZ" পরীক্ষা করতে পারে মিথ্যা, তবে "abcdefg @@" সত্য ফিরে আসে।
tli2020

1
গুগল আমাকে এখানে নিয়ে গেছে। @ ডিজেল এখানে জাভা ডেটা কাঠামো যা আপনি ব্যবহার করতে পারেন তা: docs.oracle.com/javase/7/docs/api/java/util/BitSet.html । আশা করি এটি কাউকে আন্তঃলিবিগুলির মধ্য দিয়ে ভ্রমণে সহায়তা করবে।
nattyddubbs

@ নাট্টিডাবস, ধন্যবাদ, আমি উত্তরে এই এবং আরও কয়েকটি লিঙ্ক যুক্ত করেছি
স্নোবার

222

আমি যে পুস্তকটি পড়ছি তা থেকে আপনি এই কোডটি পেয়েছিলেন এমন এক সন্দেহজনক সন্দেহ আমার কাছে রয়েছে ... এখানে কোডটি নিজেই অপারেটরদের মতো প্রায় গুপ্ত নয় - | =, &, এবং << যা সাধারণত ব্যবহৃত হয় না আমাদের সাধারণ মানুষ- লেখক প্রক্রিয়াটি ব্যাখ্যা করতে বা এখানে জড়িত প্রকৃত যান্ত্রিক কী কী তা অতিরিক্ত সময় নেওয়ার জন্য বিরক্ত করেননি। শুরুতে এই থ্রেডটিতে পূর্ববর্তী উত্তর নিয়ে আমি সন্তুষ্ট ছিলাম তবে কেবল একটি বিমূর্ত স্তরে। আমি এটিতে ফিরে এসেছি কারণ আমি অনুভব করেছি যে এখানে আরও দৃ concrete় ব্যাখ্যা হওয়া দরকার - একজনের অভাব আমাকে সর্বদা অস্বস্তিকর অনুভূতিতে ফেলে দেয়।

এই অপারেটরটি << একটি বাম বিটওয়াস শিফটার এটি number সংখ্যা বা অপারেন্ডের বাইনারি উপস্থাপনা নেয় এবং ডানদিকে অপারেন্ড বা সংখ্যা দ্বারা নির্দিষ্ট অনেকগুলি স্থান কেবল বাইনারিগুলিতে দশমিক সংখ্যার মতো সরিয়ে দেয় over আমরা বেস 2-দিয়ে গুণ করছি যখন আমরা উপরে যাই তবে অনেকগুলি স্থান 10-এর ভিত্তিতে নয়- সুতরাং ডানদিকে সংখ্যাটি হ'ল ঘরের এবং বামে সংখ্যাটি 2 এর বেস একাধিক।

এই অপারেটর | = অপারেন্ডটি বাম দিকে নিয়ে যান বা এটি অপারেন্ডের সাথে ডান দিকে- এবং এটির একটি - '&' এবং এর অপরেন্দ্রগুলির বিট এবং বামে এটি ডানদিকে।

সুতরাং আমাদের এখানে যা আছে তা একটি হ্যাশ টেবিল যা 32 বার বিট বাইনারি সংখ্যায় চেকার হিসাবে প্রতিবার চেকার হয়ে যায় বা checker |= (1 << val)এটির সাথে সম্পর্কিত বিট এটির সাথে সেট করা হচ্ছে এমন একটি অক্ষরের নির্ধারিত বাইনারি মান সহ সংরক্ষণ করা হচ্ছে। চরিত্রটির মান চেকার ( checker & (1 << val)) > 0) এর সাথে রয়েছে - এটি যদি 0 এর চেয়ে বেশি হয় তবে আমরা জানতে পারি আমাদের একটি ডুপ রয়েছে- কারণ দুটি অভিন্ন বিট সত্যকে সেট করা হয়েছে এবং একসাথে সত্য বা '1' 'ফিরে আসবে।

এখানে 26 টি বাইনারি জায়গা রয়েছে যার প্রত্যেকটি একটি ছোট হাতের অক্ষরের সাথে মিলে যায় - লেখক বলেছিলেন স্ট্রিংটিতে কেবল ছোট হাতের অক্ষর রয়েছে is এবং এটি কারণ আমাদের কাছে কেবলমাত্র 6 টি (32 বিট পূর্ণসংখ্যার মধ্যে) গ্রাস করতে বাকি আছে- এবং আমাদের থেকে একটি সংঘর্ষ পেতে

00000000000000000000000000000001 a 2^0

00000000000000000000000000000010 b 2^1

00000000000000000000000000000100 c 2^2

00000000000000000000000000001000 d 2^3

00000000000000000000000000010000 e 2^4

00000000000000000000000000100000 f 2^5

00000000000000000000000001000000 g 2^6

00000000000000000000000010000000 h 2^7

00000000000000000000000100000000 i 2^8

00000000000000000000001000000000 j 2^9

00000000000000000000010000000000 k 2^10

00000000000000000000100000000000 l 2^11

00000000000000000001000000000000 m 2^12

00000000000000000010000000000000 n 2^13

00000000000000000100000000000000 o 2^14

00000000000000001000000000000000 p 2^15

00000000000000010000000000000000 q 2^16

00000000000000100000000000000000 r 2^17

00000000000001000000000000000000 s 2^18

00000000000010000000000000000000 t 2^19

00000000000100000000000000000000 u 2^20

00000000001000000000000000000000 v 2^21

00000000010000000000000000000000 w 2^22

00000000100000000000000000000000 x 2^23

00000001000000000000000000000000 y 2^24

00000010000000000000000000000000 z 2^25

সুতরাং, একটি ইনপুট স্ট্রিং 'আজ্যা' এর জন্য, আমরা ধাপে ধাপে সরানো

স্ট্রিং 'এ'

a      =00000000000000000000000000000001
checker=00000000000000000000000000000000

checker='a' or checker;
// checker now becomes = 00000000000000000000000000000001
checker=00000000000000000000000000000001

a and checker=0 no dupes condition

স্ট্রিং 'আজ'

checker=00000000000000000000000000000001
z      =00000010000000000000000000000000

z and checker=0 no dupes 

checker=z or checker;
// checker now becomes 00000010000000000000000000000001  

স্ট্রিং 'আজি'

checker= 00000010000000000000000000000001    
y      = 00000001000000000000000000000000 

checker and y=0 no dupes condition 

checker= checker or y;
// checker now becomes = 00000011000000000000000000000001

স্ট্রিং 'আজ্যা'

checker= 00000011000000000000000000000001
a      = 00000000000000000000000000000001

a and checker=1 we have a dupe

এখন, এটি একটি সদৃশ ঘোষণা করে


@ আইভান-টিচি আপনি কি এটি পরীক্ষা করেছেন? দেখে মনে হচ্ছে এটি 'ক' অক্ষরগুলি ডুপ্লিকেট করতে ব্যর্থ হবে যেহেতু এটি 0 তে সেট করা হয়েছে এবং বাম-স্থানান্তর এটি এখনও 0 এ রাখবে
রিজ

1
@ রিজ নো, সর্বদা '1' দিয়ে শুরু হয়, আলগোরিদম চিঠির উপর ভিত্তি করে 1 টি স্থানান্তরিত করে। সুতরাং, 'ক' অক্ষরটি একবার এলে তা 1 হবে, যা (.... 000001)।
টেলর হলিডে

2
@ ইভান ম্যান, আমিও একই কথা ভাবছিলাম। এমনকি নির্বাচিত উত্তর অপারেটরদের সম্পর্কে ব্যাখ্যা দেয় না। বিস্তারিত তথ্যের জন্য আপনাকে ধন্যবাদ।
ওয়াওউ

আমার কি উপরোক্ত অনন্য চেকিংটি কেবল সাজানো অক্ষর সেট (abcd ... z) দিয়ে কাজ করা উচিত? (বিসিএডি ...) সহ নয়
আবদুল রশিদ

"আমি এখানে ছাপছি" একই বইটি পড়ে আপনি এই কোডটি পেয়েছেন বলে আমার মনে সন্দেহ ছড়িয়ে পড়েছে :) আমাকে হাসিয়ে দিয়েছে
মেরুদণ্ড

39

আমার মনে হয় এই সমস্ত উত্তরগুলি কীভাবে এটির কাজ করে তা ব্যাখ্যা করে তবে আমি কিছু ভেরিয়েবলের নাম পরিবর্তন করে, আরও কিছু যুক্ত করে এবং এতে মন্তব্য যুক্ত করে কীভাবে আরও ভাল দেখলাম তার জন্য আমার ইনপুট দেওয়ার মতো অনুভব করেছি:

public static boolean isUniqueChars(String str) {

    /*
    checker is the bit array, it will have a 1 on the character index that
    has appeared before and a 0 if the character has not appeared, you
    can see this number initialized as 32 0 bits:
    00000000 00000000 00000000 00000000
     */
    int checker = 0;

    //loop through each String character
    for (int i = 0; i < str.length(); ++i) {
        /*
        a through z in ASCII are charactets numbered 97 through 122, 26 characters total
        with this, you get a number between 0 and 25 to represent each character index
        0 for 'a' and 25 for 'z'

        renamed 'val' as 'characterIndex' to be more descriptive
         */
        int characterIndex = str.charAt(i) - 'a'; //char 'a' would get 0 and char 'z' would get 26

        /*
        created a new variable to make things clearer 'singleBitOnPosition'

        It is used to calculate a number that represents the bit value of having that 
        character index as a 1 and the rest as a 0, this is achieved
        by getting the single digit 1 and shifting it to the left as many
        times as the character index requires
        e.g. character 'd'
        00000000 00000000 00000000 00000001
        Shift 3 spaces to the left (<<) because 'd' index is number 3
        1 shift: 00000000 00000000 00000000 00000010
        2 shift: 00000000 00000000 00000000 00000100
        3 shift: 00000000 00000000 00000000 00001000

        Therefore the number representing 'd' is
        00000000 00000000 00000000 00001000

         */
        int singleBitOnPosition = 1 << characterIndex;

        /*
        This peforms an AND between the checker, which is the bit array
        containing everything that has been found before and the number
        representing the bit that will be turned on for this particular
        character. e.g.
        if we have already seen 'a', 'b' and 'd', checker will have:
        checker = 00000000 00000000 00000000 00001011
        And if we see 'b' again:
        'b' = 00000000 00000000 00000000 00000010

        it will do the following:
        00000000 00000000 00000000 00001011
        & (AND)
        00000000 00000000 00000000 00000010
        -----------------------------------
        00000000 00000000 00000000 00000010

        Since this number is different than '0' it means that the character
        was seen before, because on that character index we already have a 
        1 bit value
         */
        if ((checker & singleBitOnPosition) > 0) {
            return false;
        }

        /* 
        Remember that 
        checker |= singleBitOnPosition is the same as  
        checker = checker | singleBitOnPosition
        Sometimes it is easier to see it expanded like that.

        What this achieves is that it builds the checker to have the new 
        value it hasnt seen, by doing an OR between checker and the value 
        representing this character index as a 1. e.g.
        If the character is 'f' and the checker has seen 'g' and 'a', the 
        following will happen

        'f' = 00000000 00000000 00000000 00100000
        checker(seen 'a' and 'g' so far) = 00000000 00000000 00000000 01000001

        00000000 00000000 00000000 00100000
        | (OR)
        00000000 00000000 00000000 01000001
        -----------------------------------
        00000000 00000000 00000000 01100001

        Therefore getting a new checker as 00000000 00000000 00000000 01100001

         */
        checker |= singleBitOnPosition;
    }
    return true;
}

2
দুর্দান্ত ব্যাখ্যা। ধন্যবাদ!
হরমিগাস

পরিষ্কার ব্যাখ্যা..হয় ধন্যবাদ আপনাকে
प्रभाकर এ

দুর্দান্ত ব্যাখ্যা। সহজে বোধগম্য. আপনাকে ধন্যবাদ
অনিল কুমার

সে একজন সেরা
ভ্লাদিমির নবোকভ

মন্তব্যগুলি আবিষ্কার করার কারণেই এটি।
মিঃ সূর্য ঝা

30

আমিও ধরে নিয়েছি যে আপনার উদাহরণটি কোড সাক্ষাত্কার ক্র্যাকিংয়ের বই থেকে এসেছে এবং আমার উত্তর এই প্রসঙ্গে সম্পর্কিত।

সমস্যাটি সমাধান করার জন্য এই অ্যালগরিদমটি ব্যবহার করার জন্য, আমাদের স্বীকার করতে হবে যে আমরা কেবলমাত্র একটি টু জেড (ছোট হাতের অক্ষর) থেকে অক্ষরগুলি পাস করতে যাচ্ছি।

যেহেতু কেবলমাত্র 26 টি অক্ষর রয়েছে এবং এগুলি এনকোডিং টেবিলটিতে সঠিকভাবে সাজানো হয় আমরা ব্যবহার করি, এটি আমাদের গ্যারান্টি দেয় যে সমস্ত সম্ভাব্য পার্থক্য str.charAt(i) - 'a'32 এর চেয়ে নিকৃষ্ট হবে (ইন্টি ভেরিয়েবলের আকার)checker )।

যেমন স্নোবার দ্বারা ব্যাখ্যা করা হয়েছে, আমরা এটি ব্যবহার করতে চলেছি checker বিটের অ্যারে হিসাবে চলকটি । উদাহরণস্বরূপ একটি পদ্ধতির আসুন:

চল বলি str equals "test"

  • প্রথম পাস (i = t)

পরীক্ষক == 0 (00000000000000000000000000000000)

In ASCII, val = str.charAt(i) - 'a' = 116 - 97 = 19
What about 1 << val ?
1          == 00000000000000000000000000000001
1 << 19    == 00000000000010000000000000000000
checker |= (1 << val) means checker = checker | (1 << val)
so checker = 00000000000000000000000000000000 | 00000000000010000000000000000000
checker == 524288 (00000000000010000000000000000000)
  • দ্বিতীয় পাস (i = ই)

পরীক্ষক == 524288 (00000000000010000000000000000000)

val = 101 - 97 = 4
1          == 00000000000000000000000000000001
1 << 4     == 00000000000000000000000000010000
checker |= (1 << val) 
so checker = 00000000000010000000000000000000 | 00000000000000000000000000010000
checker == 524304 (00000000000010000000000000010000)

এবং এইভাবে .. যতক্ষণ না আমরা শর্তের মাধ্যমে একটি নির্দিষ্ট চরিত্রের জন্য চেকারে ইতিমধ্যে সেট বিট খুঁজে পাই

(checker & (1 << val)) > 0

আশা করি এটা সাহায্য করবে


2
বাকি আইএমও এর চেয়ে অনেক বেশি ভাল ব্যাখ্যা তবে একটি জিনিস যা আমি এখনও পাইনি তা হ'ল চেকার = 00000000000010000000000000000000000 | 00000000000000000000000000010000 তেমন বিটওয়াইস নয় | = অপারেটর। যে একটি মান বা অন্য চয়ন না? এটি কেন ব্যবহার করে সেট এবং উভয় বিট?
কোডক্র্যাক

@ কোডক্র্যাক আপনি বলেছেন যে এটি সামান্য দিকের OR OR এটি বিট অ্যারে স্তরে নয় বিট স্তরে তুলনা করে। দ্রষ্টব্য: ইনট বিট অ্যারে
মিউজিকম্যান

7

ইতিমধ্যে উপরে সরবরাহ করা বেশ কয়েকটি দুর্দান্ত উত্তর রয়েছে। তাই আমি ইতিমধ্যে যা কিছু বলেছি তা পুনরাবৃত্তি করতে চাই না। আমি উপরোক্ত প্রোগ্রামটির সাথে দু'টি জিনিস যুক্ত করতে চাইছিলাম কারণ আমি ঠিক একই প্রোগ্রামের মাধ্যমে কাজ করেছি এবং বেশ কয়েকটি প্রশ্ন ছিল কিন্তু কিছু সময় ব্যয় করার পরে, আমি এই প্রোগ্রামটি সম্পর্কে আরও স্পষ্টতা পেয়েছি।

সবার আগে "পরীক্ষক" অক্ষরটি ট্র্যাক করতে ব্যবহৃত হয় যা ইতিমধ্যে স্ট্রিংয়ে ট্র্যাক করা হয়েছে যাতে কোনও অক্ষর পুনরাবৃত্তি হচ্ছে কিনা তা দেখার জন্য।

এখন "চেকার" একটি ইনট ডাটা টাইপ তাই এটিতে কেবল 32 বিট বা 4 বাইট থাকতে পারে (প্ল্যাটফর্মের উপর নির্ভর করে) সুতরাং এই প্রোগ্রামটি কেবলমাত্র 32 টি অক্ষরের ব্যাপ্তির মধ্যে থাকা একটি অক্ষরের জন্য সঠিকভাবে কাজ করতে পারে। এ কারণেই, এই প্রোগ্রামটি কেবলমাত্র ছোট ছোট অক্ষরের জন্য এই প্রোগ্রামটি চালিত করতে প্রতিটি অক্ষর থেকে 'ক' বিয়োগ করে। তবে আপনি যদি নিম্ন এবং উচ্চতর অক্ষরের মিশ্রণ করেন তবে এটি কার্যকর হবে না।

যাইহোক, আপনি যদি প্রতিটি অক্ষর থেকে 'ক' বিয়োগ করেন না (নীচের বিবৃতিটি দেখুন) তবে এই প্রোগ্রামটি কেবলমাত্র বড় অক্ষরের অক্ষরের সাথে কেবল স্ট্রিং বা স্ট্রিংয়ের জন্য সঠিকভাবে কাজ করবে। সুতরাং উপরের প্রোগ্রামের ক্ষেত্রটি কেবল ছোট ছোট অক্ষর থেকে বড় হাতের অক্ষরেও বেড়ে যায় তবে সেগুলি একসাথে মিশানো যায় না।

int val = str.charAt(i) - 'a'; 

তবে আমি বিটওয়াইস অপারেশন ব্যবহার করে একটি জেনেরিক প্রোগ্রাম লিখতে চেয়েছিলাম যা উচ্চতর ক্ষেত্রে, ছোট হাতের অক্ষর, সংখ্যা বা কোনও বিশেষ চরিত্র সম্পর্কে চিন্তা না করে কোনও ASCII অক্ষরের জন্য কাজ করা উচিত। এটি করার জন্য, আমাদের "পরীক্ষক" 256 টি অক্ষর (ASCII অক্ষর সেট আকার) সংরক্ষণ করার জন্য যথেষ্ট বড় হওয়া উচিত। তবে জাভাতে কোনও ইনট কাজ করবে না কারণ এটি কেবল 32 বিট সংরক্ষণ করতে পারে। সুতরাং নীচের প্রোগ্রামে, আমি জেডিকে উপলভ্য বিটসেট ক্লাস ব্যবহার করছি যা কোনও বিটসেট অবজেক্ট ইনস্ট্যান্ট করার সময় কোনও ব্যবহারকারীর সংজ্ঞায়িত আকার পাস করতে পারে।

এখানে একটি প্রোগ্রাম যা বিটওয়াইস অপারেটর ব্যবহার করে উপরের প্রোগ্রামটির মতো একই কাজ করে তবে এই প্রোগ্রামটি ASCII অক্ষর সেট থেকে কোনও অক্ষরের সাথে একটি স্ট্রিংয়ের জন্য কাজ করবে।

public static boolean isUniqueStringUsingBitVectorClass(String s) {

    final int ASCII_CHARACTER_SET_SIZE = 256;

    final BitSet tracker = new BitSet(ASCII_CHARACTER_SET_SIZE);

    // if more than  256 ASCII characters then there can't be unique characters
    if(s.length() > 256) {
        return false;
    }

    //this will be used to keep the location of each character in String
    final BitSet charBitLocation = new BitSet(ASCII_CHARACTER_SET_SIZE);

    for(int i = 0; i < s.length(); i++) {

        int charVal = s.charAt(i);
        charBitLocation.set(charVal); //set the char location in BitSet

        //check if tracker has already bit set with the bit present in charBitLocation
        if(tracker.intersects(charBitLocation)) {
            return false;
        }

        //set the tracker with new bit from charBitLocation
        tracker.or(charBitLocation);

        charBitLocation.clear(); //clear charBitLocation to store bit for character in the next iteration of the loop

    }

    return true;

}

1
আমি এই সমাধানটি খুঁজছিলাম, তবে দুটি বিটসেট ভেরিয়েবলের প্রয়োজন নেই। শুধু ট্র্যাকারই যথেষ্ট। লুপ কোডের জন্য আপডেট হয়েছে: for(int i = 0; i < s.length(); i++) { int charVal = s.charAt(i); if(tracker.get(charVal)) { return false; } tracker.set(charVal); }
জাম্ব্রো

7

ইভানের উত্তর উপরে পড়া সত্যিই আমাকে সাহায্য করেছিল, যদিও আমি এটিকে কিছুটা আলাদাভাবে ব্যাখ্যা করব।

<<মধ্যে (1 << val)একটি বিট নাড়াচাড়া অপারেটর। এটি গ্রহণ করে 1(যা বাইনারি 000000001হিসাবে আপনি পূর্ববর্তী জিরো হিসাবে পছন্দ হিসাবে / মেমরির দ্বারা বরাদ্দ করা হয় হিসাবে উপস্থাপিত হয় ) এবং এটি valফাঁকা জায়গায় বাম দিকে স্থানান্তর করে। যেহেতু আমরা কেবল অজকে ধরে নিচ্ছি এবং aপ্রতিবার বিয়োগ করে চলেছি, তাই প্রতিটি অক্ষরের মান 0-25 হবে, যা চিঠিটির সূচক হবে ডান দিক থেকে checkerপূর্ণসংখ্যার বুলিয়ান উপস্থাপনায়, যেহেতু আমরা 1বাম দিকে বাম দিকে সরিয়ে নেবchecker val সময়ে সময়ে ।

প্রতিটি চেক শেষে, আমরা |=অপারেটর দেখতে । এই দুটি বাইনারি সংখ্যার সংযোজন, প্রতিস্থাপন সব 0's এর সাথে 1এর একটি 1করে সূচিতে পারেন প্রতীক বিদ্যমান। এখানে, এর অর্থ হ'ল যে যেখানেই 1উপস্থিত রয়েছে (1 << val), 1তার অনুলিপি করা হবে checker, তবে checkerবিদ্যমান বিদ্যমান 1 টির সমস্ত সংরক্ষণ করা হবে।

আপনি সম্ভবত অনুমান করতে পারেন, 1সত্য হিসাবে একটি বুলিয়ান পতাকা হিসাবে এখানে একটি ফাংশন। যখন আমরা এটি পরীক্ষা করে দেখি যে কোনও চরিত্রটি ইতিমধ্যে স্ট্রিংয়ে উপস্থাপিত হয়েছে কিনা, আমরা তুলনা করি checker, যা এই মুহুর্তে 1ইতিমধ্যে প্রতিনিধিত্ব করা অক্ষরের সূচীতে বুলিয়ান পতাকা ( মান) এর একটি অ্যারে, মূলত একটি অ্যারে যা রয়েছে তার সাথে 1বর্তমান চরিত্রের সূচকে একটি পতাকা সহ বুলিয়ান মানগুলি ।

&অপারেটর এই চেক সম্পাদন করে। এর মতোই |=, &অপারেটর 1 কেবল তখনই অনুলিপি করতে পারে যদি উভয় অপারেন্ডের সূচকটিতে একটি 1থাকে। সুতরাং, মূলত, আগে থেকেই উপস্থিত শুধুমাত্র পতাকার checkerযে মধ্যে প্রতিনিধিত্ব করা হয় (1 << val)ওভার কপি করা হবে। এই ক্ষেত্রে, এর অর্থ কেবল যদি বর্তমান চরিত্রটি ইতিমধ্যে উপস্থাপিত হয়ে থাকে 1তবে ফলাফলের যে কোনও জায়গায় উপস্থিত থাকতে পারে checker & (1 << val)। এবং যদি 1সেই অপারেশনের ফলাফলের মধ্যে যদি কোনও স্থান উপস্থিত থাকে তবে প্রত্যাবর্তিত বুলিয়ানটির মান value> 0 এবং পদ্ধতিটি মিথ্যা প্রত্যাবর্তন করে।

এই হল, আমি অনুমান করছি কেন বিট ভেক্টর এছাড়াও বলা হয় বিট অ্যারে । কারণ, যদিও তারা অ্যারে ডেটা প্রকারের নয়, বুলিয়ান পতাকা সংরক্ষণের জন্য অ্যারেগুলি যেভাবে ব্যবহার করা হয় তার অনুরূপ ব্যবহার করা যেতে পারে।


1
খুব সহায়ক, আপনার জাভা তথ্য ছিটানোর জন্য ধন্যবাদ।
বাচ্চিরি তৌফিক আবদাররহমান

4

সরল ব্যাখ্যা (নীচে জেএস কোড সহ)

  • মেশিন কোড প্রতি ইন্টিজার ভেরিয়েবল একটি 32-বিট অ্যারে হয়
  • সমস্ত বিট ওয়াইজ অপারেশন হয় 32-bit
  • তারা ওএস / সিপিইউ আর্কিটেকচারের ভাষা বা ভাষাটির নির্বাচিত নম্বর সিস্টেমের DEC64জ্যোতিস্টিক , যেমন জেএসের জন্য।
  • এই অনুলিপি গবেষনার পদ্ধতির অনুরূপ আকার 32 একটি অ্যারের অক্ষর সংরক্ষণকারী যেখানে, আমরা সেট 0thযদি আমরা খুঁজে সূচক a, স্ট্রিং 1stজন্যb & তাই।
  • স্ট্রিংয়ের একটি সদৃশ চরিত্রটির সংশ্লিষ্ট বিটটি দখল করা হবে বা এই ক্ষেত্রে 1 তে সেট করা থাকবে set
  • ইভান ইতিমধ্যে ব্যাখ্যা করেছে : এই সূচক গণনাটি আগের উত্তরটিতে কীভাবে কাজ করে

ক্রিয়াকলাপের সংক্ষিপ্তসার:

  • সঞ্চালন মধ্যবর্তী অপারেশন checker&index চরিত্রের
  • অভ্যন্তরীণভাবে উভয় হয় Int-32-Arrays
  • এই 2 এর মধ্যে এটি কিছুটা বিজ্ঞানসম্পন্ন অপারেশন।
  • ifঅপারেশন আউটপুট ছিল চেক1
  • যদি output == 1
    • checkerপরিবর্তনশীল হয়েছে সেই নির্দিষ্ট সূচক তম বিট উভয় অ্যারের সেট
    • সুতরাং এটি একটি সদৃশ।
  • যদি output == 0
    • এই চরিত্রটি এখনও পাওয়া যায় নি
    • চরিত্রের & এর মধ্যে একটি ওআর অপারেশন করুনcheckerindex
    • এর মাধ্যমে সূচক-বিটকে আপডেট করা হচ্ছে 1
    • আউটপুট বরাদ্দ করুন checker

অনুমিতি:

  • আমরা ধরে নিয়েছি আমরা সমস্ত ছোট হাতের অক্ষর পেয়ে যাব
  • এবং, সেই আকার 32 যথেষ্ট
  • অত: পর, আমরা আমাদের সূচক বেড়ে চলেছে থেকে শুরু করে 96 রেফারেন্স হিসেবে বিন্দু বিবেচনা করা ASCII কোড aহল97

নীচে জাভাস্ক্রিপ্ট উত্স কোড দেওয়া হল ।

function checkIfUniqueChars (str) {

    var checker = 0; // 32 or 64 bit integer variable 

    for (var i = 0; i< str.length; i++) {
        var index = str[i].charCodeAt(0) - 96;
        var bitRepresentationOfIndex = 1 << index;

        if ( (checker & bitRepresentationOfIndex) > 1) {
            console.log(str, false);
            return false;
        } else {
            checker = (checker | bitRepresentationOfIndex);
        }
    }
    console.log(str, true);
    return true;
}

checkIfUniqueChars("abcdefghi");  // true
checkIfUniqueChars("aabcdefghi"); // false
checkIfUniqueChars("abbcdefghi"); // false
checkIfUniqueChars("abcdefghii"); // false
checkIfUniqueChars("abcdefghii"); // false

নোট করুন যে জেএসে, পূর্ণসংখ্যা 64৪ বিটের সত্ত্বেও, সর্বদা 32 বিটে কিছুটা বুদ্ধিমান অপারেশন করা হয়।

উদাহরণ: যদি স্ট্রিংটি হয় aa:

// checker is intialized to 32-bit-Int(0)
// therefore, checker is
checker= 00000000000000000000000000000000

i = 0

str[0] is 'a'
str[i].charCodeAt(0) - 96 = 1

checker 'AND' 32-bit-Int(1) = 00000000000000000000000000000000
Boolean(0) == false

// So, we go for the '`OR`' operation.

checker = checker OR 32-bit-Int(1)
checker = 00000000000000000000000000000001

i = 1

str[1] is 'a'
str[i].charCodeAt(0) - 96 = 1

checker= 00000000000000000000000000000001
a      = 00000000000000000000000000000001

checker 'AND' 32-bit-Int(1) = 00000000000000000000000000000001
Boolean(1) == true
// We've our duplicate now

3

কোড লাইন লাইন ভেঙে ফেলা যাক।

int চেকার = 0; আমরা একটি চেকার চালু করছি যা আমাদের সদৃশ মানগুলি খুঁজতে সহায়তা করবে।

int val = str.charAt (i) - 'ক'; আমরা স্ট্রিংয়ের 'I অবস্থান' তে অক্ষরের ASCII মান পাচ্ছি এবং এটিকে 'ক' এর ASCII মান দিয়ে বিয়োগ করছি। যেহেতু অনুমান করা হয় যে স্ট্রিংটি কেবলমাত্র কম অক্ষর, তাই অক্ষরের সংখ্যা 26 টি সীমাবদ্ধ He হেস, 'ভাল' এর মান সর্বদা> = 0 থাকবে।

যদি ((চেকার & (1 << ভাল))> 0) মিথ্যা ফিরে আসে;

পরীক্ষক | = (1 << ভাল);

এখন এটি জটিল অংশ। আমাদের "abcda" স্ট্রিং সহ একটি উদাহরণ বিবেচনা করতে দিন। এটি আদর্শভাবে মিথ্যা প্রত্যাবর্তন করা উচিত।

লুপ পুনরাবৃত্তির জন্য 1:

পরীক্ষক: 000000000000000000000000000000

ভাল: 97-97 = 0

1 << 0: 000000000000000000000000000001

পরীক্ষক এবং (1 << ভাল): 000000000000000000000000000000000000 নয়> 0

সুতরাং পরীক্ষক: 000000000000000000000000000001

লুপ পুনরাবৃত্তির জন্য 2:

পরীক্ষক: 000000000000000000000000000001

ভাল: 98-97 = 1

1 << 0: 00000000000000000000000000001010

পরীক্ষক এবং (1 << ভাল): 000000000000000000000000000000000000 নয়> 0

সুতরাং পরীক্ষক: 00000000000000000000000000001111

লুপ পুনরাবৃত্তির জন্য 3:

পরীক্ষক: 00000000000000000000000000001111

ভাল: 99-97 = 0

1 << 0: 000000000000000000000000000100

পরীক্ষক এবং (1 << ভাল): 000000000000000000000000000000000000 নয়> 0

সুতরাং পরীক্ষক: 0000000000000000000000000001111

লুপ পুনরাবৃত্তির জন্য 4:

পরীক্ষক: 0000000000000000000000000001111

ভাল: 100-97 = 0

1 << 0: 000000000000000000000000001000

পরীক্ষক এবং (1 << ভাল): 000000000000000000000000000000000000 নয়> 0

সুতরাং পরীক্ষক: 00000000000000000000000000001111

লুপ পুনরাবৃত্তির জন্য 5:

পরীক্ষক: 00000000000000000000000000111111

ভাল: 97-97 = 0

1 << 0: 000000000000000000000000000001

পরীক্ষক এবং (1 << ভাল): 00000000000000000000000000000000011> 0

সুতরাং মিথ্যা প্রত্যাবর্তন।


ভাল: 99-97 = 0 হতে হবে ভাল: 99-97 = 2 এবং ভাল: 100-97 = 0 হওয়া উচিত 3
ব্রোসেফ

2
public static void main (String[] args)
{
    //In order to understand this algorithm, it is necessary to understand the following:

    //int checker = 0;
    //Here we are using the primitive int almost like an array of size 32 where the only values can be 1 or 0
    //Since in Java, we have 4 bytes per int, 8 bits per byte, we have a total of 4x8=32 bits to work with

    //int val = str.charAt(i) - 'a';
    //In order to understand what is going on here, we must realize that all characters have a numeric value
    for (int i = 0; i < 256; i++)
    {
        char val = (char)i;
        System.out.print(val);
    }

    //The output is something like:
    //             !"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\]^_`abcdefghijklmnopqrstuvwxyz{|}~ ¡¢£¤¥¦§¨©ª«¬­®¯°±²³´µ¶·¸¹º»¼½¾¿ÀÁÂÃÄÅÆÇÈÉÊËÌÍÎÏÐÑÒÓÔÕÖ×ØÙÚÛÜÝÞßàáâãäåæçèéêëìíîïðñòóôõö÷øùúûüýþÿ
    //There seems to be ~15 leading spaces that do not copy paste well, so I had to use real spaces instead

    //To only print the characters from 'a' on forward:
    System.out.println();
    System.out.println();

    for (int i=0; i < 256; i++)
    {
        char val = (char)i;
        //char val2 = val + 'a'; //incompatible types. required: char found: int
        int val2 = val + 'a';  //shift to the 'a', we must use an int here otherwise the compiler will complain
        char val3 = (char)val2;  //convert back to char. there should be a more elegant way of doing this.
        System.out.print(val3);
    }

    //Notice how the following does not work:
    System.out.println();
    System.out.println();

    for (int i=0; i < 256; i++)
    {
        char val = (char)i;
        int val2 = val - 'a';
        char val3 = (char)val2;
        System.out.print(val3);
    }
    //I'm not sure why this spills out into 2 lines:
    //EDIT I cant seem to copy this into stackoverflow!

    System.out.println();
    System.out.println();

    //So back to our original algorithm:
    //int val = str.charAt(i) - 'a';
    //We convert the i'th character of the String to a character, and shift it to the right, since adding shifts to the right and subtracting shifts to the left it seems

    //if ((checker & (1 << val)) > 0) return false;
    //This line is quite a mouthful, lets break it down:
    System.out.println(0<<0);
    //00000000000000000000000000000000
    System.out.println(0<<1);
    //00000000000000000000000000000000
    System.out.println(0<<2);
    //00000000000000000000000000000000
    System.out.println(0<<3);
    //00000000000000000000000000000000
    System.out.println(1<<0);
    //00000000000000000000000000000001
    System.out.println(1<<1);
    //00000000000000000000000000000010 == 2
    System.out.println(1<<2);
    //00000000000000000000000000000100 == 4
    System.out.println(1<<3);
    //00000000000000000000000000001000 == 8
    System.out.println(2<<0);
    //00000000000000000000000000000010 == 2
    System.out.println(2<<1);
    //00000000000000000000000000000100 == 4
    System.out.println(2<<2);
    // == 8
    System.out.println(2<<3);
    // == 16
    System.out.println("3<<0 == "+(3<<0));
    // != 4 why 3???
    System.out.println(3<<1);
    //00000000000000000000000000000011 == 3
    //shift left by 1
    //00000000000000000000000000000110 == 6
    System.out.println(3<<2);
    //00000000000000000000000000000011 == 3
    //shift left by 2
    //00000000000000000000000000001100 == 12
    System.out.println(3<<3);
    // 24

    //It seems that the -  'a' is not necessary
    //Back to if ((checker & (1 << val)) > 0) return false;
    //(1 << val means we simply shift 1 by the numeric representation of the current character
    //the bitwise & works as such:
    System.out.println();
    System.out.println();
    System.out.println(0&0);    //0
    System.out.println(0&1);       //0
    System.out.println(0&2);          //0
    System.out.println();
    System.out.println();
    System.out.println(1&0);    //0
    System.out.println(1&1);       //1
    System.out.println(1&2);          //0
    System.out.println(1&3);             //1
    System.out.println();
    System.out.println();
    System.out.println(2&0);    //0
    System.out.println(2&1);       //0   0010 & 0001 == 0000 = 0
    System.out.println(2&2);          //2  0010 & 0010 == 2
    System.out.println(2&3);             //2  0010 & 0011 = 0010 == 2
    System.out.println();
    System.out.println();
    System.out.println(3&0);    //0    0011 & 0000 == 0
    System.out.println(3&1);       //1  0011 & 0001 == 0001 == 1
    System.out.println(3&2);          //2  0011 & 0010 == 0010 == 2, 0&1 = 0 1&1 = 1
    System.out.println(3&3);             //3 why?? 3 == 0011 & 0011 == 3???
    System.out.println(9&11);   // should be... 1001 & 1011 == 1001 == 8+1 == 9?? yay!

    //so when we do (1 << val), we take 0001 and shift it by say, 97 for 'a', since any 'a' is also 97

    //why is it that the result of bitwise & is > 0 means its a dupe?
    //lets see..

    //0011 & 0011 is 0011 means its a dupe
    //0000 & 0011 is 0000 means no dupe
    //0010 & 0001 is 0011 means its no dupe
    //hmm
    //only when it is all 0000 means its no dupe

    //so moving on:
    //checker |= (1 << val)
    //the |= needs exploring:

    int x = 0;
    int y = 1;
    int z = 2;
    int a = 3;
    int b = 4;
    System.out.println("x|=1 "+(x|=1));  //1
    System.out.println(x|=1);     //1
    System.out.println(x|=1);      //1
    System.out.println(x|=1);       //1
    System.out.println(x|=1);       //1
    System.out.println(y|=1); // 0001 |= 0001 == ?? 1????
    System.out.println(y|=2); // ??? == 3 why??? 0001 |= 0010 == 3... hmm
    System.out.println(y);  //should be 3?? 
    System.out.println(y|=1); //already 3 so... 0011 |= 0001... maybe 0011 again? 3?
    System.out.println(y|=2); //0011 |= 0010..... hmm maybe.. 0011??? still 3? yup!
    System.out.println(y|=3); //0011 |= 0011, still 3
    System.out.println(y|=4);  //0011 |= 0100.. should be... 0111? so... 11? no its 7
    System.out.println(y|=5);  //so we're at 7 which is 0111, 0111 |= 0101 means 0111 still 7
    System.out.println(b|=9); //so 0100 |= 1001 is... seems like xor?? or just or i think, just or... so its 1101 so its 13? YAY!

    //so the |= is just a bitwise OR!
}

public static boolean isUniqueChars(String str) {
    int checker = 0;
    for (int i = 0; i < str.length(); ++i) {
        int val = str.charAt(i) - 'a';  //the - 'a' is just smoke and mirrors! not necessary!
        if ((checker & (1 << val)) > 0) return false;
        checker |= (1 << val);
    }
    return true;
}

public static boolean is_unique(String input)
{
    int using_int_as_32_flags = 0;
    for (int i=0; i < input.length(); i++)
    {
        int numeric_representation_of_char_at_i = input.charAt(i);
        int using_0001_and_shifting_it_by_the_numeric_representation = 1 << numeric_representation_of_char_at_i; //here we shift the bitwise representation of 1 by the numeric val of the character
        int result_of_bitwise_and = using_int_as_32_flags & using_0001_and_shifting_it_by_the_numeric_representation;
        boolean already_bit_flagged = result_of_bitwise_and > 0;              //needs clarification why is it that the result of bitwise & is > 0 means its a dupe?
        if (already_bit_flagged)
            return false;
        using_int_as_32_flags |= using_0001_and_shifting_it_by_the_numeric_representation;
    }
    return true;
}

0

পূর্ববর্তী পোস্টগুলি কোড ব্লক কী করে তা ভালভাবে ব্যাখ্যা করে এবং আমি বিটসেট জাভা ডেটা কাঠামোটি ব্যবহার করে আমার সাধারণ সমাধানটি যুক্ত করতে চাই:

private static String isUniqueCharsUsingBitSet(String string) {
  BitSet bitSet =new BitSet();
    for (int i = 0; i < string.length(); ++i) {
        int val = string.charAt(i);
        if(bitSet.get(val)) return "NO";
        bitSet.set(val);
    }
  return "YES";
}

0
Line 1:   public static boolean isUniqueChars(String str) {
Line 2:      int checker = 0;
Line 3:      for (int i = 0; i < str.length(); ++i) {
Line 4:          int val = str.charAt(i) - 'a';
Line 5:          if ((checker & (1 << val)) > 0) return false;
Line 6:         checker |= (1 << val);
Line 7:      }
Line 8:      return true;
Line 9:   }

জাভাস্ক্রিপ্ট ব্যবহার করে যেভাবে বুঝলাম। ইনপুট ধরে নিচ্ছিvar inputChar = "abca"; //find if inputChar has all unique characters

চল শুরু করি

Line 4: int val = str.charAt(i) - 'a';

উপরের লাইনের ইনপুটচারে প্রথম অক্ষরের বাইনারি মান সন্ধান করে যা a , a = 97 ascii হয়, তারপরে 97 কে বাইনারি রূপান্তরিত করে 1100001 হয়

জাভাস্ক্রিপ্টে উদাহরণ: "a".charCodeAt().toString(2) 1100001 প্রদান করে

checker = 0 // বাইনারি 32 বিট উপস্থাপনা = 0000000000000000000000000

checker = 1100001 | checker; // পরীক্ষক 1100001 হয়ে যায় (32 বিট উপস্থাপনায় এটি 000000000 হয়ে যায় ..... 00001100001)

তবে আমি চাই যে আমার বিটমাস্ক ( int checker) কেবলমাত্র একটি বিট সেট করবে, তবে চেকারটি 1100001

Line 4:          int val = str.charAt(i) - 'a';

এখন উপরের কোডটি কাজে আসবে। আমি কেবল সর্বদা 97 বিয়োগ করি (একটি এর ASCII ভাল)

val = 0; // 97 - 97  Which is  a - a
val = 1; // 98 - 97 Which is b - a
val = 1;  // 99 - 97 Which is c - a

valপুনরায় সেট করা হয় যা ব্যবহার করতে দেয়

লাইভ 5 এবং লাইন 6 ভাল উত্তর দেওয়া হয়েছে ইভান উত্তর


0

কেবলমাত্র যদি কেউ বিট ভেক্টর ব্যবহার করে কোনও স্ট্রিংয়ের অনন্য অক্ষরের সমতুল্য কোটলিন খুঁজছেন

fun isUnique(str: String): Boolean {
    var checker = 0
    for (i in str.indices) {
        val bit = str.get(i) - 'a'
        if (checker.and(1 shl bit) > 0) return false
        checker = checker.or(1 shl bit)
    }
    return true
}

রেফ: https://www.programiz.com/kotlin-programming/bitwise

আমাদের সাইট ব্যবহার করে, আপনি স্বীকার করেছেন যে আপনি আমাদের কুকি নীতি এবং গোপনীয়তা নীতিটি পড়েছেন এবং বুঝতে পেরেছেন ।
Licensed under cc by-sa 3.0 with attribution required.