Java sum algorithm not returning anything - java

I'm trying to solve the two sum algorithm on Leetcode:
Given an array of integers, return indices of the two numbers such that they add up to a specific target. You may assume that each input would have exactly one solution, and you may not use the same element twice.
And came up with this:
public class Leet {
public static void main(String[] args) {
System.out.println(Arrays.toString(twoSum(new int[]{1, 2, 3, 4, 5, 6}, 2)));
}
public static int[] twoSum(int[] nums, int target) {
int[] answer = null;
int i = 0;
for (int j = nums[i]; i < nums.length; i++) {
for (int x : nums) {
if (x != j & (j + x) == target) {
int x2 = java.util.Arrays.asList(nums).indexOf(x);
answer[0] = i;
answer[1] = x2;
} else {
return nums;
}
}
}
System.out.println("leet method executed");
return answer;
}
}
The problem is it's not returning anything, not event the printed statement. Any ideas?

See some fixes. Remember about array initialization and cases when values can be same in the array.
public class Solution {
public int[] twoSum(int[] nums, int target) {
int[] answer = null;
for(int i=0;i<nums.length;i++) {
int value = nums[i];
for(int j=i+1;j<nums.length;j++) {
int x=nums[j];
if ((value+x)==target) {
answer = new int[2];
answer[0]=i;
answer[1]=j;
}
}
}
System.out.println("leet method executed");
if (answer == null) {
return nums;
}
return answer;
}
}

I can see 2 things wrong or not intended in the program (leaving aside whether it's the best approach to the problem).
As stated in a comment, you should use && instead of & for boolean AND. & is bitwise AND, useful for integer bit twiddling.
You declare answer as an array, but never create space for it. You need to say int [] answer = new int[2]; or similar.
I haven't run the code, but if the test program ends with no output, check that you aren't getting a NullPointerException (caused by #2 above).

Don't forget about null-checks and the case where no correct number-pair was found.
public static int[] twoSum(int[] numbers, int target) {
if(Objects.isNull(numbers)){
throw new IllegalArgumentException("numbers is not allowed to be null");
}
for (int a=0;a<numbers.length;a++) {
int first = numbers[a];
for (int b=0;b<numbers.length;b++) {
int second = numbers[b];
if (first + second == target && a!=b) {
return new int[] { first, second };
}
}
}
throw new IllegalArgumentException("there has to be a matching pair");
}

Related

Find sum of subsequent 3 elements of an array

I need to sum the three consecutive elements of an array when appending numbers to the same array dynamically and return true if the sum is equal to the argument value. I have already written the code below and it all return required output but it fails for some test cases( I don't have the the exact test cases), Can anybody tell me what exact scenario which my programme can be failed?
import java.util.LinkedList;
import java.util.List;
public class Test {
List<Integer> mergeList = new LinkedList<Integer>();
List<List<Integer>> allList = new LinkedList<List<Integer>>();
List<Integer> tail;
int from = 0;
int to = 0;
public void addLast(int[] list) {
allList.removeAll(allList);
for(int i : list) {
mergeList.add(i);
}
if (mergeList.size() > 0) {
int j = 0;
while(to < mergeList.size()){
from = j;
to = j + 3;
tail = mergeList.subList(from, to);
j++;
allList.add(tail);
}
}
}
public boolean containsSum3(int sum) {
boolean retVal = false;
for (List<Integer> sum3List : allList) {
if (sum3List.stream().mapToInt(Integer::intValue).sum() == sum) {
retVal = true;
}
}
return retVal;
}
public static void main(String[] args) {
Test s = new Test();
s.addLast(new int[] { 1, 2, 3 });
System.out.println(s.containsSum3(6));
System.out.println(s.containsSum3(9));
s.addLast(new int[] { 4 });
System.out.println(s.containsSum3(9));
s.addLast(new int[] { 5, 2});
System.out.println(s.containsSum3(11));
s.addLast(new int[] { 0, -1 });
System.out.println(s.containsSum3(7));
System.out.println(s.containsSum3(2));
}
}
Output:
true
false
true
true
true
false
I generated large random collections of integers and couldn't find any obvious cases your code fails for beyond the insufficient elements. Incidentally, the function I wrote to check if a list has any consecutive n elements that sum to a given value was:
public static boolean containsSum(List<Integer> list, int sum, int n) {
return IntStream.range(0, list.size() - n + 1)
.anyMatch(i -> list.subList(i, i + n).stream()
.reduce(0, Integer::sum) == sum);
}
I can't see any reason for your code that keeps all the list of lists: the space / time tradeoff doesn't make a lot of sense. I suggest you could simplify addLast to just add the elements to mergeList. There are a bunch of stylistic issues with your code but I'm sure you'll work those out in your own time.

Boolean assignment not catching, need to understand more

public class MyClass {
public static void main(String args[]) {
int[] nums = {1, 2, 9, 3, 4};
boolean results = false;
int end = nums.length;
if (end>4)end=4;
for (int x=0;x<end;x++)
{
System.out.println(nums[x]);
results = (nums[x] == 9);
}
System.out.println(results);
}
}
The following code checks to see if a 9 is present in the first 4 elements of an array, yet using the boolean operator in this fashion seems to always fail if there are not more than 1 "9" in the first 4 elements of the array.
Why is this? Logically it seems that this should work, and it really helps me to understand better when I understand why something doesn't work.
The reason is that you have itetate all the elements,the result will be the result of the last element,
So you need to stop for when you find the match result
for (int x=0;x<end;x++)
{
System.out.println(nums[x]);
if(nums[x] == 9){
result = true;
break;
}
}
You overwrite results every time. As written, this'll tell you whether the last item in the array equals 9 (which it doesn't), not whether any item in the array equals 9.
You should assign true to result if num[x] == 9; otherwise, don't assign anything.
#lucumt's answer shows an example of how to do that. One other example, just replace
results = (nums[x] == 9);
with
results |= (nums[x] == 9);
where the |= assignment is equivalent to results = results || (num[x] == 9); - in other words, if any value is true, the entire expression will be true. (Note that #lucumt's answer is slightly more efficient because it's O(n) whereas this is Theta(n) - i.e. this will always run exactly n times, where n is the length of the list, but #lucumt's can end the loop early if it finds any 9).
In your for loop you are over writing the value each time. This means you are testing if the 4th value is equal to 9.
you can solve your problem like so:
boolean results = false;
for (int x = 0; x < end; x++) {
System.out.println(nums[x]);
if(nums[x] == 9) {
results = true;
break;
}
}
Try this:
boolean isPresent(int[] nums, int val)
{
for (int x : nums )
{
if (nums[x] == val)
return true;
}
return false;
}
Otherwise you rewrite a value every time you're checking
I wrote you a class. The method nignPresentInFirst4Elements(int[] arr) returns true if the given array contains a 9 in one or more of it's first 4 elements:
public class Test {
private static boolean nignPresentInFirst4Elements(int[] arr) {
if(arr == null)
return false;
for(int i = 0; i < Math.min(arr.length, 4); i++) {
if(arr[i] == 9)
return true;
}
return false;
}
public static void main(String[] args) {
int[][] arrs = new int[][] {
{5, 8, 9, 3},
{5, 8, 9, 3, 8, 26},
{5, 8, 9, 9},
{5, 8, 23, 0}
};
for(int i = 0; i < arrs.length; i++) {
System.out.println(toString(arrs[i]) + " | " + nignPresentInFirst4Elements(arrs[i]));
}
}
private static String toString(int[] arr) {
if(arr == null)
return "null";
String s = "[";
if(arr.length > 0)
s += arr[0];
for(int i = 1; i < arr.length; i++) {
s += ", " + arr[i];
}
s += "]";
return s;
}
}

Count different values in array in Java

I'm writing a code where I have an int[a] and the method should return the number of unique values. Example: {1} = 0 different values, {3,3,3} = 0 different values, {1,2} = 2 different values, {1,2,3,4} = 4 different values etc. I am not allowed to sort the array.
The thing is that my method doesn't work probably. There is something wrong with my for statement and I can't figure it out.
public class Program
{
public static void main(String[] args)
{
int[] a = {1, 2, 3, 1};
System.out.println(differentValuesUnsorted(a));
//run: 4 //should be 3
}
public static int differentValuesUnsorted(int[] a)
{
int values; //values of different numbers
if (a.length < 2)
{
return values = 0;
}else if (a[0] == a[1])
{
return values = 0;
}else
{
values = 2;
}
int numberValue = a[0];
for (int i = a[1]; i < a.length; i++)
{
if (a[i] != numberValue)
{
numberValue++;
values++;
}
}
return values;
}
}
Can anybody help?
This is actually much simpler than most people have made it out to be, this method works perfectly fine:
public static int diffValues(int[] numArray){
int numOfDifferentVals = 0;
ArrayList<Integer> diffNum = new ArrayList<>();
for(int i=0; i<numArray.length; i++){
if(!diffNum.contains(numArray[i])){
diffNum.add(numArray[i]);
}
}
if(diffNum.size()==1){
numOfDifferentVals = 0;
}
else{
numOfDifferentVals = diffNum.size();
}
return numOfDifferentVals;
}
Let me walk you through it:
1) Provide an int array as a parameter.
2) Create an ArrayList which will hold integers:
If that arrayList DOES NOT contain the integer with in the array
provided as a parameter, then add that element in the array parameter
to the array list
If that arrayList DOES contain that element from the int array parameter, then do nothing. (DO NOT ADD THAT VALUE TO THE ARRAY LIST)
N.B: This means that the ArrayList contains all the numbers in the int[], and removes the repeated numbers.
3) The size of the ArrayList (which is analogous to the length property of an array) will be the number of different values in the array provided.
Trial
Input:
int[] numbers = {3,1,2,2,2,5,2,1,9,7};
Output: 6
First create distinct value array, It can simply create using HashSet.
Then alreadyPresent.size() will provide number of different values. But for the case such as -{3,3,3} = 0 (array contains same elements); output of alreadyPresent.size() is 1. For that use this simple filter
if(alreadyPresent.size() == 1)){
return 0;
}
Following code will give the count of different values.
import java.util.Arrays;
import java.util.HashSet;
import java.util.Set;
public class Demo {
public static void main(String[] args)
{
int array[] = {9,9,5,2,3};
System.out.println(differentValuesUnsorted(array));
}
public static int differentValuesUnsorted(int[] array)
{
Set<Integer> alreadyPresent = new HashSet<Integer>();
for (int nextElem : array) {
alreadyPresent.add(nextElem);
}
if(alreadyPresent.size() == 1){
return 0;
}
return alreadyPresent.size();
}
}
You can use a HashSet, which can only contain unique elements. The HashSet will remove the duplicated items and you can then get the size of the set.
public static int differentValuesUnsorted(int[] a) {
Set<Integer> unique = new HashSet<Integer>();
for (int val : a) {
unique.add(val); // will only be added if a is not in unique
}
if (unique.size() < 2) { // if there are no different values
return 0;
}
return unique.size();
}
For small arrays, this is a fast concise method that does not require the allocation of any additional temporary objects:
public static int uniqueValues(int[] ids) {
int uniques = 0;
top:
for (int i = 0; i < ids.length; i++) {
final int id = ids[i];
for (int j = i + 1; j < ids.length; j++) {
if (id == ids[j]) continue top;
}
uniques++;
}
return uniques;
}
Try this:
import java.util.ArrayList;
public class DifferentValues {
public static void main(String[] args)
{
int[] a ={1, 2, 3, 1};
System.out.println(differentValuesUnsorted(a));
}
public static int differentValuesUnsorted(int[] a)
{
ArrayList<Integer> ArrUnique = new ArrayList<Integer>();
int values=0; //values of different numbers
for (int num : a) {
if (!ArrUnique.contains(num)) ArrUnique.add(num);
}
values = ArrUnique.size();
if (values == 1) values = 0;
return values;
}
}
input:{1,1,1,1,1} - output: 0
input:{1,2,3,1} - output: 3
Try this... its pretty simple using ArrayList. You don't even need two loop. Go on
import java.util.*;
public class distinctNumbers{
public static void main(String []args){
int [] numbers = {2, 7, 3, 2, 3, 7, 7};
ArrayList<Integer> list=new ArrayList<Integer>();
for(int i=0;i<numbers.length;i++)
{
if(!list.contains(numbers[i])) //checking if the number is present in the list
{
list.add(numbers[i]); //if not present then add the number to the list i.e adding the distinct number
}
}
System.out.println(list.size());
}
}
Try this simple code snippet.
public static int differentValuesUnsorted(int[] a)
{
ArrayList<Integer> list=new ArrayList<Integer>(); //import java.util.*;
for(int i:numbers) //Iterate through all the elements
if(!list.contains(i)) //checking for duplicate element
list.add(i); //Add to list if unique
return list.size();
}
What about this?
private <T> int arrayDistinctCount(T[] array) {
return Arrays.stream(array).collect(Collectors.toSet()).size();
}
Use a set to remove duplicates
public static int differentValuesUnsorted(int[] a) {
if (a.length < 2) {
return 0;
}
Set<Integer> uniques = new HashSet<>(a);
return singleUnique.size();
}

how to find a number in a range in array

For example if I enter inRange(1,6) then it must print {2,2,2,3,5} for the below array. I am not sure if my logic is right. Is there a better way to do this? I am also not sure of how to construct my return statement. I want to do this without using arraylist or array.
public class AgeCount {
static int[] a=new int[]{1,2,45,6,3,2,1,2,5,6,65,45,43,21,34,34};
public AgeCount(){
}
public static int inRange(int b,int e)
{
int store[]=new int[a.length];
int count=0;
for (int i = 0; i < a.length; i++) {
if(a[i]>b && a[i]<e)
{
return a[i];
}
}
return 0;
}
If your method only has to print the numbers of the given range, it doesn't have to return anything :
public static void inRange(int b,int e)
{
int count=0;
System.out.print('{');
boolean first = true;
for (int i = 0; i < a.length; i++) {
if(a[i]>=b && a[i]<=e)
{
if (!first) {
System.out.print(',');
} else {
first = false;
}
System.out.print(a[i]);
}
}
System.out.print('}');
}
This is assuming the order of the output doesn't matter. If it does matter, sort the input array prior to the loop.
Java 8 approach:
int[] arr = new int[] {1,2,45,6,3,2,1,2,5,6,65,45,43,21,34,34};
int res[] = Arrays.stream(arr).filter(n -> n >= b && n <= e).toArray();
System.out.println(Arrays.toString(res));
I'm not sure why you don't want to use arrays or some kind of a list. If it's for homework purposes, then instead of returning a value from the method, print it if you only want to display the result. Otherwise, you should consider using List.
Java8:
public static void main(String[] args) {
int[] arrayToFilter = new int[]{1, 2, 45, 6, 3, 2, 1, 2, 5, 6, 65, 45, 43, 21, 34, 34};
int upperLimit = 5;
inRange(arrayToFilter, upperLimit);
}
private static void inRange(int[] arrayToFilter, int upperLimit) {
String sortedAndLimitedString = Arrays.stream(arrayToFilter)
.sorted()
.filter(value -> value < upperLimit)
.mapToObj(String::valueOf)
.collect(Collectors.joining(",", "{", "}"));
System.out.println(sortedAndLimitedString);
}
Output:
{1,1,2,2,2,3}
This sounds like a homework question. Still here goes.
Your return being a single int it has to be something like 122235 which represents all the ints satisfying your range condition.
So you use BitSet class and set the bits when found in range, which you can convert to an int like above and return.
I assumed that the result must be sorted.
public static int[] inRange(int b,int e) {
return IntStream.of(a)
.filter(n -> n > b && n < e)
.sorted()
.toArray();
}
System.out.println(Arrays.toString(AgeCount.inRange(1, 6)));
// -> [2, 2, 2, 3, 5]
```
Here is the simple & the shortest solution.
import java.util.*;
public class AgeCount
{
static int[] a=new int[]{1,2,45,6,3,2,1,2,5,6,65,45,43,21,34,34};
public AgeCount()
{
}
public static void inRange(int b,int e)
{
int store[]=new int[a.length];
Arrays.sort(a);
for (int i = b; i < e; i++)
{
System.out.print(a[i+1]+",");
}
}
}
And this is how you return a value for the same.
//sort an array, get a defined index values, and print it on the screen.
import java.util.*;
public class AgeCount
{
static int[] a=new int[]{1,2,45,6,3,2,1,2,5,6,65,45,43,21,34,34};
public AgeCount()
{
}
public static int[] inRange(int b,int e)
{
int store[]=new int[a.length];
int[] myRange = new int[e-b];
Arrays.sort(a);
for (int i = b; i < e; i++)
{
for (int j = 0; j < (e-b); j++)
{
myRange[j] = a[i+1];
}
System.out.print(a[i+1]+",");
}
return myRange;
}
}
Nice start so far! Even though you said you didn't want to use array or ArrayList, it makes the most sense here to use one. I would use an ArrayList of Integers instead of just an array, because we don't know the length yet. Instead of saying return a[i];, you would say store.append(a[i]);. I haven't tested this code, so there may be an error or two, so please correct me if I'm wrong, but here's the fixed version:
public class AgeCount {
static int[] a=new int[]{1,2,45,6,3,2,1,2,5,6,65,45,43,21,34,34};
public AgeCount(){
}
public static void inRange(int b,int e)
{
ArrayList<Integer> store = new ArrayList<Integer>();
int count=0;
for (int i = 0; i < a.length; i++) {
if(a[i]>=b && a[i]<=e)
{
store.append(a[i]);
}
}
println(store);
}
}
Well first things first, it seems like you aren't fully clear on what you are trying to do. And that's okay! Sometimes a problem can seem overwhelming and confusing if we're not really sure what's supposed to happen.
I recommend when you're starting a new task you take some time to decompose the task. Take a piece of paper and try and break it down into its smallest and simplest parts and go from there, coding and testing it bit by bit. The basics of the SDLC (try googling the software development lifecycle) could help you here too - it's all about figuring out what you are trying to achieve and what are the various things you need to implement to get there.
And please, Don't panic and throw code you don't understand down! You'll only sink deeper into the confusion!

Find an array inside another larger array

I was recently asked to write 3 test programs for a job. They would be written using just core Java API's and any test framework of my choice. Unit tests should be implemented where appropriate.
Although I haven't received any feedback at all, I suppose they didn't like my solutions (otherwise I would have heard from them), so I decided to show my programs here and ask if this implementation can be considered good, and, if not, then why?
To avoid confusion, I'll ask only first one for now.
Implement a function that finds an
array in another larger array. It
should accept two arrays as parameters
and it will return the index of the
first array where the second array
first occurs in full. Eg,
findArray([2,3,7,1,20], [7,1]) should
return 2.
I didn't try to find any existing solution, but instead wanted to do it myself.
Possible reasons:
1. Should be static.
2. Should use line comments instead of block ones.
3. Didn't check for null values first (I know, just spotted too late).
4. ?
UPDATE:
Quite a few reasons have been presented, and it's very difficult for me to choose one answer as many answers have a good solution. As #adietrich mentioned, I tend to believe they wanted me to demonstrate knowledge of core API (they even asked to write a function, not to write an algorithm).
I believe the best way to secure the job was to provide as many solutions as possible, including:
1. Implementation using Collections.indexOfSubList() method to show that I know core collections API.
2. Implement using brute-force approach, but provide a more elegant solution.
3. Implement using a search algorithm, for example Boyer-Moore.
4. Implement using combination of System.arraycopy() and Arrays.equal(). However not the best solution in terms of performance, it would show my knowledge of standard array routines.
Thank you all for your answers!
END OF UPDATE.
Here is what I wrote:
Actual program:
package com.example.common.utils;
/**
* This class contains functions for array manipulations.
*
* #author Roman
*
*/
public class ArrayUtils {
/**
* Finds a sub array in a large array
*
* #param largeArray
* #param subArray
* #return index of sub array
*/
public int findArray(int[] largeArray, int[] subArray) {
/* If any of the arrays is empty then not found */
if (largeArray.length == 0 || subArray.length == 0) {
return -1;
}
/* If subarray is larger than large array then not found */
if (subArray.length > largeArray.length) {
return -1;
}
for (int i = 0; i < largeArray.length; i++) {
/* Check if the next element of large array is the same as the first element of subarray */
if (largeArray[i] == subArray[0]) {
boolean subArrayFound = true;
for (int j = 0; j < subArray.length; j++) {
/* If outside of large array or elements not equal then leave the loop */
if (largeArray.length <= i+j || subArray[j] != largeArray[i+j]) {
subArrayFound = false;
break;
}
}
/* Sub array found - return its index */
if (subArrayFound) {
return i;
}
}
}
/* Return default value */
return -1;
}
}
Test code:
package com.example.common.utils;
import com.example.common.utils.ArrayUtils;
import junit.framework.TestCase;
public class ArrayUtilsTest extends TestCase {
private ArrayUtils arrayUtils = new ArrayUtils();
public void testFindArrayDoesntExist() {
int[] largeArray = {1,2,3,4,5,6,7};
int[] subArray = {8,9,10};
int expected = -1;
int actual = arrayUtils.findArray(largeArray, subArray);
assertEquals(expected, actual);
}
public void testFindArrayExistSimple() {
int[] largeArray = {1,2,3,4,5,6,7};
int[] subArray = {3,4,5};
int expected = 2;
int actual = arrayUtils.findArray(largeArray, subArray);
assertEquals(expected, actual);
}
public void testFindArrayExistFirstPosition() {
int[] largeArray = {1,2,3,4,5,6,7};
int[] subArray = {1,2,3};
int expected = 0;
int actual = arrayUtils.findArray(largeArray, subArray);
assertEquals(expected, actual);
}
public void testFindArrayExistLastPosition() {
int[] largeArray = {1,2,3,4,5,6,7};
int[] subArray = {5,6,7};
int expected = 4;
int actual = arrayUtils.findArray(largeArray, subArray);
assertEquals(expected, actual);
}
public void testFindArrayDoesntExistPartiallyEqual() {
int[] largeArray = {1,2,3,4,5,6,7};
int[] subArray = {6,7,8};
int expected = -1;
int actual = arrayUtils.findArray(largeArray, subArray);
assertEquals(expected, actual);
}
public void testFindArrayExistPartiallyEqual() {
int[] largeArray = {1,2,3,1,2,3,4,5,6,7};
int[] subArray = {1,2,3,4};
int expected = 3;
int actual = arrayUtils.findArray(largeArray, subArray);
assertEquals(expected, actual);
}
public void testFindArraySubArrayEmpty() {
int[] largeArray = {1,2,3,4,5,6,7};
int[] subArray = {};
int expected = -1;
int actual = arrayUtils.findArray(largeArray, subArray);
assertEquals(expected, actual);
}
public void testFindArraySubArrayLargerThanArray() {
int[] largeArray = {1,2,3,4,5,6,7};
int[] subArray = {4,5,6,7,8,9,10,11};
int expected = -1;
int actual = arrayUtils.findArray(largeArray, subArray);
assertEquals(expected, actual);
}
public void testFindArrayExistsVeryComplex() {
int[] largeArray = {1234, 56, -345, 789, 23456, 6745};
int[] subArray = {56, -345, 789};
int expected = 1;
int actual = arrayUtils.findArray(largeArray, subArray);
assertEquals(expected, actual);
}
}
The requirement of "using just core Java API's" could also mean that they wanted to see whether you would reinvent the wheel. So in addition to your own implementation, you could give the one-line solution, just to be safe:
public static int findArray(Integer[] array, Integer[] subArray)
{
return Collections.indexOfSubList(Arrays.asList(array), Arrays.asList(subArray));
}
It may or may not be a good idea to point out that the example given contains invalid array literals.
Clean and improved code
public static int findArrayIndex(int[] subArray, int[] parentArray) {
if(subArray.length==0){
return -1;
}
int sL = subArray.length;
int l = parentArray.length - subArray.length;
int k = 0;
for (int i = 0; i < l; i++) {
if (parentArray[i] == subArray[k]) {
for (int j = 0; j < subArray.length; j++) {
if (parentArray[i + j] == subArray[j]) {
sL--;
if (sL == 0) {
return i;
}
}
}
}
}
return -1;
}
For finding an array of integers in a larger array of integers, you can use the same kind of algorithms as finding a substring in a larger string. For this there are many algorithms known (see Wikipedia). Especially the Boyer-Moore string search is efficient for large arrays. The algorithm that you are trying to implement is not very efficient (Wikipedia calls this the 'naive' implementation).
For your questions:
Yes, such a method should be static
Don't care, that's a question of taste
The null check can be included, or you should state in the JavaDoc that null values are not allowed, or JavaDoc should state that when either parameter is null a NullPointerException will be thrown.
Well, off the top of my head:
Yes, should be static.
A company complaining about that would not be worth working for.
Yeah, but what would you do? Return? Or throw an exception? It'll throw an exception the way it is already.
I think the main problem is that your code is not very elegant. Too many checks in the inner loop. Too many redundant checks.
Just raw, off the top of my head:
public int findArray(int[] largeArray, int[] subArray) {
int subArrayLength = subArray.length;
if (subArrayLength == 0) {
return -1;
}
int limit = largeArray.length - subArrayLength;
int i=0;
for (int i = 0; i <= limit; i++) {
boolean subArrayFound = true;
for (int j = 0; j < subArrayLength; j++) {
if (subArray[j] != largeArray[i+j]) {
subArrayFound = false;
break;
}
/* Sub array found - return its index */
if (subArrayFound) {
return i;
}
}
/* Return default value */
return -1;
}
You could keep that check for the first element so you don't have the overhead of setting up the boolean and the for loop for every single element in the array. Then you'd be looking at
public int findArray(int[] largeArray, int[] subArray) {
int subArrayLength = subArray.length;
if (subArrayLength == 0) {
return -1;
}
int limit = largeArray.length - subArrayLength;
for (int i = 0; i <= limit; i++) {
if (subArray[0] == largeArray[i]) {
boolean subArrayFound = true;
for (int j = 1; j < subArrayLength; j++) {
if (subArray[j] != largeArray[i+j]) {
subArrayFound = false;
break;
}
/* Sub array found - return its index */
if (subArrayFound) {
return i;
}
}
}
/* Return default value */
return -1;
}
Following is an approach using KMP pattern matching algorithm. This solution takes O(n+m). Where n = length of large array and m = length of sub array. For more information, check:
https://en.wikipedia.org/wiki/KMP_algorithm
Brute force takes O(n*m). I just checked that Collections.indexOfSubList method is also O(n*m).
public static int subStringIndex(int[] largeArray, int[] subArray) {
if (largeArray.length == 0 || subArray.length == 0){
throw new IllegalArgumentException();
}
if (subArray.length > largeArray.length){
throw new IllegalArgumentException();
}
int[] prefixArr = getPrefixArr(subArray);
int indexToReturn = -1;
for (int m = 0, s = 0; m < largeArray.length; m++) {
if (subArray[s] == largeArray[m]) {
s++;
} else {
if (s != 0) {
s = prefixArr[s - 1];
m--;
}
}
if (s == subArray.length) {
indexToReturn = m - subArray.length + 1;
break;
}
}
return indexToReturn;
}
private static int[] getPrefixArr(int[] subArray) {
int[] prefixArr = new int[subArray.length];
prefixArr[0] = 0;
for (int i = 1, j = 0; i < prefixArr.length; i++) {
while (subArray[i] != subArray[j]) {
if (j == 0) {
break;
}
j = prefixArr[j - 1];
}
if (subArray[i] == subArray[j]) {
prefixArr[i] = j + 1;
j++;
} else {
prefixArr[i] = j;
}
}
return prefixArr;
}
A little bit optimized code that was posted before:
public int findArray(byte[] largeArray, byte[] subArray) {
if (subArray.length == 0) {
return -1;
}
int limit = largeArray.length - subArray.length;
next:
for (int i = 0; i <= limit; i++) {
for (int j = 0; j < subArray.length; j++) {
if (subArray[j] != largeArray[i+j]) {
continue next;
}
}
/* Sub array found - return its index */
return i;
}
/* Return default value */
return -1;
}
int findSubArr(int[] arr,int[] subarr)
{
int lim=arr.length-subarr.length;
for(int i=0;i<=lim;i++)
{
int[] tmpArr=Arrays.copyOfRange(arr,i,i+subarr.length);
if(Arrays.equals(tmpArr,subarr))
return i; //returns starting index of sub array
}
return -1;//return -1 on finding no sub-array
}
UPDATE:
By reusing the same int array instance:
int findSubArr(int[] arr,int[] subarr)
{
int lim=arr.length-subarr.length;
int[] tmpArr=new int[subarr.length];
for(int i=0;i<=lim;i++)
{
System.arraycopy(arr,i,tmpArr,0,subarr.length);
if(Arrays.equals(tmpArr,subarr))
return i; //returns starting index of sub array
}
return -1;//return -1 on finding no sub-array
}
I would suggest the following improvements:
make the function static so that you can avoid creating an instance
the outer loop condition could be i <= largeArray.length-subArray.length, to avoid a test inside the loop
remove the test (largeArray[i] == subArray[0]) that is redundant
Here's #indexOf from String:
/**
* Code shared by String and StringBuffer to do searches. The
* source is the character array being searched, and the target
* is the string being searched for.
*
* #param source the characters being searched.
* #param sourceOffset offset of the source string.
* #param sourceCount count of the source string.
* #param target the characters being searched for.
* #param targetOffset offset of the target string.
* #param targetCount count of the target string.
* #param fromIndex the index to begin searching from.
*/
static int indexOf(char[] source, int sourceOffset, int sourceCount,
char[] target, int targetOffset, int targetCount,
int fromIndex) {
if (fromIndex >= sourceCount) {
return (targetCount == 0 ? sourceCount : -1);
}
if (fromIndex < 0) {
fromIndex = 0;
}
if (targetCount == 0) {
return fromIndex;
}
char first = target[targetOffset];
int max = sourceOffset + (sourceCount - targetCount);
for (int i = sourceOffset + fromIndex; i <= max; i++) {
/* Look for first character. */
if (source[i] != first) {
while (++i <= max && source[i] != first);
}
/* Found first character, now look at the rest of v2 */
if (i <= max) {
int j = i + 1;
int end = j + targetCount - 1;
for (int k = targetOffset + 1; j < end && source[j]
== target[k]; j++, k++);
if (j == end) {
/* Found whole string. */
return i - sourceOffset;
}
}
}
return -1;
}
First to your possible reasons:
Yes. And the class final with a private constructor.
Shouldn't use this kind of comments at all. The code should be self-explanatory.
You're basically implicitly checking for null by accessing the length field which will throw a NullPointerException. Only in the case of a largeArray.length == 0 and a subArray == null will this slip through.
More potential reasons:
The class doesn't contain any function for array manipulations, opposed to what the documentation says.
The documentation for the method is very sparse. It should state when and which exceptions are thrown (e.g. NullPointerException) and which return value to expect if the second array isn't found or if it is empty.
The code is more complex than needed.
Why is the equality of the first elements so important that it gets its own check?
In the first loop, it is assumed that the second array will be found, which is unintentional.
Unneeded variable and jump (boolean and break), further reducing legibility.
largeArray.length <= i+j is not easy to grasp. Should be checked before the loop, improving the performance along the way.
I'd swap the operands of subArray[j] != largeArray[i+j]. Seems more natural to me.
All in all too long.
The test code is lacking more edge cases (null arrays, first array empty, both arrays empty, first array contained in second array, second array contained multiple times etc.).
Why is the last test case named testFindArrayExistsVeryComplex?
What the exercise is missing is a specification of the component type of the array parameters, respectively the signature of the method. It makes a huge difference whether the component type is a primitive type or a reference type. The solution of adietrich assumes a reference type (thus could be generified as further improvement), mine assumes a primitive type (int).
So here's my shot, concentrating on the code / disregarding documentation and tests:
public final class ArrayUtils {
// main method
public static int indexOf(int[] haystack, int[] needle) {
return indexOf(haystack, needle, 0);
}
// helper methods
private static int indexOf(int[] haystack, int[] needle, int fromIndex) {
for (int i = fromIndex; i < haystack.length - needle.length; i++) {
if (containsAt(haystack, needle, i)) {
return i;
}
}
return -1;
}
private static boolean containsAt(int[] haystack, int[] needle, int offset) {
for (int i = 0; i < needle.length; i++) {
if (haystack[i + offset] != needle[i]) {
return false;
}
}
return true;
}
// prevent initialization
private ArrayUtils() {}
}
byte[] arr1 = {1, 2, 3, 4, 5, 6, 7, 7, 8, 9, 1, 3, 4, 56, 6, 7};
byte[] arr2 = {9, 1, 3};
boolean i = IsContainsSubArray(arr1, arr2);
public static boolean IsContainsSubArray(byte[] Large_Array, byte[] Sub_Array){
try {
int Large_Array_size, Sub_Array_size, k = 0;
Large_Array_size = Large_Array.length;
Sub_Array_size = Sub_Array.length;
if (Sub_Array_size > Large_Array_size) {
return false;
}
for (int i = 0; i < Large_Array_size; i++) {
if (Large_Array[i] == Sub_Array[k]) {
k++;
} else {
k = 0;
}
if (k == Sub_Array_size) {
return true;
}
}
} catch (Exception e) {
}
return false;
}
Code from Guava:
import javax.annotation.Nullable;
/**
* Ensures that an object reference passed as a parameter to the calling method is not null.
*
* #param reference an object reference
* #param errorMessage the exception message to use if the check fails; will be converted to a
* string using {#link String#valueOf(Object)}
* #return the non-null reference that was validated
* #throws NullPointerException if {#code reference} is null
*/
public static <T> T checkNotNull(T reference, #Nullable Object errorMessage) {
if (reference == null) {
throw new NullPointerException(String.valueOf(errorMessage));
}
return reference;
}
/**
* Returns the start position of the first occurrence of the specified {#code
* target} within {#code array}, or {#code -1} if there is no such occurrence.
*
* <p>More formally, returns the lowest index {#code i} such that {#code
* java.util.Arrays.copyOfRange(array, i, i + target.length)} contains exactly
* the same elements as {#code target}.
*
* #param array the array to search for the sequence {#code target}
* #param target the array to search for as a sub-sequence of {#code array}
*/
public static int indexOf(int[] array, int[] target) {
checkNotNull(array, "array");
checkNotNull(target, "target");
if (target.length == 0) {
return 0;
}
outer:
for (int i = 0; i < array.length - target.length + 1; i++) {
for (int j = 0; j < target.length; j++) {
if (array[i + j] != target[j]) {
continue outer;
}
}
return i;
}
return -1;
}
I would to do it in three ways:
Using no imports i.e. using plain Java statements.
Using JAVA core APIs - to some extent or to much extent.
Using string pattern search algorithms like KMP etc. (Probably the most optimized one.)
1,2 and 3 are all shown above in the answers. Here is approach 2 from my side:
public static void findArray(int[] array, int[] subArray) {
if (subArray.length > array.length) {
return;
}
if (array == null || subArray == null) {
return;
}
if (array.length == 0 || subArray.length == 0) {
return;
}
//Solution 1
List<Integer> master = Arrays.stream(array).boxed().collect(Collectors.toList());
List<Integer> pattern = IntStream.of(subArray).boxed().collect(Collectors.toList());
System.out.println(Collections.indexOfSubList(master, pattern));
//Solution2
for (int i = 0; i <= array.length - subArray.length; i++) {
String s = Arrays.toString(Arrays.copyOfRange(array, i, i + subArray.length));
if (s.equals(Arrays.toString(subArray))) {
System.out.println("Found at:" + i);
return;
}
}
System.out.println("Not found.");
}
Using java 8 and lambda expressions:
String[] smallArray = {"1","2","3"};
final String[] bigArray = {"0","1","2","3","4"};
boolean result = Arrays.stream(smallArray).allMatch(s -> Arrays.stream(bigArray).anyMatch(b -> b.equals(s)));
PS: is important to have finalString[] bigArray for enclosing space of lambda expression.
FYI: if the goal is simply to search wether an array y is a subset of an array x, we can use this:
val x = Array(1,2,3,4,5)
val y = Array(3,4,5)
val z = Array(3,4,8)
x.containsSlice(y) // true
x.containsSlice(z) // false

Categories