| Bytes | Lang | Time | Link |
|---|---|---|---|
| 814 | Zig | 250214T134501Z | 138 Aspe |
| 194 | Elixir | 250214T071027Z | 138 Aspe |
| 041 | Haskell + hgl | 240720T020113Z | Wheat Wi |
| nan | C89 | 230801T055849Z | Pignotto |
| nan | Rust | 230729T140042Z | mousetai |
| 047 | JavaScript Node.js | 230801T035122Z | l4m2 |
| 108 | Ruby | 230731T013302Z | Value In |
| 053 | Perl 5 | 230730T232032Z | good old |
| 008 | Nekomata + e | 230731T072004Z | alephalp |
| 026 | Charcoal | 230730T140337Z | Neil |
| 073 | Haskell | 230730T123742Z | Gurkengl |
| 059 | JavaScript Node.js | 230730T075502Z | tsh |
| 095 | JavaScript | 230729T144258Z | bsoelch |
| 144 | Retina 0.8.2 | 230730T075426Z | Neil |
| 139 | Haskell | 230730T070715Z | LeopardS |
| nan | Scala | 230729T153542Z | 138 Aspe |
| 013 | Jelly | 230729T164305Z | Jonathan |
Zig, 814 bytes
814 bytes, it can be golfed much more.
Golfed version. Attempt This Online!
const P = struct { f: i32, s: i32 };
fn f(a: []const i8, b: []const i8) bool {
const A=std.heap.page_allocator;
var s=std.ArrayList(P).init(A);
defer s.deinit();
s.append(P{.f=0,.s=0}) catch unreachable;
for (0..a.len)|i| {
var n= std.ArrayList(P).init(A);
for (s.items)|p|{
const x1=p.f+a[i];
const y1=p.s+b[i];
const x2=p.f+b[i];
const y2=p.s+a[i];
if(x1>=0 and y1>=0){
n.append(.{.f=x1, .s=y1}) catch unreachable;
}
if (x2>=0 and y2>=0) {
n.append(.{ .f=x2, .s=y2}) catch unreachable;
}
}
s.deinit();
s=n;
}
for (s.items)|p|{
if (p.f==0 and p.s==0){
return 1<2;
}
}
return 1>2;
}
Ungolfed version. Attempt This Online!
const std = @import("std");
const TestCase = struct {
a: []const i8,
b: []const i8,
expected: bool,
};
// Define a Pair struct
const Pair = struct {
first: i32,
second: i32,
};
fn f(a: []const i8, b: []const i8) bool {
const alloc = std.heap.page_allocator;
var state = std.ArrayList(Pair).init(alloc);
defer state.deinit(); // We'll only deinit `state` at the very end
// Start state with (0, 0)
_ = state.append(Pair{ .first = 0, .second = 0 }) catch unreachable;
// Iterate over elements in `a` (and `b`)
// Prefer "for (a) |_, i|" or "for (0..a.len) |i|" in modern Zig.
for (0..a.len) |i| {
var nextState = std.ArrayList(Pair).init(alloc);
// IMPORTANT: do NOT `defer nextState.deinit();` here, since we'll move it into `state`.
for (state.items) |pair| {
const x1 = pair.first + a[i];
const y1 = pair.second + b[i];
const x2 = pair.first + b[i];
const y2 = pair.second + a[i];
if (x1 >= 0 and y1 >= 0) {
_ = nextState.append(.{ .first = x1, .second = y1 }) catch unreachable;
}
if (x2 >= 0 and y2 >= 0) {
_ = nextState.append(.{ .first = x2, .second = y2 }) catch unreachable;
}
}
// Deinit old `state`
state.deinit();
// Transfer ownership from `nextState` to `state`
state = nextState;
}
// Finally, check if (0,0) is in the final `state`
for (state.items) |pair| {
if (pair.first == 0 and pair.second == 0) {
return true;
}
}
return false;
}
pub fn main() !void {
const stdout = std.io.getStdOut().writer();
// Each test case has slices a and b, and the expected boolean value
const testCases = [_]TestCase{
.{ .a = &[_]i8{1}, .b = &[_]i8{-1}, .expected = false },
.{ .a = &[_]i8{ 1, -1 }, .b = &[_]i8{ 1, -1 }, .expected = true },
.{ .a = &[_]i8{ 1, 1, 1, -1, -1, -1 }, .b = &[_]i8{ 1, -1, 1, -1, 1, -1 }, .expected = true },
.{ .a = &[_]i8{ 1, -1, 1, -1, -1, -1 }, .b = &[_]i8{ 1, 1, 1, -1, 1, -1 }, .expected = true },
.{ .a = &[_]i8{ -1, -1, -1, 1, 1, 1 }, .b = &[_]i8{ 1, 1, 1, -1, -1, -1 }, .expected = false },
.{ .a = &[_]i8{ -1, -1, -1, -1, -1, -1, -1 }, .b = &[_]i8{ -1, -1, -1, -1, -1, -1 }, .expected = false },
.{ .a = &[_]i8{ -1, -1, -1, -1, -1, -1, -1 }, .b = &[_]i8{ -1, -1, -1, -1, -1, -1, -1 }, .expected = false },
.{ .a = &[_]i8{ 1, -1, -1, -1, -1, -1, -1 }, .b = &[_]i8{ 1, 1, 1, 1, 1, 1, -1 }, .expected = false },
};
// Run each test case
for (testCases) |testCase| {
const result = f(testCase.a, testCase.b);
// Print arrays a
try stdout.print("a: {{ ", .{});
for (testCase.a, 0..) |val, idx| {
try stdout.print("{any}{any}", .{ val, if (idx < testCase.a.len - 1) ", " else "" });
}
try stdout.print(" }} ", .{});
// Print arrays b
try stdout.print("b: {{ ", .{});
for (testCase.b, 0..) |val, idx| {
try stdout.print("{any}{any}", .{ val, if (idx < testCase.b.len - 1) ", " else "" });
}
try stdout.print(" }} ", .{});
try stdout.print("expected: {any}, got: {any}\n", .{ testCase.expected, result });
}
}
Elixir, 194 bytes
Golfed version. Attempt This Online!
def f(a,b),do: Enum.zip(a,b)|>Enum.reduce([{0,0}],fn{x,y},d->d|>Enum.flat_map(fn{p,q}->[{p+x,q+y},{p+y,q+x}]end)|>Enum.filter(fn{x,y}->x>=0 and y>=0 end)end)|>Enum.any?(fn{x,y}->{x,y}=={0,0}end)
Ungolfed version. Attempt This Online!
defmodule Main do
# This function corresponds to 'f' in the Scala code.
# It takes two lists of integers (originally bytes in Scala)
# and returns a boolean.
def f(a, b) do
# Start with the initial accumulator of [{0, 0}]
# Then for each pair {x, y}, expand each accumulator entry {p, q}
# into two possibilities, filtering out negative coordinates.
# Finally check if we have (0, 0) in the resulting list.
Enum.zip(a, b)
|> Enum.reduce([{0, 0}], fn {x, y}, acc ->
acc
|> Enum.flat_map(fn {p, q} ->
[
{p + x, q + y},
{p + y, q + x}
]
end)
|> Enum.filter(fn {px, py} ->
px >= 0 and py >= 0
end)
end)
|> Enum.any?(fn {px, py} -> {px, py} == {0, 0} end)
end
# For demonstration, let's mimic the original test cases
def run_tests do
test_cases = [
{[1], [-1], false},
{[1, -1], [1, -1], true},
{[1, 1, 1, -1, -1, -1], [1, -1, 1, -1, 1, -1], true},
{[1, -1, 1, -1, -1, -1], [1, 1, 1, -1, 1, -1], true},
{[-1, -1, -1, 1, 1, 1], [1, 1, 1, -1, -1, -1], false},
# Equivalent to Seq.fill(6)((-1).toByte)
{Enum.map(1..6, fn _ -> -1 end), Enum.map(1..6, fn _ -> -1 end), false},
# Equivalent to Seq.fill(7)((-1).toByte)
{Enum.map(1..7, fn _ -> -1 end), Enum.map(1..7, fn _ -> -1 end), false},
# (Seq(1.toByte) ++ Seq.fill(6)((-1).toByte), Seq.fill(6)(1.toByte) ++ Seq((-1).toByte))
{[1] ++ Enum.map(1..6, fn _ -> -1 end), Enum.map(1..6, fn _ -> 1 end) ++ [-1], false}
]
for {seq_a, seq_b, expected} <- test_cases do
got = f(seq_a, seq_b)
IO.puts("#{inspect(seq_a)} #{inspect(seq_b)} expected: #{inspect(expected)}, got: #{inspect(got)}")
end
end
end
# If you want to invoke the tests when running the file, you can call:
Main.run_tests()
Haskell + hgl, 41 bytes
mx<(zWn~<rv)<(no lt0*^*q0<gj)<<scp<<sQ<tx
Takes the input as a list of length 2 with 1 representing ( and -1 representing ).
I'm not convinced this is as short as possible. It does outperform a naïve conversion of the shortest pure Haskell answer. I will come back to this later and try again.
Explanation
txtranspose the input.sQperform the cartesian product.scpscan each element with addition to get the cumulative sums.no lt0check elements have no negative values ...*^*... and ...gj... end in ...q0... zero.zWn~<rvzip the result with its reverse using logical and.mxdetermine if any result is true.
Reflection
I'm a bit annoyed by how long this is. I also don't like the input format and feel like it's indicative of a weakness. I'd prefer to take it as two separate arguments.
- This feels like not the first time I've used
sQ<tx. It will probably be useful and should have a builtin. - There should be a builtin to determine if a string is balanced. We could do this as:
if such a builtin existed. (Input format would be a list of two strings.)mx<(zWn~<rv)<blp<<sQ<tx - For all the
zWvariants we already have, there could be versions that apply a function to each element before combining them with the fixed function. This would save a little plumbing here. - I'm debating whether there should be a
mx<<zWnandmn<<zWX, we use the former here and the latter here. It seems like it might be a recurring pattern.
C89, 79 77 69 bytes
r,c;f(*a,*b){for(c=r=1;*a&0<c;++a)c+=*a^*b++?r=-r:*a;return c==1==r;}
Using (int)1 as '(' and (int)-1 as ')'
int diff;
int count;
int check(int *a, int *b)
{
for ( c=1, r=1; *a!=0 && 0<c; ++a, ++b )
{
c += (*a != *b) ? (r=-r) : *a;
}
return (c==1) == r;
}
The logic is based on the consideration that if a solution exists, it will get a count on the nodes of different values lower than what it would get by alternating between '(' and ')', so that would also be a solution
Rust, 204 179 147 132 123 98 90 80 bytes
|a,b|a.iter().zip(b).fold([0;3],|[c,d,f],(&e,g)|[c+e+g,d^e^g,f.min(c+d)])==[0;3]
- -9 bytes thanks to SUTerliankov
- -2 bytes thanks to SUTerliankov
Radically new algorithm. We know the only possible failure case is if:
- We get 2 simultaneous closing parenthesis when the nesting level is 0
- We get 2 different closing parenthesis when the nesting level is 0
We use d to store if there currently is an odd or even number of unequal pairs. If the nesting level c-d is negative, we fail. If the nesting level is not 0 or the number of unequal pairs is not even at the end we fail.
d^((e^!g)+1)/2 should be 1 if e=g and 0 otherwise.
Uses 1 to represent an opening parenthesis and -1 for closing.
JavaScript (Node.js), 47 bytes
Input: array, 2([), -2(])
Output: integer, 0(balanced), truthy(not)
a=>b=>a.some((v,i)=>0<(S=v-b[i]?S^1:S-v),S=0)|S
JavaScript (Node.js), 52 bytes
a=>b=>!a.some((v,i)=>1<(S-=v-b[i]?j^=-2:v),S=j=1)==S
1 if true
0 if some ")" mismatched, in which case S>1 so S!=0
|
a=>b=>!a.some((v,i)=>1<(S-=v-b[i]?j^=-2:v),S=j=1)==S
|
'-- If more ")" appeared
Ruby, 108 bytes
Brute forces all combinations of the two inputs until it finds one that is balanced. Input is an array containing two arrays of integers, where 1 represents ( and -1 represents ).
->a{(v=0,1).product(*[v]*~-a[0].size).any?{i=-1;j=k=0;_1.all?{|n|(j+=a[n][i+=1])|(k+=a[1-n][i])>=0}&&j|k<1}}
Perl 5, 53 bytes
sub{y/(/#/for@_;((pop)&pop)=~/^(#((!?)(?1)*\3)\))+$/}
First (wrong) version is in editing history, this one seems to pass. Please tell if it fails some test.
Nekomata + -e, 8 bytes
Ťᵐ↕∫Ɔž∑≤
Takes input as a list of lists of -1 and 1 representing ( and ) respectively. For example, [[-1,1,1,1],[-1,-1,-1,1]] represents ())) ((().
Ťᵐ↕∫Ɔž∑≤
Ť Transpose
ᵐ↕ Non-deterministically permute each inner list
∫ Cumulative sum
Ɔ Split into the last element and the rest
ž Check if the last element is all 0s
∑ Sum; since the last element is all 0s, this will be 0
≤ Is the rest less than or equal to this sum (0)?
Charcoal, 26 bytes
∧⁼№⁺θη(Lθ⬤θ›№⁺…θ⊕κ…η⊕κ(|κ¹
Try it online! Link is to verbose version of code. Outputs a Charcoal boolean, i.e. - for balanced, nothing if not. Explanation:
θ First input
⁺ Concatenated with
η Second input
№ Count of
) Literal string `)`
⁼ Equals
θ First input
L Length
∧ Logical And
θ First input
⬤ All characters satisfy
θ First input
… Truncated to length
κ Current index
⊕ Incremented
⁺ Concatenated with
η Second input
… Truncated to length
κ Current index
⊕ Incremented
№ Count of
( Literal string `(`
› Is greater than
κ Current index
| Bitwise Or
¹ Literal integer `1`
The idea here is that the strings can be balanced if the following two conditions hold:
- Exactly half of all of the characters are
(s. - For each prefix of both strings, there are more
(s than the 0-indexed position of the last character of the prefix, plus 1 if that is even.
Examples:
1st 2nd (s Needed
Valid:
( ( 2 >1
() (( 3 >1
()) ((( 4 >3
())) ((() 4 >3
Invalid:
( ( 2 >1
(( () 3 >1
(() ()) 3 >3
(()) ())( 4 >3
Haskell, 77 73 bytes
o a b=all(<1)$scanr(%)0$3:zipWith(+)a b
3%c= -c
0%c=c+1-2*mod c 2
n%c=c+n
The other Haskell entry sets the precedent that (=1 and )=-1. The right-to-left running totals of A and B are to stay <1 (and end >-1, as checked by 3%). A+B has all information we need. Wlog the running total of A-B stays in [0,2]. scanr(%)0 maps A+B to the running total of A+B + (A-B)/2.
JavaScript (Node.js), 59 bytes
a=>b=>(h=u=>u<d|!a[i]?u|d:h(u+=p=a[i]+b[i++],d^=!p))(i=d=0)
Input arrays of numbers: 0.5 for (, -0.5 for ). Output falsy (0) for "can be balanced", truthy (non-zero) for "cannot be balanced".
Construct a string c using inputs a and b by:
- if the i-th characters match, aka.
a[i]==b[i], thenc[i]=a[i] - Otherwise, they mismatch. For the k-th mismatch (1-indexed),
c[i]=')'when k is odd, andc[i]='('when k is even.
Test if c is balanced and there are even number of mismatching.
In above code, u-d is how many unclosed "(" in string c. d is a boolean, truthy when next mismatch should be "(".
I’m feeling its correctness. Although I don’t have a mathematical proof to it. However, at least no testcase rejects it currently.
JavaScript, 109 107 ... 95 bytes
Thanks to @Arnauld for saving 2 bytes
b=(x,k=0n)=>k<0?0:x?b(x/4n,k+x%4n-2n):!k
f=(l,r,k=0n,x=k&(r^l))=>b(l^x)&b(r^x)||k<l&&f(l,r,++k)
returns false (for false) or 1 (for true).
Encodes expressions as base four numbers with 3 for ( and 1 for )
Helper functions for converting strings to the corresponding base 4 numbers
e=(s)=>s?4n*e(s.slice(1))+(s[0]=='('?3n:1n):0n
h=(x,y)=>f(e(x),e(y))
h(")))(((","((()))") // -> false
I was unable to verify the last two Test-cases, as the function exceeded the maximum recursion depth (which as far as I known is allowed for code-golf)
Explanation
b checks if a the expression encoded by the given number is balanced, by counting the difference of 3 digits minus 1 digits and returning 0 if the intermediate count goes below zero,
or if the final count is not exactly zero.
f checks for all binary numbers k less than l (swapping the outer brackets cannot balance the expression) if swapping the bits of the two inputs at the positions that are one in k will result in a pair of balanced strings.
Swapping a bit has no effect if it is the low bit of a base 4 digit where both numbers have a 1 bit, if it is the high bit it will swap the characters that the given positions in the strings.
JavaScript, 108 bytes
b=(x,k=0n)=>k<0?0:x?b(x/4n,k+x%4n-2n):!k
f=l=>r=>eval("for(v=0,k=0n;k<l;k++)v|=b(l^k&(r^l))&b(r^k&(r^l));v")
uses for-loop to prevent crash due to recursion limit
Retina 0.8.2, 144 bytes
|^
$&#
+%`^(((\()|(?<-3>\)))*)#(.)(.* ((\()|(?<-7>\)))*)#(.)
$1$4#$5$8#$'¶$1$8#$5$4#
G`^((\()|(?<-2>\)))*(?(2)$)# ((\()|(?<-4>\)))*(?(4)$)#$
^.
Try it online! Link includes test cases. Explanation:
|^
$&#
Place markers at the start of each string to determine progress through them.
^(((\()|(?<-3>\)))*)#(.)(.* ((\()|(?<-7>\)))*)#(.)
$1$4#$5$8#$'¶$1$8#$5$4#
If the current prefix of both strings is a validly balanced prefix, then progress through the string, generating results with and without a swap of the next character. Testing of balanced prefixes is unsurprisingly performed using .NET's balancing groups.
+%`
Repeat the above separately on each intermediate result until no new results can be obtained.
G`^((\()|(?<-2>\)))*(?(2)$)# ((\()|(?<-4>\)))*(?(4)$)#$
Keep only those results that progressed through the whole string and also are completely balanced rather than simply a balanced prefix (using conditional regex to enforce that the balancing group is now empty).
^.
Check that we had at least one result.
Haskell, 139 bytes
g=(\c->all(>=0) c&&last c==0).scanl(+)0
o j k=any(\(d,e)->g d&&g e).foldr(\(x,y)h->concat[[(x:a,y:b),(y:a,x:b)]|(a,b)<-h])[([],[])]$zip j k
foldr(\(x,y)h->concat[[(x:a,y:b),(y:a,x:b)]|(a,b)<-h])[([],[])]$zip j k gives a list of all possible pairs. o then uses g, which determines if a string is balanced, to get the final result. Input is taken as a sequence, with 1 representing '(' and −1 representing ')'.
Scala, 165 136 bytes
Port of @mousetail's Rust answer in Scala.
Golfed version. Try it online!
Saved 29 bytes thanks to the comment of @corvus_192
(a,b)=>(a zip b)./:(Seq((0,0))){case(c,(z,y))=>c.flatMap{case(f,v)=>Seq((f+z,v+y),(f+y,v+z))}filter(g=>g._1>=0&&g._2>=0)}exists((0,0)==)
Ungolfed version. Try it online!
object Main {
def main(args: Array[String]): Unit = {
val f: (Seq[Byte], Seq[Byte]) => Boolean = (a, b) => {
a.zip(b).foldLeft(Seq[(Int, Int)]((0,0))) { (c, de) =>
c.flatMap { f =>
Seq((f._1 + de._1, f._2 + de._2), (f._1 + de._2, f._2 + de._1))
}.filter(g => g._1 >= 0 && g._2 >= 0)
}.exists(_ == (0, 0))
}
val testCases = Seq(
(Seq(1.toByte), Seq((-1).toByte), false),
(Seq(1.toByte, (-1).toByte), Seq(1.toByte, (-1).toByte), true),
(Seq(1.toByte, 1.toByte, 1.toByte, (-1).toByte, (-1).toByte, (-1).toByte), Seq(1.toByte, (-1).toByte, 1.toByte, (-1).toByte, 1.toByte, (-1).toByte), true),
(Seq(1.toByte, (-1).toByte, 1.toByte, (-1).toByte, (-1).toByte, (-1).toByte), Seq(1.toByte, 1.toByte, 1.toByte, (-1).toByte, 1.toByte, (-1).toByte), true),
(Seq((-1).toByte, (-1).toByte, (-1).toByte, 1.toByte, 1.toByte, 1.toByte), Seq(1.toByte, 1.toByte, 1.toByte, (-1).toByte, (-1).toByte, (-1).toByte), false),
(Seq.fill(6)((-1).toByte), Seq.fill(6)((-1).toByte), false),
(Seq.fill(7)((-1).toByte), Seq.fill(7)((-1).toByte), false),
(Seq(1.toByte) ++ Seq.fill(6)((-1).toByte), Seq.fill(6)(1.toByte) ++ Seq((-1).toByte), false)
)
for (testCase <- testCases) {
println(s"${testCase._1} ${testCase._2} expected: ${testCase._3}, got: ${f(testCase._1, testCase._2)}")
}
}
}
Jelly, 13 bytes
ZŒpÄṂȯṪƊ€oṚ$Ạ
A monadic Link that accepts a pair of lists of \$\{1,-1\}\$ representing ( and ) respectively and yields \$0\$ if balancable or \$1\$ if not (i.e. outputs the inverse).
Try it online! Or see the test-suite.
How?
ZŒpÄṂȯṪƊ€oṚ$Ạ - Link: pair of lists of -1 and 1 := ) and ( respectively
Z - transpose
Œp - Cartesian product
Ä - cumulative sums (vectorises)
Ɗ€ - for each: last three links as a monad:
Ṫ - tail
Ṃ - minimum (of the rest)
ȯ - {minimum} logical OR {tail}
$ - last two links as a monad:
Ṛ - reverse
o - logical OR (vectorises)
Ạ - all?