Related
Given a set of distinct positive integers S we need to partition a set in such a way that the following function is maximize. Let S1, S2, ... Sn be the parition. n can be atleast 2.
F(S1, S2, ..., Sn) = AND(XOR(S1), XOR(S2), ..., XOR(Sn)))
where, AND is bitwise AND operation and XOR is bitwise XOR operation
We need to print the all such partitions possible.
I have tried the exponential approach as shown below.
I am looking for a solution with lesser complexity.
This problem is part of a homework, so only provide the hint.
from functools import reduce
from collections import defaultdict
def partition(collection):
if len(collection) == 1:
yield [ collection ]
return
first = collection[0]
for smaller in partition(collection[1:]):
# insert `first` in each of the subpartition's subsets
for n, subset in enumerate(smaller):
yield smaller[:n] + [[ first ] + subset] + smaller[n+1:]
# put `first` in its own subset
yield [ [ first ] ] + smaller
# print("END OF THE LOOP")
x = 4
initialAssum = [2, 4, 8, 16]
something = initialAssum
def andxor(xs):
def xorlist(xs):
return reduce(lambda i, j: i ^ j, xs)
tmp = [xorlist(x) for x in xs]
return reduce(lambda i, j: i & j, tmp)
ans = defaultdict(list)
for n, p in enumerate(partition(something), 1):
r = andxor(p)
if len(p) > 1:
ans[r].append(p)
m = max(ans.keys())
for a in ans[m]:
print(a)
#print(a, len(a))
print(f'{m}')
INPUT: the set itself
OUTPUT: max value possible followed by the all the partitions producing it
INPUT:
[2, 3, 4]
OUTPUT:
2
[[4, 2], [3]]
[[2], [4, 3]]
INPUT:
[2, 4, 6, 8]
OUTPUT:
0
[[2], [4, 8, 16]]
[[2, 4], [8, 16]]
[[4], [2, 8, 16]]
[[2], [4], [8, 16]]
[[2, 4, 8], [16]]
[[4, 8], [2, 16]]
[[2], [4, 8], [16]]
[[2, 8], [4, 16]]
[[8], [2, 4, 16]]
[[2], [8], [4, 16]]
[[2, 4], [8], [16]]
[[4], [2, 8], [16]]
[[4], [8], [2, 16]]
[[2], [4], [8], [16]]
This problem is part of a homework, so only provide the hint.
Hint: if we consider each bit separately from the highest to lowest, we can consider bit k as being set in the result if and only if that bit can appear an odd number of times in each part of the partition.
I need to remove all duplicates from a set of arrays, but we define 'duplicate' in a special way here: Two 4 element arrays are 'dupes' if they share the first two elements in any order and the last two elements in any order.
So my thought is to split these arrays into 2 halves, sort those 2-element half arrays, and put them back together again to form 4-element arrays. Then we will have some textbook duplicates we can remove.
Is this a good approach?
We start with a set of 6 4-element arrays, none of which is an exact duplicate of another.
[6, 4, 3, 2]
[4, 6, 2, 3]
[3, 4, 2, 6]
[4, 3, 6, 2]
[3, 6, 2, 4]
[6, 3, 4, 2]
split each array in the middle
[[6, 4], [3, 2]]
[[4, 6], [2, 3]]
[[3, 4], [2, 6]]
[[4, 3], [6, 2]]
[[3, 6], [2, 4]]
[[6, 3], [4, 2]]
Here's the hard part in Neo4j!
Sort each of the two inner arrays only.
[[4, 6], [2, 3]]
[[4, 6], [2, 3]]
[[3, 4], [2, 6]]
[[3, 4], [2, 6]]
[[3, 6], [2, 4]]
[[3, 6], [2, 4]]
Put them back together.
[4, 6, 2, 3]
[4, 6, 2, 3]
[3, 4, 2, 6]
[3, 4, 2, 6]
[3, 6, 2, 4]
[3, 6, 2, 4]
Dedupe by using DISTINCT.
[4, 6, 2, 3]
[3, 4, 2, 6]
[3, 6, 2, 4]
This very simple query (with your sample data) implements your approach, which seems reasonable:
WITH [
[6, 4, 3, 2],
[4, 6, 2, 3],
[3, 4, 2, 6],
[4, 3, 6, 2],
[3, 6, 2, 4],
[6, 3, 4, 2]
] AS data
UNWIND data AS d
RETURN DISTINCT
CASE WHEN d[0] > d[1] THEN [d[1], d[0]] ELSE d[0..2] END +
CASE WHEN d[2] > d[3] THEN [d[3], d[2]] ELSE d[2..] END AS res;
The result is:
+-----------+
| res |
+-----------+
| [4,6,2,3] |
| [3,4,2,6] |
| [3,6,2,4] |
+-----------+
Handling arrays of any (even) size:
The following query will accept as input a collection of sub-collections of even size (does not have to be 4). It will return a collection of distinct properly internally "sorted" collections.
For example (notice that the sub-collections do not have to be the same size):
WITH [
[6, 4, 3, 2, 3, 2],
[3, 4, 2, 6, 7, 8],
[4, 3, 6, 2, 8, 7],
[3, 6, 2, 4],
[6, 3, 4, 2],
[4, 6, 2, 3, 2, 3]
] AS data
WITH EXTRACT(d IN data |
REDUCE(s = [], i IN RANGE(0, SIZE(d)-1, 2) | s + CASE WHEN d[i] > d[i+1] THEN [d[i+1], d[i]] ELSE d[i..i+2] END)) AS sorted
UNWIND sorted AS res
RETURN DISTINCT res;
The output of the above is:
+---------------+
| res |
+---------------+
| [4,6,2,3,2,3] |
| [3,4,2,6,7,8] |
| [3,6,2,4] |
+---------------+
I have a range of numbers R = (1..n). I also have another character 'a'. I want to generate strings of length L (L > n + 2) that have all the numbers in the same order, but go through every repeated permutation of 'a' to fill the length L. For example, if n = 3, and L = 7, then some valid strings would be :
"123aaaa",
"1a23aaa",
"1aa2a3a",
"aaaa123"
while the following strings would be invalid:
"213aaaa", # invalid, because 1,2,3 are not in order
"123a", #invalid, because length < L
"1123aaa", # invalid because a number is repeated
I am currently doing this, which is way too inefficient:
n = 3
L = 7
all_terms = (1..n).to_a + Array.new(L - n, 'a')
all_terms.permutation.each do |permut|
if(valid_permut? permut) # checks if numbers are in their natural order
puts permut.join
end
end
How do I directly generate valid strings more efficiently?
The problem is equivalent to: select n elements from index 0 to L - 1, fill these with 1 to n accordingly, and fill the rest with some constant character.
In your example, it's taking 3 elements from 0..6:
(0..6).to_a.combination(3).to_a
=> [[0, 1, 2], [0, 1, 3], [0, 1, 4], [0, 1, 5], [0, 1, 6], [0, 2, 3], [0, 2, 4],
[0, 2, 5], [0, 2, 6], [0, 3, 4], [0, 3, 5], [0, 3, 6], [0, 4, 5], [0, 4, 6], [0, 5, 6],
[1, 2, 3], [1, 2, 4], [1, 2, 5], [1, 2, 6], [1, 3, 4], [1, 3, 5], [1, 3, 6], [1, 4, 5],
[1, 4, 6], [1, 5, 6], [2, 3, 4], [2, 3, 5], [2, 3, 6], [2, 4, 5], [2, 4, 6], [2, 5, 6],
[3, 4, 5], [3, 4, 6], [3, 5, 6], [4, 5, 6]]
Every subarray here represents a possible result. For example, [0, 2, 3] corresponds to '0a12aaa', [3, 5, 6] corresponds to 'aaa0a12', etc. The code for this conversion is straight-forward.
You can model this as all possible interleavings of two strings, where relative order of the input elements is preserved. Here's a recursive solution. It works by choosing an element from one list, and prepending it to all possible subproblems, then doing it again where an element is chosen from the second list instead, and combining the two solution sets at the end.
# Returns an array of all possible interleaving of two strings
# Maintains relative order of each character of the input strings
def interleave_strings_all(a1, a2)
# Handle base case where at least one input string is empty
return [a1 + a2] if a1.empty? || a2.empty?
# Place element of first string, and prepend to all subproblems
set1 = interleave_strings_all(a1[1..-1], a2).map{|x| a1[0] + x}
# Place element of second string and prepend to all subproblems
set2 = interleave_strings_all(a1, a2[1..-1]).map{|x| a2[0] + x}
# Combine solutions of subproblems into overall problem
return set1.concat(set2)
end
if __FILE__ == $0 then
l = 5
n = 3
a1 = (1..n).to_a.map{|x| x.to_s}.join()
a2 = 'a' * (l - n)
puts interleave_strings_all(a1, a2)
end
The output is:
123aa
12a3a
12aa3
1a23a
1a2a3
1aa23
a123a
a12a3
a1a23
aa123
For an example I need to sort:
?- mergesort([8,1,[4,6,3],2],Sorted).
The outcome should be:
Sorted = [1, 2, 8, [3, 4, 6]]
Unfortunately I'm not sure what to do. I've tried to find an answer myself, but didn't find a solution. Currently the outcome is:
Sorted = [1, 2, 8, [4, 6, 3]]
My code:
mergesort([],[]).
mergesort([A],[A]).
mergesort([A,B|R],S) :-
split([A,B|R],L1,L2),
mergesort(L1,S1),
mergesort(L2,S2),
merge(S1,S2,S).
split([],[],[]).
split([A],[A],[]).
split([A,B|R],[A|Ra],[B|Rb]) :- split(R,Ra,Rb).
merge(A,[],A).
merge([],B,B).
merge([A|Ra],[B|Rb],[A|M]) :- A #=< B, merge(Ra,[B|Rb],M).
merge([A|Ra],[B|Rb],[B|M]) :- A #> B, merge([A|Ra],Rb,M).
Big thanks in advance!
I would write a simple preprocessing step:
sortl([H|T],[Hs|Ts]) :-
( is_list(H)
-> mergesort(H,Gs),
sortl(Gs,Hs)
; Hs = H
),
sortl(T,Ts).
sortl([],[]).
then you could use it this way
?- sortl([8,1,[4,6,[3,4],[1,8],3],2,[1,3,2]],T),mergesort(T,Sorted).
T = [8, 1, [3, 4, 6, [1, 8], [3|...]], 2, [1, 2, 3]],
Sorted = [1, 2, 8, [1, 2, 3], [3, 4, 6, [...|...]|...]]
I was trying to write predicate divide(L,Len,Slist) which will be true when Slist can unify with a List of length Len allocated from List L. for example
divide([1,2,3,4,5,6,7],3,Slist).
Should give such answers
Slist=[1,2,3];
Slist=[2,3,4];
Slist=[3,4,5];
Slist=[4,5,6];
Slist=[5,6,7];
But i couldn't find a better way then length(X,Len), sublist(L,X). but it does work too slow.
How should look divide predicate?
Alternatively you could use DCG as mentionned by #false in this great answer:
seq([]) --> [].
seq([E|Es]) --> [E], seq(Es).
divide(List, Length, Result) :-
length(Result, Length),
phrase((seq(_), seq(Result), seq(_)), List).
sublist/2 doesn't seems to work as expected:
?- [library(dialect/sicstus/lists)].
% library(dialect/sicstus/lists) compiled into sicstus_lists 0,00 sec, 14 clauses
true.
?- L=[1,2,3,4,5,6], length(T, 3),sublist(T,L).
L = [1, 2, 3, 4, 5, 6],
T = [1, 2, 3] ;
L = [1, 2, 3, 4, 5, 6],
T = [1, 2, 4] ;
L = [1, 2, 3, 4, 5, 6],
T = [1, 2, 5] ;
....
You could use append/3 instead:
?- L=[1,2,3,4,5,6], length(T, 3), append(_, Q, L), append(T, _, Q).
L = [1, 2, 3, 4, 5, 6],
T = [1, 2, 3],
Q = [1, 2, 3, 4, 5, 6] ;
L = [1, 2, 3, 4, 5, 6],
T = [2, 3, 4],
Q = [2, 3, 4, 5, 6] ;
L = [1, 2, 3, 4, 5, 6],
T = [3, 4, 5],
Q = [3, 4, 5, 6] ;
L = [1, 2, 3, 4, 5, 6],
T = Q, Q = [4, 5, 6] ;
false.
I don't think it's very fast, just essential...