Given an array and some value X, find the number of pairs such that i < j , a[i] = a[j] and (i * j) % X == 0
Array size <= 10^5
I am thinking of this problem for a while but only could come up with the brute force solution(by checking all pairs) which will obviously time-out [O(N^2) time complexity]
Any better approach?
First of all, store separate search structures for each distinct A[i] as we iterate.
i * j = k * X
i = k * X / j
Let X / j be some fraction. Since i is an integer, k would be of the form m * least_common_multiple(X, j) / X, where m is natural.
Example 1: j = 20, X = 60:
lcm(60, 20) = 60
matching `i`s would be of the form:
(m * 60 / 60) * 60 / 20
=> m * q, where q = 3
Example 2: j = 6, X = 2:
lcm(2, 6) = 6
matching `i`s would be of the form:
(m * 6 / 2) * 2 / 6
=> m * q, where q = 1
Next, I would consider how to efficiently query the number of multiples of a number in a sorted list of arbitrary naturals. One way is to hash the frequency of divisors of each i we add to the search structure of A[i]. But first consider i as j and add to the result the count of divisors q that already exist in the hash map.
JavaScript code with brute force testing at the end:
function gcd(a, b){
return b ? gcd(b, a % b) : a;
}
function getQ(X, j){
return X / gcd(X, j);
}
function addDivisors(n, map){
let m = 1;
while (m*m <= n){
if (n % m == 0){
map[m] = -~map[m];
const l = n / m;
if (l != m)
map[l] = -~map[l];
}
m += 1;
}
}
function f(A, X){
const Ais = {};
let result = 0;
for (let j=1; j<A.length; j++){
if (A[j] == A[0])
result += 1;
// Search
if (Ais.hasOwnProperty(A[j])){
const q = getQ(X, j);
result += Ais[A[j]][q] || 0;
// Initialise this value's
// search structure
} else {
Ais[A[j]] = {};
}
// Add divisors for j
addDivisors(j, Ais[A[j]]);
}
return result;
}
function bruteForce(A, X){
let result = 0;
for (let j=1; j<A.length; j++){
for (let i=0; i<j; i++){
if (A[i] == A[j] && (i*j % X) == 0)
result += 1;
}
}
return result;
}
var numTests = 1000;
var n = 100;
var m = 50;
var x = 100;
for (let i=0; i<numTests; i++){
const A = [];
for (let j=0; j<n; j++)
A.push(Math.ceil(Math.random() * m));
const X = Math.ceil(Math.random() * x);
const _brute = bruteForce(A, X);
const _f = f(A, X);
if (_brute != _f){
console.log("Mismatch!");
console.log(X, JSON.stringify(A));
console.log(_brute, _f);
break;
}
}
console.log("Done testing.")
Just in case If someone needed the java version of this answer - https://stackoverflow.com/a/69690416/19325755 explanation has been provided in that answer.
I spent lot of time in understanding the javascript code so I thought the people who are comfortable with java can refer this for better understanding.
import java.util.HashMap;
public class ThisProblem {
public static void main(String[] args) {
int t = 1000;
int n = 100;
int m = 50;
int x = 100;
for(int i = 0; i<t; i++) {
int[] A = new int[n];
for(int j = 0; j<n; j++) {
A[j] = ((int)Math.random()*m)+1;
}
int X = ((int)Math.random()*x)+1;
int optR = createMaps(A, X);
int brute = bruteForce(A, X);
if(optR != brute) {
System.out.println("Wrong Answer");
break;
}
}
System.out.println("Test Completed");
}
public static int bruteForce(int[] A, int X) {
int result = 0;
int n = A.length;
for(int i = 1; i<n; i++) {
for(int j = 0; j<i; j++) {
if(A[i] == A[j] && (i*j)%X == 0)
result++;
}
}
return result;
}
public static int gcd(int a, int b) {
return b==0 ? a : gcd(b, a%b);
}
public static int getQ(int X, int j) {
return X/gcd(X, j);
}
public static void addDivisors(int n, HashMap<Integer, Integer> map) {
int m = 1;
while(m*m <= n) {
if(n%m == 0) {
map.put(m, map.getOrDefault(m, 0)+1);
int l = n/m;
if(l != m) {
map.put(l, map.getOrDefault(l, 0)+1);
}
}
m++;
}
}
public static int createMaps(int[] A, int X) {
int result = 0;
HashMap<Integer, HashMap<Integer, Integer>> contentsOfA = new HashMap<>();
int n = A.length;
for(int i = 1; i<n; i++) {
if(A[i] == A[0])
result++;
if(contentsOfA.containsKey(A[i])) {
int q = getQ(X, i);
result += contentsOfA.get(A[i]).getOrDefault(q, 0);
} else {
contentsOfA.put(A[i], new HashMap<>());
}
addDivisors(i, contentsOfA.get(A[i]));
}
return result;
}
}
How to implement a round robin schedule for an array of 4 elements [1,2,3,4]? The result of the algorithm should be able to display, for each element, the list of the players it will face in chronological order:
(1: 4,2,3)
(2: 3,1,4)
(3: 2,4,1)
(4: 1,3,2)
Line 1: 4,2,3 means that the player (1) will face in order the players (4), (2) and (3).
Of the same way, line 2: 3,1,4 indicates that the player (2) will face in order the players (3), (1) and (2).
We have implemented this code but we encounter a bug when we start filling in the name of the player. Do you have any idea about this problem?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NAME_MAX_LENGTH 20
#define NUM_MIN_PLAYERS 2
#define NUM_MAX_PLAYERS 20
enum Style
{
STYLE_COMPACT,
STYLE_TABLE
};
enum Format
{
FORMAT_ID,
FORMAT_NAME
};
struct PlayerList
{
unsigned int num_players;
char name[NUM_MAX_PLAYERS][NAME_MAX_LENGTH + 1];
};
struct Grid
{
unsigned int num_players;
unsigned int day[NUM_MAX_PLAYERS]
[NUM_MAX_PLAYERS];
};
void printList(struct PlayerList *list)
{
for (int i = 0; i < list->num_players; i++)
{
printf("%d:%s\n", i + 1, list->name[i]);
}
}
struct Grid calculer_berger(struct PlayerList *list)
{
struct Grid grid;
// algo pour remplir la grid
grid.num_players = list->num_players;
int i, j;
for (i = 0; i < list->num_players - 1; i++)
{
for (j = 0; j < list->num_players - 1; j++)
{
if (i == j)
{
/* edge cases */
grid.day[i][list->num_players - 1] = ((i + j) + (i + j) / list->num_players) % list->num_players;
grid.day[list->num_players - 1][j] = ((i + j) + (i + j) / list->num_players) % list->num_players;
grid.day[i][j] = 0;
}
else
{
grid.day[i][j] = ((i + j) + (i + j) / list->num_players) % list->num_players;
}
}
}
grid.day[0][list->num_players - 1] = list->num_players - 1;
grid.day[list->num_players - 1][list->num_players - 1] = 0;
grid.day[list->num_players - 1][0] = list->num_players - 1;
return grid;
}
void permuter(struct Grid *grid)
{
int tmp;
for (int i = 0; i < grid->num_players; i++)
{
for (int j = 1; j <= grid->num_players / 2; j++)
{
tmp = grid->day[i][j];
grid->day[i][j] = grid->day[i][grid->num_players - j];
grid->day[i][grid->num_players - j] = tmp;
}
}
}
void print_grid(struct Grid *grid, struct PlayerList *list)
{
for (int i = 0; i < grid->num_players; i++)
{
for (int j = 0; j < grid->num_players; j++)
{
if (j == 0)
{
printf("%d:", grid->day[i][j] + 1);
}
else
{
printf("%d", grid->day[i][j] + 1);
if (j < grid->num_players - 1)
{
printf(",");
}
}
}
printf("\n");
}
}
int main(int argc, char **argv)
{
struct PlayerList playerList;
char nom[NAME_MAX_LENGTH + 1];
int nbCharLu = 0;
while ((nbCharLu = fscanf(stdin, "%s", nom)) != -1)
{
strcpy(playerList.name[playerList.num_players], nom);
playerList.num_players++;
}
struct Grid myGrid = calculer_berger(&playerList);
printList(&playerList);
print_grid(&myGrid, &playerList);
printf("Apres la permut\n");
permuter(&myGrid);
print_grid(&myGrid, &playerList);
return 0;
}
Assuming you are storing the elements in an Integer array and that you would like to just display the results.
Here is one implementation....The code should accommodate "N" values because of the use of "sizeof"....
feel free to customize it further....
#include <stdio.h>
int main() {
int i,j;
int array[] = {1,2,3,4};
for(i = 0; i < sizeof(array)/sizeof(int);++i){
printf("(%d :",array[i]);
for(j = 0; j < sizeof(array)/sizeof(int);++j){
if(j == i)
continue;
printf("%d ",array[j]);
}
printf(")\n");
}
}
#include <stdio.h>
void main() {
int mid;
int num;
int j, temp;
int k = 0;
int num1;
int data[] = {1,2,3,4,5,6,7,8,9,10,11,12,13,14};
num = sizeof(data)/sizeof(int);
mid = (sizeof(data)/sizeof(int))/2;
while(k < num - 1){
printf("Round %d ( ",k+1);
num1 = num;
for(int i = 0;i < mid;i++,num1--) /*pairing the competitors in each round*/
printf("%d:%d ",data[i],data[num1-1]);
for(int i = 0,j = num-1; i < num -2;i++,j--){ /* fixing the first competitor and rotating the others clockwise*/
temp = data[j];
data[j] = data[j-1];
data[j-1] = temp;
}
printf(")\n");
k++;
}
}
Find minimum cost of tickets required to buy for traveling on known days of the month (1...30). Three types of tickets are available : 1-day ticket valid for 1 days and costs 2 units, 7-days ticket valid for 7 days and costs 7 units, 30-days ticket valid for 30 days and costs 25 units.
For eg: I want to travel on [1,4,6,7,28,30] days of the month i.e. 1st, 4th, 6th ... day of the month. How to buy tickets so that the cost is minimum.
I tried to use dynamic programming to solve this but the solution is not giving me the correct answer for all cases. Here is my solution in Java :
public class TicketsCost {
public static void main(String args[]){
int[] arr = {1,5,6,9,28,30};
System.out.println(findMinCost(arr));
}
public static int findMinCost(int[] arr) {
int[][] dp = new int[arr.length][3];
int[] tDays = {1,7,30};
int[] tCost = {2,7,25};
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < 3; j++) {
if (j==0){
dp[i][j]= (i+1)*tCost[j];
}
else{
int c = arr[i]-tDays[j];
int tempCost = tCost[j];
int k;
if (c>=arr[0] && i>0){
for (k = i-1; k >= 0; k--) {
if (arr[k]<=c){
c = arr[k];
}
}
tempCost += dp[c][j];
int tempCostX = dp[i-1][j] + tCost[0];
tempCost = Math.min(tempCost,tempCostX);
}
dp[i][j] = Math.min(tempCost,dp[i][j-1]);
}
}
}
return dp[arr.length-1][2];
}
}
The solution doesn't work for {1,7,8,9,10} input, it gives 10 but the correct answer should be 9. Also, for {1,7,8,9,10,15} it give 13 but the correct is 11.
I have posted my solution not for other to debug it for me but just for reference. I was taken a bottom-up dynamic programming approach for this problem. Is this approach correct?
Let MC(d) denote the minimum cost that will pay for all trips on days 1 through d. The desired answer is then MC(30).
To calculate MC(d), observe the following:
If there's no trip on day d, then MC(d) = MC(d − 1).
As a special case, MC(d) = 0 for all d ≤ 0.
Otherwise, the minimum cost involves one of the following:
A 1-day pass on day d. In this case, MC(d) = MC(d − 1) + 2.
A 7-day pass ending on or after day d. In this case, MC(d) = min(MC(d − 7), MC(d − 6), …, MC(d − 1)) + 7.
And since MC is nondecreasing (adding a day never reduces the minimum cost), this can be simplified to MC(d) = MC(d − 7) + 7. (Hat-tip to Ravi for pointing this out.)
A 30-day pass covering the whole period. In this case, MC(d) = 25.
As you've realized, dynamic programming (bottom-up recursion) is well-suited to this.
For ease of coding, I suggest we start by converting the list of days into a lookup table for "is this a trip day?":
boolean[] isDayWithTrip = new boolean[31]; // note: initializes to false
for (final int dayWithTrip : arr) {
isDayWithTrip[dayWithTrip] = true;
}
We can then create an array to track the minimum costs, and populate it starting from index 0:
int[] minCostUpThroughDay = new int[31];
minCostUpThroughDay[0] = 0; // technically redundant
for (int d = 1; d <= 30; ++d) {
if (! isDayWithTrip[d]) {
minCostUpThroughDay[d] = minCostUpThroughDay[d-1];
continue;
}
int minCost;
// Possibility #1: one-day pass on day d:
minCost = minCostUpThroughDay[d-1] + 2;
// Possibility #2: seven-day pass ending on or after day d:
minCost =
Math.min(minCost, minCostUpThroughDay[Math.max(0, d-7)] + 7);
// Possibility #3: 30-day pass for the whole period:
minCost = Math.min(minCost, 25);
minCostUpThroughDay[d] = minCost;
}
And minCostUpThroughDay[30] is the result.
You can see the above code in action at: https://ideone.com/1Xx1fd.
One recursive solution in Python3.
from typing import List
def solution(A: List[int]) -> int:
if not any(A):
return 0
tickets = {
1: 2,
7: 7,
30: 25,
}
import sys
min_cost = sys.maxsize
size = len(A)
for length, price in tickets.items():
current_cost = price
idx = 0
last_day = A[idx] + length
while idx < size and A[idx] < last_day:
idx += 1
if current_cost > min_cost:
continue
current_cost += solution(A[idx:])
if current_cost < min_cost:
min_cost = current_cost
return min_cost
if __name__ == '__main__':
cases = {
11: [1, 4, 6, 7, 28, 30],
9: [1, 7, 8, 9, 10],
}
for expect, parameters in cases.items():
status = (expect == solution(parameters))
print("case pass status: %s, detail: %s == solution(%s)" %
(status, expect, parameters))
public class Main03v3
{
public static void main(String[] args)
{
int[] A = {1,7,8,9,10,15,16,17,18,21,25};
System.out.println("Traveling days:\r\n "+Arrays.toString(A));
int cost = solution(A);
System.out.println("\r\nMinimum cost is " + cost);
System.out.println("\r\n" + new String(new char[40]).replace("\0", "-"));
}
public static int solution(int[] A)
{
if (A == null) return -1;
int sevenDays = 7;
int dayCost = 2, weekCost = 7, monthCost = 25;
int ratio_WeekAndDays = weekCost / dayCost;
int len = A.length;
if (len == 0) return -1;
if (len <= 3) return len * dayCost;
int cost[] = new int[len];
int i = 0;
while (i < len)
{
int startIdx = i, endIdx = i + 1;
while (endIdx < len && A[endIdx]-A[startIdx] < sevenDays)
endIdx++;
if (endIdx-startIdx > ratio_WeekAndDays)
{
if (endIdx >= startIdx + sevenDays)
endIdx = startIdx + sevenDays;
int j = startIdx;
cost[j] = ((j == 0) ? 0 : cost[j-1]) + weekCost;
while (++j < endIdx) {
cost[j] = cost[j-1];
}
i = j;
}
else
{
cost[i] = ((i == 0) ? 0 : cost[i-1]) + dayCost;
i++;
}
}
int finalCost = Math.min(cost[len-1], monthCost);
return finalCost;
}
}
Find minimum cost of tickets in JavaScript
case 1 : if input is [1,7,8,9,10] then the required output is 9
case 2 : if input is [1,7,8,9,10,15] then the required output is 11
function calMinCosts(arr){
if(!arr || arr.length===0)
return 0;
var len = arr.length;
var costsOfDateArr = Array.apply(null,{length:arr[len-1]+1}).map(()=>0);
var price1=2,price2=7,price3=25;
var days=7;
var index=0,n=costsOfDateArr.length;
for(var i=1;i<n;i++){
if(i===arr[index]){
if(i>=days+1){
costsOfDateArr[i] = Math.min(costsOfDateArr[i-days-1]+price2, costsOfDateArr[i-1]+price1);
}else{
costsOfDateArr[i] = Math.min(costsOfDateArr[0]+price2, costsOfDateArr[i-1]+price1);
}
index+=1;
}else{
costsOfDateArr[i] = costsOfDateArr[i-1];
}
}
return Math.min(price3,costsOfDateArr[n-1]);
}
console.log(calMinCosts([1,7,8,9,10]))
console.log(calMinCosts([1,7,8,9,10,15]))
Here is the C++ solution including print outs
#include <vector>
#include <iostream>
#include <cmath>
#include <algorithm>
int compute(std::vector<int> &A)
{
int sum[A.size()][A.size()+1];
for (int i = 0; i < A.size(); i++)
{
for(int j =0; j < A.size(); j++)
{
sum[i][j]=2;
}
}
for (int k = 0; k < A.size();k++)
{
sum[k][A.size()]=0;
}
for (int i = 0; i < A.size(); i++)
{
for(int j = 0; j < A.size(); j++)
{
if (i!=j)
{
if (sum[i][i] != 7)
{
int temp = abs(A[j]-A[i]);
if (temp<7 && abs(j-i)>=3)
{
sum[i][i]=7;
sum[i][j]=7;
if (i>j)
{
for(int k = j;k < i;k++)
sum[i][k]=7;
}
else
{
for(int k = i;k < j;k++)
sum[i][k]=7;
}
}
}
}
}
}
for (int i = 0; i < A.size(); ++i)
{
for(int j = 0; j < A.size(); ++j)
{
if (sum[i][j]==7)
{
sum[i][A.size()]+=1;
}
}
}
for (int i = 0; i < A.size(); ++i)
{
for (int j = 0; j < A.size()+1; ++j)
std::cout<<sum[i][j]<<" ";
std::cout<<std::endl;
}
int result = 0;
int row = A.size()-1;
int column = A.size()-1;
while(1)
{
int value = sum[row][A.size()];
if (value == 0)
value=1;
int temp = sum[row][column];
result += temp;
row = row-value;
column = column-value;
while (sum[row][column+1]==7 && row>=0)
{
row-=1;
column-=1;
result+=2;
}
if (row < 0)
break;
}
return result;
}
int solution(std::vector<int> &A) {
if (A.size() > 24)
return 25;
if (A.size() <= 3)
return A.size() * 2;
return std::min(25,compute(A));
}
int main()
{
std::vector<int> AA={1,2,3,4,5,29,30};
std::vector<int> B={1,2,3,4,5};
std::vector<int> A={1,2,3,4,5,9,10,11,12,13,14,17,18,20,21};
std::vector<int> C={1,2,3,12};
std::vector<int> D={1,2,3,4,12,13,14,15,29,30};
std::vector<int> DD={1,2,3,4,5,14,17,18,19,20,23,28,29,30};
std::vector<int> CC={1,2,3,4,5,6,7,9,14,17,18,19,20,23,28,29,30};
std::cout<<solution(AA)<<std::endl;
std::cout<<solution(D)<<std::endl;
std::cout<<solution(B)<<std::endl;
std::cout<<solution(A)<<std::endl;
std::cout<<solution(C)<<std::endl;
std::cout<<solution(DD)<<std::endl;
std::cout<<solution(CC)<<std::endl;
return 0;
}
Solved using the same approach of bottom-up dynamic programming. Here is the full solution :
public class PublicTicketCost {
public static void main(String args[]){
int[] arr = {1,7,8,9,10,15,16,17,18,21,25};
int[] tDays = {1,7,30};
int[] tCost = {2,7,25};
System.out.println(minCost(arr, tDays, tCost));
}
public static int minCost(int[] arr, int[] tDays, int[] tCost) {
int[][] dp = new int[arr.length][tDays.length];
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < tDays.length; j++) {
int prevDayIndex = findPrevDayIndex(arr,i,tDays,j);
int prevCost = prevDayIndex>=0 ? dp[prevDayIndex][tDays.length-1] : 0;
int currCost = prevCost + tCost[j];
if(j-1>=0){
currCost = Math.min(currCost, dp[i][j-1]);
}
dp[i][j] = currCost;
}
}
//print(dp);
return dp[arr.length-1][tDays.length-1];
}
private static void print(int arr[][]){
for (int i = 0; i < arr.length; i++) {
for (int j = 0; j < arr[0].length; j++) {
System.out.print(arr[i][j]+" ");
}
System.out.println();
}
}
private static int findPrevDayIndex(int[] arr, int i, int[] days, int j){
int validAfterDate = arr[i] - days[j];
if (validAfterDate<1){
return -1;
}
for (int k = i-1; k >= 0; k--) {
if (arr[k]<=validAfterDate){
return k;
}
}
return -1;
}
}
http://ideone.com/sfgxGo