diff --git a/build.zig b/build.zig index aca1ad9..4636075 100644 --- a/build.zig +++ b/build.zig @@ -97,6 +97,13 @@ pub fn build(b: *std.Build) void { .name = "knapsack.zig", .category = "dynamicProgramming" }); + if (std.mem.eql(u8, op, "dp/longestIncreasingSubsequence")) + build_algorithm(b, .{ + .optimize = optimize, + .target = target, + .name = "longestIncreasingSubsequence.zig", + .category = "dynamicProgramming" + }); // Math algorithms if (std.mem.eql(u8, op, "math/ceil")) diff --git a/dynamicProgramming/longestIncreasingSubsequence.zig b/dynamicProgramming/longestIncreasingSubsequence.zig new file mode 100644 index 0000000..bc78012 --- /dev/null +++ b/dynamicProgramming/longestIncreasingSubsequence.zig @@ -0,0 +1,68 @@ +const std = @import("std"); +const print = std.debug.print; +const testing = std.testing; +const ArrayList = std.ArrayList; + +// Function that returns the lower bound in O(logn) +pub fn lower_bound(arr: []const i32, key: i32) usize { + var lo: usize = 0; + var hi: usize = arr.len; + + while (lo < hi) { + const mid: usize = lo + (hi - lo) / 2; + if (key <= arr[mid]) { + hi = mid; + } else { + lo = mid + 1; + } + } + + if (lo < arr.len and arr[lo] < key) { + lo += 1; + } + + return lo; +} + +// Function that returns the length of the longest increasing subsequence of an array +// Runs in O(nlogn) using the lower bound function +// Arguments: +// arr: the passed array +// allocator: Any std.heap type allocator +pub fn lis(arr: []const i32, allocator: anytype) usize { + var v = ArrayList(i32).init(allocator); + defer v.deinit(); + + const n = arr.len; + + for (0..n) |i| { + const it = lower_bound(v.items, arr[i]); + if (it == v.items.len) { + _ = v.append(arr[i]) catch return 0; + } else { + v.items[it] = arr[i]; + } + } + + return v.items.len; +} + +test "testing longest increasing subsequence function" { + var gpa = std.heap.GeneralPurposeAllocator(.{}){}; + defer _ = gpa.deinit(); + + const v = [4]i32{ 1, 5, 6, 7 }; + try testing.expect(lis(&v, gpa.allocator()) == 4); + + const v2 = [5]i32{ 1, -1, 5, 6, 7 }; + try testing.expect(lis(&v2, gpa.allocator()) == 4); + + const v3 = [5]i32{ 1, 2, -1, 0, 1 }; + try testing.expect(lis(&v3, gpa.allocator()) == 3); + + const v4 = [0]i32{}; + try testing.expect(lis(&v4, gpa.allocator()) == 0); + + const v5 = [5]i32{ 0, 0, 0, 0, 0 }; + try testing.expect(lis(&v5, gpa.allocator()) == 1); +} diff --git a/runall.cmd b/runall.cmd index a971e85..3848b0f 100644 --- a/runall.cmd +++ b/runall.cmd @@ -25,6 +25,7 @@ rem Data Structures rem Dynamic Programming %ZIG_TEST% -Dalgorithm=dp/coinChange %Args% %ZIG_TEST% -Dalgorithm=dp/knapsack %Args% +%ZIG_TEST% -Dalgorithm=dp/longestIncreasingSubsequence %Args% rem Sort %ZIG_TEST% -Dalgorithm=sort/quicksort %Args% diff --git a/runall.sh b/runall.sh index 9e394f7..cdd3947 100755 --- a/runall.sh +++ b/runall.sh @@ -25,6 +25,7 @@ $ZIG_TEST -Dalgorithm=ds/lrucache $Args # Dynamic Programming $ZIG_TEST -Dalgorithm=dp/coinChange $Args $ZIG_TEST -Dalgorithm=dp/knapsack $Args +$ZIG_TEST -Dalgorithm=dp/longestIncreasingSubsequence $Args ## Sort $ZIG_TEST -Dalgorithm=sort/quicksort $Args