Sorting an array with dates (Quicksort) - java

My goal is to sort an matrix with events according to their dates (Stored in the matrix as events[eventIndex][1]. Somehow I get the almost correct output, except the section showed in bold
Do i have to sort the year, months, and days seperately?
Or do I have som logical error in my compare method?
Before sorting:
12/24/2015
12/19/2015
12/30/2015
11/13/2015
12/30/2015
01/15/2016
12/31/2015
01/15/2016
12/24/2015
12/19/2015
12/31/2015
01/15/2016
After sorting:
11/13/2015
12/19/2015
12/19/2015
12/24/2015
12/24/2015
12/30/2015
12/31/2015
12/30/2015
12/31/2015
01/15/2016
01/15/2016
01/15/2016
Here is my code.
public void quickSort(String[][] event, int low, int high, Compare c) {
if (event == null || event.length == 0)
return;
if (low >= high)
return;
// pick the pivot
int middle = low + (high - low) / 2;
// make left < pivot and right > pivot
int i = low, j = high;
while (i <= j) {
while (c.compare(i, middle)) {
i++;
}
while (c.compare(middle, j)) {
j--;
}
if (i <= j) {
String[] temp = event[i];
event[i] = event[j];
event[j] = temp;
i++;
j--;
}
}
// recursively sort two sub parts
if (low < j)
quickSort(event, low, j,c);
if (high > i)
quickSort(event, i, high,c);
}
//Interface for comparing two types
public interface Compare {
boolean compare(int first, int second);
}
public class CompareDate implements Compare {
#Override
public boolean compare(int first, int second) {
//Splitting up the date string and converts into int
//Splitting first index
String[] temp = event[first][1].split("/");
int firstYear = Integer.parseInt(temp[2]);
int firstMonth = Integer.parseInt(temp[0]);
int firstDay = Integer.parseInt(temp[1]);
//Splitting second index
temp = event[second][1].split("/");
int secondYear = Integer.parseInt(temp[2]);
int secondMonth = Integer.parseInt(temp[0]);
int secondDay = Integer.parseInt(temp[1]);
//Comparing the values
if (firstYear < secondYear) return true;
else if (secondYear < firstYear) return false;
else if (firstMonth < secondMonth) return true;
else if (secondMonth < firstMonth) return false;
return (firstDay < secondDay);
}
}

Here is a nice solution using recursion. It may not be optimal but it works fine.
public static void quickSort(String[] event) {
String temp;
int a, b, c, d, e, f;
// Sorting years
for (int i = 0 ; i < event.length - 1 ; i++){
a = Integer.valueOf(event[i].split("/")[2]);
b = Integer.valueOf(event[i+1].split("/")[2]);
// Sorting years
if (a > b){
temp = event[i];
event[i] = event[i+1];
event[i+1] = temp;
quickSort(event);
} else if (a == b){
c = Integer.valueOf(event[i].split("/")[0]);
d = Integer.valueOf(event[i+1].split("/")[0]);
// Sorting months
if (c > d){
temp = event[i];
event[i] = event[i+1];
event[i+1] = temp;
quickSort(event);
} else if (c == d){
e = Integer.valueOf(event[i].split("/")[1]);
f = Integer.valueOf(event[i+1].split("/")[1]);
// Sorting days
if (e > f){
temp = event[i];
event[i] = event[i+1];
event[i+1] = temp;
quickSort(event);
}
}
}
}
}

The simpler approach I can think of is converting the dates into a long and then comparing them. It is simpler.
The other option would be using the Java Calendar class.
https://docs.oracle.com/javase/7/docs/api/java/util/Calendar.html

Related

How can I show the value of array with the Binary Search Tree of Comparison?

I going to do searching the value in the array, did I need to create a method to handle it? For example, the array logged 32,21,13,44,22, and I going to find 22 of the comparison. How can I implement this?
public class binarySearch {
public static void main(String [] args) {
int i = binarySearch(0, new int[]{32,21,13,44,22});
System.out.println("Iterations: " + i);
}
public static int binarySearch(int key, int[] array) {
int left = 0;
int mid;
int right = array.length - 1;
int i = 0;
while (left <= right) {
mid = (left + right) / 2;
int comp = Integer.compare(key, array[mid]);
i++;
if (comp < 0) {
right = mid - 1;
} else if (comp > 0) {
left = mid + 1;
} else {
break; // success
}
}
return i;
}
}
My final answer is here. May help you all in the future.
public static int binarySearch(int key, int[] array) {
int left = 0;
int mid;
int right = array.length - 1;
int i = 0;
while (left <= right) {
mid = (left + right) / 2;
int comp = Integer.compare(key, array[mid]);
i++;
if (comp < 0) {
right = mid - 1;
} else if (comp > 0) {
left = mid + 1;
} else {
break; // success
}
}
return i;
}
If you have shuffled array, all you can do is go through an array and find your number.
BinarySearch works only with sorted array. I think your solution could look like this:
public static int binarySearch(int[] arr, int key) {
Arrays.sort(arr);
return Arrays.binarySearch(arr, key);
}

perfect squares leetcode - recursive solution with memoization

Trying to solve this problem with recursion and memoization but for input 7168 I'm getting wrong answer.
public int numSquares(int n) {
Map<Integer, Integer> memo = new HashMap();
List<Integer> list = fillSquares(n, memo);
if (list == null)
return 1;
return helper(list.size()-1, list, n, memo);
}
private int helper(int index, List<Integer> list, int left, Map<Integer, Integer> memo) {
if (left == 0)
return 0;
if (left < 0 || index < 0)
return Integer.MAX_VALUE-1;
if (memo.containsKey(left)) {
return memo.get(left);
}
int d1 = 1+helper(index, list, left-list.get(index), memo);
int d2 = 1+helper(index-1, list, left-list.get(index), memo);
int d3 = helper(index-1, list, left, memo);
int d = Math.min(Math.min(d1,d2), d3);
memo.put(left, d);
return d;
}
private List<Integer> fillSquares(int n, Map<Integer, Integer> memo) {
int curr = 1;
List<Integer> list = new ArrayList();
int d = (int)Math.pow(curr, 2);
while (d < n) {
list.add(d);
memo.put(d, 1);
curr++;
d = (int)Math.pow(curr, 2);
}
if (d == n)
return null;
return list;
}
I'm calling like this:
numSquares(7168)
All test cases pass (even complex cases), but this one fails. I suspect something is wrong with my memoization but cannot pinpoint what exactly. Any help will be appreciated.
You have the memoization keyed by the value to be attained, but this does not take into account the value of index, which actually puts restrictions on which powers you can use to attain that value. That means that if (in the extreme case) index is 0, you can only reduce what is left with one square (1²), which rarely is the optimal way to form that number. So in a first instance memo.set() will register a non-optimal number of squares, which later will get updated by other recursive calls which are pending in the recursion tree.
If you add some conditional debugging code, you'll see that map.set is called for the same value of left multiple times, and with differing values. This is not good, because that means the if (memo.has(left)) block will execute for cases where that value is not guaranteed to be optimal (yet).
You could solve this by incorporating the index in your memoization key. This increases the space used for memoization, but it will work. I assume you can work this out.
But according to Lagrange's four square theorem every natural number can be written as the sum of at most four squares, so the returned value should never be 5 or more. You can shortcut the recursion when you get passed that number of terms. This reduces the benefit of using memoization.
Finally, there is a mistake in fillSquares: it should add n itself also when it is a perfect square, otherwise you'll not find solutions that should return 1.
Not sure about your bug, here is a short dynamic programming Solution:
Java
public class Solution {
public static final int numSquares(
final int n
) {
int[] dp = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
dp[0] = 0;
for (int i = 1; i <= n; i++) {
int j = 1;
int min = Integer.MAX_VALUE;
while (i - j * j >= 0) {
min = Math.min(min, dp[i - j * j] + 1);
++j;
}
dp[i] = min;
}
return dp[n];
}
}
C++
// Most of headers are already included;
// Can be removed;
#include <iostream>
#include <cstdint>
#include <vector>
#include <algorithm>
// The following block might slightly improve the execution time;
// Can be removed;
static const auto __optimize__ = []() {
std::ios::sync_with_stdio(false);
std::cin.tie(nullptr);
std::cout.tie(nullptr);
return 0;
}();
#define MAX INT_MAX
using ValueType = std::uint_fast32_t;
struct Solution {
static const int numSquares(
const int n
) {
if (n < 1) {
return 0;
}
static std::vector<ValueType> count_perfect_squares{0};
while (std::size(count_perfect_squares) <= n) {
const ValueType len = std::size(count_perfect_squares);
ValueType count_squares = MAX;
for (ValueType index = 1; index * index <= len; ++index) {
count_squares = std::min(count_squares, 1 + count_perfect_squares[len - index * index]);
}
count_perfect_squares.emplace_back(count_squares);
}
return count_perfect_squares[n];
}
};
int main() {
std::cout << std::to_string(Solution().numSquares(12) == 3) << "\n";
return 0;
}
Python
Here we can simply use lru_cache:
class Solution:
dp = [0]
#functools.lru_cache
def numSquares(self, n):
dp = self.dp
while len(dp) <= n:
dp += min(dp[-i * i] for i in range(1, int(len(dp) ** 0.5 + 1))) + 1,
return dp[n]
Here are LeetCode's official solutions with comments:
Java: DP
class Solution {
public int numSquares(int n) {
int dp[] = new int[n + 1];
Arrays.fill(dp, Integer.MAX_VALUE);
// bottom case
dp[0] = 0;
// pre-calculate the square numbers.
int max_square_index = (int) Math.sqrt(n) + 1;
int square_nums[] = new int[max_square_index];
for (int i = 1; i < max_square_index; ++i) {
square_nums[i] = i * i;
}
for (int i = 1; i <= n; ++i) {
for (int s = 1; s < max_square_index; ++s) {
if (i < square_nums[s])
break;
dp[i] = Math.min(dp[i], dp[i - square_nums[s]] + 1);
}
}
return dp[n];
}
}
Java: Greedy
class Solution {
Set<Integer> square_nums = new HashSet<Integer>();
protected boolean is_divided_by(int n, int count) {
if (count == 1) {
return square_nums.contains(n);
}
for (Integer square : square_nums) {
if (is_divided_by(n - square, count - 1)) {
return true;
}
}
return false;
}
public int numSquares(int n) {
this.square_nums.clear();
for (int i = 1; i * i <= n; ++i) {
this.square_nums.add(i * i);
}
int count = 1;
for (; count <= n; ++count) {
if (is_divided_by(n, count))
return count;
}
return count;
}
}
Java: Breadth First Search
class Solution {
public int numSquares(int n) {
ArrayList<Integer> square_nums = new ArrayList<Integer>();
for (int i = 1; i * i <= n; ++i) {
square_nums.add(i * i);
}
Set<Integer> queue = new HashSet<Integer>();
queue.add(n);
int level = 0;
while (queue.size() > 0) {
level += 1;
Set<Integer> next_queue = new HashSet<Integer>();
for (Integer remainder : queue) {
for (Integer square : square_nums) {
if (remainder.equals(square)) {
return level;
} else if (remainder < square) {
break;
} else {
next_queue.add(remainder - square);
}
}
}
queue = next_queue;
}
return level;
}
}
Java: Most efficient solution using math
Runtime: O(N ^ 0.5)
Memory: O(1)
class Solution {
protected boolean isSquare(int n) {
int sq = (int) Math.sqrt(n);
return n == sq * sq;
}
public int numSquares(int n) {
// four-square and three-square theorems.
while (n % 4 == 0)
n /= 4;
if (n % 8 == 7)
return 4;
if (this.isSquare(n))
return 1;
// enumeration to check if the number can be decomposed into sum of two squares.
for (int i = 1; i * i <= n; ++i) {
if (this.isSquare(n - i * i))
return 2;
}
// bottom case of three-square theorem.
return 3;
}
}

Each substring of a certian length of a binary substring should have at least one '1' character

You have been given a binary string containing only the characters '1' and '0'.
Calculate how many characters of the string need to be changed in order to make the binary string such that each of its substrings of at least a certain length contains at least one "1" character.
I came to think of the following idea but it fails for many testcases:
public static int minimumMoves(String s, int d) {
int n = s.length();
int i=0, answer = 0;
while(i<n)
{
boolean hasOne = false;
int j=i;
while(j<n && j<i+d)
{
if(s.charAt(j) == '1')
{
hasOne = true;
break;
}
j++;
}
if(!hasOne) {
answer++;
i += d;
}
else i++;
}
return answer;
}
Also my algorithm runs on O(|s|2) time. Can anyone suggest ideas on O(|s|) time?
Just throwing off an idea:
return s.split("(?<=\\G.{" + String.valueof(d) + "})").stream().filter(str -> str.contains("1")).count()
You just need to break ensure there is no run of d zeros.
public static int minimumMoves(String s, int d) {
int result = 0;
int runLength = 0;
for(char c: s.toCharArray()) {
if (c == '0') {
runLength += 1;
if (runLength == d) { // we need to break this run
result += 1;
runLength = 0;
}
} else {
runLength = 0;
}
}
return result;
}
I used the sliding window technique and Deque to solve this. This is my accepted solution:
public static int minimumMoves(String s, int d) {
int n = s.length();
Deque<Character> dq = new LinkedList<>();
int count = 0, answer = 0;
for(int i=0; i<d; i++)
{
if(s.charAt(i) == '1') count++;
dq.addLast(s.charAt(i));
}
if(count == 0) {
answer++;
count++;
dq.removeLast();
dq.addLast('1');
}
int i=d;
while(i<n)
{
if(dq.getFirst() == '1') count--;
dq.removeFirst();
if(s.charAt(i) == '1') count++;
dq.addLast(s.charAt(i));
if(count == 0)
{
answer++;
dq.removeLast();
dq.addLast('1');
count++;
}
i++;
}
return answer;
}
You just need to use a sliding window and a count of 1s so far at each index. Use a sliding window of d and if you don't see any ones so far, update the last index of that window with 1 and increment the result.
Code below:
public static int minimumMoves(String s, int d) {
int n = s.length();
int[] count = new int[n+1];
int res = 0;
for ( int i = 1; i <= d; i++ ) {
if ( s.charAt(i-1) == '1') count[i] = count[i-1]+1;
else count[i] = count[i-1];
}
if ( count[d] == 0 ) {
res++;
count[d] = 1;
}
for ( int i = d+1; i <= n; i++ ) {
if ( s.charAt(i-1) == '0' ) {
count[i] = count[i-1];
int ones = count[i] - count[i-d];
if ( ones == 0 ) {
count[i] = count[i-1] + 1;
res++;
}
} else {
count[i] = count[i-1] + 1;
}
}
return res;
}
Thought of another implementation you can do for this by working from the maximum possible changes (assumes at start that all values are '0' in String), reduce it when it finds a '1' value, and then jump to the next substring start. This allows it to run in O(n) and Ω(n/m) (n = String length, m = Substring length).
public static int minimumMoves(String s, int d)
{
char[] a = s.toCharArray();
//Total possible changes (not counting tail)
if(a.length < d)
return 0;
int t = (int) a.length / d;
//Total possible changes (counting tail)
//int t = (int) Math.ceil((double) a.length / (double) d);
for(int i = 0; i < a.length; i++)
{
if(a[i] == '1')
{
t--;
//Calculate index for start of next substring
i = (i / d + 1) * d - 1;
}
}
return t;
}

Sorting three command line integers

Hello I'm trying to make a code that takes three integers from the command line and sorts them into the min, mid, and max values. I can't figure out the mid programming. It won't always sort them properly. Can you help?
public class SortInteger{
public static int max3(int a, int b, int c) {
int max = a;
if (b > max) max = b;
if (c > max) max = c;
return max;
}
public static int min3(int a, int b, int c) {
int min = a;
if (b < min) min = b;
if (c < min) min = c;
return min;}
public static int sort(int a, int b, int c){
int sort = a;
if (sort > b && sort < c) sort = a;
else sort = b;
if (sort > a && sort < c) sort = b;
else sort =c;
if (sort > c && sort < a) sort = c;
else sort =b;
if (sort > c && sort < b) sort = c;
else sort = b;
if (sort > a && sort < b) sort = c;
else sort = c;
return sort;
}
public static void main(String[] args){
int a= Integer.parseInt(args [0]);
int b=Integer.parseInt(args[1]);
int c=Integer.parseInt(args[2]);
StdOut.println("Min is " + min3(a, b, c));
StdOut.println("Mid is " + sort(a, b, c));
StdOut.println("Max is " + max3(a, b, c));
}
}
Try:
public static int mid(int a, int b, int c){
return a + b + c - max(a,b,c) - min(a,b,c);
}
Also for the min and max just use Math:
public static int min(int a, int b, int c){
return Math.min(Math.min(a,b),c);//Replace with Math.max for max.
}
You're stepping all over your own toes inside the sort function. Take, for instance, your first two if statements:
if (sort > b && sort < c) sort = a;
else sort = b;
if (sort > a && sort < c) sort = b;
else sort =c;
If a is between b and c, your first if statement will be true, and sort will be kept as the value of a. But, then consider your next one. The value in a will not be greater than a, so the second if statement will be false, and change sort to c, even though you already found a to be the middle value. Not what you wanted. To fix this, you could change the code you execute when your if statements are true to just return the value of sort. So, like:
if (sort > b && sort < c) return sort;
else sort = b;
if (sort > a && sort < c) return sort;
else sort =c;
// etc.
Try the following:
public class SortInteger
{
//use general sorting algorithm for arbitrary length, this is for 3 length specifically
public static int[] sort(int[] inputs)
{
int k;
if(inputs[0] >= inputs[1])
{
k = inputs[0];
inputs[0] = inputs[1];
inputs[1] = k;
}
if(inputs[1] >= inputs[2])
{
k = inputs[1];
inputs[1] = inputs[2];
inputs[2] = k;
}
//incase our last element is less than our first we repeat:
if(inputs[0] >= inputs[1])
{
k = inputs[0];
inputs[0] = inputs[1];
inputs[1] = k;
}
return inputs
}
public static void main(String[] args)
{
int[] x = new int[3];
x[0] = Integer.parseInt(args[0]);
x[1] = Integer.parseInt(args[1]);
x[2] = Integer.parseInt(args[2]);
x = sort(x);
System.out.println("min is: " + x[0]);
System.out.println("mid is: " + x[1]);
System.out.println("max is: " + x[2]);
}
}

Recursive Knapsack

I'm trying to implement recursive Knapsack I used the common algorithm to write it as following:
int pack(int n, int s) {
if (n < 0)
return 0;
if (List[n].s > s)
return pack(n-1, s);
else {
int max = Math.max(pack(n-1,s), pack(n-1, s -List[n].s) + List[n].v);
return max;
}
}
Is there anyway I can know which items were packed?
Update: I want only the items that belong to best choice and I don't want to change the function header.
EDIT Using array to track items, what's wrong with this?
int pack(int n , int s)
{
if(n < 0)
{
counter =0;
return 0;
}
if (itemsList[n].s > s)
{
return pack(n-1, s);
}
else
{
int max1 = pack(n-1,s);
int max2 = pack(n-1, s - itemsList[n].s) + itemsList[n].v ;
if(max2 > max1)
{
flag1[counter] = new item();
flag1[counter] = itemsList[n];
counter ++;
}
return max(max1, max2);
}
}
Something like this ?
int pack(int n, int s) {
if (n < 0)
return 0;
if (List[n].s > s)
return pack(n-1, s);
else {
int without = pack(n-1,s);
int with = pack(n-1, s-List[n].s) + List[n].v;
if (with >= without) {
System.out.println(n);
}
return Math.max(with, without);
}
}
or, you can return the list of results:
int pack(int n, int s) {
return reallyPack(n, s, new ArrayList<Item>());
}
int reallyPack(int n, int s, List<Item> l) {
if (n < 0)
return 0;
if (List[n].s > s)
return reallyPack(n-1, s);
else {
int without = reallyPack(n-1,s);
int with = reallyPack(n-1, s-List[n].s) + List[n].v;
if (with >= without) {
l.add(itemsList[n]);
}
return Math.max(with, without);
}
}
and of course, you still know how many items were selected: this is simply the size of the returned list.
You can keep track of all items that are currently selected (using e.g. boolean[] field). Then you have to remember the max in the calls of pack with n < 0.
int maximum;
int currentMax;
boolean[] packed;
boolean[] maxPacked;
int pack(int n, int s) {
if (n < 0) {
if (maximum < currentMax) {
// found better selection
maximum = currentMax;
// copy array
for (int i = 0; i < packed.length; i++)
maxPacked[i] = packed[i];
}
return 0;
}
packed[n] = false;
int maxWithout = pack(n-1, s);
if (List[n].s > s) {
return maxWithout;
} else {
packed[n] = true;
currentMax += List[n].v;
int maxWith = pack(n-1, s -List[n].s) + List[n].v;
currentMax -= List[n].v;
return Math.max(maxWith, maxWithout);
}
}
void callingFunction() {
int maxCost = //...;
// always possible to choose no items
maximum = 0;
currentMax = 0;
packed = new boolean[List.length];
maxPacked = new boolean[List.length];
pack(List.length-1, maxCost);
// print best selection
System.out.println(Arrays.toString(maxPacked));
}

Categories