Longest Sequence in array with matching last and first character - java

I recently was asked a question to create a sequence from an array of string such that the string elements can combine if the last character of element 1 matches the first character of element 2.
Eg: {"ab", "bc", "cd", "ad", "def", "cedd"} should return "abceddef".
What I'm getting for above input is "abcdef".
public class LongestSubstringConsecutiveEnds {
static StringBuilder sbMax = new StringBuilder();
static StringBuilder sbTemp;
public static void main(String[] args) {
String[] inputStrings = {"ab", "bc", "cd", "ad", "def", "cedd"};
List<String> inputList = new ArrayList<String>(Arrays.asList(inputStrings));
for(int i=0; i<inputList.size(); i++) {
String str = inputList.get(i);
sbTemp = new StringBuilder(str);
inputList.remove(str);
longestSequence(sbTemp, new ArrayList<String>(inputList));
inputList.add(0, str);
}
System.out.println(sbMax.toString());
}
private static void longestSequence(StringBuilder tempSubstring, final List<String> inputList) {
System.out.println(tempSubstring.toString() + inputList);
if(tempSubstring.length() > sbMax.length()) {
sbMax.delete(0, sbMax.length());
sbMax.append(tempSubstring);
}
for(int i=0; i<inputList.size(); i++) {
String inputListString = inputList.get(i);
char tempStrLastChar = tempSubstring.charAt(tempSubstring.length()-1);
if(inputListString.charAt(0) == tempStrLastChar) {
String str = inputList.remove(i);
longestSequence(tempSubstring.append(inputListString.substring(1)), inputList);
inputList.add(i, str);
}
}
}
}

According your question:
if the last character of element 1 matches the first character of element 2.
Part you described in your question can be done easy:
for (int i = 0; i < strings.length - 1; i++) {
// last char of element i is equal first char of element i+1
if (strings[i].charAt(strings[i].length()-1) == strings[i+1].charAt(0)) {
// print element i.
System.out.print(strings[i]);
}
}
Output:
cd
That is, position 3 matches with 4 (cd-def)
But that does not match with
should return "abceddef"
And I can't find a logic... where last ef comes from? you mean match when for example last is a and first is b ??. That would be:
for (int i = 0; i < strings.length - 1; i++) {
// get last and first char
String actual = strings[i];
char last = actual.charAt(actual.length()-1);
char first = strings[i+1].charAt(0);
if ((int) first == last + 1) {
System.out.print(actual);
}
}
Output:
ab
That is, position 2 matches with 3 (ab-cd)

public static void main(String...args){
final String[] input={"ab", "bc", "cd", "ad", "def", "cedd"};
System.out.println( funkyConcat(input));
}
private static String funkyConcat(String...strings){
String ret="";
for(String i:strings){
if(ret.isEmpty()){
ret=i;
}else if(ret.substring(ret.length()-1).equals(i.substring(0,1))){
ret+=i.substring(1);
}
}
return ret;
}

Related

Encoding a String Array

EDIT : [Schoolwork Assignment]
So, I want to encode, with only 0 and 1, words.
0 = word not present
1 = word present
My dictionary correspond to :
String[] dictionary = {"Hello", "I", "am", "Lukas", "and", "Jonas", "play", "football"};
For example : If I encode these words...
String[] listOfWords = {"Hello", "play" "football"};
I must have the following array :
int[] wordsEncode = {1,0,0,0,0,0,1,1};
You can see that "Hello" is present, "I" "am" "Lukas" "and" "Jonas" are not present. Finally, "play" and "football" are present.
We must preserve the order of dictionary and that is my problem in my code.
I don't really know how to fix that problem (using a second for loop ?) ?
I think wordEncode[i] is my error, but how to fix that ?
Here is my code :
class Dictionary {
/**
* Array words Dictionary
*/
String[] dictionary;
/**
* Maximum of words MAX_WORDS
*/
final int MAX_WORDS = 50;
/**
* Number of words in the dictionary
*/
int numberWordsDictionary;
/**
* Constructor
*/
Dictionary() {
dictionary = new String[MAX_WORDS];
numberWordsDictionary = 0;
}
int[] encoder(String[] listOfWords) {
int[] wordsEncode = new int[numberWordsDictionary];
StringBuilder builder = new StringBuilder();
for(String word : dictionary) {
builder.append(word);
}
String dictionaryString = builder.toString();
for(int i = 0; i < listOfWords.length; i++) {
if(dictionaryString.contains(listOfWords[i])) {
wordsEncode[i] = 1;
} else {
wordsEncode[i] = 0;
}
}
return wordsEncode;
}
}
Sorry about indentation (not same as my Java IDE) :(
Thanks !
Using two-level nested loops, you should check each element of dictionary[] whether it is there in listOfWords[] and if yes, update the value at the corresponding index in wordsEncode[] to 1.
import java.util.Arrays;
public class Main {
public static void main(String[] args) {
String[] dictionary = { "Hello", "I", "am", "Lukas", "and", "Jonas", "play", "football" };
String[] listOfWords = { "Hello", "play", "football" };
int[] wordsEncode = new int[dictionary.length];
for (int i = 0; i < dictionary.length; i++) {
boolean found = false;
for (String s : listOfWords) {
if (s.equals(dictionary[i])) {
found = true;
break;
}
}
if (found) {
wordsEncode[i] = 1;
}
}
// Display the result
System.out.println(Arrays.toString(wordsEncode));
}
}
Output:
[1, 0, 0, 0, 0, 0, 1, 1]
Loop your input words. For each input word, see if your list of target words contains that particular word. If so, add a 1 to your results list. If not, add zero.
I use the more convenient Collections, but you could do the same approach with arrays.
List< String > input = List.of( "Hello", "I", "am", "Lukas", "and", "Jonas", "play", "football" ) ;
List< String > targets = List.of( "Hello", "play" "football" ) ;
List< Integers > hits = new ArrayList<>() ;
for( String s : input )
{
int i = targets.contains( s ) ? 1 : 0 ;
hits.add( i ) ;
}
What you did here is iterate through dictionary array and added the words to a StringBuilder to check if a certain word you got in the listOfWords array is in the StringBuilder. But there a better solution to this you can just make a nested loop that compares every element of listOfWords array and dictionary array and if it found a match it sets the encode array value at the index of the second loop to 1:
int[] encoder(String[] listOfWords) {
int[] wordsEncode = new int[numberWordsDictionary];
for (int i = 0; i < listOfWords.length; i++) {
for (int j = 0; j < numberWordsDictionary; j++) {
if (listOfWords[i].equals(dictionary[j])) {
wordsEncode[j] = 1;
break;
}
}
}
return wordsEncode;
}
/* This approach is wrong, the combined string could catch words that are
part of the ending of one word and part of the beginning of another but
not actually a word in the dictionary. For instance, if you had
"arch" and "attach" in your dictionary, testing for "chat" would return true
*/
/*
StringBuilder builder = new StringBuilder();
for(String word : dictionary) {
builder.append(word);
}
String dictionaryString = builder.toString();
*/
for(int i = 0; i < listOfWords.length; i++) {
boolean found = false;
for (int j = 0; j < dictionary.length; j++) {
if (dictionary[j].equalslistOfWords[i]) {
found = true;
}
}
if (found) {
wordsEncode[i] = 1;
} else {
wordsEncode[i] = 0;
}
// you can also do wordsEncode[i] = found ? 1 : 0;
}
return wordsEncode;
}

Replace Strings with specific list of words

Replace a given string at given index with list of words.
The problem statement goes below, can someone give me some intuition or idea how to proceed on this?
//A replacement class similar to Linked List
class Replacement {
int start;
String before;
String after;
//Method to replace the words
public static String replaceRanges(String text, List<Replacement> replacements) {
//TODO your code here
return null;
}
}
/* below is the example of the problem
Example #1:
Input:
text = "num foo"
replacements = [
{start: 0, before: "num", after: "String"},
{start: 4, before: "foo", after: "bar"}
]
Output:
replaceRanges(text, replacements) returns:
"String bar"
Example #2: Input: text = "num_fooBar", Output: "String_barBar"
*/
If you have your replacements sorted from smallest index to highest, you can iterate the list from last to first and search for substrings in input string and replace them if they match
public static String replaceRanges(String text, List<Replacement> replacements) {
StringBuilder s = new StringBuilder(text);
for (int i = replacements.size() - 1; i>=0; i--) {
Replacement r = replacements.get(i);
int begin = r.start;
int end = r.start + r.before.length();
if (begin >= 0 && begin < s.length() && end >= 0 && end <= s.length()) {
if (s.substring(begin, end).equals(r.before)) {
s.replace(begin, end, r.after);
}
}
}
return s.toString();
}
If your list is not sorted, you need to sort it first using Collections.sort().
I used this code for testing:
public static void main(String[] args) {
List<Replacement> replacements = List.of(
new Replacement(0, "num", "String"),
new Replacement(4, "foo", "bar"));
System.out.println(replaceRanges("num foo", replacements)); // Output: String bar
System.out.println(replaceRanges("num_fooBar", replacements)); // Output: String_barBar
System.out.println(replaceRanges("num_f", replacements)); // Output: String_f
System.out.println(replaceRanges("", replacements)); // Output:
System.out.println(replaceRanges("foonum", replacements)); // Output: foonum
}
You could replace your original string one by one and keep in mind that you have to shift the start position (because you could replace the small substring to the bigger substring)
public String replaceRanges(String text, List<Replacement> replacements) {
for(int i = 0; i < replacements.size(); i++) {
Replacement replacement = replacements.get(i);
String firstPart = text.substring(0, replacement.start);
String secondPart = text.substring(replacement.start, text.length());
String updatedSecondPart = secondPart.replace(replacement.before, replacement.after);
text = firstPart + updatedSecondPart;
updateStart(i + 1, replacements, updatedSecondPart.length() - secondPart.length());
}
return text;
}
privat void updateStart(int startIndex, List<Replacement> replacements, int shift) {
for( int i = startIndex; i < replacements.size(); i++) {
Replacement r = replacements.get(i);
r.start += shift;
}
}
Using this method you can process:
Replacement r1 = new Replacement(0, "hi", "Hello");
Replacement r2 = new Replacement(2, "lo", "p");
Sting result = replaceRanges("hi louie!", asList(r1, r2)); //result = 'Hello puie!'

LeetCode 14. longest common prefix

Question:
Write a function to find the longest common prefix string among an array of strings. If there is no common prefix, return an empty string "".
Example 1:
Input: ["flower","flow","flight"]
Output: "fl"
Example 2:
Input: ["dog","racecar","car"]
Output: ""
Explanation: There is no common prefix among the input strings.
Code:
public class Solution {
public String longestCommonPrefix(String[] strs) {
if(strs==null || strs.length==0)
return "";
for(int i=0;i<strs[0].length();i++) {
char x = strs[0].charAt(i);
for(int j=0;j<strs.length;j++) {
if((strs[j].length()==i)||(strs[j].charAt(i)!=x)) {
return strs[0].substring(0,i);
}
}
}
return strs[0];
}
}
This is the second solution, but I don't understand the inner loop.
I think if the second element in strs returns a string and ends the for loop, the third element will not have a chance to be compared.
You have to check same position in all of the words and just compare it.
positions
word 0 1 2 3 4 5
=====================
w[0] F L O W E R
w[1] F L O W
w[2] F L I G H T
In Java:
class Main {
public static void main(String[] args) {
String[] words = {"dog","racecar","car"};
String prefix = commonPrefix(words);
System.out.println(prefix);
// return empty string
String[] words2 = {"dog","racecar","car"};
String prefix2 = commonPrefix(words2);
System.out.println(prefix2);
// Return "fl" (2 letters)
}
private static String commonPrefix(String[] words) {
// Common letter counter
int counter = 0;
external:
for (int i = 0; i < words[0].length(); i++) {
// Get letter from first word
char letter = words[0].charAt(i);
// Check rest of the words on that same positions
for (int j = 1; j < words.length; j++) {
// Break when word is shorter or letter is different
if (words[j].length() <= i || letter != words[j].charAt(i)) {
break external;
}
}
// Increase counter, because all of words
// has the same letter (e.g. "E") on the same position (e.g. position "5")
counter++;
}
// Return proper substring
return words[0].substring(0, counter);
}
}
Your first loop is itterating over all chars in the first string of array. Second loop is checking char at i posistion of all strings of array. If characters do not match, or length of string is the same as i it returns substring result.
I think the best way to understand is debug this example.
If the char in the second string is different than the char in the first one, then it is correct to return, since it means that the common prefix ends there. Checking the third and following strings is not necessary.
Basically it returns as soon as it finds a mismatch char.
If we first sort them then it would be very easy we have to only go and compare the first and the last element in the vector present there so,
the code would be like,This is C++ code for the implementation.
class Solution {
public:
string longestCommonPrefix(vector<string>& str) {
int n = str.size();
if(n==0) return "";
string ans = "";
sort(begin(str), end(str));
string a = str[0];
string b = str[n-1];
for(int i=0; i<a.size(); i++){
if(a[i]==b[i]){
ans = ans + a[i];
}
else{
break;
}
}
return ans;
}
};
public class Solution {
public string LongestCommonPrefix(string[] strs) {
if(strs.Length == 0)
{
return string.Empty;
}
var prefix = strs[0];
for(int i=1; i<strs.Length; i++) //always start from 1.index
{
while(!strs[i].StartsWith(prefix))
{
prefix = prefix.Substring(0, prefix.Length-1);
}
}
return prefix;
}
}

How to check if an array contains a specific number of values?

import java.util.Scanner;
public class CountVowel{
public static void main(String[] args){
Scanner scan = new Scanner(System.in);
Getting the size of the array:
System.out.println("Type how many words will be typed: ");
int input = scan.nextInt();
Filling array with string values
String[] ar1 = new String[input];
for(int i = 0; i < ar1.length; i++){
System.out.println("Type the elements of array with words: ");
ar1[i] = scan.next();
}
Output of the program :
System.out.println( input + " words are typed and " +
countVowels(ar1) +
" of them contain more than 3 vowels.");
}
The method that counts vowels:
public static int countVowels(String[] ar1){ // this method counts
int a = 0;
String[] ar2 = new String[]{"a", "e", "i", "u", "y", "o"};
for(int i = 0; i < ar1.length; i++){
for(String s : ar2){
if(ar1[i].toLowerCase().contains(s)){
a++;
}
}
}
return a;
}
}
The method above is to check the vowels, but i dont know how to make it check if
there are more than 3 vowels.
Another solution with replaceAll method.
The main idea is to substract from word.length() the same word length without vowels. And check the difference.
public static int countVowels(String[] ar1){
int a = 0;
for (String word : ar1) {
int i = word.length() - word.toLowerCase().replaceAll("[aeyiuo]", "").length();
if (i >= 3) {
a++;
}
}
return a;
}
Or you can use matches() as #pkgajulapalli suggested. It can be quite concise with stream api:
long count = Arrays.stream(words)
.filter(s -> s.toLowerCase().matches("(.*[aeyiuo].*){3,}"))
.count();
public static int countVowels(String[] ar1) { // this method counts
int vowelPerWord = 0;
int totalWordsWithThreeVowels = 0;
char[] ar2 = new char[] { 'a', 'e', 'i', 'u', 'y', 'o' };
for (int i = 0; i < ar1.length; i++) {
vowelPerWord = 0;
for (int j = 0; j < ar1[i].length(); j++) {
for (int k = 0; k < ar2.length; k++) {
if (ar2[k] == (ar1[i].charAt(j))) {
vowelPerWord++;
}
}
}
if (vowelPerWord >= 3) {
totalWordsWithThreeVowels++;
}
}
return totalWordsWithThreeVowels;
}
EDIT
alright now i fixed the error and edited the variablenames to make a bit more sense. although this is O(n*m) i believe (where n is the number of strings and m is the number of char the longest string has) (not so good complexity) it gets the job done ar1 in this case is your input of strings, ar2 are just the vowels that exist.
so you go through every string in ar1 and set "vowelPerWord" to 0, go through every single char in every string and check if it is a vowel increase the vowelPerWord by 1. at the end, after you went through every char of that string you check if there were 3 or more vowels, if so increase the totalWordsWithThreeVowels, which at the end is returned.
What you need is an additional loop and count. Something like this:
// This method counts how many words have at least 3 vowels
public static int countVowels(String[] wordsArray){
int atLeastThreeVowelsCount = 0;
for(String word : wordsArray){
int vowelCount = 0;
for(String vowel : new String[]{ "a", "e", "i", "u", "y", "o" }){
if(word.toLowerCase().contains(vowel)){
vowelCount++;
}
}
if(vowelCount >= 3){
atLeastThreeVowelsCount++;
}
}
return atLeastThreeVowelsCount;
}
Try it online.
Note that I've also given the variables some more useful names, instead of ar1, s, etc. so it's easier to read what's going on.
You can use regex matching to find if a string contains any set of characters. For example, if you want to find if a string contains any of vowels, you can use:
String str = "yydyrf";
boolean contains = str.toLowerCase().matches(".*[aeiou].*");
System.out.println(contains);
EDIT:
So your code would look like:
public static int countVowels(String[] ar1) {
int a = 0;
String[] ar2 = new String[] { "a", "e", "i", "u", "y", "o" };
String pattern = ".*[" + String.join("", ar2) + "].*";
for (int i = 0; i < ar1.length; i++) {
if (ar1[i].matches(pattern)) {
a++;
}
}
return a;
}
You can use this:
public static int countVowels(String[] words) {
char[] chars = {'a', 'e', 'i', 'u', 'y', 'o'};
int wordsWith3Vowels = 0;
for (String word : words) {
int countedVowels = 0;
for (char s : chars) {
if (word.toLowerCase().indexOf(s) != -1) {
countedVowels++;
}
}
if (countedVowels >= 3) {
wordsWith3Vowels++;
}
}
return wordsWith3Vowels;
}
Which uses chars instead of Strings which is a tad faster
public static int countVowels(String[] ar1){ // this method counts
//Create hash map key = array string && value = vowels count
Map<String,Integer> mapVowels=new HashMap<String,Integer>();
int a = 0;
String[] ar2 = new String[]{"a", "e", "i", "u", "y", "o"};
for(int i = 0; i < ar1.length; i++){
for(String s : ar2){
if(ar1[i].toLowerCase().contains(s)){
//Check map string already has vowel count then increase by one
if(mapVowels.get(s)!=null) {
mapVowels.put(s,mapVowels.get(s)+1);
//After add the vowels count get actual count and check is it more than 3
if(mapVowels.get(s)>3)
a++;
}
else {
//If the vowels string new for map then add vowel count as 1 for first time
mapVowels.put(s,1);
}
}
}
}
return a;
}
Since java-8 you can now use Streams.
String[] values = {"AA","BC","CD","AE"};
boolean contains = Arrays.stream(values).anyMatch("s"::equals);
To check whether an array of int, double or long contains a value use IntStream, DoubleStream or LongStream respectively.
Example
int[] a = {1,2,3,4};
boolean contains = IntStream.of(a).anyMatch(x -> x == 4);

Comparing two strings by character in java

I have 2 strings :
first= "BSNLP"
second = "PBN" (or anything that user enters).
Requirement is , O/P should return me the string with only those characters in first but not in second.
Eg. in this case O/P is SL
Eg2.
first = "ASDR"
second = "MRT"
, o/p = "ASD"
For this, the coding I have developed:
String one = "pnlm";
String two ="bsnl";
String fin = "";
for(int i =0; i<one.length();i++)
{
for(int j=0;j<two.length();j++)
{
//System.out.print(" "+two.charAt(j));
if(one.charAt(i) == two.charAt(j))
{
fin+=one.charAt(i);
}
}
}
ch=removeDuplicates(fin);
System.out.print(" Ret ::"+fin);
System.out.println("\n Val ::"+ch);
CH gives me the string with equal characters, but using this logic i cant get the unequal characters.
Can anyone please help?
You can use the Set interface to add all the second array of character so you can check it there later.
sample:
String one = "ASDR";
String two ="MRT";
StringBuilder s = new StringBuilder();
Set<Character> set = new HashSet<>();
for(char c : two.toCharArray())
set.add(c); //add all second string character to set
for(char c : one.toCharArray())
{
if(!set.contains(c)) //check if the character is not one of the character of second string
s.append(c); //append the current character to the pool
}
System.out.println(s);
result:
ASD
I have simple exchange your logic, see:
String one = "pnlm";
String two = "bsnl";
String fin = "";
int cnt;
for (int i = 0; i < one.length(); i++) {
cnt = 0; // zero for no character equal
for (int j = 0; j < two.length(); j++) {
// System.out.print(" "+two.charAt(j));
if (one.charAt(i) == two.charAt(j)) {
cnt = 1; // ont for character equal
}
}
if (cnt == 0) {
fin += one.charAt(i);
}
}
System.out.print(" Ret ::" + fin);
o/p: Ret ::pm.
public static void main(String[] args)
{
String one = "ASDR";
String two ="MRT";
String fin = unique(one, two);
System.out.println(fin);
}
private static String unique(final String one,
final String two)
{
final List<Character> base;
final Set<Character> toRemove;
final StringBuilder remaining;
base = new ArrayList<>(one.length());
toRemove = new HashSet<>();
for(final char c : one.toCharArray())
{
base.add(c);
}
for(final char c : two.toCharArray())
{
toRemove.add(c);
}
base.removeAll(toRemove);
remaining = new StringBuilder(base.size());
for(final char c : base)
{
remaining.append(c);
}
return (remaining.toString());
}
Iterate over the first string
For each character, check if the second string contains it
If it doesn't, add the caracter to a StringBuilder
Return stringBuilder.toString()

Categories