package com.interview.algorithms.dp; /** * Created_By: zouzhile * Date: 3/24/14 * Time: 2:53 PM * * See http://community.topcoder.com/stat?c=problem_statement&pm=1259&rd=4493 * * A sequence of numbers is called a zig-zag sequence if the differences * between successive numbers strictly alternate between positive and negative. * The first difference (if one exists) may be either positive or negative. * A sequence with fewer than two elements is trivially a zig-zag sequence. * * For example, 1,7,4,9,2,5 is a zig-zag sequence because the differences (6,-3,5,-7,3) * are alternately positive and negative. In contrast, 1,4,7,2,5 and 1,7,4,5,5 are not zig-zag sequences, * the first because its first two differences are positive and the second because its last difference is zero. * * Given a sequence of integers, sequence, return the length of the longest subsequence of sequence * that is a zig-zag sequence. A subsequence is obtained by deleting some number of elements (possibly zero) * from the original sequence, leaving the remaining elements in their original order. * */ public class C12_5_ZigZag { public int longestZigZag(int[] array) { int N = array.length; // optimal[i] is the length of the longest zigzag for subarray [0..i] int[] optimal = new int[N]; // sol[i] is the members of the longest zigzag for subarray [0..i] // if array[i] = array[i+1], then only array[i+1] is selected (array[i] deselected) in sol[i+1] boolean[][] sol = new boolean[N][N]; // init states for (int i = 0; i < N; i++) { optimal[i] = 1; sol[i][i] = true; // at least the element itself is a zigzag of length 1 } if (N >= 2 && array[1] != array[0]) { sol[1][0] = true; // selecting array[0] to form a zigzag of length 2 optimal[1] = 2; } // do dynamic programming for (int i = 2; i < N; i++) { int j = i - 1; for (int k = j - 1; k >= 0; k--) { if (sol[j][k]) { // array[k] is the selected member before array[j] in sol[j] /* At any given time, sol[i] only depends on sol[j]. array[k] < array[j] array[i] < array[j] -> sol[i] = sol[j] + array[i] array[i] >= array[j] -> sol[i] = sol[j] - array[j] + array[i] array[k] = array[j] This case doesn't exist by the definition of sol[] array array[k] > array[j] array[i] > array[j] -> sol[i] = sol[j] + array[i] array[i] <= array[j] -> sol[i] = sol[j] - array[j] + array[i] => so in summary: array[k] < array[j] > array[i] or array[k] > array[j] < array[i] -> sol[i] = sol[j] + array[i] all other cases -> sol[i] = sol[j] - array[j] + array[i] */ if ((array[i] - array[j]) * (array[j] - array[k]) < 0) { // copy sol[j] including j for (int m = 0; m <= j; m++) sol[i][m] = sol[j][m]; sol[i][i] = true; // array[i] is counted optimal[i] = optimal[j] + 1; } else { for (int m = 0; m < j; m++) sol[i][m] = sol[j][m]; sol[i][j] = false; // deselecting j sol[i][i] = true; // selecting i optimal[i] = optimal[j]; } break; } } } return optimal[N - 1]; } }