I am having trouble with this problem: I am to write a method contains3 that accepts a List of strings as a parameter and returns true if any single string occurs at least 3 times in the list, and false otherwise. I need to use a map.
When there are three instances of a word, it still does not return true; I am having trouble locating where things went wrong.
Here is what I have:
private static boolean contains3(List<String> thing) {
Map<String, Integer> wordCount = new TreeMap<String, Integer>();
for (String s: thing) {
String word = s;
if (wordCount.containsKey(word)) { // seen before.
int count = wordCount.get(word);
wordCount.put(word, count + 1);
} else {
wordCount.put(word, 1); // never seen before.
}
if (wordCount.containsValue(3)) {
return true;
} else {
return false;
}
}
return false;
}
The problem is here:
if (wordCount.containsValue(3)) {
//...
You should get the value using the key, in other words, the word you're counting.
if (wordCount.get(word) >= 3) {
return true;
}
Note that I removed the return false; from this if statement since it will break the method in the first iteration.
As a suggestion, you may use a HashMap instead of TreeMap to enhance the performance of your method since the put and get time in HashMap are O(1) (constant time) while TreeMap's are O(log n).
Try using the following code.
private static boolean contains3(List<String> thing) {
Map<String, Integer> wordCount = new TreeMap<String, Integer>();
thing.add("hi");
thing.add("hi");
thing.add("hi");
thing.add("hia");
thing.add("hi3");
for (String s: thing) {
String word = s;
if (wordCount.containsKey(word)) { // seen before.
int count = wordCount.get(word);
wordCount.put(word, count + 1);
} else {
wordCount.put(word, 1); // never seen before.
}
}
if (wordCount.containsValue(3)) {
return true;
} else {
return false;}
You're running this code as you add each word:
if (wordCount.containsValue(3)) {
return true;
} else {
return false;
The test will fail when the first word is added, and you'll immediately return false. Move that block to the end of the method, in the final line where you currently have return false to only make the check when you've counted all the words.
put
if (wordCount.containsValue(3)) {
return true;
} else {
return false;
}
outside the for loop
It is much more efficient to check if count is >= 3 in the initial if block
if (wordCount.containsKey(word)) { // seen before.
int count = wordCount.get(word) + 1;
if(count >= 3) {
return true;
}
wordCount.put(word, count);
}
and remove the following if else block
if (wordCount.containsValue(3)) {
return true;
} else {
return false;
}
Related
I am trying to solve a coding problem. The problem is following:
Given a sequence of integers as an array, determine whether it is possible to obtain a strictly increasing sequence by removing no more than one element from the array.
For example:
[1,3,2,1] is false
[1,3,2] is true
I implemented it in Java. The code is as follows:
boolean almostIncreasingSequence(int[] sequence) {
int count =0;
for(int i =0; i < sequence.length; i++){
if (sequence[i] <= sequence[i-1]){
count++;
}
if(count>1){
return false;
}
if(sequence[i] <= sequence[i-2] && sequence[i+1] <= sequence[i-1]){
return false;
}
}
return true;
}
This is the following error:
Execution error on test 1: Your program had a runtime error.
Any help will be appreciated. It seems a small problem but I can't resolve it.
One implementation can be based on remove just 1 element when strictly ascending condition is not achieved.
public class TestAlmostIncreasingSequence {
public static boolean almostIncreasingSequence(int[] sequence)
{
if(sequence==null) return false;
//mandatory to remove just 1 element, if no one(or more) removed then false
boolean flag_removed=false;
for(int i=1, prev=sequence[0];i<sequence.length;i++)
{
if(prev>=sequence[i] && flag_removed==false)
{
//mark removed
flag_removed=true;
}
//if element was removed then false
else if(prev>=sequence[i] && flag_removed==true)
{
return false;
}
else
{
//change only if element removed is not the current
//comparisons will not be done with removed element
prev=sequence[i];
}
//System.out.println(prev);
}
//could have a strictly increased arr by default which will return false [1,2,3]
return flag_removed;
}
public static void main(String[] args)
{
//only for printing purpose
String arr="";
int s1[] = {1,2,3,1};
arr=Arrays.stream(s1).mapToObj(t->String.valueOf(t)).
collect(Collectors.joining(",","[","]"));
System.out.println(arr+"\n"+almostIncreasingSequence(s1)+"\n");
int s2[] = {1,2,3};
arr=Arrays.stream(s2).mapToObj(t->String.valueOf(t)).
collect(Collectors.joining(",","[","]"));
System.out.println(arr+"\n"+almostIncreasingSequence(s2)+"\n");
int s3[] = {1,2,3,1,2};
arr=Arrays.stream(s3).mapToObj(t->String.valueOf(t)).
collect(Collectors.joining(",","[","]"));
System.out.println(arr+"\n"+almostIncreasingSequence(s3)+"\n");
int s4[] = {1};
arr=Arrays.stream(s4).mapToObj(t->String.valueOf(t)).
collect(Collectors.joining(",","[","]"));
System.out.println(arr+"\n"+almostIncreasingSequence(s4)+"\n");
int s5[] = {1,1};
arr=Arrays.stream(s5).mapToObj(t->String.valueOf(t)).
collect(Collectors.joining(",","[","]"));
System.out.println(arr+"\n"+almostIncreasingSequence(s5)+"\n");
int s6[] = null;
arr="null";
System.out.println(arr+"\n"+almostIncreasingSequence(s6)+"\n");
}
}
Output
[1,2,3,1]
true
[1,2,3]
false
[1,2,3,1,2]
false
[1]
false
[1,1]
true
null
false
Note: The implementation have a case when the result is wrong [1,5,2,3], just update with one more branch with removed element=the previous one(not the current) and check both branched (one true means true)
This should fix the case
//method name is misguided, removePrev is better
public static boolean removeCurrent(int[] sequence)
{
if(sequence==null) return false;
//mandatory to remove just 1 element, if no one remove then false
boolean flag_removed=false;
for(int i=1, prev=sequence[0];i<sequence.length;i++)
{
if(prev>=sequence[i] && flag_removed==false)
{
//mark removed
flag_removed=true;
}
//if element was removed then false
else if(prev>=sequence[i] && flag_removed==true)
{
return false;
}
//compared element will be the current one
prev=sequence[i];
//System.out.println(prev);
}
//could have a strictly increased arr by default which will return false [1,2,3]
return flag_removed;
}
and use
int s1[] = {1,5,2,3};
arr=Arrays.stream(s1).mapToObj(t->String.valueOf(t)).
collect(Collectors.joining(",","[","]"));
boolean result= (almostIncreasingSequence(s1)==false) ? removeCurrent(s1) : true;
System.out.println(arr+"\n"+result +"\n");
Output
[1,5,2,3]
true (from removeCurrent_branch)
Seems one more case is wrong [5,6,3,4], means need to see if element[i-2](only after remove element) is not greater then current and 'prev' on last branch.
6>3 remove 6 (prev=3, 3<4 but [5>4 or 5>3] so false)
public static boolean removeCurrent(int[] sequence)
{
if(sequence==null) return false;
//mandatory to remove just 1 element, if no one remove then false
boolean flag_removed=false;
for(int i=1, prev=sequence[0], twoprev=Integer.MIN_VALUE;i<sequence.length;i++)
{
if(prev>=sequence[i] && flag_removed==false)
{
//mark removed
flag_removed=true;
if(i>=2) twoprev=sequence[i-2];
}
//if element was removed then false
else if(prev>=sequence[i] && flag_removed==true)
{
return false;
}
else if(twoprev>=sequence[i] || twoprev>=prev)
{
return false;
}
//compared element will be the current one
prev=sequence[i];
//System.out.println(prev);
}
//could have a strictly increased arr by default which will return false [1,2,3]
return flag_removed;
}
Output
[5,6,3,4]
false
Now, as far as I see all cases seems covered.
Brute force can also generate a solution but will be less optimal.(use a loop to remove an element, sort the result and compare with base)
public class TestInc {
public static void main(String[] args)
{
int s1[] = {1,1,2,3};
System.out.println(checkInc(s1));
}
public static boolean checkInc(int[] arr)
{
if(arr==null || arr.length==1) return false;
List<Integer> lst = Arrays.stream(arr).boxed().collect(Collectors.toList());
//remove this check if requirement is other(or return true)
if(checkIfAlreadySortedAsc(lst))
{
return false;
}
for(int i=0;i<lst.size();i++)
{
List<Integer> auxLst = new ArrayList<Integer>(lst);
auxLst.remove(i);
List<Integer> sorted = new ArrayList<Integer>(auxLst);
sorted = sorted.stream().distinct().sorted().collect(Collectors.toList());
if(auxLst.equals(sorted))
{
// System.out.println("=");
return true;
}
else
{
// System.out.println("!=");
}
}
return false;
}
//any ascending sorted list will be the same type if remove one element
//but as requirement on this case will return false
//(or don't use method in want other)
public static boolean checkIfAlreadySortedAsc(List<Integer> lst)
{
List<Integer> auxLst = new ArrayList<Integer>(lst);
auxLst = auxLst.stream().distinct().sorted().collect(Collectors.toList());
if(auxLst.equals(lst))
{
return true;
}
return false;
}
}
Output
[1,1,2,3]
true
This line would produce an ArrayIndexOutOfBoundsException when i == 0 because it will attempt to access sequence[-1]
if (sequence[i] <= sequence[i-1]){
this is a supplementary question aligned to a question I asked recently. I have the following recursive code that will give me the largest number from a List of integers
static int maximum (List<Integer> a)
{
if ((a.getTail().isEmpty()))
return 0;
else {
int n = maximum(a.getTail());
System.out.println(n);
if (a.getHead() > n) {
return (a.getHead());
} else {
return m;
}}
}
This is helpful. But what I really want to do is to be able to return a Boolean value true or false depending on where the list increases in value or decreases. So my method would become:
static boolean maximum (List<Integer> a)
{
if ((a.getTail().isEmpty()))
return true;
else {
int n = maximum(a.getTail());
System.out.println(n);
if (a.getHead() > n) {
return true;
} else {
return false;
}}
}
But this will not run. The challenge I am faced with is that the recursive call as I have written returns an integer so that I can compare the previous maximum with the current maximum ----- if (a.getHead() > m).
What I want to do is to try and complete the assessment of the current verses previous max within the recursive call so that I only have to return a Boolean, true or false.
So for example if as the recursion occurs the list continually increases then the Boolean stays true but if at any point it decreases then it will give a false:
1,2,3,4 = true
1,2,4,3 = false
Thank you for your help I am really struggling with the whole concept of recursion.....
Some things you might have missed:
in a function, a return statement terminates (break) the function immediatly. So in
if(...) { return ...; }
else {...}
→ else is redundant, as if the condition is true, the function is already terminated (break)
Something like a==0 has a boolean value (true or false). So
if(i==0) { return true; }
else { return false; }
can be shortened to return count==0;
I recommend to always use braces, because something like if(i==0) ++i; break;, means if(i==0) {++i;}. break; will be called in any case.
what you want, is something like this:
static boolean is_sorted(List<Integer> list)
{
return is_sorted_from(0, list);
}
static boolean is_sorted_from(int index, List<Integer> list)
{
if(index+1 >= a.size()) { return true };
return list.get(index) < list.get(index+1)
&& is_next_sorted(index+1, list);
}
static boolean maximum (List<Integer> a, boolean cont){
if(cont){
if ((a.getTail().isEmpty())){
cont = false;
}else {
int n = maximum(a.getTail());
System.out.println(n);
if (a.getHead() > n) {
maximum(a.getHead(), cont);
} else {
maximum(n, cont);
}
}
}
return cont;
}
I'd say to make the method void or return the List, but I left it as boolean since that is technically what your question asked for.
You would just call the method with cont having the value of true. By using two parameters, you can continue comparing your max function while simultaneously using a boolean as your recursion flag. You would not be able to return your maximum however, but you could work around this by setting the maximum to either a class instance or to an object that you have as your third parameter (Double, Integer, etc.).
I want to write a code to check the existence of given two values in a List.
List<Tag> tags = new ArrayList<>();
The requirement is to return true only if the List tag contains both "start" and "end" values.
My code is like this, but it doesn't cater to the requirement.
public static boolean checkStartAndEndTimeTag(List<Tag> tags) {
boolean isSuccess = false;
int count = 0;
for (Tag tag : tags) {
if (tag.getKey().equals("start") || tag.getKey().equals("end")) {
count++;
if (count == 2)
break;
isSuccess = true;
}
}
return isSuccess;
Can someone help me with to resolve this issue?
This...
if (count == 2)
break;
isSuccess = true;
doesn't make sense. This will set isSuccess even if there is only one match
The long winded approach
Okay, let's assuming for a second that you only care if there is at least one start and one end (discounting duplicates). One approach would be to use to state flags, one for start and one for end. To keep it simple, they would start of as 0 but would only ever be a maximum of 1 (because we don't want duplicates), then you might be able to do something like...
public static boolean checkStartAndEndTimeTag(List<Tag> tags) {
boolean isSuccess = false;
int starts = 0;
int ends = 0;
for (Tag tag : tags) {
if (tag.getKey().equals("start")) {
starts = 1;
} else if (tag.getKey().equals("end")) {
ends = 1;
}
}
isSuccess = (starts + ends) == 2;
return isSuccess;
}
Ok, you don't need isSuccess = (starts + ends) == 2; and could simply return the result of the comparison. You could also break out of the loop if (starts + ends) == 2 and save yourself from unnecessary computation
for (Tag tag : tags) {
if (tag.getKey().equals("start")) {
starts = 1;
} else if (tag.getKey().equals("end")) {
ends = 1;
}
if ((starts + ends) == 2) {
break;
}
}
Using streams...
One approach might be to make use the streams support and simply filter the List and count the results, for example...
import java.util.ArrayList;
import java.util.List;
public class Test {
public static void main(String[] args) {
new Test();
}
public Test() {
List<Tag> tags = new ArrayList<Tag>(25);
tags.add(new Tag("begin"));
tags.add(new Tag("front"));
tags.add(new Tag("start"));
tags.add(new Tag("finish"));
tags.add(new Tag("tail"));
tags.add(new Tag("end"));
boolean isSuccessful = tags.stream().filter(tag -> tag.getKey().equals("start") || tag.getKey().equals("end")).count() >= 2;
System.out.println(isSuccessful);
}
public class Tag {
private String key;
public Tag(String key) {
this.key = key;
}
public String getKey() {
return key;
}
}
}
Updated...
Okay, this got complicated fast. Let's assume you don't want to match two start tags, so you MUST have both one end and one start tag
So, using the above, example, we can modify the Tag class to support equals (and by extension hashcode)
public class Tag {
private String key;
public Tag(String key) {
this.key = key;
}
public String getKey() {
return key;
}
#Override
public String toString() {
return getKey();
}
#Override
public int hashCode() {
int hash = 7;
hash = 73 * hash + Objects.hashCode(this.key);
return hash;
}
#Override
public boolean equals(Object obj) {
if (this == obj) {
return true;
}
if (obj == null) {
return false;
}
if (getClass() != obj.getClass()) {
return false;
}
final Tag other = (Tag) obj;
if (!Objects.equals(this.key, other.key)) {
return false;
}
return true;
}
}
Then we can simply use distinct to filter out any duplicates, for example...
boolean isSuccessful = tags
.stream()
.distinct()
.filter(tag -> tag.getKey().equals("start") || tag.getKey().equals("end"))
.count() >= 2;
Probably not the most efficient solution, but certainly one of the shortest
In this code
if (tag.getKey().equals("start") || tag.getKey().equals("end")) {
count++;
if (count == 2)
break;
isSuccess = true;
}
you are setting isSuccess to true whenever the tag is start or end.
Better way would be
if (tag.getKey().equals("start") || tag.getKey().equals("end")) {
count++;
if (count == 2)
return true;
}
You could also use
tags.stream()
.map(Tag::getKey)
.distinct()
.filter(t -> "start".equals(t) || "end".equals(t))
.count() == 2;
This would also fix the issue that your original code falsely returns true if the list contains statt or end twice.
What about
tags.containsAll(Arrays.asList(new Tag("start"), new Tag("stop")))
I have below code but when i try to run the check function its giving me stackOverFlow error please help
when i debugged it its going till "return true;", but also entering else.
NOTE :
I have this data in my collection :
{1=[2, 3], 2=[3], 3=[4], 4=[3], 5=[6], 6=[5]}
How can i find the link between two nodes
private Map<Integer, ArrayList<Integer>> graphList = new HashMap<Integer, ArrayList<Integer>>();
private boolean checkLink(ArrayList<Integer> dataListFirst, int match) {
if (dataListFirst != null) {
for (int data : dataListFirst) {
if (data == match) {
return true;
} else {
checkLink(graphList.get(data), match);
}
}
}
return false;
}
You are not using the retun value of your recursive call:
if (data == match) {
return true;
} else {
checkLink(graphList.get(data), match); // <--- Return value unused
}
You can modify your code to check if the recursive calls find your element:
private boolean checkLink(ArrayList<Integer> dataListFirst, int match) {
if (dataListFirst != null) {
for (int data : dataListFirst) {
if (data == match || checkLink(graphList.get(data), match)) {
return true;
}
}
}
return false;
}
This code still could has a problem if your graph has cycles, you could return false in your function when you are trying to check the same value again.
// Just call the recursive function with an empty list of elements
private boolean checkLink(ArrayList<Integer> dataListFirst, int match) {
return checkLink(dataListFirst, match, new ArrayList<Integer>());
}
private boolean checkLink(ArrayList<Integer> dataListFirst, int match, List<Integer> nodes) {
if (dataListFirst != null) {
for (int data : dataListFirst) {
if (nodes.contains(data)) {
return false;
}
nodes.add(data);
if (data == match || checkLink(graphList.get(data), match, nodes)) {
return true;
}
}
}
return false;
}
It seems to me you only want to make a recursive call after checking all the elements of the current ArrayList. And you should use the value returned by the recursive call (that's the reason your recursion didn't end after return true;) :
private boolean checkLink(ArrayList<Integer> dataListFirst, int match)
{
if (dataListFirst != null) {
for (int data : dataListFirst) {
if (data == match) {
return true;
}
}
for (int data : dataListFirst) {
boolean found = checkLink(graphList.get(data), match);
if (found)
return found;
}
}
return false;
}
I'm not sure this will work in all cases, though, since if there are cycles in the graph you may get into an infinite recursion without ever finding the desired node.
EDIT: With your help I managed to fix my problem. I have edited my code to now show how I had to have it set up to get it working.
Currently I am having trouble coding a part which compares the content of two iterators. As part of the requirements for my assignment, I need to use a linkedlist to store the individual characters of the entered String. I have gotten to the point where I have two iterators which would contain the input one way and the reverse way.
String palindrom = input.getText();
String [] chara = palindrom.split (""); //this is successfully splitting them, tested.
int length = palindrom.length( ); // length == 8
System.out.println (length); //can use this for how many checks to do?
LinkedList ll = new LinkedList(Arrays.asList(chara));
Iterator iterator = ll.iterator();
Iterator desIterator = ll.descendingIterator();
/*while(iterator.hasNext() ){
System.out.println(iterator.next() );
}
while(desIterator.hasNext() ){
System.out.println(desIterator.next() );
}*/
boolean same = true;
while(iterator.hasNext()){
if(!iterator.next().equals(desIterator.next())){
same = false;
break;
}
}
And using the System.out I can see that they are being stored correctly, but I don't know how to check if the iterators store the same contents. What would be one of the simplest methods to compare the two iterators or convert them into something I can compare? To clarify I want to verify they contain the same elements in the same order.
boolean same = true;
while(iterator.hasNext()){
if(!desIterator.hasNext() || !iterator.next().equals(desIterator.next())){
same = false;
break;
}
}
System.out.println(same);
You need to iterate over both iterators simultaneously, i.e. with one loop. Here is a general comparison function (0 when equal, < 0 when A < B, > 0 when A > B):
static <T extends Comparable<S>, S> int compare(Iterator<T> a, Iterator<S> b) {
while (a.hasNext() && b.hasNext()) {
int comparison = a.next().compareTo(b.next());
if (comparison != 0) {
return comparison;
}
}
if (a.hasNext())
return 1;
if (b.hasNext())
return -1;
return 0;
}
To just check if they are equal, this can be simplified:
static <T, S> boolean equals(Iterator<T> a, Iterator<S> b) {
while (a.hasNext() && b.hasNext()) {
if (!a.next().equals(b.next())) {
return false;
}
}
if (a.hasNext() || b.hasNext()) {
// one of the iterators has more elements than the other
return false;
}
return true;
}
Guava implements this as Iterators.elementsEqual.
In both answers throw NullPointerException, if iterator.next() == null. This method is more optimal.
public static boolean equals(Iterator i1, Iterator i2) {
if (i1 == i2) {
return true;
}
while (i1.hasNext()) {
if (!i2.hasNext()) {
return false;
}
if (!Objects.equals(i1.next(), i2.next())) {
return false;
}
}
if (i2.hasNext()) {
return false;
}
return true;
}