किसी दिए गए रेंज में सभी संख्याओं के XOR का पता लगाएं


99

आपको एक बड़ी रेंज दी गई है [a, b] जहां 'a' और 'b' आमतौर पर 1 से 4,000,000,000 के बीच हो सकते हैं। आपको दिए गए रेंज में सभी संख्याओं के XOR का पता लगाना है।

TopCoder SRM में इस समस्या का उपयोग किया गया था। मैंने मैच में प्रस्तुत किए गए समाधानों में से एक को देखा और मैं यह पता लगाने में सक्षम नहीं हूं कि इसका काम कैसा है।

किसी को जीतने का हल समझाने में मदद मिल सकती है:

long long f(long long a) {
     long long res[] = {a,1,a+1,0};
     return res[a%4];
}

long long getXor(long long a, long long b) {
     return f(b)^f(a-1);
}

यहाँ, getXor()उत्तीर्ण श्रेणी [a, b] और "f ()" में सभी संख्या के xor की गणना करने का वास्तविक कार्य एक सहायक कार्य है।


मैंने आपके प्रश्न को थोड़ा संपादित किया। हमें कुछ कोड के बारे में बताने में कोई आपत्ति नहीं है, लेकिन हमें इसे हल करने के लिए अन्य तरीकों की नई सूची की आवश्यकता नहीं है। कि TopCoder को छोड़ दें।
केव

@ कोई बात नहीं! मैंने ऐसा इसलिए लिखा क्योंकि कुछ लोग पहले से लिखी हुई बात को समझाने के बजाय अपना रास्ता देना पसंद करते हैं। और कोई भी नया विचार कभी भी बेकार नहीं होता ...)
rajneesh2k10

इसके लिए a<=0, या के लिए अपरिभाषित व्यवहार है b<0long longएक हस्ताक्षरित प्रकार है, इसलिए x%4नकारात्मक जानकारी के लिए नकारात्मक (या 0) है । शायद आप चाहते हैं unsigned long long, और / या a & 3सरणी को अनुक्रमित करने के लिए?
पीटर कॉर्डेस

जवाबों:


152

यह एक बहुत चालाक समाधान है - यह इस तथ्य का फायदा उठाता है कि रनिंग एक्सओआर में परिणामों का एक पैटर्न है। f()समारोह से XOR कुल रन [0, एक] गणना करता है। 4-बिट संख्या के लिए इस तालिका पर एक नज़र डालें:

0000 <- 0  [a]
0001 <- 1  [1]
0010 <- 3  [a+1]
0011 <- 0  [0]
0100 <- 4  [a]
0101 <- 1  [1]
0110 <- 7  [a+1]
0111 <- 0  [0]
1000 <- 8  [a]
1001 <- 1  [1]
1010 <- 11 [a+1]
1011 <- 0  [0]
1100 <- 12 [a]
1101 <- 1  [1]
1110 <- 15 [a+1]
1111 <- 0  [0]

जहां पहले कॉलम में बाइनरी प्रतिनिधित्व है और फिर दशमलव परिणाम और इसके संबंध में इसका (ए) एक्सओआर सूची में है। ऐसा इसलिए होता है क्योंकि सभी ऊपरी बिट्स रद्द हो जाते हैं और सबसे कम दो बिट्स चक्र 4 होते हैं। इसलिए, यह है कि कैसे उस छोटी सी दिखने वाली मेज पर पहुंचे।

अब, [a, b] की एक सामान्य श्रेणी पर विचार करें। हम f()XOR को [0, a-1] और [0, b] के लिए खोज सकते हैं। चूँकि किसी भी मूल्य का XOR'd अपने आप में शून्य होता है, f(a-1)बस XOR के सभी मानों को कम से कम चलाते हैं a, जिससे आप रेंज [, a, b] के XOR से निकल जाते हैं।


न्यूनतम सीमा सीमा 1 है, 0 नहीं
पेनो इलचेव

2
@PenchoIlchev में 0 शामिल है या नहीं यह मूट का प्रकार है - (n ^ 0) == n
FatalError

2
@ rajneesh2k10 खैर, 4 के रन में (4 के कई पर शुरू), सबसे कम को छोड़कर सभी बिट समान हैं, इसलिए वे एक दूसरे को रद्द करने या उनके मूल मूल्य के बीच वैकल्पिक होते हैं। यह सच है कि प्रत्येक 2 में सबसे कम बिट चक्र होता है, लेकिन 0 ^ 1 == 1 (यानी वे रद्द नहीं होते हैं)। सबसे कम दो का कारण है क्योंकि (00 ^ 01 ^ 10 ^ 11) == 00 दूसरे शब्दों में, आपके द्वारा चक्रित प्रत्येक 4 मान आपको 0 पर वापस लाते हैं, और इसलिए आप ऐसे सभी चक्रों को रद्द कर सकते हैं, जो है क्यों एक% 4 महत्वपूर्ण है।
फाटलएयर

3
@Pandrei aवहाँ 2, नहीं 0. है
हेरोल्ड

1
वह स्तंभ चालू xor है और 1 xor 3 3 है, इसलिए उस पंक्ति में वर्तमान मान मुझे सही लगता है।
FatalError

58

FatalError के शानदार उत्तर को जोड़ते हुए, लाइन return f(b)^f(a-1);को बेहतर तरीके से समझाया जा सकता है। संक्षेप में, यह इसलिए है क्योंकि XOR में ये अद्भुत गुण हैं:

  • यह साहचर्य है - जहाँ भी आप चाहते हैं, कोष्ठक रखें
  • यह सराहनीय है - इसका मतलब है कि आप ऑपरेटरों को इधर से उधर कर सकते हैं (वे "कम्यूट" कर सकते हैं)

यहाँ दोनों कार्रवाई में है:

(a ^ b ^ c) ^ (d ^ e ^ f) = (f ^ e) ^ (d ^ a ^ b) ^ c
  • इसका उल्टा ही होता है

ऐशे ही:

a ^ b = c
c ^ a = b

जोड़ें और गुणा करें अन्य सहयोगी / कम्यूटेटिव ऑपरेटरों के दो उदाहरण हैं, लेकिन वे खुद को उल्टा नहीं करते हैं। ठीक है, तो, ये गुण क्यों महत्वपूर्ण हैं? खैर, एक सरल मार्ग यह है कि वास्तव में यह क्या है, और फिर आप इन गुणों को काम पर देख सकते हैं।

सबसे पहले, हम परिभाषित करते हैं कि हम क्या चाहते हैं और इसे n कहते हैं:

n      = (a ^ a+1 ^ a+2 .. ^ b)

यदि यह मदद करता है, तो XOR (^) के बारे में सोचें जैसे कि यह एक ऐड था।

चलिए फ़ंक्शन को भी परिभाषित करते हैं:

f(b)   = 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ b

bसे अधिक है a, इसलिए केवल कुछ अतिरिक्त कोष्ठक में सुरक्षित रूप से छोड़ने के द्वारा (जो हम कर सकते हैं क्योंकि यह साहचर्य है), हम यह भी कह सकते हैं:

f(b)   = ( 0 ^ 1 ^ 2 ^ 3 ^ 4 .. ^ (a-1) ) ^ (a ^ a+1 ^ a+2 .. ^ b)

जो सरल करता है:

f(b)   = f(a-1) ^ (a ^ a+1 ^ a+2 .. ^ b)

f(b)   = f(a-1) ^ n

अगला, हम उस उलटी संपत्ति का उपयोग करते हैं और हमें जादुई रेखा देने के लिए कम्यूटिविटी:

n      = f(b) ^ f(a-1)

यदि आप एक ऐड की तरह XOR के बारे में सोच रहे हैं, तो आप वहां एक घटाव में गिर गए होंगे। XOR को XOR में जोड़ना है जो घटाना है!

मैं खुद कैसे इस के साथ आऊं?

तार्किक ऑपरेटरों के गुणों को याद रखें। उनके साथ लगभग एक ऐड की तरह काम करें या अगर यह मदद करता है तो गुणा करें। यह असामान्य लगता है कि (और), xor (^) और (()) साहचर्य हैं, लेकिन वे हैं!

पहले के माध्यम से अनुभवहीन कार्यान्वयन को चलाएं, आउटपुट में पैटर्न की तलाश करें, फिर उन नियमों को ढूंढना शुरू करें जो पैटर्न के सत्य होने की पुष्टि करते हैं। आगे भी अपने कार्यान्वयन को सरल बनाएं और दोहराएं। यह संभवतः वह मार्ग है जिसे मूल निर्माता ने लिया था, इस तथ्य पर प्रकाश डाला कि यह पूरी तरह से इष्टतम नहीं है (यानी एक सरणी के बजाय एक स्विच स्टेटमेंट का उपयोग करें)।


3
यह मुझे मेरे असतत गणित पाठ्यक्रम की याद दिलाता है जो मैंने पिछले साल विश्वविद्यालय में लिया था। मस्ती भरे दिन। इसे पढ़ने के तुरंत बाद मेरे दिमाग में क्या आया यह एक्सकेसीडी कॉमिक है
सीन फ्रांसिस एन। बैलैस

3

मुझे पता चला कि नीचे दिया गया कोड भी प्रश्न में दिए गए समाधान की तरह काम कर रहा है।

हो सकता है कि यह थोड़ा अनुकूलित हो, लेकिन इसका सिर्फ मुझे स्वीकार किए गए उत्तर में दिए गए दोहराव को देखने से मिला,

मैं दिए गए कोड के पीछे के गणितीय प्रमाण को जानना / समझना चाहूंगा, जैसे @Luke ब्रिग्स द्वारा उत्तर में समझाया गया है

यहाँ वह जावा कोड है

public int findXORofRange(int m, int n) {
    int[] patternTracker;

    if(m % 2 == 0)
        patternTracker = new int[] {n, 1, n^1, 0};
    else
        patternTracker = new int[] {m, m^n, m-1, (m-1)^n};

    return patternTracker[(n-m) % 4];
}

2

मैंने समस्या को पुनरावृत्ति के साथ हल किया है। मैं हर पुनरावृत्ति के लिए डेटासेट को लगभग बराबर भाग में बांटता हूं।

public int recursion(int M, int N) {
    if (N - M == 1) {
        return M ^ N;
    } else {
        int pivot = this.calculatePivot(M, N);
        if (pivot + 1 == N) {
            return this.recursion(M, pivot) ^ N;
        } else {
            return this.recursion(M, pivot) ^ this.recursion(pivot + 1, N);
        }
    }
}
public int calculatePivot(int M, int N) {
    return (M + N) / 2;
}

मुझे समाधान पर अपने विचार बताएं। सुधार फीडबैक पाने के लिए खुश। प्रस्तावित समाधान XOR को 0 (लॉग एन) जटिलता में गणना करता है।

धन्यवाद


यह सामान्य m ^ (m + 1) ^ ... ^ (n-1) ^ n गणना के साथ समान कम्प्यूटेशनल जटिलता है। यह 0 (n) है।
Th 'Anh Nguyễn

0

XOR को 0 से N का समर्थन करने के लिए नीचे दिए गए कोड को संशोधित करने की आवश्यकता है,

int f(int a) {
    int []res = {a, 1, a+1, 0};
    return res[a % 4];
}

int getXor(int a, int b) {
    return f(b) ^ f(a);
}
हमारी साइट का प्रयोग करके, आप स्वीकार करते हैं कि आपने हमारी Cookie Policy और निजता नीति को पढ़ और समझा लिया है।
Licensed under cc by-sa 3.0 with attribution required.