1

I'm trying to:

  1. create string array with N size
  2. ask the user to fill it with names
  3. delete duplicates and replace it with null
  4. print out array with same order

A solution is in outermost loop to take the word at index i out into a separate String variable so that you have got it for comparing with every other word also after you have set the array entry at index i to null. – Ole V.V.

Question is: Is it possible to solve this in better and more optimized way?

import java.util.Scanner;
import java.util.Arrays;

public class DeleteEquals {
    public static String[] strings;
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int arrSize = 10;
        strings = new String[arrSize];

        for (int i = 0; i < arrSize; i++) {
            strings[i] = sc.nextLine();
        }

        // is it possible to make it better way?
        for (int i = 0; i < arrSize; i++) {
            String check = strings[i];
            for (int j = i + 1; j < arrSize; j++) {
                if (check == null) {
                    break;
                }
                if (check.equals(strings[j])) {
                    strings[i] = null;
                    strings[j] = null;
                }
            }
        }
        Arrays.stream(strings).forEach(System.out::println);
    }
}
5
  • Yes, there is a way. Commented May 9, 2021 at 11:36
  • Should I share it with you ? Commented May 9, 2021 at 11:52
  • 1
    To check if a value already occurred one usually uses a Set: looking up an element both in the TreeSet and HashSet implementation takes O(log n). Commented May 9, 2021 at 12:07
  • Please check answer I have shared it to you Commented May 9, 2021 at 13:42
  • 1
    Just went back to stackoverflow and realized that I have so much usefull answers for my question. And I'm trying to understand all your suggestions for this problem. Thank you guys for your help. Because I'm dummy in programming and taking only first month of JavaRush course. Thanks a lot.) Commented May 9, 2021 at 16:33

5 Answers 5

1

Just rewriting the Uzair Code. Brother You did a amazing Job. Just distinct will work too

 Scanner sc = new Scanner(System.in);
       List<String> strings = new ArrayList<>() ;
       List<String> result = new ArrayList<>();
       int arraySize = 4;
        for (int i = 0; i <arraySize ; i++) {
            strings.add(sc.nextLine());
        }
    result = strings.stream().distinct();
Sign up to request clarification or add additional context in comments.

2 Comments

Thank you Sir. Yeah I know how different way. we can do it. Still thanks to you
You can omit distinct entirely if you used a set instead of a list. You can convert it to a list afterward.
1

This solution is equivalent to my previous answer, which only uses Arrays. It hides complexity of the previous answer behind implementation of java LinkedHashSet:

import java.util.Scanner;
import java.util.Arrays;
import java.util.LinkedHashSet

public class DeleteEquals {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int arrSize = 10;
        Set<String> result = new LinkedHashSet<>()

        for (int i = 0; i < arrSize; i++) {
            String check = sc.nextLine();
            if (check != null) {
              result.add(sc.nextLine());
            }
        }
        result.forEach(System.out::println);
    }
}

As mentioned in the comments, the duplicates will be removed, and it takes O(n * log n) time, due to implementation of HashSet. By using LinkedHashSet, you save the sequential ordering of the values, provided by the user.

If you need more lower-level solution, which only requires Arrays (+ one temporary map), then see my previous answer

Comments

1

You can do:

Scanner sc = new Scanner(System.in);
int n = 3;

Set<String> distinctStrings = IntStream.range(0, n)
        .mapToObj(i -> sc.nextLine())
        .collect(Collectors.toSet());

System.out.println(distinctStrings);

Input:

Westbrook
Jordan
Westbrook

Output:

[Jordan, Westbrook]

Comments

0

It will get distinct values in given strings of Input. Filter out the duplicated strings.

      Scanner sc = new Scanner(System.in);
   List<String> strings = new ArrayList<>() ;
   List<String> result = new ArrayList<>();
   int arraySize = 4;
    for (int i = 0; i <arraySize ; i++) {
        strings.add(sc.nextLine());
    }
 result =  strings.stream()
.filter(e -> Collections.frequency(strings, e) >= 1)
.distinct()
.collect(Collectors.toList());
 System.out.print("After Removing Duplicated Value:\n ");
 result.stream().forEach(System.out::println);

OUTPUT

Output

5 Comments

This code will throw ConcurrentModificationException, because you use Collections.frequency(strings, e), which is another iterator inside iterator of the same "strings" collection.
It also does not use an array, which the question asks for. Whether that matters is for the OP to say.
@mykhailoskliar you can separate them. It's not difficult. I did my job to give you hint how it can be possible. But I will update it in question
@Uzair you may not need to use filter if you are using distinct. Using only distinct would return unique values
@Uzair If you remove unnecessary and confusing Collections.frequency and add not-null filter, then this solution is equivalent to using LinkedHashSet. The only difference is that "distinct" will be applied to completely filled List, but "distinct" will also create the same LinkedHashSet. If the list has 1 milliard elements, then the list and the set together will have 2 milliard elements. Adding each line directly to the LinkedHashSet is twice faster and twice less memory.
0

This solution only uses Arrays:

import java.util.Scanner;
import java.util.Arrays;

public class DeleteEquals {
    public static void main(String[] args) {
        Scanner sc = new Scanner(System.in);
        int arrSize = 10;
        String[] sortedResult = new String[arrSize];
        String[] result = new String[arrSize];
        Map<String, Integer> originalIndexMap = new HashMap<>();

        for (int i = 0; i < arrSize; i++) {
            String currentResult = sc.nextLine();
            sortedResult[i] = currentResult;
            if (originalIndexMap.get(currentResult) == null) {
              //store the index of the first appearance of currentResult
              originalIndexMap.put(currentResult, i);
            }
        }

        //sorting array with "quicksort" to reduce the time to find the duplicates (time will be O(n * log n) with quicksort)
        Arrays.sort(sortedResult);
        String previousResult = null;
        for (int i = 0; i < arrSize; i++) {
          String currentResult = sortedResult[i];
          if (currentResult != null && currentResult != previousResult) {
            //currentResult is unique because of the sorting
            previousResult = currentResult;
            //originalIndexMap stores the index of the first appearance of the currentResult string. We should store currentResult by the index of the first appearance to preserve user input order
            result[originalIndexMap.get(currentResult)] = currentResult;
          } else {
             //duplicate or null: ignore it
          }
        }

        for (int i = 0; i < arrSize; i++) {
          //with originalIndexMap we preserve the order of the user input in the result array
          String currentResult = result[i];
          if (currentResult != null) {
            System.out.println(currentResult);
          } else {
            //null value corresponds to null or duplicate value in the original result: should be ignored
          }            
        }
    }
}

This solution will have O(n * log n) time function, due to implementation of Arrays.sort() in java.util.Arrays (they use "quicksort" by default).

We have to use 4 iterations:

 1. first iteration will initialise sortedResult and originalIndexMap
 2. second iteration will sort the elements in the sortedResult, using Arrays.sort()
 3. third iteration will remove duplicates and insert unique not-null elements in result array by putting it at the index of the first appearance of the element in the user input
 4. fourth iteration will output result array, ignoring null values, which correspond to null or duplicate elements in the original input

So if the number of elements is n, this algorithm will require:

1. (3 * n) elements in stack memory
2. O(n) time in the first iteration
3. O(n log n) time for sorting array
4. O(n log n) time for storing elements to result array (map search gives us O(log n) for each element here)
5. O(n) for result output

Total time function of this algorithm is O(n) + O(n log n) + O(n log n) + O(n), which is equivalent to O(n log n)

Total memory footprint of this algorithm is equivalent to 3n

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.