I'm trying to solve this problem:
Given an array of positive integers, and an integer Y, you are allowed to replace at most Y array-elements with lesser values. Your goal is for the array to end up with as large a subset of identical values as possible. Return the size of this largest subset.
The array is originally sorted in increasing order, but you do not need to preserve that property.
So, for example, if the array is [10,20,20,30,30,30,40,40,40] and Y = 3, the result should be 6, because you can get six 30s by replacing the three 40s with 30s. If the array is [20,20,20,40,50,50,50,50] and Y = 2, the result should be 5, because you can get five 20s by replacing two of the 50s with 20s.
Below is my solution with O(nlogn) time complexity. (is that right?) I wonder if I can further optimize this solution?
Thanks in advance.
public class Nails {
public static int Solutions(int[] A, int Y) {
int N = A.length;
TreeMap < Integer, Integer > nailMap = new TreeMap < Integer, Integer > (Collections.reverseOrder());
for (int i = 0; i < N; i++) {
if (!nailMap.containsKey(A[i])) {
nailMap.put(A[i], 1);
} else {
nailMap.put(A[i], nailMap.get(A[i]) + 1);
}
}
List < Integer > nums = nailMap.values().stream().collect(Collectors.toList());
if (nums.size() == 1) {
return nums.get(0);
}
//else
int max = nums.get(0);
int longer = 0;
for (int j = 0; j < nums.size(); j++) {
int count = 0;
if (Y < longer) {
count = Y + nums.get(j);
} else {
count = longer + nums.get(j);
}
if (max < count) {
max = count;
}
longer += nums.get(j);
}
return max;
}
public static void main(String[] args) {
Scanner scanner = new Scanner(System.in);
while (scanner.hasNext()) {
String[] input = scanner.nextLine().replaceAll("\\[|\\]", "").split(",");
System.out.println(Arrays.toString(input));
int[] A = new int[input.length - 1];
int Y = Integer.parseInt(input[input.length - 1]);
for (int i = 0; i < input.length; i++) {
if (i < input.length - 1) {
A[i] = Integer.parseInt(input[i]);
} else {
break;
}
}
int result = Solutions(A, Y);
System.out.println(result);
}
}
}
A C++ implementation would like the following where A is the sorted pin size array and K is the number of times the pins can be hammered.
{1,1,3,3,4,4,4,5,5}, K=2 should give 5 as the answer
{1,1,3,3,4,4,4,5,5,6,6,6,6,6,6}, K=2 should give 6 as the answer
int maxCount(vector<int>& A, int K) {
int n = A.size();
int best = 0;
int count = 1;
for (int i = 0; i < n-K-1; i++) {
if (A[i] == A[i + 1])
count = count + 1;
else
count = 1;
if (count > best)
best = count;
}
int result = max(best+K, min(K+1, n));
return result;
}
Since the array is sorted to begin with, a reasonably straightforward O(n) solution is, for each distinct value, to count how many elements have that value (by iteration) and how many elements have a greater value (by subtraction).
public static int doIt(final int[] array, final int y) {
int best = 0;
int start = 0;
while (start < array.length) {
int end = start;
while (end < array.length && array[end] == array[start]) {
++end;
}
// array[start .. (end-1)] is now the subarray consisting of a
// single value repeated (end-start) times.
best = Math.max(best, end - start + Math.min(y, array.length - end));
start = end; // skip to the next distinct value
}
assert best >= Math.min(y + 1, array.length); // sanity-check
return best;
}
First, iterate through all the nails and create a hash H that stores the number of nails for each size. For [1,2,2,3,3,3,4,4,4], H should be:
size count
1 : 1
2 : 2
3 : 3
4 : 3
Now create an little algorithm to evaluate the maximum sum for each size S, given Y:
BestForSize(S, Y){
total = H[S]
while(Y > 0){
S++
if(Y >= H[S] and S < biggestNailSize){
total += H[S]
Y -= H[S]
}
else{
total += Y
Y = 0
}
}
return total;
}
Your answer should be max(BestForSize(0, Y), BestForSize(1, Y), ..., BestForSize(maxSizeOfNail, Y)).
The complexity is O(n²). A tip to optimize is to start from the end. For example, after you have the maximum value of nails in the size 4, how can you use your answer to find the maximum number of size 3?
Here is my java implementation: First I build a reversed map of each integer and its occurence for example {1,1,1,1,3,3,4,4,5,5} would give {5=2, 4=2, 3=2, 1=4}, then for each integer I calculate the max occurence that we can get of it regarding the K and the occurences of the highest integers in the array.
public static int ourFunction(final int[] A, final int K) {
int length = A.length;
int a = 0;
int result = 0;
int b = 0;
int previousValue = 0;
TreeMap < Integer, Integer > ourMap = new TreeMap < Integer, Integer > (Collections.reverseOrder());
for (int i = 0; i < length; i++) {
if (!ourMap.containsKey(A[i])) {
ourMap.put(A[i], 1);
} else {
ourMap.put(A[i], ourMap.get(A[i]) + 1);
}
}
for (Map.Entry<Integer, Integer> entry : ourMap.entrySet()) {
if( a == 0) {
a++;
result = entry.getValue();
previousValue = entry.getValue();
} else {
if( K < previousValue)
b = K;
else
b = previousValue;
if ( b + entry.getValue() > result )
result = b + entry.getValue();
previousValue += entry.getValue();
}
}
return result;
}
Since the array is sorted, we can have an O(n) solution by iterating and checking if current element is equals to previous element and keeping track of the max length.
static int findMax(int []a,int y) {
int n = a.length,current = 1,max = 0,diff = 0;
for(int i = 1; i< n; i++) {
if(a[i] == a[i-1]) {
current++;
diff = Math.min(y, n-i-1);
max = Math.max(max, current+diff);
}else {
current = 1;
}
}
return max;
}
given int array is not sorted than you should sort
public static int findMax(int []A,int K) {
int current = 1,max = 0,diff = 0;
List<Integer> sorted=Arrays.stream(A).sorted().boxed().collect(Collectors.toList());
for(int i = 1; i< sorted.size(); i++) {
if(sorted.get(i).equals(sorted.get(i-1))) {
current++;
diff = Math.min(K, sorted.size()-i-1);
max = Math.max(max, current+diff);
}else {
current = 1;
}
}
return max;
}
public static void main(String args[]) {
List<Integer> A = Arrays.asList(3,1,5,3,4,4,3,3,5,5,5,1);
int[] Al = A.stream().mapToInt(Integer::intValue).toArray();
int result=findMax(Al, 5);
System.out.println(result);
}
I have this question I am trying to solve. I have tried coding for the past 4 hours.
An integer is defined to be a Smart number if it is an element in the infinite sequence
1, 2, 4, 7, 11, 16 …
Note that 2-1=1, 4-2=2, 7-4=3, 11-7=4, 16-11=5 so for k>1, the kth element of the sequence is equal to the k-1th element + k-1. For example, for k=6, 16 is the kth element and is equal to 11 (the k-1th element) + 5 ( k-1).
Write function named isSmart that returns 1 if its argument is a Smart number, otherwise it returns 0. So isSmart(11) returns 1, isSmart(22) returns 1 and isSmart(8) returns 0
I have tried the following code to
import java.util.Arrays;
public class IsSmart {
public static void main(String[] args) {
// TODO Auto-generated method stub
int x = isSmart(11);
System.out.println(x);
}
public static int isSmart(int n) {
int[] y = new int[n];
int j = 0;
for (int i = 1; i <= n; i++) {
y[j] = i;
j++;
}
System.out.println(Arrays.toString(y));
for (int i = 0; i <= y.length; i++) {
int diff = 0;
y[j] = y[i+1] - y[i] ;
y[i] = diff;
}
System.out.println(Arrays.toString(y));
for (int i = 0; i < y.length; i++) {
if(n == y[i])
return 1;
}
return 0;
}
}
When I test it with 11 it is giving me 0 but it shouldn't. Any idea how to correct my mistakes?
It can be done in a simpler way as follows
import java.util.Arrays;
public class IsSmart {
public static void main(String[] args) {
int x = isSmart(11);
System.out.println("Ans: "+x);
}
public static int isSmart(int n) {
//------------ CHECK THIS LOGIC ------------//
int[] y = new int[n];
int diff = 1;
for (int i = 1; i < n; i++) {
y[0] =1;
y[i] = diff + y[i-1];
diff++;
}
//------------ CHECK THIS LOGIC ------------//
System.out.println(Arrays.toString(y));
for (int i = 0; i < y.length; i++) {
if(n == y[i])
return 1;
}
return 0;
}
}
One of the problems is the way that your populating your array.
The array can be populated as such
for(int i = 0; i < n; i++) {
y[i] = (i == 0) ? 1 : y[i - 1] + i;
}
The overall application of the function isSmart can be simplified to:
public static int isSmart(int n) {
int[] array = new int[n];
for(int i = 0; i < n; i++) {
array[i] = (i == 0) ? 1 : array[i - 1] + i;
}
for (int i = 0; i < array.length; i++) {
if (array[i] == n) return 1;
}
return 0;
}
Note that you don't need to build an array:
public static int isSmart(int n) {
int smart = 1;
for (int i = 1; smart < n; i++) {
smart = smart + i;
}
return smart == n ? 1 : 0;
}
Here is a naive way to think of it to get you started - you need to fill out the while() loop. The important thing to notice is that:
The next value of the sequence will be the number of items in the sequence + the last item in the sequence.
import java.util.ArrayList;
public class Test {
public static void main(String[] args) {
System.out.println(isSmart(11));
}
public static int isSmart(int n) {
ArrayList<Integer> sequence = new ArrayList<Integer>();
// Start with 1 in the ArrayList
sequence.add(1);
// You need to keep track of the index, as well as
// the next value you're going to add to your list
int index = 1; // or number of elements in the sequence
int nextVal = 1;
while (nextVal < n) {
// Three things need to happen in here:
// 1) set nextVal equal to the sum of the current index + the value at the *previous* index
// 2) add nextVal to the ArrayList
// 3) incriment index by 1
}
// Now you can check to see if your ArrayList contains n (is Smart)
if (sequence.contains(n)) { return 1; }
return 0;
}
}
First think of a mathematical solution.
Smart numbers form a sequence:
a0 = 1
an+1 = n + an
This gives a function for smart numbers:
f(x) = ax² + bx + c
f(x + 1) = f(x) + x = ...
So the problem is to find for a given y a matching x.
You can do this by a binary search.
int isSmart(int n) {
int xlow = 1;
int xhigh = n; // Exclusive. For n == 0 return 1.
while (xlow < xhigh) {
int x = (xlow + xhigh)/2;
int y = f(x);
if (y == n) {
return 1;
}
if (y < n) {
xlow = x + 1;
} else {
xhigh = x;
}
}
return 0;
}
Yet smarter would be to use the solution for x and look whether it is an integer:
ax² + bx + c' = 0 where c' = c - n
x = ...
I was playing around with this and I noticed something. The smart numbers are
1 2 4 7 11 16 22 29 ...
If you subtract one you get
0 1 3 6 10 15 21 28 ...
0 1 2 3 4 5 6 7 ...
The above sequence happens to be the sum of the first n numbers starting with 0 which is n*(n+1)/2. So add 1 to that and you get a smart number.
Since n and n+1 are next door to each other you can derive them by reversing the process.
Take 29, subtract 1 = 28, * 2 = 56. The sqrt(56) rounded up is 8. So the 8th smart number (counting from 0) is 29.
Using that information you can detect a smart number without a loop by simply reversing the process.
public static int isSmart(int v) {
int vv = (v-1)*2;
int sq = (int)Math.sqrt(vv);
int chk = (sq*(sq+1))/2 + 1;
return (chk == v) ? 1 : 0;
}
Using a version which supports longs have verified this against the iterative process from 1 to 10,000,000,000.
I am trying to use java to pass an array to get the mean, median,mode , max an min in java. I am currently having an issue passing the array to a function and return its value so i can output the results. I believe i have the loops correct to solve the mean median and mode but i cannot get them to send and receive as wanted. How can I pass the array and send back the values needed?
UPDATE: i have updated the code it will compile and i can input the number of years but i get several errors following after that. it is also not printing the outputs
Exception in thread "main" java.util.UnknownFormatConversionException: Conversion = 'i'
at java.util.Formatter$FormatSpecifier.conversion(Formatter.java:2646)
at java.util.Formatter$FormatSpecifier.(Formatter.java:2675)
at java.util.Formatter.parse(Formatter.java:2528)
at java.util.Formatter.format(Formatter.java:2469)
at java.io.PrintStream.format(PrintStream.java:970)
at java.io.PrintStream.printf(PrintStream.java:871)
at la5cs1110_woodspl_03.pkg17.pkg2016.La5cs1110_WoodsPl_03172016.main(La5cs1110_WoodsPl_03172016.java:56)
Java Result: 1
public static void main(String[] args) {
int i;
List<Double> hArray = new ArrayList<>();
int nYears = 0, y = 0;
double rMax = 0.00,rMin = 100.00;
//get input check if between 1-80
while(y == 0){
String userData = JOptionPane.showInputDialog
("Enter number of years");
nYears = Integer.parseInt(userData);
if (nYears > 1 && nYears <= 80 )
y = 1;
}
y = 0;
while(y <= nYears){
for(i = 0; i < 12; i++){
Random rand = new Random();
double rNum = rand.nextFloat() * (rMax - rMin) + rMin;
hArray.add(rNum);
}
double mean = getMean (hArray);
double median = getMedian (hArray);
double mode = getMode (hArray);
double max = getMaxValue(hArray);
double min = getMinValue (hArray);
System.out.printf("In year %i the Mean = %d , mode = %d, median = %d," +
" max = %d, min = %d", y , mean, median, mode, max, min);
y++;
}
}
private static double getMean(List<Double> hArray) {
double sum = 0;
for (int i = 0; i < hArray.size(); i++) {
sum += hArray.get(i);
}
return sum / hArray.size();
}
//Median
private static double getMedian(List<Double> hArray) {
int middle = hArray.size()/2;
if (hArray.size() %2 == 1) {
return hArray.get(middle);
} else {
return (hArray.get(middle-1) + hArray.get(middle)) / 2.0;
}
}
//Mode
public static double getMode(List<Double> hArray) {
double maxValue = 0, maxCount = 0;
for (int i = 0; i < hArray.size(); ++i) {
int count = 0;
for (int j = 0; j < hArray.size(); ++j) {
if (hArray.get(j) == hArray.get(i)) ++count;
}
if (count > maxCount) {
maxCount = count;
maxValue = hArray.get(i);
}
}
return maxValue;
}
public static double getMaxValue(List<Double> hArray){
double maxValue = hArray.get(0);
for(int i=1;i < hArray.size();i++){
if(hArray.get(i) > maxValue){
maxValue = hArray.get(i);
}
}
return maxValue;
}
public static double getMinValue(List<Double> hArray){
double minValue = hArray.get(0);
for(int i=1;i<hArray.size();i++){
if(hArray.get(i) < minValue){
minValue = hArray.get(i);
}
}
return minValue;
}
}
Your hArray is a List. You should convert it to an array first.
getMean(hArray.toArray)
Check out this.
This does not compile, you try to pass a Double to a method, which expects a double[]. So you have to change the parameter of your methods and use a List and just pass in the hArray (see Tibrogargan answer - i.e., you would have to modify each of your implementations) or do the following:
create a Double[]
Double[] hArray2 = hArray.toArray(new Double[hArray.size()]);
change your methods' signature, so that they expect an Double[]
private static double getMean(Double[] hArray) { ...}
pass hArray2 instead of hArray
double mean = getMean(hArray2);
// ...
That should be it.
Replace the section where you're trying to pass a single element from the array to your statistics functions with calls using the whole array and change the signature of the calls so they take a List<Double> param, not a double[]. Something like this:
double mean = getMean (hArray);
double median = getMedian (hArray);
double mode = getMode (hArray);
double max = getMaxValue(hArray);
double min = getMinValue (hArray);
//Mean
private static double getMean(List<Double> hArray) {
double sum = 0;
for (int i = 0; i < hArray.size(); i++) {
sum += hArray.get(i);
}
return sum / hArray.size();
}
See also: How do you calculate the variance, median, and standard deviation in C++ or Java?
Fix for median:
Copied directly from this above link with some minor modifications to use a List as a param
public Double median(List<Double> list)
{
Double[] array = list.toArray(new Double[list.size()]);
Arrays.sort(data);
if (data.length % 2 == 0)
{
return (data[(data.length / 2) - 1] + data[data.length / 2]) / 2.0;
}
else
{
return data[data.length / 2];
}
}
Fix for mode:
public Double mode(List<Double> list)
{
java.util.TreeMap<Double,Integer> map = new java.util.TreeMap<>();
Double maxVal = null;
int maxCount = 0;
for (Double d : list) {
int count = 0;
if (map.containsKey(d)) {
count = map.get(d) + 1;
} else {
count = 1;
}
map.put(d, count);
if (count > maxCount) {
maxVal = d;
maxCount = count;
}
}
return maxVal;
}
So i am currently working on a project for a course that i am doing, and i am writing a method that needs to add two ArrayLists containing integers together, and sets the sum in a new ArrayList. currently i have this, which is working fine
public BigInt add(BigInt otherBigInt) {
BigInt result = new BigInt();
int length = digitList.size() - 1;
int lengthOther = otherBigInt.digitList.size() - 1;
int temp = 0;
int whole = 0;
int carry = 0;
for (int i = length; i >= 0; i--){
temp = (digitList.get(i) + otherBigInt.digitList.get(i));
temp += carry;
// temp is equal to the sum of this(i) and otherBigInt(i), plus any number carried over.
if (temp >= 10){
whole = temp - 10;
carry = 1;
result.digitList.add(whole);
}
else if (temp < 10){
carry = 0;
result.digitList.add(temp);
}
}
if (carry == 1){
result.digitList.add(carry);
}
//adds any remaining carried number after for loop
// Supply this code.
return result;
}
however, currently the method only works if the arrayLists are of the same size, how would i modify the method to accommodate lists of varying size? an example of this would be two lists containing 735934 and 68945 giving the result 804879.
p.s.
not sure if it's needed, (still new to posting here) but the two lists I'm currently adding are 7359 and 6894, giving the answer 14253.
If my assumption is correct, then you are trying to simulate a case where you add two numbers using two lists, where one digit of the number occupies one index of the list.
Simplest solution would be to assume that the shortest list has zero's instead of no value and add till the max of the two lists:
public BigInt add(BigInt otherBigInt) {
BigInt result = new BigInt();
int length = Math.max(digitList.size(), otherBigInt.digitList.size()) - 1;
int lengthOther = otherBigInt.digitList.size() - 1;
int temp = 0;
int whole = 0;
int carry = 0;
for (int i = length; i >= 0; i--){
temp = ( checkAndGet(digitList, i) + checkAndGet(otherBigInt.digitList, i) );
temp += carry;
// temp is equal to the sum of this(i) and otherBigInt(i), plus any number carried over.
if (temp >= 10) {
whole = temp - 10;
carry = 1;
result.digitList.add(whole);
}
else {
carry = 0;
result.digitList.add(temp);
}
}
if (carry == 1){
result.digitList.add(carry);
}
//adds any remaining carried number after for loop
// Supply this code.
return result;
}
// if the index position being retrieved is larger than the size, assume 0
private int checkAndGet(List<Integer> input, position) {
return (input.size() < position) ? input.get(position) : 0;
}
Let the two digit array be a1[0 ... n1] and a2[0 ... n2]. Now your algorithm would be something like :
add(a1, a2):
min_length = min{a1.length, a2.length}
result[0 ... max{a1.length, a2.length} + 1]
carry = 0
for(i in [0 ... min_length - 1])
result[i] = carry + a1[i] + a2[i]
carry = result[i] / 10
result[i] %= 10
while(i < a1.length)
result[i] = a1[i]
while(i < a2.length)
result[i] = a2[i]
result[i] = carry
Notice that you have to add the remaining digits in case they are not of same size. I assume that the digits are stored in order i.e. a[0] is the 1st digit.
I would iterate through the smaller array backwards, adding the indexes together as you go:
ArrayList<Integer> toIterate = (array1.size() > array2.size)? a1 : a2;
ArrayList<Integer> seperate = (array1.size() > array2.size)? a2 : a1;
for (int i = toIterate.size - 1; i >= 0; i --) {
if (seperate.get(i) != null) {
arrayResult.add(toIterate.get(i) + seperate.get(i));
}
else {
arrayResult.add(toIterate.get(i));
}
}
class CalorieExpenditures {
String activity
int lbs90
int lbs100
int lbs110
int lbs120
int lbs130
int lbs140
int lbs150
int lbs160
int lbs170
int lbs180
int lbs190
int lbs200
int lbs220
int lbs240
int lbs260
int lbs280
int lbs300
}
From the above POGO (b'se i am using grails).
How to find the nearest lbs property from POGO
e.g
if i pass 282 it will return lbs280 and if i pass 295 it will return lbs300.
logic is the difference between two values if the difference is same will return the grater value.
You can suggest java method or grails method to work with.
I need a simple program that finds nearest value.
Thanks in advance.
Below is example to find given number from int array, with nearest lower & upper
public class FindNearestInt
{
public static void main(String[] args)
{
Random random = new Random();
int array[] = new int[30];
//Initialise array with rendom values
for (int i = 0; i < array.length; i++)
{
array[i] = random.nextInt(200);
}
System.out.println(Arrays.toString(array));
Arrays.sort(array);
System.out.println(Arrays.toString(array));
// Number you want to find in array
int searchFor = 57;
//Nearest lower you searching for
int nearestLower = 0;
//Nearest upper you searching for
int nearestUpper = Integer.MAX_VALUE;
int searchForExist = -1;
for (int i = 0; i < array.length; i++)
{
int j = array[i];
if (j < searchFor)
{
if(j > nearestLower){
nearestLower = j;
}
} else if (j > searchFor){
if(j < nearestUpper){
nearestUpper = j;
}
} else {
nearestLower = -1;
nearestUpper = -1;
searchForExist = j;
break;
}
}
System.out.println("Nearest Lower : " + nearestLower);
// This will print -1 if number exist in array
System.out.println("Provided Number Already Exist : " + searchForExist);
System.out.println("Nearest Upper : " + nearestUpper);
}
}
A simpler and faster solution is to use a formula
public static int nearest(int num) {
return num < 90 ? 90 :
num < 200 ? Math.round(num/10.0) * 10 :
num < 300 ? Math.round(num/20.0) * 20 : 300;
def calorieExpendituresWeightCategory(float weight){
int nearest = 0;
int min = Integer.MAX_VALUE
CalorieExpenditures.properties.each {
if(it.toString().startsWith("lbs")){
int j = it.toString().substring(it.toString().indexOf("lbs"))
int k = (weight - j) * (weight - j)
if(k < min){
min = k
nearest = j
}
}
}
return nearest
}
This works for me i think simple and works for me.
Thanks for the answers.