110
\$\begingroup\$

Conceptually, this challenge is really simple. You're given a list of non-negative integers ai. If possible, find a non-negative integer N, such that the list consisting of bi = ai XOR N is sorted. If no such N exists, output should be anything that can't be mistaken for a valid N, e.g. a negative number, nothing at all, an error etc.

Here is an example:

[4, 7, 6, 1, 0, 3]

If we take every element in this list XOR 5, we get

[1, 2, 3, 4, 5, 6]

which is sorted. (Note that it is not a requirement for the resulting list to have unique elements and contain no gaps. If the result of such an operation was [0, 1, 1, 3] that would still be valid.) On the other hand for the list

[4, 7, 1, 6, 0, 3]

no such N exists.

You may write a program or function, taking input via STDIN (or closest alternative), command-line argument or function argument and outputting the result via STDOUT (or closest alternative), function return value or function (out) parameter.

Input may be in any convenient list or string format. You may assume that the ai are less than 231 each and that the list contains at least one element.

Your code must handle any of the test cases (especially the four large ones) in a matter of a few seconds.

Standard rules apply.

Test Cases

For every test case which doesn't return -1 there's an infinite number of correct answers. The one listed here is the smallest one. Additional solutions exist by additionally setting bits which are the same across all integers in the input (notably those which are larger than the most-significant bit in the largest number of the list).

[4 7 6 1 0 3] => 5
[4 7 1 6 0 3] => -1
[0 1 3 4 6 7] => 0
[4 2 3 1] => 6
[2 3 0 0 7 7 4 5 11 11] => 2
[2 3 0 0 7 7 5 4 11 11] => -1
[1086101479 748947367 1767817317 656404978 1818793883 1143500039] => -1
[180522983 1885393660 751646477 367706848 331742205 724919510 850844696 2121330641 869882699 1831158987 542636180 1117249765 823387844 731663826 1762069894 240170102 1020696223 1212052937 2041219958 712044033 195249879 1871889904 1787674355 1849980586 1308879787 1743053674 1496763661 607071669 1987302942 178202560 1666170841 1035995406 75303032 1755269469 200581873 500680130 561748675 1749521426 1828237297 835004548 934883150 38711700 1978960635 209243689 1355970350 546308601 590319412 959613996 1956169400 140411967 112601925 88760619 1977727497 672943813 909069787 318174568 385280382 370710480 809689639 557034312 865578556 217468424 346250334 388513751 717158057 941441272 437016122 196344643 379529969 821549457 97008503 872313181 2105942402 603939495 143590999 1580192283 177939344 853074291 1288703007 1605552664 162070930 1325694479 850975127 681702163 1432762307 1994488829 780869518 4379756 602743458 1963508385 2115219284 1219523498 559301490 4191682 1918142271 169309431 346461371 1619467789 1521741606 1881525154] => -1
[37580156 64423492 87193676 91914964 93632157 96332899 154427982 176139560 184435039 228963836 230164674 279802291 301492375 309127664 345705721 370150824 380319820 403997410 410504675 416543032 418193132 424733526 428149607 435596038 477224208 515649925 519407995 525469350 614538124 624884850 642649261 653488151 679260270 685637235 690613185 739141066 825795124 832026691 832633584 833213619 852655299 913744258 917674993 921902522 925691996 931307936 954676047 972992595 997654606 1020009811 1027484648 1052748108 1071580605 1108881241 1113730139 1122392118 1154042251 1170901568 1180031842 1180186856 1206428383 1214066097 1242934611 1243983997 1244736049 1262979035 1312007069 1312030297 1356274316 1368442960 1377432523 1415342434 1471294243 1529353536 1537868913 1566069818 1610578189 1612277199 1613646498 1639183592 1668015280 1764022840 1784234921 1786654280 1835593744 1849372222 1875931624 1877593764 1899940939 2007896363 2023046907 2030492562 2032619034 2085680072 2085750388 2110824853 2123924948 2131327206 2134927760 2136423634] => 0
[1922985547 1934203179 1883318806 1910889055 1983590560 1965316186 2059139291 2075108931 2067514794 2117429526 2140519185 1659645051 1676816799 1611982084 1736461223 1810643297 1753583499 1767991311 1819386745 1355466982 1349603237 1360540003 1453750157 1461849199 1439893078 1432297529 1431882086 1427078318 1487887679 1484011617 1476718655 1509845392 1496496626 1583530675 1579588643 1609495371 1559139172 1554135669 1549766410 1566844751 1562161307 1561938937 1123551908 1086169529 1093103602 1202377124 1193780708 1148229310 1144649241 1257633250 1247607861 1241535002 1262624219 1288523504 1299222235 840314050 909401445 926048886 886867060 873099939 979662326 963003815 1012918112 1034467235 1026553732 568519178 650996158 647728822 616596108 617472393 614787483 604041145 633043809 678181561 698401105 776651230 325294125 271242551 291800692 389634988 346041163 344959554 345547011 342290228 354762650 442183586 467158857 412090528 532898841 534371187 32464799 21286066 109721665 127458375 192166356 146495963 142507512 167676030 236532616 262832772] => 1927544832
[1922985547 1934203179 1883318806 1910889055 1983590560 1965316186 2059139291 2075108931 2067514794 2117429526 2140519185 1659645051 1676816799 1611982084 1736461223 1810643297 1753583499 1767991311 1819386745 1355466982 1349603237 1360540003 1453750157 1461849199 1439893078 1432297529 1431882086 1427078318 1487887679 1484011617 1476718655 1509845392 1496496626 1583530675 1579588643 1609495371 1559139172 1554135669 1549766410 1566844751 1562161307 1561938937 1123551908 1086169529 1093103602 1202377124 1193780708 1148229310 1144649241 1257633250 1241535002 1247607861 1262624219 1288523504 1299222235 840314050 909401445 926048886 886867060 873099939 979662326 963003815 1012918112 1034467235 1026553732 568519178 650996158 647728822 616596108 617472393 614787483 604041145 633043809 678181561 698401105 776651230 325294125 271242551 291800692 389634988 346041163 344959554 345547011 342290228 354762650 442183586 467158857 412090528 532898841 534371187 32464799 21286066 109721665 127458375 192166356 146495963 142507512 167676030 236532616 262832772] => -1

Finally, here are four very large test cases to ensure that submissions are sufficiently efficient:

Why would anyone do this?

It occurred to me the other day that a XOR operation can "sort" an array, which makes it possible to perform a binary search on the array in O(log n) without having to sort it first. It appears to be possible to determine N in pseudolinear time, which would make this a faster alternative to most sorting algorithms, and it doesn't have the memory requirements of radix sort. Of course, a straight linear search through the unsorted array will be faster, but if you want to search the same array many times, a single linear pre-computation can bring down the time required for each search significantly.

Unfortunately, the class of lists this works on is rather limited (uniformly random distributions are unlikely to admit an N).

An interesting question is whether there are other bijective functions which are easier to check and/or are applicable for a wider class of lists.

\$\endgroup\$
12
  • 44
    \$\begingroup\$ "Xorting" is a really cool name for that. \$\endgroup\$ Dec 29, 2015 at 18:41
  • 7
    \$\begingroup\$ @insertusernamehere Credits for that go to randomra. \$\endgroup\$ Dec 29, 2015 at 18:52
  • 3
    \$\begingroup\$ An extremely interesting challenge! \$\endgroup\$
    – DavidC
    Dec 29, 2015 at 23:11
  • 4
    \$\begingroup\$ Paebbels: presuming you have the Xorting key, it is possible to calculate the original value. For the purposes here (a binary search), you would XOR the input with the key and then check it exists in the 'sorted' array. It is certainly a sort, but the relation/function you're sorting over is chosen s.t. the position of each element remains the same. \$\endgroup\$
    – meiamsome
    Dec 30, 2015 at 1:19
  • 8
    \$\begingroup\$ @Paebbels I never claimed that this is sorting. I called it by a made-up word and the paragraph you cite has "sort" in quotes for a reason. My point was that this is a bijective transformation which allows the array to be treated as is if it was sorted for certain operations (like a binary search) without actually having to sort it. \$\endgroup\$ Dec 30, 2015 at 7:30

18 Answers 18

36
\$\begingroup\$

Pyth, 40 36 31 30 bytes

Ju.|G^2slHxMf>FT.:Q2Z|tSIxRJQJ

Try it online: Demonstration or Test Suite

Each of the big test-cases finishes in a couple of seconds.

Explanation:

First I'll explain the method and why it works. I'll do this with the example list: [7, 2, 13, 9].

The first two numbers are already wrong (7 > 2). We want to xor with some number to change that inequality symbol (7 xor X < 2 xor X). Since xor operates on the binary representations, lets look at them.

7 = 1 1 1
2 =   1 0

When we apply xor with some number to each number, the value at some positions will change. If you change the values at the first position (2^0), the inequality symbol doesn't change. The same thing happens, when we change the values at the second position (2^1). Also the symbol won't change if we change values at the fourth, fifth, ... positions (2^3, 2^4, ...). The inequality symbol only changes direction, if we change the third position (2^2).

7 xor 2^0 = 1 1 0   7 xor 2^1 = 1 0 1   7 xor 2^2 =   1 1   7 xor 2^3 = 1 1 1 1
2 xor 2^0 =   1 1   2 xor 2^1 =     0   2 xor 2^2 = 1 1 0   2 xor 2^3 = 1 0 1 0
     6 > 3               5 > 0               3 < 6               15 > 10

If we change multiple positions at once, of course the same thing happens. If any of the positions we change is the third, than the inequality symbol changes, otherwise not.

The next pair is already sorted: 2 < 13. If we look at the binary representation, we notice, that we can xor anything to it and the inequality symbol is still correct, except when we change the fourth position (2^3).

 2 =     1 0    2 xor 2^3 = 1 0 1 0
13 = 1 1 0 1   13 xor 2^3 =   1 0 1
   2 < 13            10 > 5

So we don't want to change the fourth position. For the next pair we want to change something, since 13 > 9. Here we again have to change the third position.

13 = 1 1 0 1   13 xor 2^2 = 1 0 0 1
 9 = 1 0 0 1    9 xor 2^2 = 1 1 0 1
   13 > 9            9 < 13

Now recap: To end up in a sorted list, we again have to change the third position and don't want to change the fourth position. All other positions doesn't matter. The smallest number is simply 4 = 0100. Other choices would be 5 = 0101, 6 = 0110, 7 = 0111, 20 = 10100, 21 = 10101, ...

Xoring with 4 will result in the list [3, 6, 9, 13], with 6 will get [1, 4, 11, 15], and with 21 will get [18, 23, 24, 28].

So for a list, we need to find the positions, that will change the inequality symbol if it points into the wrong direction. We find the position simply by taking the most significant bit of the xor of the pair. We combine all these position (with or) to result in a candidate number. The we check, if we haven't accidentally destroyed the already sorted pairs.

Ju.|G^2slHxMf>FT.:Q2Z   implicit: Q = input list
                .:Q2    all substrings of length 2
            f>FT        filter for pairs that are in descending order
          xM            apply xor to each such pair
 u                  Z   reduce this list, start value G = 0
                           iteration value is H
     ^2slH                 2 to the power of floor(logarithm base 2 of H)
                           this gives a mask representing the most significant bit
  .|G                      update G with the bitwise or of G and ^
J                       store the result in J


|tSIxRJQJ   
    xRJQ      xor each element of the input list with J
  SI          check if the list is sorted
 t            subtract 1
|       J     this number or (if equal to zero) J
              implicit print
\$\endgroup\$
9
  • 3
    \$\begingroup\$ I'm exhorting at the existence of such a clean, simple solution. \$\endgroup\$
    – quintopia
    Dec 30, 2015 at 22:32
  • \$\begingroup\$ It would be awesome if you could give an explanation of why this works for those of us who are more mathematically obtuse. I understand all the steps but don't quite see why the bitwise or of the MSB of every xor'ed descending pair is going to be the right value. \$\endgroup\$
    – Luke
    Dec 31, 2015 at 0:19
  • 1
    \$\begingroup\$ @Luke Added a long explanation. Hopefully it helps. \$\endgroup\$
    – Jakube
    Dec 31, 2015 at 8:35
  • \$\begingroup\$ Wonderful explanation! \$\endgroup\$
    – edc65
    Dec 31, 2015 at 8:42
  • 1
    \$\begingroup\$ If you keep 2 binary values, the bits that have to change, and the bits that have to not change, then you have your final result with no more iterations \$\endgroup\$
    – edc65
    Dec 31, 2015 at 9:30
15
\$\begingroup\$

Ruby 2, 119

->a,*o{a.each_cons(2){|x,y|x==y||o[i=(x^y).bit_length-1]==1-(o[i]=x[i])&&(return-1)};(o.map(&:to_i).reverse*'').to_i 2}

Runs in 42 milliseconds on the large test cases.

Ungolfed:

def first_differing_bit(a,b)
  (a^b).bit_length - 1
end

def xort(ary)
  required_bits = []
  ary.each_cons(2) do |a,b|
    i = first_differing_bit(a,b)
    if i > -1
      bit = a[i]
      if required_bits[i] && required_bits[i] != bit
        return -1
      else
        required_bits[i] = bit
      end
    end
  end
  required_bits.map(&:to_i).reverse.join.to_i(2)
end

For once I wrote the ungolfed version first, then golfed it, since figuring out the right algorithm was a challenge in itself.

I actually tried to write something like this a few years ago to make a binary tree structure that would locally self-balance by letting each node redefine its comparison function dynamically. At first I thought I could just use xor, but as you say for random data there's unlikely to be a viable value.

\$\endgroup\$
2
  • \$\begingroup\$ Good solution, I like the array initialization and ruby's bit [] function. But try for example the list [4,4,4], this will give a SyntaxError as it tries to eval 0b. Luckily, as it often happened to me, there's another way to do the same thing in the same amount of bytes. This should work, I hope: ->a,*o{a.each_cons(2){|x,y|x==y||o[i=(x^y).bit_length-1]==1-(o[i]=x[i])&&(return-1)};(o.map(&:to_i).reverse*'').to_i 2} \$\endgroup\$
    – blutorange
    Dec 31, 2015 at 3:44
  • \$\begingroup\$ Indeed it does, nice catch! \$\endgroup\$
    – histocrat
    Dec 31, 2015 at 14:04
11
\$\begingroup\$

Julia, 174 144 77 75 71

[EDIT] Thanks to Alex A. for anonymizing & various shorthands.
[EDIT 2] Replaced my own implementation by the builtin issorted().

Runs in linear time and handles the big files without noticeable delay. Works just as well for negative numbers.

l->(r=0;s=issorted;for d=63:-1:0 s((l$r).>>d)||(r$=2^d)end;s(l$r)?r:[])

Another variant that calculates the result closest to a given key (the above returns the smallest).

(l,r)->(s=issorted;for d=63:-1:0 s((l$r).>>d)||(r$=2^d)end;s(l$r)?r:[])

usage:

julia> xort = l->(r=0;s=issorted;for d=63:-1:0 s((l$r).>>d)||(r$=2^d)end;s(l$r)?r:[])
(anonymous function)

julia> xort([4 7 6 1 0 3])
5

Example, step by step: [4 7 6 1 0 3] => 5

Start with:
     4  0b0100
     7  0b0111
     6  0b0110
     1  0b0001
     0  0b0000
     3  0b0011
result  0b0000

If the first n bits are sorted, do nothing.
        0b0
        0b0
        0b0
        0b0
        0b0
        0b0
result  0b0000
          ^
If the first n bits are not sorted, flip the nth bit.
        0b01            0b00
        0b01            0b00
        0b01            0b00
        0b00      =>    0b01
        0b00            0b01
        0b00            0b01
result  0b0000          0b0100
           ^               ^
        0b000
        0b001
        0b001
        0b010
        0b010
        0b011
result  0b0100
            ^
        0b0000          0b0001  1
        0b0011          0b0010  2
        0b0010          0b0011  3
        0b0101    =>    0b0100  4
        0b0100          0b0101  5
        0b0111          0b0110  6
result  0b0100          0b0101  5
             ^               ^
If the bit flip does not sort the truncated integers, xorting is
impossible. We continue anyway and check for success in the end.
\$\endgroup\$
1
  • 2
    \$\begingroup\$ 71 bytes: l->(r=0;s=issorted;for d=63:-1:0 s((l$r).>>d)||(r$=2^d)end;s(l$r)?r:[]) \$\endgroup\$
    – Alex A.
    Dec 31, 2015 at 2:28
8
\$\begingroup\$

Jelly, 25 bytes

ṡ2Zµ^/Bo1Ḅ‘×>/|/H
Ç-¹^Ç¥?

The latest commits postdate this challenge, but the above code works with this revision, which predates it. Try it online!

To run the large test cases, depending on your shell, it may be necessary to wrap the above code in a program that reads input from STDIN. Try it online!

Test cases

$ xxd -c 13 -g 1 xort-prog.jelly 
0000000: ae 32 5a 8c 5e 2f 42 6f 31 a4 b6 94 3e  .2Z.^/Bo1...>
000000d: 2f 7c 2f 48 0a 92 2d 8e 5e 92 84 3f     /|/H..-.^..?
$ ./jelly f xort-prog.jelly '[4, 7, 6, 1, 0, 3]'; echo
5
$ ./jelly f xort-prog.jelly '[4, 7, 1, 6, 0, 3]'; echo
-1
$ ./jelly f xort-prog.jelly '[0, 1, 3, 4, 6, 7]'; echo
0
$ ./jelly f xort-prog.jelly '[4, 2, 3, 1]'; echo
6
$ ./jelly f xort-prog.jelly '[2, 3, 0, 0, 7, 7, 4, 5, 11, 11]'; echo
2
$ ./jelly f xort-prog.jelly '[2, 3, 0, 0, 7, 7, 5, 4, 11, 11]'; echo
-1
$
$ wget -q http://pastebin.com/raw/{P96PNi79,zCNLMsx9,GFLBXn5b,6F1Yn3gG}
$ xxd -c 14 -g 1 xort-func.jelly 
0000000: ae 32 5a 8c 5e 2f 42 6f 31 a4 b6 94 3e 2f  .2Z.^/Bo1...>/
000000e: 7c 2f 48 0a 92 2d 8e 5e 92 84 3f 0a a0 92  |/H..-.^..?...
$ tr \  , < P96PNi79 | time -f '\n%es' ./jelly f xort-func.jelly
-1
3.69s
$ tr \  , < zCNLMsx9 | time -f '\n%es' ./jelly f xort-func.jelly
0
2.78s
$ tr \  , < GFLBXn5b | time -f '\n%es' ./jelly f xort-func.jelly
1096442624
2.73s
$ tr \  , < 6F1Yn3gG | time -f '\n%es' ./jelly f xort-func.jelly
-1
2.70s

Idea

This uses a the same approach as @Jakube's answer, but my implementation is a bit different.

Jelly has no sorting yet, so we compute a xorting candidate, XOR the input list with it, compute a xorting candidate of the XORed list, and check if the new candidate is zero. If it is, we print the first candidate; otherwise, we print -1.

Also, Jelly seems to have no sane way to cast to integer yet (even integer division can return floats), so I had to come up with a rather creative way of rounding a list of numbers down to the next power of 2. Rather than log-floor-pow, I convert all integers to binary, replace all binary digits with 1, convert back to integer, add 1, and divide by 2.

Code

ṡ2Zµ^/Bo1Ḅ‘×>/|/H  Helper link. Argument: M (list of integers)

ṡ2                 Yield all overlapping slices of length 2 (pairs) of M.
  Z                Zip to group first and second coordinates.
   µ               Begin a new, monadic chain.
    ^/             XOR the corresponding coordinates.
      B            Convert all results to binary.
       o1          OR (logical) all binary digits with 1.
         Ḅ         Convert back to integer.
          ‘        Increment all integers.
           ×>/     Multiply each rounded (a ^ b) by (a > b).
                   This replaces (a ^ b) with 0 unless a > b.
              |/   OR all results.
                H  Halve the result.

Ç-¹^Ç¥?            Main link. Input: L (list of integers)

Ç                  Call the helper link on L. Result: C (integer)
     ¥             Create a dyadic chain:
   ^                 XOR the elements of L with C.
    Ç                Call the helper link on the result.
      ?            If the result in non-zero:
 -                   Yield -1.
  ¹                Else, yield C.
\$\endgroup\$
0
8
\$\begingroup\$

JavaScript (ES6) 85 97 114 117

Edit Removed stupid,useless last AND
Edit2 Top bit search shortened
Edit3 Wow! I discovered that ES6 (almost) has a builtin to find the top bit (Math.clz32 counts the top 0 bits)

This is based on the solution of @Jakube (pls upvote that). I could never have found it by myself.

Here I go one step forward, iterating the list once and keeping a bit mask with the bits that have to be flipped, and another one with the bits that have to be kept.

If there is an overlap of the bit masks, then no solution is possible, else the solution is "bits to flip"

As binary operations in javascript work only on signed 32 bits integers, the return value is a signed 32 bit integer that can be negative or 0.

If there is no solution the return value is 'X'

l=>l.map(v=>(t=v^p&&1<<(31-Math.clz32(v^p)),v>p?k|=t:c|=t,p=v),p=l[c=k=0])&&c&k?"X":c

Test

The longer tests on jsfiddle

X=l=>l.map(v=>(t=v^p&&1<<(31-Math.clz32(v^p)),v>p?k|=t:c|=t,p=v),p=l[c=k=0])&&c&k?"X":c

console.log=x=>O.textContent+=x+'\n'
;[
[[4,7,6,1,0,3], 5],
[[4,7,1,6,0,3], 'X'],
[[0,1,3,4,6,7], 0],
[[4,2,3,1], 6], 
[[2,3,0,0,7,7,4,5,11,11], 2],
[[2,3,0,0,7,7,5,4,11,11], 'X'],
[[1086101479,748947367,1767817317,656404978,1818793883,1143500039],'X'],
[[180522983,1885393660,751646477,367706848,331742205,724919510,850844696,2121330641,869882699,1831158987,542636180,1117249765,823387844,731663826,1762069894,240170102,1020696223,1212052937,2041219958,712044033,195249879,1871889904,1787674355,1849980586,1308879787,1743053674,1496763661,607071669,1987302942,178202560,1666170841,1035995406,75303032,1755269469,200581873,500680130,561748675,1749521426,1828237297,835004548,934883150,38711700,1978960635,209243689,1355970350,546308601,590319412,959613996,1956169400,140411967,112601925,88760619,1977727497,672943813,909069787,318174568,385280382,370710480,809689639,557034312,865578556,217468424,346250334,388513751,717158057,941441272,437016122,196344643,379529969,821549457,97008503,872313181,2105942402,603939495,143590999,1580192283,177939344,853074291,1288703007,1605552664,162070930,1325694479,850975127,681702163,1432762307,1994488829,780869518,4379756,602743458,1963508385,2115219284,1219523498,559301490,4191682,1918142271,169309431,346461371,1619467789,1521741606,1881525154],'X'],
[[37580156,64423492,87193676,91914964,93632157,96332899,154427982,176139560,184435039,228963836,230164674,279802291,301492375,309127664,345705721,370150824,380319820,403997410,410504675,416543032,418193132,424733526,428149607,435596038,477224208,515649925,519407995,525469350,614538124,624884850,642649261,653488151,679260270,685637235,690613185,739141066,825795124,832026691,832633584,833213619,852655299,913744258,917674993,921902522,925691996,931307936,954676047,972992595,997654606,1020009811,1027484648,1052748108,1071580605,1108881241,1113730139,1122392118,1154042251,1170901568,1180031842,1180186856,1206428383,1214066097,1242934611,1243983997,1244736049,1262979035,1312007069,1312030297,1356274316,1368442960,1377432523,1415342434,1471294243,1529353536,1537868913,1566069818,1610578189,1612277199,1613646498,1639183592,1668015280,1764022840,1784234921,1786654280,1835593744,1849372222,1875931624,1877593764,1899940939,2007896363,2023046907,2030492562,2032619034,2085680072,2085750388,2110824853,2123924948,2131327206,2134927760,2136423634],0],
[[1922985547,1934203179,1883318806,1910889055,1983590560,1965316186,2059139291,2075108931,2067514794,2117429526,2140519185,1659645051,1676816799,1611982084,1736461223,1810643297,1753583499,1767991311,1819386745,1355466982,1349603237,1360540003,1453750157,1461849199,1439893078,1432297529,1431882086,1427078318,1487887679,1484011617,1476718655,1509845392,1496496626,1583530675,1579588643,1609495371,1559139172,1554135669,1549766410,1566844751,1562161307,1561938937,1123551908,1086169529,1093103602,1202377124,1193780708,1148229310,1144649241,1257633250,1247607861,1241535002,1262624219,1288523504,1299222235,840314050,909401445,926048886,886867060,873099939,979662326,963003815,1012918112,1034467235,1026553732,568519178,650996158,647728822,616596108,617472393,614787483,604041145,633043809,678181561,698401105,776651230,325294125,271242551,291800692,389634988,346041163,344959554,345547011,342290228,354762650,442183586,467158857,412090528,532898841,534371187,32464799,21286066,109721665,127458375,192166356,146495963,142507512,167676030,236532616,262832772],1927544832],
[[1922985547,1934203179,1883318806,1910889055,1983590560,1965316186,2059139291,2075108931,2067514794,2117429526,2140519185,1659645051,1676816799,1611982084,1736461223,1810643297,1753583499,1767991311,1819386745,1355466982,1349603237,1360540003,1453750157,1461849199,1439893078,1432297529,1431882086,1427078318,1487887679,1484011617,1476718655,1509845392,1496496626,1583530675,1579588643,1609495371,1559139172,1554135669,1549766410,1566844751,1562161307,1561938937,1123551908,1086169529,1093103602,1202377124,1193780708,1148229310,1144649241,1257633250,1241535002,1247607861,1262624219,1288523504,1299222235,840314050,909401445,926048886,886867060,873099939,979662326,963003815,1012918112,1034467235,1026553732,568519178,650996158,647728822,616596108,617472393,614787483,604041145,633043809,678181561,698401105,776651230,325294125,271242551,291800692,389634988,346041163,344959554,345547011,342290228,354762650,442183586,467158857,412090528,532898841,534371187,32464799,21286066,109721665,127458375,192166356,146495963,142507512,167676030,236532616,262832772],'X']
].forEach(t=>{
  var i=t[0],k=t[1],r=X(i)
  console.log((k==r?'OK ':'Error (expected '+k+') ')+r+' for input '+i)
})
<pre id=O></pre>

\$\endgroup\$
8
\$\begingroup\$

ES6, 84 bytes

a=>(i=e=0,a.reduce((x,y)=>(z=1<<31-Math.clz32(x^y),x>y?i|=z:y>x?e|=z:z,y)),i&e?-1:i)

Edit: By the time it took me to write the answer the algorithm had already been independently posted by @Jakube; my algorithm is the same but this wasn't plagiarism honest! Also I notice another JavaScript answer has since been posted too. Sorry if I'm stepping on anyone's toes.

Edit: Saved 8 bytes thanks to edc65.

\$\endgroup\$
4
  • \$\begingroup\$ You're not stepping on anyone's toes at all. This is a good answer, nice work. :) \$\endgroup\$
    – Alex A.
    Dec 31, 2015 at 17:39
  • \$\begingroup\$ Nice, you beat @edc65! That almost never happens. \$\endgroup\$ Jan 1, 2016 at 4:53
  • \$\begingroup\$ You have my vote. I think you too should use the clz32 function to beat me again. \$\endgroup\$
    – edc65
    Jan 2, 2016 at 15:35
  • \$\begingroup\$ If only 1<<31>>>32 was zero then I could save another 4 bytes. \$\endgroup\$
    – Neil
    Jan 6, 2016 at 14:33
5
\$\begingroup\$

C, 144 bytes

#include <strings.h>
#include <stdio.h>
m[2],l,i;main(v){while(scanf("%d",&v)==1)m[l<v]|=(i++&&v^l)<<~-fls(v^l),l=v;printf("%d",*m&m[1]?-1:*m);}

This is almost standard C99 (it misses a few int specifiers and has 1 argument for main). It also relies on 0<<-1 being 0 (which seems to be true when compiled with Clang at least — I haven't tested others)

I've taken Jakube's method and ported it to C. I think it does surprisingly well size-wise for C. It's also super-fast (0.061s to run all test files, including the massive 4). It takes input from STDIN and will print the matching value or -1 to STDOUT, so run it with one of:

echo "4 7 6 1 0 0 3" | ./xort
./xort < file.txt

Breakdown:

// Globals initialise to 0
m[2],                                    // Stores our bit masks
                                         // (m[0]=CHANGE, m[1]=MUST NOT CHANGE)
l,                                       // Last value
i;                                       // Current iteration
main(v){
    while(scanf("%d",&v)==1)             // Read each value in turn
        m[l<v]|=                         // If they are sorted, we mark a bit as
                                         // MUST NOT CHANGE (m[1]), otherwise we
                                         // mark as CHANGE (m[0])
                (i++&&v^l)               // If this is the first iteration,
                                         // or the value is unchanged, mark nothing
                          <<~-fls(v^l),  // Mark the highest bit which has changed
                                         // = (1<<(fls(v^l)-1)
        l=v;                             // Update last value
    printf("%d",
                *m&m[1]                  // Check if result is valid (if any bits
                                         // are both MUST NOT CHANGE and CHANGE,
                                         // it is not valid)
                       ?-1               // Print -1 on failure
                          :*m);          // Print value on success
}
\$\endgroup\$
4
\$\begingroup\$

Julia, 124 bytes

f(x,g=0)=issorted(([g|=2^Int(log2(h)÷1)for h=map(k->k[1]$k[2],filter(j->j[1]>=j[2],[x[i-1:i]for i=2:endof(x)]))];g)$x)?g:-1

This is a function that accepts an integer array and returns an integer. It uses Jakube's approach.

Ungolfed:

function f{T<:Integer}(x::Array{T,1}, g::T=0)
    # Get all pairs of elements in the input array
    pairs = [x[i-1:i] for i = 2:endof(x)]

    # Filter to pairs in descending order
    desc = filter(j -> j[1] ≥ j[2], pairs)

    # Map XOR over these pairs
    xord = map(k -> k[1] $ k[2], desc)

    # For each element of this array, update the
    # parameter g (which defaults to 0) as the
    # bitwise OR of itself and 2^floor(log2(element))
    for h in xord
        g |= 2^Int(log2(h) ÷ 1)
    end

    # If the array constructed as g XOR the input is
    # sorted, we've found our answer! Otherwise -1.
    return issorted(g $ x) ? g : -1
end
\$\endgroup\$
1
  • \$\begingroup\$ Out of curiosity, why is XOR $? \$\endgroup\$ Mar 11, 2018 at 0:34
4
\$\begingroup\$

Python 2, 204 bytes

def f(a):
 m=n=0
 for i in range(32):
  b=2**(31-i);m|=b
  for n in[n,n|b]:
   if not q(a,m,n):break
  else:return-1
 return n
def q(a,m,n):
 if a:p=a[0]&m^n
 for t in a:
  t=t&m^n
  if t<p:return 1
  p=t

The input is passed as a list to function f.

This code figures out the value of N (named n in the program) one bit at a time, starting with the most significant bit. (the "for i" loop)

For each bit position, the "for n" loop first tries using 0 for that bit of n. If that doesn't work, it tries using 1. If neither of these works, then there is no solution. Note that the else clause is on the "for n" loop, not the if statement. In Python, a for statement can have an else clause, which is executed after the loop runs to completion, but is not executed if we break out of the loop.

The q function checks for problems with the list order given the list (a), a bit mask (m), and the value to be xored with each value in the list (n). It returns 1 if there is a problem with the ordering, or None if the order is ok. None is the default return value, so that saved me several characters.

This code handles an empty list or a list with 1 element correctly, returning 0. The "if a:" in function q is there only to avoid an IndexError exception when the list is empty. So 5 more bytes could be removed if handling empty lists isn't required.

On my computer, large test case #3 took 0.262 seconds. #2 took about the same. All the test cases together took 0.765 seconds.

\$\endgroup\$
1
  • 1
    \$\begingroup\$ Handling empty lists isn't required, I'll clarify that. \$\endgroup\$ Dec 31, 2015 at 9:32
3
\$\begingroup\$

CJam, 37 bytes

q~_2ew{:>},{:^2mLi2\#}%0+:|_@f^_$=\W?

Test it here.

This uses the same algorithm as several of the other answers. It's essentially my reference implementation which I used to create the test cases. However, I did steal Jakube's trick of checking only the offending pairs and simply trying out the result with a sort. That breaks the pseudolinearity, but O(n log n) is still fast enough for the test cases. My original code also checked the pairs that are already in order, and built up a list of bits which must not be toggled in order to keep their relative order, and checked at the end that there are no overlaps between the two bit masks. This algorithm was originally suggested by Ben Jackson.

\$\endgroup\$
2
\$\begingroup\$

Python 2, 226 214 bytes

Simpleish algorithm, built it yesterday, golfed today.

o=input()
s=sorted
p=s(set(o),key=o.index)
n=q=0
while 1:
 a=1
 while 1-q and p[0]<p[1]:p=p[1:];q=len(p)==1
 if q:break
 while not p[0]^a<p[1]^a:a*=2
 n+=a;p=[i^a for i in p]
t=[a^n for a in o]
print[-1,n][s(t)==t]

Ungolfed:

def xor(a,b): return a^b

def rm_dupes(seq):
    seen = set()
    seen_add = seen.add
    return [x for x in seq if not (x in seen or seen_add(x))]

def rm_sorted(seq):
    while seq[0] < seq[1]:
        seq = seq[1:]
        if len(seq) == 1: return seq
    return seq

inp = input()
oi = inp

inp = rm_dupes(inp)
n=0
old_inp=0
while old_inp != inp:
    old_inp = inp
    inp = rm_sorted(inp)
    if len(inp)==1:break
    highest_set0 = len(bin(inp[0]))-3 # bin returns in form 0bxxx
    highest_set1 = len(bin(inp[1]))-3 # bin returns in form 0bxxx
    if highest_set1 == 0:
        try:
            t0 = max(int(bin(inp[0])[3:], 2), 1)
        except ValueError: toggle_amount = 1
        else: toggle_amount = t0^inp[0]
    else:
        fallen = False
        for i in xrange(max(highest_set0,highest_set1)+1):
            toggle_amount = 2**i
            if inp[0]^toggle_amount < inp[1]^toggle_amount:
                fallen = True
                break
        assert(fallen)
    n+=toggle_amount
    inp = [i^toggle_amount for i in inp]

out=map(xor, oi, [n]*len(oi))
if sorted(out)==out :print n
else:print -1
\$\endgroup\$
2
\$\begingroup\$

C, 312 bytes

#define R return
t,i,*b;f(int*a,int l,int k){int s=a[0]>>k&1,j=-1,i=1;if(k<0)R 0;for(;i<l;++i){t=a[i]>>k&1;if(s!=t)if(j<0)j=i,s=t;else R 1;}if(j<0)R f(a,l,k-1);else{if(s+b[k]==2)R 1;b[k]=s+1;R f(a,j,--k)||f(a+j,l-j,k);}}h(int*a,int l){int c[32]={0};b=c;if(f(a,l,30))R -1;t=0;for(i=0;i<32;++i)t|=(b[i]&1)<<i;R t;}

Defines a function h(int*a,int l) taking a pointer to an array and its length. Here is a test program behemoth.

Slightly ungolfed:

int t, i, *b;

int f(int * a, int l, int k) {
    int s = a[0] >> k & 1;
    int j = -1;
    int i = 1;
    if (k < 0) return 0;
    for (; i < l; ++i) {
        t = a[i] >> k & 1;
        if (s != t) {
            if (j < 0) {
                j = i;
                s = t;
            } else return 1;
        }
    }
    if (j < 0) {
        return f(a, l, k - 1);
    } else {
        if (s + b[k] == 2) return 1;
        b[k] = s + 1;
        return f(a, j, --k) || f(a + j, l - j, k);
    }
}

int h(int * a, int l) {
    int c[32] = {0};
    b = c;
    if (f(a, l, 30)) return -1;
    t = 0;
    for (i = 0; i < 32; ++i) {
        t |= (b[i] & 1) << i;
    }
    return t;
}
\$\endgroup\$
0
2
\$\begingroup\$

Mathematica, 99 97 Characters

Thanks to Martin Büttner for advices.

x@l_:=If[OrderedQ[l~BitXor~#],#,-1]&@Fold[#+#2Boole@!OrderedQ@⌊l~BitXor~#/#2⌋&,0,2^32/2^Range@32]

Explanation:

We will do multiple tries to modify N starting from zero, and do a test to validate the candidate N.

Step 1. We get these numbers (32-bit integers) "xor"ed by N(= 0 now) and divided by 2^31: ⌊l~BitXor~#/#2⌋. There are three cases:

  • ordered, e.g. {0, 0, 1, 1, 1, 1, 1, 1};
  • can be corrected, e.g. {1, 1, 1, 1, 0, 0, 0, 0};
  • else, e.g. {0, 0, 1, 0, 0, 1, 1, 1}.

We do nothing to N for the first case, or we add 2^31 to N to correct the order for the second case: #+#2Boole@!OrderedQ@.... While for the third case, it is impossible to xorting the list what ever we do, thus we just add 2^31 to N for simplicity (or anything!).

Step 2. We get these numbers "xor"ed by N and divided by 2^30. There are again three cases:

  • ordered, e.g. {0, 1, 2, 2, 2, 2, 3, 3};
  • can be corrected, e.g. {1, 1 , 0, 0, 3, 2, 2, 2};
  • else, e.g. {3, 3, 1, 3, 2, 0, 1, 0}.

We do nothing to N for the first case, or we add 2^30 to N to correct the order for the second case. Otherwise, we realize that xorting is impossible, thus we just add 2^30 to N for simplicity again.

Step 3 ~ 32. We recursively get these numbers "xor"ed by N and divided by 2^29, 2^28, ..., 2^0. And do similar things: Fold[...,0,2^32/2^Range[32]]

Step 33. Now we finally get a candidate N. If[OrderedQ[l~BitXor~#],#,-1]& is used to check if such N indeed xorting the list. If the list can be xorting by some N, it is not difficult to proof that we will always encounter the first or the second case.

\$\endgroup\$
0
2
\$\begingroup\$

Perl 6, 79 bytes

If there wasn't a time limit the shortest Perl 6 code would probably be

{first {[<=] $_ X+^@_},^2*.max} # 31 bytes

Instead I have to do something a bit more clever.
Since I took a while to come back to this, there was already an answer that describes a good algorithm, and the reasoning behind it.

{$/=0;for @_.rotor(2=>-1) ->(\a,\b){b>=a or$/+|=2**msb a+^b};$/if [<=] $/X+^@_} # 79
{
  # cheat by using a special variable
  # so there is no need to declare it
  $/=0;

  # takes the elements two at a time, backing up one
  for @_.rotor(2=>-1)
    # since that is a non-flat list, desugar each element into 2
    # terms
    ->(\a,\b){
      # if they are not sorted
      b>=a or
      # take the most significant bit of xoring the two values
      # and numeric or 「+|」 it into 「$/」
      $/+|=2**msb a+^b
    };
  

  # returns 「$/」 if the list is Xorted
  # otherwise returns Empty
  $/if [<=] $/X+^@_

  # 「 $/ X[+^] @_ 」
  # does numeric xor 「+^」 between 「$/」
  # and each element of the original list 「@_」
}

Usage:

# give it a lexical name for ease of use
my &code = {...}

say code [8,4,3,2,1];     # 15

say code [4,7,6,1,0,3]; # 5
say code [4,7,1,6,0,3]; # ()
say code [0,1,3,4,6,7]; # 0
say code [4,2,3,1];     # 6
say code [2,3,0,0,7,7,4,5,11,11]; # 2
say code [2,3,0,0,7,7,5,4,11,11]; # ()
say code [1086101479,748947367,1767817317,656404978,1818793883,1143500039]; # ()

# the example files
for 'testfiles'.IO.dir.sort».comb(/«\d+»/) {
  printf "%10s in %5.2f secs\n", code( @$_ ).gist, now - ENTER now;
}
#         () in  9.99 secs
#          0 in 11.70 secs
# 1096442624 in 13.54 secs
#         () in 11.44 secs
\$\endgroup\$
1
\$\begingroup\$

Mathematica 650 415 194 bytes

This challenge helped me understand quite a bit about Xor that I had never thought about. It took a long time to whittle down the code, but was worth the effort.

BitXor works directly on base 10 numbers. This greatly reduced the code from the earlier versions.

The logic is simple. One works, not with pairs of numbers (as some submissions did) but rather with the complete set of numbers after being BitXored with the current "key".

Start with tentative solution, or "key" of zero, that is with all bits are zero. When the original n numbers are BitXored with zero , they are returned, unaltered. Correlate the ordering of the numbers with the range1, 2, ...n, which represent a perfectly ordered list. The correlation, with a value between -1 and 1, reflects how well the numbers are ordered.

Then set the hi bit, obtain the new key, and BitXor the key with the current set of numbers. If the correlation between the new sequence of numbers and the perfectly ordered list is an improvement, keep the bit set. If not, leave the bit unset.

Proceed in this manner from the hi to the low bit. If the best correlation is 1, then the key is the solution. If not, it is -1.

There would be ways to make the code a bit more efficient, for example, by interrupting the process as soon as a solution is found, but this would require more coding and the current approach is very fast as it is. (The final and longest test case takes 20 msec.)

c@i_:=Correlation[Ordering@i,Range[Length[i]]]//N;
t@{i_,k_,b_,w_}:=(v= c@BitXor[i,m=k+2^(b-1)];{i,If[v>w,m,k],b-1,v~Max~w})
g@i_:= (If[#4==1,#2,-1] &@@Nest[t,{i,0,b=1+Floor@Log[2,Max@i],x=c@i},b])

g[{4, 7, 6, 1, 0, 3}]

5


g[{4, 7, 1, 6, 0, 3}]

-1


g2@{0, 1, 3, 4, 6, 7}

0


g@{1922985547, 1934203179, 1883318806, 1910889055, 1983590560, 1965316186,2059139291, 2075108931, 2067514794, 2117429526, 2140519185, 1659645051, 1676816799, 1611982084, 1736461223, 1810643297, 1753583499, 1767991311, 1819386745, 1355466982, 1349603237, 1360540003, 1453750157, 1461849199, 1439893078, 1432297529, 1431882086, 1427078318, 1487887679, 1484011617, 1476718655, 1509845392, 1496496626, 1583530675, 1579588643, 1609495371, 1559139172, 1554135669, 1549766410, 1566844751, 1562161307,1561938937, 1123551908, 1086169529, 1093103602, 1202377124, 1193780708, 1148229310, 1144649241, 1257633250, 1247607861, 1241535002, 1262624219, 1288523504, 1299222235,840314050, 909401445, 926048886, 886867060, 873099939, 979662326,963003815, 1012918112, 1034467235, 1026553732, 568519178, 650996158,647728822, 616596108, 617472393, 614787483, 604041145, 633043809, 678181561, 698401105, 776651230, 325294125, 271242551, 291800692, 389634988, 346041163, 344959554, 345547011, 342290228, 354762650, 442183586, 467158857, 412090528, 532898841, 534371187, 32464799, 21286066, 109721665, 127458375, 192166356, 146495963, 142507512, 167676030, 236532616, 262832772}

1927544832

\$\endgroup\$
1
\$\begingroup\$

Add++, 125 119 bytes

D,g,@@,BxBBBDbU1€oB]BJ2$Bb1+
D,j,@,bUBSVcGbU£{g}B]BkAbUBSVcGbU£>B]BKBcB*¦Bo2/i
L!,B#a=
D,f,?!,{j}Vad{j}BF€Bx1]G$0=-1$Qp

Try it online!

I am actually really proud that Add++ is able to do this, and isn't the longest solution here

Declares a function f that takes each element as a separate argument (e.g. $f>4>2>3>1)

How it works

Buckle up folks, it's going to be a long ride

D,g,@@,		; Declare a function 'g'
		; Example arguments: 		[4 7]
	Bx	; Xor;			STACK = [3]
	BB	; To binary;		STACK = [11]
	BD	; Digits;		STACK = [[1 1]]
	bU	; Unpack;		STACK = [1 1]
	1€o	; Replace 0s with 1s;	STACK = [1 1]
	B]	; Wrap;			STACK = [[1 1]]
	BJ	; Concatenate;		STACK = ['11']
	2$Bb	; From binary;		STACK = [3]
	1+	; Increment;		STACK = [4]
		;			Return   4

D,j,@,		; Declare a function 'j'
		; Example argument:		[[4 7 6 1 0 3]]
	bU	; Unpack;		STACK = [4 7 6 1 0 3]
	BS	; Overlapping pairs;	STACK = [4 7 6 1 0 3 [[4 7] [4 6] [6 1] [1 0] [0 3]]]
	VcG	; Keep first element;	STACK = [[[4 7] [4 6] [6 1] [1 0] [0 3]]]
	bU	; Unpack;		STACK = [[4 7] [4 6] [6 1] [1 0] [0 3]]
	£{g}	; Apply 'g' over each;	STACK = [4 2 8 2 4]
	B]	; Wrap;			STACK = [[4 2 8 2 4]]
	Bk	; Global save;		STACK = []		; GLOBAL = [4 2 8 2 4]
	A	; Push arguments;	STACK = [[4 7 6 1 0 3]]
	bU	; Unpack;		STACK = [4 7 6 1 0 3]
	BSVcGbU	; Overlapping pairs;	STACK = [[4 7] [4 6] [6 1] [1 0] [0 3]]
	£>	; Greater than each;	STACK = [0 1 1 1 0]
	B]	; Wrap;			STACK = [[0 1 1 1 0]]
	BK	; Global get;		STACK = [[0 1 1 1 0] [4 2 8 2 4]]
	BcB*	; Products;		STACK = [[0 2 8 2 0]]
	¦Bo	; Reduce by logical OR;	STACK = [10]
	2/i	; Halve;		STACK = [5]
		;			Return   5

L!,		; Declare 'lambda 1'
		; Example argument:		[[1 2 3 4 5]]
	B#	; Sort;			STACK = [[1 2 3 4 5]]
	a=	; Equal to argument;	STACK = [1]
		; 			Return   1

D,f,?!,		; Declare a function 'f'
		; Example arguments:		[[4 7 6 1 0 3]]
	{j}	; Call 'j';		STACK = [5]
	V	; Save;			STACK = []		; REGISTER = 5
	ad	; Push arguments twice;	STACK = [[4 7 6 1 0 3] [4 7 6 1 0 3]]
	{j}	; Call 'j';		STACK = [[4 7 6 1 0 3] 5]
	BF	; Flatten;		STACK = [4 7 6 1 0 3 5]
	€Bx	; Xor each with 5;	STACK = [1 2 3 4 5 6]
	1]	; Call 'lambda 1';	STACK = [1]
	G$	; Retrieve REGISTER;	STACK = [5 1]
	0=	; If equal to 0:
	-1$Q	;   Return -1
	p	; Else, pop condition;	STACK = [5]
		;			Return   5
\$\endgroup\$
1
\$\begingroup\$

Stax, 29 bytes

¬√▬ⁿ{j╔■α√ï(íP♫_z(.▀ng▒JU↨@b┬

Run and debug online!

Uses @RainerP.'s solution (came up with the flipping bit part independently but uses the 32rr part)

Linear time complexity.

Uses the unpacked version to explain.

32rr{|2Y;{y/m:^!c{,{y|^m~}Mm,:^ud:b
32rr                                   Range [32,31..0]
    {                      m           Map each number `k` in the range with
     |2Y                                   `2^k`
        ;{y/m                              Map each number `l` in the input to `floor(l/2^k)`
             :^!                           The mapped array is not non-decreasing
                                           This is the binary digit `l` is mapped to
                c{       }M                If that's true, do
                  ,{y|^m~                  Flip the corresponding bit of every element in the input
                            ,:^        The final array is sorted
                               ud      Take inverse and discard, if the final array is not sorted this results in zero-division error
                                 :b    Convert mapped binary to integer
\$\endgroup\$
1
\$\begingroup\$

Japt, 11 bytes

(Eventually) Outputs undefined for falsey inputs.

@Ë^XÃäÎø1}f

Try it

@Ë^XÃäÎø1}f     :Implicit input of array U
@               :Function taking an integer X as argument
 Ë              :  Map U
  ^X            :    XOR X
    Ã           :  End map
     ä          :  Consecutive pairs
      Î         :  Signs of differences
       ø1       :  Contains 1?
         }      :End function
          f     :Get the first X>=0 that returns false
\$\endgroup\$

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Not the answer you're looking for? Browse other questions tagged or ask your own question.