Check if Sudoku solution is valid [closed] - sudoku

Closed. This question needs to be more focused. It is not currently accepting answers.
Want to improve this question? Update the question so it focuses on one problem only by editing this post.
Closed 7 years ago.
Improve this question
You're given a solution to a Sudoku puzzle. Write the code to check if it's a valid solution.
Your function signature should be:
boolean isValid(int starti, int startj, int endi, int endj)
Rules for those unfamiliar with Sudoku:
Grid size is 9x9, divided into 9 regions of 3x3
Each row must contain all digits from 1-9
Each column must contain all digits from 1-9
Each 3x3 square must contain all digits from 1-9
I wasn't asked this question, but saw it on several places. Checking the last rule might be the interesting part

// rows
for (int i=0; i<9; i++) {
std::bitset<9> filled;
for (int j=0; j<9; j++)
filled.set(grid[i][j] - 1);
if (filled.count() != 9)
return false;
}
// ... similar with the loops "swapped" to get the columns
// (or do both in one loop)
for (int i=0; i<9; i += 3)
for (int j=0; j<9; j += 3) {
std::bitset<9> filled;
for (int k=0; k<3; k++)
for (int l=0; l<3; l++)
filled.set(grid[i+k][j+l] - 1);
if (filled.count() != 9)
return false;
}
return true;

Sorry, I know this must be homework, but I can't help myself. It's just too much fun to come up with something :-)
A spoon full of LINQ makes the medicine go down:
public class Sudoku
{
private int[][] sudoku;
public Sudoku(int[][] sudoku)
{
// TODO: Validate bounds and values
this.sudoku = sudoku;
}
public bool Validate() =>
VerticalLines.All(IsValid)
&& HorizontalLines.All(IsValid)
&& Squares.All(IsValid);
IEnumerable<IEnumerable<int>> VerticalLines =>
from line in sudoku select line;
IEnumerable<IEnumerable<int>> HorizontalLines =>
from y in Enumerable.Range(0, 9)
select (
from x in Enumerable.Range(0, 9)
select sudoku[x][y]);
IEnumerable<IEnumerable<int>> Squares =>
from x in Enumerable.Range(0, 3)
from y in Enumerable.Range(0, 3)
select GetSquare(x, y);
IEnumerable<int> GetSquare(int x, int y) =>
from squareX in Enumerable.Range(0, 3)
from squareY in Enumerable.Range(0, 3)
select sudoku[x * 3 + squareX][y * 3 + squareY];
bool IsValid(IEnumerable<int> line) => !(
from item in line
group item by item into g
where g.Count() > 1
select g)
.Any();
}
The nice thing about this solution is, that no teacher will believe you if you say you came up with this ;-)

SQL allows you to define the rules as CONSTRAINTS: invalid puzzels are forbidden and cannot exist.
-- Domain with only values 1..9 allowed,
-- used for both the {x,y,z} coordinates and the cell values.
CREATE DOMAIN one_nine
AS INTEGER
CHECK (value >= 1 AND value <= 9)
;
-- Table containing exactly one sudoku puzzle.
-- The zzz coordinate (the "box number") is formally redundant
-- (since it is functionally dependant on {xxx,yyy})
DROP TABLE IF EXISTS sudoku3 CASCADE;
CREATE TABLE sudoku3
( yyy one_nine NOT NULL
, xxx one_nine NOT NULL
, zzz one_nine NOT NULL
, val one_nine
);
-- First constraint: (x,y) is unique
ALTER TABLE sudoku3 ADD PRIMARY KEY (xxx,yyy);
-- Three constraints for unique values for {rows,columns,boxes}
CREATE UNIQUE INDEX sudoku_xv ON sudoku3 (xxx,val);
CREATE UNIQUE INDEX sudoku_yv ON sudoku3 (yyy,val);
CREATE UNIQUE INDEX sudoku_zv ON sudoku3 (zzz,val);
-- Create empty board.
INSERT INTO sudoku3 (yyy, xxx, zzz)
SELECT 1+(nn/9)
, 1+(nn%9)
, 1+3*((nn/3)%3)+1*(nn/27)
-- generate_series() is postgres-specific
FROM generate_series(0,80) AS nn;
Now, the ->val members can be updated, but the resulting table can never violate any of the four constraints (three are actually INDEXES, but that is unimportant here).
Checking for a completely valid filled-in table means: checking if there are 81 non-NULL entries:
SELECT 1 AS result -- COUNT(*)
FROM sudoku3
WHERE val IS NOT NULL
HAVING COUNT(*) = 81
;

A Java implementation using bit sets:
public static boolean isValid(int[][] board) {
//Check rows and columns
for (int i = 0; i < board.length; i++) {
BitSet bsRow = new BitSet(9);
BitSet bsColumn = new BitSet(9);
for (int j = 0; j < board[i].length; j++) {
if (board[i][j] == 0 || board[j][i] == 0) continue;
if (bsRow.get(board[i][j] - 1) || bsColumn.get(board[j][i] - 1))
return false;
else {
bsRow.set(board[i][j] - 1);
bsColumn.set(board[j][i] - 1);
}
}
}
//Check within 3 x 3 grid
for (int rowOffset = 0; rowOffset < 9; rowOffset += 3) {
for (int columnOffset = 0; columnOffset < 9; columnOffset += 3) {
BitSet threeByThree = new BitSet(9);
for (int i = rowOffset; i < rowOffset + 3; i++) {
for (int j = columnOffset; j < columnOffset + 3; j++) {
if (board[i][j] == 0) continue;
if (threeByThree.get(board[i][j] - 1))
return false;
else
threeByThree.set(board[i][j] - 1);
}
}
}
}
return true;
}

This would my solution in ruby
#Sudoku grid 9x9 with numbers between 1 and 9
#three rules:
#1) in any row all numbers between 1 and 9 have to be present
#2) in any columns all numbers between 1 and 9 have to be present
#3) in any of the 9 3x3 boxes all numbers between 1 and 9 have to be present
sudoku_correct =[[8,3,5,4,1,6,9,2,7],
[2,9,6,8,5,7,4,3,1],
[4,1,7,2,9,3,6,5,8],
[5,6,9,1,3,4,7,8,2],
[1,2,3,6,7,8,5,4,9],
[7,4,8,5,2,9,1,6,3],
[6,5,2,7,8,1,3,9,4],
[9,8,1,3,4,5,2,7,6],
[3,7,4,9,6,2,8,1,5]]
sudoku_incorrect =[[8,3,5,4,1,6,9,2,7],
[2,9,6,8,5,7,4,3,1],
[4,1,7,2,9,3,6,5,8],
[5,6,9,1,3,4,7,8,2],
[1,2,3,6,7,8,5,4,9],
[7,4,8,5,2,9,1,6,3],
[6,5,2,7,8,1,3,9,4],
[9,8,1,3,4,5,2,7,6],
[3,7,4,9,6,2,8,1,1]]
class Sudoku
def initialize(s_arr)
#sudoku_arr = s_arr
end
# given 9 integers makesure that you have 1 to 9
def valid_contents?(set)
set.each do |e|
return false unless (1..9).include?(e)
end
return true
end
# check if set has no duplicates
def has_no_duplicates?(set)
set.uniq.size < set.size ? false : true
end
def valid_set?(set)
valid_contents?(set) && has_no_duplicates?(set)
end
# obtain blocks of sudoku, given a grid
def get_blocks(s_grid)
blocks = []
s_grid.each_slice(3) do |row_set|
blocks_temp = [[],[],[]]
row_set.each do |row|
row.each_slice(3).with_index do|s,i|
blocks_temp[i] = blocks_temp[i] + s
end
end
blocks += blocks_temp
end
blocks
end
def valid?(s_arr = #sudoku_arr)
#check for row validity
s_arr.each do |set|
return false unless valid_set?(set)
end
#check for block validity
get_blocks(s_arr).each do |set|
return false unless valid_set?(set)
end
#check column validity
s_arr.transpose.each do |set|
return false unless valid_set?(set)
end
true
end
end
puts Sudoku.new(sudoku_correct).valid?
puts Sudoku.new(sudoku_incorrect).valid?
# output: True & False

the solution which use just one array iteration.
through the whole iteration of array, posRec array is going to have each numbers availability in ROW/COL/GRID.
if there is missing bit in posRec, we can say sudoku isn’t correct.
#include <stdio.h>
#define ROW 0
#define COL 1
#define GRID 2
#define TRUE 1
#define FALSE 0
char sudoku_correct[9][9] ={{8,3,5,4,1,6,9,2,7},
{2,9,6,8,5,7,4,3,1},
{4,1,7,2,9,3,6,5,8},
{5,6,9,1,3,4,7,8,2},
{1,2,3,6,7,8,5,4,9},
{7,4,8,5,2,9,1,6,3},
{6,5,2,7,8,1,3,9,4},
{9,8,1,3,4,5,2,7,6},
{3,7,4,9,6,2,8,1,5}};
char sudoku_incorrect[9][9] ={{8,3,5,4,1,6,9,2,7},
{2,9,6,8,5,7,4,3,1},
{4,1,7,2,9,3,6,5,8},
{5,6,9,1,3,4,7,8,2},
{1,2,3,6,7,8,5,4,9},
{7,4,8,5,2,9,1,6,3},
{6,5,2,7,8,1,3,9,4},
{9,8,1,3,4,5,2,7,6},
{3,7,4,9,6,2,8,1,1}};
short posRec[9][3];
int isValid(char a[][9]) {
int i, j, val, gIndex;
for(i=0; i <9; i++){
posRec[i][ROW] = 0;
posRec[i][COL] = 0;
posRec[i][GRID] = 0;
}
for(i=0; i<9; i++) {
for(j=0; j<9; j++) {
val=a[i][j]-1; //convert to 0-8 array index
if((posRec[val][ROW]>>i) & 0x1)
return FALSE;
posRec[val][ROW] |= (0x1<<i);
if((posRec[val][COL]>>j) & 0x1)
return FALSE;
posRec[val][COL] |= (0x1<<j);
gIndex = (j/3) + ((i/3) * 3);
if((posRec[val][GRID]>>gIndex) & 0x1)
return FALSE;
posRec[val][GRID] |= (0x1<<gIndex);
}
}
for(i=0; i<9;i++){
if(posRec[i][COL] != 0x1ff ||
posRec[i][ROW] != 0x1ff ||
posRec[i][GRID] != 0x1ff)
return FALSE;
}
return TRUE;
}
int main(){
printf("correct sudoku check = %s \n", isValid(sudoku_correct)?"CORRECT":"INCORRECT");
printf("incorrect sudoku check = %s \n", isValid(sudoku_incorrect)?"CORRECT":"INCORRECT");
return 0;
}

package Questions;
public class SudukoSonChek {
public static void main(String args[]) {
int a[][] = { { 2, 4, 8, 3, 9, 5, 7, 1, 6 },
{ 5, 7, 1, 6, 2, 8, 3, 4, 9 }, { 9, 3, 6, 7, 4, 1, 5, 8, 2 },
{ 6, 8, 2, 5, 3, 9, 1, 7, 4 }, { 3, 5, 9, 1, 7, 4, 6, 2, 8 },
{ 7, 1, 4, 8, 6, 2, 9, 5, 3 }, { 8, 6, 3, 4, 1, 7, 2, 9, 5 },
{ 1, 9, 5, 2, 8, 6, 4, 3, 7 }, { 4, 2, 7, 9, 5, 3, 8, 6, 1 } };
System.out.println(check(a));
}
public static boolean check(int arr[][]) {
int i, j;
int count[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
int count1[] = { 0, 0, 0, 0, 0, 0, 0, 0, 0, 0 };
boolean b = true;
for (i = 0; i < 9; i++) {
for (j = 0; j < 9; j++) {
if (count[arr[j][i]] > i) {
b = false;
return b;
}
if (count1[arr[i][j]] > i) {
b = false;
return b;
}
count1[arr[i][j]]++;
count[arr[j][i]]++;
}
}
return b;
}
}

In reference to the excellent answer from #Stephen, here is a solution in C# without resorting to LINQ, to show the difference between the two approaches.
This solution handles both 4x4 and 9x9 Sodoku boards.
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
namespace Sodoku
{
class Program
{
static void Main(string[] args)
{
List<string> lines = new List<string>();
lines.Add("4;1,4,2,3,2,3,1,4,4,2,3,1,3,1,4,2");
lines.Add("4;2,1,3,2,3,2,1,4,1,4,2,3,2,3,4,1");
lines.Add("9;5,3,4,6,7,8,9,1,2,6,7,2,1,9,5,3,4,8,1,9,8,3,4,2,5,6,7,8,5,9,7,6,1,4,2,3,4,2,6,8,5,3,7,9,1,7,1,3,9,2,4,8,5,6,9,6,1,5,3,7,2,8,4,2,8,7,4,1,9,6,3,5,3,4,5,2,8,6,1,7,9");
lines.Add("9;8,7,1,4,6,9,3,5,2,4,2,6,3,5,1,8,9,7,5,9,3,7,2,8,4,6,1,3,5,2,9,4,7,6,1,8,6,4,9,1,8,2,5,7,3,1,8,7,5,3,6,2,4,9,9,6,4,2,1,3,7,8,5,7,3,8,6,9,5,1,2,4,2,1,5,8,7,4,9,3,6");
lines.Add("9;1,2,7,5,3,9,8,4,6,4,5,3,8,6,1,7,9,2,8,9,6,4,7,2,1,5,3,2,8,9,3,1,7,4,6,5,3,6,5,2,8,4,9,1,7,7,4,1,9,5,6,3,2,8,9,7,4,6,2,8,5,3,1,5,1,2,7,4,3,6,8,9,6,3,8,1,9,5,2,7,4");
lines.Add("4;1,4,4,3,2,3,4,4,3,2,3,1,3,1,4,2");
foreach (var line in lines)
{
var tokens = line.Split(';');
var NxN = int.Parse(tokens[0]);
var nums = tokens[1].Trim().Split(',').Select(int.Parse).ToArray();
// Copy into Grid. Input is in row major form.
var grid = new int[NxN, NxN];
{
int i = 0;
for (int row = 0; row < NxN; row++)
{
for (int col = 0; col < NxN; col++)
{
grid[row, col] = nums[i];
i++;
}
}
}
int violations = 0;
// Check if each column passes tests for Sodoku.
{
for (int row = 0; row < NxN; row++)
{
var tempArray = new int[NxN];
for (int col = 0; col < NxN; col++)
{
tempArray[col] = grid[row, col];
}
if (IfArrayPassesSodoku(tempArray) == false)
{
violations++;
}
}
}
// Check if each row passes tests for Sodoku.
{
for (int row = 0; row < NxN; row++)
{
var tempArray = new int[NxN];
for (int col = 0; col < NxN; col++)
{
tempArray[col] = grid[col, row];
}
if (IfArrayPassesSodoku(tempArray) == false)
{
violations++;
}
}
}
// Check if each sub-grid passes tests for Sodoku.
// In 9x9 Sodoku, there are 9 subgrids of 3x3 each.
{
int NxNsub = (int)Math.Sqrt(NxN); // Length of side of sub-grid, for a 9x9 board this will be 3.
for (int row = 0; row < NxN; row += NxNsub)
{
for (int col = 0; col < NxN; col += NxNsub)
{
var tempArray = new int[NxN];
int index = 0;
for (int i = 0; i < NxNsub; i++)
{
for (int j = 0; j < NxNsub; j++)
{
tempArray[index] = grid[i + col, j + row];
index++;
}
}
if (IfArrayPassesSodoku(tempArray) == false)
{
violations++;
}
}
}
}
Console.WriteLine(violations == 0 ? "True" : "False");
// Correct output is:
// True
// False
// True
// True
// True
// False
}
Console.ReadKey();
}
/// <summary>
/// Checks to see if one-dimensional array passes Sodoku rules:
/// 1. Digits range from 1 to N.
/// 2. No repeating digits.
/// Could be way more efficient, but this solution is more readable compared to other concise forms.
/// </summary>
/// <param name="array">Array.</param>
/// <returns>True if one-dimensional array passes Sodoku rules.</returns>
static bool IfArrayPassesSodoku(int[] array)
{
int violations = 0;
// Check for repeating digits.
bool ifRepeatedDigits = (array.Distinct().ToArray().Length != array.Length);
if (ifRepeatedDigits == true)
{
return false;
}
// Check to see that it contains the digits 1 to N.
var sorted = array.OrderBy(o => o).ToArray();
if (array.Length == 4)
{
if (sorted[0] != 1 || sorted[3] != 4)
{
return false;
}
}
else if (array.Length == 9)
{
if (sorted[0] != 1 || sorted[8] != 9)
{
return false;
}
}
else
{
Console.Write("Error E5234. Invalid grid size.\n");
return false;
}
return true;
}
}
}

I had a similar task, input coming from standard input.
I used sets.
Put the element to the right row, column, and square (called box in my code).
If all 3 set's size is 9, it's valid.
#include <iostream>
#include <set>
int main()
{
//decl
std::set<int> row[9];
std::set<int> column[9];
std::set<int> box[9];
//read & store
for (int i = 0; i < 9; ++i)
{
for (int j = 0; j < 9; ++j)
{
int val;
std::cin >> val;
if ((val >= 1) && (val <= 9))
{
row[i].insert(val);
column[j].insert(val);
int k = j / 3 + i / 3 + i / 3 + i / 3;
box[k].insert(val);
}
}
}
//check
bool l = true;
int i = 0;
while (l && i < 9)
{
l = row[i].size() == 9;
++i;
}
if (!l) std::cout << "Invalid" << std::endl;
else
{
bool l = true;
int i = 0;
while (l && i < 9)
{
l = column[i].size() == 9;
++i;
}
if (!l) std::cout << "Invalid" << std::endl;
else
{
bool l = true;
int i = 0;
while (l && i < 9)
{
l = box[i].size() == 9;
++i;
}
if (!l) std::cout << "Invalid" << std::endl;
else std::cout << "Valid" << std::endl;
}
}
return 0;
}

I thought my solution was terse, but apparently so if everyone else's. Anyways, I think this is a very clear and easy to read answer in ruby I made for an interview question on 7/11/2014:
## Returns true iff the given string is a valid sudoku solution
def is_valid_solution(grid)
return false unless grid.is_a? String and grid.size == 9 * 9
validate_rows(grid) and validate_columns(grid) and validate_boxes(grid)
end
## Returns true iff the set is the chars "1", "2", ..., "9"
def is_valid_set(set)
return false if set.size != 9
(1..9).each do | x |
return false unless set.include?(x.to_s)
end
true
end
def validate_rows(grid)
(0...9).each do | row |
index = row * 9
return false unless is_valid_set(grid[index, 9])
end
true
end
def validate_columns(grid)
(0...9).each do | index |
column = (index...81).step(9).to_a.map { | i | grid[i] }.join
return false unless is_valid_set(column)
end
true
end
## This is ugly, but I'm running out of time...
TOP_LEFT_INDICES = [ 0, 1, 2, 9, 10, 11, 18, 19, 20]
TOP_MID_INDICES = [ 3, 4, 5, 12, 13, 14, 21, 22, 23]
TOP_RIGHT_INDICES = [ 6, 7, 8, 15, 16, 17, 24, 25, 26]
MID_LEFT_INDICES = [27, 28, 29, 36, 37, 38, 45, 46, 47]
MID_MID_INDICES = [30, 31, 32, 39, 40, 41, 48, 49, 50]
MID_RIGHT_INDICES = [33, 34, 35, 42, 43, 44, 51, 52, 53]
BOT_LEFT_INDICES = [54, 55, 56, 63, 64, 65, 72, 73, 74]
BOT_MID_INDICES = [57, 58, 59, 66, 67, 68, 75, 76, 77]
BOT_RIGHT_INDICES = [60, 61, 62, 69, 70, 71, 78, 79, 80]
BOX_INDICES = [TOP_LEFT_INDICES, TOP_MID_INDICES, TOP_RIGHT_INDICES,
MID_LEFT_INDICES, MID_MID_INDICES, MID_RIGHT_INDICES,
BOT_LEFT_INDICES, BOT_MID_INDICES, BOT_RIGHT_INDICES]
def validate_boxes(grid)
BOX_INDICES.each do | indices |
box = indices.map { | i | grid[i] }.join
return false unless is_valid_set(box)
end
true
end

The rows and columns can be validated in a single loop
public class SudokuChecker {
static int[][] sMatrix = {
{5,3,4,6,7,8,9,1,2},
{6,7,2,1,9,5,3,4,8},
{1,9,8,3,4,2,5,6,7},
{8,5,9,7,6,1,4,2,3},
{4,2,6,8,5,3,7,9,1},
{7,1,3,9,2,4,8,5,6},
{9,6,1,5,3,7,2,8,4},
{2,8,7,4,1,9,6,3,5},
{3,4,5,2,8,6,1,7,9}
};
public static void main(String[] args) {
if (rowColumnCheck() && boxCheck()) {
System.out.println("Valid!");
} else {
System.out.println("Invalid!");
}
}
private static boolean boxCheck() {
for (int i = 0; i < sMatrix.length; i += 3) {
for (int j = 0; j < sMatrix.length; j += 3) {
boolean[] gridMatrix = new boolean[9];
for (int k = i; k < 3 + i; k++) {
for (int l = j; l < 3 + j; l++) {
int currentNumber = sMatrix[k][l];
if (currentNumber < 1 || currentNumber > 9) {
return false;
}
gridMatrix[currentNumber - 1] = true;
}
}
for (boolean booleanValue : gridMatrix) {
if (!booleanValue) {
return false;
}
}
}
}
return true;
}
private static boolean rowColumnCheck() {
for (int i = 0; i < 9; i++) {
boolean[] rowArray = new boolean[9];
boolean[] columnArray = new boolean[9];
for (int j = 0; j < 9; j++) {
int currentNumberRow = sMatrix[i][j];
int currentNumberColumn = sMatrix[j][i];
if ((currentNumberRow < 1 || currentNumberRow > 9) && (currentNumberColumn < 1 || currentNumberColumn > 9)) {
return false;
}
rowArray[currentNumberRow - 1] = true;
columnArray[currentNumberColumn - 1] = true;
}
for (boolean booleanValue : rowArray) {
if (!booleanValue) {
return false;
}
}
for (boolean booleanValue : columnArray) {
if (!booleanValue) {
return false;
}
}
}
return true;
}
}

Related

Competitive programming - Prepare the perfect curry with ingredients P, Q, and R

Recently i got a competetive programming task which i couldn't manage to complete. Just curious to know the best solution for the problem
"A" is a zero-indexed array of N integers.
Elements of A are integers within the range [−99,999,999 to 99,999,999]
The 'curry' is a string consisting of N characters such that each character is either 'P', 'Q' or 'R' and the
corresponding index of the array is the weight of each ingredient.
The curry is perfect if the sum of the total weights of 'P', 'Q' and 'R' is equal.
write a function
makeCurry(Array)
such that, given a zero-indexed array Array consisting of N integers, returns the perfect curry of this array.
The function should return the string "noLuck" if no perfect curry exists for that Array.
For example, given array Array such that
A[0] = 3 A[1] = 7 A[2] = 2 A[3] = 5 A[4] = 4
the function may return "PQRRP", as explained above. Given array A such that
A[0] = 3 A[1] = 6 A[2] = 9
the function should return "noLuck".
The approach i tried was this
import collections
class GetPerfectCurry(object):
def __init__(self):
self.curry = ''
self.curry_stats = collections.Counter({'P': 0, 'Q': 0, 'R': 0})
pass
def get_perfect_curry(self, A):
if len(A) == 0:
return "noLuck"
A.sort(reverse=True)
for i, ele in enumerate(A):
self.check_which_key_to_add_new_element_and_add_element(ele)
if self.curry_stats['P'] == self.curry_stats['Q'] == self.curry_stats['R']:
return self.curry
else:
return "noLuck"
def check_which_key_to_add_new_element_and_add_element(self, val):
# get the maximum current value
# check if addition of new value with any of the other two key equals the max value
# if yes then add that value and append the key in the curry string
current_max_key = max(self.curry_stats, key=self.curry_stats.get)
check_for_equality = False
key_to_append = None
for key, ele in enumerate(self.curry_stats):
if ele != current_max_key:
if self.curry_stats[ele] + val == self.curry_stats[current_max_key]:
check_for_equality = True
key_to_append = ele
if check_for_equality:
self.curry_stats.update(str(key_to_append) * val)
self.curry += str(key_to_append)
pass
else:
# if no value addition equals the current max
# then find the current lowest value and add it to that key
current_lowest_key = min(self.curry_stats, key=self.curry_stats.get)
self.curry_stats.update(str(current_lowest_key)*val)
self.curry += str(current_lowest_key)
if __name__ == '__main__':
perfect_curry = GetPerfectCurry()
A = [3, 7, 2, 5, 4]
# A = [3, 6, 9]
# A = [2, 9, 6, 3, 7]
res = perfect_curry.get_perfect_curry(A)
print(res)
But it was incorrect. Scratching my head for the past four hours for the best solution for this problem
A possible algorithm is as follows:
Sum the weights. If it's not a multiple of 3, no luck. If it is, divide by 3 to get the target.
Find subsets of A that add up to target. For such subsets, remove it and you get B. Find a subset of B that adds up to target.
Here's a Java implementation (I'm not a Python guy, sorry):
import java.util.Arrays;
public class Main
{
// Test if selected elements add up to target
static boolean check(int[] a, int selection, int target)
{
int sum = 0;
for(int i=0;i<a.length;i++)
{
if(((selection>>i) & 1) == 1)
sum += a[i];
}
return sum==target;
}
// Remove the selected elements
static int[] exclude(int[] a, int selection)
{
int[] res = new int[a.length];
int j = 0;
for(int i=0;i<a.length;i++)
{
if(((selection>>i) & 1) == 0)
res[j++] = a[i];
}
return Arrays.copyOf(res, j);
}
static String getCurry(int[] a)
{
int sum = 0;
for(int x : a)
sum += x;
if(sum%3 > 0)
return "noLuck";
int target = sum/3;
int max1 = 1<<a.length; // 2^length
for(int i=0;i<max1;i++)
{
if(check(a, i, target))
{
int[] b = exclude(a, i);
int max2 = 1<<b.length; // 2^length
for(int j=0;j<max2;j++)
{
if(check(b, j, target))
return formatSolution(i, j, a.length);
}
}
}
return "noLuck";
}
static String formatSolution(int p, int q, int len)
{
char[] res = new char[len];
Arrays.fill(res, 'R');
int j = 0;
for(int i=0;i<len;i++)
{
if(((p>>i) & 1) == 1)
res[i] = 'P';
else
{
if(((q>>j) & 1) == 1)
res[i] = 'Q';
j++;
}
}
return new String(res);
}
public static void main(String[] args)
{
// int[] a = new int[]{3, 7, 2, 5, 4};
// int[] a = new int[]{1, 1, 2, -1};
int[] a = new int[]{5, 4, 3, 3, 3, 3, 3, 3};
System.out.println(getCurry(a));
}
}
You can test it here.
Hereafter so many years I'm writing code for js for needed people. (TBH I took the ref of the accepted answer)
As he mentioned, A possible algorithm is as follows:
Sum the weights. If it's not a multiple of 3, no luck. If it is, divide by 3 to get the target.
Find subsets of A that add up to target. For such subsets, remove it and you get B. Find a subset of B that adds up to target.
// Test if selected elements add up to target
function check(a, selection, target)
{
let sum = 0;
for(let i=0;i<a.length;i++)
{
if(((selection>>i) & 1) == 1)
sum += a[i];
}
return sum==target;
}
// Remove the selected elements
function exclude(a, selection)
{
let res = [a.length];
let j = 0;
for(let i=0;i<a.length;i++)
{
if(((selection>>i) & 1) == 0)
res[j++] = a[i];
}
return res
}
function getCurry(a)
{
let sum = a.reduce((accumulator, currentValue) => accumulator + currentValue);
if(sum%3 > 0)
return "noLuck";
let target = sum/3;
let max1 = 1<<a.length; // 2^length
for(let i=0;i<max1;i++)
{
if(check(a, i, target))
{
let b = exclude(a, i);
let max2 = 1<<b.length; // 2^length
for(let j=0;j<max2;j++)
{
if(check(b, j, target))
return formatSolution(i, j, a.length);
}
}
}
return "noLuck";
}
function formatSolution(p, q, len)
{
let res = new Array(len)
res.fill('R')
let j = 0;
for(let i=0;i<len;i++)
{
if(((p>>i) & 1) == 1)
res[i] = 'P';
else
{
if(((q>>j) & 1) == 1)
res[i] = 'Q';
j++;
}
}
return new String(res);
}
// let a = [3, 7, 2, 5, 4]
// let a = [1, 1, 2, -1]
let a = [5, 4, 3, 3, 3, 3, 3, 3]
getCurry(a)

Two-Dimentional array circle rotation algorithm?

Given NxN two-dimensional array. Write a function that rotates it by 1 element clockwise (almost circling move).
[1][2][3][4]
[5][6][7][8]
[9][0][1][2]
[3][4][5][6]
Becomes:
[5][1][2][3]
[9][0][6][4]
[3][1][7][8]
[4][5][6][2]
Update:
This was an online interview question - HackerRank. I couldn't solve it. All I found in StackOverflow so far are 90-degree rotation (if you found this question somewhere please share the link in comments).
I'm not very sure what kind of problem you've encountered, as obvious solution works well:
original array:
final int[][] a = { {1, 2, 3, 4}, {5, 6, 7, 8}, {9, 0, 1, 2}, {3, 4, 5, 6}};
rotation:
for (int i = 0; i < (a.length >>> 1); i++) {
final int minx = i;
final int miny = i;
final int maxx = a.length - 1 - i;
final int maxy = a.length - 1 - i;
int incx = 1, incy = 0;
int prev = a[miny][minx];
for (int x = (minx + 1), y = miny; ((x != minx) || (y != miny)); x += incx, y += incy) {
final int temp = a[y][x];
a[y][x] = prev;
prev = temp;
if ((x == maxx) && (incx == 1)) {
incx = 0;
incy = 1;
}
if ((y == maxy) && (incy == 1)) {
incx = -1;
incy = 0;
}
if ((x == minx) && (incx == -1)) {
incx = 0;
incy = -1;
}
}
a[miny][minx] = prev;
}
output:
5 1 2 3
9 0 6 4
3 1 7 8
4 5 6 2
Another solution in Java.
The row and column distances are declared rather than computed.
final int[][] a = { { 1, 2, 3, 4 }, { 5, 6, 7, 8 }, { 9, 0, 1, 2 },
{ 3, 4, 5, 6 } };
final int[][] dRow = { { 1, 0, 0, 0 }, { 1, 1, 0, -1 },
{ 1, 0, -1, -1 }, { 0, 0, 0, -1 } };
final int[][] dCol = { { 0, -1, -1, -1 }, { 0, 0, -1, 0 },
{ 0, 1, 0, 0 }, { 1, 1, 1, 0 } };
int[][] tmp = { { 0, 0, 0, 0 }, { 0, 0, 0, 0 }, { 0, 0, 0, 0 },
{ 0, 0, 0, 0 } };
// rotate a to tmp
for (int row = 0; row < a.length; row++)
for (int col = 0; col < a[row].length; col++)
tmp[row][col] = a[row + dRow[row][col]][col + dCol[row][col]];
// copy tmp to a
for (int row = 0; row < a.length; row++)
for (int col = 0; col < a[row].length; col++)
a[row][col] = tmp[row][col];
// show result
for (int row = 0; row < a.length; row++)
for (int col = 0; col < a[row].length; col++)
System.out.print((col == 0 ? "\n" : "") + a[row][col]);
I quickly gave this a go, with a slightly different approach in Python for square matrix (you specified NxN). For each layer, I unwrap, rotate and re-apply. This is definitely more work than necessary, but was easy to trace and felt logical - and works for +-n step rotation.
def rotate_matrix(m, n):
assert len(m) is len(m[0]), 'Assertion: rotation requires square matrix'
rotated_matrix = [[None] * len(m[0]) for _ in range(len(m))]
def _rotate_layer(ns):
return ns[n:] + ns[:n]
def _nth_layer(l):
left = [m[i][l-1] for i in range(l-1, len(m)-(l-1))]
bottom = m[len(m)-1-(l-1)][l:len(m)-(l-1)]
right = [m[i][len(m[0])-l] for i in reversed(range(l-1, len(m)-l))]
upper = m[l-1][len(m[0])-l-1:l-1:-1]
return left + bottom + right + upper
def _apply_layer(l):
ns = _rotate_layer(_nth_layer(l))
for i in range(l-1, len(m)-(l-1)):
rotated_matrix[i][l-1] = ns.pop(0)
for i in range(l, len(m)-(l-1)):
rotated_matrix[len(m)-1-(l-1)][i] = ns.pop(0)
for i in reversed(range(l-1, len(m)-l)):
rotated_matrix[i][len(m[0])-l] = ns.pop(0)
for i in reversed(range(l, len(m[0])-l)):
rotated_matrix[l-1][i] = ns.pop(0)
for i in range(1, len(m)/2+1):
_apply_layer(i)
return rotated_matrix

Find all M-length sets of positive integers that sum to N

The problem I'm trying to solve is how do we find all the integer sets [a1, a2, ... ,am] so that
a1 + a2 + ... + am = N
and with the constraint ai >= 1
For example if M = 4, and N = 7 there are three answers
[1,1,1,4]
[1,1,2,3]
[1,2,2,2]
Since you have to print all the sets that sum to N. You can employ a complete search algorithm using recursion. In the following code, M is the number of numbers in the set and N is the sum required.
int M;
int N;
void run(){
M = 4;
N = 7;
int[] arr = new int[M];
print(arr, 0, N, 1);
}
// req holds the required sum for the numbers in the array from arr[from]
// to arr[M-1].
// "last" holds the last value that we had put in the array.
// The first call to the array will be with last=1.
void print(int[] arr, int from, int req, int last){
// Reached the end of the array and sum required 0.
if(from==M && req==0){
System.out.println(Arrays.toString(arr));
return;
}
// Either reached the end of the array but sum is not equal to N
// Or if we have not reached the end of the array but sum has already
// become more than or equal to N.
if(from==M || req<=0){
return;
}
for(int i=last; i<=req; i++){
arr[from] = i;
print(arr, from+1, req-i, i);
}
}
Output for M=4 and N=7:
[1, 1, 1, 4]
[1, 1, 2, 3]
[1, 2, 2, 2]
Output for M=3 and N=10:
[1, 1, 8]
[1, 2, 7]
[1, 3, 6]
[1, 4, 5]
[2, 2, 6]
[2, 3, 5]
[2, 4, 4]
[3, 3, 4]
Answer for the problem in the link, just got accepted.
The idea is simple, assume that we know the maximum value for each section is X, and we want to find a way to divide these cabinets to achieve that , we can greedily divide them as follow:
Starting from first cabinet, iterating through each cabinet, until the total from first to ith cabinet is greater than X. So this is the first section, similarly, we can select other sections. This greedy will always find a solution (if exists).
Finally, we can using binary search to adjust the value of X, decrease X if we can find a way to divide the cabinets, or increase X if we cannot find one.
Here is the code in Java:
public class FairWorkload {
public int getMostWork(int[] folders, int workers) {
int[] data = new int[folders.length];
data[0] = folders[0];
for (int i = 1; i < data.length; i++) {
data[i] = data[i - 1] + folders[i];
}
if (workers == 1) {
return data[data.length - 1];
}
int start = 0;
int end = data[data.length - 1];
int result = Integer.MAX_VALUE;
while (start <= end) {
int mid = (start + end) / 2;
int index = 0;
for (int k = 0; k < workers && index < data.length; k++) {
int less = index > 0 ? data[index - 1] : 0;
int temp = index;
for (int i = index; i < data.length; i++) {
if (data[i] - less <= mid) {
temp = i;
} else {
break;
}
}
// System.out.println(data[temp] - less + " " + mid);
if(data[temp] - less > mid){
index = -1;
break;
}
index = temp + 1;
}
//System.out.println(mid + " " + index);
if (index != data.length) {
start = mid + 1;
} else {
result = Math.min(result, mid);
end = mid - 1;
}
}
return result;
}
public static void main(String[] args) {
int[] data = {1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1, 1000};
System.out.println(new FairWorkload().getMostWork(data, 2));
}
}
One possible solution uses a counting technique, finding the rightmost term that satisfies [i] <= [length-1] - 2, and then flattening out all other terms to the right as much as possible, keeping a[i] <= a[i+1].
import java.util.Arrays;
public class test {
public static void main(String[] args) {
test t = new test();
t.go();
}
private void go() {
int w = 3;
int sum = 10;
int[] terms = new int[w];
for (int i = 0; i < terms.length; i++) {
terms[i] = 1;
}
terms[w-1] = sum - w + 1;
System.out.println(Arrays.toString(terms));
for (int i = right_index(terms); i>=0; i = right_index(terms)) {
terms[i]++;
int a = terms[i];
int overflow = -1;
// balance all the terms to the right
for (int j = i+1; j < terms.length-1; j++) {
overflow += terms[j] - a;
terms[j] = a;
}
terms[terms.length-1] += overflow;
System.out.println(Arrays.toString(terms));
}
}
// find the rightmost index i, where [i] <= [ia.length-1] - 2
private int right_index(int[] ia) {
int max = ia[ia.length-1];
for (int i = ia.length - 1; i >= 0; i--) {
if (ia[i] <= max - 2)
return i;
}
return -1;
}
}

Algorithm for Adding/Subtracting numbers to find if number can be made?

I was wondering if there is an efficient premade algorithm for determining if the sum/difference of a group of numbers can equal a different number. Example:
5, 8, 10, 2, using + or -, to equal 9.
5 - 8 = -3 + 10 = 7 + 2 = 9
If there is a preexisting algorithm, what is it called. If not, I can figure out how to program it, though it may not be efficient.
Thank you!
Yeah, this is basically knapsack problem, but it can be computed in pseudopolynomial time using dynamic programming.
I did it few month ago, so maybe this java code can help you, if you want to implement it :
public void solve() {
while (this.isEnd() == false) {
int priceSum = this.getItemsInstance().getTotalPrice()/divide;
int numOfItems = this.getItemsInstance().itemCount();
int maxWeight = this.getItemsInstance().getMaxWeight();
int[][] array = new int[numOfItems + 1][priceSum + 1];
boolean[][] arrayCounted = new boolean[numOfItems + 1][priceSum + 1];
for (int i = 0; i < numOfItems + 1; i++) {
array[i][0] = 0;
arrayCounted[i][0] = true;
}
int max = 0;
int price = 0;
for (int j = 1; j < priceSum + 1; j++) {
for (int i = 1; i < numOfItems + 1; i++) {
int temp = W(i, j, array, arrayCounted);
if (temp <= maxWeight) {
max = temp;
price = j;
}
}
}
}
}
private int W(int i, int c, int[][] array, boolean[][] arrayCounted) {
if (c < 0) {
return MAX_PRICE / divide;
}
if (i == 0) {
if (c == 0) {
return 0;
} else {
return MAX_PRICE / divide;
}
}
if (arrayCounted[i][c]) {
return array[i][c];
}
arrayCounted[i][c] = true;
array[i][c] = Math.min(W(i - 1, c, array, arrayCounted), W(i - 1, c - this.items[i - 1].price/divide, array, arrayCounted) + this.items[i - 1].weight);
return array[i][c];
}
its not an NP problem, if the problem is to find a given number from adding or subtracting each elements of a list/array. if you think about AP. here is a sample code in C++
int Np( int mn, list<int>a, int c )
{
int size = a.size(), rst = 0, maxI = 0;
std::list<int>::iterator it;
while( size > c )
{
a.sort();
maxI += a.back();
a.pop_back();
rst = 0;
for( auto ele : a )
{
rst += ele;
cout << rst << endl;
}
if( (rst - maxI) == mn or (maxI - rst) == mn or (maxI + rst) == mn )
{
return mn;
}
size--;
}
return rst;
}
this should help. i think.
I actually wrote a simple java program, I was not actually aware of knapsack strategies. This is my own solution. Hope this helps
import java.util.ArrayList;
import java.util.List;
public class Puzzle {
public static void main(String[] args) {
int targetNumber = 0;
int min = 2147483647;
int[] numbers = {-10, -30, -20, -50};
//int[] numbers = {0,0,0,0};
//int[] numbers = {7, 2, 10};
//int[] numbers = {1, 2, 3, 4, 5};
//int[] numbers = {1000, 2, 3, 4, 100};
char set[] = {'+', '-'};
min = getNumberClosestToTarget(numbers, set, min, targetNumber);
System.out.println(String.format(" %d is closest to %d", min, targetNumber));
}
private static int getNumberClosestToTarget(int[] numbers, char[] set, int min, int targetNumber) {
List<String> operators = new ArrayList<>();
computeAllOperatorsCombination(set, "", set.length, numbers.length - 1, operators);
for (String operatorString : operators) {
String[] ops = operatorString.split("");
int sum = computeSum(numbers, ops, numbers.length - 1);
min = getClosestToTarget(min, targetNumber, sum);
}
return min;
}
static int computeSum(int[] numbers, String[] operators, int index) {
int result = numbers[index];
if (index == 0) {
return result;
} else {
switch (operators[index - 1]) {
case "+":
return computeSum(numbers, operators, index - 1) + result;
case "-":
return computeSum(numbers, operators, index - 1) - result;
}
return result;
}
}
static void computeAllOperatorsCombination(char set[], String prefix, int n, int k, List<String> result) {
if (k == 0) {
result.add(prefix);
return;
}
for (int i = 0; i < n; i++) {
String newPrefix;
newPrefix = prefix + set[i];
computeAllOperatorsCombination(set, newPrefix, n, k - 1, result);
}
}
private static int getClosestToTarget(int min, int targetNumber, int r) {
int distance = Math.abs(targetNumber - r) < Math.abs(r - targetNumber) ? Math.abs(targetNumber - r) : Math.abs(r - targetNumber);
if (distance < Math.abs(min)) {
min = distance;
if (r < 0) {
min = -distance;
}
}
return min;
}
}

Find longest increasing sequence

You are given a sequence of numbers and you need to find a longest increasing subsequence from the given input(not necessary continuous).
I found the link to this(Longest increasing subsequence on Wikipedia) but need more explanation.
If anyone could help me understand the O(n log n) implementation, that will be really helpful. If you could explain the algo with an example, that will be really appreciated.
I saw the other posts as well and what I did not understand is:
L = 0
for i = 1, 2, ... n:
binary search for the largest positive j ≤ L such that X[M[j]] < X[i] (or set j = 0 if no such value exists)
above statement, from where to start binary search? how to initialize M[], X[]?
A simpler problem is to find the length of the longest increasing subsequence. You can focus on understanding that problem first. The only difference in the algorithm is that it doesn't use the P array.
x is the input of a sequence, so it can be initialized as:
x = [0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15]
m keeps track of the best subsequence of each length found so far. The best is the one with the smallest ending value (allowing a wider range of values to be added after it). The length and ending value is the only data needed to be stored for each subsequence.
Each element of m represents a subsequence. For m[j],
j is the length of the subsequence.
m[j] is the index (in x) of the last element of the subsequence.
so, x[m[j]] is the value of the last element of the subsequence.
L is the length of the longest subsequence found so far. The first L values of m are valid, the rest are uninitialized. m can start with the first element being 0, the rest uninitialized. L increases as the algorithm runs, and so does the number of initialized values of m.
Here's an example run. x[i], and m at the end of each iteration is given (but values of the sequence are used instead of indexes).
The search in each iteration is looking for where to place x[i]. It should be as far to the right as possible (to get the longest sequence), and be greater than the value to its left (so it's an increasing sequence).
0: m = [0, 0] - ([0] is a subsequence of length 1.)
8: m = [0, 0, 8] - (8 can be added after [0] to get a sequence of length 2.)
4: m = [0, 0, 4] - (4 is better than 8. This can be added after [0] instead.)
12: m = [0, 0, 4, 12] - (12 can be added after [...4])
2: m = [0, 0, 2, 12] - (2 can be added after [0] instead of 4.)
10: m = [0, 0, 2, 10]
6: m = [0, 0, 2, 6]
14: m = [0, 0, 2, 6, 14]
1: m = [0, 0, 1, 6, 14]
9: m = [0, 0, 1, 6, 9]
5: m = [0, 0, 1, 5, 9]
13: m = [0, 0, 1, 5, 9, 13]
3: m = [0, 0, 1, 3, 9, 13]
11: m = [0, 0, 1, 3, 9, 11]
7: m = [0, 0, 1, 3, 7, 11]
15: m = [0, 0, 1, 3, 7, 11, 15]
Now we know there is a subsequence of length 6, ending in 15. The actual values in the subsequence can be found by storing them in the P array during the loop.
Retrieving the best sub-sequence:
P stores the previous element in the longest subsequence (as an index of x), for each number, and is updated as the algorithm advances. For example, when we process 8, we know it comes after 0, so store the fact that 8 is after 0 in P. You can work backwards from the last number like a linked-list to get the whole sequence.
So for each number we know the number that came before it. To find the subsequence ending in 7, we look at P and see that:
7 is after 3
3 is after 1
1 is after 0
So we have the subsequence [0, 1, 3, 7].
The subsequences ending in 7 or 15 share some numbers:
15 is after 11
11 is after 9
9 is after 6
6 is after 2
2 is after 0
So we have the subsequences [0, 2, 6, 9, 11], and [0, 2, 6, 9, 11, 15] (the longest increasing subsequence)
One of the best explanation to this problem is given by MIT site.
http://people.csail.mit.edu/bdean/6.046/dp/
I hope it will clear all your doubts.
based on FJB's answer, java implementation:
public class Lis {
private static int[] findLis(int[] arr) {
int[] is = new int[arr.length];
int index = 0;
is[0] = index;
for (int i = 1; i < arr.length; i++) {
if (arr[i] < arr[is[index]]) {
for (int j = 0; j <= index; j++) {
if (arr[i] < arr[is[j]]) {
is[j] = i;
break;
}
}
} else if (arr[i] == arr[is[index]]) {
} else {
is[++index] = i;
}
}
int[] lis = new int[index + 1];
lis[index] = arr[is[index]];
for (int i = index - 1; i >= 0; i--) {
if (is[i] < is[i + 1]) {
lis[i] = arr[is[i]];
} else {
for (int j = is[i + 1] - 1; j >= 0; j--) {
if (arr[j] > arr[is[i]] && arr[j] < arr[is[i + 1]]) {
lis[i] = arr[j];
is[i] = j;
break;
}
}
}
}
return lis;
}
public static void main(String[] args) {
int[] arr = new int[] { 0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11,
7, 15 };
for (int i : findLis(arr)) {
System.out.print(i + "-");
}
System.out.println();
arr = new int[] { 1, 9, 3, 8, 11, 4, 5, 6, 4, 19, 7, 1, 7 };
for (int i : findLis(arr)) {
System.out.print(i + "-");
}
System.out.println();
}
}
Below is the O(NLogN) longest increasing subsequence implementation:
// search for the index which can be replaced by the X. as the index can't be
//0 or end (because if 0 then replace in the findLIS() and if it's greater than the
//current maximum the just append)of the array "result" so most of the boundary
//conditions are not required.
public static int search(int[] result, int p, int r, int x)
{
if(p > r) return -1;
int q = (p+r)/2;
if(result[q] < x && result[q+1]>x)
{
return q+1;
}
else if(result[q] > x)
{
return search(result, p, q, x);
}
else
{
return search(result, q+1, r, x);
}
}
public static int findLIS(int[] a)
{
int[] result = new int[a.length];
result[0] = a[0];
int index = 0;
for(int i=1; i<a.length; i++)
{
int no = a[i];
if(no < result[0]) // replacing the min number
{
result[0] = no;
}
else if(no > result[index])//if the number is bigger then the current big then append
{
result[++index] = no;
}
else
{
int c = search(result, 0, index, no);
result[c] = no;
}
}
return index+1;
}
Late to the party, but here's a JavaScript implementation to go along with the others.. :)
var findLongestSubsequence = function(array) {
var longestPartialSubsequences = [];
var longestSubsequenceOverAll = [];
for (var i = 0; i < array.length; i++) {
var valueAtI = array[i];
var subsequenceEndingAtI = [];
for (var j = 0; j < i; j++) {
var subsequenceEndingAtJ = longestPartialSubsequences[j];
var valueAtJ = array[j];
if (valueAtJ < valueAtI && subsequenceEndingAtJ.length > subsequenceEndingAtI.length) {
subsequenceEndingAtI = subsequenceEndingAtJ;
}
}
longestPartialSubsequences[i] = subsequenceEndingAtI.concat();
longestPartialSubsequences[i].push(valueAtI);
if (longestPartialSubsequences[i].length > longestSubsequenceOverAll.length) {
longestSubsequenceOverAll = longestPartialSubsequences[i];
}
}
return longestSubsequenceOverAll;
};
Based on #fgb 's answer, I implemented the algorithm using c++ to find the longest strictly increasing sub-sequence. Hope this will be somewhat helpful.
M[i] is the index of the last element of the sequence whose length is i, P[i] is the index of the previous element of i in the sequence, which is used to print the whole sequence.
main() is used to run the simple test case: {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15}.
#include <vector>
using std::vector;
int LIS(const vector<int> &v) {
int size = v.size(), max_len = 1;
// M[i] is the index of the last element of the sequence whose length is i
int *M = new int[size];
// P[i] is the index of the previous element of i in the sequence, which is used to print the whole sequence
int *P = new int[size];
M[0] = 0; P[0] = -1;
for (int i = 1; i < size; ++i) {
if (v[i] > v[M[max_len - 1]]) {
M[max_len] = i;
P[i] = M[max_len - 1];
++max_len;
continue;
}
// Find the position to insert i using binary search
int lo = 0, hi = max_len - 1;
while (lo <= hi) {
int mid = lo + ((hi - lo) >> 1);
if (v[i] < v[M[mid]]) {
hi = mid - 1;
} else if (v[i] > v[M[mid]]) {
lo = mid + 1;
} else {
lo = mid;
break;
}
}
P[i] = P[M[lo]]; // Modify the previous pointer
M[lo] = i;
}
// Print the whole subsequence
int i = M[max_len - 1];
while (i >= 0) {
printf("%d ", v[i]);
i = P[i];
}
printf("\n");
delete[] M, delete[] P;
return max_len;
}
int main(int argc, char* argv[]) {
int data[] = {0, 8, 4, 12, 2, 10, 6, 14, 1, 9, 5, 13, 3, 11, 7, 15};
vector<int> v;
v.insert(v.end(), data, data + sizeof(data) / sizeof(int));
LIS(v);
return 0;
}
The O(N lg N) solution comes from patience sorting of playing card. I found this from my code comment and hence sharing here. I believe it would be really easier to understand for everyone how it works. Also you can find all possible longest increasing sub-sequence list if you understand well.
https://www.cs.princeton.edu/courses/archive/spring13/cos423/lectures/LongestIncreasingSubsequence.pdf
Code:
vector<int> lisNlgN(vector<int> v) {
int n = v.size();
vector<int> piles = vector<int>(n, INT_MAX);
int maxLen = 0;
for(int i = 0; i < n; i++) {
int pos = lower_bound(piles.begin(), piles.end(), v[i]) - piles.begin();
piles[pos] = v[i];
maxLen = max(maxLen, pos+1); // Plus 1 because of 0-based index.
}
// // Print piles for debug purpose
// for (auto x : piles) cout << x << " ";
// cout << endl;
//
// // Print position for debug purpose
// for (auto x : position) cout << x << " ";
// cout << endl;
vector<int> ret = vector<int>(piles.begin(), piles.begin() + maxLen);
return ret;
}
Code:
vector<vector<int>> allPossibleLIS(vector<int> v) {
struct Card {
int val;
Card* parent = NULL;
Card(int val) {
this->val = val;
}
};
auto comp = [](Card* a, Card* b) {
return a->val < b->val;
};
int n = v.size();
// Convert integers into card node
vector<Card*> cards = vector<Card*>(n);
for (int i = 0; i < n; i++) cards[i] = new Card(v[i]);
vector<Card*> piles = vector<Card*>(n, new Card(INT_MAX));
vector<Card*> lastPileCards;
int maxLen = 0;
for(int i = 0; i < n; i++) {
int pos = lower_bound(piles.begin(), piles.end(), new Card(v[i]), comp) - piles.begin();
piles[pos] = cards[i];
// Link to top card of left pile
if (pos == 0) cards[i]->parent = NULL;
else cards[i]->parent = piles[pos-1];
// Plus 1 because of 0-based index.
if (pos+1 == maxLen) {
lastPileCards.push_back(cards[i]);
} else if (pos+1 > maxLen) {
lastPileCards.clear();
lastPileCards.push_back(cards[i]);
maxLen = pos + 1;
}
}
// Print for debug purpose
// printf("maxLen = %d\n", maxLen);
// printf("Total unique lis list = %d\n", lastPileCards.size());
vector<vector<int>> ret;
for (auto card : lastPileCards) {
vector<int> lis;
Card* c = card;
while (c != NULL) {
lis.push_back(c->val);
c = c->parent;
}
reverse(lis.begin(), lis.end());
ret.push_back(lis);
}
return ret;
}

Resources